Por que esse Verilog monopoliza 30 macrocélulas e centenas de termos de produto?


8

Eu tenho um projeto que consome 34 das macrocélulas do Xilinx Coolrunner II. Percebi que havia um erro e o localizei para isso:

assign rlever = RL[0] ? 3'b000 :
                RL[1] ? 3'b001 :
                RL[2] ? 3'b010 :
                RL[3] ? 3'b011 :
                RL[4] ? 3'b100 :
                RL[5] ? 3'b101 :
                RL[6] ? 3'b110 :
                        3'b111;

assign llever = LL[0] ? 3'b000 :
                LL[1] ? 3'b001 :
                LL[2] ? 3'b010 :
                LL[3] ? 3'b011 :
                LL[4] ? 3'b100 :
                LL[5] ? 3'b101 :
                        3'b110 ;

O erro é esse rlevere llevertem um bit de largura, e eu preciso que eles tenham três bits de largura. Eu tolo. Eu mudei o código para ser:

wire [2:0] rlever ...
wire [2:0] llever ...

então havia bits suficientes. No entanto, quando reconstruí o projeto, essa alteração me custou mais de 30 macrocélulas e centenas de termos do produto. Alguém pode explicar o que fiz de errado?

(A boa notícia é que agora simula corretamente ... :-P)

EDIT -

Suponho que estou frustrado porque, na época em que acho que começo a entender a Verilog e o CPLD, acontece algo que mostra que eu claramente não entendo.

assign outp[0] = inp[0] | inp[2] | inp[4] | inp[6];
assign outp[1] = inp[1] | inp[2] | inp[5] | inp[6];
assign outp[2] = inp[3] | inp[4] | inp[5] | inp[6];

A lógica para implementar essas três linhas ocorre duas vezes. Isso significa que cada uma das 6 linhas da Verilog consome cerca de 6 macrocélulas e 32 termos de produto cada .

EDIT 2 - Conforme sugestão do @ ThePhoton sobre a opção de otimização, aqui estão as informações das páginas de resumo produzidas pelo ISE:

Synthesizing Unit <mux1>.
    Related source file is "mux1.v".
    Found 3-bit 1-of-9 priority encoder for signal <code>.
Unit <mux1> synthesized.
(snip!)
# Priority Encoders                                    : 2
 3-bit 1-of-9 priority encoder                         : 2

Tão claramente que o código foi reconhecido como algo especial. O design ainda está consumindo enormes recursos, no entanto.

EDIT 3 -

Fiz um novo esquema incluindo apenas o mux recomendado pelo @thePhoton. A síntese produziu um uso insignificante de recursos. Também sintetizei o módulo recomendado por @Michael Karas. Isso também produziu um uso insignificante. Então, alguma sanidade é predominante.

Claramente, meu uso dos valores da alavanca está causando consternação. Mais por vir.

Edição final

O design não é mais louco. Não tenho certeza do que aconteceu, no entanto. Fiz muitas alterações para implementar novos algoritmos. Um fator que contribuiu foi uma 'ROM' de 111 elementos de 15 bits. Isso consumiu um número modesto de macrocélulas, mas muitodos termos do produto - quase todos os disponíveis no xc2c64a. Eu procuro isso, mas não o notei. Acredito que meu erro foi oculto pela otimização. As 'alavancas' de que estou falando são usadas para selecionar valores da ROM. Minha hipótese é que, quando implementei o codificador de prioridade de 1 bit (eliminado), o ISE otimizou uma parte da ROM. Isso seria um truque, mas é a única explicação que posso pensar. Essa otimização reduziu acentuadamente o uso de recursos e levou-me a esperar uma certa linha de base. Quando consertei o codificador de prioridade (conforme esse segmento), vi a sobrecarga do codificador de prioridade e da ROM que anteriormente haviam sido otimizadas e atribuí isso exclusivamente ao antigo.

Depois de tudo isso, eu era bom em macrocélulas, mas havia esgotado meus termos de produto. Metade da ROM era um luxo, na verdade, pois eram apenas os comp de 2 da primeira metade. Eu removi os valores negativos, substituindo-os em outros lugares por um cálculo simples. Isso me permitiu trocar macrocélulas por termos de produto.

