Marta Santos Posted April 14, 2021 Posted April 14, 2021 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; } } }
codando Posted April 14, 2021 Posted April 14, 2021 Você está utilizando a memória de dados e de programa como sendo a mesma? poderia enviar seu array Mem?
Felipe.Silva Posted April 14, 2021 Posted April 14, 2021 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 load, store 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á. ?
Marta Santos Posted April 14, 2021 Author Posted April 14, 2021 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; }
Felipe.Silva Posted April 14, 2021 Posted April 14, 2021 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.
Marta Santos Posted April 14, 2021 Author Posted April 14, 2021 Eu sei a lógica da operação, mas não entendo como faço para pegar o bit mais significativo
Marta Santos Posted April 14, 2021 Author Posted April 14, 2021 Porque não posso fazer um casting como o felipe mostrou...
Felipe.Silva Posted April 14, 2021 Posted April 14, 2021 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.
Recommended Posts
Archived
This topic is now archived and is closed to further replies.