• Nenhum resultado encontrado

A.2 Fundamentação Teórica

A.2.1 Verificação Funcional

A verificação funcional é uma técnica utilizada para verificar se o IP em desenvolvimento respeita suas especificações. A idéia básica desta técnica consiste em comparar o design do dispositivo a ser desenvolvido, de agora em diante DUV (Design Under Verification), com um modelo de referência. Esse modelo de referência, por definição, respeita as especifica- ções que o DUV também deve respeitar. A comparação consiste em fornecer os mesmos estímulos para os dois modelos e comparar os resultados produzidos por cada um deles. A ocorrência de valores de saída diferentes significa que o DUV possui erro. A verificação

funcional não prescreve quais linguagens devem ser usadas para definição dos modelos. No entanto, tradicionalmente, o DUV é descrito em uma linguagem de descrição de hardware, tal como Verilog [1], e o modelo de referência é descrito em C/C++ ou SystemC [18].

Essa comparação de dois modelos mencionada no parágrafo anterior, contudo, é um processo que envolve outros elementos além desses dois modelos. Um elemento chave na verificação funcional é o ambiente de verificação funcional, também chamado de testbench. O testbench é o ambiente que envolve o DUV. Ele é responsável por abarcar os elementos que são responsáveis pela geração de estímulos e pela comparação automática dos resultados de saída.

O ambiente de verificação deve ser implementado preferencialmente em um nível de abs- tração alto, denominado de nível de transação (Transaction-level). Esse nível de transação não se preocupa com detalhes de protocolos no nível de sinais. Ao invés disso, o seu foco é a comunicação entre blocos e a transferência de transações. Uma transação é uma represen- tação básica para a troca de informações entre dois blocos funcionais. Em outras palavras, é uma operação que inicia num determinado momento no tempo e termina em outro, sendo caracterizada pelo conjunto de instruções e dados necessários para realizar a operação. Ela é definida pelo seu tempo inicial, tempo final e atributos [24]. Um exemplo de uma transação poderia ser uma transmissão de um pacote ethernet.

Análise de Cobertura

Um aspecto crítico da verificação funcional é a detecção de seu término. Idealmente, a veri- ficação funcional deve terminar assim que todas as funcionalidades implementadas tenham sido exercitadas. Porém, esta constatação depende da qualidade e da quantidade de estímulos utilizados, pois a comparação dos resultados do modelo de referência e DUV são realizadas através de simulação. Assim sendo, é muito importante que exista um mecanismo para detectar se todas as funcionalidades especificadas foram exercitadas.

Para responder se todas as funcionalidades especificadas foram exercitadas, os engenhei- ros de verificação usam análise de cobertura. A análise de cobertura é uma técnica usada para medir o progresso da verificação e reportar quais funcionalidades deixaram de ser exer- citadas. A análise de cobertura pode ser compreendida como sendo um conjunto de metas que devem ser atingidas durante a verificação funcional. Essas metas podem ser especifica-

das em função de diversos critérios. Segundo esses critérios, podemos classificar dois tipos de cobertura principais: análise de cobertura de código e análise de cobertura funcional. Análise de Cobertura de Código

Para a cobertura de código, a ferramenta de análise de cobertura vai reportar quais partes de código foram executadas e quais não foram durante a simulação. Este tipo de análise é importante por revelar ao engenheiro se existe alguma parte do design que não foi exercitada. A existência de partes do design que não foram exercitadas é ruim porque elas podem conter algum erro. Este tipo de cobertura requer algum tipo de instrumentação do código. Esta instrumentação consiste de pontos de observação no código para registrar se tal parte foi exercitada de fato. As seguintes métricas podem ser usadas para este tipo de cobertura: linhas de código, caminhos de execução e expressões.

Na cobertura de linhas de código, a ferramenta mede quais linhas exatamente foram exe- cutadas e quais não foram. Para se alcançar 100 % de cobertura de código é necessário compreender quais condições lógicas devem ser satisfeitas para se alcançar as linhas desco- bertas. Contudo, é muito comum que a codificação defensiva leve a produção de blocos de comandos que nunca são executados, fazendo com que a cobertura total nunca seja alcan- çada.

A cobertura de caminhos de execução mede as possíveis seqüências de linha de comando que podem ser executadas em um design. A existência de comandos de fluxo de controle, tais como estruturas condicionais do tipo if then else, faz com que existam vários caminhos de execução. Por exemplo, temos um caminho em que o bloco then é executado e temos outro referente ao bloco else. Este tipo de cobertura é bem mais precisa que a cobertura de linhas de código, pois um erro pode ser revelado somente quando uma seqüência específica ocorre. Em contra-partida, o número de seqüências cresce exponencialmente em função do número de comandos de fuxo de controle.

Ainda mais precisa que a cobertura de caminhos de execução, a cobertura de expressões analisa as diversas instâncias que um caminho de execução pode ocorrer. Por exemplo, a condição de um bloco if pode conter uma expressão com o operador lógico ou. Natural- mente, esta expressão pode ser satisfeita quando um dos operandos for verdadeiro, fazendo com que exista pelo menos três instâncias do mesmo caminho de execução.

Análise de Cobertura Funcional

Se a análise de cobertura de código mede o quanto do código foi exercitado, a análise de co- bertura funcional mede o quanto da especificação original foi exercitada. Ela pode analisar, por exemplo, o nível de ocupação de um buffer, a quantidade de pacotes enviados, requi- sição de barramento etc. Assim, a cobertura funcional está focada no propósito da função implementada enquanto a cobertura de código está focada na execução do código.

A cobertura de código, portanto, depende do domínio da aplicação. Na prática, isto sig- nifica que a especificação dos critérios de cobertura deve ser realizada manualmente pelo engenheiro de verificação, isto é, os critérios de cobertura não podem ser extraídos automa- ticamente do código em linguagem de descrição do hardware. Assim como na análise de cobertura de código, os valores das execuções são extraídos durante a simulação e armaze- nados em uma base de dados. A partir dessa base, a análise de cobertura ocorre propriamente em função do que foi especificado. Os critérios comumente utilizados para cobertura funci- onal são os seguintes: cobertura de valores escalares individuais e cobertura cruzada.

Na cobertura de valores escalares, o engenheiro especifica o conjunto de valores rele- vantes que devem ser observados na verificação, seja como estímulos de entrada, seja como resultados de saída. Exemplos de valores escalares utilizados para este tipo de cobertura são: tamanho de pacote, ocupação de buffer, acesso a barramento etc. É uma tarefa muito simples especificar e medir cobertura desta natureza, sendo que as medições chegam bem perto de 100 % na maioria das vezes. É importante que fique claro que 100% de cobertura não ga- rante que o design está isento de erros. Isto que significa que todos os critérios especificados foram totalmente satisfeitos.

A cobertura cruzada de valores2trata de medir a ocorrência da combinação de diversos

valores. Ela é útil para especificar propriedades do tipo: “ Um pacote corrompido foi inserido em todas as portas?” “Todos os buffers ficaram preenchidos ao mesmo tempo?”. A imple- mentação de cobertura cruzada segue o mesmo princípio da cobertura de valores escalares, a diferença é que na cobertura cruzada várias valores são coletados ao mesmo tempo.

A.2.2

Redes de Petri Coloridas Hierárquicas