ELD129003-Engtelecom (Diário) - Prof. Marcos Moecke

De MediaWiki do Campus São José
Revisão de 15h56min de 2 de julho de 2025 por Moecke (discussão | contribs) (ATUAL)
Ir para navegação Ir para pesquisar

1 Registro on-line das aulas

1.1 Unidade 1 - Aula inicial, Introdução a disciplina

  • 1 ENCONTRO
Unidade 1 - Aula inicial, Introdução a disciplina
Encontro 1 (18 mar.)
  • A página da UC contém os materiais que não alteram entre semestre.
  • Relação com as outras UCs do Eixo Sistemas Computacionais (Marrom). Ver grafo do curriculo
  • ELD129002 - ELETRÔNICA DIGITAL I (ELD1): Sistema de numeração e códigos. Lógica booleana. Circuitos combinacionais. Circuitos aritméticos. Linguagem de descrição de hardware. Implementação e teste de circuitos digitais. Projeto de circuitos lógicos.
  • ELD129003 - ELETRÔNICA DIGITAL II (ELD2): Dispositivos lógicos programáveis. Circuitos sequenciais. Metodologia síncrona. Projeto hierárquico e parametrizado. Máquinas de estados finita. Register Transfer Methodology. Teste de circuitos digitais. Implementação em FPGA. Introdução a Linguagem de Descrição de Hardware.
  • AOC129004 - ARQUITETURA E ORGANIZAÇÃO DE COMPUTADORES (AOC): Introdução à Arquitetura Computadores. Linguagem Assembly. Linguagem de Máquina. Programação Assembly. Modos de Endereçamento. Processo de compilação e carga de um programa. Introdução à Organização de Computadores. Organização Monociclo e Multiciclo. Pipeline. Memória e Sistema de E/S.
  • MIC129007 - MICROCONTROLADORES (MIC): Introdução a Microcontroladores e Aplicações. Arquitetura de um microcontrolador. Pilha e Subrotinas. Interrupção. Contadores e Temporizadores. Interface com Periféricos. Programação em alto nível (ex.: C, C++ e RUST) para Microcontroladores: Mapeamento de tipos e estruturas de alto nível para sistemas com recursos limitados. Projeto de hardware e firmware com microcontroladores.
  • STE129008 - STE - SISTEMAS EMBARCADOS (STE): Conceitos em Sistemas Embarcados. Metodologia de Desenvolvimento de Sistemas Embarcados. Sistemas Operacionais para Sistemas Embarcados. Ferramentas de desenvolvimento e depuração. Barramentos e dispositivos de acesso a redes. Desenvolvimento de Projeto.
  • Nesta página está o Registro diário dos encontros e avaliações.
  • A entrega de atividades e avaliações será através da plataforma Moodle. A inscrição dos alunos é automática a partir do SIGAA.
  • Para a comunicação entre professor-aluno, além dos avisos no SIGAA, utilizaremos o chat institucional. A princípio todos os alunos já estão previamente cadastrados pelo seu email institucional. Confiram enviando uma mensagem de apresentação.
  • Utilizaremos durante as aulas algumas ferramentas computacionas como o site do Falstad para entender circuitos digitais e fazer simulações básicas.
  • Também utilizaremos os softwares Quartus Light e ModelSim instalados nas maquinas do laboratório para praticar a parte de programação de hardware (descrição de hardware). Esses softwares também podem ser usados através da Nuvem do IFSC..
  • Para a prática de implementação dos circitos em dispositivos lógicos utilizaremos os kits de FPGA disponíveis no LabSiDi. Ver User Manual da DE2-115, e Manual do Usuário da Mercúrio IV.
LER PARA O PRÓXIMO ENCONTRO

1.2 Unidade REV - PRIMEIRO CONTATO COM VHDL

  • 4 ENCONTROS
Unidade REV - PRIMEIRO CONTATO COM VHDL
Nivelamento 1
  • Estrutura do código VHDL
  • Declaração das bibliotecas e pacotes LIBRARY / PACKAGE
 library library_name;
 use library_name.package_name.all;
  • ENTITY
 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
 architecture arch_name of entity_name is
   [declarative_part]
 begin
   statement_part
 end [architecture] [arch_name];
Nivelamento 2
  • Descrição do harware utilizando código VHDL no Quartus.
  • Rever a IDE do Quartus
  • Realizar análise e síntese.
  • Obter Diagrama RTL e Technology Map do circuito
  • Realizar simulação funcional com ModelSim
  • Conhecer a IDE do ModelSim
  • Seguir o procedimento descrito em Uso do ambiente EDA - QUARTUS Prime para programação em VHDL
PARA O PRÓXIMO ENCONTRO
  • Para os alunos que são da matriz curricular 1290 (PPC 2023).
  • Para conhecer um pouco mais da linguagem VHDL, ler VHDL ou VHDL.en. A maioria dessas instruções serão tratadas posteriormente.
Nivelamento 3- Simulação

1.2.1 REVISÃO ATUAL

Nivelamento 4 - Circuitos aritméticos
  • Circuitos aritméticos: somadores, incrementador, decrementador, complemento de dois, multiplicador, comparadores
  • slides
  • Incrementador de 4 bits [1] [2]
  • Decrementador de 4 bits [3] [4]
  • Somador completo [5]
  • Somador de 4 bits [6]
  • Complemento de dois de 4 bits [7]
  • Usando o tipo integer

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 um incrementador, um dos fatores do somador é substituído por '1' e o compilador irá implementar um circuito incrementador.

entity incrementador is
	port ( 
	a : in integer range 0  to 15; 
	inc : out integer range 0  to 15);
end entity;

architecture ifsc of incrementador is
begin
	inc <=  a + 1;
end architecture;

Figura 4.6 - Código RTL do incrementador com tipo integer com range
Fonte: Elaborado pelo autor.

Note que no incrementador apenas a segunda entrada do módulo RTL somador passa a ter um valor fixo '1'. Isso faz com que o hardware necessário para efetuar a soma (+1) é reduzido.


Para fazer o decrementador, um dos fatores do somador é substituído por '-1' e o compilador irá implementar um circuito decrementador.

entity decrementador is
	port ( 
	a : in integer range 0  to 15; 
	dec : out integer range 0  to 15);
end entity;

architecture ifsc of decrementador is
begin
	dec <=  a - 1;
end architecture;

Figura 4.7 - Código RTL do decrementador com tipo integer com range
Fonte: Elaborado pelo autor.

Note que no decrementador apenas a segunda entrada do módulo RTL somador passa a ter um valor fixo, mas também nas duas entradas o sinal A(0) e B(0) recebem o valor fixo '1', para produzir um carry_in para a soma do bit A(1) com B(1).

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.

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.

ATENÇÃO: Multiplicações por constantes não utilizam os multiplicadores, pois 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.

O tipo INTEGER não é muito adequado para realizar as operações aritméticas por três motivos:

  1. Com INTEGER as operações só podem ser feita com no máximo 32 bits.
  2. Se não for dado um RANGE, as operações serão feitas com 32 bits, gerando hardware desnecessário
  3. Alguns simuladores (como o ModelSim) ao incrementarem um INTEGER além do valor máximo interrompem a simulação por overflow.
tb_somador_int.do
# Define o nome do componente VHDL
set arq_vhd somador_int

vlib rtl_work
vmap work rtl_work
vcom -93 -work work "../../${arq_vhd}.vhd"
vsim work.${arq_vhd}(ifsc)

# Adiciona sinais ao waveform
add wave -position end sim:/$arq_vhd/a
add wave -position end sim:/$arq_vhd/b
add wave -position end sim:/$arq_vhd/s

#Adiciona sinais ao waveform e mostra o valor em UNSIGNED
add wave -position end -radix unsigned sim:/$arq_vhd/a
add wave -position end -radix unsigned sim:/$arq_vhd/b
add wave -position end -radix unsigned sim:/$arq_vhd/s

# Força valores em b e varia a de 0 a 15

force -freeze sim:/$arq_vhd/b 7 0
for {set i 0} {$i < 16} {incr i} {
    force -freeze sim:/$arq_vhd/a 10#$i 0
    run 1 ns
}


# Ajustes visuais
configure wave -timelineunits ns
wave zoom full

Figura 4.11 - Simulação com parada devido a erro de overflow no ModelSim
Fonte: Elaborado pelo autor.

Note que nessa simulação, ao atingir a soma 9 + 7 = 16, ocorre o overflow e o simulador indica o Fatal error e para.

** Fatal: (vsim-3421) Value 16 is out of range 0 to 15.

Figura 4.12 - Erro Fatal no ModelSim
Fonte: Elaborado pelo autor.

Veja como ficaria um somador usando o tipo UNSIGNED como portas de entrada e saída.

library ieee;
use ieee.numeric_std.all;

entity somador is
	generic (N : natural := 4);
	port ( 
	a, b : in unsigned(N-1 downto 0);
	s : out unsigned(4 downto 0)
	);
end entity;

architecture ifsc of somador is
	s <=  a + b;
end architecture;

Mesmo essa solução acima não é a mais adequada, pois utiliza portas que não estão de acordo com a recomendação do padrão industrial e que é compatível com as ferramentas de EDA no mercado. O ideal é ter sempre as portas definidas com tipos std_logic ou std_logic_vector. Por isso a recomendação é adotar uma solução como a seguinte:

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity somador_slv is
	generic (N : natural := 4);
	port ( 
	a, b : in std_logic_vector(N-1 downto 0);
	s : out std_logic(4 downto 0);
	);
end entity;

architecture ifsc_v1 of somador_slv is
begin
	s <=  std_logic_vector(unsigned(a) + unsigned(b));
end architecture;

architecture ifsc_v2 of somador_slv is
	signal a_uns, b_uns : unsigned(N-1 downto 0);
	signal s_uns : unsigned(N-1 downto 0);
begin
	s <= std_logic_vector(s_uns)
	s_uns <= a_uns + b_uns;
	a_uns <=  unsigned(a);
	a_uns <=  unsigned(b);
end architecture;

Figura 4.12 - Simulação correta no ModelSim
Fonte: Elaborado pelo autor.

Note que nessa simulação, ao atingir a soma 9 + 7 = 16, ocorre o overflow, como são apenas 4 bits que são utilizados, o resultado 10000 é guardado como 0000 e e o simulador indica corretamente o s = 0 no instante 9ns.

Para utilizar corretamente os tipos UNSIGNED e SIGNED leia atentamente

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/

Ler e guardar a página sobre Aritmética com vetores em VDHL

1.3 Unidade 2 - Dispositivos Lógicos Programáveis

  • 3 ENCONTROS
Unidade 2 - Dispositivos Lógicos Programáveis
Encontro 2 (20 mar.)
-- Exemplo: Declaração do circuito combinacional
-- Y = A'.B + A.B'
-- Autor:     prof. Marcos Moecke
-- Data:      20/03/2025
-- Filename:  REV1.vhd
-- A declaracao abaixo nao e necessaria pois o pacote standart da biblioteca std e autodeclarada (por default)
library std;
use std.standard.all;

-- 
entity REV1 is
    port (a, B: in bit; y: out bit);
end entity;

-- Implementacao direta com funcoes logicas
architecture ifsc_v1 of rev1 is
begin
    Y <= (not a and b) or (A and not B);
end architecture;

-- Implementacao com funcoes logica por etapas
architecture ifsc_v2 of rev1 is
	signal nota, notb : bit;     -- sinais internos podem ser declarados em uma unica linha se forem do mesmo tipo
	signal and_1 : bit;          -- o nome dos sinais nao pode usar palavras reservadas do VHDL como and.
	signal and_2 : bit;          -- usar uma linha para cada sinal pode ser uma boa pratica de documentacao
	signal or_3 : bit;
begin
	notA <= not A;
	notb <= not B;
	and_1 <= nota and b;
	and_2 <= (A and notB);
	or_3 <= and_1 or and_2;
	Y <= or_3;                  -- assim se faz a conexao entre um sinal interno uma saida
	-- as ultimas 2 linhas acima poderiam ser tambem simplificadas
	-- Y <= and_1 or and_2;
end architecture;

-- Implementacao com WHEN-ELSE
architecture ifsc_v3 of rev1 is
begin

end architecture;

-- Implementacao com WITH-SELECT
architecture ifsc_v4 of rev1 is
begin

end architecture;

-- associacao da architetura a entidade. 
-- Se nao for feita, a ultima arquitetura e associada
configuration rev1_cfg of REV1 is
--	for ifsc_v1 end for;
	for ifsc_v2 end for;	
--	for ifsc_v3 end for;	
--	for ifsc_v4 end for;
end configuration;
PARA O PRÓXIMO ENCONTRO
  • Implente e teste as várias versões de architecture da entity REV1 .
1) diretamente com as funções lógicas
2) com funções lógicas por etapas
3) com WHEN-ELSE
4) com WITH-SELECT


Encontro 3 (25 mar.)
  • Introdução aos dispositivos lógicos programáveis:
  • Conceito, tipos de PLDs
  • SPLD:
Exemplos de PLDs

Figura 2.1 - Exemplo de PAL
Fonte: http://www.vhdl.us/book/Pedroni_VHDL_3E_Chapter4.pdf.

Figura 2.2 - Exemplo de PLA
Fonte: http://www.vhdl.us/book/Pedroni_VHDL_3E_Chapter4.pdf.

Figura 2.3 - Macrobloco do PLD EP300 da ALTERA
Fonte: https://www.altera.com/solutions/technology/system-design/articles/_2013/in-the-beginning.html.

Figura 2.4 - Macrocélula dos PLDs Clássicos EP600, EP900, EP1800 da ALTERA (1999)
Fonte: https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ds/archives/classic.pdf.

Figura 2.5 - Princípio de construção de uma LUT
Fonte: https://www.vhdl.us/book/Pedroni_VHDL_3E_Chapter4.pdf.

Figura 2.6 - Architetura do PLD EP1800 da ALTERA
Fonte: https://www.altera.com/solutions/technology/system-design/articles/_2013/in-the-beginning.html.

Figura 2.7 - Architetura do PLD EP1800 da ALTERA
Fonte: https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ds/archives/classic.pdf.

Figura 2.8 - Pinagem e tipos de encapsulamento do PLD EP1800 da ALTERA
Fonte: https://www.altera.com/content/dam/altera-www/global/en_US/pdfs/literature/ds/archives/classic.pdf.

Figura 2.9 - Architetura do CPLD MAX 5000 da ALTERA
Fonte: https://www.altera.com/solutions/technology/system-design/articles/_2013/in-the-beginning.html.
PARA O PRÓXIMO ENCONTRO
Encontro 4 (27 mar.)
  • Arquitetura de FPGAs (Xilinx e Altera): CLB, LAB, LUT, Flip_flop D, RAM, DSP, Clock, PLL, DLL, I/O
