uint8_t CPU::fetch_destination(ADDRESSING_MODE mode) { switch (mode) { case ADDRESSING_ZEROPAGE: { return fetch_operand(ADDRESSING_IMMEDIATE); } case ADDRESSING_ZEROPAGE_X: { return fetch_operand(ADDRESSING_IMMEDIATE) + index_x; } case ADDRESSING_ZEROPAGE_Y: { return fetch_operand(ADDRESSING_IMMEDIATE) + index_y; } default: { printf("fetch_destination(): Invalid addressing mode %d", mode); std::exit(255); } } }
//-------------------------------------------------------------------- // void execute(instr *i) // // execute consists of the following tasks: // - fetch the operands // - execute the operation in the intruction // - write the data back in the destination // - compute the next address for (jmp, call, return...) // //-------------------------------------------------------------------- void cycle_model::execute(instr *i) { int in1, in2, out = 0; // fetch operands --------------------------------------------------- if(i->n_src>=1) in1 = fetch_operand(&(i->src1)); if(i->n_src>=2) in2 = fetch_operand(&(i->src2)); #ifdef DEBUG printf("execute %d, with in1=%d and in2=%d\n",i->type,in1, in2); #endif // execute ---------------------------------------------------------- switch(i->type) { case i_add: { out = in1 + in2; break; } case i_sub: { out = in1 - in2; break; } case i_inc: { out = in1+1; break; } case i_dec: { out = in1-1; break; } case i_mul: { out = in1 * in2; break; } case i_div: { out = in1/in2; break; } // logic operations case i_and: { out = in1 & in2; break; } case i_or: { out = in1 | in2; break; } case i_xor: { out = in1 ^ in2; break; } case i_rl: { out = in1<<1; break; } case i_rr: { out = in2>>1; break; } // data transfer case i_mov: { out = in1; break; } // branching (out==0 -> don't branch) case i_call: case i_ret: case i_jmp: case i_sjmp: { out = 1; break; } case i_jz: { out = (A==0); break; } case i_jnz: { out = (A!=0); break; } case i_cjne: { out = (in1!=in2); break; } case i_djnz: { out=in1-1; // decrement reg/direct and jump if != 0 break; } default: { break; } } // write back -------------------------------------------------------- write_back(&(i->dst),out); // compute next address ---------------------------------------------- switch(i->type) { case i_call: { stack_el *new_stack_el= (stack_el *) malloc(sizeof(stack_el)); new_stack_el->up = my_stack; new_stack_el->address = in1; my_stack = new_stack_el; /* wait additional cycles */ int result; exec_bus_cycle(OP_IDLE,0,0,&result); break; } case i_ret: { stack_el *new_stack_el = my_stack->up; free(my_stack); my_stack = new_stack_el; if(my_stack!=NULL) my_stack->address += 1; // increment address after jump /* wait additional cycles */ int result; exec_bus_cycle(OP_IDLE,0,0,&result); exec_bus_cycle(OP_IDLE,0,0,&result); exec_bus_cycle(OP_IDLE,0,0,&result); break; } case i_jmp: { my_stack->address = in1; /* wait additional cycles */ int result; exec_bus_cycle(OP_IDLE,0,0,&result); break; } case i_sjmp: case i_jz: case i_jnz: { if(out!=0) my_stack->address += in1+1; else my_stack->address += 1; /* wait additional cycles */ int result; exec_bus_cycle(OP_IDLE,0,0,&result); break; } case i_cjne: { int in3 = fetch_operand(&i->dst); if(out!=0) my_stack->address += in3+1; else my_stack->address += 1; /* wait additional cycles */ int result; exec_bus_cycle(OP_IDLE,0,0,&result); break; } case i_djnz: { if(out!=0) my_stack->address += in2+1; else my_stack->address += 1; /* wait additional cycles */ int result; exec_bus_cycle(OP_IDLE,0,0,&result); break; } default: { my_stack->address += 1; break; } } }
uint8_t CPU::fetch_operand(ADDRESSING_MODE mode) { lastInstructionCrossedPageBoundary = false; switch (mode) { case ADDRESSING_IMMEDIATE: { uint8_t operand = fetch_memory_byte(program_counter, true); last_operand = operand; return operand; } case ADDRESSING_ZEROPAGE: { //TODO: Why is this here? uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE); last_operand = address; return address; } case ADDRESSING_ZEROPAGE_X: { uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE); lastInstructionCrossedPageBoundary = (address + index_x < address); uint8_t operand = fetch_zero_page_byte(address + index_x); last_operand = address; return operand; } case ADDRESSING_ZEROPAGE_Y: { uint8_t address = fetch_operand(ADDRESSING_IMMEDIATE); lastInstructionCrossedPageBoundary = (address + index_y < address); uint8_t operand = fetch_zero_page_byte(address + index_y); last_operand = address; return operand; } case ADDRESSING_ABSOLUTE: { uint8_t addrLow = fetch_memory_byte(program_counter); uint8_t addrHigh = fetch_memory_byte(program_counter); WideAddress address = { addrHigh, addrLow }; uint8_t operand = fetch_memory_byte(address, false); last_operand = address; return operand; } case ADDRESSING_ABSOLUTE_X: { uint8_t addrLow = fetch_memory_byte(program_counter); uint8_t addrHigh = fetch_memory_byte(program_counter); WideAddress address = { addrHigh, addrLow }; lastInstructionCrossedPageBoundary = (addrLow + index_x < addrLow); uint8_t operand = fetch_memory_byte(address.add(index_x, false), false); last_operand = address; return operand; } case ADDRESSING_ABSOLUTE_Y: { uint8_t addrLow = fetch_memory_byte(program_counter); uint8_t addrHigh = fetch_memory_byte(program_counter); WideAddress address = { addrHigh, addrLow }; lastInstructionCrossedPageBoundary = (addrLow + index_y < addrLow); uint8_t operand = fetch_memory_byte(address.add(index_y, false), false); last_operand = address; return operand; } case ADDRESSING_INDIRECT_X: { WideAddress operand_address = fetch_dereferenced_zero_page_pointer(INDEX_X); last_operand = operand_address; uint8_t operand = fetch_memory_byte(operand_address, false); last_operand = operand; return operand; } case ADDRESSING_INDIRECT_Y: { WideAddress destination = fetch_dereferenced_zero_page_pointer(INDEX_NONE); lastInstructionCrossedPageBoundary = ((destination & 0xFF00) + index_y) > (destination & 0xFF00); destination = destination.add(index_y, false); uint8_t operand = fetch_memory_byte(destination); last_operand = operand; return operand; } default: { printf("fetch_operand(): Invalid addressing mode %d", mode); std::exit(255); } } }