Jump to content

Ajuda - Simulador CPU em C


Marta Santos

Recommended Posts

Posted

Boa tarde, estou a fazer um exercício de C. Consiste em programar o ciclo de fetch, decode e execute para simular a execução das instruções na memória. A main já foi fornecida, apenas tenho que fazer as instruções pedidas. O meu programa está com Time Limit Exceeded e não tenho bem a certeza se todas as instruções estão corretas. Alguém me pode ajudar???

16 bits words
12 bits addresses (max memory 2^12 words but less may be installed)
1 register (AC)

Code      Assembly    Desciption
0x0XXX    HALT        halts CPU
0x1EEE    LOAD EEE    AC <- Mem[EEE]
0x2EEE    STORE EEE   Mem[EEE] <- AC
0x3EEE    ADD EEE     AC <- AC + Mem[EEE]
0x4EEE    SUB EEE     AC <- AC - Mem[EEE]
0x5EEE    JUMP EEE    PC <- EEE
0x6EEE    JZ EEE      if AC == 0  PC <- EEE
0x7EEE    JA EEE      if AC > 0  PC <- EEE
0x8EEE    JB EEE      if AC < 0  PC <- EEE
0x9XXX    CLEAR       AC <- 0
*/


extern unsigned short int Mem[];

void dorun(){

    unsigned short int pc;  // program counter
    unsigned short int ir;  // instruction register
    unsigned short int ac;  // accumulator
    unsigned short int opcode;
    unsigned short int address;

    pc = 0;
    int continuar = 1;
    while(continuar) {

       ir = Mem[pc];
       opcode = (ir & 0xf000)>>12;
       address = ir & 0x0fff;

       switch(opcode) {
             case 0x00: /* HALT */
               continuar = 0;
               break;
             case 0x01: /* LOAD */
               ac = Mem[address];
               pc = pc + 1;
               break;
             case 0x02: /* STORE */
               Mem[address] = ac;
               pc = pc + 1;
               break;
             case 0x03: /* ADD */
               ac = ac + Mem[address];

               break;
             case 0x04: /*  SUB */
               ac = ac - Mem[address];

               break;
             case 0x05: /* JUMP */
               pc = address;
               break;
             case 0x06: /* JZ */
               if(ac == 0) pc = address;
               break;
             case 0x07: /* JA */
               if(ac > 0) pc = address;
               break;
             case 0x08: /* JB */
               if(ac < 0) pc = address;
               break;
             case 0x09: /* CLEAR */
               ac = 0;
               break;
       }
    }

}

 

Posted

Você não está atualizando o registrador "pc" corretamente. Remova as linhas "pc = pc + 1;" e, ao invés disso, atualize o pc imediatamente após carregar a instrução da memória. Tu pode fazer assim:
 

ir = Mem[pc++];

O pc precisa ser atualizado sempre que uma instrução for executada. Como você só estava atualizando em algumas instruções, o loop ficava rodando indefinidamente porque pc estava sempre apontando para a mesma instrução.

Sobre saber se as instruções fazem o que era esperado... Para isso eu sugiro que você compile o código no seu PC, execute e veja se o resultado foi o esperado.
Eu testei aqui as instruções loadstore e add e funcionaram conforme o esperado... Esse foi o código que usei para testar:
 

#include <stdio.h>

unsigned short int Mem[] = {
    0x1004,
    0x3005,
    0x2004,
    0x0000,

    // Data
    0x0005,
    0x0002,
};

void dorun()
{
  // etc...
}

int main(void)
{
  dorun();

  for (int i = 0; i < sizeof Mem / sizeof *Mem; i++)
  {
    printf("%04x, ", Mem[i]);
  }

  putchar('\n');
  return 0;
}

 

Não testei as outras instruções, mas com base nisso daí tu pode testar elas... Ou meter o louco e já submeter após corrigir a atualização do pc e ver no que dá. ? 

Posted

Eu corrigi algumas coisas e ficou quase tudo bem. Apenas me falta as instruções de jump (JZ, JA, JB), porque tenho que verificar se o que está em ac é um numero positivo ou negativo, mas em complemento para 2.

switch(opcode) {
             case 0x00: /* HALT */
               continuar = 0;
               break;
             case 0x01: /* LOAD */
               ac = Mem[address];
               pc++;
               break;
             case 0x02: /* STORE */
               Mem[address] = ac;
               pc++;
               break;
             case 0x03: /* ADD */
               ac += Mem[address];
               pc++;
               break;
             case 0x04: /*  SUB */
               ac -= Mem[address];
               pc++;
               break;
             case 0x05: /* JUMP */
               pc = address;
               break;
             case 0x06: /* JZ */
               if(ac == 0) pc = address;
               else pc++;
               break;
             case 0x07: /* JA */
               if(ac > 0) pc = address;
               else pc++;
               break;
             case 0x08: /* JB */
               if(ac < 0) pc = address;
               else pc++;
               break;
             case 0x09: /* CLEAR */
               ac = 0;
               pc++;
               break;
       }

 

Posted

Acontece que ac é unsigned short int, por isso a comparação do if do C não interpreta como um número sinalizado. Mas aí é só você fazer um casting para um número sinalizado que o código já vai estar correto. Exemplo:
 

if((short int)ac < 0) pc = address;

Mas se por algum motivo você quiser fazer a verificação manualmente, bastaria você pegar o bit mais significativo (MSB) do número e ver se ele está ligado ou não. Se estiver, significa que o número é negativo... Mas como eu disse, isso não é necessário.

Posted
opcode = (ir & 0xf000)>>12;

Quando você fez isso daqui, você pegou os 4 bits mais significativos de ir. Para pegar só 1 é a mesma coisa, só vai mudar o número de bits setados no valor com que está sendo feito o AND.

if ( ac & (1 << 15) ) pc = address; // Negativo! ac é menor que zero

if ( ac && !(ac & (1 << 15)) ) pc = address; // ac é diferente de zero e positivo.

 

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...