FONTE: FPGA Architecture - ALTERA
Exemplos de FPGA

Figura 2.9 - Arquitetura de um FPGA
Fonte: https://www.intel.com/content/www/us/en/docs/programmable/683176/18-1/fpga-overview-opencl-standard.html.

Figura 2.10 - Diagrama simplificado da ALM de um FPGA Intel/Altera
Fonte: https://www.intel.com/content/www/us/en/content-details/771003/fpga-architecture-8-input-lut-legacy-white-paper.html.

Figura 2.11 - Arquitetura interna de uma LUT
Fonte: FPGA Architecture - ALTERA.

Figura 2.12 - Configuração de uma LUT
Fonte: https://www.allaboutcircuits.com/technical-articles/purpose-and-internal-functionality-of-fpga-look-up-tables/.

Figura 2.13 - Arquitetura do Cyclone® V Intel/Altera
Fonte: https://www.intel.com.br/content/www/br/pt/products/details/fpga/cyclone/v/article.html.

Figura 2.14 - Leiaute de um FPGA Xilinx genérico
Fonte: https://www.sciencedirect.com/science/article/pii/B9780750678667500032.

Figura 2.15 - Roteamento de sinal em um FPGA
Fonte: https://www.sciencedirect.com/science/article/pii/B9780750678667500032.

Figura 2.16 - Tecnologias usadas na configuração de FPGAs
Fonte: https://www.sciencedirect.com/topics/computer-science/one-time-programmable.
Ver também SRAM, EEPROM, What Is Flash Memory
PARA O PRÓXIMO ENCONTRO
  • Leia a assista a alguns dos vídeos sobre a historia e processo de produção dos chips.
Encontro 5 (1 abr.)
  • System on Chip

Figura 2.17 - Altera - Visão geral do dispositivo Arria V SX e ST
Fonte: https://br.mouser.com/datasheet/2/612/av_51001-1623623.pdf.

Figura 2.18 - Altera - Agilex 7 SoCs HPS Digrama de Blocos
Fonte: https://static6.arrow.com/aropdfconversion/b568cfe009abfed6a28eff56700189883d7fc179/ag-overview-683458-666707.pdf.
PARA O PRÓXIMO ENCONTRO
  • Ver preços de DLPs em
  • Fabricantes de DLPs/FPGAs e familias de DLPs atuais.


Encontro 6 (3 abr.)

1.4 Unidade 3 - Circuitos sequenciais (Implementação com HDL)

  • 8 ENCONTROS
Unidade 3 - Circuitos sequenciais (Implementação com HDL)
Encontro 6 (3 abr.)
  • Flip-Flop e circuitos sequenciais.
  • Diferenças entre código concorrente e sequencial <=> circuitos combinacional e sequencial
  • Diferenças entre os objetos SIGNAL e VARIABLE
  • Tipos de elementos de memória: Latch x Flip-flop
  • Latch D
  • Flip-flop tipo D com reset assíncrono e com reset (clear) síncrono
  • Seção de código sequencial PROCESS: lista de sensibilidade
[rótulo:] PROCESS [(lista_de_sensibilidade)] [IS]
             [parte_declarativa]
         BEGIN
             afirmação_sequencial;
             afirmação_sequencial;
             ...
         END PROCESS [rótulo];
  • Instrução IF
[rótulo:] IF condição THEN
             afirmação_sequencial;
             afirmação_sequencial;
             ...
         ELSIF condição THEN
             afirmação_sequencial;
             afirmação_sequencial;
             ...
         ELSE
             afirmação_sequencial;
             afirmação_sequencial;
             ...
         END IF [rótulo];
  • Exemplos:
  • DFFs com Reset Assincrono e Reset Sincrono, com Enable, com Preset (Variação Ex 6.1).
--Flip Flop tipo D com reset assincrono, sensivel a borda de subida.
process (clock,reset)
begin
   if (reset = '1') then
      q <= '0';
-- elsif (clock'event and clock = '1') then or
   elsif (rising_edge(clock)) then
      q <= d;
   end if;
end process;

Figura 3.1 - RTL de Flip-flop D de borda de subida, com reset assíncrono
Fonte: Elaborado pelo autor.
--Flip Flop tipo D com preset assincrono e sinal de enable, sensivel a borda de descida.
process (clock, preset)
begin
   if (preset = '1') then
      q <= '1';
   elsif (falling_edge(clock)) then
      if (enable = '1') then
         q <= d;
      end if;
   end if;
end process;

Figura 3.2 - RTL de Flip-flop D de borda de descida, com preset assíncrono e enable
Fonte: Elaborado pelo autor.
  • Comparar com Latch (sem clk'event).
--Latch tipo D com reset assincrono.
process (enable, reset, d)
begin
   if (reset = '1') then
      q <= '0';
   elsif (enable='1')) then
      q <= d;
   end if;
end process;

Figura 3.3 - RTL de Latch D de com reset assíncrono e enable ativo alto
Fonte: Elaborado pelo autor.
  • Na figura abaixo, note que o Latch é implementado utilizando a LUT do elemento lógico do FPGA, enquanto que o Flip-flop utiliza o componente já disponível neste elemento lógico.
  • Evite os latches no projeto

Figura 3.4 - Comparação do Technology Map de um Latch_D (esquerda) com FF_D (direita)
Fonte: Elaborado pelo autor.
-- Flip Flop tipo D com reset síncrono sensível a borda de subida. 
-- Modifique a descrição para que o reset_ass seja assíncrono e reset_sinc seja síncrono.
-- Note que a função rising_edge(clock) é equivalente a (clock'event and clock'last_value = '0' and clock = '1'))

process (clock, reset)
begin
   if (reset = '1') then
      q <= '0';
   elsif (clock'event and clock'last_value = '0' and clock = '1')) then
      q <= d;
   end if;
end process;

Figura 3.5 - RTL do Flip-flop D com reset assíncrono e reset síncrono
Fonte: Elaborado pelo autor.
Encontro 7 (8 abr.)
  • Exercício: Implemente um registrador com N FF_D no lugar de um único FF_D.

Figura 3.6 - RTL do Registrador (de 4 bits) com reset assíncrono
Fonte: Elaborado pelo autor.

Figura 3.7 - Techonogy Map do Registrador (de 4 bits) com reset assíncrono
Fonte: Elaborado pelo autor.
  • Faça a simulação funcional do DFFs e do Latch
Para o próximo encontro
  • Use o script do arquivo de simulação tb_FFD_v_ruim.do para repetir a simulação feita em aula.
  • Melhore o script eliminando comentários desnecessários.
  • Deixe no inicio do script os comandos (alguns estarão comentados)
vlib rtl_work
Função: Criar uma biblioteca de trabalho chamada rtl_work.
vmap work rtl_work
Função: Faz o mapeamento da biblioteca padrão work para a biblioteca rtl_work criada anteriormente.
vcom -93 -work work {../../FFD_N.vhd}
Função: Compila o arquivo VHDL FFD_N.vhd utilizando o padrão VHDL-93, e coloca o resultado da compilação na biblioteca work.
vsim work.ffd_n(ifsc_v1)
Função: Inicia a simulação do componente ffd_n, presente na biblioteca work, utilizando a configuração ifsc_v1.
add wave -r sim:/ffd_n/* 
Função: Adicione todos os sinais da hierarquia a janela Wave.
  • Para cada estímulo (entrada) faça com que haja apenas uma linha de comando force usando o padrão abaixo:
force -freeze sim:/ffd_n/<nome do estimulo> valor1 tempo1, valor2 tempo2, valor3 tempo3 
  • Para a entrada clock use:
force -freeze sim:/ffd_n/clock v1 t1, v2 t2 -r Tclk
onde:
o primeiro par (v1 t1) indica o valor inicial do clock v1 = 1 => começa ALTO. v1 = 0 => começa BAIXO. t1 é normalmente 0, indica quando o valor v1 deve ser gerado.
o segundo par (v2 t2) indica o valor final do clock, v2 deve ser o complemento de v1. t2 é a duração do valor v1 em ps (ou outra unidade)
o tempo Tclk é o período em que o sinal deve ser repetido.
Exemplo de um sinal de período de 100ps => fclk = 10GHz;
force -freeze sim:/ffd_n/clock 1 0, 0 50 -r 100
  • Conclua a simulação com uma linha de run que seja suficiente para variar todos os estímulos e obter os resultados:
run XXX ps ou  
run XXX ns|us|ms|sec|min|hr
  • Para visualizar todo o período de tempo simulado inclua o seguinte comando no script
wave zoom full
  • Ao final crie o arquivo FFD_N.qar que deve conter além dos arquivos de projeto, também os dois scripts de simulação. Use o Quartus para incluir esses arquivos e gerar o qar. Confira o seu conteúdo no arquivo FFD_N.qarlog
	=========== Files Selected: ===========
 /home/moecke/ELD2/2025.1/AULA7/FFD_N.qpf
 /home/moecke/ELD2/2025.1/AULA7/FFD_N.qsf
 /home/moecke/ELD2/2025.1/AULA7/FFD_N.vhd
 /home/moecke/ELD2/2025.1/AULA7/simulation/modelsim/tb_FFD_v2_melhor.do
 /home/moecke/ELD2/2025.1/AULA7/simulation/modelsim/tb_FFD_v_ruim.do
 /opt/intelFPGA/20.1/quartus/linux64/assignment_defaults.qdf
	======= Total: 6 files to archive =======
Encontro 8(10 abr.)
Circuito síncrono vs assíncrono

Tipo de Circuito Características

  • Síncrono: Usa flip-flops com um clock global comum. Estados mudam apenas na borda do clock.
  • GALS (Globally Asynchronous, Locally Synchronous): Módulos internos síncronos com seus próprios clocks, mas sem sincronismo global. Comunicação entre módulos requer cuidados especiais.
  • Assíncrono: Não utiliza clock. As transições de estado dependem apenas das mudanças nas entradas e no tempo de propagação dos sinais. Difícil de projetar corretamente.
  • Circuito globalmente síncrono: todos os elementos de memória (D FFs) controlados (sincronizados) por um sinal de clock global comum.
  • Circuito globalmente assíncrono, mas localmente síncrono (GALS).
  • Circuito globalmente assíncrono: Usa DFF, mas não um clock global. Não usa sinal de clock.

Um dos aspectos de projeto mais difíceis de um circuito sequencial é satisfazer as restrições (constraints) de tempo (ex.: Tsetup e Thold). No MÉTODO SÍNCRONO, todos os DFFs utilizam em um único clock. Assim apenas é necessário lidar com a restrição de tempo de um elemento de memória.

Circuito Sequencial Síncrono - Diagrama Conceitual

Figura 5.21 - Diagrama conceitual de circuitos síncronos
Fonte: RTL Hardware Desing, P. Chu.
  • External Input: Entradas externas fornecem os sinais que afetam a transição entre estados.
  • Next-State Logic (lógica de próximo estado): Circuito combinacional que determina qual será o próximo estado (state_next) com base no estado atual (state_reg) e nas entradas externas.
  • State Register (registrador de estado): Elemento de memória (Flip-Flop tipo D) que armazena o estado atual. Ele captura o valor de state_next na borda ativa do sinal de clock (clk).
  • Output Logic (lógica de saída): Circuito combinacional que gera as saídas do sistema com base no estado atual. Pode ou não depender das entradas (Moore vs Mealy):
  • Moore: Saída depende apenas do estado.
  • Mealy: Saída depende do estado e das entradas.
Funcionamento - Fluxo de dados:
  • O sinal de clock (clk) sincroniza todas as mudanças de estado.
  • O registrador atualiza seu valor na borda do clock, armazenando o state_next calculado anteriormente.
  • A lógica combinacional (tanto de próximo estado quanto de saída) opera continuamente, processando entradas e o estado atual.
  • O sistema avança de estado apenas no clock, garantindo que as transições ocorrem de forma ordenada e previsível.
  • Glitches não tem efeitos na saída, desde que o state_next esteja estável quando ocorre a borda de subida do clock, e Tsetup e Thold sejam respeitados.
Encontro 9 (15 abr.)
  • Código com 2 segmentos: 1) parte sequencial (apena atualiza o r_reg) 2) parte combinatória (cálcula o r_next)
  • Código com 1 segmento: todo o código fica em um único process.
  • Contador decimal (mod-10)
  • Analisar a diferença entre utilizar signal e variable. O signal é atualizado apenas ao final do process (end process), enquanto que a variable é atualizada imediatamente. Essa diferença pode gerar códigos que não fazem exatamente o que desejamos.
DOIS segmentos vs. UM segmento
  • Código de dois segmentos
  • Separa o segmento de memória do resto do código;
  • Pode ser um pouco complicado (lógica separada);
  • Tem um mapeamento claro para o componente de hardware.
  • Código de um segmento
  • Mistura o segmento de memória e lógica de próximo estado/lógica de saída;
  • Em alguns casos pode ser mais compacto;
  • Mapeamento de hardware não é claro;
  • Propenso a erros.

No exemplo do contador binário livre com pulso de máximo é possível perceber um dos tipos de erros que o uso de código em um segmento pode gerar. Como cada atribuição feita a um sinal dentro do if rising_edge(clk) then, gera um flip-flop para a saida max_pulse, e pode causar atrasos indesejados em sinais.

architecture extra_ff_max_pulse of binary_counter4_pulse is
   signal r_reg: unsigned(3 downto 0);
begin
   process(clk,reset)
   begin
      if (reset='1') then
         r_reg <= (others=>'0');
      elsif rising_edge(clk) then
         r_reg <= r_reg + 1;
         if r_reg="1111" then
            max_pulse <= '1';
         else
            max_pulse <= '0';
         end if;
      end if;
   end process;
   q <= std_logic_vector(r_reg);
end architecture;

Figura 5.22 - Diagrama RTL contador com max_pulse output
Fonte: Elaborado pelo autor.

Figura 5.22 - Diagrama RTL contador com extra flip-flop in max_pulse output
Fonte: Elaborado pelo autor.

Figura 5.23 - Simulação do extra flip-flop in max_pulse output - errado
Fonte: Elaborado pelo autor.

Figura 5.24 - Simulação do max_pulse output - correto
Fonte: Elaborado pelo autor.

No exemplo do contador decimal (mod-10) é possível perceber um outro tipo de erros que o uso de código em um segmento pode gerar. Como um sinal (signal) é atualizado apenas no final do processo, isso pode levar a códigos com erro como mostrado no exemplo a seguir.

architecture one_seg_arch_signal of mod10_counter is
   constant TEN: integer := 10;
   signal r_reg: unsigned(3 downto 0);
begin
   -- register
   process(clk,reset)
   begin
      if (reset='1') then
         r_reg <= (others => '0');
      elsif rising_edge(clk) then
			r_reg <= r_reg + 1;
			if r_reg=TEN then
				r_reg <= (others => '0');
			end if;
      end if;
   end process;
   -- output logic
   q <= std_logic_vector(r_reg);
end architecture;

Na comparação r_reg=TEN, espera-se que o r_reg tenha sido incrementado (r_reg <= r_reg + 1), mas o valor de r_reg ainda é o valor que tinha ao entrar no process. Assim o contador acaba contando de 0 a 10 e não de 0 a 9.

architecture one_seg_arch_variable of mod10_counter is
   constant TEN: integer := 10;
begin
   -- register
   process(clk,reset)
		variable r_reg: unsigned(3 downto 0);
   begin
      if (reset='1') then
         r_reg := (others => '0');
      elsif rising_edge(clk) then
			r_reg := r_reg + 1;
			if r_reg = TEN then
				r_reg := (others => '0');
			end if;
      end if;
      -- output logic
	  q <= std_logic_vector(r_reg);		
   end process;
end architecture;

A solução acima utiliza variable no lugar de signal para o r_reg. Neste caso a comparação r_reg = TEN irá comparar corretamente o valor atual de r_reg já incrementado (r_reg := r_reg + 1), e a contagem será correta de 0 a 9.

Para o próximo encontro
  • Implementar um contador BCD que efetue a contagem de 000 a 999. O contador deve ter uma entrada de enable que habilita a contagem, além das entradas de reset (assincrono) e clock. O contador deve ter 3 saídas de 4 bits std_logic_vector(3 downto 0), uma para unidade, uma para dezena e outra para a centena.
  • O código deverá ser implementado em 2 segmentos separados. Um contendo apenas a parte sequencial (state register), e outro contendo a parte combinacional. A parte combinacional deve ter a next state logic e em separado a output logic.
  • Exemplo do que pode ter no state register:
-- state register
   process(clock,reset)
   begin
      if (reset='1') then
         centena_reg <= (others=>'0');
         dezena_reg <= (others=>'0');
         unidade_reg <= (others=>'0');
      elsif rising_edge(clock) then
         centena_reg <= centena_next;
         dezena_reg <= dezena_next;
         unidade_reg <= unidade_next;
      end if;
   end process;


Encontro 10 (17 abr.)
  • Variações do contador BCD
  • Em 2 segmentos com WHEN ELSE
  • Em 2 segmentos com IFs aninhados
  • Registrador de Deslocamento

Abaixo estão três formas distintas de implementar um registrador de deslocamento, todas com a mesma funcionalidade, mas com diferenças na legibilidade, generalização e estilo de codificação:

  • Usando operador de concatenação:
	r_next <= d & r_reg(3 downto 1);
	q <= r_reg(0);

Essa abordagem é compacta e permite facilmente estender o registrador para um número genérico de bits.

  • Atribuições bit a bit (sem laço):
	r_next(3) <= d;
	r_next(2) <= r_reg(3);
	r_next(1) <= r_reg(2);
	r_next(0) <= r_reg(1);
	q <= r_reg(0);

Apesar de ser explícita e didática, essa forma não é escalável, pois exige reescrever todas as atribuições para cada nova largura de registrador.

  • Atribuições bit a bit com for generate:
	r_next(3) <= d;
	l1: for i in 2 downto 0 generate
		r_next(i) <= r_reg(i + 1);
	end generate;
	q <= r_reg(0);

Esta versão combina clareza com generalização. Assim como a primeira, é facilmente adaptável para registradores de qualquer tamanho.

Observação: A primeira e a terceira implementações são mais adequadas quando se deseja gerar registradores de deslocamento de largura genérica, facilitando a reutilização do código. Já a segunda, apesar de simples, não é prática para registros maiores, pois não é escalável.

Para o próximo encontro
  • DESAFIO: Desenvolver um contador genérico capaz de contar em BCD com qualquer número de dígitos.
Encontro 11 (22 abr.)
  • Para replicar hardware várias vezes, utilize estruturas como: for generate ou for loop
  • Instrução Concorrente FOR-GENERATE:
-- Note que neste caso o '''label''' é obrigatório

label: FOR identificador IN faixa GENERATE
   [Parte_Declarativa
   BEGIN]
     afirmação_concorrente;
     afirmação_concorrente;
     ...
   END GENERATE [label];
  • Instrução Sequencial FOR-LOOP:
[rótulo:] FOR identificador IN faixa LOOP
             afirmação_sequencial;
             afirmação_sequencial;
             ...
          END LOOP [rótulo];
  • Implementar um registrador com N FF_D usando a instrução FOR GENERATE.

Figura 5.8 - Technology Map de Shift Register
Fonte: Elaborado pelo autor.

Figura 5.9 - Simulação de Shift Register
Arquivo:Shift reg SIM.png
Fonte: Elaborado pelo autor.
  • Implementar uma porta or (and) ou xor de N entradas usando a instrução FOR GENERATE.

Novas dicas para representar N dígitos BCD, cada um com 4 bits, será necessário criar um novo tipo de dado:

   type bcd_digits is array (natural range <>) of unsigned(3 downto 0);
   signal bcd  : bcd_digits(0 to N-1);
  • Para utilizar esse tipo na declaração das portas (interface do componente), a declaração do tipo deve estar dentro de um pacote (package), e esse pacote deve ser importado no seu arquivo com:
library work;
use work.nome_do_pacote.all;
Para o próximo encontro
  • DESAFIO: Desenvolver um contador genérico capaz de contar em BCD com qualquer número de dígitos.


Encontro 14 (24 abr.)
  • Temporizações de um Flip-Flop.
  • atraso do clock para saída (Tcq)
  • tempo de setup (T_{setup}) e tempo de hold (T_{hold})

Figura 5.22 - Temporizações de um Flip Flop
Fonte: RTL Hardware Desing, P. Chu.

Nota: a violação do tempo de setup ou hold leva ao estado de meta-estabilidade, na qual a saída fica temporariamente em um valor indefenido.

  • Os circuitos devem ser projetos para serem globalmente síncronos.
  • Violação do tempo de Setup do FF e frequência máxima do circuito (Fmax).

Figura 5.23 - Modelo de Circuito Sequencial
Fonte: RTL Hardware Desing, P. Chu.

Figura 5.24 - Tempo de Setup e Fmax
Fonte: RTL Hardware Desing, P. Chu.

Figura 5.25 - Equações do Tempo de Setup e Fmax (1/Tc(min))
Fonte: RTL Hardware Desing, P. Chu.

Figura 5.26 - Equações do Tempo de Hold
Fonte: RTL Hardware Desing, P. Chu.

Figura 5.27 - Atraso da saída
Fonte: RTL Hardware Desing, P. Chu.
Para o próximo encontro
  • Contador de sequencia arbitraria (implementado com when else)
  • Contador de livre com indicação de valor máximo. (implementado com incrementador) - Já feito
  • Contador com opções de clear sincrono, load, e parada
  • Contador de modulo 10 - Já feito
  • Contador de modulo m (onde m é uma entrada).


Encontro 15 (29 abr.)

Instruções do tipo LOOP: LOOP incondicional, FOR-LOOP, WHILE-LOOP, NEXT, EXIT

  • Instrução LOOP incondicional:
[rótulo:] LOOP
             afirmação_sequencial;
             afirmação_sequencial;
             ...
          END LOOP [rótulo];


  • Instrução WHILE-LOOP:
[rótulo:] WHILE condição LOOP            -- Executa as "afirmações enquanto a "condição" for verdadeira
             afirmação_sequencial;
             afirmação_sequencial;
             ...
          END LOOP [rótulo];
  • Instrução LOOP com EXIT:
[rótulo:] [FOR identificador IN faixa] LOOP
             afirmação_sequencial;
             EXIT [rótulo] [WHEN condição];    -- Se a "condição" é verdadeira, termina o "LOOP"
             afirmação_sequencial;
             ...
          END LOOP [rótulo];
  • Instrução LOOP com NEXT:
[rótulo:] [FOR identificador IN faixa] LOOP
             afirmação_sequencial;
             NEXT [rótulo] [WHEN condição];    -- Se a "condição" é verdadeira, não executa as linhas até a linha "END LOOP"
                                               -- e incrementa o "identificador".
             afirmação_sequencial;
             ...
          END LOOP [rótulo];
  • Instrução CASE
 [rótulo opcional:] CASE expressão IS
                  WHEN valor =>                             -- valor único
                    afirmação_sequencial;                            
                    afirmação_sequencial;                            
                    ...
                  WHEN valor1 | valor2 | ... | valorN  =>   -- lista de valores
                    afirmação_sequencial;                            
                    afirmação_sequencial;                            
                    ...
                  WHEN valor1 TO valor2 =>                  -- faixa de valores
                    afirmação_sequencial;                            
                    afirmação_sequencial; 
                    ...
                  WHEN OTHERS  =>                          -- para evitar latches
                    afirmação_sequencial;                            
                    afirmação_sequencial; 
                    ...
          END CASE;
Exemplos
  • Leading Zeros (LOOP com EXIT) (Ex 6.5) - Esse circuito deve determinar quantos zeros tem em um vetor de entrada Data antes do primeiro bit '1', começando da esquerda para a direita.
  • Fazer a síntese do circuito; fazer simulação no Modelsim; analisar a forma como o compilador implementou o incrementador.
entity leading_zeros is
	generic (N : natural := 8);
	port
		(	________ : in std_logic_vector(0 to N-1);
			count	: out integer range 0 to N
		);
end entity;

architecture ____ of leading_zeros is

begin
	process (data)
	variable count : integer ____ 0 to N
	begin
		count := 0;
		for i ___ data'range ____
			case data(i) is
				when '0' => count := count + 1;
				when _____ => exit;
			end  ___
		end ____
		zeros <= count;
	end process;
end _______;

Figura 5.15 - Simulação do leading_zeros
Fonte: Elaborado pelo autor.
  • Contador de zeros (LOOP com NEXT ou apenas LOOP) - Esse circuito deve determinar quantos zeros tem em um vetor de entrada Data.
  • Fazer a síntese do circuito; fazer simulação no Modelsim; analisar a forma como o compilador implementou o incrementador.

Figura 5.16 - Simulação do counting_zeros
Fonte: Elaborado pelo autor.
  • Ver pag. 161 a 164 de [1]
Encontro 16 (6 mai.)
  • Implemente o contador de sequencia arbitraria (implementado com when else) (ver Listing 8.11 - Arbitrar-sequence counter).
  • Implemente o contador com opções de clear sincrono, load, e parada (ver Listing 8.13 - Featured binary counter).
  • Implemente o contador de modulo m (onde m é uma entrada) (ver Listing 8.15 e 8.16 - Programmable mod-m counter).
Encontro 17 (8 mai.)
  • Projetar um divisor de clock que dado um clock de entrada de fclk Hz, produza na saída um sinal de clock de f/N onde N é um número inteiro (div_clk)
entity div_clk  is
   port(
     clk:       in std_logic;
     reset:     in std_logic;
	 clk_1ms:   out std_logic;
	 clk_10sec: out std_logic;
	 clk_1sec:  out std_logic
   );
end entity;
  • Utilize esse circuito para obter um clock de 1 Hz (1 sec) clk_1sec a partir do sinal de 50MHz existente no kit DE2-115.
Para o próximo encontro
  • Completar o projeto do divisor de clock, acrescentando:
  • Implemente uma segunda saída para um clock de 1kHz (1 ms) clk_1ms
  • Implemente uma terceira saída para um clock de 0,1 Hz (10 sec) clk_10sec
  • Configure o circuito no kit DE2-115 dispositivo EP4CE115F29C7, usando 1 led para sinalizar cada um desses clocks gerados.
ver Preparando para gravar o circuito lógico no FPGA e Interfaces de entrada e saída da DE2-115
porta pino nome do sinal no kit
clk Y2 CLOCK_50
reset AB28 SW[0]
clk_1sec F17 LEDG[8]
clk_10sec E21 LEDG[0]
clk_1ms G19 LEDR[0]
  • Preparar o código dos seguintes circuitos:
  • Contador de segundos e minutos com clock derivado (ver Listing 9.5)
  • Contador de segundos e minutos síncrono (ver Listing 9.6)
Encontro 18 (13 mai.)
  • Fazer a compilação completa, simular e fazer o timing analysis dos seguintes circuitos:
  • Contador de segundos e minutos com clock derivado (ver Listing 9.5)

Figura 3.17 - Contador de segundos e minutos - clock derivado
Fonte: RTL Hardware Desing, P. Chu..
  • Contador de segundos e minutos síncrono (ver Listing 9.6)

Figura 3.18 - Contador de segundos e minutos - clock síncrono
Fonte: RTL Hardware Desing, P. Chu..


Encontro 19 (15 mai.)

Comparar o desempenho Fmax, número de elementos lógicos, número de registradores, número de pinos dos seguintes contadores, considerando uma saída de N_bits.

  • Contador binario sequencial
  b_next <= b_reg+1; 
ver Código Gray
  b <= g_reg xor ('0' & b(WIDTH-1 downto 1));
  b1 <= b+1; 
  g_next <= b1 xor ('0' & b1(WIDTH-1 downto 1));
  r_next <= r_reg(0) & r_reg(WIDTH-1 downto 1);
  • Contador Johnson (uso de um inversor na realimentação do contador em anel)
  r_next <= (not r_reg(0)) & r_reg(WIDTH-1 downto 1); 
  fb <= r_reg(1) xor r_reg(0);
  r_next <= fb & r_reg(3 downto 1);
Para o próximo encontro
  • Ver como se pode implementar um contador LFSR de n bits.
  • Consultar [9] ou a página 5 de [10] para obter os termos que são usados na realimentação.
Encontro 20 (20 mai.)
  • Em algumas aplicações ao invés de usar diretamente a contagem, se usa o estado do contador para geram sinais de saída. Um exemplo é um circuito de modulação por largura de pulso (PWM), que gera um pulso de saída com um ciclo de trabalho ajustável.
  • Por exemplo, em um circuito PWM que tem 16 passos, o ciclo de trabalho pode ser ajustado em incrementos de 1/16, ou seja, o ciclo de trabalho pode ser 1/16, 2/16, 3/16, ..., até 16/16. Este circuito pode ser implementado por um contador mod-16 com um circuito de saída especial, que define o valor da saída em alto de acordo com o valor da contagem. O período dos pulsos de saída neste caso sempre será de 16 vezes o período do relógio.
  • Note que uma expressão booleana adicional, w="0000", é incluída para acomodar a condição especial.
   buf_next <= '1' when (r_reg<unsigned(w)) or (w="0000") else '0';

Figura 5.X - RTL do circuito de PWM
Fonte: Elaborado pelo autor.

Na simulação abaixo, um clock de 50 ps foi utilizado, e o valor da entrada w foi definida como (3, 8, 0, 1, 15) a cada 1600 ps. Note que a largura do pulso da saída pwm_pulse está de acordo com aquela entrada.


Figura 5.X - Simulação do circuito de PWM
Fonte: Elaborado pelo autor.
  • Implementar um contador decrescente N até 0, com N ≠ 2^Mbits (5, 10)
  • Com underflow no valor mínimo

Figura 5.13 - Simulação do contador decrescente 5 a 0
Fonte: Elaborado pelo autor.
  • Implementar um contador decrescente com parada no valor mínimo

Figura 5.14 - Simulação do contador decrescente 5 a 0 com parada
Fonte: Elaborado pelo autor.
  • Implementar um contador bidirecional entre MIN e MAX. Uma entrada DIR indica a direção da contagem. Considere DIR = 0 (crescente) e DIR = 1 (decrescente).
  • Versão 1: Com underflow no valor mínimo (MIN) e overflow no máximo (MAX).
  • Versão 2: Com parada no valor mínimo (MIN), se decrescente e também no máximo (MAX) se crescente.
Encontro 21 (22 mai.)
  • Instrução IF GENERATE
<generate_label>: 
	if <condition> generate
		-- Concurrent Statement(s)
	end generate;

Essa instrução é utilizada para a geração condicional de código durante a elaboração. Com isso, partes do projeto são sintetizadas e outras não, dependendo de certas condições ou parâmetros definidos no projeto. Como ela faz parte do grupo de instruções concorrentes, ela não pode ser utilizada dentro de PROCESS, FUNCTION ou PROCEDURE.

Para exemplificar, consideramos a situação em que um contador crescente (UP) OU um contador decrescente (DOWN) devem serm utilizados, mas o contador nunca será aplicado nas duas direções de contagem. Neste caso, é possível estabelecer um parâmetro GENERIC, que definirá se a contagem é UP ou DOWN. Analise o código a seguir escrito em segmento único e usando variável:

entity contador_up_down_if_generate is
	generic
	(
		MIN     : natural := 3;
		MAX     : natural := 21;
		UPDOWN  : natural := 0          -- 0 => up; 1 => down
	);
	port
	(
		clk, rst   : in std_logic;
		cnt_out    : out integer range MIN to MAX   -- Aqui deveria ser usado std_logic_vector
	);
end entity;
architecture ifsc_v1 of contador_up_down_if_generate is
begin
	L1: if UPDOWN = 0 generate
		process (clk, rst)
			variable cnt : integer range MIN to MAX;
		begin
			if rst = '1' then
				cnt := MIN;
			elsif (rising_edge(clk)) then
					if cnt = MAX then
						cnt := MIN;
					else
						cnt := cnt + 1;
					end if;
			end if;
			cnt_out <= cnt;
		end process;
	end generate;
	L2: if UPDOWN = 1 generate
		process (clk, rst)
			variable cnt : integer range MIN to MAX;
		begin
			if rst = '1' then
				cnt := MAX;
			elsif (rising_edge(clk)) then
					if cnt = MIN then
						cnt := MAX;
					else
						cnt := cnt - 1;
					end if;
			end if;
			cnt_out <= cnt;
		end process;	
	end generate;
end architecture;

Agora analise o mesmo contador descrito em dois segmentos, parte sequencial e parte de logica de próximo estado:

architecture ifsc_v2 of contador_up_down_if_generate is
    signal reg_cnt, next_cnt : integer range MIN to MAX;
begin
    -- Contagem crescente
    L1: if UPDOWN = 0 generate
        -- Segmento sequencial
        process (clk, rst)
        begin
            if rst = '1' then
                reg_cnt <= MIN;
            elsif rising_edge(clk) then
                reg_cnt <= next_cnt;
            end if;
        end process;
        -- Segmento de próximo estado
        next_cnt <= MIN when reg_cnt = MAX else reg_cnt + 1;
    end generate;

    -- Contagem decrescente
    L2: if UPDOWN = 1 generate
        -- Segmento sequencial
        process (clk, rst)
        begin
            if rst = '1' then
                reg_cnt <= MAX;
            elsif rising_edge(clk) then
                reg_cnt <= next_cnt;
            end if;
        end process;
        -- Segmento de próximo estado
        next_cnt <= MAX when reg_cnt = MIN else reg_cnt - 1;
    end generate;
    -- Código de saída
    cnt_out <= reg_cnt;
end architecture;

Se o parâmetro UPDOWN for instanciado com 0, teremos um contador crescente. Caso seja instanciado com 1, o contador será decrescente. Veja a simulação nos dois casos.


Figura 5.20 - Simulação do contador UPDOWN com 0
Fonte: Elaborado pelo autor.

Figura 5.21 - Simulação do contador UPDOWN com 1
Fonte: Elaborado pelo autor.
  • Uso de duas architecture para obter a mesma opção do IF GENERATE
entity contador_up_down_two_arch is
	generic
	(
		MIN : natural := 3;
		MAX : natural := 21
	);
	port
	(
		clk, rst    : in std_logic;
		count_out   : out integer range MIN to MAX
	);
end entity;

architecture arch_up of contador_up_down_two_arch is
begin
		process (clk, rst)
			variable cnt : integer range MIN to MAX;
		begin
			if rst = '1' then
				cnt := MIN;
			elsif (rising_edge(clk)) then
					if cnt = MAX then
						cnt := MIN;
					else
						cnt := cnt + 1;
					end if;
			end if;
			count_out <= cnt;
		end process;
end architecture;

architecture arch_down of contador_up_down_two_arch is
begin
		process (clk, rst)
			variable cnt : integer range MIN to MAX;
		begin
			if rst = '1' then
				cnt := MAX;
			elsif (rising_edge(clk)) then
					if cnt = MIN then
						cnt := MAX;
					else
						cnt := cnt - 1;
					end if;
			end if;
			count_out <= cnt;
		end process;	
end architecture;

configuration ifsc_cfg of contador_up_down_2arch is
--	for arch_up end for;
	for arch_down end for;
end configuration;
  • Uso de uma porta de entrada UPDOWN fixada em '0' ou '1' para obter a mesma opção do IF GENERATE
entity contador_up_down_pin is
	generic
	(
		MIN : natural := 3;
		MAX : natural := 21
	);
	port
	(
		clk, rst		   : in std_logic;
		UPDOWN : natural := 1; -- 0 => up; 1 => down
		count_out   : out integer range MIN to MAX
	);
end entity;

architecture ifsc_v1 of contador_up_down_pin is
	signal cnt_down, cnt_up   : integer range MIN to MAX;
begin
		process (clk, rst)
			variable cnt : integer range MIN to MAX;
		begin
			if rst = '1' then
				cnt := MIN;
			elsif (rising_edge(clk)) then
					if cnt = MAX then
						cnt := MIN;
					else
						cnt := cnt + 1;
					end if;
			end if;
			cnt_up <= cnt;
		end process;

		process (clk, rst)
			variable cnt : integer range MIN to MAX;
		begin
			if rst = '1' then
				cnt := MAX;
			elsif (rising_edge(clk)) then
					if cnt = MIN then
						cnt := MAX;
					else
						cnt := cnt - 1;
					end if;
			end if;
			cnt_down <= cnt;
		end process;	
	count_out <= cnt_up when UPDOWN = 1 else cnt_down;
end architecture;


Encontro 22 (27 mai.)
  • Uso de componentes e instanciação de componentes.

Nesta parte da materia, o aluno deverá aprender a perguntar para uma ferramente de IA (e.g. ChatGPT) sobre um conteúdo específico formulando perguntas que conduzam a resposta e detalhamento desejado. De acordo com as respostas as perguntas precisam ser adaptadas. As respostas precisam ser avaliadas, pois podem conter erros graves. Exemplo de ordem de perguntas:

1) Como é feita a instanciação de componentes em VHDL?
2) Como devem ser os arquivos da entidade e do top level?
3) Quais tipos de instanciação existem? Além dessa instanciação nominal, também existe a posicional, podes explicar e exemplificar os dois casos?
4) O que devo fazer se não for utilizada uma porta de entrada ou de saída na instanciação de um componente?
Resposta do ChatGPT

A instanciação de componentes em VHDL é o processo de incluir e conectar componentes em um design hierárquico. Isso permite que você reutilize módulos já implementados em diferentes partes do projeto. O processo de instanciação segue algumas etapas, conforme descrito abaixo:

Declaração do componente

Antes de usar um componente em uma arquitetura, ele precisa ser declarado no escopo da arquitetura (a menos que você esteja usando bibliotecas com pacotes, onde a declaração pode ser omitida). A declaração define os sinais de entrada e saída do componente.

Exemplo de declaração do componente:

component MeuComponente
    generic (
        WIDTH : natural := 4
    )
    port (
        clk   : in  std_logic;
        reset : in  std_logic;
        data  : in  std_logic_vector(7 downto 0);
        valid : out std_logic
    );
end component;
Instanciação do componente

Após declarar o componente, ele pode ser instanciado dentro do corpo da arquitetura. Na instanciação, você define um "rótulo" (um nome para a instância) e conecta as portas do componente aos sinais locais do módulo que o utiliza. Existem duas formas principais de conectar as portas durante a instanciação:

Conexão posicional: As portas são conectadas pela ordem em que aparecem no port map. Deve-se garantir que a ordem dos sinais corresponda à ordem definida no componente.

Exemplo:

Instancia2: MeuComponente
    generic map (
         8
    )
    port map (
        clk_signal,
        reset_signal,
        input_data,
        output_valid
    );

Conexão nomeada: As portas são conectadas explicitamente pelo nome, o que é mais claro e menos propenso a erros. Este é o método preferido, especialmente em designs complexos.

Instancia1: MeuComponente
    generic map (
        WIDTH => 8
    )
    port map (
        clk   => clk_signal,
        reset => reset_signal,
        data  => input_data,
        valid => output_valid
    );

No exemplo acima

  • Instancia1 é o rótulo da instância.
  • clk, reset, data, e valid são os nomes das portas do componente.
  • clk_signal, reset_signal, input_data, e output_valid são os sinais do módulo que está utilizando o componente.

Em VHDL, os arquivos da entidade (componente) e do top level (nível superior do design) seguem uma estrutura organizada para garantir a modularidade, reutilização de código e facilidade de manutenção. Abaixo está uma explicação de como estruturar esses arquivos corretamente.

Arquivo da Entidade (Componente)

Um arquivo que define uma entidade (componente) deve conter:

  • A declaração da entidade, que define as entradas e saídas do módulo.
  • A arquitetura, que contém a lógica do componente (ou uma descrição de como ele é implementado).

Exemplo de Arquivo para o Componente:

-- Arquivo: MeuComponente.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Declaração da entidade
entity MeuComponente is
    port (
        clk   : in  std_logic;
        reset : in  std_logic;
        data  : in  std_logic_vector(7 downto 0);
        valid : out std_logic
    );
end MeuComponente;

-- Declaração da arquitetura
architecture Behavioral of MeuComponente is
begin
    -- Implementação da lógica do componente
    process(clk, reset)
    begin
        if reset = '1' then
            valid <= '0';
        elsif rising_edge(clk) then
            if data = "11111111" then
                valid <= '1';
            else
                valid <= '0';
            end if;
        end if;
    end process;
end Behavioral;

Neste exemplo:

  • Entidade: Define as portas (clk, reset, data, valid).
  • Arquitetura: Implementa a lógica funcional do componente.
Arquivo do Top Level

O arquivo do Top Level é responsável por integrar e conectar os componentes em um design hierárquico. Ele também define as entradas e saídas globais do sistema e instancia os componentes (como o MeuComponente no exemplo).

Exemplo de Arquivo Top Level:

-- Arquivo: TopLevel.vhd

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Declaração da entidade do Top Level
entity TopLevel is
    port (
        clk   : in  std_logic;
        reset : in  std_logic;
        data  : in  std_logic_vector(7 downto 0);
        valid : out std_logic
    );
end TopLevel;

-- Declaração da arquitetura do Top Level
architecture Structural of TopLevel is
    -- Sinais internos para conexão
    signal clk_signal   : std_logic;
    signal reset_signal : std_logic;
    signal input_data   : std_logic_vector(7 downto 0);
    signal output_valid : std_logic;

    -- Declaração do componente
    component MeuComponente
        port (
            clk   : in  std_logic;
            reset : in  std_logic;
            data  : in  std_logic_vector(7 downto 0);
            valid : out std_logic
        );
    end component;

begin
    -- Conectando sinais externos aos sinais internos
    clk_signal   <= clk;
    reset_signal <= reset;
    input_data   <= data;

    -- Instanciação do componente
    Instancia1: MeuComponente
        port map (
            clk   => clk_signal,
            reset => reset_signal,
            data  => input_data,
            valid => output_valid
        );

    -- Conectando o sinal interno à saída global
    valid <= output_valid;
end Structural;

Neste exemplo:

  • O Top Level possui sua própria entidade e arquitetura.
  • Ele instancia o componente MeuComponente e conecta os sinais externos (entradas e saídas globais) aos sinais internos que se conectam ao componente.
Organização dos Arquivos

Nomeação dos Arquivos:

  • O nome do arquivo deve corresponder ao nome da entidade definida dentro dele.
  • Por exemplo:
  • Para a entidade MeuComponente, o arquivo deve ser MeuComponente.vhd.
  • Para a entidade TopLevel, o arquivo deve ser TopLevel.vhd.

Separação de Arquivos:

  • Cada entidade e arquitetura deve estar em um arquivo separado.
  • Isso facilita a reutilização e a organização, especialmente em projetos maiores.

Hierarquia:

  • O Top Level deve ser o ponto de entrada do design. Ele referencia (ou instancia) os componentes.
Como Compilar e Simular

Para que os arquivos funcionem juntos, siga estas etapas:

Compilação:

  • Compile primeiro os arquivos dos componentes, como MeuComponente.vhd.
  • Depois, compile o arquivo do Top Level, que depende dos componentes.

Simulação:

  • Simule o arquivo do Top Level, pois ele integra todos os componentes.
  • Use um banco de testes (testbench) conectado ao Top Level para verificar o comportamento geral.

Ferramentas de Desenvolvimento:

  • Use ferramentas como ModelSim, Quartus, Xilinx Vivado ou GHDL para compilar, simular e sintetizar os arquivos.

Quando uma porta de entrada ou saída de um componente não é utilizada durante a instanciação em VHDL, você deve explicitamente informar isso no momento da conexão com o port map. Isso garante que o design seja claro e sem erros de compilação, já que todas as portas devem ser conectadas (mesmo que não sejam usadas).

A forma de lidar com isso depende se a porta é de entrada ou saída:

Para uma Porta de Entrada Não Utilizada

As portas de entrada devem receber um valor, mesmo que não sejam usadas na lógica. Nesse caso, você pode: Você pode conectar a porta a um literal (como '0', '1' ou "000...").

Exemplo:

Instancia1: MeuComponente
    port map (
        clk   => clk,
        reset => reset,
        data  => (others => '0'), -- Porta de entrada não utilizada
        valid => valid_signal
    );

No exemplo acima, a entrada data foi conectada a (others => '0'), indicando que todos os bits do vetor serão definidos como 0.

Para uma Porta de Saída Não Utilizada

As portas de saída não precisam ser conectadas diretamente a nada, mas é necessário indicar explicitamente que você está ignorando a saída. Para isso, você pode usar a palavra-chave open.

Exemplo:

Instancia3: MeuComponente
    port map (
        clk   => clk,
        reset => reset,
        data  => data_signal,
        valid => open -- Porta de saída não utilizada
    );

O open informa que a saída valid não será usada e evita que o compilador gere erros.

Ao fazer as mesmas perguntas para a mesma IA, as respostas podem ser diferentes. Por isso, todas respostas de IA deve passar por um processo de curadoria por humanos.

Encontro 23 a 27 (29 mai. a 05 jun.)
Timer de segundos, com mostrador SSD
  • Utilize como componente o contador BCD 00-99 já foi construido em aula anterior (contaBCD.vhd). Será necessário acrescentar um sinal de enable ao contador, também assegure-se que seja possível configurar a contagem de 00 até NN. Através do IF GENERATE disponibilize um contador que faça o overflow, e outro que pare ao chegar ao final da contagem. Também inclua uma entrada ZERAR, e outra de CONTAR, que tem a função dada pelo nome.
  • Utilize como componente o divisor de clock para gerar um sinal de enable para o contador a cada segundo (div_clk.vhd).
  • Projete um componente para converter de BCD para SSD - display de sete segmentos (bcd2ssd.vhd). Esse conversor deve ter uma entrada que permite escolher se o mostrador é do tipo anodo comum ou catodo comum, utilizando a instrução IF GENERATE. Para possibilitar mostrar ou não o zero, deve haver uma entrada que ao ser ativada fará com que o número zero não seja mostrada no mostrador.
  • Crie um projeto top_level no qual existem 4 instancias. 2 instancias do componente bcd2ssd.vhd uma em cada saída do contaBCD.vhd, o qual deverá contar apenas de 00 a 59 e reiniciar a contagem. Utilize o componente div_clk.vhd para habilitar o contaBCD.vhd.
  • Faça a simulação de cada um dos componentes e simule o timer completo.
  • Escolha um dos kits disponíveis no lab e implemente o projeto. Em seguida configure o circuito para ser implementado nos 2 mostradores (HEX0, HEX1).
1) Verifique se o mostrador do seu kit é do tipo anodo comum ou catodo comum.
2) Confira quais os clocks estão disponíveis no kit.
3) Defina quais serão as chaves de controle do timer. CONTAR, ZERAR, RESET
4) A entrada que permite esconder o zero deve ser configurada de modo que a primeira instância mostre o número zero, enquanto a segunda instância ocultará o zero.
entity timer_seg is
    generic (DEZENA : natural :=5; UNIDADE : natural := 9; FCLK := 5); -- para simulaçao
	port (
		CLK50MHZ, RESET : in std_logic;
		CONTAR       : std_logic;
		ZERAR        : std_logic;
		LED_SEG      : out std_logic;
		SSD_DEZENA   : out std_logic_vector(6 downto 0);
		SSD_UNIDADE  : out std_logic_vector(6 downto 0);
	);
end entity;

architecture ifsc of top_level is

begin

end architecture;

Figura 5.17 - RTL timer_sec
Fonte: Elaborado pelo autor.

A seguir o resultado da simulação do timer_sec de segundos desde 00 até 59 segundos. No próximo segundo é feito o overflow, retornando a 00. O teste da entrada CONTAR é feito mantendo ela ativa inicialmente, e desativando-a entre 7,5 e 12,3 segundos, o que para a contagem. Para testar a entrada ZERAR, ela é atividada no segundo 86,3, zerando o contador na próxima borda do clock. A contagem reinicia em 87 segundos quando o sinal ZERAR é desativado. O sinal RESET é apenas usado no início da simulação para inicializar os registradores.


Figura 5.18 - Simulação do timer_sec
Fonte: Elaborado pelo autor.

Figura 5.19 - Simulação do div_clk
Fonte: Elaborado pelo autor.

Figura 5.20 - Simulação do conta_bcd
Fonte: Elaborado pelo autor.

Figura 5.21 - Simulação do bcd2ssd (Catodo Comum)
Fonte: Elaborado pelo autor.

Figura 5.22 - Simulação do bcd2ssd (Anodo Comum)
Fonte: Elaborado pelo autor.


1.5 Unidade 4 - Maquinas de Estado Finitas

Unidade 4 - Maquinas de Estado Finitas
Encontro 25 (12 jun.)
  • O que é uma FSM - Finite State Machine

Figura 4.1 - Exemplo de diagrama de estados de uma FSM Fig4.1(a) e implementação em hardware da FSM Fig4.2(a)
Fonte: Figura 11.1 e 11.2 de [1].
  • Modelo básico em VHDL de FSM
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
----------------------------------------------------------
ENTITY < entity_name > IS
PORT (
	clk, rst : IN STD_LOGIC;
	entradas : IN < data_type > ;
	saidas : OUT < data_type >);
END entity;
----------------------------------------------------------
ARCHITECTURE < architecture_name > OF < entity_name > IS
	TYPE state IS (A, B, C, ...);
	SIGNAL pr_state, nx_state : state;
	-- ATTRIBUTE ENUM_ENCODING : STRING; --optional attribute
	-- ATTRIBUTE ENUM_ENCODING OF state : TYPE IS "sequential";
	-- ATTRIBUTE SYN_ENCODING OF state : TYPE IS "safe";
BEGIN
	------Logica Sequencial da FSM:------------
	PROCESS (clk, rst)
	BEGIN
		IF (rst = '1') THEN
			pr_state <= A;
		ELSIF rising_edge(clk) THEN
			-- apenas na borda do "clk" ocorre a mudança de estado da FSM
			pr_state <= nx_state;
		END IF;
	END PROCESS;
	------Logica Combinacional da FSM:------------
	PROCESS (pr_state, entradas)
	BEGIN
		------Valores default das saidas------------
                saidas <= < valor > ;
		CASE pr_state IS
			WHEN A =>
				-- é necessário um  WHEN para definir as "saidas" durante cada estado 
				-- e analisar as "entradas" para definir o próximo estado
				saidas <= < valor > ;   -- apenas se diferente do valor default
				IF (entradas = < valor >) THEN
					nx_state <= B;
					...
				ELSE
					nx_state <= A;
				END IF;
			WHEN B =>
				saidas <= < valor > ; -- apenas se diferente do valor default
				-- dependendo das "entradas", pode ser que hajam mais de um estados de destino
				IF (entradas = < valor >) THEN
					nx_state <= C;
				ELSIF (entradas = < valor >) THEN
					nx_state <= A;
				ELSE
					nx_state <= B;
				END IF;
			WHEN C =>
				saidas <= < valor > ; -- apenas se diferente do valor default
				-- a passagem para outro estado pode não depender de nenhuma "entrada"
				nx_state <= D;
			WHEN ...


		END CASE;
	END PROCESS;
	------Seção de Saída (opcional):-------
	-- Essa seção visa garantir que a saida new_output esteja sincronizada com o clk.  
	-- Se isso não for importante, ela pode ser suprimida
	PROCESS (clk, rst)
	BEGIN
		IF (rst = '1') THEN
			new_output <= < valor > ;
		ELSIF rising_edge(clk) THEN --or falling_edge(clk)
			new_output <= output;
		END IF;
	END PROCESS;
END architecture;
Dica
Se ao discrever uma FSM, faltar algum estado, o Quartus dará erro durante a compilação. Para resolver temporariamente isso pode se usar antes de encerrar o case
	WHEN others => 
		nx_state <= <initial_state>;
  • Usando o template acima descreva em VHDL a FSM indicada na Figura 11.1.
  • Faça a simulação da FSM com Modelsim utilizando um testbench em VHDL que faça a FSM seguir os estados

RSTAx=0Ax=1Ax=2Bx=2Bx=0Cx=0Cx=2Cx=1Ax=2Bx=1A

Ver pag. 277 a 280 de [1]
Note que o uso da atribuição manual do enum_encoding pode faz com que o compilador do Quartus não reconheça a FSM, mas use logica regular para representar o sistema.
Encontro 26 (17 jun.)
  • Controlador semafórico para duas vias
  • Use o template da FSM para modelar o controlador semafórico da figurar a seguir.

Figura 4.2 - FSM - Controlador semafórico para duas vias (diagrama de estados)
Fonte: Elaborado pelo autor.
Encontro 27 (24 jun.)
  • Diagrama de blocos de uma FSM completa. Diferença entre saída Moore e saída Mealy.
No diagrama abaixo, uma FSM (Finite State Machine) é modelada através dos seus componentes básicos:
  • Entradas - são os sinais que fazem a FSM evoluir para os próximos estados.
  • Clock: o clock (relógio) é o sinal que sincroniza as transições entre os estados. A mudança sempre ocorre na transição (borda) desse sinal.
  • Lógica do Próximo Estado: é um circuito combinacional que Determina o próximo estado com base no estado atual e nas entradas.
  • Registrador de Estado: Armazena o estado atual
  • Lógica de Saída Moore: Gera a saída apenas com base no estado atual.
  • Lógica de Saída Mealy: Gera a saída com base no estado atual e na entrada.

Figura 4.3 - Diagrama de blocos de um FSM
Fonte: Elaborado pelo autor.
  • Modelagem de FSM com Diagrama de Estados e ASM (Algorithmic State Machine).

Figura 4.4 - Blocos de um diagrama ASM
Fonte: Figure 10.4 de RTL Hardware Desing, P. Chu [2].


  • Exemplo da modelagem de um controlador de memória com modo de leitura BURST.

Figura 4.5 - Diagrama de estados de um controlador de memória
Fonte: Figure 10.3 de RTL Hardware Desing, P. Chu [2].

Figura 4.6 - ASM de um controlador de memória
Fonte: Figure 10.9 de RTL Hardware Desing, P. Chu [2].
  • A partir da descrição da FSM em diagrama de estados ou na forma ASM, é possível implementar essa FSM em VHDL. No código a seguir, é feita a descrição da FSM usando um código em dois segmentos, no qual o primeiro PROCESS realiza a atualização do Registrador de Estado, e o segundo PROCESS realiza a Lógica do Próximo Estado, Lógicas de Saída Moore e a Lógica de Saída Mealy.
library ieee;
use ieee.std_logic_1164.all;
entity mem_ctrl is
	port (
		clk            : in std_logic;
		reset          : in std_logic;
		mem, rw, burst : in std_logic;
		oe, we, we_me  : out std_logic
	);
end entity;
architecture two_seg_arch2 of mem_ctrl is
	type mc_state_type is
	(idle, read1, read2, read3, read4, write1);
	signal state_reg, state_next : mc_state_type;
begin
	process (clk, reset)
	begin
		if (reset = '1') then
			state_reg <= idle;
		elsif rising_edge(clk) then
			state_reg <= state_next;
		end if;
	end process;
	process (state_reg, mem, rw, burst)
		begin
			oe    <= '0';
			we    <= '0';
			we_me <= '0';
			case state_reg is
				when idle =>
					if mem = '1' then
						if rw = '1' then
							state_next <= read1;
						else
							we_me      <= '1';
							state_next <= write1;
						end if;
					else
						state_next <= idle;
					end if;
				when write1 =>
					we         <= '1';
					state_next <= idle;
				when read1 =>
					oe <= '1';
					if (burst = '1') then
						state_next <= read2;
					else
						state_next <= idle;
					end if;
				when read2 =>
					oe         <= '1';
					state_next <= read3;
				when read3 =>
					oe         <= '1';
					state_next <= read4;
				when read4 =>
					oe         <= '1';
					state_next <= idle;
			end case;
		end process;
end architecture;

Fonte: adaptado de RTL Hardware Desing, P. Chu.


Figura 4.7 - RTL do controlador de memória
Fonte: Quartus Light.

Figura 4.8 - FSM do controlador de memória
Fonte: Quartus Light.


  • Simulação do controlador de memória.

Na figura abaixo a FSM modelada tem duas saídas Moore ("oe" e "we"), e uma saída Mealy ("we_me"). Note que as saídas do tipo Moore sempre tem a duração de um período de clock, e elas não dependem diretamente de nenhuma entrada, mas são consequência do estado em que se encontra a FSM. No caso da saída Mealy, as entradas afeta diretamente a saída, conforme se pode ver os gliches da entrada "mem" são transmitidas para a saída "we_me".


Figura 4.9 - Simulação do controlador de memoria - diferença entre a saída Moore e saída Mealy
Fonte: Elaborado pelo autor.

Figura 4.10 - Simulação de escritas, leituras simples e leitura em burst no controlador de memoria
Fonte: Elaborado pelo autor.
Encontro 28 (26 jun.)
  • Circuito detector de borda

Figura 4.11 - Diagram de estados do detector de borda - implementação com saídas Moore
Fonte: Fonte: RTL Hardware Desing, P. Chu..
library ieee;
use ieee.std_logic_1164.all;
entity edge_detector1 is
   port(
      clk, reset: in std_logic;
      strobe: in std_logic;
      p1: out std_logic
   );
end edge_detector1;

architecture moore_arch of edge_detector1 is
   type state_type is (zero, up, one);
   signal state_reg, state_next: state_type;
begin
   -- state register
   process(clk,reset)
   begin
      if (reset='1') then
         state_reg <= zero;
      elsif (clk'event and clk='1') then
         state_reg <= state_next;
      end if;
   end process;
   -- next-state logic
   process(state_reg,strobe)
   begin
      case state_reg is
         when zero=>
            if strobe= '1' then
               state_next <= up;
            else
               state_next <= zero;
            end if;
         when up=>
            if strobe= '1' then
               state_next <= one;
            else
               state_next <= zero;
            end if;
         when one =>
            if strobe= '1' then
               state_next <= one;
            else
               state_next <= zero;
            end if;
      end case;
   end process;
   -- Moore output logic
   p1 <= '1' when state_reg=up else
         '0';
end moore_arch;

Fonte: RTL Hardware Desing, P. Chu.


Figura 4.12 - Simulação do detector de borda - implementação com saídas Moore
Fonte: Elaborado pelo autor.

Ao simular o detector de borda, percebe-se que o primeiro pulso (entre 140 e 180 ps) não foi detectado, pois não durou tempo suficiente para ter o estado atualizado no próximo clock. Isso ocorre pois na saída tipo Moore, as mudanças das saídas só acontecem sincronizadas com o clock. Note ainda que os pulsos em p1 tem a duração exata de um período de clock.


Figura 4.13 - Diagram de estados do detector de borda - implementação com saídas Mealy
Fonte: Fonte: RTL Hardware Desing, P. Chu..
library ieee;
use ieee.std_logic_1164.all;
entity edge_detector2 is
   port(
      clk, reset: in std_logic;
      strobe: in std_logic;
      p2: out std_logic
   );
end edge_detector2;

architecture mealy_arch of edge_detector2 is
   type state_type is (zero, one);
   signal state_reg, state_next: state_type;
begin
   -- state register
   process(clk,reset)
   begin
      if (reset='1') then
         state_reg <= zero;
      elsif (clk'event and clk='1') then
         state_reg <= state_next;
      end if;
   end process;
   -- next-state logic
   process(state_reg,strobe)
   begin
      case state_reg is
         when zero=>
            if strobe= '1' then
               state_next <= one;
            else
               state_next <= zero;
            end if;
         when one =>
            if strobe= '1' then
               state_next <= one;
            else
               state_next <= zero;
            end if;
      end case;
   end process;
   -- Mealy output logic
   p2 <= '1' when (state_reg=zero) and (strobe='1') else
         '0';
end mealy_arch;

Fonte: RTL Hardware Desing, P. Chu.


Figura 4.14 - Simulação do detector de borda - implementação com saídas Mealy
Fonte: Elaborado pelo autor.

Ao simular o detector de borda, percebe-se que o primeiro pulso (entre 140 e 180 ps) agora foi detectado. Isso ocorre pois na saída tipo Mealy, as mudanças das saídas dependem do estado atual e da entrada, e por isso não são sincronizadas com o clock. Note que agora os pulsos em p1 tem duração variável, e menor que um período de clock.


DESAFIO1
  • Descreva o diagrama de estados abaixo em VHDL, e simule o detector de borda. Note que agora os pulsos em p1 tem duração variável, mas todos terão duração um pouco maior que um período de clock.
DESAFIO2
  • Descreva os 3 diagramas de estado dos detectores de borda usando ASM.



Figura 4.15 - Diagram de estados do detector de borda - implementação com saídas Mealy melhorado
Fonte: Fonte: RTL Hardware Desing, P. Chu..

1.6 Unidade 5 - Metodologia RT (Register Transfer)

Unidade 5 - Metodologia RT (Register Transfer)

A fonte principal dessa unidade é o capítulo 11 e 12 do livro "RTL Hardware Desing, P. Chu.". É recomendado que os alunos leiam estes capítulos e usem como fonte de consulta.

Encontro 29 (1 jul.)
  • Um algoritmo é uma sequência detalhada de ações ou passos para realizar uma tarefa ou resolver um problema. Como a semântica das linguagens de programação tradicionais também se baseia na execução sequencial, um algoritmo pode ser facilmente convertido em um programa utilizando as construções dessas linguagens. O programa, então, é compilado em instruções de máquina e executado em um computador de uso geral.
  • Exemplo de algoritmo que soma de 4 números e divide o resultado por 8.
# entrada a(0), a(1), a(2) e a(3)
# saída out_q
size = 4
sum = 0;
for i in (0 to size - 1) do {
    sum = sum + a(i);
}
q = sum / 8;
r = sum rem 8;
if (r > 3) {
    q = q + 1;
}
out_q = q;

O algoritmo primeiro soma os elementos individuais e armazena o resultado em uma variável chamada sum. Em seguida, usa as operações de divisão (/) e de resto (rem) para encontrar o quociente e o resto. Se o resto for maior que 3, adiciona-se 1 extra ao quociente para realizar o arredondamento.

  • Uma variável em um algoritmo ou pseudocódigo pode ser interpretada como uma "localização de memória com um endereço simbólico" (ou seja, o nome da variável). Ela é usada para armazenar um resultado intermediário de um cálculo. Por exemplo, na segunda instrução, o valor 0 é armazenado na localização de memória com o endereço simbólico sum. Dentro do laço for, o valor a(i) é somado ao conteúdo atual de sum, e o resultado da soma é armazenado de volta na mesma localização. Na quarta instrução, o conteúdo de sum é dividido por 8 e o resultado é armazenado em uma localização de memória com um endereço simbólico.
  • A execução de um algoritmo é realizada de forma sequencial, e a ordem dos passos é importante. Por exemplo, a soma dos elementos precisa ser feita antes que a operação de divisão possa ser executada. Note que a ordem de execução pode depender de certas condições, como nos comandos for e if.
  • O algoritmo poderia ser descrito na forma estrutural baseada em fluxo de dados usando VHDL desenrolando o laço do algoritmo e converter as variáveis em sinais de conexão internos. Suponha que sum seja um sinal de 8 bits. Além disso a divisão por 8 pode ser implementado através de uma rotação a direita de 3 posições, sendo o resto os bits que foram rotacionados (2 downto 0).
sum(0) <= a(0);
sum(1) <= sum(0) + a(1);
sum(2) <= sum(1) + a(2);
sum(3) <= sum(2) + a(3);
q <= "000" & sum(3)(7 downto 3);
r <= "00000" & sum(3)(2 downto 0);
out_q <= q + 1 when (r > 3) else q;
  • A implementação estrutural baseada em fluxo de dados não é geral e só pode ser aplicada a algoritmos simples e triviais.
  • As duas variações a seguir do algoritmo anterior ilustram a limitação dessa abordagem.
  • Em primeiro, vamos considerar um vetor com 10 elementos. No pseudocódigo, isso pode ser feito substituindo o número 4 por 10 na primeira instrução. Isso aumenta o número de iterações do laço. Podemos desenrolar o laço (loop unrolling) e derivar a implementação estrutural baseada em fluxo de dados, o que exigiria nove somadores. Se o número de elementos do vetor continuar a crescer, o número de somadores aumentará proporcionalmente. Claramente, essa abordagem exige recursos de hardware excessivos e não é prática para um vetor maior.
  • Em segundo lugar, vamos supor que o tamanho do vetor não seja fixo, mas seja especificado por uma entrada adicional, n. Para realizar isso no algoritmo, basta substituir o valor fixo na primeira instrução por n, ou seja, fazer size = n. Isso será muito difícil de implementar com uma abordagem estrutural baseada em fluxo de dados. Como o hardware não pode se expandir ou encolher dinamicamente, seria necessário construir um circuito capaz de calcular os resultados para todos os possíveis valores de n e, em seguida, usar um multiplexador para direcionar o valor desejado para a saída.
  • A metodologia de transferência entre registradores (metodologia RT) é voltada para possibilitar realizar algoritmos em hardware.

As características principais dessa metodologia RT são:

  • Usar registradores para armazenar os dados intermediários e imitar as variáveis utilizadas em um algoritmo;
  • Usar um caminho de dados (datapath) personalizado para realizar todas as operações necessárias com os registradores;
  • Usar um caminho de controle (control path) personalizado para especificar a ordem das operações nos registradores.
  • Quando um algoritmo é implementado usando a metodologia RT, a manipulação e o roteamento dos dados são realizados por hardware dedicado. O circuito de manipulação de dados, a rede de roteamento e os registradores, juntos, são conhecidos como o caminho de dados (data path).
  • Como um algoritmo é descrito como uma sequência de ações, precisamos de um circuito que controle quando e quais operações de transferência entre registradores devem ocorrer. Esse circuito é conhecido como caminho de controle (control path).
  • Um caminho de controle pode ser implementado por uma máquina de estados finitos (FSM), que pode usar estados para impor a ordem dos passos desejados e caixas de decisão para imitar os desvios (branches) e iterações (laços) de um algoritmo.
  • Podemos usar uma máquina de estados finita estendida (FSM estendida) para descrever a operação geral do sistema. Ela é conhecida como FSM com caminho de dados (FSMD).
  • A principal diferença entre uma variável em um algoritmo e um registrador em um sistema com clock é que neste último as operações são feitas implicitamene como operações de transferência de registros (Operação básica de RT). Sua forma básica é:
rdest ← f(rsrc1, rsrc2, ...);
  • A interpretação dessa operação é:
  • Na borda de subida do clock, as saídas dos registradores rsrc1, rsrc2, etc., ficam disponíveis;
  • Essas saídas são enviadas para um circuito combinacional que executa a função f( ) (por exemplo: soma, multiplicação, deslocamento, etc.);
  • Na próxima borda de subida do clock, o resultado da operação é armazenado no registrador de destino rdest.
  • Visão geral do FSMD

Figura 4.1 - Diagrama de blocos básico de uma FSMD
Fonte: RTL Hardware Desing, P. Chu.

1.6.1 ATUAL

Encontro 30 (3 jul.) - Multiplicador por adição repetitivas.

Nota: Este exemplo é apresentado no livro RTL Hardware Desing, P. Chu na seção 11.3

Considere um multiplicador como os dois operandos da multiplicação sendo a_in e b_in, e a saída r_out onde todos os três sinais são do tipo UNSIGNED. Um algoritmo sequencial simples consiste em somar a_in repetidamente porb_in vezes. Por exemplo, 7×5 pode ser calculado como 7 + 7 + 7 + 7 + 7. Embora esse método não seja eficiente, ele é simples, e permite apreender a elaboração do diagrama ASMD e do hardware.

Pseudocódigo do algoritmo

Esse algoritmo pode ser representado pelo pseudocódigo:

if (a_in = 0 or b_in = 0) then 
    r = 0
else
    a = a_in
    n = b_in
    r = 0
    while (n ≠ 0) 
        r = r + a
        n = n - 1
r_out = r

Como o diagrama ASMD não possui uma construção de laço (loop), mas usa uma caixa de decisão com uma condição booleana para escolher um entre dois caminhos de saída possíveis. Portanto é semelhante a uma combinação de if com instrução goto. O pseudocódigo revisado fica assim:

    if (a_in = 0 or b_in = 0) then 
        r_out = 0
    else 
        a = a_in
        n = b_in
        r = 0
op:     r = r + a
        n = n - 1
        if (n = 0) then 
            goto stop
        else
            goto op
stop:   r_out = r
ASMD do algoritmo

Observe na ASMD abaixo que os sinais start (início) e ready (pronto) foram adicionados para permitir a operação sequencial do sistema. Imaginando o multiplicador sequencial como parte de um sistema principal, quando ele deseja executar uma operação de multiplicação, primeiro verifica o sinal ready. Se estiver alto, coloca os dois operandos nas entradas de dados a_in e b_in e ativa o sinal start. Ao detectar o sinal start, o multiplicador sequencial captura os operandos e inicia o processamento. Após a conclusão do cálculo, o sinal ready é ativado para informar ao sistema principal que o resultado está disponível em r_out.

O diagrama ASMD, mostrado na figura abaixo, segue de forma fiel o pseudoalgoritmo. Ele utiliza os registradores de dados n, a e r para representar as três variáveis do algoritmo, emprega caixas de decisão para implementar as estruturas condicionais (if) e utiliza operações de transferência entre registradores (operações RT) para executar as instruções sequenciais.


Figura 5.2 - Diagrama ASMD do algoritmo multiplicador L11.1
Fonte: RTL Hardware Desing, P. Chu.
FSMD do algoritmo

A construção do caminho de controle (DATA PATH) (1), (2) e (3) é a mesma utilizada com a máquina de estados (FSM). Os sinais dentro da caixa de decisão são as entradas da FSM. No diagrama ASMD, as expressões booleanas utilizam quatro sinais: start (comando externo) e a_is_0, b_is_0 e count_0 (sinais de status internos, provenientes do caminho de dados). Eles são ativados quando as condições correspondentes são satisfeitas.

A saída do caminho de controle inclui o sinal externo de status ready (pronto) e os sinais de controle que especificam as operações de transferência entre registradores (operações RT) no caminho de dados. Neste exemplo, foi usada a saída do registrador de estado como sinal de controle (idle, ab0, load, op).



Figura 5.3 - FSMD do algoritmo multiplicador L11.1
Fonte: RTL Hardware Desing, P. Chu.
  • Simulação essa FSMD, verificando o funcionamento da FSM através da simulação no MODELSIM. Teste com multiplicações menores (2 x 31 = 62); (31 x 2 = 62) e maiores (9 x 31 = 279) (31 x 9 = 279).
  • Anote a Fmax e meça o número de clocks (N_clk) transcorrido entre duas bordas de subida do sinal READY. Dica use dois cursores para medir o tempo total , e divida pelo período do clock utilizado na simulação.
  • Analise se ocorre alguma melhorias em termos de tempo de processamento (N_clk/Fmax) e número de elementos lógicos nas versões L11.1 a L11.3, L11.5 e L11.6. Também verifique se o resultado está correto em todas as versões. Verifique também a versão 11.4.

2 Avaliações

Durante o semestre serão realizadas entre 2 avaliações e várias atividades feitas extra classe.

Data das avaliações
  • A1 : Avaliação A1 (peso 35) XX/XX/2025
  • A2 : Avaliação A2 (peso 40) XX/XX/2025
  • AEs : Média ponderada das AEs (peso 25)
  • R1 e R2 : Recuperação de A1 e A2 :XX/XX/2025
  • Folha de consulta de VHDL

3 Atividade relâmpago (AR)

As atividades relâmpago devem ser entregues no Moodle da disciplina. A não entrega dessas atividades não gera nenhum desconto, apenas geram pontos de BÔNUS que são adicionados aos conceitos das avaliações A1 a AN.

4 Atividade extra-classe (AE)

A média ponderada das atividades extra-classe será considerada no cálculo do conceito final da UC. A entrega das mesmas será feita pelo Moodle, e cada dia de atraso irá descontar 0,2 na nota da atividade. Muitas dessas atividades também geram pontos de BÔNUS que são adicionados aos conceitos das avaliações A1 a AN. Para os BÔNUS só serão considerados projetos entregues no prazo.

4.1 AE1 - Conhecendo os dispositivos lógicos programáveis

AE1 - Conhecendo os dispositivos lógicos programáveis
Objetivos
  • Conhecer o Quartus Prime e as características dos dispositivos lógicos programáveis
  • Analisar os tempos de propagação em um circuito combinacional
  • Alterar configurações do compilador
  • Fazer a simulação funcional e temporal de um circuito combinacional.
Atividades
  • Ao escolher a família de FPGAS, escolha inicialmente um dispositivo da família Max II. Anote o código (Name), tensão de alimentação no núcleo (Core Voltage), Número de elementos lógicos configuráveis (LEs ou ALMs) desse dispositivo.
  • Capture as telas solicitadas e depois utilize-as no relatório da atividade.
  • Anote o tempo utilizado para cada uma das etapas do processo de compilação.
  • Anote o número de elementos lógicos configuráveis utilizados e o número de pinos utilizados, bem com o percentual em relação ao número total do dispositivo.
  • Anote algum erro (Error) ou alertas (Warnings) que o Quartus II indicar no painel de mensagens [Messages]
  • Ao final salve o projeto em um arquivo QAR (sugestão PJ1.QAR)
  • PASSO 2: Repita a atividade descrita em Conhecendo os dispositivos lógicos programáveis - QUARTUS PRIME, trocando a família e dispositivo a ser usado na implementação. Escolha nesta vez um dispositivos da família Cyclone IV E, Cyclone V, Cyclone 10 ou Arria 10. Anote o código (Name), tensão de alimentação no núcleo (Core Voltage), Número de elementos lógicos configuráveis (LEs ou ALMs) desse dispositivo.
  • Observe as mudanças que ocorrem tanto no tipo de elemento lógico configurável, no Chip Planner, no Pin Planner, e no circuito dos pinos de I/O. Note que estes FPGAs também apresenta novos componentes, tais como: Memória, Multiplicadores, DSP, PLL, DLL, etc. Verifique se consegue encontra-los no leiaute mostrado no Chip Planner, e documente aqueles que encontrar.
  • Compare os resultados obtidos nos procedimentos do PASSO 1 e PASSO 2.
  • Ao escolher a família de FPGAS, escolha um dispositivo FPGA da família Cyclone IV E. Anote o código (Name), tensão de alimentação no núcleo (Core Voltage), Número de elementos lógicos configuráveis (LEs ou ALMs) desse dispositivo.
  • Capture as telas mostradas no roteiro e depois utilize-as no relatório da atividade.
  • Anote o máximo tempo de propagação entre entrada e saída.
  • Anote o número de elementos lógicos utilizados e o número de pinos utilizados, bem com o percentual em relação ao número total do dispositivo.
  • Experimente modificar as configurações do compilador, conforme mostrado em Configurando o compilador. Se desejar mude a semente inicial trocando o valor de [Seed: 1]
  • Experimente inserir diferentes restrições de atraso máximo para o compilador, e analise o resultado obtido.
  • Anote algum erro (Error) ou alertas (Warnings) que o Quartus II indicar no painel de mensagens [Messages]
  • Ao final salve o projeto em um arquivo QAR (sugestão PJ2.QAR)
  • PASSO 4: Realize a simulação funcional do circuito hamming_distance
  • Capture as telas que mostram o circuito funcionando e depois utilize-as no relatório da atividade.
Entregas
  1. Envie um arquivo QAR contendo todos os arquivos necessário para compilar cada um dos projetos.
  2. Envie um relatório em PDF, incluindo as imagens capturadas (inclua um título para cada figura) e escreva para cada imagem um texto comentando o que representa. O relatório também deve ter a identificação (autor, título, data) uma breve introdução e uma conclusão. A descrição dos procedimentos feita na página wiki não precisa incluída no relatório.
  3. Use preferencialmente o Overleaf para gerar o relatório. Mas o uso de MS-Word, Libreoffice e Google Docs também é permitida.
  4. A entrega será feita através do Moodle da disciplina. Observe o prazo de entrega.

4.2 AE2 - Contador BCD 000 a 999

AE2 - Contador BCD 000 a 999
Objetivos
  • Construir um contador BCD de 000 a 999, utilizando um código de dois segmentos.
  • o primeiro segmento contém apenas a parte sequencial
  • o segundo segmento contém a parte combinatorial Next State Logic e lógica de saída
  • Analisar o desempenho de um circuito pelo Fmax.
Passo 1 - Projeto um contador BCD
  • Projete um contador BCD que conte, Unidades, Dezenas, Centenas.
entity contador_bcd is
    Port ( clock    : in  std_logic;
           reset    : std_logic;
           enable   : std_logic;
           centena  : out std_logic_vector(3 downto 0);
           dezena   : out std_logic_vector(3 downto 0);
           unidade  : out std_logic_vector(3 downto 0)
    );
end entity;
  • Capture o diagrama RTL do contador.
Passo 2 - Realize a simulação funcional do circuito do contador BCD
  • Faça a simulação do contador realizando a contagem de 0 a 999 e novamente até 999. Verifique se o contador retorna a zero após o overflow em 999.
  • Utilize como clock um sinal de 1 sec, e escolhe como escala de tempo o sec (segundo) no Wave do Modelsim.
  • Capture detalhes da simulação que mostram as contagem das Unidades, Dezenas, Centenas e também o Overflow. Use tantas capturas quantos achar necessário.
Passo 3 - Otimização de área e desempenho em Fmax
  • Use a família de FPGAS Cyclone IV E, o dispositivo EP4CE6E22A7. Anote a tensão de alimentação no núcleo (Core Voltage), Número de elementos lógicos configuráveis (LEs ou ALMs) desse dispositivo.
  • Utilize o procedimento descrito em Como obter o Fmax do projeto no Quartus.
  • Anote a Fmax do projeto (do modelo Slow 1200mV 125ºC), número de elementos lógicos utilizados e o número de pinos utilizados.
  • Utilize o procedimento indicado em Restringir a frequencia máxima de clock no Quartus, modificando a frequencia do clock de modo a forçar o compilador a obter melhores resultados.
  • Anote a Fmax do projeto, número de elementos lógicos utilizados e o número de pinos utilizados.
  • Experimente modificar as configurações do compilador, conforme mostrado em Configurando o compilador. Se desejar mude a semente inicial trocando o valor de [Seed: 1]
  • Anote a Fmax do projeto, número de elementos lógicos utilizados e o número de pinos utilizados, e eventuais elementos DSPs utilizados.
  • Apresente os resultados obtidos em uma tabela única.
Entregas
  1. Envie um arquivo QAR contendo todos os arquivos necessário para compilar o projeto.
  2. Envie um relatório em PDF, incluindo as imagens capturadas (inclua um título para cada figura) e escreva para cada imagem um texto comentando o que representa. O relatório também deve ter a identificação (autor, título, data) uma breve introdução e uma conclusão. A descrição dos procedimentos feita na página wiki não precisa incluída no relatório.
  3. O relatório deve indicar os ajustes que foram feitos para obter a maior Fmax e o menor número de elementos lógicos.
  4. Use preferencialmente o Overleaf para gerar o relatório. Mas o uso de MS-Word, Libreoffice e Google Docs também é permitida.
  5. A entrega será feita através do Moodle da disciplina. Observe o prazo de entrega.
Bônus
  • 1 ponto na Avaliação A1 para o(a) estudante que apresentar o projeto que funcione com a maior Fmax.
  • 0,5 ponto na Avaliação A1 para o(a) estudante que apresentar o projeto com o menor número de elementos lógicos.
  • 0,5 ponto na Avaliação A1 para o(a) estudante que apresentar o projeto que funcione com o segundo maior Fmax.
  • 0,3 ponto na Avaliação A1 para o(a) estudante que apresentar o projeto com o segundo menor número de elementos lógicos.
  • Em caso de empate, o critério de desempate é a data de entrega
  • Cada estudante pode receber no máximo 1 ponto na Avaliação A1 através da AE2.

4.3 AE3 - Contador BCD genérico

AE3 - Contador BCD genérico
Objetivos
  • Construir um contador BCD genérico, que permita definir qualquer número de dígitos BCD, desde 1 até N, utilizando um código de dois segmentos.
  • o primeiro segmento contém apenas a parte sequencial
  • o segundo segmento contém a parte combinatorial Next State Logic e lógica de saída
  • Criar tipos de dados e utiliza-los como portas da entity e sinais internos.
  • Utilizar estruturas de repetição de hardware.
  • Gerar e utilizar sinais de Enable para ativar os diversos contadores de 0 a 9.
  • Analisar o desempenho de um circuito pelo Fmax.
Passo 1 - Projeto um contador BCD genérico
  • Projete um contador BCD genérico, que conte, Unidades, Dezenas, Centenas, Unidades de Milhar, Dezenas de Milhar, etc. conforme solicitado no parâmetro genérico N.
  • Obtenha um contador para 3 digitos BCD, e capture o diagrama RTL do contador.
  • Obtenha um contador para 6 digitos BCD, e capture o diagrama RTL do contador.
Passo 2 - Realize a simulação funcional do circuito do contador BCD genérico
  • Faça a simulação do contador para N = 3 digitos BCD. Verifique se o contador retorna a zero após o overflow em 999.
  • Capture detalhes da simulação que mostram as contagem das Unidades, Dezenas, Centenas e também o Overflow. Use tantas capturas quantos achar necessário.
Passo 3 - Geração de um sinal de Enable a cada 1 ms.
  • Projete um circuito que gere um sinal de enable para o contador de miléssimo de segundo. O sinal de Enable deve durar exatamente o período do clock do kit a ser utilizado.
  • A geração do sinal de Enable só deve ocorrer se a entrada START estiver em 1.
  • Conecte esse circuito ao contador BCD com N = 5, sendo que os 2 digitos mais significativos devem contar os segundos, e os 3 dígitos menos significativos os milessimos de segundo.
Passo 4 - Implemente o contador com o divisor de clock no kit
  • Utilize o kit DE2-115 na implementação do contador de 0 a 99,999 sec. Ver Preparando para gravar o circuito lógico no FPGA
  • Ao escolher a família de FPGAS, escolha o dispositivo FPGA da família Cyclone IV E do kit e anote o código (Name), tensão de alimentação no núcleo (Core Voltage), Número de elementos lógicos configuráveis (LEs ou ALMs) desse dispositivo.
  • Utilize o procedimento indicado em Restringir a frequencia máxima de clock no Quartus, modificando a frequencia do clock de modo a definir o clock desejado como 50MHz, pois é o clock do kit a ser utilizado
  • Utilize o procedimento descrito em Como obter o Fmax do projeto no Quartus
  • Anote a Fmax do projeto, número de elementos lógicos utilizados e o número de pinos utilizados.
  • Verifique o funcionamento correto do contador comparando o tempo total da contagem 100 segundos com um cronometro (https://dollyclock.com/pt/stopwatch)
Dicas
  • Para replicar um hardware N vezes vai precisar instruções como FOR GENERATE e FOR LOOP.
  • Para gerar N saída BCD com 4 bits para cada dígito, será necessário criar um novo tipo de dado.
  type bcd_digits is array (natural range <>) of unsigned(3 downto 0);
  signal bcd  : bcd_digits(0 to N-1);
  • Para que um tipo seja conhecido na declaração das portas é necessario incluir essa declação do tipo em um pacote e incluir o pacote no arquivo.
-- FILE : ifsc_pkg.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

package ifsc_pkg is
    type bcd_digits is array (natural range <>) of unsigned(3 downto 0);
end package;
Entregas
  1. Envie um arquivo QAR contendo todos os arquivos necessário para compilar o projeto.
  2. Envie um relatório em PDF, incluindo as imagens capturadas (inclua um título para cada figura) e escreva para cada imagem um texto comentando o que representa. O relatório também deve ter a identificação (autor, título, data) uma breve introdução e uma conclusão. A descrição dos procedimentos feita na página wiki não precisa incluída no relatório.
  3. Use preferencialmente o Overleaf para gerar o relatório. Mas o uso de MS-Word, Libreoffice e Google Docs também é permitida.
  4. Grave um vídeo mostrando que o contador está funcionando de acordo com o cronometro, e disponibilize o link para o vídeo.
  5. A entrega será feita através do Moodle da disciplina. Observe o prazo de entrega.

4.4 AE4 - Análise de contadores digitais

AE4 - Análise de contadores digitais
Objetivos
  • Implementar e simular diferentes tipos de contadores digitais:
  • Contador binario sequencial;
  • Contador Gray;
  • Contador em anel;
  • Contador Johnson e
  • Contador LFSR.
  • Acrescentar um sinal de Enable em cada um dos contadores fornecidos em aula.
  • Todos os contadores devem ser implementados em 2 segmentos de código (parte sequencial e parte combinatória)
  • Analisar a influência do tipo de contador e número de bits sobre a área usada (número de elementos lógicos) e desempenho em velocidade (Fmax).
Divisão em equipes
  • As equipes (ou estudante individual) deverão modificar os contadores vistos em aula para que fique com a seguinte quantidade de bits:
E1 - 5 e 15 bits
E2 - 6 e 14 bits
E3 - 7 e 13 bits
E4 - 8 e 18 bits
E5 - 7 e 10 bits
E6 - 8 e 17 bits
I1 - 9 bits
I2 - 11 bits
I3 - 12 bits
I4 - 16 bits
I5 - 13 bits
I6 - 14 bits
I7 - 18 bits
I8 - 19 bits
I9 - 17 bits 
  • Nos trabalhos individuais apenas um contador de cada tipo será implementado e simulado.
  • Nos trabalhos em equipe dois contadores precisam ser implementados e simulados.
Em todos os contadores
  • Capture o diagrama RTL do contador.
  • Capture a tela de simulação que mostram a contagem (as contagens podem se bem altas, neste caso faça a contagem até 1000)
  • Ao escolher a família de FPGAS, escolha o dispositivo FPGA da família Cyclone IV E do kit e anote o código (Name), tensão de alimentação no núcleo (Core Voltage), Número de elementos lógicos configuráveis (LEs ou ALMs) desse dispositivo.
  • Utilize o procedimento indicado em Restringir a frequencia máxima de clock no Quartus, modificando a frequencia do clock de modo a definir o clock desejado como 50MHz, pois é o clock do kit a ser utilizado
  • Utilize o procedimento descrito em Como obter o Fmax do projeto no Quartus
  • Anote a Fmax do projeto, número de elementos lógicos utilizados e o número de pinos utilizados.
  • Salve o arquivo QAR com todos os arquivos VHDL, arquivos de simulação tb_XXX.do e wave_XXX.do, e demais necessaários para repetir o projeto.
Passo 1 - Projeto um contador binário sequencial
  • Adapte o código do contador binário para que seja genérico e uso o número de bits indicado para sua equipe.
Passo 2 - Contador Gray
  • Adapte o código do contador Gray para que seja genérico e uso o número de bits indicado para sua equipe.
Passo 3 - Contador em anel
  • Adapte o código do contador em anel para que seja genérico e uso o número de bits indicado para sua equipe.
Passo 4 - Contador Johnson
  • Adapte o código do contador Johnson para que seja genérico e uso o número de bits indicado para sua equipe.
Passo 5 - Contador LFSR
  • Adapte o código do contador LFSR para o número de bits indicado para sua equipe.
  • Ver como se pode implementar um contador LFSR de n bits.
  • Consultar [11] ou a página 5 de [12] para obter os termos que são usados na realimentação.
Entregas
  1. Envie um arquivo QAR contendo todos os arquivos necessário para compilar os projetos de todos os contadores.
  2. Envie um relatório em PDF, incluindo as imagens capturadas (inclua um título para cada figura) e escreva para cada imagem um texto comentando o que representa. O relatório também deve ter a identificação (autor, título, data) uma breve introdução e uma conclusão. A descrição dos procedimentos feita na página wiki não precisa incluída no relatório.
  3. Use preferencialmente o Overleaf para gerar o relatório. Mas o uso de MS-Word, Libreoffice e Google Docs também é permitida.
  4. A entrega será feita através do Moodle da disciplina. Observe o prazo de entrega.

4.5 AE15 - Timer de Segundos com Mostrador SSD

AE15 - Timer de Segundos com Mostrador SSD
Objetivos
  • Desenvolver um timer de segundos, exibindo a contagem de 00 até DU através de dois displays de sete segmentos (SSD).
  • Realizar um projeto hierárquico com componentes já utilizados anteriormente.
  • Utilizar parâmentros genéricos na instanciação dos componentes para definir o valor total da contagem DU.
  • Utilizar sinais ZERAR e CONTAR para controlar o contador BCD.
  • Possibilitar a ocultação do número zero na casa da dezena de segundo.
  • O projeto deverá ser implementado em FPGA em um dos kits disponíveis no LabSiDi.
PASSO 0
  • Adapte o contador BCD (contaBCD.vhd)
  • Baseie-se no contador desenvolvido em aula (faixa 00–99).
  • O clock do contador deverá ser o clock fornecido pelo kit (50MHz => 20ns)
  • São necessárias as seguintes modificações:
  • Adicione entradas: 1) ENABLE para controlar a contagem. 2) ZERAR: zera a contagem. 3) CONTAR: habilita ou desabilita a contagem.
  • Adicione os parâmetros (generics) para limitar a contagem de 00 até DU.
  • Use IF GENERATE para disponibilizar: 1) Um modo com overflow automático (contagem contínua). 2) Um modo com parada ao atingir o valor final (DU).
  • Simule o contador e verifique que funciona.
  • Use um CLOCK de 10Hz e um sinal de ENABLE de 1Hz com duty cycle de 10%
  • Teste o funcionamento das entradas ZERAR e CONTAR.
  • Verifique se os parâmetros genéricos D e U limitam corretamente a contagem. Teste com D = 2 e U = 3. O contador deve contar de 00 a 23.
  • Verifique se as opções de overflow e parada funcionam.
PASSO 1
  • Adapte o divisor de clock (div_clk.vhd)
  • Gere um pulso de habilitação (ENABLE_OUT) para o contador a cada 1 segundo, a partir do clock disponível no kit. O pulso deve durar o período de 1 clock (20ns)
  • Se ainda não tiver, inclua uma entrada de RESET assincrono neste componente.
  • Gere também um sinal de CLOCK_OUT de 1 segundo com duty cycle de 50% para ser conectado a um led externo.
  • Simule o divisor de clock e verifique que funciona.
  • Use um CLOCK de 50Hz e verifique se as saidas CLOCK_OUT e ENABLE_OUT estão corretas
PASSO 2
  • Projeto o conversor BCD para SSD (bcd2ssd.vhd)
  • Converta o valor de entrada BCD (0 a 9) para o padrão de 7 segmentos.
  • Usando IF GENERATE selecionar o tipo de display: a) Ânodo comum b) cátodo comum.
  • Inclua uma entrada OCULTA_ZERO para ocultar o zero no display.
  • Simule o conversor BCD para SSD e verifique que funciona.
  • Use na entradas valores BCD de 0 a 9 e verifique se as saidas SSD estão corretas
  • Teste com a opção ânodo comum e cátodo comum.
  • Teste se a entrada OCULTA_ZERO funciona.
PASSO 3
  • Implemente a entity Top-Level (timer_seg.vhd)
  • Instancie os componentes:
2x bcd2ssd.vhd → um para as unidades, outro para as dezenas.
1x contaBCD.vhd → configurado para contar de 00 a 59, com reset automático ao final.
1x div_clk.vhd → para gerar o sinal de ENABLE de 1 Hz e o clock de 1 sec.
entity timer_seg is
    generic (DEZENA  : natural := 5; UNIDADE : natural := 9; FCLOCK : natural := 50);
    port (
        CLOCK50MHz  : in std_logic;
        RESET_PB    : in std_logic;
        CONTAR_SW   : in std_logic;
        ZERAR_PB    : in std_logic;
        LED_1SEC    : out std_logic;
        SSD_DEZENA  : out std_logic_vector(6 downto 0);
        SSD_UNIDADE : out std_logic_vector(6 downto 0));
end entity;

Arquitetura sugerida
architecture ifsc of timer_seg is
    -- Sinais internos: BCD_UNIDADE, BCD_DEZENA, ENABLE_1SEC, etc.
    -- Declaração dos componentes usados
begin
    -- Instância do divisor de clock
    -- Instância do contador BCD
    -- Instâncias dos conversores BCD para SSD
end architecture;
  • O projeto deve ser sincrono, portanto todos os registradores (flip-flops) devem estar conectados ao CLOCK50MHz
  • Conecte o RESET_PB a entrada reset dos componentes div_clk.vhd e contaBCD.vhd.
  • Conecte a saída de ENABLE_OUT ao ENABLE do contador
  • Conecte a saída BCD das dezenas a um dos conversores bcd2ssd.vhd e a saída das unidades ao outro.
  • O display das dezenas podeve ocultar o zero, enquanto que o display das unidades sempre deve mostrar o zero.
  • Simule o timer para contar de 00 a 59 com reinício automático (overflow), e para display de cátodo comum.
  • Simule o timer para contar de 00 a 23 com parada, e para display de ânodo comum.
PASSO 4

Implemente o projeot no FPGA:

  • Escolha um dos kits disponíveis no laboratório.
  • Configure o projeto para exibir nos dois mostradores HEX (HEX0 e HEX1) ou DISP (DISP0 e DISP1).
  • Verifique se o display do kit é ânodo comum ou cátodo comum, e configure o bcd2ssd.vhd corretamente.
  • Verifique os clocks disponíveis no kit (Ex.: 50 MHz, 100 MHz), e configure corretamente o parâmetro FCLOCK, para que o ENABLE_1SEC e LED_1SEC estejam com período de 1 segundo.
  • Defina as chaves (ou botões) de controle para: CONTAR (SW), ZERAR (PB), RESET (PB). Verifique se os PUSH BUTTON (PB) são normalmente BAIXOS ou ALTOS. No segundo caso é necessário incluir um inversor no top-level.
  • Configure o parâmetro DU para que a contagem seja de 00 até 59 e depois reinicie automaticamente.
PASSO 5 - ENTREGAS
  • Documentar o experimento em um relatório técnico que contenha no mínimo:
  • Identificação (título, disciplina, data, autores);
  • Introdução;
  • Descrição dos componentes utilizados e do sistema completo. Cada componente deve ser descrito em termos funcionais, e também deve ter uma simulação que demonstre o seu funcinamento.
  • Documente todas as simulações com ondas claras para cada componente e para o sistema completo.
  • Resultados obtidos (com imagens dos itens importantes) e análise dos resultados;
  • Apresente tabelas da pinagem utilizada na configuração do FPGA, número de elementos lógicos usados em cada componente e pelo sistema completo.
  • Conclusão.
  • O relatório deve também responder as questões levantadas e mostrar que os objetivos apresentados na introdução foram atendidos.
  • O arquivo QAR contendo o projeto com todos os arquivos .vhd .do necessários para repetir o projeto e as simulações
  • O arquivo SOF usado na programação do FPGA.
  • Se for solicitado disponibilize vídeos demonstrando o funcionamento do timer.

4.6 AE16 - Controlador de Semáforo de duas vias

AE16 - Controlador de Semáforo de duas vias
Objetivos
  • Projetar uma Maquina de Estados Finita (FSM) para controlar um semáforo, com timer de segundos em componente externo.
  • Reutilizar o timer de segundos (binário)
  • Reutilizar o divisor de clock, e gerador de sinal de enable a cada segundo.
  • Realizar um projeto hierárquico.
  • Realize um projeto sincrono
  • Os componentes deve usar um código em dois segmentos, no qual o primeiro segmento realiza a atualização dos registrador, e o segundo segmento realiza a Lógica do Próximo Estado, e as Lógicas de Saída.
  • O projeto pode ser implementado em FPGA em um dos kits disponíveis no LabSiDi, mas não é obrigatório.
PASSO 0
  • Adapte o timer de segundas para contar em binário (timer_sec.vhd)
  • O clock do contador deverá ser o clock fornecido pelo kit (50MHz => 20ns)
  • Adicione entradas: 1) ENABLE para controlar a contagem. 2) ZERAR: zera a contagem. 3) CONTAR: habilita ou desabilita a contagem.
  • Adicione os parâmetros (generics) para limitar a contagem de 0 até MAX, onde MAX é o tempo máximo de verde do semáforo.
  • Simule o contador e verifique se funciona.
  • Use um CLOCK de 10Hz e um sinal de ENABLE de 1Hz com duty cycle de 10%
  • Teste o funcionamento das entradas ZERAR e CONTAR.
PASSO 1
  • Utilize o divisor de clock (div_clk.vhd) da atividade AE15. Nenhuma adaptação é necessária.
PASSO 2
  • Projeto da FSM do semáforo (FSM_semaforo.vhd)
  • Utilize o template fornecido para descrever a FSM representada pelo seguinte diagrama de estados:

Figura AE16a - FSM - Controlador semafórico para duas vias (diagrama de estados)
Fonte: Elaborado pelo autor.
  • Adicione uma saída Mealy enviar um signal ZERAR o timer que é usado nas transições da FSM.
  • Opcionalmente, você pode enviar um signal ZERAR usando uma saída Moore, que é ativada em 6 estados adicionais inseridos antes de entrar em cada um dos 6 estados da FSM.
  • Simule a FSM do semáforo e verifique se funciona.
  • Para testar, é necessário gerar manualmente o sinal de ATIVAR e os valores do timer para verificar o avanço dos estados da FSM
  • Verifique se o sinal de saida ZERAR é ativado corretamente.
  • Mostre claramente a FSM alternando entre AM1 e AM2, e depois fazendo 1 ou 2 ciclos de controle das vias.
PASSO 3
  • Implemente a entity Top-Level (timer_seg.vhd)
  • Instancie os componentes:
1x FSM_semaforo.vhd → FSM com saida ZERAR_CNT do tipo Mealy (ou Moore).
1x timer_sec.vhd → configurado para contar de 00 a 99, sendo reiniciado pelo sinal ZERAR_CNT .
1x div_clk.vhd → para gerar o sinal de ENABLE de 1 Hz e o clock de 1 sec.

Figura AE16b - Diagrama RTL do Controlador semafórico para duas vias
Fonte: Elaborado pelo autor.
entity controlador_semaforo IS
generic (
	tAMG : natural := 5; tVD1G : natural := 60; tVD2G : natural := 30; 
	Nbits_timer :natural := 6; 
	FCLK : natural := 50; Nbits_clk : natural := 6);
port (
	CLK50MHz : in std_logic;
	RESET_PB : in std_logic;	
	ATIVAR_SW : in std_logic;
	CONTAR_SW : in std_logic;
	LED_1sec	: out std_logic;
	vm1_LED, vd1_LED, am1_LED, vm2_LED, vd2_LED, am2_LED : out std_logic);
end entity;

Arquitetura sugerida
architecture ifsc of controlador_semaforo is
    -- Sinais internos: timer_std, zerar_cnt, ena_1sec, etc.
    -- Declaração dos componentes usados
begin
    -- Instância do divisor de clock
    -- Instância do timer binario de 1 sec
    -- Instância da FSM do semaforo 
end architecture;
  • O projeto global deve ser sincrono, portanto todos os registradores (flip-flops) devem estar conectados ao CLOCK50MHz
  • Simule o funcionamento da FSM no modo amarelo piscante (ativar = 0).

Figura AE16c - Simulação do Controlador semafórico para duas vias (amarelo piscante)
Fonte: Elaborado pelo autor.
  • Simule o funcionamento da FSM no modo normal (ativar = 1), permitindo pelo menos dois ciclos de VERDE nas duas vias controladas.

Figura AE16d - Simulação do Controlador semafórico para duas vias (ciclo verde)
Fonte: Elaborado pelo autor.
PASSO 4 - ENTREGAS
  • Documentar o experimento em um relatório técnico que contenha no mínimo:
  • Identificação (título, disciplina, data, autores);
  • Introdução;
  • Descrição dos componentes utilizados e do sistema completo. Cada componente deve ser descrito em termos funcionais, e também deve ter uma simulação que demonstre o seu funcionamento.
  • A FSM deve ser descrita usando um diagrama de estados ou um ASM.
  • Nas simulações de FSM é importante destacar a evolução dos estados da FSM.
  • Documente todas as simulações com ondas claras para cada componente e para o sistema completo.
  • Resultados obtidos (com imagens dos itens importantes) e análise dos resultados;
  • Descrever claramente o papel de cada membro da equipe no projeto. Lembre-se que todos devem ter um papel, e podem ser questionados sobre sua participação.
  • Conclusão.
  • O relatório deve também responder as questões levantadas e mostrar que os objetivos apresentados na introdução foram atendidos.
  • O arquivo QAR contendo o projeto com todos os arquivos .vhd .do necessários para repetir o projeto e as simulações


5 Referências Bibliográficas:

  1. 1,0 1,1 1,2 1,3 1,4 Erro de citação: Marca <ref> inválida; não foi fornecido texto para as refs chamadas PEDRONI2010b
  2. 2,0 2,1 2,2 Erro de citação: Marca <ref> inválida; não foi fornecido texto para as refs chamadas CHU2006

Será que uma boa parte do que fazemos com calculo digital será analógico no futuro? Future Computers Will Be Radically Different (Analog Computing)

Curso de Engenharia de Telecomunicações