Por enquanto, essa coisa se encaixa no xc2c64a; Eu usei 81% e 84% das minhas macrocélulas e termos do produto, respectivamente. Claro, agora tenho que testá-lo para garantir que ele faça o que quero ...

Agradecemos a ThePhoton e Michael Karas pela assistência. Além do apoio moral que eles emprestaram para me ajudar a resolver isso, aprendi com o documento da Xilinx publicado pelo ThePhoton e implementei o codificador de prioridade sugerido por Michael.


todo ponto de interrogação não implica efetivamente um multiplexador e, estruturalmente, você também os colocou em cascata? Quantas macrocélulas você esperava?
vicatcu

Não sei quantas macrocélulas a construção deve consumir. No entanto, considerando que meu projeto atualmente consome 34 macrocélulas, incluindo esses dois multiplexadores de '1 bit', e que essas são uma pequena parte do projeto, estou surpreso com esse resultado.
Tony Ennis

Qual ferramenta você está usando?
O Photon

ISE da Xilinx ...
Tony Ennis

No código da sua edição, acho que você deseja, em |vez de ||.
The Photon

Respostas:


7

O código que você mostra é essencialmente um codificador prioritário. Ou seja, possui uma entrada de muitos sinais e sua saída indica qual desses sinais está definido, dando prioridade ao sinal definido à esquerda, se mais de um estiver definido.

No entanto, vejo definições conflitantes do comportamento padrão desse circuito nos dois locais que verifiquei.

De acordo com a Wikipedia , o codificador de prioridade padrão numera suas entradas de 1. Ou seja, se o bit de entrada menos significativo for definido, ele gera 1, e não 0. O codificador de prioridade da Wikipedia gera 0 quando nenhum dos bits de entrada está definido.

O Guia do usuário XST da Xilinx (p. 80), no entanto, define um codificador de prioridade mais próximo do que você codificou. As entradas são numeradas de 0, portanto, quando o lsb da entrada é definido, ele fornece uma saída 0. No entanto, a definição do Xilinx não fornece especificações para a saída quando todos os bits de entrada estiverem limpos (seu código produzirá 3'd7).

O guia do usuário do Xilinx, é claro, determinará o que o software de síntese do Xilinx está esperando. O ponto principal é que uma diretiva especial (*priority_extract ="force"*)é necessária para o XST reconhecer essa estrutura e gerar ótimos resultados de síntese.

Aqui está o formulário recomendado pelo Xilinx para um codificador de prioridade de 8 a 3:

(* priority_extract="force" *)
module v_priority_encoder_1 (sel, code);
input [7:0] sel;
output [2:0] code;
reg [2:0] code;
always @(sel)
begin
    if (sel[0]) code = 3b000;
    else if (sel[1]) code = 3b001;
    else if (sel[2]) code = 3b010;
    else if (sel[3]) code = 3b011;
    else if (sel[4]) code = 3b100;
    else if (sel[5]) code = 3b101;
    else if (sel[6]) code = 3b110;
    else if (sel[7]) code = 3b111;
    else code = 3bxxx;
end
endmodule

Se você pode reorganizar sua lógica circundante para permitir o uso do estilo de codificação recomendado pelo Xilinx, essa é provavelmente a melhor maneira de obter um resultado melhor.

Eu acho que você pode conseguir isso instanciando o módulo codificador Xilinx com

v_priority_encoder_1 pe_inst (.sel({~|{RL[6:0]}, RL[6:0]}), .code(rlever));

Eu não uni todos os bits RL[6:0]para obter um 8º bit de entrada que acionará a saída 3'b111 quando todos os bits RL estiverem baixos.

Para a lleverlógica, você provavelmente pode reduzir o uso de recursos criando um módulo codificador modificado, seguindo o modelo Xilinx, mas exigindo apenas 7 bits de entrada (seus 6 bits LLmais um bit adicional que aumenta quando os outros 6 estão baixos).

O uso deste modelo pressupõe que a versão do ISE que você possui está usando o mecanismo de síntese XST. Parece que eles mudam as ferramentas de síntese em todas as principais revisões do ISE, portanto, verifique se o documento que vinculei realmente corresponde à sua versão do ISE. Caso contrário, verifique o estilo recomendado na sua documentação para ver o que sua ferramenta espera.


Obrigado, isso levará algum tempo para digerir. Meu ISE está usando o XST, embora eu não saiba qual versão.
Tony Ennis

A chave é ter a (* priority_extract="force" *)e provavelmente também incluir explicitamente a saída não-importante, mesmo que você cubra todas as entradas possíveis. (Sem ele, o XST provavelmente está tentando gerar uma tabela de consulta completa, e é por isso que muitos termos do produto) Tente adicionar a opção não se importar primeiro. Se não funcionar, tente usar exatamente o padrão da Xilinx.
The Photon

Eu implementei uma cópia completa do código acima e não obtive um resultado aprimorado. As páginas de resumo do ISE indicam que um MUX foi reconhecido, embora o reconhecimento não tenha sido tão forte quanto em outras construções. Vou postar as informações relevantes em alguns minutos.
Tony Ennis

editar - ignore o comentário acima sobre 'reconhecimento forte' - está lá, eu perdi ontem à noite; Refiz o trabalho e a realidade está funcionando corretamente.
Tony Ennis

6

A resposta do ThePhoton é excelente. Gostaria de adicionar algumas informações adicionais aqui para sua consideração. Isso decorre do fato de que, embora tenhamos dispositivos FPGA e CPLD sofisticados, usando HDLs e ferramentas de sistema, pode ser informativo olhar de perto as coisas projetadas anos atrás. Fique comigo enquanto eu passo por isso até a minha recomendação no final.

Existem partes lógicas discretas que executam a função de codificação prioritária. A lógica implementada por essas partes existe há muito tempo, quando era essencial reduzir o número de transistores ao mínimo. Você pode procurar na web por peças lógicas com números de peça genéricos, como 74HC148 ou MC14532B, para encontrar folhas de dados que incluem diagramas lógicos equivalentes para essas peças. O diagrama abaixo é um exemplo retirado da folha de dados da TI para a peça 74HC148 .

insira a descrição da imagem aqui

Essa lógica implementa a seguinte tabela verdade (retirada da mesma folha de dados):

insira a descrição da imagem aqui

Observe que a família de peças acima usa sinais de entrada ativos baixos. Outra folha de dados da peça ON Semiconductor MC14532B mostra uma tabela verdade para a função do codificador usando sinais de entrada alta ativos semelhantes ao seu exemplo da Verilog.

insira a descrição da imagem aqui

A mesma folha de dados mostra as equações lógicas para o MC14532B da seguinte maneira:

insira a descrição da imagem aqui

Convém codificar equações semelhantes diretamente no seu código Verilog para ver como ele se compara ao seu exemplo atual. É altamente provável que resulte em um resultado muito mais favorável.


Obrigado, eu farei isso. Esse problema está me matando. Eu acredito que estava sintetizando mais eficientemente anteriormente. E então eu mudei algo. / selfbonk
Tony Ennis

Obrigado, eu implementei. Infelizmente, não fez diferença material.
Tony Ennis

Boa resposta. Vamos ver Tony quantos termos de produto devem ser necessários para implementar essa lógica. Tony, se você usa o clichê do Xilinx ou as equações de Michael e ainda está gerando centenas de termos de produto, precisa procurar uma alteração sutil em outro lugar do código que possa ter causado o problema; ou então olhe com muita atenção o arquivo de log de síntese para ver se algo está acontecendo que você não espera.
The Photon

Eu concordo completamente com @ThePhoton. Eu manchei alguma coisa. Tenho certeza de que isso costumava funcionar - eu nem percebi o consumo que era tão pequeno. Bem, é uma boa desculpa começar a entender mais as informações de Resumo.
Tony Ennis
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.