Baixe o app para aproveitar ainda mais
Prévia do material em texto
INSTITUTO FEDERAL DO ESPÍRITO SANTO BACHARELADO EM SISTEMA DE INFORMAÇÃO JEAN CARLOS PENAS ARQUITETURA DE COMPUTADORES SERRA 2014 P a g i n a 2 JEAN CARLOS PENAS ARQUITETURA DE COMPUTADORES Trabalho apresentado no curso de Bacharelado em Sistemas De Informação, Na disciplina Organização e Arquitetura de Computadores no Instituto Federal do Espírito Santo Professor: Flavio Giraldeli SERRA 2014 P a g i n a 3 Resumo Neste relatório será inferido aspectos entre duas linguagens em função da diferença do nível de abstração entre elas. A primeira linguagem é o assembly, depois da binária é a linguagem mais próxima da máquina, nela é possível acessar o conteúdo e endereço dos registradores, manipular interrupções e portas lógicas, na programação de circuitos. A principal característica desta linguagem é uso de instruções simples, isto graças a organização ISA, que traz consigo um conjunto de instruções simples com o propósito de facilitar o projeto do hardware e a geração do código por parte do compilador. A linguagem C é uma linguagem mais abstraída e por este motivo utiliza instruções que operam sobre estruturas de dados complexas. Em linguagens com alto nível de abstração a compilação de uma sequência de instruções geralmente gera uma sequência maior de instruções ISA que funcionam sobre estruturas de dados mais simples, presentes também no programa fonte. Segundo o projeto ISA, o objetivo da linguagem de máquina como o assembly é dar suporte as linguagens com um nível de abstração superior como a linguagem c, permitindo o uso de estruturas de dados como procedimentos, variáveis locais, variáveis globais, constantes, operações como alocação e realocação dinâmica, tipos estruturados, funções e etc. Então é exatamente em cima das instruções oferecidos pela arquitetura ISA que vamos avaliar quantidade de instruções de maior relevância, alguns aspectos entre as duas linguagens e mesclar as vantagens de se utilizar linguagens como essas em situações do mundo real por meio de um algoritmo de uma calculadora simples. P a g i n a 4 Abstract This report is inferred aspects between two languages depending on the difference in the level of abstraction between them. The first language is the assembly, after the binary is the closest machine language, it is possible to access the content and address of registers, handle interruptions and logic gates in circuit programming. The main feature of this language is the use of simple instructions, this thanks to ISA organization that brings a set of simple instructions in order to facilitate the design of hardware and code generation by the compiler. The C language is a more abstracted language and for this reason uses instructions that operate on complex data structures. In languages with a high level of abstraction to compile a sequence of instructions usually generates greater sequence ISA instructions that operate on simple data structures, also present in the source program. According to the ISA project, the goal of machine language as the assembly is to support languages with a higher level of abstraction as the C language, allowing the use of data structures and procedures, local variables, global variables, constants, operations like dynamic allocation and reallocation, structured types, functions, and so on. So right on top of the instructions offered by ISA architecture that we evaluate the amount of instruction more relevant, aspects between the two languages and merge the advantages of using languages like those in real-world situations by using an algorithm of a calculator simple. P a g i n a 5 ILUSTRAÇÕES Figura 1 – 4 Linhas, Assembly X 7 Linhas, C, para um mesmo resultado. ............................... 8 Figura 2 – Assembly. .................................................................................................................. 8 Figura 3 – Linguagem C. ............................................................................................................ 8 Figura 4 - Definição De Variáveis Em Assembly. ...................................................................... 9 Figura 5 - Definição De Variáveis Em C. ................................................................................... 9 Figura 6 – Registradores. ............................................................................................................ 9 Figura 7 – Execução da calculadora em Assembly, Números Grande Positivos. .................... 10 Figura 8 – Execução Da Calculadora Em assembly, Números Grandes Negativos. ................ 10 Figura 9 – Interrupções, Assembly. .......................................................................................... 11 Gráfico 1 - Linhas/Instrução, Código Assembly. ..................................................................... 11 Gráfico 2 - Composição dos trechos de código retirados do EMU8086.INC .......................... 13 P a g i n a 6 SUMÁRIO RESUMO ................................................................................................................................... 3 INTRODUÇÃO .......................................................................................................................... 7 ASPECTOS ENTRE AS LINGUAGENS .................................................................................. 8 QUANTIDADE DE INSTRUÇÕES ........................................................................................ 11 MACROS E PROCEDIMENTOS ........................................................................................... 12 O ALGORITMO ASSEMBLY ................................................................................................. 14 CONCLUSÃO .......................................................................................................................... 15 REFERÊNCIAS BIBLIOGRÁFICAS ..................................................................................... 17 P a g i n a 7 INTRODUÇÃO Linguagem, o que seria linguagem? É qualquer sistema ou conjunto de sinais convencionais, fonéticos ou visuais, que servem para a expressão dos pensamentos e sentimentos, ou conjunto de sons em cuja produção intervém a lingua ou articulação, ou ainda sistema de representação que os membros de uma comunidade linguística usam como principal meio de comunicação, falado ou escrito? Enfim não existe uma definição específica para o termo linguagem, mas no campo da computação ela é tratada como um conjunto de símbolos, palavras e regras que expressam comandos que são interpretados pelo processador. A linguagem a ser avaliada é exatamente aquela que está relacionada ao computador. Na computação existem várias linguagens cada qual com um nível de abstração específica, mas resolveram generaliza-las como baixo, médio e alto nível. Neste relatório vamos avaliar duas linguagens, uma com um nível de abstração baixo e a outra com um nível mediano que são a linguagem assembly e a C, respectivamente. Para citar os aspectos entre elas seria necessário conhecer a arquitetura que está oculta no computador. A arquitetura do computador é divida em seis níveis que são: Nível lógico digital, micro arquitetura,arquitetura de instruções, sistema operacional, linguagem assembly, linguagens de alto nível. A arquitetura ISA se configura extamente no terceiro nível que é a onde os programadores de baixo nível devem ter total conhecimento em função das instruções oferecidas por ela, para que a solução seja construída com eficiência, essas instruções serão gerenciadas pelo sistema operacional e este irá oferecer toda uma estrutura para que seja possível a implementação da linguagem asssembly que por sua vez servirá de suporte para as linguagens medianas e de alto nível. Programar em uma linguagem como o assembly é complicado, por isto a necessidade de criar níveis de organização para facilitar a programação. Como já foi mencionado o terceiro nível de organização é a arquitetura ISA, em outras palavras é tratada como um conjunto de instruções que representam a interface entre o software e o hardware. Nesta interface cada nível de organização possui uma linguagem associada e então a medida que a linguagem evolui a favor do usuário, ela vai se tornando mais conveniente para ele. Nesta mesma arquitetura o usuário escreve um programa fonte que pode ser escrito tanto em linguagem de alto nível quanto em uma linguagem de montagem e então o programa é traduzido para um código objeto numa linguagem de máquina e desta forma ele é interpretado por um micro programa ou por um hardware. O objetivo final é falicitar o projeto do hardware P a g i n a 8 e tornar a compilação mais eficiente, no entanto, segundo a Universidade Federal Do Rio Grande Do Norte em uma das suas pesquisas diz que o projeto de uma linguagem de máquina deve dar suporte aos níveis de organização superiores para que seja possível construir estruturas de dados como procedimentos, variáveis locais, variáveis globais, constantes e dentre outros que por sua vez seriam utilizados numa linguagem de alto nível. Então para criar soluções em ambientes onde os detalhes a respeito da arquitetura e da organização são fundamentais será necessário um conhecimento eminente de cada aspecto como modelo da memória, conjunto de registradores, formato de instruções, modos de endereçamento, tipos de instruções e fluxos de controle que são considerados fundamentais nesse nível de organização. ASPECTOS ENTRE AS LINGUAGENS Sabe-se que as duas linguagens se diferem na questão do nível de organização da arquitetura, então é interessante frisar as consequências da implementação, como por exemplo a questão do conjunto de instruções que quanto mais simples, maior serão as linhas necessárias para produzir uma mesma solução que em outra linguagem poderia ser escrita em pouquíssimas linhas, a Figura 1 avalia exatamente esta propriedade. As instruções de movimento, pilha, saltos incondicionais e condicionais e o uso de registradores também existem na linguagem C, mas não são acessíveis ao programador, mas podem ser notadas. Abaixo há imagens, Figura 2 e Figura 3 que vão mesclar exatamente algumas dessas características que uma pessoa desinformada dificilmente conseguiria notar. Na Figura 2, tem-se comparações seguidas de Figura 1 – 4 Linhas, Linguagem CX 7 Linhas, Assembly, para um mesmo resultado. Figura 2 – Assembly. Figura 3 – Linguagem C. P a g i n a 9 saltos, pilha, saltos incondicionais, instruções de movimentação de dados, operações aritméticas e flags, essas características foram inferidas na linguagem c. Na Figura 3, temos uma instrução switch que vai receber o endereço que contém o operador e a partir disto ele vai determinar o fluxo por uma série de desvios seguidos de saltos condicionais e incodicondicionais para produzir um resultado que então será armazenado em um endereço e impresso na tela. Neste caso temos fatores comuns que são operações de desvios e a utilização de labels para determinar o desvio do fluxo, mas porém as operações de pilha e a sinalização por flags não estão visíveis na linguagem c. Porém existe toda uma série de cuidados que foram obedecidos na Figura 2 e que na Figura 3 não oferece risco de penalização pois não está sob o domínio do programador, trata-se das operações que acontecem na pilha, esta estrutura é compartilhada pelas instruções ret, call, pop e push que colocam e retiram endereços e valores no topo da pilha, neste cenário será necessário apenas uma operação de pilha indevida para que toda execução do código seja penalizada. Na Figura 4 é apresentado a forma de como se declara variáveis no assembly, neste caso não existe definição de tipos como inteiro, char e real. A única definição possível é do tamanho da variável que será criada, ou seja ela pode ser de 8 ou 16 bits (DB ou DW, respectivamente), já na Figura 5, na linguagem c, os aspectos mudam e existe toda uma estrutura para que seja possível definir tipos Figura 5 - Definição De Variáveis Em C. Figura 4 - Definição De Variáveis Em Assembly. Figura 6 – Registradores. P a g i n a 10 para cada variável. Além disto no assembly qualquer variável é global e na linguagem c esta mesma propriedade não é aplicável. O assembly não é case sentive ou seja a variável VAR1 = var1=Var1 e assim por diante, já na linguagem c esta característica não foi notada, ou seja ele é case sentive, a variável VAR1 é diferente da variável var1 e assim por diante. Outro aspecto que dificlmente seria acessível na linguagem C são os registradores, todos eles são de 16 bits, mas cada qual possui um par de registradores de 8 bits e como podem ver, a Figura 6 mostra um conjunto finito de registradores cada qual com uma propriedade específica, por exemplo os registradores de azul são de endereço, os verdes são de propósito geral, os de laranja são registradores de seguimento, e o vermelho é composto pelo registrador IP usado somente pelo sistema operacional para calcular o endereço de uma instrução e outro usado para flags. Especificamente cada registrador possui uma propriedade, o registrador AX é usado para calculos aritméticos; BX é um registrador base para referencia de posições de memória; CX é utilizado em operações iterativas como contador; DX para armazenar parte de um produto de 32 bits em operações de multiplicação e resto em uma divisão, além disto é usado para especificar endereço de uma porta de E/S. Os registradores de seguimento são usado para endereçamento do código de programa, dados e pilha e o registrador IP é usado para calcular o endereço da proxima instrução que será executada. Outra observação é a quantidade de locais endereçáveis na memória, no caso de uma variável de 8 bits é possível endereçar 256 locais de memória e a faixa de valores para que seja possível a sua representação é considerando a parte negativa e positiva do conjunto, desta forma qualquer número que for armazenado numa posição de memória de 8 bits terá que existir na faixa de -128__0__127, se o número for de 16 bits a faixa muda para este formato -32768_0_32767. Esta noção de quanto de memória usada em uma variável e a faixa de valores usados para representa-la é necessário, pois será uma das condições para que determinados tipos de calculos indevidos ou difíceis de ser tratados possam ser evitados, a Figura 8 e a Figura 7 ilustram muito bem esta situação. Além disto, como podem ver não foi implementado uma validação para evitar operações semelhantes a essas ilustradas pelas figuras acima, então se o número for positivo e Figura 7 – Execução da calculadora em Assembly, Números Grande Positivos. Figura 8 – Execução Da Calculadora Em assembly, Números Grandes Negativos. P a g i n a 11 muito grande a ponto deser maior do que (2^(n-1)-1) ele terá outra representação que corresponderá ao extremo negativo deslocado em V-(-2^(n-1)) vezes, se for negativo porém muito grande ele vai para o extremo positivo (2^(n-1)-1) também deslocado em V-(2^(n-1)-1) o mesmo problema também acontece na linguagem c, alguns professores consideram esses resultados como corretos e lógicos, serial algo como está errado, mas está certo. Além dos registradores, as interrupções não são acessíveis na linguagem C, mas estão implícitas. O termo Interrupção é definido como o instante em que o processador desvia o seu fluxo de execução, salvando o ponto em que foi interrompido para atender uma solicitação e voltar para o ponto onde parou. Na Figura 9 mostra a interrupção INT executando uma subfunção 10H usada na Macro SALTALINHA implementada no algoritmo da calculadora para saltar uma linha na tela do usuário na impressão. QUANTIDADE DE INSTRUÇÕES Como Previsto foram necessárias 321 linhas de código para desenvolver o algoritmo da calculadora simples em assembly, 54% ((176/321) *100) do algoritmo está dentro do trecho compreendido entre o ORG e a ultima instrução ret a ser executada. Os outros 44% foram retirados de uma biblioteca chamada emu8086.inc. O tempo de implementação deste algoritmo foi relativamente rápido. Foram necessários 30 minutos para implementar os procedimentos e as macros que já estavam prontas e foram necessárias 3 horas para implementar o trecho principal equivalente ao ORG, no total foram 3 horas e meia, então tecnicamente foram escritas 176 linhas de código (Os dados numéricos foram calculados com base no Gráfico 1). Na Figura 9 – Interrupções, Assembly. 8 10 20 80 12 176 6 9 321 0 50 100 150 200 250 300 350 IMPRIME PRINT_NUM_UNS PRINT_NUM SCAN_NUM DECLARAÇÕES ORG PUTC SALTALINHA TOTAL Linhas/Assembly Gráfico 1 - Linhas/Instrução, Código Assembly. P a g i n a 12 linguagem C, o código do mesmo algoritmo corresponde aproximadamente 15% do assembly, ou seja foram necessários 51 linhas de código para fazer o mesmo algoritmo em C, além disto, somente 12% do tempo de implementação do algoritmo em assembly foi utilizado para implementar o mesmo problema na linguagem c, ou seja foram necessários 25 minutos para a implementação. Os dados numéricos e o Gráfico 1 mostra que ao simplificar as instruções duas linhas de raciocínio serão criadas, a primeira é vantajosa para o processador, pois com instruções simples precisará de menos ciclos para executá-las e consequentemente isto tráz vantagens para o compilador, porém a complexidade da implementação e manutenção de soluções feitas em linguagens que se baseiam em instruções simples como o assembly aumenta conforme o domínio do problema. A segunda vertente é vantajosa para o ser humano pois ao resolver um problema em um ambiente com instruções mais complexas e longas e com dominíos maiores, poucas linhas de código serão necessárias para a sua construção, isto torna o código mais legível, fácil de se implementar e de se corrigir. Por outro lado essas instruções exigirão mais ciclos para serem processadas e consequentemente o programa será mais lento. MACROS E PROCEDIMENTOS Como ja foi mencinado 44% do algoritmo implementado na linguagem assembly é composto pelos trechos de código que foram retirados de um arquivo e estão representados no gráfico de pizza, cada trecho recebe uma entrada e produz um resultado que poderá ou não ser usado por outro trecho ou então ser impresso na tela, desta forma será descrito cada um deles, na sequência em que se encontra na legenda do Gráfico 2, modelo pizza. P a g i n a 13 Gráfico 2 - Composição dos trechos de código retirados do EMU8086.INC Dos 44% de código retirado do arquivo estão sendo representados no gráfico acima, as porcentagens descritas revelam o tamanho da partipação de cada um deles no código da calculadora. Um exemplo disto é o SCAN_NUM que compôe 60% dos 44% de código que foram tirados do arquivo EMU8086.inc. Abaixo foram definidas de forma resumida a participação de cada um desses trechos no algoritmo. PRINT_NUM_UNS É um procedimento para impressão de números positivos, ele recebe um número que será gerado pelo PRINT_NUM e por uma série de divisão na base 10 ele vai calculando o valor de cada dígito até formar uma cadeia caracteres (Tabela ASCII) que represente exatamente o valor dado na entrada. PRINT_NUM É um procedimento de impressão, ele espera o valor em AX para ser imprimido, quando o valor é zero ele simplesmente imprimi o caracter zero na tela, quando o numero é positivo, ele chama o procedimento PRINT_NUN_UNS para impressão de um número positivo, caso o numero seja negativo, ele faz o complemento de dois para obter o número e configura a sua impressão como um número negativo. SCAN_NUM É um procedimento e a sua função é receber a entrada do usuário e configurá-la para que possa ser processada. Ele usa uma instrução para imprimir o caracter dado na entada e P a g i n a 14 outra instrução para armazenar –lo e em cada iteração ele vai formando a entrada do usuário, ele possui a implementação do backspace para deletar o caracter na entrada que é feita através de uma operação deslocamento de base 10 para esquerda (Divisão) no fluxo de execução através do registrador CS. Quando é escrito um número (caracteres) muito grande ele desloca a cadeia de caracteres para direita através de uma multiplicação na base 10. Quando um número com sinal é dado na entrada, ele seta o valor dela no fluxo de execução para 1, quando o usuário digita Enter, o seu valor é ajustado para zero. O interessante deste procedimento é que ele vai formando o valor através de operações deslocamento e depois forma o número través de uma operação de complemento de 2, se necessário. PUTC É uma macro que recebe uma entrada cujo tamanho é de 8 bits e sobre ação de uma subfunção de impressão e de uma instrução de interrupção ela imprimirá um caracter na tela. SALTALINHA É uma macro, ela utiliza a mesma instrução e interrupção da macro PUTC para impressão de caracter na tecla, com uma diferença são combinados dois caracteres que provocarão um salto de linha, ambos estão baseados na tabela ASCII. O ALGORITMO ASSEMBLY Nas operações abaixo não foi implementado a verificação do número em relação a faixa de representação, então se o número for positivo e muito grande a ponto de ser maior do que (2^(n-1) -1) ele terá outra representação que corresponderá ao extremo negativo deslocado em V-(-2^(n-1)) vezes, se for negativo porém muito grande ele vai para o extremo positivo (2^(n-1) -1) também deslocado em V-(2^(n-1) -1). Soma O algoritmo da calculadora se inicia recebendo o operador e os operandos na entrada pelo usuário, em seguida é feita uma série comparações seguidas de saltos para determinar qual operação será feita. Foram implementadas quatro operações, a primeira delas é a soma, nesta operação os operandos salvos na pilha são retirados para não influenciar na resultante final, a operação de soma acontece, existe a possibilidade de overflow então é verificada, caso aconteça ela é sinalizado com a impressão da frase “OVERFLOW!” e o algoritmo termina, P a g i n a 15 caso contrário ele imprime a mensagem “RESULTADO” com um procedimento para impressão de caracteres e outro para impressão do valor em AX. Subtração Na subtração, a operação de subtração acontece, nela é feita uma verificação de overflow, caso tenha sucesso o overflow será sinalizado, se o overflow nãoacontecer o valor de saída estará no registrador AX e um procedimento de impressão é utilizado para imprimir a mensagem para o usuário e outro para impressão do valor em AX. Multiplicação Nesta operação foi necessário validar o sinal dos operandos, caso fossem positivos uma instrução MUL será utilizada para fazer a operação, caso haja overflow ele é sinalizado, do contrário o valor é impresso na mesma configuração dos trechos acima. Para números com sinal a multiplicação é feita com a instrução IMUL e os mesmo procedimentos para sinalizar o overflow ou o resultado são feitos iguais aos trechos acima. Divisão Se os valores estiverem dentro da faixa, é verificado se o segundo operando é zero para evitar uma divisão por zero, se o número for positivo será utilizada instrução DIV, antes da operação o registrador DX é inicializado com zero para para evitar calculos errados provocados por lixo então é verificada a possibilidade de overflow caso aconteça será sinalizado do contrário o resultado impressão na mesma configuração dos trecho acima. CONCLUSÃO Para comfirmar a hipótese de que tornando as instruções mais simples, o tempo de implementação seria grande, tomamos como exemplo o algoritmo da calculadora em assembly, ja ousamos criar algoritmos muito mais complicados do que uma calculadora simples, mas não se engane o tempo de implementação da calculadora nesta linguagem durou 3,5 horas. Para confirmar o fato de que tornando as instruções mais complexas mas porém com domínios maiores, as soluções se tornam fáceis de se implementar tomamos como exemplo a duração da implementação do mesmo algoritmo na linguagem C, que foi de mais ou menos 25 minutos. A complexidade do algoritmo na linguagem assembly aumentou com a questão dos sinais, segundo o professor Giraldeli não seria necessária a implementação de um procedimento para validar os sinais, logicamente isto foi seguido quando foi percebido que os procedimentos SCAN_NUM, SCAN_NUM_UNS, PRINT_NUM e o PRINT_NUM_UNS P a g i n a 16 fazia tal validação e toda a configuração necessária para falicitar os calculos. Durante a implementação do código no montador assembler foi notado que não seria uma tarefa simples, pois o conhecimento sobre quais registradores usar, administração da pilha de endereços e de execução que é compartilhada, interrupções e subfunções seriam necessários. Este conhecimento está diretamente ligado a arquitetura do computador ou seja teria que ser feita perguntas do tipo: Será que o processador possui o conjunto de instruções necessário para implementar ou construir tal solução? Um conhecimento mais profundo sobre a organização e a arquitetura do computador seria necessário para resolver problemas mais complexos. Ocorreu a oportunidade de implementar operações interessantes vistas em sala de aula como o complemento de dois que é feita com a instrução NEG. Concluiu-se que cada instrução é parte fundamental do código, uma operação errada, toda a execução é penalizada. Foi visto que o armazenamento de números muito grandes sejam eles positivos ou negativos saltavam para o extremo negativo da faixa de representação -2^(n-1) deslocado em A vezes ou saltavam para o extremo positivo (2^(n-1) – 1), o primeiro acontecia quando número é positivo porém maior que o limite positivo da faixa de representação, o segundo aconteceia quando o número era negativo porém maior que a faixa negativa de representação. Esses aspectos são considerados como errados, mas certos. Um dos trechos dos códigos retirados do arquivo EMU8086.INC me chamou a atenção, trata-se do SCAN_NUM combinado com o SCAN_NUM_UNS, ele usufrui das operações de deslocamento binário para formar o número, tratar sinais e evitar que números muito grandes sejão inseridos na entrada, muito interessante esta idéia e é muito utilizada pelo processador em determinados tipos de operações com o propósito de ganhar tempo. A arquitetura do computador é organizada em 6 níveis começando do mais baixo para o mais alto e começa com o nível lógico digital, microarquitetura, cojunto de instrução, sistema operacional, linguagem assembly, e finalmente a linguaguem de alto nível, como foi percebido, o sistema operacional é responsável por oferecer suporte a linguagem assembly para que seja possível a implementação da solução do problema. O conjunto de instruções tem papel fundamental no suporte ao sistema operacional é nele que é definido se tais instruções serão do tipo CISC ou RISC, um exemplo de arquitetura RISC é a ISA que é o conjunto instruções simples que visa melhorar a performance do processador e a geração de código por parte do compilador se baseando no fato de que instruções simples precisam de menos ciclos para serem processadas como consequência processador ganha tempo de processamento ao lhe dar com elas. P a g i n a 17 REFERÊNCIAS BIBLIOGRÁFICAS USP. Compiladores. Disponível em: http://www.icmc.usp.br/pessoas/delamaro/SlidesCompiladores/Aula1- Cap1.pdf Acesso em 25 de Júlio, 2014. UFU. Linguagem De Programação. Disponível em: http://www.daniel.prof.ufu.br/apostilas/linguaProgram.pdf Acesso em 25 de Júlio, 2014. UFU. Linguagem De Programação. Disponível em: http://www.ime.usp.br/~song/mac412/oc-risc.pdf Acesso em 26 de Júlio, 2014. UFMG. Arquitetura. Disponível em: http://www.verlab.dcc.ufmg.br/_media/cursos/arquitetura/2007- 1/transparencias/aula04-prig.pdf Acesso em 27 de Júlio, 2014. UFRN. Nível ISA. Disponível em: http://www.dca.ufrn.br/~pablo/FTP/arq_de_comp/apostilha/capitulo3.pdf Acesso em 3 de Agosto, 2014. Projeto Lógico De Computadores. ISA. Disponível em: http://walderson.com/2012-2/plc/aula3-plc-nisa.pdf Acesso em 4 de Agosto, 2014.
Compartilhar