// Execute one instruction cycle // void one_instruction_cycle(int reg[], int nreg, int mem[], int memlen) { // If the CPU isn't running, say so and return. // If the pc is out of range, complain and stop running the CPU. // if (!running){ printf("Error: CPU not running.\n"); return; } // Get instruction and increment pc // int instr_loc = pc; // Instruction's location (pc before increment) ir = mem[pc++]; // Decode instruction into opcode, reg_R, addr_MM, and instruction sign // int opcode = abs(mem[instr_loc] / 1000); int reg_R = abs((mem[instr_loc] / 100) % 10); int addr_MM = abs(mem[instr_loc] % 100); int instr_sign = 0; // double check we're not trying to divide by 0 if (mem[instr_loc] != 0) { instr_sign = mem[instr_loc] / abs(mem[instr_loc]); } // Echo instruction // printf("At %02d instr %d %d %02d: ", instr_loc, opcode, reg_R, addr_MM); // basic bounds checks. bail if we're out of range if (reg_R < -1 || nreg < reg_R || addr_MM < -1 || 100 < addr_MM) { printf("Error: bad instruction. reg_R or addr_MM is out of bounds.\n"); return; } switch (opcode) { case 0: exec_HLT(reg_R, addr_MM, reg, nreg, mem, memlen); break; case 1: exec_LD(reg_R, addr_MM, reg, nreg, mem, memlen); break; case 2: exec_ST(reg_R, addr_MM, reg, nreg, mem, memlen); break; case 3: exec_ADD(reg_R, addr_MM, reg, nreg, mem, memlen); break; case 4: exec_NEG(reg_R, reg, nreg); break; case 5: exec_LDM(reg_R, addr_MM, instr_sign, reg, nreg, mem, memlen); break; case 6: exec_ADDM(reg_R, addr_MM, instr_sign, reg, nreg, mem, memlen); break; case 7: exec_BR(addr_MM, mem, memlen); break; case 8: exec_BRC(reg_R, addr_MM, instr_sign, reg, nreg, mem, memlen); break; case 9: switch (reg_R) { case 0: exec_GETC(reg, nreg); break; case 1: exec_OUT(reg, nreg); break; case 2: exec_PUTS(addr_MM, mem, memlen); break; case 3: exec_DMP(addr_MM, reg, nreg, mem, memlen); break; case 4: exec_MEM(addr_MM, reg, nreg, mem, memlen); break; case 5: case 6: case 7: case 8: case 9: printf("Unknown I/O; skipped\n"); break; } break; default: printf("Bad opcode!? %d\n", opcode); } }
void one_instruction_cycle(int reg[], int nreg, int mem[], int memlen) { int reg_R, addr_MM, instr_sign, opcode; /* Check if CPU is running */ if (running == 0) { printf("The CPU is not running"); return; } /* Make sure that we didn't hit any boundaries */ if (pc >= memlen) { printf("Program counter out of range"); exec_HLT(); } /* Get instruction and increment PC */ int instr_loc = pc; ir = mem[pc++]; /* Check instruction sign */ if (ir < 0) { instr_sign = -1; ir *= -1; } else if (ir > 0) { instr_sign = 1; } /* Decode instruction into opcode, register, and memory address */ opcode = ir / 1000; reg_R = (ir % 1000) / 100; addr_MM = ir % 100; printf("At %02d instr %d %d %02d: ", instr_loc, opcode, reg_R, addr_MM); switch (opcode) { /* HALT */ case 0: exec_HLT(); break; /* LOAD */ case 1: { reg[reg_R] = mem[addr_MM]; } break; /* STORE */ case 2: { mem[addr_MM] = reg[reg_R]; } break; /* ADD-IM-MM */ case 3: { reg[reg_R] += mem[addr_MM]; } break; /* NOT */ case 4: { reg[reg_R] = (-reg[reg_R]); } break; /* LOAD IMMEDIATE */ case 5: { reg[reg_R] = addr_MM * instr_sign; } break; /* ADD IMMEDIATE */ case 6: { reg[reg_R] += addr_MM * instr_sign; } break; /* JUMP */ case 7: { pc = addr_MM; } break; /* BRANCH CONDITIONAL */ case 8: { if (reg[reg_R] > 0 && instr_sign > 0) { pc = addr_MM; } else if (reg[reg_R] < 0 && instr_sign < 0) pc = addr_MM; } break; /* I/O Subroutines */ case 9: { switch (reg_R) { /* GETCHAR */ case 0: { printf("enter a character>> "); int k = getchar(); reg[0] = k; } break; /* PRINTCHAR */ case 1: { printf("%c\n", reg[0]); } break; /* PRINT-STRING */ case 2: { while (mem[addr_MM] != 0) { printf("%c \n", mem[addr_MM++]); } printf("\n"); } break; /* DUMP CU */ case 3: { dump_control_unit(pc, ir, running, reg, nreg); } break; /* DUMP MEM */ case 4: { dump_memory(mem, memlen); } break; default: return; break; } } break; default: printf("Bad opcode!? %d\n", opcode); } }