Lógica OU redefinir e limpar?
Estou tentando descobrir a melhor prática para implementar uma redefinição (assíncrona aplicada, sincronização desmarcada) e uma entrada clara. Eu tenho um processo que deve ser executado fora de um relógio derivado de lógica (NCO) que é chamado code_clk, mais lento, mas síncrono para o clk real. O processo envolve um Linear Feedback Shift Register que deve ser redefinido para todos os 1s para iniciar uma sequência de geração de código depois que a redefinição for suspensa. No entanto, durante a operação, o processo também deve ser redefinido para todos os 1s quando um novo conjunto de torneiras (T1 e T2) são selecionados para a saída, é claro, a fim de redefinir a sequência de geração de código e garantir que o novo código seja válido com o novo torneiras. Isso é feito com uma entrada clr síncrona separada que é mantida alta por um único ciclo de clock do sistema enquanto os taps são movidos.
Aqui está o meu código:
process(code_clk, reset, clr)
begin
if(reset='0' or clr='1') then
-- EARLY LFSR
EG1(1 to 10) <= (others => '1');
EG2(1 to 10) <= (others => '1');
early_code <= '0';
delay_os <= '0';
elsif(falling_edge(code_clk)) then
if(delay_os='0') then
-- LFSR feedbacks for early code
EG1(2 to 10) <= EG1(1 to 9);
EG2(2 to 10) <= EG2(1 to 9);
EG1(1) <= EG1(3) xor EG1(10);
EG2(1) <= EG2(2) xor EG2(3) xor EG2(6) xor EG2(8) xor EG2(9) xor EG2(10);
early_code <= EG1(10) xor EG2(T1) xor EG2(T2); -- C/A output of early LFSR
else
-- delay of code chips commanded - do not shift this time
delay_os <= '0';
end if;
late_code <= early_code; -- one half chip delay from prompt code
elsif(rising_edge(code_clk)) then
prompt_code <= early code; -- one half chip delay from early code
end if;
end process;
O if (reset = '0' or clr = '1') condicional meio que salta para mim como sendo um estilo ruim. Parece apenas uma daquelas situações em que a síntese produzirá lógica desnecessária ou atraso de tempo porque o caminho de reinicialização não é tão direto. Posso fazer isso ou devo tentar outra coisa? A limpeza precisa acontecer imediatamente, então eu precisaria fazer o processo funcionar fora do relógio do sistema ou outra coisa. Isso é considerado uma boa prática?
Respostas
Seus instintos para o condicional estão corretos. Algumas ferramentas de síntese podem entender o que você está tentando fazer, mas muitas não, pois o que você escreveu não é um padrão estabelecido, portanto, as ferramentas podem não inferir o que você quer da maneira que você deseja. O padrão (se é que existe tal coisa) / maneira aceita de escrever o que você está tentando alcançar é assim:
process(clk, reset)
begin
if reset = '1' then -- async reset
-- your code here
elsif Rising_edge(clk) then
if sync_clr = '1' then -- sync clear
-- your code here
end if;
end if;
end process;
Noto que o seu reset está ativo baixo, o que tende a ser desaprovado no FPGA (mais a ver com a legibilidade do código do que com questões arquitetônicas reais).
Mas espere! Por que isso realmente importa?
Isso se resume à arquitetura individual do FPGA que você está usando. Abaixo está um fragmento do diagrama de blocos para um Módulo de Lógica Adaptável Cyclone V.
Olhando para os registradores, você pode ver que eles têm apenas um único controle - CLR. No topo do diagrama, você pode ver os sinais aclr [1: 0] que chegam ao ALM. Quando você infere uma redefinição assíncrona, é isso que está definido. Observe que este ALM tem 4 registradores, mas apenas 2 sinais de reinicialização que são compartilhados pelos pares. Isso tem uma implicação em quantos ALMs são usados.
Você também pode ver um sinal de liberação síncrona ( sclr ) e um sinal de carga síncrona ( syncload ) chegando ao ALM. Eles são compartilhados por todos os 4 registradores. Esses circuitos serão usados se inferidos em código. O diagrama é detalhado o suficiente para entender como os sinais funcionam.
O sclr deve ser alto ativo. Ele é invertido e ligado com os dados que alimentam a entrada D dos registradores. Isso significa que quando alto, 0 é alimentado para a entrada D e Q atualiza para 0 no próximo ciclo de clock.
syncload aciona um multiplexador que seleciona as saídas dos LUTs ou datae0 que se origina fora do ALM.
Observe como não há conjunto assíncrono. Se você escreveu isso, as ferramentas não seriam capazes de fazer a correspondência com a arquitetura do dispositivo e, em vez disso, implementariam usando LUTs. Isso é o mesmo para todos os controles que não fazem parte da arquitetura dos dispositivos.
A Xilinx tem um white paper que explica isso com muito mais detalhes: https://www.xilinx.com/support/documentation/white_papers/wp275.pdf