Endereços de Memória no MIPS

mips

Oi pessoal! Tudo bem? Espero que sim. Nos últimos três artigos desta série eu apresentei as instruções de operações lógicas mais comuns: AND, OR e NOT. No quarto, quinto e sexto artigos apresentei a vocês como converter Arrays para MIPS, usando instruções de carga (LW) e armazenamento (SW). No sétimo, oitavo e nono artigos apresentei as principais instruções MIPS de desvio: BNE, BEQ e SLT. Estou citando esses artigos anteriores pois hoje vou apresentar a vocês um conceito muito importante que deve ser considerado para o conjunto de instruções inteiro do MIPS: os endereços de memória no MIPS.

 

Big Endian e Little Endian

 

Grande parte das Arquiteturas de Computadores são endereçáveis por Byte (8 bits) e o MIPS é uma delas. Assim, arquiteturas de computadores podem ser classificadas de acordo com a ordem dos bytes, o que é denominado Endian. Quando se projeta para armazenar os bytes menos significativos nos endereços mais baixos, tem-se uma arquitetura Little Endian. Já quando os bytes mais significativos são armazenados nos endereços mais baixos, tem-se uma arquitetura Big Endian. A Tabela 1 exemplifica as diferenças entre os dois tipos de arquiteturas.

 

Big

Byte 0

Byte 1

Byte 2

Byte 3

Little

Byte 3

Byte 2

Byte 1

Byte 0

 

Mais alto

Mais baixo

Tabela 1: Exemplo de Big Endian e Little Endian.

 

Restrição de Alinhamento

 

Já vimos aqui na série como trabalhar com Arrays e instruções de desvio, porém, naquela ocasião, não expliquei com detalhes a forma que é armazenado e localizado na memória, portanto, é chegada a hora. Normalmente, as Linguagens de Programação de Médio e Baixo nível permitem que os programadores trabalhem desde variáveis simples, até variáveis mais complexas, como os Arrays, Listas, Filas, Pilhas, Árvores, etc., que além de serem estruturas de dados mais elaboradas, também podem ser de vários tipos de dados (heterogêneo), e não apenas um (homogêneo).

 

Como bem sabemos, uma Arquitetura de Computadores de 32 bits possui 32 registradores, e assim por diante. Portanto, a quantidade de dados que pode ser manipulada por Linguagens de Alto/Médio nível é muito maior que a quantidade de registradores disponível no computador. Exemplificando: imagine um software de processamento de texto, como o Microsoft Word, executando em seu computador; um arquivo gerado por esse tipo de software gera muitos bytes, sendo impossível armazenar esses bytes nos registradores. Daí eu faço uma pergunta a vocês: Como um computador pode representar, e também acessar, essas estruturas de dados, que costumam ser realmente muito grandes?

 

A resposta para essa pergunta você, com certeza, já deve saber, porém vou elucidar. Um Sistema Computacional é formado por vários outros sistemas, que conversam entre si, entre eles: sistema de entrada e saída, sistema de barramento, sistema de armazenamento, sistema de processamento, etc. Caso esteja com muita dúvida a respeito disto, sugiro ler o artigo que eu escrevi sobre o assunto Arquitetura de John Von Neumann. Quando terminar lá, volte aqui, tudo bem?

 

Então, concluímos que as Memórias RAM, e também as Memórias Cache, são aquelas que podem resolver o nosso problema com as estruturas. Assim, o Processador mantém uma pequena quantidade de dados nos registradores e, na Memória RAM/Cache, a maior parte deles. Quando trabalhamos com ARRAYS na compilação de instruções de alto/médio nível para Assembly MIPS, conforme já mencionado em artigos anteriores, devemos sempre usar as instruções LW e SW, para realizar a transferência dos dados entre os registradores e a memória RAM/Cache.

 

Para acessar uma palavra na memória, é necessário que a instrução forneça o endereço de memória, o qual começa em zero e atua como índice. O endereço, portanto, é um valor usado para delinear o local de um elemento de dados específico dentro de uma sequência da memória. A Figura 1 ilustra os endereços de memória com o processador.

 

Representação dos Endereços de Memória
Figura 1: Representação dos Endereços de Memória

 

Observe que o endereço 0 contém o valor 1, o endereço 1, o valor 101, e assim por diante. Porém, como já dito anteriormente, o MIPS trabalha com endereços de bytes, com cada palavra representando quatro (4) bytes. Dessa forma, a representação da Figura 1 não é condizente com a realidade do MIPS. A Figura 2 apresenta a forma correta:

 

Representação dos Endereços de Memória em múltiplos de 4
Figura 2: Representação dos Endereços de Memória em múltiplos de 4

 

