Você está na página 1de 6

Macros(2)

João Paulo
Luan Mark

Montador(3)
Joao Antonio
Raíssa
Vítor

Carregador(1)
William

Máquina(1)
Bianca

Interface(1)
Matheus

Processador De Macros
Implementação em 1 passo
O que fizemos ?

Bem os macros são subrotinas abertas e o processador de macros é basicamente


responsável por traduzir essas subrotinas, o processador de macro deve realizar
basicamente quatro tarefas, reconhecer as definições de macros, salvar as definições de
macros para que seja possível realizar a expansão, reconhecer as invocações das macros,
expandir as invocações, com a possibilidade de substituir argumentos e verificar condições.
Então quando um macro aparece o processador traduz esse macro pegando toda
linha e a copiando para o código principal, ele pode ser implementado em 1 ou dois passos.
Uma das diferenças entre o processador de macros de 2 passos para o de 1 é que o
processador de 1 passo não permite chamadas futuras, toda macro chamada deve ter sido
previamente definida. Outra diferença importante é que o processador de 1 passo permite
chamadas e definições de macros aninhadas.
Nosso processador de macros simplesmente percorre o arquivo passado e quando
encontra uma definição de macro ele entra em modo definição e salva nas arrayLists
adequadas, quando ele encontrar uma chamada ele entra em modo de expansão,
carregando os valores passados na chamada e os substituindo no corpo da macro definida
O processador de macros não vê instruções nem parâmetros de instruções, ele só vê
macros e os parâmetros de macros, qualquer outra coisa o processador só copia e segue
em frente.

ArrayList defTab: para salvar as definições de macros, esta arrayList salva o nome
da macro e seus parâmetros, as macros são salvas em ordem de hierarquia, depois são
desempilhadas assim que a definição da Macro acaba. Se a defTab estiver vazia então não
está no modo definição.

ArrayList MacroParams: Salva as definições das macros assim como a defTab,


mas esta não tem nível hierárquico e as definições nunca são removidas, esta arraylist vai
ser usada no momento de fazer a expansão.

ArrayList macroHierarchy: Salva o id das definições das macros e o id dos níveis


superiores de hierarquia da macro em questão, desta forma é possível acessar os
parâmetros das hierarquias superiores caso necessário;

ArrayList macroScopo: Salva tudo que tem dentro da macro, sem alterar nada

ArrayList actualParam: Salva os parâmetros que foram passados para a macro em


uma chamada de macro

ArrayList linhasMacroExpandida: Salva as linhas expandidas das Macros


Como fizemos ?
- Detalhes código

Montador:
Funções Básicas do montador

1. Converter operações Mnemônicas para a representação em código de máquina Por


exemplo: CLEAR A,B => 0xB403
2. Converter operandos simbólicos para os endereços
3. Montar o código de máquina de acordo com o formato de endereçamento.
4. Converter dados constantes rotulados para valores absolutos.
5. Criar o arquivo Listing contendo as informações de montagem como endereço
inicial,endereço final, e o conjunto de Strings representando o código das instruções.
Diretivas de Montagem

Principais Estruturas de dados utilizadas na montagem

SYMTAB (tabela de símbolos referentes aos rótulos)

OPTAB (tabela de referência para montar instruções)

PARSERLINE ( contém attr: “rótulo” “opcode” “prefixo” “operando” ao


fazer um parsing na linha)

LOCCTR: Usado para indexar as posições de memória que as


instruções irão ocupar na memória após a montagem.

LISTING_PROGRAM: Objeto contendo header com as referências ao


endereço inicial do programa, endereço da primeira instrução executável
e o endereço final. E uma Stream de Strings de caracteres em Hex. É a
saída do montador e a entrada do Carregador.

Implementação em 2 passos do montador para máquina SIC.XE

1º Passo:

- Define o endereço inicial onde o programa será carregado para memória baseado do
valor do operando da diretiva START
EXEMPLO:
Indica para o carregador que o programa começará no endereço de memória 100
A diretiva é opcional, caso não encontrada no arquivo de montagem a posição de
começo será por default 0 (zero)
- Se existir um rótulo no campo de RÓTULO de uma operação mnemônica, então é
criada uma entrada na tabela de símbolos com o nome da chave referente ao rótulo
e conteúdo referente ao endereço da linha que foi encontrada o rótulo.
- Se um rótulo para ser definido já estiver na Tabela de símbolo, o montador irá
retornar um erro de múltipla definição de símbolos.
- O montador irá atualizar o LOCCTR (location counter) de acordo com o tamanho de
memória necessário para armazenar a instrução ou diretiva de memória.
- O tamanho que a instrução irá ocupar dependerá do seu formato, F2,F3,F4 e
também do espaço de memória que uma diretiva de dados necessitará.
- Por conta disso o montador possui uma estrutura auxiliar chamada de OPTAB
contendo todas as instruções disponíveis ao programador e seu tamanho esperado.
- Caso a instrução for formato estendido ela conterá um prefixo (“+”) que avisará ao
montador para atualizar o LOCCTR em 4 posições.
- Ao final do passo 1 teremos um arquivo intermediário (contendo os objetos
referentes as linhas de instruções) contendo as instruções e seus tamanhos para
utilizar no passo 2.

