void cpu_execute(struct cpu* cpu) { cpu->pc += 2; uint8_t vx = cpu->v[cpu->opcode.x]; uint8_t vy = cpu->v[cpu->opcode.y]; switch (cpu->opcode.op) { case 0x0: switch (cpu->opcode.n) { case 0x0: return cpu_clear(cpu); case 0xE: return cpu_jump(cpu, cpu->stack[--cpu->sp]); default: return cpu_error(cpu); } case 0x1: return cpu_jump(cpu, cpu->opcode.addr); case 0x2: return cpu_call(cpu, cpu->opcode.addr); case 0x3: return cpu_skip(cpu, vx == cpu->opcode.kk); case 0x4: return cpu_skip(cpu, vx != cpu->opcode.kk); case 0x5: return cpu_skip(cpu, vx == vy); case 0x6: return cpu_assign_register(cpu, cpu->opcode.x, cpu->opcode.kk); case 0x7: return cpu_assign_register(cpu, cpu->opcode.x, vx + cpu->opcode.kk); case 0x8: switch (cpu->opcode.n) { case 0x0: return cpu_assign_register(cpu, cpu->opcode.x, vy); case 0x1: return cpu_assign_register(cpu, cpu->opcode.x, vx | vy); case 0x2: return cpu_assign_register(cpu, cpu->opcode.x, vx & vy); case 0x3: return cpu_assign_register(cpu, cpu->opcode.x, vx ^ vy); case 0x4: return cpu_add_carry(cpu, vx, vy); case 0x5: return cpu_subtract_borrow(cpu, vx, vy); case 0x6: return cpu_shift_right(cpu); case 0x7: return cpu_subtract_borrow(cpu, vy, vx); case 0xE: return cpu_shift_left(cpu); default: return cpu_error(cpu); } case 0x9: return cpu_skip(cpu, vx != vy); case 0xA: return cpu_assign_i(cpu, cpu->opcode.addr); case 0xB: return cpu_jump(cpu, cpu->opcode.addr + cpu->v[0]); case 0xC: return cpu_random(cpu); case 0xD: return cpu_draw(cpu); case 0xE: switch (cpu->opcode.kk) { case 0x9E: return cpu_skip(cpu, SDL_GetKeyboardState(NULL)[key_map[vx]]); case 0xA1: return cpu_skip(cpu, !SDL_GetKeyboardState(NULL)[key_map[vx]]); default: return cpu_error(cpu); } case 0xF: switch (cpu->opcode.kk) { case 0x07: return cpu_assign_register(cpu, cpu->opcode.x, cpu->delay_timer); case 0x0A: return cpu_wait_key_press(cpu); case 0x15: return cpu_assign_delay_timer(cpu, vx); case 0x18: return cpu_assign_sound_timer(cpu, vx); case 0x1E: return cpu_assign_i(cpu, cpu->i + vx); case 0x29: return cpu_assign_i(cpu, vx * 5); case 0x33: return cpu_store_bcd(cpu); case 0x55: return cpu_copy_to_memory(cpu); case 0x65: return cpu_copy_from_memory(cpu); default: return cpu_error(cpu); } } return cpu_error(cpu); }
void CALL(cpu_state_t *state, const enum ARG_TYPE arg0, const union REG_INPUT i0, const enum ARG_TYPE arg1, const union REG_INPUT i1) { if(arg0 == ARG_TYPE_DATA16_UNSIGNED || (arg0 == ARG_TYPE_NC && !cpu_carry(state)) || (arg0 == ARG_TYPE_NZ && !cpu_zero(state)) || (arg0 == ARG_TYPE_REG8 && cpu_carry(state)) //Actually the carry flag. || (arg0 == ARG_TYPE_Z && cpu_zero(state))) { cpu_call(state, state->arg); } else { state->success = 0; } }
/* Process the current interrupt if there is one. This operation must be called after each instruction to handle the interrupts. If interrupts are masked, it does nothing. */ int interrupts_process (struct interrupts *interrupts) { int id; uint8 ccr; /* See if interrupts are enabled/disabled and keep track of the number of cycles the interrupts are masked. Such information is then reported by the info command. */ ccr = cpu_get_ccr (interrupts->cpu); if (ccr & M6811_I_BIT) { if (interrupts->start_mask_cycle < 0) interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->start_mask_cycle >= 0 && (ccr & M6811_I_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->start_mask_cycle; if (t < interrupts->min_mask_cycles) interrupts->min_mask_cycles = t; if (t > interrupts->max_mask_cycles) interrupts->max_mask_cycles = t; interrupts->start_mask_cycle = -1; interrupts->last_mask_cycles = t; } if (ccr & M6811_X_BIT) { if (interrupts->xirq_start_mask_cycle < 0) interrupts->xirq_start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->xirq_start_mask_cycle >= 0 && (ccr & M6811_X_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->xirq_start_mask_cycle; if (t < interrupts->xirq_min_mask_cycles) interrupts->xirq_min_mask_cycles = t; if (t > interrupts->xirq_max_mask_cycles) interrupts->xirq_max_mask_cycles = t; interrupts->xirq_start_mask_cycle = -1; interrupts->xirq_last_mask_cycles = t; } id = interrupts_get_current (interrupts); if (id >= 0) { uint16 addr; struct interrupt_history *h; /* Implement the breakpoint-on-interrupt. */ if (interrupts->interrupts[id].stop_mode & SIM_STOP_WHEN_TAKEN) { sim_io_printf (CPU_STATE (interrupts->cpu), "Interrupt %s will be handled\n", interrupt_names[id]); sim_engine_halt (CPU_STATE (interrupts->cpu), interrupts->cpu, 0, cpu_get_pc (interrupts->cpu), sim_stopped, SIM_SIGTRAP); } cpu_push_all (interrupts->cpu); addr = memory_read16 (interrupts->cpu, interrupts->vectors_addr + id * 2); cpu_call (interrupts->cpu, addr); /* Now, protect from nested interrupts. */ if (id == M6811_INT_XIRQ) { cpu_set_ccr_X (interrupts->cpu, 1); } else { cpu_set_ccr_I (interrupts->cpu, 1); } /* Update the interrupt history table. */ h = &interrupts->interrupts_history[interrupts->history_index]; h->type = id; h->taken_cycle = cpu_current_cycle (interrupts->cpu); h->raised_cycle = interrupts->interrupts[id].cpu_cycle; if (interrupts->history_index >= MAX_INT_HISTORY-1) interrupts->history_index = 0; else interrupts->history_index++; interrupts->nb_interrupts_raised++; cpu_add_cycles (interrupts->cpu, 14); return 1; } return 0; }
/** This function exec byte code of instructions @param code array of byte code @return number of error(0 if no error) */ int cpu_run(char* addr_code) { assert(addr_code); cpu_t* cpu = NULL; cpu_ctor(&cpu, CPU_STACK_MAX, addr_code); char* current_byte = addr_code; start_logging("logs.txt"); while(FOREVER) { int cmd = *current_byte; current_byte++; //printf("%d \n",cmd); switch(cmd) { case PUSH: if(cpu_push(cpu, ¤t_byte)) printf("CPU CRASHED! PUSH HAVEN'T FULFILLED"); break; case POP: if(cpu_pop(cpu, ¤t_byte)) printf("CPU CRASHED! POP HAVEN'T FULFILLED"); break; case OK: if(cpu_ok(cpu)) printf("CPU CRASHED! CPU ISN'T OK"); break; case DUMP: if(cpu_dump(cpu)) printf("CPU CRASHED! DUMP HAVEN'T FULFILLED"); break; case ADD: if(cpu_add(cpu)) printf("CPU CRASHED! ADD HAVEN'T FULFILLED"); break; case SUB: if(cpu_sub(cpu)) printf("CPU CRASHED! SUB HAVEN'T FULFILLED"); break; case MUL: if(cpu_mul(cpu)) printf("CPU CRASHED! MUL HAVEN'T FULFILLED"); break; case DIR: if(cpu_dir(cpu)) printf("CPU CRASHED! DIR HAVEN'T FULFILLED"); break; case SIN: if(cpu_sin(cpu)) printf("CPU CRASHED! SIN HAVEN'T FULFILLED"); break; case COS: if(cpu_cos(cpu)) printf("CPU CRASHED! COS HAVEN'T FULFILLED"); break; case SQRT: if(cpu_sqrt(cpu)) printf("CPU CRASHED! SQRT HAVEN'T FULFILLED"); break; case JA: if(cpu_ja(cpu, ¤t_byte)) printf("CPU CRASHED! JA HAVEN'T FULFILLED"); break; case JAE: if(cpu_jae(cpu, ¤t_byte)) printf("CPU CRASHED! JAE HAVEN'T FULFILLED"); break; case JB: if(cpu_jb(cpu, ¤t_byte)) printf("CPU CRASHED! JB HAVEN'T FULFILLED"); break; case JBE: if(cpu_jbe(cpu, ¤t_byte)) printf("CPU CRASHED! JBE HAVEN'T FULFILLED"); break; case JE: if(cpu_je(cpu, ¤t_byte)) printf("CPU CRASHED! JE HAVEN'T FULFILLED"); break; case JNE: if(cpu_jne(cpu, ¤t_byte)) printf("CPU CRASHED! JNE HAVEN'T FULFILLED"); break; case JMP: if(cpu_jmp(cpu, ¤t_byte)) printf("CPU CRASHED! JMP HAVEN'T FULFILLED"); break; case OUT: if(cpu_out(cpu)) printf("CPU CRASHED! OUT HAVEN'T FULFILLED"); break; case MOV: if(cpu_mov(cpu, ¤t_byte)) printf("CPU CRASHED! MOV HAVEN'T FULFILLED"); break; case INC: if(cpu_inc(cpu, ¤t_byte)) printf("CPU CRASHED! INC HAVEN'T FULFILLED"); break; case DEC: if(cpu_dec(cpu, ¤t_byte)) printf("CPU CRASHED! DEC HAVEN'T FULFILLED"); break; case CALL: if(cpu_call(cpu, ¤t_byte)) printf("CPU CRASHED! CALL HAVEN'T FULFILLED"); break; case RET: if(cpu_ret(cpu, ¤t_byte)) printf("CPU CRASHED! RET HAVEN'T FULFILLED"); break; case END: return 0; break; default: { fprintf(stderr, "ERROR! Unknown command at address %o. \n", (int)current_byte); return 1; } } } return 0; }
/* Process the current interrupt if there is one. This operation must be called after each instruction to handle the interrupts. If interrupts are masked, it does nothing. */ int interrupts_process (struct interrupts *interrupts) { int id; uint8 ccr; /* See if interrupts are enabled/disabled and keep track of the number of cycles the interrupts are masked. Such information is then reported by the info command. */ ccr = cpu_get_ccr (interrupts->cpu); if (ccr & M6811_I_BIT) { if (interrupts->start_mask_cycle < 0) interrupts->start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->start_mask_cycle >= 0 && (ccr & M6811_I_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->start_mask_cycle; if (t < interrupts->min_mask_cycles) interrupts->min_mask_cycles = t; if (t > interrupts->max_mask_cycles) interrupts->max_mask_cycles = t; interrupts->start_mask_cycle = -1; interrupts->last_mask_cycles = t; } if (ccr & M6811_X_BIT) { if (interrupts->xirq_start_mask_cycle < 0) interrupts->xirq_start_mask_cycle = cpu_current_cycle (interrupts->cpu); } else if (interrupts->xirq_start_mask_cycle >= 0 && (ccr & M6811_X_BIT) == 0) { signed64 t = cpu_current_cycle (interrupts->cpu); t -= interrupts->xirq_start_mask_cycle; if (t < interrupts->xirq_min_mask_cycles) interrupts->xirq_min_mask_cycles = t; if (t > interrupts->xirq_max_mask_cycles) interrupts->xirq_max_mask_cycles = t; interrupts->xirq_start_mask_cycle = -1; interrupts->xirq_last_mask_cycles = t; } id = interrupts_get_current (interrupts); if (id >= 0) { uint16 addr; cpu_push_all (interrupts->cpu); addr = memory_read16 (interrupts->cpu, interrupts->vectors_addr + id * 2); cpu_call (interrupts->cpu, addr); /* Now, protect from nested interrupts. */ if (id == M6811_INT_XIRQ) { cpu_set_ccr_X (interrupts->cpu, 1); } else { cpu_set_ccr_I (interrupts->cpu, 1); } interrupts->nb_interrupts_raised++; cpu_add_cycles (interrupts->cpu, 14); return 1; } return 0; }