ASM - Mapa de memória

A forma na qual a maioria das CPUs acessam periféricos (teclado/ mouse/ USB/ tela/ ...) é a do periférico mapeado em memória. Essa técnica utiliza da capacidade do computador de escrever e ler da memória RAM, fazendo com que regiões de endereços da memória não sejam uma 'memória' física, mas sim um periférico do computador.

Vamos trabalhar com o exemplo do nosso Z01, a memória é composta de:

  • RAM
  • LCD
  • Chaves
  • LEDs

Nesse nosso hardware a memória que é visível pela CPU é organizada da seguinte maneira:

Endereço Periférico Leitura (r) / Escrita (w)
0 - 16383 RAM r/w
16384 - 21183 LCD w
21184 LED w
21185 SW r

RAM

Endereço Periférico Leitura (r) / Escrita (w)
0 - 16383 RAM r/w

A memória RAM é um componente do computador que permite guardar dados voláteis (que vão se perder após o reset do computador). É nela que guardamos as variáveis do programa.

Note

Nossa memória RAM possui 16 bits de largura.

A princípio podemos utilizar qualquer endereço da memória RAM para armazenar dados temporários, isso não será verdade mais para frente do curso, onde iremos organizar nossa memória RAM em secções.

Tip

Iremos dar alguns nomes para os endereços específicos da memória RAM:

endereço label / nome
0 SP
1 LCL
2 ARG
3 THIS
4 THAT

Example

Vamos fazer um exemplo que lê um dado na RAM[3] o incrementa e salva novamente no mesmo endereço de memória:

leaw $3, %A    ; faz %A = 3 (%A aponta para RAM[3])
movw (%A), %D  ; move o valor de RAM[%A] para %D
incw %D        ; incrementa o valor de D (D = D + 1, D = RAM[3] + 1)
movw %D, (%A)  ; move o valor incrementado de volta para a RAM[3]
  • Podemos também usar o label ARG para referencia o endereço 3 da memória RAM:
leaw $ARG, %A  ; faz %A = 3 (%A aponta para RAM[ARG])

Tip

Execute você esse código no simulador! E analise o resultado.

Warning

É necessário notar que a memória RAM não é um registrador e possui uma grande limitação, não podemos realizar uma ação de ESCRITA E LEITURA no mesmo ciclo! O que impossibilita de fazermos o seguinte:

leaw $3, %A  
incw (%A)              ; Não funciona no nosso hardware!!
addw (%A), %D, (%A)    ; Nao funciona no nosso hardware!!
  • O assembly permite que vocês escrevam essas operações, porém quando forem executar no hardware o resultado não vai ser o esperado.

LEDs

Endereço Periférico Leitura (r) / Escrita (w)
21184 LED w

Os LEDs da FPGA são mapeados no endereço de memória 21184 onde cada bit (9..0) representa um LED, se o bit específico estiver valor 1o LED está aceso e 0 apagado.

Example

Como isso é traduzido para código? Imagine que desejamos acender um LED que nosso computador controla, para isso devemos fazer com que o registrador %A aponte para o endereço de memória na qual o LED está associado e então escreva nele:

leaw $21184, %A   ; endereço do LED
movw $1, (%A)     ; move valor 1 para ele

Tip

Execute você esse código no simulador!

Tip

Note que usamos movw $1, (%A). Isso é possível porque nossa ULA é capaz de gerar os valores 1, -1 e 0, mas outros valores não!

SW

Endereço Periférico Leitura (r) / Escrita (w)
21185 SW r

Os chaves (SW) da FPGA são mapeados no endereço de memória 21185 onde cada bit (9..0) representa uma chave, se o bit específico estiver valor 1 indica que a chave está ligada (on) e 0 desligada.

Example

O exemplo a seguir copia o valor das chaves para os LEDs:

leaw $21185, %A   ; endereço da chave
movw (%A), %D     ; copia valor das chaves para %D
leaw $21184, %A   ; endereço do LED
movw %D, (%A)     ; move valor das chaves para %D

Tip

Execute você esse código no simulador!

LCD

Endereço Periférico Leitura (r) / Escrita (w)
16384 - 21183 LCD w

O nosso LCD é um dispositivo de 320x240 pixels. Cada linha do endereço de memória do LCD representa 16 pixels do dispositivo, conforme figura anterior. Para acender um pixel, basta colocar 1 ou 0 para apagar.-

endereços do LCD

Como nosso LCD possui 320px na horizontal, e como cada endereço de memória acessa 16px por vez, uma linha é acessível por: 320/16 = 20 endereços. Ou seja, para acessar os primeiros px de cada linha devemos escrever endereço de memória:

  • Primeira linha: 16384 + 0 vezes 20: 16384
  • Segunda linha: 16384 + 1 vezes 20: 16404
  • Terceira linha: 16384 + 2 vezes 20: 16424
  • ...
  • Última linha: 16384 + 239 vezes 20: 21164

LCD

Para desenhar um pixel no meio do LCD é necessário carregar o valor 0x0001 no endereço 18242

leaw $18242, %A
movw $1, (%A)

Tip

Execute você esse código no simulador!