2º Passo:
- Resetar o LOCCTR para posição inicial novamente e começar a ler as linhas
contidas no arquivo intermediário.
- Se a linha contiver um OPCODE(instrução) (comparar com a tabela OPTAB) montar
o código objeto de acordo com o formato da instrução (F2,F3/4)
- Converter rótulos no campo operando para o endereço relativo ao rótulo.
- Fazer os cálculos necessários para encontrar o Target Address de acordo com os
prefixos utilizados nas instruções
- Retornar o código objeto em formato HexString para o arquivo listing(texto)
- Processar diretivas de dados como RESW, RESB, WORD e adicioná-las ao arquivo
listing(texto).
- (OPCIONAL) Setar o endereço da primeira instrução para ser executada pela
máquina de acordo com o rótulo gravado no operando de END

SINTAXE DAS INSTRUÇÕES QUE O MONTADOR ACEITA

Sintaxe instruções formato 2:


[RÓTULO] [OPCODE] [PREFIXO][OPERANDO 1] [OPERANDO]
[RÓTULO] - Opcional indica o endereço da instrução
[OPCODE] - Obrigatório de acordo com as instruções pré definidas
[PREFIXO] - Opcional indica se quer utilizar letras ou números para representar
registradores.
[OPERANDO 1] - obrigatório - registrador utilizado na instrução
[OPERANDO 2] - facultativo para certas instruções e o obrigatórias para outras
Exemplo de sintaxe de operações F2:
- ROTULO1 COMPR A,B
- COMPR A,B
- COMPR #0,3
- CLEAR A

Sintaxe Instruções F3 - F4

[RÓTULO] [Estendido Prefix][OPCODE] [PREFIXO][OPERANDO]

[Estendido Prefix] - Opcional: indica que a instrução usará endereçamento estendido de 20


bits para representar Target Address

[PREFIXO] - Opcional: [“#"] Indica se o operando será imediato (sem acesso a memória)
[“@”] indireto (acesso a memória) ou simples: [vazio] O operando será um endereço de
memória.

Exemplo de sintaxe de operações F2:

- FIRST LDA VALOR1 (instr com rótulo e endereçamento simples)


- LDB #5 (instr sem rótulo e endereçamento imediato)
- LOOP +JEQ TAMANHO (instr c/ rótulo e endereçamento formato estendido)
- STA @INICIOBUFFER (instr c/rótulo e endereçamento indireto)

Carregador:
É o programa da máquina virtual responsável por converter as strings em formato
hexadecimal para valores em byte e armazenar na memória da máquina.
É responsável também por passar o endereço da primeira instrução executável para
o PC(Program Counter) da máquina.

Implementação:
A implementação do carregador utilizado no trabalho é chamado de carregador Absoluto,
pois carrega na memória dados e instruções de forma contígua.
Essa é a forma mais básica de carregar um programa na memória da máquina. Pois não
envolve relocação de dados e instruções, e nem linkagem.
Um detalhe importante de se notar é que pelo motivo das instruções poderem estar junto
das instruções temos que evitar a máquina de tentar executar área reservada para dados.
Para contornar esse problema recomendamos ao programador declarar as posições de
memória que será utilizada no programa antes ou depois das instruções. Caso o
programador escolha reservar posições de memória entre instruções, deve-se utilizar um
JUMP para pular essas regiões.
(passar para Bianca)

Máquina:
A Máquina Virtual foi implementada baseada no livro do Leland, Systems Software:
An Introduction to System Programming, consistindo na implementação de um simulador
SIC/XE.
Opcode e Modos de endereçamento:
Opcodes estão em hexadecimal. 3 formas de endereçamento são utilizadas:
formatos 2, 3 e 4. Instruções de formato 1 não são utilizadas no projeto.
Alguns Métodos, os mais importantes:
loadF2:
Para instruções do formato 2, como, por exemplo, ADDR, CLEAR.

loadF3F4:
Para instruções do formato 3 e 4, como, por exemplo, LDA, STR, J.

loadByte:
Pega um byte da memória. O PC(program counter) é incrementado toda vez que é
pego um byte da memória.

exec:
Execução da Máquina Virtual. Para saber o formato da instrução é executada no
formato 2 primeiro. Se não for no formato 2, executa o formato 3 ou 4.
O Target Access é determinado pelas flags nixbpe, que são por sua vez
determinadas pelo modo de endereçamento.

Sobre os registradores e memória:


– REGISTRADORES
Registradores foi implementado como uma ArrayList de registradores. Os
registradores são inicializados e preenchidos com 0. Também são definidos com tamanho de
24 bits. Foi apenas feito 8 registradores, pois o registrador F, utilizado para números do tipo
float, não é utilizado no projeto. Os registradores estão em ordem de número de
identificação.
– MEMÓRIA
Memória foi feita com palavras de 3 bytes e endereçamento à palavra, contendo
funções get e set de Byte e Palavra (Word). Tem capacidade de 1MB.

Interface:
Matheus

Você também pode gostar