Download do QSF mínimo para: botões, chaves e display (sete segmentos).
O projeto deve funcionar na placa DE0-CV, portanto, vamos iniciar verificando os recursos disponíveis.
Os periféricos do kit de desenvolvimento para FPGA, são conectados ao pinos do chip da FPGA de acordo com o projeto da placa.
Para poder configurar essas conexões, existe um arquivo com a extensão “qsf”. Ele está no diretório do projeto e possui o mesmo nome do projeto.
Ao criar um novo projeto, o Quartus cria um arquivo nome do projeto.qsf com as definições desse projeto. Porém, nesse momento ele não possui informação sobre quais pinos da FPGA serão utilizados.
É necessário adicionar a definição dos pinos, que serão utilizados, nesse arquivo
Abra o arquivo nome do projeto.qsf e adicione , após o cabeçalho, os conteúdos da listagem: DE0-CV_QSF_minimo.txt.
Os pinos que estão comentados não serão utilizados no curso e podem ser apagados.
Caso não utilize algum outro recurso, comente os seus pinos para evitar mensagens na compilação.
Não sobrescreva o cabeçalho do QSF criado pelo Quartus, adicione, após o cabeçalho, os conteúdos da listagem abaixo.
###Arquivo SDC Mínimo
O arquivo SDC (Synopsis Design Constraint) define os pinos e parâmetros para a verificação da temporização do projeto.
O arquivo está na raíz do diretório do projeto e tem o nome do tipo: “nome do projeto”.sdc
O conteúdo mínimo está abaixo:
# Quartus SDC constraints
# I/Os of the top-level block are called port,
# I/Os of the subblocks are called pin.
# So get_ports and get_pins commands must be used accordingly.
# The signals other than the I/Os are called net.
# The nets may be collected and constrained by using get_nets command, however most of the synthesis tools optimize out them or change the names.
# It is better to avoid using get_nets if not mandatory.
# Otherwise most of the synthesis tools require dont_touch attribute or something similar to keep the net.
# Constrain the main clock:
create_clock -name "CLOCK_50" -period 20.000ns -waveform {0.0 10.0} [get_ports {CLOCK_50}]
# Constrain the step by step clock (the period may be more than 80 ns but the waveform must be the same):
#create_clock -name "key(0)" -period 80.000ns -waveform {0.0 10.0} [get_ports {key[0]}]
# Constrain the JTAG clock used by In-System Memory Content Editor, SignalTap or Nios II:
#create_clock -period "30.303 ns" -name {altera_reserved_tck} {altera_reserved_tck}
# Only use one of the clocks at a time:
#set_clock_groups -exclusive -group {CLOCK_50} -group {key(0)}
# Constrain the derived clock:
#create_generated_clock -add -source CLOCK_50 -divide_by 62500 -name CLK_400HZ [get_pins {CLK_400HZ|q}]
#create_generated_clock -add -source [get_pins {CLK_400HZ|q}] -name CLK_10HZ [get_pins {CLK_10HZ|q}]
#set_false_path -from [get_pins {CLK_400HZ|q}] -to [get_pins {CLK_10HZ|d}]
# Automatically apply a generate clock on the output of phase-locked loops (PLLs)
# This command can be safely left in the SDC even if no PLLs exist in the design
derive_pll_clocks
derive_clock_uncertainty
# Constrain the input I/O path
set_input_delay -clock CLOCK_50 -max 3 [all_inputs]
set_input_delay -clock CLOCK_50 -min 2 [all_inputs]
# Constrain the output I/O path
set_output_delay -clock CLOCK_50 -max 3 [all_outputs]
set_output_delay -clock CLOCK_50 -min 2 [all_outputs]
# Setting LED outputs as false path, since no timing requirement
#set_false_path -from * -to [get_ports LEDR[*]]
# Setting HEX (7 segments) outputs as false path, since no timing requirement
#set_false_path -from * -to [get_ports HEX0[*]]
#set_false_path -from * -to [get_ports HEX1[*]]
#set_false_path -from * -to [get_ports HEX2[*]]
#set_false_path -from * -to [get_ports HEX3[*]]
#set_false_path -from * -to [get_ports HEX4[*]]
#set_false_path -from * -to [get_ports HEX5[*]]
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.buffer_3_state_8portas
port map(entrada => sinalLocal, habilita => sinalLocal, saida => sinalLocal);
Nome do arquivo: buffer_3_state_8portas.vhd
library IEEE;
use ieee.std_logic_1164.all;
entity buffer_3_state_8portas is
port(
entrada : in std_logic_vector(7 downto 0);
habilita : in std_logic;
saida : out std_logic_vector(7 downto 0));
end entity;
architecture comportamento of buffer_3_state_8portas is
begin
-- A saida esta ativa quando o habilita = 1.
saida <= "ZZZZZZZZ" when (habilita = '0') else entrada;
end architecture;
Pode ser necessário adicionar um registrador à entrada deste circuito.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.conversorHex7Seg
port map(dadoHex => sinalLocal,
apaga => sinalLocal,
negativo => sinalLocal,
overFlow => sinalLocal,
saida7seg => sinalLocal);
Nome do arquivo: conversorHex7Seg.vhd
library IEEE;
use ieee.std_logic_1164.all;
entity conversorHex7Seg is
port
(
-- Input ports
dadoHex : in std_logic_vector(3 downto 0);
apaga : in std_logic := '0';
negativo : in std_logic := '0';
overFlow : in std_logic := '0';
-- Output ports
saida7seg : out std_logic_vector(6 downto 0) -- := (others => '1')
);
end entity;
architecture comportamento of conversorHex7Seg is
--
-- 0
-- ---
-- | |
-- 5| |1
-- | 6 |
-- ---
-- | |
-- 4| |2
-- | |
-- ---
-- 3
--
signal rascSaida7seg: std_logic_vector(6 downto 0);
begin
rascSaida7seg <= "1000000" when dadoHex="0000" else ---0
"1111001" when dadoHex="0001" else ---1
"0100100" when dadoHex="0010" else ---2
"0110000" when dadoHex="0011" else ---3
"0011001" when dadoHex="0100" else ---4
"0010010" when dadoHex="0101" else ---5
"0000010" when dadoHex="0110" else ---6
"1111000" when dadoHex="0111" else ---7
"0000000" when dadoHex="1000" else ---8
"0010000" when dadoHex="1001" else ---9
"0001000" when dadoHex="1010" else ---A
"0000011" when dadoHex="1011" else ---B
"1000110" when dadoHex="1100" else ---C
"0100001" when dadoHex="1101" else ---D
"0000110" when dadoHex="1110" else ---E
"0001110" when dadoHex="1111" else ---F
"1111111"; -- Apaga todos segmentos.
saida7seg <= "1100010" when (overFlow='1') else
"1111111" when (apaga='1' and negativo='0') else
"0111111" when (apaga='0' and negativo='1') else
rascSaida7seg;
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
Nome do arquivo: decoder3x8.vhd
library ieee;
use ieee.std_logic_1164.all;
entity decoder3x8 is
port ( entrada : in std_logic_vector(2 downto 0);
saida : out std_logic_vector(7 downto 0)
);
end entity;
architecture comportamento of decoder3x8 is
begin
saida(7) <= '1' when (entrada = "111") else '0';
saida(6) <= '1' when (entrada = "110") else '0';
saida(5) <= '1' when (entrada = "101") else '0';
saida(4) <= '1' when (entrada = "100") else '0';
saida(3) <= '1' when (entrada = "011") else '0';
saida(2) <= '1' when (entrada = "010") else '0';
saida(1) <= '1' when (entrada = "001") else '0';
saida(0) <= '1' when (entrada = "000") else '0';
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
Nome do arquivo: decoderGeneric.vhd
library ieee;
use ieee.std_logic_1164.all;
entity decoderGeneric is
port ( entrada : in std_logic_vector(3 downto 0);
saida : out std_logic_vector(3 downto 0)
);
end entity;
architecture comportamento of decoderGeneric is
constant NOP : std_logic_vector(3 downto 0) := "0000";
constant LDA : std_logic_vector(3 downto 0) := "0001";
constant SOMA : std_logic_vector(3 downto 0) := "0010";
constant SUB : std_logic_vector(3 downto 0) := "0011";
constant CLRA : std_logic_vector(3 downto 0) := "1111";
begin
saida <= "0000" when entrada = NOP else
"XXXX" when entrada = LDA else
"XXXX" when entrada = SOMA else
"XXXX" when entrada = SUB else
"XXXX" when entrada = CLRA else
"0000"; -- NOP para os entradas Indefinidas
end architecture;
Abaixo temos o código para um multiplex de duas entradas.
A quantidade de bits de entrada é definida A largura do barramento de entrada (e saída) é definida pela declaração do generic.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.muxGenerico2x1 generic map (larguraDados => VALOR_LOCAL)
port map( entradaA_MUX => sinalLocal,
entradaB_MUX => sinalLocal,
seletor_MUX => sinalLocal,
saida_MUX => sinalLocal);
Nome do arquivo: muxGenerico2x1.vhd
library ieee;
use ieee.std_logic_1164.all;
entity muxGenerico2x1 is
-- Total de bits das entradas e saidas
generic ( larguraDados : natural := 8);
port (
entradaA_MUX, entradaB_MUX : in std_logic_vector((larguraDados-1) downto 0);
seletor_MUX : in std_logic;
saida_MUX : out std_logic_vector((larguraDados-1) downto 0)
);
end entity;
architecture comportamento of muxGenerico2x1 is
begin
saida_MUX <= entradaB_MUX when (seletor_MUX = '1') else entradaA_MUX;
end architecture;
Abaixo temos o código para um multiplex com o número de entradas configurável.
A largura do barramento de entrada (e saída) é definida pela declaração do generic.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.muxGenericoNx1 generic map (larguraEntrada => VALOR_LOCAL, larguraSelecao => VALOR_LOCAL)
port map( entrada_MUX => sinalLocal,
seletor_MUX => sinalLocal,
saida_MUX => sinalLocal);
Nome do arquivo: muxGenericoNx1.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity muxGenericoNx1 is
generic ( larguraEntrada : natural := 16;
larguraSelecao : natural := 4;
invertido : boolean := FALSE);
port (
entrada_MUX : in std_logic_vector(larguraEntrada-1 downto 0);
seletor_MUX : in std_logic_vector(larguraSelecao-1 downto 0);
saida_MUX : out std_logic
);
end entity;
architecture Behavioral of muxGenericoNx1 is
begin
tipo: if invertido generate
saida_MUX <= entrada_MUX((larguraEntrada-1) - to_integer(unsigned(seletor_MUX)));
else generate
saida_MUX <= entrada_MUX(to_integer(unsigned(seletor_MUX)));
end generate;
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.somadorGenerico generic map (larguraDados => VALOR_LOCAL)
port map( entradaA => sinalLocal, entradaB => sinalLocal, saida => sinalLocal);
Nome do arquivo: somadorGenerico.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- Biblioteca IEEE para funções aritméticas
entity somadorGenerico is
generic
(
larguraDados : natural := 32
);
port
(
entradaA, entradaB: in STD_LOGIC_VECTOR((larguraDados-1) downto 0);
saida: out STD_LOGIC_VECTOR((larguraDados-1) downto 0)
);
end entity;
architecture comportamento of somadorGenerico is
begin
saida <= STD_LOGIC_VECTOR(unsigned(entradaA) + unsigned(entradaB));
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.subtratorGenerico generic map (larguraDados => VALOR_LOCAL)
port map( entradaA => sinalLocal, entradaB => sinalLocal, saida => sinalLocal);
Nome do arquivo: subtratorGenerico.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- Biblioteca IEEE para funções aritméticas
entity subtratorGenerico is
generic
(
larguraDados : natural := 32
);
port
(
entradaA, entradaB: in STD_LOGIC_VECTOR((larguraDados-1) downto 0);
saida: out STD_LOGIC_VECTOR((larguraDados-1) downto 0)
);
end entity;
architecture comportamento of subtratorGenerico is
begin
saida <= STD_LOGIC_VECTOR(unsigned(entradaA) - unsigned(entradaB));
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.somaConstante generic map (larguraDados => VALOR_LOCAL, constante => VALOR_LOCAL)
port map( entrada => sinalLocal, saida => sinalLocal);
Nome do arquivo: somaConstante.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; --Soma (esta biblioteca =ieee)
entity somaConstante is
generic
(
larguraDados : natural := 32;
constante : natural := 4
);
port
(
entrada: in STD_LOGIC_VECTOR((larguraDados-1) downto 0);
saida: out STD_LOGIC_VECTOR((larguraDados-1) downto 0)
);
end entity;
architecture comportamento of somaConstante is
begin
saida <= std_logic_vector(unsigned(entrada) + constante);
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.estendeSinalGenerico generic map (larguraDadoEntrada => VALOR_LOCAL, larguraDadoSaida => VALOR_LOCAL)
port map (estendeSinal_IN => sinalLocal, estendeSinal_OUT => sinalLocal);
Nome do arquivo: estendeSinalGenerico.vhd
library ieee;
use ieee.std_logic_1164.all;
entity estendeSinalGenerico is
generic
(
larguraDadoEntrada : natural := 16;
larguraDadoSaida : natural := 32
);
port
(
-- Input ports
estendeSinal_IN : in std_logic_vector(larguraDadoEntrada-1 downto 0);
-- Output ports
estendeSinal_OUT: out std_logic_vector(larguraDadoSaida-1 downto 0)
);
end entity;
architecture comportamento of estendeSinalGenerico is
begin
estendeSinal_OUT <= (larguraDadoSaida-1 downto larguraDadoEntrada => estendeSinal_IN(larguraDadoEntrada-1) ) & estendeSinal_IN;
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.ULASomaSub generic map(larguraDados => VALOR_LOCAL)
port map (entradaA => sinalLocal, entradaB => sinalLocal, saida => sinalLocal, seletor => sinalLocal);
Nome do arquivo: ULASomaSub.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- Biblioteca IEEE para funções aritméticas
entity ULASomaSub is
generic ( larguraDados : natural := 4 );
port (
entradaA, entradaB: in STD_LOGIC_VECTOR((larguraDados-1) downto 0);
seletor: in STD_LOGIC;
saida: out STD_LOGIC_VECTOR((larguraDados-1) downto 0)
);
end entity;
architecture comportamento of ULASomaSub is
signal soma : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
signal subtracao : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
begin
soma <= STD_LOGIC_VECTOR(unsigned(entradaA) + unsigned(entradaB));
subtracao <= STD_LOGIC_VECTOR(unsigned(entradaA) - unsigned(entradaB));
saida <= soma when (seletor = '1') else subtracao;
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.ULA generic map(larguraDados => VALOR_LOCAL)
port map (entradaA => sinalLocal, entradaB => sinalLocal, saida => sinalLocal, seletor => sinalLocal, flagZero => sinalLocal);
Nome do arquivo: ULA.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- Biblioteca IEEE para funções aritméticas
entity ULA is
generic
(
larguraDados : natural := 8
);
port
(
entradaA, entradaB: in STD_LOGIC_VECTOR((larguraDados-1) downto 0);
seletor: in STD_LOGIC_VECTOR(2 downto 0);
saida: out STD_LOGIC_VECTOR((larguraDados-1) downto 0);
flagZero: out std_logic
);
end entity;
architecture comportamento of ULA is
--constant zero : std_logic_vector(larguraDados-1 downto 0) := (others => '0');
signal soma : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
signal subtracao : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
signal op_and : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
signal op_or : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
signal op_xor : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
signal op_not : STD_LOGIC_VECTOR((larguraDados-1) downto 0);
begin
soma <= STD_LOGIC_VECTOR(unsigned(entradaA) + unsigned(entradaB));
subtracao <= STD_LOGIC_VECTOR(unsigned(entradaA) - unsigned(entradaB));
op_and <= entradaA and entradaB;
op_or <= entradaA or entradaB;
op_xor <= entradaA xor entradaB;
op_not <= not entradaA;
saida <= soma when (seletor = "000") else
subtracao when (seletor = "001") else
entradaA when (seletor = "010") else
entradaB when (seletor = "011") else
op_xor when (seletor = "100") else
op_not when (seletor = "101") else
op_and when (seletor = "110") else
op_or when (seletor = "111") else
entradaA; -- outra opcao: saida = entradaA
--flagZero <= '1' when unsigned(saida) = unsigned(zero) else '0';
flagZero <= '1' when unsigned(saida) = 0 else '0';
end architecture;
Forma de instanciar no arquivo que utilizará este componente:
detectorSub0: work.edgeDetector(bordaSubida) port map (clk => CLOCK_50, entrada => (not KEY(0)), saida => auxReset);
detectorSub1: work.edgeDetector(bordaSubida) port map (clk => CLOCK_50, entrada => (not KEY(1)), saida => auxBt1);
detectorSub2: work.edgeDetector(bordaSubida) port map (clk => CLOCK_50, entrada => (not KEY(2)), saida => auxBt2);
detectorSub3: work.edgeDetector(bordaSubida) port map (clk => CLOCK_50, entrada => (not KEY(3)), saida => auxBt3);
Nome do arquivo: edgeDetector.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity edgeDetector is
Port ( clk : in STD_LOGIC;
entrada : in STD_LOGIC;
saida : out STD_LOGIC);
end entity;
architecture bordaSubida of edgeDetector is
signal saidaQ : STD_LOGIC;
begin
process(clk)
begin
if rising_edge(clk) then
saidaQ <= entrada;
end if;
end process;
saida <= entrada and (not saidaQ);
end architecture bordaSubida;
architecture bordaDescida of edgeDetector is
signal saidaQ : STD_LOGIC;
begin
process(clk)
begin
if rising_edge(clk) then
saidaQ <= entrada;
end if;
end process;
saida <= (not entrada) and saidaQ;
end architecture bordaDescida;
A largura dos dados (número de bits) é definida pelo generic.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.registradorGenerico generic map (larguraDados => VALOR_LOCAL)
port map (DIN => sinalLocal, DOUT => sinalLocal, ENABLE => sinalLocal, CLK => sinalLocal, RST => sinalLocal);
Nome do arquivo: registradorGenerico.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity registradorGenerico is
generic (
larguraDados : natural := 8
);
port (DIN : in std_logic_vector(larguraDados-1 downto 0);
DOUT : out std_logic_vector(larguraDados-1 downto 0);
ENABLE : in std_logic;
CLK,RST : in std_logic
);
end entity;
architecture comportamento of registradorGenerico is
begin
-- In Altera devices, register signals have a set priority.
-- The HDL design should reflect this priority.
process(RST, CLK)
begin
-- The asynchronous reset signal has the highest priority
if (RST = '1') then
DOUT <= (others => '0'); -- Código reconfigurável.
else
-- At a clock edge, if asynchronous signals have not taken priority,
-- respond to the appropriate synchronous signal.
-- Check for synchronous reset, then synchronous load.
-- If none of these takes precedence, update the register output
-- to be the register input.
if (rising_edge(CLK)) then
if (ENABLE = '1') then
DOUT <= DIN;
end if;
end if;
end if;
end process;
end architecture;
Para obter a referência de tempo para o relógio, é necessário dividir o clock de entrada por um valor X (inteiro) e obter a saida_clk.
Para tanto, pode-se utilizar o diagrama do divisorGenerico, mostrado abaixo.
O sinal clk do desenho deve ser conectado ao CLOCK_50 da placa de FPGA.
O funcionamento está descrito abaixo:
Faz a divisão do clock de entrada (CLOCK_50 do kit de desenvolvimento):
Usando um contador até 25.000.000;
Cuja saída irá ativar um flip-flop que divide por 2;
Assim, será obtido um sinal de 1 Hz, 50% de ciclo ativo e sincronizado com o clock do circuito.
O código desse divisor está mostrado abaixo:
Forma de instanciar no arquivo que utilizará este componente:
divisor : entity work.divisorGenerico
generic map (divisor => 25000000) -- divide por 50M.
port map (clk => sinalLocal, saida_clk => sinalLocal);
Nome do arquivo: divisorGenerico.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
entity divisorGenerico is
generic (divisor : natural := 8);
port(
clk : in std_logic;
saida_clk : out std_logic);
end entity;
-- O valor "n" do divisor, define a divisao por "2n".
-- Ou seja, n é metade do período da frequência de saída.
architecture divInteiro of divisorGenerico is
signal tick : std_logic := '0';
signal contador : integer range 0 to divisor+1 := 0;
begin
process(clk)
begin
if rising_edge(clk) then
if contador = divisor then
contador <= 0;
tick <= not tick;
else
contador <= contador + 1;
end if;
end if;
end process;
saida_clk <= tick;
end architecture divInteiro;
Para poder ler a base de tempo dentro do relógio, é necessário que ela esteja ligada a uma interface de leitura - como a mostrada no desenho abaixo.
Essa interface deve possuir o sinal da base tempo e dois endereços: o de leitura e o de limpeza da leitura (leitura feita).
Forma de instanciar no arquivo que utilizará este componente:
interfaceBaseTempo : entity work.divisorGenerico_e_Interface
port map (clk => sinalLocal,
habilitaLeitura => sinalLocal,
limpaLeitura => sinalLocal,
leituraUmSegundo => sinalLocal);
Nome do arquivo: divisorGenerico_e_Interface.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
entity divisorGenerico_e_Interface is
port(clk : in std_logic;
habilitaLeitura : in std_logic;
limpaLeitura : in std_logic;
leituraUmSegundo : out std_logic
);
end entity;
architecture interface of divisorGenerico_e_Interface is
signal sinalUmSegundo : std_logic;
signal saidaclk_reg1seg : std_logic;
begin
baseTempo: entity work.divisorGenerico
generic map (divisor => 5) -- divide por 10.
port map (clk => clk, saida_clk => saidaclk_reg1seg);
registraUmSegundo: entity work.flipflopGenerico
port map (DIN => '1', DOUT => sinalUmSegundo,
ENABLE => '1', CLK => saidaclk_reg1seg,
RST => limpaLeitura);
-- Faz o tristate de saida:
leituraUmSegundo <= sinalUmSegundo when habilitaLeitura = '1' else 'Z';
end architecture interface;
As memórias podem ser:
Somente Leitura (ROM);
Leitura e Escrita (RAM);
Síncronas:
Só alteram o conteúdo armazenado na transição do clock;
Só alteram o conteúdo sendo lido (exibido) a partir da transição do clock.
Assíncronas:
A partir do aparecimento de um novo endereço, elas exibem o conteúdo da posição de memória após o tempo de propagação.
A alteração do conteúdo é controlada pelo sinal de escrita (WR).
Uma característica do VHDL é o endereçamento de memória ser feito com um tipo inteiro.
Porém, para a simulação se beneficiar dos recursos multinível do tipo std_logic(_vector) precisamos que a interface dos componentes usem esse tipo de dados.
No caso das memórias, deve-se converter o valor do endereço de std_logic_vector para inteiro, conforme mostrado abaixo:
Este banco de registradores permite a leitura e a escrita de um mesmo registrador.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.bancoRegistradoresArqRegMem generic map (larguraDados => valorLocal, larguraEndBancoRegs => valorLocal)
port map ( clk => sinalLocal,
endereco => sinalLocal,
dadoEscrita => sinalLocal,
habilitaEscrita => sinalLocal,
saida => sinalLocal);
Nome do arquivo: bancoRegistradoresArqRegMem.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bancoRegistradoresArqRegMem is
generic
(
larguraDados : natural := 8;
larguraEndBancoRegs : natural := 3 --Resulta em 2^3=8 posicoes
);
-- Leitura e escrita de um registrador.
port
(
clk : in std_logic;
endereco : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
dadoEscrita : in std_logic_vector((larguraDados-1) downto 0);
habilitaEscrita: in std_logic := '0';
saida : out std_logic_vector((larguraDados -1) downto 0)
);
end entity;
architecture comportamento of bancoRegistradoresArqRegMem is
subtype palavra_t is std_logic_vector((larguraDados-1) downto 0);
type memoria_t is array(2**larguraEndBancoRegs-1 downto 0) of palavra_t;
-- Declaracao dos registradores:
shared variable registrador : memoria_t;
begin
process(clk) is
begin
if (rising_edge(clk)) then
if (habilitaEscrita = '1') then
registrador(to_integer(unsigned(endereco))) := dadoEscrita;
end if;
end if;
end process;
saida <= registrador(to_integer(unsigned(endereco)));
end architecture;
Este banco de registradores permite a leitura de dois registradores e a escrita em um terceiro registrador.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.bancoRegistradoresArqRegReg generic map (larguraDados => valorLocal, larguraEndBancoRegs => valorLocal)
port map ( clk => sinalLocal,
enderecoA => sinalLocal,
enderecoB => sinalLocal,
enderecoC => sinalLocal,
dadoEscritaC => sinalLocal,
escreveC => sinalLocal,
saidaA => sinalLocal,
saidaB => sinalLocal);
Nome do arquivo: bancoRegistradoresArqRegReg.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bancoRegistradoresArqRegReg is
generic
(
larguraDados : natural := 8;
larguraEndBancoRegs : natural := 5 --Resulta em 2^5=32 posicoes
);
-- Leitura de 2 registradores e escrita em 1 registrador simultaneamente.
port
(
clk : in std_logic;
enderecoA : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoB : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoC : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
dadoEscritaC : in std_logic_vector((larguraDados-1) downto 0);
escreveC : in std_logic := '0';
saidaA : out std_logic_vector((larguraDados -1) downto 0);
saidaB : out std_logic_vector((larguraDados -1) downto 0)
);
end entity;
architecture comportamento of bancoRegistradoresArqRegReg is
subtype palavra_t is std_logic_vector((larguraDados-1) downto 0);
type memoria_t is array(2**larguraEndBancoRegs-1 downto 0) of palavra_t;
-- Declaracao dos registradores:
shared variable registrador : memoria_t;
begin
process(clk) is
begin
if (rising_edge(clk)) then
if (escreveC = '1') then
registrador(to_integer(unsigned(enderecoC))) := dadoEscritaC;
end if;
end if;
end process;
saidaA <= registrador(to_integer(unsigned(enderecoA)));
saidaB <= registrador(to_integer(unsigned(enderecoB)));
end architecture;
Possuem a escrita síncrona e a leitura assíncrona. Porém, devido ao Quartus, em algumas máquinas, o bypass dos valores escritos e lidos no mesmo ciclo pode não funcionar.
Existem três soluções que, dependendo do Quartus, podem funcionar.
Porém, antes de modificar, é interessante compilar o seu projeto em uma NUK do laboratório de Arquitetura de Computadores. Elas estão com a versão antiga do Quartus, que não dava problema. Por favor, conversem com o técnico do laboratório.
Funcionou bem até o Quartus 18.
Uma possível solução, através da alteração de configurações do Quartus, está mostrada logo após este código.
Nome do arquivo: bancoRegistradores
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Baseado no apendice C (Register Files) do COD (Patterson & Hennessy).
entity bancoRegistradores is
generic
(
larguraDados : natural := 32;
larguraEndBancoRegs : natural := 5 --Resulta em 2^5=32 posicoes
);
-- Leitura de 2 registradores e escrita em 1 registrador simultaneamente.
port
(
clk : in std_logic;
--
enderecoA : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoB : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoC : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
--
dadoEscritaC : in std_logic_vector((larguraDados-1) downto 0);
--
escreveC : in std_logic := '0';
saidaA : out std_logic_vector((larguraDados -1) downto 0);
saidaB : out std_logic_vector((larguraDados -1) downto 0)
);
end entity;
architecture comportamento of bancoRegistradores is
subtype palavra_t is std_logic_vector((larguraDados-1) downto 0);
type memoria_t is array(2**larguraEndBancoRegs-1 downto 0) of palavra_t;
-- Declaracao dos registradores:
shared variable registrador : memoria_t;
constant zero : std_logic_vector(larguraDados-1 downto 0) := (others => '0');
begin
process(clk) is
begin
if (rising_edge(clk)) then
if (escreveC = '1') then
registrador(to_integer(unsigned(enderecoC))) := dadoEscritaC;
end if;
end if;
end process;
-- IF endereco = 0 : retorna ZERO
saidaB <= zero when to_integer(unsigned(enderecoB)) = to_integer(unsigned(zero)) else registrador(to_integer(unsigned(enderecoB)));
saidaA <= zero when to_integer(unsigned(enderecoA)) = to_integer(unsigned(zero)) else registrador(to_integer(unsigned(enderecoA)));
end architecture;
Possível Solução para o Problema com o Banco de Registradores da Versão Acima (Leitura durante Escrita)
A leitura durante a escrita (atualizar o valor de um registrador e ler esse valor no mesmo ciclo de clock) pode ter problemas no Quartus.
O Quartus pode gerar um aviso ou mesmo ficar silencioso.
Caso o Quartus fique silencioso:
Para o caso em que não existe aviso e mesmo assim os valores só são lidos, atualizados, no clock seguinte, pode-se resolver através da alteração da borda do clock (somente do banco de registradores) de rising_edge para falling_edge (ver exemplo comentado no código do banco de registradores).
Caso haja o aviso:
A leitura durante a escrita não funciona se houver o aviso abaixo:
Warning (276020): Inferred RAM node from synchronous design logic. Pass-through logic has been added to match the read-during-write behavior of the original design.
Solução que funcionou:
https://www.intel.com/content/www/us/en/programmable/quartushelp/13.0/mergedProjects/logicops/logicops/def_auto_ram_recognition.htm
Auto RAM Replacement Logic Option
This option can be set in the Assignment Editor, or you can set this option in the Analysis & Synthesis Settings page in the Settings dialog box. A logic option that allows the Compiler to find a set of registers and logic that can be replaced with the altsyncram or the lpm_ram_dp megafunction. Turning on this option may change the functionality of the design.
This option is useful for finding areas of the design that can be implemented more efficiently, and as a result, minimizing the area and maximizing the speed of the design.
This option must be assigned to a design entity or it is ignored. This option is available for all Altera devices supported by the Quartus II software except MAX series devices.
Outra opção, ainda não testada:
https://www.intel.com/content/www/us/en/programmable/quartushelp/13.0/mergedProjects/logicops/logicops/def_add_pass_through_logic_to_inferred_rams.htm
Add Pass-Through Logic to Inferred RAMs Logic Option
This option can be set in the Assignment Editor.
A logic option that allows the Compiler to add extra logic to inferred RAM blocks requiring a read-after-write mode that is not supported by RAM blocks in the current device. When a design reads and writes to the same memory address, this extra hardware guarantees that the read returns the new data being written to the address. However, the extra logic increases the area of the design and possibly reduces its performance if the design’s critical path includes the inferred RAM.
This option must be applied to an inferred RAM block or it is ignored. This option is available for all Altera devices.
Nome do arquivo: bancoRegistradores
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Baseado no apendice C (Register Files) do COD (Patterson & Hennessy).
entity bancoRegistradores is
generic
(
larguraDados : natural := 32;
larguraEndBancoRegs : natural := 5 --Resulta em 2^5=32 posicoes
);
-- Leitura de 2 registradores e escrita em 1 registrador simultaneamente.
port
(
clk : in std_logic;
--
enderecoA : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoB : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoC : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
--
dadoEscritaC : in std_logic_vector((larguraDados-1) downto 0);
--
escreveC : in std_logic := '0';
saidaA : out std_logic_vector((larguraDados -1) downto 0);
saidaB : out std_logic_vector((larguraDados -1) downto 0)
);
end entity;
architecture comportamento of bancoRegistradores is
subtype palavra_t is std_logic_vector((larguraDados-1) downto 0);
type memoria_t is array(2**larguraEndBancoRegs-1 downto 0) of palavra_t;
-- Declaracao dos registradores:
shared variable registrador : memoria_t;
constant zero : std_logic_vector(larguraDados-1 downto 0) := (others => '0');
begin
process(clk) is
begin
if (falling_edge(clk)) then
if (escreveC = '1') then
registrador(to_integer(unsigned(enderecoC))) := dadoEscritaC;
end if;
end if;
end process;
-- IF endereco = 0 : retorna ZERO
saidaB <= zero when to_integer(unsigned(enderecoB)) = to_integer(unsigned(zero)) else registrador(to_integer(unsigned(enderecoB)));
saidaA <= zero when to_integer(unsigned(enderecoA)) = to_integer(unsigned(zero)) else registrador(to_integer(unsigned(enderecoA)));
end architecture;
Nome do arquivo: bancoRegistradores
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
-- Baseado no apendice C (Register Files) do COD (Patterson & Hennessy).
entity bancoRegistradores is
generic
(
larguraDados : natural := 32;
larguraEndBancoRegs : natural := 5 --Resulta em 2^5=32 posicoes
);
-- Leitura de 2 registradores e escrita em 1 registrador simultaneamente.
port
(
clk : in std_logic;
--
enderecoA : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoB : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoC : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
--
dadoEscritaC : in std_logic_vector((larguraDados-1) downto 0);
--
escreveC : in std_logic := '0';
saidaA : out std_logic_vector((larguraDados -1) downto 0);
saidaB : out std_logic_vector((larguraDados -1) downto 0)
);
end entity;
architecture comportamento of bancoRegistradores is
subtype palavra_t is std_logic_vector((larguraDados-1) downto 0);
type memoria_t is array(2**larguraEndBancoRegs-1 downto 0) of palavra_t;
-- Declaracao dos registradores:
shared variable registrador : memoria_t;
signal bypassA, bypassB, zeroA, zeroB : std_logic;
signal selectA, selectB : std_logic_vector(1 downto 0);
constant zero : std_logic_vector(larguraDados-1 downto 0) := (others => '0');
begin
process(clk) is
begin
if (rising_edge(clk)) then
if (escreveC = '1') then
registrador(to_integer(unsigned(enderecoC))) := dadoEscritaC;
end if;
end if;
end process;
-- para resolver problemas de leitura e escrita no mesmo clock
bypassA <= '1' when (enderecoA = enderecoC) else '0';
bypassB <= '1' when (enderecoB = enderecoC) else '0';
-- IF endereco = 0 : retorna ZERO
zeroA <= '1' when to_integer(unsigned(enderecoA)) = to_integer(unsigned(zero)) else '0';
zeroB <= '1' when to_integer(unsigned(enderecoB)) = to_integer(unsigned(zero)) else '0';
selectA <= zeroA & bypassA;
selectB <= zeroB & bypassB;
saidaA <= dadoEscritaC when selectA = "01" else
zero when selectA = "10" else
zero when selectA = "11" else
registrador(to_integer(unsigned(enderecoA)));
saidaB <= dadoEscritaC when selectB = "01" else
zero when selectB = "10" else
zero when selectB = "11" else
registrador(to_integer(unsigned(enderecoB)));
end architecture;
Com o código do banco de registradores escolhido, para inicializar os valores dos registradores é necessário criar uma função de inicialização (initMemory) logo após a definição do tipo de dados memoria_t, conforme mostrado abaixo.
Em seguida, a inicialização precisar ser chamada na definição da variável registrador:
A função de inicialização é mostrada abaixo, juntamente com a chamada da mesma:
function initMemory
return memoria_t is variable tmp : memoria_t := (others => (others => '0'));
begin
-- Inicializa os endereços:
tmp(0) := x"AAAAAAAA"; -- Nao deve ter efeito.
tmp(8) := 32x"00"; -- $t0 = 0x00
tmp(9) := 32x"0A"; -- $t1 = 0x0A
tmp(10) := 32x"0B"; -- $t2 = 0x0B
tmp(11) := 32x"0C"; -- $t3 = 0x0C
tmp(12) := 32x"0D"; -- $t4 = 0x0D
tmp(13) := 32x"16"; -- $t5 = 0x16
return tmp;
end initMemory;
-- Declaracao dos registradores:
shared variable registrador : memoria_t := initMemory;
O seu conteúdo deve ter sido previamente gravado no dispositivo.
Possuem a leitura assíncrona.
A função initMemory carrega os dados na ROM da FPGA.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.memoriaROM generic map (dataWidth => VALOR_LOCAL, addrWidth => VALOR_LOCAL)
port map (Endereco => sinalLocal, Dado => sinalLocal);
Nome do arquivo: memoriaROM
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity memoriaROM is
generic (
dataWidth: natural := 8;
addrWidth: natural := 3
);
port (
Endereco : in std_logic_vector (addrWidth-1 DOWNTO 0);
Dado : out std_logic_vector (dataWidth-1 DOWNTO 0)
);
end entity;
architecture assincrona of memoriaROM is
type blocoMemoria is array(0 TO 2**addrWidth - 1) of std_logic_vector(dataWidth-1 DOWNTO 0);
function initMemory
return blocoMemoria is variable tmp : blocoMemoria := (others => (others => '0'));
begin
-- Inicializa os endereços:
tmp(0) := x"AA";
tmp(1) := x"42";
tmp(2) := x"43";
tmp(3) := x"44";
tmp(4) := x"45";
tmp(5) := x"46";
tmp(6) := x"47";
tmp(7) := x"55";
return tmp;
end initMemory;
signal memROM : blocoMemoria := initMemory;
begin
Dado <= memROM (to_integer(unsigned(Endereco)));
end architecture;
A definição do tipo de dados da memória lê um arquivo definido com os dados e os carrega na ROM da FPGA.
Nome do arquivo: romMIF
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity romMif is
generic
(
dataWidth : natural := 8;
addrWidth : natural := 8
);
port (
Endereco : in std_logic_vector (addrWidth-1 DOWNTO 0);
Dado : out std_logic_vector (dataWidth-1 DOWNTO 0)
);
end entity;
architecture initFileROM of romMif is
type memory_t is array (2**addrWidth -1 downto 0) of std_logic_vector (dataWidth-1 downto 0);
signal content: memory_t;
attribute ram_init_file : string;
attribute ram_init_file of content:
signal is "initROM.mif";
begin
Dado <= content(to_integer(unsigned(Endereco)));
end architecture;
Formato do arquivo initROM.mif:
-- Copyright (C) 2017 Intel Corporation. All rights reserved.
-- Your use of Intel Corporation's design tools, logic functions
-- and other software and tools, and its AMPP partner logic
-- functions, and any output files from any of the foregoing
-- (including device programming or simulation files), and any
-- associated documentation or information are expressly subject
-- to the terms and conditions of the Intel Program License
-- Subscription Agreement, the Intel Quartus Prime License Agreement,
-- the Intel FPGA IP License Agreement, or other applicable license
-- agreement, including, without limitation, that your use is for
-- the sole purpose of programming logic devices manufactured by
-- Intel and sold by Intel or its authorized distributors. Please
-- refer to the applicable agreement for further details.
WIDTH=8;
DEPTH=256;
ADDRESS_RADIX=DEC;
DATA_RADIX=HEX;
CONTENT BEGIN
--endereco : dado;
0 : 44;
1 : 41;
2 : 4C;
3 : 2F;
[4..5] : 20;
6 : 22;
[7..8] : 00;
9 : 01;
10 : 6A;
11 : AB;
12 : 1B;
13 : AC;
14 : 09;
15 : 00;
16 : AF;
17 : 00;
18 : AE;
19 : 11;
20 : 01;
[21..23] : 00;
24 : AE;
25 : 14;
[26..28] : 00;
29 : 8D;
30 : 0C;
[31..33] : 00;
34 : AE;
[35..37] : 00;
38 : 26;
[39..255] : 20;
END;
O endereçamento, no caso do MIPS, é feito considerando o byte.
O acesso é feito, no caso do MIPS, considerando a palavra de 32 bits.
Nome do arquivo: ROMMIPS
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity ROMMIPS IS
generic (
dataWidth: natural := 32;
addrWidth: natural := 32;
memoryAddrWidth: natural := 6 ); -- 64 posicoes de 32 bits cada
port (
Endereco : in std_logic_vector (addrWidth-1 downto 0);
Dado : out std_logic_vector (dataWidth-1 downto 0) );
end entity;
architecture assincrona OF ROMMIPS IS
type blocoMemoria IS ARRAY(0 TO 2**memoryAddrWidth - 1) OF std_logic_vector(dataWidth-1 downto 0);
signal memROM: blocoMemoria;
attribute ram_init_file : string;
attribute ram_init_file of memROM:
signal is "ROMcontent.mif";
-- Utiliza uma quantidade menor de endereços locais:
signal EnderecoLocal : std_logic_vector(memoryAddrWidth-1 downto 0);
begin
EnderecoLocal <= Endereco(memoryAddrWidth+1 downto 2);
Dado <= memROM (to_integer(unsigned(EnderecoLocal)));
end architecture;
A escrita é síncrona e a leitura assíncrona. Ou seja, se o endereço para a leitura mudar durante qualquer parte do período de clock, a saída mudará após o tempo de propagação - independendo da borda do clock.
Modelo retirado dos templates do Quartus e modificado para ter o endereço do tipo std_logic_vector e leitura assíncrona.
Forma de instanciar no arquivo que utilizará este componente:
nomeComponente : entity work.memoriaRAM generic map (dataWidth => VALOR_LOCAL, addrWidth => VALOR_LOCAL)
port map (addr => sinalLocal, we => sinalLocal, re => sinalLocal, habilita => sinalLocal, dado_in => sinalLocal, dado_out => sinalLocal, clk => sinalLocal);
Nome do arquivo: memoriaRAM
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity memoriaRAM is
generic (
dataWidth: natural := 8;
addrWidth: natural := 8
);
port
(
addr : in std_logic_vector(addrWidth-1 downto 0);
we, re : in std_logic;
habilita : in std_logic;
clk : in std_logic;
dado_in : in std_logic_vector(dataWidth-1 downto 0);
dado_out : out std_logic_vector(dataWidth-1 downto 0)
);
end entity;
architecture rtl of memoriaRAM is
-- Build a 2-D array type for the RAM
subtype word_t is std_logic_vector(dataWidth-1 downto 0);
type memory_t is array((2**addrWidth-1) downto 0) of word_t;
-- Declare the RAM signal.
signal ram : memory_t;
begin
process(clk)
begin
if(rising_edge(clk)) then
if(we = '1' and habilita='1') then
ram(to_integer(unsigned(addr))) <= dado_in;
end if;
end if;
end process;
-- A leitura é sempre assincrona e quando houver habilitacao:
dado_out <= ram(to_integer(unsigned(addr))) when (re = '1' and habilita='1') else (others => 'Z');
end architecture;
O endereçamento, no caso do MIPS, é feito considerando o byte.
O acesso é feito, no caso do MIPS, considerando a palavra de 32 bits.
Nome do arquivo: RAMMIPS
library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
entity RAMMIPS IS
generic (
dataWidth: natural := 32;
addrWidth: natural := 32;
memoryAddrWidth: natural := 6 ); -- 64 posicoes de 32 bits cada
port ( clk : IN STD_LOGIC;
Endereco : IN STD_LOGIC_VECTOR (addrWidth-1 DOWNTO 0);
Dado_in : in std_logic_vector(dataWidth-1 downto 0);
Dado_out : out std_logic_vector(dataWidth-1 downto 0);
we, re, habilita : in std_logic
);
end entity;
architecture assincrona OF RAMMIPS IS
type blocoMemoria IS ARRAY(0 TO 2**memoryAddrWidth - 1) OF std_logic_vector(dataWidth-1 DOWNTO 0);
signal memRAM: blocoMemoria;
-- Caso queira inicializar a RAM (para testes):
-- attribute ram_init_file : string;
-- attribute ram_init_file of memRAM:
-- signal is "RAMcontent.mif";
-- Utiliza uma quantidade menor de endereços locais:
signal EnderecoLocal : std_logic_vector(memoryAddrWidth-1 downto 0);
begin
-- Ajusta o enderecamento para o acesso de 32 bits.
EnderecoLocal <= Endereco(memoryAddrWidth+1 downto 2);
process(clk)
begin
if(rising_edge(clk)) then
if(we = '1' and habilita='1') then
memRAM(to_integer(unsigned(EnderecoLocal))) <= Dado_in;
end if;
end if;
end process;
-- A leitura deve ser sempre assincrona:
Dado_out <= memRAM(to_integer(unsigned(EnderecoLocal))) when (re = '1' and habilita='1') else (others => 'Z');
end architecture;
Este arquivo é somente um exemplo, antes de usar faça os ajustes necessários para a sua implementação.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
package bibliotecaComponentes is
component conversorHex7Seg is
port
(
-- Input ports
dadoHex : in std_logic_vector(3 downto 0);
apaga : in std_logic;
negativo : in std_logic;
overFlow : in std_logic;
-- Output ports
saida7seg : out std_logic_vector(6 downto 0)
);
end component conversorHex7Seg;
-----------------------------------------------------------------------------------
component bancoRegistradores is
generic
(
larguraDados : natural := 8;
larguraEndBancoRegs : natural := 5
);
-- Leitura de 2 registradores e escrita em 1 registrador simultaneamente.
port
(
clk : in std_logic;
--
enderecoA : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoB : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
enderecoC : in std_logic_vector((larguraEndBancoRegs-1) downto 0);
--
dadoEscritaC : in std_logic_vector((larguraDados-1) downto 0);
--
escreveC : in std_logic;
saidaA : out std_logic_vector((larguraDados -1) downto 0);
saidaB : out std_logic_vector((larguraDados -1) downto 0)
);
end component bancoRegistradores;
-----------------------------------------------------------------------------------
component divisorGenerico is
generic
(divisor : natural := 8);
port(
clk : in std_logic;
saida_clk : out std_logic
);
end component divisorGenerico;
-----------------------------------------------------------------------------------
component edgeDetector is
Port ( clk : in std_logic;
entrada : in std_logic;
saida : out std_logic);
end component edgeDetector;
-----------------------------------------------------------------------------------
component estendeSinalGenerico is
generic
(
larguraDadoEntrada : natural := 8;
larguraDadoSaida : natural := 8
);
port
(
-- Input ports
estendeSinal_IN : in std_logic_vector(larguraDadoEntrada-1 downto 0);
-- Output ports
estendeSinal_OUT: out std_logic_vector(larguraDadoSaida-1 downto 0)
);
end component estendeSinalGenerico;
-----------------------------------------------------------------------------------
component muxGenerico2x1 is
generic (
-- Total de bits das entradas e saidas
larguraDados : natural := 8
);
port (
-- -- Input ports
entradaA_MUX : in std_logic_vector(larguraDados-1 downto 0);
entradaB_MUX : in std_logic_vector(larguraDados-1 downto 0);
seletorMUX : in std_logic;
--
-- -- Output ports
saidaMUX : out std_logic_vector(larguraDados-1 downto 0)
);
end component muxGenerico2x1;
-----------------------------------------------------------------------------------
component registradorGenerico is
generic (
larguraDados : natural := 8
);
port (DIN : in std_logic_vector(larguraDados-1 downto 0);
DOUT : out std_logic_vector(larguraDados-1 downto 0);
ENABLE : in std_logic;
CLK,RST : in std_logic);
end component registradorGenerico;
-----------------------------------------------------------------------------------
component somaConstanteGenerico is
generic (
larguraDados : natural := 32;
incremento : natural := 4
);
port (
entrada: in STD_LOGIC_VECTOR((larguraDados-1) downto 0);
saida: out STD_LOGIC_VECTOR((larguraDados-1) downto 0)
);
end component somaConstanteGenerico;
-----------------------------------------------------------------------------------
component somadorGenerico is
generic ( larguraDados : natural := 32 );
port (
entradaA, entradaB: in STD_LOGIC_VECTOR((larguraDados-1) downto 0);
saida: out STD_LOGIC_VECTOR((larguraDados-1) downto 0) );
end component somadorGenerico;
-----------------------------------------------------------------------------------
component deslocadorGenerico is
generic (
larguraDadoEntrada : natural := 8;
larguraDadoSaida : natural := 8;
deslocamento : natural := 2 );
port (
-- Input ports
sinalIN : in std_logic_vector(larguraDadoEntrada-1 downto 0);
-- Output ports
sinalOUT: out std_logic_vector(larguraDadoSaida-1 downto 0) );
end component deslocadorGenerico;
end package bibliotecaComponentes;
Este arquivo é somente um exemplo, antes de usar faça os ajustes necessários para a sua implementação.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
package constantesMIPS is
-- Exemplos:
-- signal Instruction : Bit_Vector(15 downto 0);
-- alias OpCode : Bit_Vector(3 downto 0) is Instruction(15 downto 12);
-- subtype TypeWord is unsigned( 31 downto 0 );
-- type TypeArrayWord is array (natural range <>) of unsigned( 31 downto 0 );
-- constant FUNCT_WIDTH : natural := 6;
constant FUNCT_WIDTH : natural := 6;
constant OPCODE_WIDTH : natural := 6;
constant DATA_WIDTH : natural := 32;
constant ADDR_WIDTH : natural := 32;
constant REGBANK_ADDR_WIDTH : natural := 5;
constant ALU_OP_WIDTH : natural := 2;
constant CTRL_ALU_WIDTH : natural := 3;
constant CONTROLWORD_WIDTH : natural := 10;
-- codigos das instrucoes do DLX:
subtype opCode_t is std_logic_vector(OPCODE_WIDTH-1 downto 0);
subtype funct_t is std_logic_vector(FUNCT_WIDTH-1 downto 0);
subtype ctrlWorld_t is std_logic_vector(CONTROLWORD_WIDTH-1 downto 0);
subtype aluOp_t is std_logic_vector(ALU_OP_WIDTH-1 downto 0);
subtype ctrlALU_t is std_logic_vector(CTRL_ALU_WIDTH-1 downto 0);
subtype dado_t is std_logic_vector(DATA_WIDTH-1 downto 0);
subtype addr_t is std_logic_vector(ADDR_WIDTH-1 downto 0);
--
constant functADD : funct_t := "100000";
constant functSUB : funct_t := "100010";
constant functAND : funct_t := "100100";
constant functOR : funct_t := "100101";
constant functSLT : funct_t := "101010";
constant opCodeTipoR : opCode_t := "000000";
--
constant opCodeLW : opCode_t := "100011";
constant opCodeSW : opCode_t := "101011";
constant opCodeBEQ : opCode_t := "000100";
--
constant opCodeTipoJ : opCode_t := "000010";
--
-- Codigos da palavra de controle:
-- alias memWRsignal: std_logic is controlWord(0);
-- alias memRDsignal: std_logic is controlWord(1);
-- alias beqSignal: std_logic is controlWord(2);
-- alias muxUlaMem: std_logic is controlWord(3);
-- alias ulaOPvalue: std_logic_vector(1 downto 0) is controlWord(5 downto 4);
-- alias muxRtImed: std_logic is controlWord(6);
-- alias regcWRsignal:std_logic is controlWord(7);
-- alias muxRtRd: std_logic is controlWord(8);
-- alias muxPcBeqJ: std_logic is controlWord(9);
--
-- ControlWorld Bit: 9 8 7 6 5,4 3 2 1 0
--Instrução Opcode Mux1 Mux2 HabEscritaReg Mux3 ULAOp Mux4 BEQ HabLeMEM HabEscME
--Tipo R |00.0000 | 0 | 1 | 1 | 0 | 10 | 0 | 0 | 0 | 0 |
--LW |10.0011 | 0 | 0 | 1 | 1 | 00 | 1 | 0 | 1 | 0 |
--SW |10.1011 | 0 | 0 | 0 | 1 | 00 | 0 | 0 | 0 | 1 |
--BEQ |00.0100 | 0 | 0 | 0 | 0 | 01 | 0 | 1 | 0 | 0 |
--J |00.0010 | 1 | X | 0 | X | XX | X | X | 0 | 0 |
-- Mux1: mux([PC+4, BEQ]/J); Mux2: mux(Rt/Rd); Mux3: mux(Rt/imediato); Mux4: mux(ULA/mem).
constant ctrlTipoR: ctrlWorld_t := "0110100000";
constant ctrlTipoJ: ctrlWorld_t := "1X0XXXXX00";
constant ctrlTipoLW: ctrlWorld_t := "0011001010";
constant ctrlTipoSW: ctrlWorld_t := "0001000001";
constant ctrlTipoBEQ: ctrlWorld_t := "0000010100";
constant ctrlZERO: ctrlWorld_t := "0000000000";
-- -- ULA ---
subtype operacaoULA_t is std_logic_vector(2 downto 0);
constant execAndULA : operacaoULA_t := "000";
constant execOrULA : operacaoULA_t := "001";
constant execAddULA : operacaoULA_t := "010";
constant execSubULA : operacaoULA_t := "110";
constant execSltULA : operacaoULA_t := "111";
end package constantesMIPS;
Este arquivo é somente um exemplo, antes de usar faça os ajustes necessários para a sua implementação.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity entity_name is
generic (
DATA_WIDTH : natural := 8;
ADDR_WIDTH : natural := 8
);
port (
-- Input ports
dataIN : in std_logic_vector(DATA_WIDTH-1 downto 0);
enable : in std_logic;
clk : in std_logic;
<name> : in <type> := <default_value>;
-- Inout ports
<name> : inout <type>;
-- Output ports
dataOUT : out std_logic_vector(DATA_WIDTH-1 downto 0);
<name> : out <type> := <default_value>
);
end entity;
architecture arch_name of entity_name is
-- Declarations (optional):
-- signal <name> : std_logic;
-- signal <name> : std_logic_vector(<msb_index> downto <lsb_index>);
-- constant FUNCT_WIDTH : natural := 6;
-- subtype funct_t is std_logic_vector(FUNCT_WIDTH-1 downto 0);
-- constant functADD : funct_t := "100000";
-- constant functSUB : funct_t := "100010";
-- alias memWRsignal: std_logic is controlWord(0);
-- alias ulaOPvalue: std_logic_vector(1 downto 0) is controlWord(5 downto 4);
begin
-- Para instanciar, a atribuição de sinais (e generics) segue a ordem: (nomeSinalArquivoDefinicaoComponente => nomeSinalNesteArquivo)
-- regA: entity work.nome_do_componente generic map (DATA_WIDTH => DATA_WIDTH)
-- port map (dataIN => dataIN, dataOUT => RegAmuxA, enable => habRegA, clk => clk, rst => rst);
end architecture;