# Time-stamp: # Atenção para a complementação das informações presentes na observação de # número 4 em relação a versões anteriores deste arquivo 1) bal: Branch And Link. sintaxe: bal label pseudoinstrução implementada como bgezal $0, label 2) mfc1 e mfc1.s são dois nomes para a mesma instrução. Por isto têm o mesmo opcode. 3) usualmente alguns montadores admitem que um nome de instrução como ADD admita duas sintaxes possíveis. Isto inclui o montador GNU as. add reg,reg,reg add reg,reg,imm no primeiro caso a instrução seria montada com um opcode (correspondente a ADD_OP) e na segunda com outro opcode (correspondente a ADDI_OP). Num montador mais simples, estas instruções como add poderiam aceitar somente a primeira sintaxe e caso se quizesse a segunda sintaxe, deveríamos explicitamente escrever addi reg,reg,imm O mesmo problema acontece com a instrução j ( jump ) que pode admitir as sintaxes j label j REG sendo que nesta última sintaxe a mesma deve ser montada como se fosse jr REG Neste projeto, para que se possa reconhecer como sintaticamente corretos qualquer arquivo assembly gerado pelo cross-compiler estas segundas sintaxes devem ser reconhecidas como corretas. Isto pode complicar um pouco a maneira de se fazer a análise sintática de instruções dos tipos R3 e J. Explica-se o por que das linhas que se seguem ao comentário # instruções com uma segunda interpretação sintática: na parte final do arquivo Tokens-2.6. No caso específico da instrução sub, não existe uma instrução subi, sub reg,reg,reg sub reg,reg,imm e a sintaxe sub reg,reg,imm é implementada como se fosse addi reg,reg,-imm 4) As instruções do tipo I2a e FP_I2a aceitam como segundo operando um 'address' (como especificado no apêndice do livro). No arquivo Tokens, consta a sintaxe Imm(Rs). Imm corresponde a um campo de 16 bits da palavra a ser montada e Rs corresponde ao mesmo campo Rs que aparece, por exemplo nas instruções do tipo R3. O nome offset pode ser encontrado como um nome possível para o mesmo campo Imm. Sintaticamente, isto permite coisas como : INT --> Imm = INT, Rs = $0 '-' INT --> Imm = -INT, Rs = $0 '(' REG ')' --> Imm = 0, Rs = REG INT '(' REG ')' --> Imm = INT, Rs = REG '-' INT '(' REG ')' --> Imm = -INT, Rs = REG mas outros casos envolvendo identificador também devem ser considerados : (nestes casos IDENT representa o endereço associado ao identificador IDENT) IDENT --> Imm = IDENT - 0x10008000, Rs = $gp INT '+' IDENT --> Imm = IDENT + INT - 0x10008000, Rs = $gp IDENT '+' INT --> Imm = IDENT + INT - 0x10008000, Rs = $gp IDENT '-' INT --> Imm = IDENT - INT - 0x10008000, Rs = $gp ( estamos supondo que os valores acima atribuidos a Imm são valores que podem ser representados com 16bits e esta suposição pode ser livremente feita no projeto. Isto equivale a dizer que o valor de IDENT deve estar entre 0x10000000 e 0x1000FFFF para que este código seja correto ) O cross-assembler aceita sintaxes como as que se seguem, porém a geração de código de fato se dá como no caso de uma pseudo-instrução. Estas sintaxes não precisarão ter código gerado corretamente no projeto. IDENT '(' REG ')' --> Sem geração de código INT '+' IDENT '(' REG ')' --> Sem geração de código IDENT '+' INT '(' REG ')' --> Sem geração de código IDENT '-' INT '(' REG ')' --> Sem geração de código No arquivo test1.s aparece um endereço como primo-8 Isto pode ser lexicamente analisado como IDENT INT ou IDENT '-' INT conforme o item léxico INT esteja reconhecendo inteiros com sinal ou não, respectivamente. A melhor implementação do analisador léxico é a do segundo caso, para que se permitam generalizações onde possam aparecer expressões como primo+3*4-7. Para quem se enquadra no primeiro caso, uma alteração para o segundo caso pode requerer, no entanto, um certo grau de alteração na gramática. Pode-se corrigir o problema acrescentando a sintaxe IDENT INT --> Imm = IDENT + INT - 0x10008000, Rs = $gp IDENT INT '(' REG ')' --> Sem geração de código 5) li.s e li.d: Load Immediate single or double (precision float number) A sintaxe é a mesma de li. Apenas que o valor imediato (a contante numérica) não é um inteiro mas um número real. 6) O campo Shamt presente na descrição do grupo R2sh significa quantos bits o valor do registrador será deslocado para a direita ou para a esquerda. É um valor imediato, uma constante. Como as palavras têm 32bits, o valor de Shamt não excede 31. Assim, 5 bits são suficientes para armazenar este campo 'Shamt'. 7) A única instrução do tipo R2ds é a instrução jalr. Sua sintaxe é jalr REG Em sua montagem, os campos Rs e Rd devem ser usados. Rd deve valer 31 e Rs corresponde ao operando REG. Esta é a única sintaxe usada no SPIM. O montador 'GNU as' também admite a sintaxe jalr REG,REG sendo que o segundo operando REG pode especificar um outro registrador que não o 31 onde será armazenado o endereço de retorno. Esta sintaxe não precisa ser implementada no projeto do montador, mas também não é difícil de ser implementada. 8) Para usar o cross-assembler disponível de modo a obter uma listagem dos opcodes gerados de um arquivo fonte de nome, por exemplo xxx.s, usá-lo da seguinte forma: /usr/local/cross/bin/as -EB -a xxx.s O cross-compiler deve ser pêgo em 9) A documentação de neg.d, neg.s, bne, mthi, mtlo no apêndice está errada. Estas instruções usam a sintaxe do grupo a que pertencem. A instrução mflo está indevidamente escrita como mfloi no apêndice. 10) Várias instruções não estão documentadas no apêndice. grupo CP: ctc0, cfc0, ctc1, cfc1, ctc2, cfc2, ctc3, cfc3, cop0, cop1, cop2, cop3. grupo FP_CMP: uma série de instruções como c.f.d, c.f.s. grupo NOARG: tlbp, tlbr, tlbwi e tlbwr. Use a sintaxe descrita no arquivo Tokens e o opcode fornecido caso se pretenda gerar código para a instrução em questão. Existe sempre a possibilidade de usar o cross-assembler num arquivo teste para ver o que está sendo montado. 11) Várias instruções do tipo CP fazem movimentação de (from) ou para (to) um registrador de ponto flutuante. O outro registrador em questão é um registrador comum. No arquivo Tokens é informado que a sintaxe é instrucao Rt,Fd O montador 'GNU as' e o também aceitam a sintaxe exdrúxula instrucao Rt,Rd onde Rd na realidade refere-se ao registrador Fd. 12) As instruções dos grupos FP_R2ds e B0 têm o opcode errado no apêndice. Pode-se confiar nos opcodes fornecidos no arquivo Tokens. 13) A função SaveCOFF cuja especificação (protótipo) está no arquivo savecoff.h e cuja implementação encontra-se no arquivo savecoff.c cria o arquivo executável na forma exigida pelo SPIM. 14) Estará sendo fornecida uma versão MSDOS do simulador SPIM que poderá ser encontrada em 15) No apêndice do livro, os campos fd e fc estão sobrando na documentação das instruções do tipo FP_CMP. 16) A sintaxe da pseudo-instrução la é la REG ',' address onde este address é o mesmo que aparece nas instruções I2a. A montagem desta pseudo-instrução é usualmente subdividida em vários casos. Em particular, se existe uma referência a um registrador que não o $0, o cross-assembler monta como lui $at, 16bits mais significativos do valor imediato de address addiu $at,$at, 16bits menos significativos do valor imediato de address addu REG,$at, registrador envolvido no address Este caso não foi previsto na especificação do projeto e não precisa ser implementado. De outra forma, pode-se gerar código apenas para os seguintes casos: IDENT INT '+' IDENT '-' INT '+' IDENT IDENT '+' INT IDENT '-' INT 17) As instruções atrasadas (delayed instructions) são as instruções que fazem acesso à memória ou desvio. Isto inclui todas as instruções dos grupos * FP_I2a, I2a e; * B0, B1, B2, J, R2ds. O grupo de instruções R1s inclui três instruções sendo que só a instrução jr é "delayed". 18) Quando o spim avisa que ocorreu uma 'exception' numa instrução é porque esta instrução está fora da especificação do MIPS. Normalmente ele iria executar algumas partes do kernel que tratariam estas exceções. Estas partes não existem, e ele começa a reclamar da exececução de instrução inválida. Uma destas exceções é a leitura de uma variável desalinhada. Por exemplo: lw $2,maxp onde maxp é um identificador. Se o endereço associado a maxp não for múltiplo de 4, o spim reclama. Para evitar este problema, a melhor política é a implementação da diretiva .align .align INT tem o efeito de arredondar o contador de endereços do segmento corrente para o próximo múltiplo de 2 elevado a INT se o contador de endereços já não for um tal múltiplo. Se INT é 2, o contador de endereços é arredondado para o próximo múltiplo de 4 (2 ao quadrado). Se INT é três, para o próximo múltiplo de 8. Outra maneira (menos correta no sentido de que está mais longe do que de fato fazem os montadores reais) de corrigir isto é a de completar para um múltiplo de 4 as diretivas que podem originar um desalinhamento. Isto inclui as diretivas .ascii, .asciiz, etc. 19) Na implementação da pseudo li, no em que o valor imediato seja de 32 bits, é melhor que seja implementado como faz o cross assembler: li REG, valor deve ser implementado como lui REG, 16 bits + sig. de valor ori REG, REG, 16 bits - sig. de valor No enunciado do projeto constava addiu ao invés de ori, mas parece que a pseudo li $gp,0x10008000 está tendo o efeito de colocar um valor errado em $gp: 0x0fff8000 se feito como tinha sido especificado no projeto. (Nota do prf: eu pessoalmente ainda acho que addiu deveria servir.) O problema vem a ser notado se futuramente for executada alguma instrução que faça um endereçamento baseado no conteúdo de $gp. Isto pode incluir uma possível implementação de lw $2,maxp 20) ação default: qualquer regra gramatical no fonte do bison que não possui nenhuma ação associada, na verdade possui a ação default { $$=$1; } Se se quiser eliminar a ação default, deve-se explicitamente associar a ação {} à regra gramatical em questão. 21) mensagens de erro do tipo type clash ('' 'inteiro') on default action tratam de incompatibilidade de tipos entre $$ e $1 na ação default { $$=$1; } No exemplo acima, $$ não tem tipo nenhum definido ('') e $1 tem o tipo 'inteiro'. Para contornar o problema deve-se eliminar a ação default (vide observação anterior) ou, se esta for desejada, deve-se declarar o tipo do nó não-terminal associado a $$ usando o comando %type. Por exemplo através de %type nonaoterminal se nonaoterminal é o nó não terminal em questão. 22) as diretivas comm e lcomm têm a sintaxe: COMM_DIR IDENT ',' INT COMM_DIR IDENT ',' INT ',' INT equivalem a reservar declarar um endereço para IDENT numa área de dados com INT bytes. LCOMM_DIR, idem. 23) O exemplo jumps.s faz referência à diretiva .word com um argumento IDENT: .word $LC0 O endereco deste label, $LC0, é que é armazenado nesta palavra. O argumento aceito pela diretiva .word, deve ser uma seqüência não vazia de inteiros e/ou endereços, separada por vírgulas. 24) Na especificação do Projeto da segunda fase, são mencionadas as diretivas .bss e .sbss. No arquivo Tokens-2.6, estas diretivas nem são declaradas. Não ocorrem nos exemplos também. Não é necessário implementar .bss ou .sbss. Pode-se implementar como sinônimos de .data, caso se queira. 25) A mensagem de erro `flex scanner jammed' ocorre quando o flex identica que as regras a ele fornecidas não dizem o que fazer com algumas entradas possíveis: Exemplo: se vem um '+' ou um `\n' no arquivo fornecido como entrada para o analisador lexico e não há nenhuma regra que diga como analisar lexicamente estes caracteres. 26) Na hora de implementar as instruções atrasadas (``delayed instruction'') podemos simplesmente gerar uma pseudointrução NOP após o opcode da instrução em questão. 27) Para poder montar o arquivo test3.s é necessário implementar as pseudoinstruções 'l.d' e 's.d'. Outros programas que envolvam números reais de precisão dupla podem requerer também a implemetação da pseudoinstrução `li.d'. É facultativa esta implementação. # Local Variables: # mode: outline # outline-regexp: "^[0-9]+).*" # End: