Oficina
4. A Memória do Computador
Sab 26 Mai 2007 11:21 |
- Detalhes
- Categoria: Sistemas Operacionais
- Atualização: Domingo, 12 Abril 2009 17:29
- Autor: vovó Vicki
- Acessos: 21578
MÓDULO 4 do SO Numaboa
A memória do computador é uma área de armazenamento temporário onde as informações em uso - dos programas e dados - são mantidas enquanto são utilizadas. A memória da máquina é composta por uma porção fixa, que faz parte da placa-mãe, sobre a qual falaremos neste tutorial. Além disto existe a memória RAM (Random Access Memomry - Memória de Acesso Randômico), que é uma (ou mais) plaquinha com chips que pode ser encaixada em soquetes especiais da placa-mãe.
Nos processadores mais novos que os 8086/8088, a memória é capaz de guardar uma fileira de bits muito longa. Nas máquinas citadas, o máximo eram 8.388.608 bits.
A organização dos bits na memória
Vamos fazer algumas contas: se os chips de memória (ROM + RAM) podem guardar até 8.388.608 bits e se 1 byte corresponde a 8 bits, então... os chips podem armazenar 1.048.576 bytes, o mesmo que dizer 1 megabyte. Mas porque estes números quebrados?
Acontece que o computador é essencialmente binário. Kilo no sistema decimal representa 1000 (10 elevado a 3 é igual a 1000), mas convencionou-se que kilo no sistema binário corresponda a 1024 (2 elevado a 10 é igual a 1024). Só para refrescar a memória, veja a tabela abaixo:
|
Mas vamos voltar ao assunto principal. A área da memória, a partir dos processadores 8086 e 8088 (os jurássicos XT), tinha capacidade de armazenar 1 megabyte e a posição de cada byte (um conjunto de 8 bits) dentro da memória podia ser identificada: convencionou-se que seria de 0 a 1.048.575, o que dá o total de 1.048.576 posições. Acontece que os processadores possuíam apenas registradores de 16 bits e os 16 bits fornecem, no máximo, o número 65.535 (1111 1111 1111 1111 binário = 65.535 decimal). Era pouco número para muito espaço de memória. A solução foi usar dois registradores.
Dois registradores de 16 bits dão um total de 32 bits. Agora era bit demais para para pouca memória porque 1 megabyte pode ser expresso com apenas 20 bits. A tabela acima mostra que 2 elevado a 20 corresponde a 1 megabyte, o que é o mesmo que dizer que o binário 1111 1111 1111 1111 1111 é igual a 1.048.575. O circo estava montado - como referenciar os endereços da memória?
Blocos de memória
Como já foi explicado no Curso relâmpago de Assembly, o jeito encontrado foi "lotear" a memória em blocos, cada um deles com 64 Kb (ou 65.536 posições numeradas de 0 a 65.535). Agora, para indicar a posição de um byte na memória, precisava-se de duas referências: o bloco e a posição dentro do bloco.
Fazendo mais algumas contas, verifica-se que 1 Mb pode ser dividido em 16 blocos de 64 Kb. Veja como a continha é fácil:
1 Mb => 1.048.576 bytes 64 Kb => 64 x 1.024 = 65.536 bytes 1 Mb / 64 Kb => 1.048.576 / 65.536 = 16 Blocos
Já que a memória estava toda arrumadinha em blocos, resolveram botar ordem na casa: cada bloco deveria conter dados com uma função definida. A tabela ao lado mostra o que foi convencionado para ser usado pelo sistema operacional DOS:
|
É preciso ficar claro que não existe uma barreira física entre os blocos. A memória continua sendo uma fileira contínua de bytes - são apenas os endereços que delimitam as áreas. Os blocos superiores são os da memória para os usuários e os blocos inferiores são os da memória ROM, somente para leitura e onde o usuário não mexe (ou não deveria mexer ).
Calculando um endereço de memória
Imagine a memória disponível para o usuário como uma fileira de bits contínuos de 640 Kb de comprimento e que cada bloco tenha 64 Kb de comprimento. Quantas partes de 64 Kb você consegue destacar nesta fileira? Até parece pegadinha
A primeira resposta que vem na cabeça da gente é 16 (mesmo porque já fizemos a conta). Pois é, se você respondeu 16, enganou-se! Imagine a primeira parte começando na primeira posição (a posição 0) e indo até a posição do byte 65.535; a segunda parte começando na segunda posição e indo até 65.536; a terceira parte começando na terceira posição e indo até 65.537 e assim sucessivamente. Só por cusiosidade, seria possível destacar 589.824 partes completas! É claro que usamos o expediente de sobrepor as partes, sempre com um intervalo de 1 byte.
Os engenheiros da Intel resolveram fazer a mesma coisa, só que com intervalos de 16 bytes, e chamaram cada parte de segmento. Portanto, segmento de memória são 65.536 bytes contínuos deslocados em 16 bytes para frente em relação ao início do segmento anterior. Está parecendo uma salada? Pois é isto mesmo que os engenheiros conseguiram fazer! A segmentação da memória ficou assim:
Segmento 0 começa na posição 0 e vai até 65535 Segmento 1 começa na posição 16 e vai até 65551 ... Segmento 100 começa na posição 1600 e vai até 67135 ... Segmento X começa na posição X*16 e vai até X*16 + 65535
Os blocos passaram a ser denominados Segmentos e a posição dentro de um bloco foi chamada de Deslocamento (offset, em Inglês). Convencionou-se indicar com Segmento:Deslocamento o parzinho que aponta uma determinada posição.
Agora um conceito importante: a diferença entre endereço absoluto ou real e endereço segmentado ou relativo. O endereço absoluto é o endereço físico, como se contássemos as posições na memória apontando com o dedo. O endereço segmentado é o indicado pelo parzinho Segmento:Deslocamento.
Talvez um exemplo de como 3 endereços segmentados indicam o mesmo endereço absoluto tire qualquer dúvida. Veja abaixo:
4660:0005 => 4660 x 16 + 5 = 74.565 4656:0069 => 4656 x 16 + 69 = 74.565 4608:0837 => 4608 x 16 + 837 = 74.565
Abra a calculadora do Windows, passe-a para o modo científica e transforme os números acima em hexadecimal (a notação usada com frequência no Assembly). Lembre-se que 16 decimal corresponde a 10 hexadecimal, portanto, basta adicionar um 0 ao hexadecimal para multiplicá-lo por 16. Você deve obter o seguinte:
1234:0005 => 1234 x 10 + 5 = 12340 + 5 = 12345 1230:0045 => 1230 x 10 + 45 = 12300 + 45 = 12345 1200:0345 => 1200 x 10 + 345 = 12000 + 345 = 12345
Curiosidades
Existem algumas coisas interessantes que podemos aprender sobre a organização da memória. Conhecer estas características vai ajudar, e muito, o nosso projeto. A partir de agora vou utilizar apenas a notação hexadecimal.
A tabela de vetores de interrupção
Logo no início da área de memória, ou seja, a partir da posição 0000:0000 até a posição 0000:03FF, existem 1024 bytes reservados para uma tabela onde se encontram os endereços segmentados (par segmento:offset) das rotinas de tratamento de interrupções. Neste espaço reservado podem ser armazenados até 256 pares segmento:deslocamento, ou seja, 256 conjuntos de 4 bytes. Adivinhe só onde o processador vem buscar esta informação quando recebe uma requisição de interrupção? É aqui na tabela de vetores de interrupção. Se a interrupção for 0, ele pega o primeiro par; se for 1, ele pega o segundo par; ou seja, se for X pega o par X * 4.
É fácil ficar contando as coisas, mas é meio sem graça. Aposto que você, assim como eu, gosta de ver para crer. Para conferir o que foi dito, basta usar um programa que acompanha o Windows: o DEBUG.EXE. Este programa você encontra no diretório \Windows\system32 e, para rodá-lo, basta dar um duplo clique. Aparece a janela de fundo preto do shell do DOS com um cursor "-". Digite "?" (sem as aspas) e Enter para obter a ajuda do programa.
Verifique o comando D [range]. Este comando faz um dump (listagem) do que for pedido através do parâmetro range (área). Experimente digitar D 0:0 seguido de Enter:
Na minha máquina, os primeiros quatro bytes, que se referem ao vetor da interrupção 0, são 68 10 A7 00. Na sua máquina, com boa probabilidade, os números serão diferentes. Bem, existe uma gracinha chamada little endian que faz com que os bytes sejam inseridos na memória "ao contrário". Para que nós, mortais comuns, possamos entender, é preciso inverter suas posições: 68 10 A7 00 representam 00A7:1068, ou seja, segmento 00A7 e deslocamento 1068. Isto quer dizer que a rotina referente à interrupção 0 se encontra no endereço absoluto 00A7 x 10 + 1068, ou seja, 1AD8 (não vamos precisar dele, foi só para treinar).
O segundo quarteto de bytes é 8B 01 70 00, que corresponde a 0070:018B. Apenas por curiosidade, digite U 70:018B e depois Enter. U é o comando para transformar os códigos operacionais em Assembly, ou seja, mostram o código que será executado pela CPU quando receber uma solicitação de interrupção 1 (exceção de debug).
Considerações finais
Não foi abordada aqui a área de memória de sistemas de 32 bits e nem a memória estendida. Será assunto de outro tutorial, quando analisarmos o modo protegido. Releia este texto tantas vezes quantas forem necessárias para entendê-lo perfeitamente. O gerenciamento da memória, que deverá ser feito pelo nosso sistema operacional, depende essencialmente deste entendimento.