Caso II: Necessidade de um controlador simples Este caso ocorre em três situações: II.1) Quando o número de unidades lógico-aritméticas é menor do que o número
C APÍTULO 4: L INGUAGENS DE E SPECIFICAÇÃO
4.1. INTRODUÇÃO
No capítulo 2 foram abordados diversos modelos conceituais, os quais podem ser aplicados em diferentes fases de metodologias de projeto para sistemas digitais. Para que possa ser tratado por ferramentas de CAD (Computer Aided Design) e de CAE (Computer
Aided Engineering), um modelo deve ser transformado em uma especificação através de uma
linguagem de especificação. Há vários tipos de linguagens de especificação, cada qual podendo capturar características de um ou mais modelos. São características desejáveis de uma linguagem de especificação:
a) Capacidade de capturar o maior número de características de uma classe de sistemas;
b) Possibilitar o uso de ferramentas de síntese, tanto para hardware quanto para software;
c) Ter boa legibilidade; e
d) Gerar uma especificação executável, a qual possa ser utilizada para propósitos de demonstração da funcionalidade do produto, documentação (servindo de guia para as diferentes equipes envolvidas no processo de projeto), análise de propriedades (verificação automática), exploração do espaço de projeto (alternativas de projeto) e síntese do projeto. Seguindo a linha adotada para este trabalho de doutorado, nas seções deste capítulo, são tratadas linguagens de especificação empregadas no projeto de sistemas digitais embutidos. As linguagens são brevemente apresentadas com base na proporção em que elas capturam, ou não, as principais características encontradas nos diversos modelos conceituais utilizados no projeto de tais sistemas. Estas características, levantadas por Gajski [3], são: a) Concorrência: Este termo refere-se à possibilidade do modelo descrever a execução
simultânea de comportamentos do sistema. Há duas formas de representação de concorrência. Na concorrência orientada a dados, não há uma ordem de execução explícita dos comportamentos envolvidos. A ordem de execução é determinada pela dependência de dados entre os comportamentos. Na concorrência orientada a controle, há segmentos de controle determinando a ordem de execução dos comportamentos envolvidos. Cada segmento de controle agrupa um conjunto de comportamentos executados seqüencialmente. A concorrência caracteriza-se pela execução simultânea destes agrupamentos seqüenciais (segmentos de controle). O conceito de concorrência pode ser aplicado em diferentes níveis de abstração (tarefas, sentenças, operações, bits); b) Transição de estados: Sistemas embutidos geralmente apresentam vários modos (estados)
de comportamento. Transições entre tais modos podem ocorrer de forma não estruturada (em oposição a um seqüenciamento linear pelos modos), mediante a detecção de certos eventos ou condições;
c) Hierarquia comportamental: Esta característica refere-se à possibilidade de decompor o comportamento (funcionalidade) de um sistema (ou subsistemas componentes) em partes menores (subcomportamentos), de forma a facilitar o gerenciamento de sua complexidade (trabalhando-se em separado sobre cada parte). Tal decomposição denomina-se paralela, quando os subcomportamentos gerados são paralelos entre si (admitindo, assim, execução simultânea), ou seqüencial, quando os subcomportamentos gerados são executados um após o outro;
d) Estruturas de programação: São as estruturas (comandos/funções/operadores) utilizadas por linguagens de programação, apropriadas para a descrição de comportamentos através de algoritmos seqüenciais;
e) Término comportamental: Esta expressão refere-se à habilidade de um comportamento indicar a sua finalização (todas as computações internas do comportamento executadas), assim como à habilidade de outras partes do sistema detectarem este fato;
f) Tratamento de exceções: Em um modelo de sistema, a ocorrência de um dado evento pode exigir que um modo de computação (comportamento ou estado local) seja imediatamente interrompido ou abortado, transferindo o fluxo de controle de execução do modelo para um outro modo de computação. Um evento desse tipo é chamado de exceção. Basicamente, há dois tipos de exceções: preempção (quando o modo atual é abortado) e interrupção (quando o modo atual é temporariamente suspenso, podendo ser retomado depois de decorrido um certo tempo, mediante dadas condições);
g) Representação de tempo: Em geral, há duas formas de especificar informações de tempo em um sistema, quais sejam, a temporização funcional e a temporização restritiva. Na primeira, as informações de tempo podem interferir na funcionalidade do modelo (em sua simulação). Já na segunda, a especificação de restrições temporais impõe limites para a execução de um comportamento ou para a permanência do sistema modelado num dado estado (tais limites são úteis para ferramentas de síntese e de verificação);
h) Comunicação: Geralmente, um sistema é composto por vários comportamentos que interagem entre si. Desta forma, faz-se necessária a adoção de um mecanismo de comunicação entre tais comportamentos. Mecanismos de comunicação enquadram-se em uma de duas categorias, quais sejam, a de modelos de comunicação por memória compartilhada (na qual existe um meio de armazenamento intermediário, representante direto de um dispositivo físico, o qual possibilita a escrita e a leitura de dados pelos comportamentos que o acessam), e a de modelos de comunicação por passagem de mensagens (na qual os detalhes de transferência de dados são substituídos pela comunicação através de um meio abstrato, denominado canal); e
i) Sincronização de processos: Em um comportamento formado por vários processos concorrentes, um processo pode gerar dados ou eventos que necessitem ser reconhecidos por outros processos. Em casos assim, pode ser necessária a sincronização entre os processos que se comunicam, isto é, pode ser necessário que um dos processos fique suspenso até que o outro (ou outros) atinja um dado ponto em sua execução. Há dois métodos de sincronização comuns a sistemas embutidos. Na sincronização dependente de controle, a estrutura de controle do comportamento é a responsável pela sincronização entre seus processos, através da especificação de pontos de sincronização. Na sincronização dependente de dados, os processos envolvidos é que controlam sua própria execução, através da verificação de determinados valores de dados (ou eventos), de acordo com o mecanismo de comunicação adotado para tais processos (memória compartilhada ou passagem de mensagens).
Como o objetivo principal deste trabalho é a obtenção de um modelo conceitual baseado em redes de Petri, que sirva de suporte à criação de uma metodologia para a modelagem, simulação e análise em alto nível de sistemas digitais (embutidos, principalmente) e, como este modelo conceitual foi desenvolvido para abranger todas as características supracitadas, faz-se necessário compreender a maneira pela qual as principais linguagens de especificação tratam tais características, inclusive para propósitos de comparação, conforme será visto na seção 11.3. Esta comparação, envolvendo linguagens de especificação com o modelo conceitual RPSD (Rede de Petri para Sistemas Digitais – capítulo 11), faz sentido, na
medida em que se pretende implementar, como decorrência deste trabalho de doutorado, uma plataforma em software que permita capturar de forma direta descrições RPSD de sistemas digitais embutidos, para as suas simulação, análise e síntese. A metodologia que abrange tal plataforma será abordada no capítulo 15.
4.2. VHDL
A linguagem VHDL (VHSIC Hardware Description Language) foi desenvolvida entre o final dos anos 70 e início dos 80, dentro do programa VHSIC (Very High Speed Integrated
Circuit) do Departamento de Defesa Norte-Americano, sendo padronizada pelo IEEE em
1987 [21]. Inicialmente, VHDL foi projetada como uma linguagem de documentação e simulação. Uma vez que a linguagem foi bem aceita na comunidade de projeto como uma linguagem de descrição, logo surgiu uma grande quantidade de ferramentas para a captura, simulação, depuração (debugging), verificação e síntese de projetos de hardware descritos em VHDL, no nível RTL (Register Transfer Level, nível de transferências entre registradores).
A unidade básica de abstração de hardware em VHDL é a entidade (entity), a qual é utilizada para identificar e representar uma porção unitária de um projeto maior, realizando uma função específica e possuindo entradas e saídas bem definidas. A funcionalidade de cada entidade é descrita através de sua arquitetura (architecture). VHDL permite que o projetista represente a arquitetura associada a uma entidade de três formas, ou de uma combinação destas. Estas formas são:
a) Seqüencial: Arquitetura utiliza-se de sentenças seqüenciais de programação;
b) Comportamental (ou a fluxo de dados – dataflow): Arquitetura utiliza-se de sentenças de programação que trabalham somente sobre sinais, os quais representam armazenadores de valores com conteúdo escalonado, conforme descrito adiante;
c) Estrutural: Arquitetura descrita como uma interconexão de componentes, os quais correspondem a instâncias de pares entidade-arquitetura.
Na seqüência, é visto como VHDL trata das características necessárias a um bom modelo conceitual para a modelagem de sistemas digitais embutidos.
a) Concorrência
VHDL suporta concorrência em dois níveis, quais sejam: nível de tarefas e nível de sentenças (statements) de programação.
No nível de tarefas a concorrência é possível, uma vez que vários processos (descrevendo, cada qual, a arquitetura seqüencial de uma entidade) podem estar ativos num dado momento.
No nível de sentenças, a concorrência é obtida através do uso de sentenças que permitem atribuição concorrente de sinais, em arquiteturas descritas de forma comportamental (dataflow). Diferentemente de variáveis (utilizadas somente em processos), que armazenam um único valor e sofrem atribuição imediata (logo após a execução da sentença), sinais permitem a atribuição de diversos valores de forma escalonada (ao longo do tempo). Como exemplo, observe o seguinte trecho de sentenças
dentro de um processo, envolvendo os sinais a e b, além do operador de atribuição de sinais (<=):
a <= b; b <= a;
wait on b;
Nele, as duas atribuições serão feitas ao mesmo tempo, trocando os valores dos sinais a e
b. A cláusula wait on mantém o processo suspenso até que ocorra um evento sobre o sinal b. Pode-se, também, obter concorrência em nível de sentenças implicitamente, através da cláusula after, a qual permite escalonar atribuição futura sobre um sinal, podendo ocorrer atribuições concorrentes, como no trecho seguinte:
a <= b + c after 10 ns;
wait for 10 ns;
x := 50;
Neste trecho, a cláusula after adia em 10 ns a atribuição sobre a, e a cláusula wait for
pára o processamento durante 10 ns, após o que será feita a atribuição sobre x. Desta forma, as atribuições sobre o sinal a e a variável x ocorrerão concorrentemente.
b) Transição de estados
Esta característica não é suportada em VHDL, pois a linguagem não trabalha com o conceito de estado.
c) Hierarquia
VHDL suporta tanto hierarquia estrutural como comportamental. A hierarquia estrutural é obtida através do uso de blocos (blocks) encadeados e de sentenças para a criação de instâncias de componentes (na descrição estrutural de uma arquitetura).
A hierarquia comportamental possui dois níveis. No nível topo, a especificação pode ser decomposta em um conjunto de processos que podem ser executados concorrentemente. O segundo nível consiste de uma decomposição seqüencial destes processos em procedimentos. No entanto, uma hierarquia comportamental verdadeira, na qual concorrência possa ser especificada em qualquer nível, não é suportada em VHDL.
d) Estruturas de programação
VHDL possui suporte completo para estruturas de programação, semelhantes às encontradas na linguagem de programação ADA. Uma ampla variedade de tipos de dados é fornecida, a qual mostra-se adequada para modelagem em alto nível, uma vez que se encontram tipos tais como inteiros, reais, enumerados, vetores, registros e ponteiros.
e) Término comportamental
Esta característica é suportada por VHDL, uma vez que o encerramento de um processo é bem definido (execução da última sentença).
f) Tratamento de exceções
VHDL não possui construtores capazes de encerrar um processo em resposta a uma exceção. Suporte parcial pode ser obtido, através do uso de uma expressão guarda (booleana), associada a um bloco, que encapsule um conjunto de atribuições concorrentes sobre sinais.
g) Representação de tempo
VHDL é limitada à especificação de temporização funcional. A cláusula after é utilizada para escalonar a atualização de um sinal no futuro. Já a cláusula wait é utilizada para suspender um processo temporariamente. Pode-se trabalhar com a noção de tempo global do sistema, através da expressão now.
A utilização de tempo para propósitos de restrição não é diretamente suportada em VHDL, embora restrições temporais possam ser especificadas indiretamente através do uso de atributos.
h) Comunicação
Comunicação entre processos em VHDL pode ser obtida através da adoção de um modelo de memória compartilhada, através do qual sinais e variáveis associados a um processo possam ser acessados por outros processos.
i) Sincronização de processos
Sincronização pode ser obtida por duas formas. Na primeira, através do uso da lista de sensibilidade de um processo. Os sinais presentes nesta são responsáveis pela ativação do processo correspondente, quando da ocorrência de um evento sobre qualquer um destes sinais. No exemplo seguinte, o processo Interface permanecerá suspenso até que um evento ocorra sobre um dos sinais (Enable ou Acknowledge) de sua lista de sensibilidade. Isto permite ao projetista sincronizar o processo Interface com outros processos que utilizem os sinais Enable ou Acknowledge.
Interface: process (Enable, Acknowledge)
begin
...
end process Interface;
Na segunda forma de sincronização, a cláusula wait pode ser empregada para suspender um processo até que seja detectada a ocorrência de um evento sobre um dos sinais explicitados, ou mediante a presença de uma dada condição (acompanhada da cláusula until<condição>). Por exemplo, o processo anterior poderia ser reescrito da seguinte forma:
Interface: process
begin
wait on Enable, Acknowledge ...
end process Interface;
4.3. VERILOG
Verilog foi desenvolvida como uma linguagem de uso particular, voltada para a especificação e simulação de sistemas digitais [22]. Em 1990, foi liberada para o domínio público e, desde então, passou a ser amplamente utilizada como uma linguagem de descrição de hardware.
a) Concorrência
Assim como VHDL, Verilog permite concorrência em nível de tarefas (vários processos executando paralelamente, acionados dentro de uma estrutura fork-join) e concorrência em nível de sentenças (através do uso de operadores de atribuição simultânea).
b) Transição de estados
Esta característica não é suportada em Verilog.
c) Hierarquia
Ao permitir que um sistema possa ser especificado como uma hierarquia de módulos (modules) interconectados, Verilog suporta hierarquia estrutural. Cada módulo pode ser descrito ou através do uso de módulos de nível inferior, ou através da especificação de seu comportamento como um programa. Verilog também suporta hierarquia comportamental, ao permitir que um processo em qualquer nível hierárquico possa ser decomposto em um conjunto de subprocessos paralelos ou seqüenciais.
d) Estruturas de programação
Verilog apresenta um conjunto de estruturas de programação similar à linguagem C, permitindo uma boa descrição de processos. Uma característica poderosa nesta linguagem é a existência de uma PLI (Programming Language Interface) padronizada, a qual permite acessar a estrutura de dados interna do Verilog. Através desta interface, pode-se implementar extensões a um simulador Verilog comercial, tais como:
• um calculador de atraso em linguagem C para uma biblioteca de células; • um gerador de waveform gráfico;
• um depurador (debugging) personalizado; • modelos de simulação em linguagem C; • interfaces hardware/software.
e) Término comportamental
Esta característica é suportada por Verilog tal qual ocorre com VHDL, uma vez que o encerramento de um processo é bem definido (execução da última sentença).
f) Tratamento de exceções
Verilog suporta preempção através da cláusula disable, a qual desabilita um determinado bloco de sentenças seqüenciais e transfere o controle para a sentença seguinte ao bloco.
g) Representação de tempo
Especificação de tempo é suportada em Verilog através da modelagem de atrasos para portas e redes, além do escalonamento na atribuição sobre um sinal. Em relação à modelagem de atrasos, Verilog permite a definição de valores para atrasos associados à subida (rise, passagem do nível lógico 0, x ou z para 1), descida (fall, passagem do nível lógico 1, x ou z para 0) ou desligamento (turn-off, passagem do nível lógico 0, 1 ou x para z) de um sinal. Para tal, utiliza-se o sinalizador de atraso #. Se apenas um valor for especificado após #, o mesmo será utilizado para os três atrasos. Caso dois valores sejam especificados, eles serão utilizados, respectivamente, como atrasos de subida e de descida, sendo o atraso de desligamento implicitamente igual ao menor destes dois valores. Outra opção é explicitar os três valores. O uso de atrasos é dado no exemplo seguinte, o qual modela o comportamento de um multiplexador 2-1:
module multiplexor_2_to_1(out, cnt, a, b);
output out;
input cnt, a, b;
wire not_cnt, a0_out, a1_out;
not # 2 n0(not_cnt, cnt); /* Rise=2, Fall=2, Turn-Off=2 */ and #(2,3) a0(a0_out, a, not_cnt); /* Rise=2, Fall=3, Turn-Off=2 */ and #(2,3) a1(a1_out, b, cnt);
or #(3,2) o0(out, a0_out, a1_out); /* Rise=3, Fall=2, Turn-Off=2 */
endmodule
O sinalizador de atraso # pode ser utilizado de forma similar à cláusula after de VHDL. Atribuições podem ser escalonadas como no exemplo abaixo, onde o valor de x
será atualizado 25 unidades de tempo após a descida do sinal clock:
@(negedge) clock #25 x = y
h) Comunicação
Comunicação pode ser implementada em Verilog através de um modelo de memória compartilhada, utilizando-se fios (wires) que conectam portas à módulos, registradores e memórias, para estabelecer comunicação entre processos.
i) Sincronização de processos
Verilog pode suportar esta característica de várias formas. Sincronização orientada a controle pode ser implementada pelo uso de estruturas fork-join. Instruções de controle de eventos (que verificam mudanças no valor de um sinal) também podem ser utilizadas para sincronizar diferentes processos. No exemplo abaixo, a cláusula wait é utilizada para suspender o processo (no qual está inserida) até que o sinal clock assuma o valor lógico 0 (observe a equivalência com o último exemplo dado, no item g):
wait (clock = 0); #25 x = y;
4.4. CSP
A linguagem CSP (Communicating Sequential Processes, processos seqüenciais que se comunicam) foi proposta por C.A.R. Hore em 1978 [23], visando superar as limitações que as linguagens de programação tradicionais apresentam ao rodar programas em máquinas multiprocessadoras. Posteriormente, outras linguagens foram derivadas de CSP como, por exemplo, Occam [24]. CSP permite especificar um programa como um conjunto de processos concorrentes, usando construtores que simplificam a especificação de comunicação e sincronização entre os processos. Além do seu uso como linguagem de programação, CSP tem sido utilizada para especificar sistemas de hardware.
a) Concorrência
Um programa CSP é formado por uma lista de comandos. O comando parallel
permite que um processo possa ser divido em um conjunto de subprocessos executados em paralelo. O comando encerra-se quando todos os seus subprocessos estiverem terminados. Cada subprocesso de um comando parallel pode ser descrito através de outro comando
parallel e, assim, sucessivamente. Desta forma, CSP suporta concorrência em nível de
tarefas.
b) Transição de estados
CSP não suporta esta característica, uma vez que não está baseada sobre a noção de estado.
c) Hierarquia
CSP suporta hierarquia comportamental, ao permitir o uso do comando parallel
em vários níveis hierárquicos. Hierarquia estrutural não é suportada em CSP.
d) Estruturas de programação
Processos CSP são descritos através de estruturas de programação. Uma característica interessante é que sub-rotinas são implementadas como co-rotinas, as quais executam em paralelo com as rotinas que as chamaram (acionaram). Sub-rotinas recursivas podem ser
simuladas por meio de um vetor de processos, onde cada elemento do vetor representa um nível de recursão.
Estruturas de controle são implementadas através do comando guarded, o qual consiste de uma lista de guardas (condições booleanas) e uma lista de comandos. Estes comandos serão executados somente quando todas as guardas forem verdadeiras.
e) Término comportamental
Esta característica é suportada, uma vez que a execução do último comando dentro de cada processo sinaliza o término do mesmo.
f) Tratamento de exceções
Não há suporte para o tratamento de exceções em CSP.
g) Representação de tempo
CSP não dispõe de mecanismos para a especificação de tempo.
h) Comunicação
Ao contrário das linguagens vistas até agora (VHDL e Verilog), CSP não utiliza um modelo de memória compartilhada, uma vez que não possui variáveis globais. Assim, a comunicação entre processos concorrentes é obtida através de um mecanismo de passagem de mensagens, com o uso dos comandos input e output. Para que um processo P1 envie dados para um processo P2, são necessárias as seguintes condições: a) O comando output de P1 especificar P2 como o destino dos dados a serem enviados; b) O comando input de P2 especificar P1 como a origem dos dados a serem recebidos; c) O tipo do receptor (variável) especificado no comando input de P2 ser compatível
com a expressão do comando output de P1.
i) Sincronização de processos
O único mecanismo de sincronização em CSP é obtido através do bloqueamento (blocking) de um processo envolvido numa comunicação. Neste mecanismo, o processo que primeiro atingir seu comando de comunicação (input/output) ficará suspenso, até que o outro processo envolvido na comunicação fique pronto para a transferência de dados, isto é, alcance seu comando correspondente (output/input).
4.5. STATECHARTS
Estendendo FSM’s com hierarquia, concorrência e comunicação, a linguagem Statecharts [7] foi projeta visando a especificação de sistemas reativos, os quais são sistemas predominantemente de controle, orientados a eventos. O objeto básico em Statecharts é o estado (state), o qual pode ser decomposto em um conjunto de subestados seqüenciais ou concorrentes. Transições entre estados são determinadas por uma combinação de eventos e condições.
a) Concorrência
Statecharts suporta concorrência em nível de tarefas, ao permitir que um estado possa ser decomposto em um conjunto de sub-estados concorrentes, os quais se encontram na condição de ativos (inativos) sempre que o estado pai (nível hierárquico superior) estiver ativo (inativo).
b) Transição de estados
Quando um estado é decomposto em um conjunto de subestados seqüenciais, a passagem de um estado para o outro (transição entre estados) é realizada mediante determinados eventos (que possam ocorrer no sistema modelado) ou condições (referentes a dados do sistema). Esta decomposição seqüencial de um estado pode ser representada por uma máquina de estados, formada pelos subestados do estado e arcos de transições. Ações instantâneas (sem atraso no tempo de computação) podem ser associadas às transições ou estados.
c) Hierarquia
Ao permitir que uma especificação possa ser decomposta em uma hierarquia de estados, Statecharts suporta hierarquia comportamental.
d) Estruturas de programação
Estruturas de programação não são suportadas em Statecharts.
e) Término comportamental
Statecharts não suporta término comportamental. Além disso, comportamento