O compilador Assembly MIPS aloca esses tipos mais complexos em memória, colocando o endereço inicial apropriado nas instruções de transferência de dados. Como o MIPS endereça bytes individuais, o endereço de uma palavra combina os endereços dos 4 bytes dentro da palavra, o que faz com que os endereços sequenciais das palavras sejam diferentes em quatro vezes. Note na Figura 2 que começa em zero, mas os endereços pulam de 4 em 4. Dessa forma, o valor 1 continua no endereço 0, mas o valor 101, que antes estava no endereço 1, agora está no endereço 4, e assim por diante. Essa situação toda gera uma restrição de alinhamento, que é justamente o fato de obrigar as palavras a começarem em endereços que sejam múltiplos de 4.

 

Calculando o índice do array

 

Com a restrição de alinhamento, o endereçamento em bytes acaba por afetar o índice do array, sendo necessário fazer um pequeno cálculo para que seja atribuído o valor de endereço correto ao índice. Vou utilizar aqui o exemplo do artigo 4

 

a = b + c [10]

 

que em Assembly MIPS é

 

LW  $t0, 10 ($s2)                  # $t0 = memória [ $s2 + 10 ]

LW  $8, 10 ($18)                   # $8 = memória [ $18 + 10 ]

 

O deslocamento correto aqui não é 10, seria se os endereços fossem como na Figura 1. O endereço correto é 10 * 4, pois na verdade o índice é:

 

a = b + c [ 40 / 4 ]

 

Assim garantimos que o índice correto será selecionado, isto é, o índice 10 será selecionado e não o índice 40. Em Assembly MIPS fica da seguinte forma:

 

LW  $t0, 10 ($s2)                  # $t0 = memória [ $s2 + (10 * 4) ] = memória [ $s2 + 40 ]

LW  $8, 10 ($18)                   # $8 = memória [ $18 + (10 * 4) ] = memória [ $18 + 40 ]

 

Vou usar agora o exemplo do artigo 5, que trata da instrução MIPS SW:

 

A [ 15 ] = a + b

 

Que em Assembly MIPS é:

 

SW $t0, 15 ($s0)                    #memória [ $t0 + 15] = $8

SW $8, 15 ( $s16 )                 #memória [ $8 + 15] = $8

 

O endereço MIPS é especificado em parte por uma constante (15) e outra parte pelo conteúdo do registrador ($s0). Novamente, o endereço correto é 15 * 4 e não apenas 15, assim temos:

 

A [ 60 / 4 ] = a + b

SW $t0, 15 ($s0)                    #memória [ $t0 + (15 * 4) ] = memória [ $t0 + 60 ] = $8

SW $8, 15 ( $s16 )                 #memória [ $8 + (15 * 4) ] = memória [ $8 +  60 ] = $8

 

Para finalizar, e certificar que todos conseguiram entender, vou mostrar como fica o exemplo do artigo 6:

 

A [ 22 ] = b [ 1 ] – c

 

LW $t0, 1 ($s1)           # $t0 = memória [ 1 + $s1 ]

SUB $t1, $t0, $s2

SW $t1, 22 ($s0)          # memória [ 22 + $s0 ] = $t1

 

LW $t0, 1 ($s1)           # $t0 = memória [ (1 * 4) + $s1 ] = memória [ 4 + $s1 ]

SUB $t1, $t0, $s2

SW $t1, 22 ($s0)         # memória [ ( 22 * 4) + $s0 ] = memória [ 88 + $s0 ] = $t1

 

Spilled Registers

 

Spilled Registers, ou registradores derramados, é o termo dado ao processo de colocar as variáveis menos utilizadas na Memória. O compilador tenta manter as variáveis mais usadas nos registradores e o restante é posto, ou na Memória Cache, ou na Memória RAM e, claramente para isso, são utilizadas as instruções de LW/SW.

 

Conclusão

 

Neste artigo eu falei um pouco sobre endereçamento no MIPS tomando como exemplo artigos anteriores desta série. Recomendo a leitura de todos eles antes de prosseguir, principalmente do artigo 9, sobre a instrução SLT, onde explico o cálculo do endereço de rótulos usando o registrador “Contador de Programa (PC)”. O entendimento deste conceito será importante para os artigos em que mostrarei como compilar instruções de LOOP para MIPS, e também sobre os modos de endereçamento.

Outros artigos da série

<< Operação Lógica NOT no MIPSOperandos Imediatos e Constantes no MIPS >>

NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Elaine Cecília Gatto
Bacharel em Engenharia de Computação. Mestre em Ciência da Computação. Co-fundarora e Líder das #GarotasCPBr. Pesquisadora Convidada no Grupo de Pesquisa de "Artes em Tecnologias Emergentes" do Programa de Pós Graduação em Design na UNESP Campus Bauru. Cantora, Docente no Magistério Superior, Geek, Nerd, Otaku e Gamer. Apaixonada por Michael Jackson, Macross, Séries e Filmes de Super Heróis, Cervejas e Vinhos. Mais informações sobre mim você encontra em: http://lattes.cnpq.br/8559022477811603.

Deixe um comentário

avatar
 
  Notificações  
Notificar