SIMULAÇÃO DA REDE HERMES
FERNANDO GEHM MORAES
Revisão: 26/abril/2018
O objetivo do presente tutorial é compreender a sinalização da interface da rede, e dominar o
processo de integração de módulos de hardware à mesma.
A rede HERMES, e seu ambiente de síntese, denominado ATLAS, está disponível para download no link:
https://corfu.pucrs.br/redmine/projects/atlas/wiki
.
Obtenha a distribuição do ambiente digitando:
wget
http://www.inf.pucrs.br/moraes/docs/atlas_distrib.tar
Configuração do ambiente de trabalho – arquivo atlas.sh
ATLAS=$HOME/atlas_distrib
export ATLAS_HOME=$ATLAS
export PATH=${ATLAS}:/soft64/mentor/ferramentas/modelsim/10.3c/modeltech/linux_x86_64:${PATH}
Inseri na raiz da sua conta um arquivo denominado .atlas:
{BrowserFile}/usr/bin/Firefox
Execute "source atlas.sh"
Se der problema para abrir, execute o linuxcompile
Atividade 1 – geração da rede para a simulação.
•
Executar a ferramenta atlas e criar um novo projeto, conforme Figura 1.
•
Selecionar a opção “NoC Generation”, definindo-se os parâmetros da rede conforme a Figura 2: rede sem
canais virtuais, controle de fluxo credit based, 3x3, flit de 16 bits, profundidade do buffer igual a 8.
Figura 2 - Interface gráfica para geração da NoC.
• Clicar no botão “Generate”, criando-se a rede 3x3. O botão “generate” cria a estrutura de diretórios
apresentada na Figura 3.
Figura 3 – Estrutura de diretórios gerada pela ferramenta Atlas, opção geração da NoC (MAIA).
Sinais de interface da rede HERMES
1. Como não iremos trabalhar com injeção de dados a partir de SystemC, remover do arquivo
topNoC.vhd
(no
diretório <work>\<nome do projeto>) a entidade inputmodule (na prática apagar da linha 96 a 136).
2. A figura 4 mostra:
a. Índice dos roteadores;
c. Sinais entre a interface de rede e o roteador. Notar que a transmissão é síncrona. Quando há dados para
transmitir, o sinal rx sobe, e dados são colocados em data_in. Se o roteador não está apto a receber
dados, o sinal credit_o vai para zero.
Figura 4 – Sinais de interface dos roteadores e índices das portas.
Atividade 2 – Escrita do processo responsável por injetar dados na rede
1. A simulação que iremos fazer inicialmente injetará dados no roteador 00, com destino para o roteador 22. Nesta
condição, devemos desabilitar a transmissão de dados por parte de todos os outros roteadores, exceto para o
roteador 00. Para isto, acrescente no final do arquivo
topNoC.vhd
para todos os roteadores, exceto o 00, as
seguintes linhas:
clock_rx(
endereço
) <= '0';
rx(
endereço
) <= '0';
Onde
endereço
assume os valores N0100, N0200, N0001, N0101, N0201, N0002, N0102, N0202
(inserção de 16 linhas de VHDL).
Cada par clock_rx/rx em zero impede que dados entrem nos roteadores, pois não há atividade do clock de
recepção do roteador, e o sinal rx nunca sinaliza que novos dados estão chegando.
2. Definição dos sinais necessários para a injeção de dados (inserir entre architecuture e begin):
signal address1, data1: std_logic_vector(15 downto 0);
signal ce1: std_logic;
•
Os sinais address1, data1 e ce1 correspondem a sinais com funcionalidade de uma interface padrão de
processador, ou seja, quando o ce estiver ativo, significa que há dado em data para o endereço address.
type packet is array (0 to 16) of std_logic_vector(15 downto 0);
•Esta linha define um pacote de 17 flits (0 a 16), sendo cada flit de largura de 16 bits.
constant pck1 : packet :=
( x"0022", x"000F", x"1001", x"2002", x"3003", x"4004", x"5005",
x"6006", x"7007", x"8008", x"9009", x"A00A",
x"B00B", x"C00C", x"D00D", x"E00E", x"F00F"
);
ROUTER 02 ROUTER12 ROUTER22 ROUTER 01 ROUTER11 ROUTER21 ROUTER 00 ROUTER10 ROUTER20 Network interfacedata_in
rx
credit_o
ad
dr
es
s
da
ta
ce
cr
ed
it_
o
ROUTER2
3
1
0
NI
Processor
4
Port indexes:
There is another signal in the interface,
named clock_rx which can be the same
of the clock router
•
Esta linha constrói o pacote o pacote que iremos transmitir. O primeiro flit corresponde ao endereço destino
do pacote (0022), tamanho do pacote (000F), e na seqüência os 15 flits do payload.
3. Escrita da interface de rede, a qual faz a ligação dos sinais de um IP (por exemplo, um processador) como
address1, data1 e ce1 aos sinais da NoC (credit_o, rx, data_in). Um exemplo de interface de rede, muito
simples, é dado abaixo:
clock_rx(N0000) <= clock(N0000); -- clock to inject data - the same of the router
process(reset, clock(N0000))
begin
if reset='1' then
rx(N0000) <= '0';
elsif clock(N0000)'event and clock(N0000)='1' then
if ce1='1' and address1=x"FFFF" then
rx(N0000) <= '1';
data_in(N0000) <= data1;
elsif credit_o(N0000)='1' then -- important: flow control
rx(N0000) <= '0';
end if;
end if;
end process;
O princípio de operação deste código VHDL é simples. Inicialmente atribui-se ao clock de recepção o
mesmo clock do roteador. Depois, um processo síncrono é responsável por gerenciar a geração do sinal rx.
Sempre que o processador ativar o CE e escrever algum dado no endereço 0xFFFF, este dado é repassado à
NoC, ativando-se o sinal rx. Notar que se não há crédito, o sinal rx permanece com valor ‘0’.
Acrescente este código após as linhas que desabilitaram injeção de tráfego para os demais roteadores.
4. O passo seguinte corresponde a escrever o comportamento de um processador, o qual deve injetar o pacote
definido no primeiro passo acima. Se fôssemos escrever um código C para a escrita de um pacote no ponteiro
data, teríamos:
do
{ while( credit_o==0 ); // waits until the availability of credit
store_word( data, address_noc);
}
A NoC, como já vimos no segundo passo, está mapeada no endereço 0xFFFF. Um exemplo de código
VHDL que simula o comportamento desta rotina C é apresentado abaixo. Insira este código após a
interface de rede.
address1 <= x"FFFF";
-- address generated by the processor
process
variable i : integer:= 0;
begin
ce1 <= '0';
wait for 400 ns;
-- time between packets
i := 0;
while i < 17 loop
if credit_o(N0000)='1' then
-- important: flow control
data1 <= pck1(i);
-- simulate a write( pck(i), address_noc)
ce1 <= '1';
wait for 20 ns;
ce1 <= '0';
wait for 20 ns;
i := i + 1;
else
wait for 20 ns;
end if;
end loop;
end process;
Atividade 3 - Simulação
1. Ir para o diretório de trabalho. Exemplo: cd {D:\noc_lab\noc1}
2. Modificar o arquivo simulate.do comentando a linha 6 (#sccom -g SC_NoC/SC_InputModule.cpp),
suprimindo as linhas 28 a 30 – elas inicializam a simulação e depois fecham o ModelSim.
3. Execute o script: do simulate.do. Pode demorar um pouco, pois há algumas rotinas SystemC compilada.
4. Inserir os sinais de interface, ou insira os comando abaixo no arquivo wave.do e execute no ModelSim do
wave.do. Estaremos visualizando as interfaces sinalizadas com círculos vermelhos na figura.
add wave -divider {FONTE DOS DADOS}add wave -format Logic /topnoc/ce1
add wave -format Literal -radix hexadecimal /topnoc/data1 add wave -divider {roteador 00 PORTA LOCAL} add wave -format Logic /topnoc/noc/router0000/clock add wave -format Logic /topnoc/noc/router0000/rx(4) add wave -format Logic /topnoc/noc/router0000/credit_o(4)
add wave -format Literal -radix hexadecimal /topnoc/noc/router0000/data_in(4) add wave -divider {roteador 00 PORTA LESTE}
add wave -format Logic /topnoc/noc/router0000/tx(0) add wave -format Logic /topnoc/noc/router0000/credit_i(0)
add wave -format Literal -radix hexadecimal /topnoc/noc/router0000/data_out(0) add wave -divider {roteador 10 PORTA LESTE}
add wave -format Logic /topnoc/noc/router0100/tx(0) add wave -format Logic /topnoc/noc/router0100/credit_i(0)
add wave -format Literal -radix hexadecimal /topnoc/noc/router0100/data_out(0) add wave -divider {roteador 20 PORTA NORTE}
add wave -format Logic /topnoc/noc/router0200/tx(2) add wave -format Logic /topnoc/noc/router0200/credit_i(2)
add wave -format Literal -radix hexadecimal /topnoc/noc/router0200/data_out(2) add wave -divider {roteador 21 PORTA NORTE}
add wave -format Logic /topnoc/noc/router0201/tx(2) add wave -format Logic /topnoc/noc/router0201/credit_i(2)
add wave -format Literal -radix hexadecimal /topnoc/noc/router0201/data_out(2) add wave -divider {roteador 22 PORTA LOCAL}
add wave -format Logic /topnoc/noc/router0202/tx(4) add wave -format Logic /topnoc/noc/router0202/credit_i(4)
add wave -format Literal -radix hexadecimal /topnoc/noc/router0202/data_out(4)
5. Execute a simulação por 2 us: run 2 us. Deve-se obter a janela abaixo:
ROUTER 02 ROUTER12 ROUTER22 ROUTER 01 ROUTER11 ROUTER21 ROUTER 00 2 ROUTER10 3 ROUTER20 4 5 1
Caminho determinado pelo algoritmo de roteamento XY
Figura 5– Simulação com transferência de um pacote do roteador 00 para o roteador 22.
Notar na simulação:
• O pacote começa a ser inserido na porta local do roteador 00 no tempo 400 ns. O pacote é
arbitrado e roteado em 5 ciclos de clock, estando disponível no tempo 500ns na porta leste do
roteador 00 (intervalo 1 da figura 4) .
• Os intervalos 2/3/4/5 mostram o caminhamento do pacote ao longo do caminho.
• A latência total do pacote é de 25 ciclos de clock (5 ciclos por hop) mais o tamanho do pacote, 17
ciclos de clock. Assim, em nanosegundos, a latência total é de (25+17)*20 = 840 ns.
• Somando-se o tempo 400 ns com 840 ns, tem-se o tempo de recepção do último flit, que é 1240
ns.
Observar no diretório de trabalho que vários arquivos textos foram gerados. Dentre estes, temos o
out8.txt, que corresponde à recepção dos dados no roteador 8 (22 no nosso caso). Simulando 10 us
obtemos a recepção de 9 pacotes:
0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 003F 1074024453 -1609912309 63 -1074024 390 35
0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 0075 1074024453 -1609912309 117 -107402 4336 37
0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 00AB 1074024453 -1609912309 171 -107402 4282 39
0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 00E1 1074024453 -1609912309 225 -107402 4228 40 0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 0117 1074024453 -1609912309 279 -107402 4174 42 0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 014D 1074024453 -1609912309 333 -107402 4120 44 0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 0183 1074024453 -1609912309 387 -107402 4066 45 0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 01B9 1074024453 -1609912309 441 -107402 4012 47
1
2
3
4
5
0022 000F 1001 2002 3003 4004 5005 6006 7007 8008 9009 A00A B00B C00C D00D E00E F00F 0000 0000 0000 01EF 1074024453 -1609912309 495 -107402 3958 49
Os valores “estranhos” ao final do pacote deve-se ao fato que não utilizamos SystemC para geração de
dados. São campos para cálculo de latência.
Pode-se observar também os dados passando em cada porta dos roteadores nos arquivos texto.
Atividade 4 – Simulação com a Interface Gráfica
• Execute novamente a ferramenta ATLAS, abrindo o projeto original. Gere novamente a rede para
obter os arquivos originais. Se for pedido um navegador, selecione /usr/bin/firefox
•
Lembre
: fazer backup do topnoc.vhd!
• Após a geração da rede, selecione Traffic Generation. Crie um cenário de simulação:
• Gere o tráfego a uma taxa de 160 Mbps para o destino 22. O cálculo é simples: o canal tem largura
de 16 bits. Logo, a 50MHz a banda do canal é de 800 Mbps. 20% corresponde a 160 Mbps. Ao
gerar-se o tráfego é aberta uma tela de confirmação
• Simular por 10 us:
Notar que foram transmitidos 10 pacotes, com taxa média de 20%, com a vazão igual a taxa de
injeção, pois não houveram colisões de pacotes. A latência média foi de 41 ciclos.
Atividade 5 – Exercício
1. Observe que a inserção dos flits ocorre a cada dois ciclos de clock. Durante um ciclo de clock o ce
está ativo, para sinalizar dado, e no outro ciclo de clock está em zero. Note entretanto, que na
recepção dos dados (data_out) os mesmo começam a ficar agrupados, resultando no destino a
recepção de um flit por ciclo de clock. O que explicaria este comportamento?
2. Modifique a geração de tráfego para duas origens enviando para o mesmo destino, 00à12 e 20à12.
Apresente a forma de onda resultante, analisando os resultados obtidos.
• Utilizar os seguintes pacotes:
constant pck1 : packet := ( x"0012", x"000F", x"1001", x"2002", x"3003", x"4004", x"5005", x"6006", x"7007", x"8008", x"9009", x"A00A", x"B00B", x"C00C", x"D00D", x"E00E", x"F00F" ); constant pck2 : packet := ( x"0012", x"000F", x"FFFF", x"EEEE", x"DDDD", x"CCCC", x"BBBB", x"AAAA", x"9999", x"8888", x"7777", x"6666", x"5555", x"4444", x"3333", x"2222", x"1111" );
• Sugestão para wave.do inicial:
add wave -divider {FONTE DOS DADOS 00} add wave -format Logic /topnoc/ce1
add wave -format Literal -radix hexadecimal /topnoc/data1 add wave -divider {FONTE DOS DADOS 20}
add wave -format Logic /topnoc/ce2
add wave -format Literal -radix hexadecimal /topnoc/data2 add wave -divider {roteador 12 PORTA LOCAL}
add wave -format Logic /topnoc/noc/router0102/tx(4) add wave -format Logic /topnoc/noc/router0102/credit_i(4)
add wave -format Literal -radix hexadecimal /topnoc/noc/router0102/data_out(4)
• Modifique o intervalo entre pacotes para 200 ns (wait for 200 ns;).
• Após a simulação, digitar o comando quit –sim, pode-se abrir o arquivo out7.txt o qual contém o
relatório dos pacotes recebidos. Há valores inseridos no final de cada linha, que seriam utilizados
pelas rotinas SystemC, desconsidere-os. Considerar apenas a parte relativa ao pacote. Os pacotes
foram corretamente recebidos?
********************************************************************************** noc.vhd --> instancia os roteadores e o gerador de relatórios
********************************************************************************** library IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use work.HermesPackage.all; entity NOC is port( clock : in regNrot; reset : in std_logic; clock_rxLocal : in regNrot; rxLocal : in regNrot; data_inLocal : in arrayNrot_regflit; credit_oLocal : out regNrot; clock_txLocal : out regNrot; txLocal : out regNrot;
data_outLocal : out arrayNrot_regflit; credit_iLocal : in regNrot);
end NOC;
architecture NOC of NOC is
signal clock_rxN0000, clock_rxN0100, clock_rxN0200, clock_rxN0300 : regNport; ....
signal credit_iN0003, credit_iN0103, credit_iN0203, credit_iN0303 : regNport; begin
Router0000 : Entity work.RouterBL generic map( address => ADDRESSN0000 ) port map( clock => clock(N0000), reset => reset, clock_rx => clock_rxN0000, rx => rxN0000, data_in => data_inN0000, credit_o => credit_oN0000, clock_tx => clock_txN0000, tx => txN0000, data_out => data_outN0000, credit_i => credit_iN0000); Router0100 : Entity work.RouterBC generic map( address => ADDRESSN0100 ) port map( clock => clock(N0100), reset => reset, clock_rx => clock_rxN0100, rx => rxN0100, data_in => data_inN0100, credit_o => credit_oN0100, clock_tx => clock_txN0100, tx => txN0100, data_out => data_outN0100, credit_i => credit_iN0100); ... fios de ligação -- ROUTER 0000 -- EAST port clock_rxN0000(0)<=clock_txN0100(1); rxN0000(1)<='0'; ....
-- the component below, router_output, must be commented to simulate without SystemC router_output: Entity work.outmodulerouter
port map( clock => clock(N0000), reset => reset, ... credit_ir15p3 => credit_iN0303(SOUTH)); end NOC; ********************************************************************************** routercc --> roteador central
**********************************************************************************
entity RouterCC is
generic( address: regmetadeflit); port( clock: in std_logic; reset: in std_logic; clock_rx: in regNport; rx: in regNport; data_in: in arrayNport_regflit; credit_o: out regNport; clock_tx: out regNport; tx: out regNport;
data_out: out arrayNport_regflit; credit_i: in regNport);
end RouterCC;
architecture RouterCC of RouterCC is
signal h, ack_h, data_av, sender, data_ack: regNport := (others=>'0'); signal data: arrayNport_regflit := (others=>(others=>'0'));
signal mux_in, mux_out: arrayNport_reg3 := (others=>(others=>'0')); signal free: regNport := (others=>'0');
begin
FEast : Entity work.Hermes_buffer port map(... );
FWest : Entity work.Hermes_buffer port map(... );
FNorth : Entity work.Hermes_buffer port map(... );
FSouth : Entity work.Hermes_buffer port map(... );
FLocal : Entity work.Hermes_buffer port map(... );
SwitchControl : Entity work.SwitchControl(AlgorithmXY) port map(... );
CrossBar : Entity work.Hermes_crossbar port map(... );
********************************************************************************** buffer.vhd ********************************************************************************** entity Hermes_buffer is port( clock: in std_logic; reset: in std_logic; clock_rx: in std_logic; rx: in std_logic; data_in: in regflit; credit_o: out std_logic; h: out std_logic; ack_h: in std_logic; data_av: out std_logic; data: out regflit; data_ack: in std_logic; sender: out std_logic); end Hermes_buffer;
architecture Hermes_buffer of Hermes_buffer is
type fifo_out is (S_INIT, S_HEADER, S_SENDHEADER, S_PAYLOAD, S_END); signal EA : fifo_out;
signal buf: buff := (others=>(others=>'0')); signal read_pointer,write_pointer: pointer ; signal counter_flit: regflit ;
signal data_available : std_logic; begin
--- -- IF:
-- write_pointer /= read_pointer : FIFO WITH SPACE TO WRITE -- read_pointer + 1 == write_pointer : FIFO EMPTY
-- write_pointer == read_pointer : FIFO FULL
--- --- -- PROCESS TO WRITE INTO THE FIFO
--- process(reset, clock)
begin
if reset='1' then
write_pointer <= (others => '0'); elsif clock'event and clock='1' then
-- if receiving data and fifo isn't empty, record data on fifo and increase write pointer if rx = '1' and write_pointer /= read_pointer then
buf(CONV_INTEGER(write_pointer)) <= data_in; write_pointer <= write_pointer + 1; end if; end if; end process;
-- If fifo isn't empty, credit is high. Else, low
credit_o <= '1' when write_pointer /= read_pointer else '0';
--- -- PROCESS TO READ THE FIFO
--- -- Available the data to transmission (asynchronous read)
data <= buf(CONV_INTEGER(read_pointer)); process(reset, clock) begin if reset='1' then h <= '0'; data_available <= '0'; sender <= '0';
-- Initialize the read pointer with one position before the write pointer read_pointer <= (others=>'1');
EA <= S_INIT;
elsif clock'event and clock='1' then case EA is
when S_INIT =>
counter_flit <= (others=>'0'); h<='0';
data_available <= '0'; -- If fifo isn`t empty
if (read_pointer + 1 /= write_pointer) then -- Routing request to Switch Control h<='1';
-- consume de 1st flit - target address read_pointer <= read_pointer + 1; EA <= S_HEADER;
end if;
when S_HEADER =>
-- When the Switch Control confirm the routing if ack_h='1' then
h <= '0'; -- Disable the routing request
sender <= '1'; -- Enable wrapper signal to packet transmission data_available <= '1';
EA <= S_SENDHEADER ; end if;
when S_SENDHEADER =>
-- If the data available is read or was read if data_ack = '1' or data_available = '0' then -- If fifo isn`t empty
if (read_pointer + 1 /= write_pointer) then data_available <= '1';
read_pointer <= read_pointer + 1; -- consumes de 2 flit (payload size) EA <= S_PAYLOAD;
-- If fifo is empty (protection clause) else
data_available <= '0'; end if;
end if;
when S_PAYLOAD =>
-- If the data available is read or was read if data_ack = '1' or data_available = '0' then -- If fifo isn`t empty or is tail
if (read_pointer + 1 /= write_pointer) or counter_flit = x"1" then -- If the second flit, memorize the packet size
if counter_flit = x"0" then
counter_flit <= buf(CONV_INTEGER(read_pointer)); elsif counter_flit /= x"1" then
counter_flit <= counter_flit - 1; end if;
-- If the tail flit
if counter_flit = x"1" then -- If tail is send if data_ack = '1' then data_available <= '0'; sender <= '0'; EA <= S_INIT; else EA <= S_END;
else
data_available <= '1';
read_pointer <= read_pointer + 1; end if;
-- If fifo is empty (protection clause) else
data_available <= '0'; end if;
end if; when S_END => -- When tail is send if data_ack = '1' then data_available <= '0'; sender <= '0'; EA <= S_INIT; end if; end case; end if; end process; data_av <= data_available; end Hermes_buffer; ********************************************************************************** Hermes_switchcontrol.vhd ********************************************************************************** library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_unsigned.all; use work.HermesPackage.all; entity SwitchControl is port( clock : in std_logic; reset : in std_logic; h : in regNport; ack_h : out regNport; address : in regmetadeflit; data : in arrayNport_regflit; sender : in regNport; free : out regNport;
mux_in : out arrayNport_reg3; mux_out : out arrayNport_reg3); end SwitchControl;
architecture AlgorithmXY of SwitchControl is type state is (S0,S1,S2,S3,S4,S5,S6,S7); signal ES, PES: state;
-- sinais do arbitro signal ask: std_logic := '0';
signal sel,prox: integer range 0 to (NPORT-1) := 0; signal incoming: reg3 := (others=> '0');
signal header : regflit := (others=> '0'); -- sinais do controle
signal sender_ant: regNport := (others=> '0'); begin
ask <= '1' when h(LOCAL)='1' or h(EAST)='1' or h(WEST)='1' or h(NORTH)='1' or h(SOUTH)='1' else '0'; incoming <= CONV_VECTOR(sel); header <= data(CONV_INTEGER(incoming)); process(sel,h) begin case sel is when LOCAL=>
if h(EAST)='1' then prox<=EAST; elsif h(WEST)='1' then prox<=WEST; elsif h(NORTH)='1' then prox<=NORTH; elsif h(SOUTH)='1' then prox<=SOUTH; else prox<=LOCAL; end if;
when EAST=>
if h(WEST)='1' then prox<=WEST; elsif h(NORTH)='1' then prox<=NORTH; elsif h(SOUTH)='1' then prox<=SOUTH; elsif h(LOCAL)='1' then prox<=LOCAL; else prox<=EAST; end if;
when WEST=>
if h(NORTH)='1' then prox<=NORTH; elsif h(SOUTH)='1' then prox<=SOUTH; elsif h(LOCAL)='1' then prox<=LOCAL; elsif h(EAST)='1' then prox<=EAST; else prox<=WEST; end if;
when NORTH=>
if h(SOUTH)='1' then prox<=SOUTH; elsif h(LOCAL)='1' then prox<=LOCAL; elsif h(EAST)='1' then prox<=EAST; elsif h(WEST)='1' then prox<=WEST; else prox<=NORTH; end if;
when SOUTH=>
if h(LOCAL)='1' then prox<=LOCAL; elsif h(EAST)='1' then prox<=EAST; elsif h(WEST)='1' then prox<=WEST; elsif h(NORTH)='1' then prox<=NORTH; else prox<=SOUTH; end if;
end case; end process;
lx <= address((METADEFLIT - 1) downto QUARTOFLIT); ly <= address((QUARTOFLIT - 1) downto 0);
tx <= header((METADEFLIT - 1) downto QUARTOFLIT); ty <= header((QUARTOFLIT - 1) downto 0);
dirx <= WEST when lx > tx else EAST; diry <= NORTH when ly < ty else SOUTH; process(reset,clock)
begin
process(ES,ask,h,lx,ly,tx,ty,auxfree,dirx,diry) begin
case ES is
when S0 => PES <= S1;
when S1 => if ask='1' then PES <= S2; else PES <= S1; end if; when S2 => PES <= S3;
when S3 => if lx = tx and ly = ty and auxfree(LOCAL)='1' then PES<=S4; elsif lx /= tx and auxfree(dirx)='1' then PES<=S5;
elsif lx = tx and ly /= ty and auxfree(diry)='1' then PES<=S6; else PES<=S1; end if;
when S4 => PES<=S7; when S5 => PES<=S7; when S6 => PES<=S7; when S7 => PES<=S1; end case; end process; process (clock) begin
if clock'event and clock='1' then case ES is -- Zera vari�veis when S0 => sel <= 0; ack_h <= (others => '0'); auxfree <= (others=> '1'); sender_ant <= (others=> '0'); mux_out <= (others=>(others=>'0')); source <= (others=>(others=>'0')); -- Chegou um header when S1=> ack_h <= (others => '0');
-- Seleciona quem tera direito a requisitar roteamento when S2=>
sel <= prox;
-- Estabelece a conex�o com a porta LOCAL when S4 =>
source(CONV_INTEGER(incoming)) <= CONV_VECTOR(LOCAL); mux_out(LOCAL) <= incoming;
auxfree(LOCAL) <= '0'; ack_h(sel)<='1';
-- Estabelece a conex�o com a porta EAST ou WEST when S5 =>
source(CONV_INTEGER(incoming)) <= CONV_VECTOR(dirx); mux_out(dirx) <= incoming;
auxfree(dirx) <= '0'; ack_h(sel)<='1';
-- Estabelece a conex�o com a porta NORTH ou SOUTH when S6 =>
source(CONV_INTEGER(incoming)) <= CONV_VECTOR(diry); mux_out(diry) <= incoming;
auxfree(diry) <= '0'; ack_h(sel)<='1';
when others => ack_h(sel)<='0'; end case;
sender_ant(LOCAL) <= sender(LOCAL); sender_ant(EAST) <= sender(EAST); sender_ant(WEST) <= sender(WEST);
if sender(LOCAL)='0' and sender_ant(LOCAL)='1' then auxfree(CONV_INTEGER(source(LOCAL))) <='1'; end if; if sender(EAST) ='0' and sender_ant(EAST)='1' then auxfree(CONV_INTEGER(source(EAST))) <='1'; end if;
if sender(WEST) ='0' and sender_ant(WEST)='1' then auxfree(CONV_INTEGER(source(WEST))) <='1'; end if;
if sender(NORTH)='0' and sender_ant(NORTH)='1' then auxfree(CONV_INTEGER(source(NORTH))) <='1'; end if;
if sender(SOUTH)='0' and sender_ant(SOUTH)='1' then auxfree(CONV_INTEGER(source(SOUTH))) <='1'; end if;
end if; end process; mux_in <= source; free <= auxfree; end AlgorithmXY; ********************************************************************************** crossbar.vhd ********************************************************************************** ibrary IEEE; use IEEE.std_logic_1164.all; use IEEE.std_logic_unsigned.all; use work.HermesPackage.all; entity Hermes_crossbar is port( data_av: in regNport; data_in: in arrayNport_regflit; data_ack: out regNport; sender: in regNport; free: in regNport; tab_in: in arrayNport_reg3; tab_out: in arrayNport_reg3; tx: out regNport;
data_out: out arrayNport_regflit; credit_i: in regNport);
end Hermes_crossbar;
architecture Hermes_crossbar of Hermes_crossbar is begin
--- -- PORTA LOCAL
---
tx(LOCAL) <= data_av(EAST) when tab_out(LOCAL)="000" and free(LOCAL)='0' else data_av(WEST) when tab_out(LOCAL)="001" and free(LOCAL)='0' else data_av(NORTH) when tab_out(LOCAL)="010" and free(LOCAL)='0' else data_av(SOUTH) when tab_out(LOCAL)="011" and free(LOCAL)='0' else '0';
data_out(LOCAL) <= data_in(EAST) when tab_out(LOCAL)="000" and free(LOCAL)='0' else data_in(WEST) when tab_out(LOCAL)="001" and free(LOCAL)='0' else
data_in(NORTH) when tab_out(LOCAL)="010" and free(LOCAL)='0' else data_in(SOUTH) when tab_out(LOCAL)="011" and free(LOCAL)='0' else
data_ack(LOCAL) <= credit_i(EAST) when tab_in(LOCAL)="000" and data_av(LOCAL)='1' else credit_i(WEST) when tab_in(LOCAL)="001" and data_av(LOCAL)='1' else
credit_i(NORTH) when tab_in(LOCAL)="010" and data_av(LOCAL)='1' else credit_i(SOUTH) when tab_in(LOCAL)="011" and data_av(LOCAL)='1' else '0';
--- -- PORTA EAST
---
tx(EAST) <= data_av(WEST) when tab_out(EAST)="001" and free(EAST)='0' else data_av(NORTH) when tab_out(EAST)="010" and free(EAST)='0' else data_av(SOUTH) when tab_out(EAST)="011" and free(EAST)='0' else data_av(LOCAL) when tab_out(EAST)="100" and free(EAST)='0' else '0';
data_out(EAST) <= data_in(WEST) when tab_out(EAST)="001" and free(EAST)='0' else data_in(NORTH) when tab_out(EAST)="010" and free(EAST)='0' else
data_in(SOUTH) when tab_out(EAST)="011" and free(EAST)='0' else data_in(LOCAL) when tab_out(EAST)="100" and free(EAST)='0' else (others=>'0');
data_ack(EAST) <= credit_i(WEST) when tab_in(EAST)="001" and data_av(EAST)='1' else credit_i(NORTH) when tab_in(EAST)="010" and data_av(EAST)='1' else
credit_i(SOUTH) when tab_in(EAST)="011" and data_av(EAST)='1' else credit_i(LOCAL) when tab_in(EAST)="100" and data_av(EAST)='1' else '0';
--- -- PORTA WEST
---
tx(WEST) <= data_av(EAST) when tab_out(WEST)="000" and free(WEST)='0' else data_av(NORTH) when tab_out(WEST)="010" and free(WEST)='0' else data_av(SOUTH) when tab_out(WEST)="011" and free(WEST)='0' else data_av(LOCAL) when tab_out(WEST)="100" and free(WEST)='0' else '0';
data_out(WEST) <= data_in(EAST) when tab_out(WEST)="000" and free(WEST)='0' else data_in(NORTH) when tab_out(WEST)="010" and free(WEST)='0' else
data_in(SOUTH) when tab_out(WEST)="011" and free(WEST)='0' else data_in(LOCAL) when tab_out(WEST)="100" and free(WEST)='0' else (others=>'0');
data_ack(WEST) <= credit_i(EAST) when tab_in(WEST)="000" and data_av(WEST)='1' else credit_i(NORTH) when tab_in(WEST)="010" and data_av(WEST)='1' else
credit_i(SOUTH) when tab_in(WEST)="011" and data_av(WEST)='1' else credit_i(LOCAL) when tab_in(WEST)="100" and data_av(WEST)='1' else '0';
--- -- PORTA NORTH
---
tx(NORTH) <= data_av(EAST) when tab_out(NORTH)="000" and free(NORTH)='0' else data_av(WEST) when tab_out(NORTH)="001" and free(NORTH)='0' else data_av(SOUTH) when tab_out(NORTH)="011" and free(NORTH)='0' else data_av(LOCAL) when tab_out(NORTH)="100" and free(NORTH)='0' else '0';
data_out(NORTH) <= data_in(EAST) when tab_out(NORTH)="000" and free(NORTH)='0' else data_in(WEST) when tab_out(NORTH)="001" and free(NORTH)='0' else
data_in(SOUTH) when tab_out(NORTH)="011" and free(NORTH)='0' else data_in(LOCAL) when tab_out(NORTH)="100" and free(NORTH)='0' else (others=>'0');
--- -- PORTA SOUTH
---
tx(SOUTH) <= data_av(EAST) when tab_out(SOUTH)="000" and free(SOUTH)='0' else data_av(WEST) when tab_out(SOUTH)="001" and free(SOUTH)='0' else data_av(NORTH) when tab_out(SOUTH)="010" and free(SOUTH)='0' else data_av(LOCAL) when tab_out(SOUTH)="100" and free(SOUTH)='0' else '0';
data_out(SOUTH) <= data_in(EAST) when tab_out(SOUTH)="000" and free(SOUTH)='0' else data_in(WEST) when tab_out(SOUTH)="001" and free(SOUTH)='0' else
data_in(NORTH) when tab_out(SOUTH)="010" and free(SOUTH)='0' else data_in(LOCAL) when tab_out(SOUTH)="100" and free(SOUTH)='0' else (others=>'0');
data_ack(SOUTH) <= credit_i(EAST) when tab_in(SOUTH)="000" and data_av(SOUTH)='1' else credit_i(WEST) when tab_in(SOUTH)="001" and data_av(SOUTH)='1' else
credit_i(NORTH) when tab_in(SOUTH)="010" and data_av(SOUTH)='1' else credit_i(LOCAL) when tab_in(SOUTH)="100" and data_av(SOUTH)='1' else '0';