2019-04-13 20:00:37 +00:00
|
|
|
#include "state.h"
|
|
|
|
#include "cpu.h"
|
2019-04-13 21:59:48 +00:00
|
|
|
#include "opcodes.h"
|
2019-04-27 10:43:15 +00:00
|
|
|
#include "memory.h"
|
2019-04-13 21:59:48 +00:00
|
|
|
#include <stdio.h>
|
2019-04-14 10:39:56 +00:00
|
|
|
#include <memory.h>
|
2019-04-14 11:24:02 +00:00
|
|
|
#include <stdlib.h>
|
2019-04-13 20:00:37 +00:00
|
|
|
|
|
|
|
void* unimplemented_instruction(State6502* state) {
|
|
|
|
printf("Error: unimplemented instruction\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2019-04-19 08:34:07 +00:00
|
|
|
int is_negative(byte value) {
|
|
|
|
return ((1 << 7) & value) != 0;
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void set_z_flag(State6502 * state, byte value) {
|
2019-04-20 06:49:28 +00:00
|
|
|
state->flags.z = value == 0;
|
|
|
|
}
|
|
|
|
|
2019-04-19 08:34:07 +00:00
|
|
|
void set_NV_flags(State6502 * state, byte value) {
|
|
|
|
state->flags.n = is_negative(value);
|
2019-04-21 13:31:53 +00:00
|
|
|
state->flags.v = ((1 << 6) & value) != 0;
|
2019-04-14 21:40:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void set_NZ_flags(State6502 * state, byte value) {
|
2019-04-20 06:49:28 +00:00
|
|
|
set_z_flag(state, value);
|
2019-04-14 21:40:53 +00:00
|
|
|
//N flag
|
2019-04-19 08:34:07 +00:00
|
|
|
state->flags.n = is_negative(value);
|
2019-04-13 21:59:48 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
byte flags_as_byte(State6502 * state) {
|
|
|
|
byte flags_value = 0;
|
|
|
|
flags_value |= state->flags.c << 0;
|
|
|
|
flags_value |= state->flags.z << 1;
|
|
|
|
flags_value |= state->flags.i << 2;
|
|
|
|
flags_value |= state->flags.d << 3;
|
|
|
|
//flag B is active with PHP
|
|
|
|
flags_value |= 1 << 4;
|
|
|
|
//unused bit is active with PHP
|
|
|
|
flags_value |= 1 << 5;
|
|
|
|
flags_value |= state->flags.v << 6;
|
|
|
|
flags_value |= state->flags.n << 7;
|
2019-04-29 04:37:56 +00:00
|
|
|
return flags_value;
|
|
|
|
}
|
|
|
|
|
2019-04-14 21:40:53 +00:00
|
|
|
void clear_flags(State6502 * state) {
|
2019-04-16 20:46:28 +00:00
|
|
|
state->flags.b =
|
|
|
|
state->flags.c =
|
|
|
|
state->flags.d =
|
|
|
|
state->flags.i =
|
|
|
|
state->flags.n =
|
|
|
|
state->flags.v =
|
|
|
|
state->flags.z = 0;
|
|
|
|
state->flags.pad = 1; //unused is supposed to be 1
|
2019-04-13 21:59:48 +00:00
|
|
|
}
|
|
|
|
|
2019-04-14 21:40:53 +00:00
|
|
|
void clear_state(State6502 * state) {
|
2019-04-13 21:59:48 +00:00
|
|
|
state->a = 0;
|
|
|
|
state->x = 0;
|
|
|
|
state->y = 0;
|
|
|
|
state->pc = 0;
|
2019-05-04 12:11:39 +00:00
|
|
|
state->sp = 0xFF;
|
2019-04-13 21:59:48 +00:00
|
|
|
clear_flags(state);
|
|
|
|
state->running = 1;
|
|
|
|
}
|
|
|
|
|
2019-04-16 20:46:28 +00:00
|
|
|
void push_byte_to_stack(State6502 * state, byte value) {
|
|
|
|
//stack located between $0100 to $01FF
|
|
|
|
state->memory[STACK_HOME + state->sp--] = value;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void push_word_to_stack(State6502 * state, word value) {
|
2019-04-26 05:22:42 +00:00
|
|
|
push_byte_to_stack(state, (value >> 8) & 0xFF);
|
|
|
|
push_byte_to_stack(state, value & 0xFF);
|
|
|
|
}
|
|
|
|
|
2019-04-16 20:46:28 +00:00
|
|
|
byte pop_byte_from_stack(State6502 * state) {
|
2019-04-19 08:34:07 +00:00
|
|
|
return state->memory[STACK_HOME + ++(state->sp)];
|
2019-04-16 20:46:28 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
word pop_word_from_stack(State6502 * state) {
|
2019-04-26 05:22:42 +00:00
|
|
|
byte low = pop_byte_from_stack(state);
|
|
|
|
byte high = pop_byte_from_stack(state);
|
2019-04-27 17:22:06 +00:00
|
|
|
return low + ((word)high << 8);
|
2019-04-26 05:22:42 +00:00
|
|
|
}
|
|
|
|
|
2019-04-13 21:59:48 +00:00
|
|
|
//bitwise or with accumulator
|
2019-04-14 21:40:53 +00:00
|
|
|
void ORA(State6502 * state, byte operand) {
|
2019-04-13 23:51:50 +00:00
|
|
|
byte result = state->a | operand;
|
2019-05-01 21:15:43 +00:00
|
|
|
set_NZ_flags(state, result);
|
2019-04-13 23:51:50 +00:00
|
|
|
state->a = result;
|
|
|
|
}
|
|
|
|
|
2019-04-14 18:45:24 +00:00
|
|
|
//bitwise and with accumulator
|
2019-04-14 21:40:53 +00:00
|
|
|
void AND(State6502 * state, byte operand) {
|
2019-04-14 18:45:24 +00:00
|
|
|
byte result = state->a & operand;
|
2019-05-01 21:15:43 +00:00
|
|
|
set_NZ_flags(state, result);
|
2019-04-14 18:45:24 +00:00
|
|
|
state->a = result;
|
|
|
|
}
|
|
|
|
|
2019-04-13 23:51:50 +00:00
|
|
|
//load accumulator
|
2019-04-14 21:40:53 +00:00
|
|
|
void LDA(State6502 * state, byte operand) {
|
2019-04-13 23:51:50 +00:00
|
|
|
state->a = operand;
|
2019-04-27 10:43:15 +00:00
|
|
|
set_NZ_flags(state, state->a);
|
2019-04-13 23:51:50 +00:00
|
|
|
}
|
|
|
|
|
2019-04-14 21:40:53 +00:00
|
|
|
void LDX(State6502 * state, byte operand) {
|
2019-04-14 20:04:16 +00:00
|
|
|
state->x = operand;
|
2019-04-27 10:43:15 +00:00
|
|
|
set_NZ_flags(state, state->x);
|
2019-04-14 20:04:16 +00:00
|
|
|
}
|
|
|
|
|
2019-04-14 21:40:53 +00:00
|
|
|
void LDY(State6502 * state, byte operand) {
|
2019-04-14 20:20:32 +00:00
|
|
|
state->y = operand;
|
2019-04-27 10:43:15 +00:00
|
|
|
set_NZ_flags(state, state->y);
|
2019-04-14 20:20:32 +00:00
|
|
|
}
|
|
|
|
|
2019-04-15 22:09:55 +00:00
|
|
|
void STA(State6502 * state, word address) {
|
|
|
|
state->memory[address] = state->a;
|
|
|
|
}
|
|
|
|
|
2019-04-14 21:40:53 +00:00
|
|
|
void STX(State6502 * state, word address) {
|
2019-04-14 21:05:37 +00:00
|
|
|
state->memory[address] = state->x;
|
|
|
|
}
|
|
|
|
|
2019-04-14 21:40:53 +00:00
|
|
|
void STY(State6502 * state, word address) {
|
2019-04-14 21:05:37 +00:00
|
|
|
state->memory[address] = state->y;
|
|
|
|
}
|
|
|
|
|
2019-04-15 21:34:21 +00:00
|
|
|
void INC(State6502 * state, word address) {
|
|
|
|
state->memory[address] += 1;
|
|
|
|
set_NZ_flags(state, state->memory[address]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DEC(State6502 * state, word address) {
|
|
|
|
state->memory[address] -= 1;
|
|
|
|
set_NZ_flags(state, state->memory[address]);
|
|
|
|
}
|
|
|
|
|
2019-04-15 22:03:48 +00:00
|
|
|
void EOR(State6502 * state, byte operand) {
|
|
|
|
state->a = state->a ^ operand;
|
2019-05-01 21:15:43 +00:00
|
|
|
set_NZ_flags(state, state->a);
|
2019-04-15 22:03:48 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 17:46:56 +00:00
|
|
|
void JMP(State6502 * state, word address) {
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void SBC(State6502 * state, byte operand) {
|
2019-04-19 09:38:52 +00:00
|
|
|
//subtract operand from A
|
|
|
|
word operand_word = operand;
|
2019-04-26 08:44:57 +00:00
|
|
|
//borrow the complement of carry flag - if the carry flag is 1, borrow 0 and vice versa
|
|
|
|
word result_word = state->a - operand_word - !state->flags.c;
|
2019-04-21 13:31:53 +00:00
|
|
|
byte result = result_word & 0xFF;
|
2019-04-19 09:38:52 +00:00
|
|
|
|
2019-04-21 07:38:38 +00:00
|
|
|
// overflow flag if the the result doesn't fit into the signed byte range -128 to 127
|
2019-04-21 13:31:53 +00:00
|
|
|
state->flags.v = ((state->a ^ operand) & 0x80) && ((state->a ^ result) & 0x80);
|
2019-04-21 07:38:38 +00:00
|
|
|
|
2019-04-26 08:44:57 +00:00
|
|
|
state->a = result;
|
2019-04-19 09:38:52 +00:00
|
|
|
state->flags.n = is_negative(state->a);
|
|
|
|
state->flags.z = state->a == 0;
|
2019-04-26 10:14:25 +00:00
|
|
|
state->flags.c = result_word <= 0xFF;
|
2019-04-21 07:28:07 +00:00
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void ADC(State6502 * state, byte operand) {
|
2019-04-21 07:28:07 +00:00
|
|
|
//add operand to A
|
2019-04-21 13:31:53 +00:00
|
|
|
word result_word = operand + state->a + (state->flags.c ? 1 : 0);
|
2019-04-21 07:38:38 +00:00
|
|
|
byte result = result_word & 0xFF;
|
|
|
|
//set overflow flag if the result's sign would change - the result doesn't fit into a signed byte
|
|
|
|
//there is overflow if the inputs do not have different signs and the input sign is different from the output sign
|
2019-04-22 08:17:26 +00:00
|
|
|
//meaning two numbers that have the same sign are added, and the result has a different sign.
|
|
|
|
|
|
|
|
//overflow = <'a' and 'arg' have the same sign> & <the sign of 'a'and 'sum' differs> & <extract sign bit>
|
2019-04-21 07:38:38 +00:00
|
|
|
state->flags.v = !((state->a ^ operand) & 0x80) && ((state->a ^ result) & 0x80);
|
2019-04-22 08:17:26 +00:00
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
state->a = result;
|
2019-04-21 07:28:07 +00:00
|
|
|
state->flags.n = is_negative(state->a);
|
|
|
|
state->flags.z = state->a == 0;
|
|
|
|
state->flags.c = result_word > 0xFF;
|
2019-04-19 09:38:52 +00:00
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void BIT(State6502 * state, byte operand) {
|
|
|
|
//BIT sets the Z flag as though the value in the address tested were ANDed with the accumulator.
|
|
|
|
//The N and V flags are set to match bits 7 and 6 respectively in the value stored at the tested address.
|
|
|
|
set_NV_flags(state, operand);
|
|
|
|
state->flags.z = (state->a & operand) == 0;
|
|
|
|
}
|
|
|
|
|
2019-04-19 08:34:07 +00:00
|
|
|
void cmp_internal(State6502 * state, byte register_value, byte operand) {
|
|
|
|
//set carry flag if A >= M
|
|
|
|
state->flags.c = register_value >= operand;
|
|
|
|
//set zero flag if A == M
|
|
|
|
state->flags.z = register_value == operand;
|
|
|
|
//set negative flag if A - M is negative
|
|
|
|
state->flags.n = is_negative(register_value - operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CMP(State6502 * state, byte operand) {
|
|
|
|
cmp_internal(state, state->a, operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPX(State6502 * state, byte operand) {
|
|
|
|
cmp_internal(state, state->x, operand);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CPY(State6502 * state, byte operand) {
|
|
|
|
cmp_internal(state, state->y, operand);
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:09:38 +00:00
|
|
|
//Aritmetic Shift Left
|
2019-04-21 13:31:53 +00:00
|
|
|
byte asl(State6502 * state, byte operand) {
|
2019-04-19 09:38:52 +00:00
|
|
|
byte result = operand << 1;
|
2019-05-07 12:09:38 +00:00
|
|
|
state->flags.c = (operand & 0x80) == 0x80;
|
2019-04-20 06:49:28 +00:00
|
|
|
set_NZ_flags(state, result);
|
2019-04-19 09:38:52 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void ASL_A(State6502 * state) {
|
2019-04-19 09:38:52 +00:00
|
|
|
state->a = asl(state, state->a);
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void ASL_MEM(State6502 * state, word address) {
|
2019-04-19 09:38:52 +00:00
|
|
|
byte operand = state->memory[address];
|
|
|
|
state->memory[address] = operand;
|
|
|
|
state->memory[address] = asl(state, operand);
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
byte lsr(State6502 * state, byte operand) {
|
2019-04-19 09:44:20 +00:00
|
|
|
byte result = operand >> 1;
|
|
|
|
state->flags.c = (operand & 0x01) != 0;
|
2019-04-20 06:49:28 +00:00
|
|
|
set_NZ_flags(state, result);
|
2019-04-19 09:44:20 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void LSR_A(State6502 * state) {
|
2019-04-19 09:44:20 +00:00
|
|
|
state->a = lsr(state, state->a);
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void LSR_MEM(State6502 * state, word address) {
|
2019-04-19 09:44:20 +00:00
|
|
|
byte operand = state->memory[address];
|
|
|
|
state->memory[address] = lsr(state, operand);
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
byte rol(State6502 * state, byte operand) {
|
2019-04-19 09:55:17 +00:00
|
|
|
word result_word = (operand << 1) | state->flags.c;
|
|
|
|
state->flags.c = result_word > 0xFF;
|
|
|
|
byte result = result_word & 0xFF;
|
2019-04-20 06:49:28 +00:00
|
|
|
set_NZ_flags(state, result);
|
2019-04-19 09:55:17 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void ROL_A(State6502 * state) {
|
2019-04-19 09:55:17 +00:00
|
|
|
state->a = rol(state, state->a);
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
void ROL_MEM(State6502 * state, word address) {
|
2019-04-19 09:55:17 +00:00
|
|
|
byte operand = state->memory[address];
|
|
|
|
state->memory[address] = rol(state, operand);
|
|
|
|
}
|
|
|
|
|
2019-04-21 13:31:53 +00:00
|
|
|
byte ror(State6502 * state, byte operand) {
|
2019-05-07 13:39:43 +00:00
|
|
|
byte result = (operand >> 1) | (state->flags.c << 7);
|
|
|
|
state->flags.c = (operand & 0x01) != 0;
|
2019-04-20 06:49:28 +00:00
|
|
|
set_NZ_flags(state, result);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ROR_A(State6502 * state) {
|
2019-05-07 13:39:43 +00:00
|
|
|
state->a = ror(state, state->a);
|
2019-04-20 06:49:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ROR_MEM(State6502 * state, word address) {
|
|
|
|
byte operand = state->memory[address];
|
|
|
|
state->memory[address] = ror(state, operand);
|
|
|
|
}
|
|
|
|
|
2019-04-26 05:22:42 +00:00
|
|
|
void JSR(State6502 * state, word address) {
|
|
|
|
//JSR pushes the address-1 of the next operation on to the stack before transferring program control to the following address.
|
|
|
|
word address_to_push = state->pc - 1;
|
|
|
|
push_byte_to_stack(state, (address_to_push >> 8 & 0xFF));
|
|
|
|
push_byte_to_stack(state, address_to_push & 0xFF);
|
2019-04-26 09:24:49 +00:00
|
|
|
state->pc = address;
|
2019-04-26 05:22:42 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void RTS_(State6502 * state) {
|
2019-04-26 05:22:42 +00:00
|
|
|
word address = pop_word_from_stack(state);
|
|
|
|
state->pc = address + 1;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void RTI_(State6502 * state) {
|
2019-04-27 11:18:28 +00:00
|
|
|
//interrupt pushes PC first, then status register
|
|
|
|
//RTI should pull status register and program counter from the stack
|
2019-05-04 14:03:54 +00:00
|
|
|
byte value = pop_byte_from_stack(state);
|
|
|
|
//we don't read the BRK flag
|
|
|
|
value &= ~(1 << 4);
|
|
|
|
//the bit 5 always comes in as true
|
|
|
|
value |= 1 << 5;
|
|
|
|
memset(&state->flags, value, sizeof(Flags));
|
2019-04-27 11:18:28 +00:00
|
|
|
word address = pop_word_from_stack(state);
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BEQ(State6502 * state) {
|
2019-04-27 10:43:15 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (state->flags.z)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BNE(State6502 * state) {
|
2019-04-27 11:02:04 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (!state->flags.z)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BCC(State6502 * state) {
|
2019-04-27 11:02:04 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (!state->flags.c)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BCS(State6502 * state) {
|
2019-04-27 11:02:04 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (state->flags.c)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BMI(State6502 * state) {
|
2019-04-27 11:02:04 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (state->flags.n)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BPL(State6502 * state) {
|
2019-04-27 11:02:04 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (!state->flags.n)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BVS(State6502 * state) {
|
2019-04-27 11:02:04 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (state->flags.v)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void BVC(State6502 * state) {
|
2019-04-27 11:02:04 +00:00
|
|
|
word address = get_address_relative(state);
|
|
|
|
if (!state->flags.v)
|
|
|
|
state->pc = address;
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void PLA_(State6502 * state) {
|
2019-04-27 11:18:28 +00:00
|
|
|
state->a = pop_byte_from_stack(state);
|
|
|
|
set_NZ_flags(state, state->a);
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void PLP_(State6502 * state) {
|
2019-04-27 11:18:28 +00:00
|
|
|
byte value = pop_byte_from_stack(state);
|
2019-05-01 19:10:12 +00:00
|
|
|
//we don't read the BRK flag
|
2019-05-01 20:15:03 +00:00
|
|
|
value &= ~(1 << 4);
|
2019-05-01 20:59:15 +00:00
|
|
|
//the bit 5 always comes in as true
|
|
|
|
value |= 1 << 5;
|
2019-04-27 11:18:28 +00:00
|
|
|
memset(&state->flags, value, sizeof(Flags));
|
|
|
|
}
|
|
|
|
|
2019-05-04 12:11:39 +00:00
|
|
|
void PHP_(State6502 * state) {
|
|
|
|
byte flags_value = flags_as_byte(state);
|
2019-04-27 11:18:28 +00:00
|
|
|
push_byte_to_stack(state, flags_value);
|
|
|
|
}
|
|
|
|
|
2019-04-13 21:59:48 +00:00
|
|
|
int emulate_6502_op(State6502 * state) {
|
|
|
|
byte* opcode = &state->memory[state->pc++];
|
2019-04-13 20:00:37 +00:00
|
|
|
switch (*opcode) {
|
2019-04-27 11:57:47 +00:00
|
|
|
case ADC_IMM: ADC(state, fetch_byte(state)); break;
|
2019-04-21 07:28:07 +00:00
|
|
|
case ADC_ZP: ADC(state, get_byte_zero_page(state)); break;
|
|
|
|
case ADC_ZPX: ADC(state, get_byte_zero_page_x(state)); break;
|
|
|
|
case ADC_ABS: ADC(state, get_byte_absolute(state)); break;
|
|
|
|
case ADC_ABSX: ADC(state, get_byte_absolute_x(state)); break;
|
|
|
|
case ADC_ABSY: ADC(state, get_byte_absolute_y(state)); break;
|
|
|
|
case ADC_INDX: ADC(state, get_byte_indirect_x(state)); break;
|
|
|
|
case ADC_INDY: ADC(state, get_byte_indirect_y(state)); break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case AND_IMM: AND(state, fetch_byte(state)); break;
|
2019-04-14 18:45:24 +00:00
|
|
|
case AND_ZP: AND(state, get_byte_zero_page(state)); break;
|
|
|
|
case AND_ZPX: AND(state, get_byte_zero_page_x(state)); break;
|
|
|
|
case AND_ABS: AND(state, get_byte_absolute(state)); break;
|
|
|
|
case AND_ABSX: AND(state, get_byte_absolute_x(state)); break;
|
|
|
|
case AND_ABSY: AND(state, get_byte_absolute_y(state)); break;
|
2019-04-14 19:25:23 +00:00
|
|
|
case AND_INDX: AND(state, get_byte_indirect_x(state)); break;
|
|
|
|
case AND_INDY: AND(state, get_byte_indirect_y(state)); break;
|
2019-04-19 09:38:52 +00:00
|
|
|
case ASL_ACC: ASL_A(state); break;
|
|
|
|
case ASL_ZP: ASL_MEM(state, get_address_zero_page(state)); break;
|
|
|
|
case ASL_ZPX: ASL_MEM(state, get_address_zero_page_x(state)); break;
|
|
|
|
case ASL_ABS: ASL_MEM(state, get_address_absolute(state)); break;
|
|
|
|
case ASL_ABSX: ASL_MEM(state, get_address_absolute_x(state)); break;
|
2019-04-27 11:02:04 +00:00
|
|
|
case BCC_REL: BCC(state); break;
|
|
|
|
case BCS_REL: BCS(state); break;
|
2019-04-27 10:43:15 +00:00
|
|
|
case BEQ_REL: BEQ(state); break;
|
2019-04-27 11:02:04 +00:00
|
|
|
case BMI_REL: BMI(state); break;
|
|
|
|
case BNE_REL: BNE(state); break;
|
|
|
|
case BPL_REL: BPL(state); break;
|
|
|
|
case BVC_REL: BVC(state); break;
|
|
|
|
case BVS_REL: BVS(state); break;
|
2019-04-21 13:31:53 +00:00
|
|
|
case BIT_ZP: BIT(state, get_byte_zero_page(state)); break;
|
|
|
|
case BIT_ABS: BIT(state, get_byte_absolute(state)); break;
|
2019-04-14 07:38:09 +00:00
|
|
|
case BRK: state->running = 0;
|
2019-04-13 23:51:50 +00:00
|
|
|
state->flags.b = 1;
|
|
|
|
break; //BRK
|
2019-04-15 21:44:07 +00:00
|
|
|
case CLC: state->flags.c = 0; break;
|
|
|
|
case CLD: state->flags.d = 0; break;
|
|
|
|
case CLI: state->flags.i = 0; break;
|
|
|
|
case CLV: state->flags.v = 0; break;
|
2019-04-13 23:51:50 +00:00
|
|
|
case NOP: break; //NOP
|
2019-04-16 20:46:28 +00:00
|
|
|
case PHA: push_byte_to_stack(state, state->a); break; //push accumulator to stack
|
2019-04-27 11:18:28 +00:00
|
|
|
case PLA: PLA_(state); break; //pull accumulator from stack
|
|
|
|
case PHP: PHP_(state); break; //push processor status
|
|
|
|
case PLP: PLP_(state); break; //pull procesor status
|
|
|
|
case RTI: RTI_(state); break;
|
2019-04-26 05:22:42 +00:00
|
|
|
case RTS: RTS_(state); break;
|
2019-04-15 21:44:07 +00:00
|
|
|
case SEC: state->flags.c = 1; break;
|
|
|
|
case SED: state->flags.d = 1; break;
|
|
|
|
case SEI: state->flags.i = 1; break;
|
2019-04-16 20:46:28 +00:00
|
|
|
case TAX: state->x = state->a; set_NZ_flags(state, state->x); break;
|
|
|
|
case TXA: state->a = state->x; set_NZ_flags(state, state->a); break;
|
|
|
|
case TAY: state->y = state->a; set_NZ_flags(state, state->y); break;
|
|
|
|
case TYA: state->a = state->y; set_NZ_flags(state, state->a); break;
|
2019-04-19 08:34:07 +00:00
|
|
|
case TSX: state->x = state->sp; set_NZ_flags(state, state->x); break;
|
2019-05-01 21:30:46 +00:00
|
|
|
case TXS: state->sp = state->x; break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case CMP_IMM: CMP(state, fetch_byte(state)); break; //TODO test
|
2019-04-19 08:36:14 +00:00
|
|
|
case CMP_ZP: CMP(state, get_byte_zero_page(state)); break; //TODO test
|
2019-04-19 08:34:07 +00:00
|
|
|
case CMP_ZPX: CMP(state, get_byte_zero_page_x(state)); break; //TODO test
|
2019-04-19 08:36:14 +00:00
|
|
|
case CMP_ABS: CMP(state, get_byte_absolute(state)); break;
|
2019-04-19 08:34:07 +00:00
|
|
|
case CMP_ABSX: CMP(state, get_byte_absolute_x(state)); break;//TODO test
|
|
|
|
case CMP_ABSY: CMP(state, get_byte_absolute_y(state)); break;//TODO test
|
|
|
|
case CMP_INDX: CMP(state, get_byte_indirect_x(state)); break;//TODO test
|
|
|
|
case CMP_INDY: CMP(state, get_byte_indirect_y(state)); break;//TODO test
|
2019-04-27 11:57:47 +00:00
|
|
|
case CPX_IMM: CPX(state, fetch_byte(state)); break;//TODO test
|
2019-04-19 08:34:07 +00:00
|
|
|
case CPX_ZP: CPX(state, get_byte_zero_page(state)); break;//TODO test
|
|
|
|
case CPX_ABS: CPX(state, get_byte_absolute(state)); break;//TODO test
|
2019-04-27 11:57:47 +00:00
|
|
|
case CPY_IMM: CPY(state, fetch_byte(state)); break;//TODO test
|
2019-04-19 08:34:07 +00:00
|
|
|
case CPY_ZP: CPY(state, get_byte_zero_page(state)); break;//TODO test
|
|
|
|
case CPY_ABS: CPY(state, get_byte_absolute(state)); break;//TODO test
|
2019-04-15 21:34:21 +00:00
|
|
|
case DEC_ZP: DEC(state, get_address_zero_page(state)); break;
|
|
|
|
case DEC_ZPX: DEC(state, get_address_zero_page_x(state)); break;
|
|
|
|
case DEC_ABS: DEC(state, get_address_absolute(state)); break;
|
|
|
|
case DEC_ABSX: DEC(state, get_address_absolute_x(state)); break;
|
2019-04-14 21:40:53 +00:00
|
|
|
case DEX: state->x -= 1; set_NZ_flags(state, state->x); break;
|
|
|
|
case DEY: state->y -= 1; set_NZ_flags(state, state->y); break;
|
|
|
|
case INX: state->x += 1; set_NZ_flags(state, state->x); break;
|
|
|
|
case INY: state->y += 1; set_NZ_flags(state, state->y); break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case EOR_IMM: EOR(state, fetch_byte(state)); break;
|
2019-04-15 22:03:48 +00:00
|
|
|
case EOR_ZP: EOR(state, get_byte_zero_page(state)); break;
|
|
|
|
case EOR_ZPX: EOR(state, get_byte_zero_page_x(state)); break;
|
|
|
|
case EOR_ABS: EOR(state, get_byte_absolute(state)); break;
|
|
|
|
case EOR_ABSX: EOR(state, get_byte_absolute_x(state)); break;
|
|
|
|
case EOR_ABSY: EOR(state, get_byte_absolute_y(state)); break;
|
|
|
|
case EOR_INDX: EOR(state, get_byte_indirect_x(state)); break;
|
|
|
|
case EOR_INDY: EOR(state, get_byte_indirect_y(state)); break;
|
2019-04-15 21:34:21 +00:00
|
|
|
case INC_ZP: INC(state, get_address_zero_page(state)); break;
|
|
|
|
case INC_ZPX: INC(state, get_address_zero_page_x(state)); break;
|
|
|
|
case INC_ABS: INC(state, get_address_absolute(state)); break;
|
|
|
|
case INC_ABSX: INC(state, get_address_absolute_x(state)); break;
|
2019-04-17 17:46:56 +00:00
|
|
|
case JMP_ABS: JMP(state, get_address_absolute(state)); break;
|
|
|
|
case JMP_IND: JMP(state, get_address_indirect_jmp(state)); break;
|
2019-04-26 05:22:42 +00:00
|
|
|
case JSR_ABS: JSR(state, get_address_absolute(state)); break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case LDA_IMM: LDA(state, fetch_byte(state)); break;
|
2019-04-14 18:45:24 +00:00
|
|
|
case LDA_ZP: LDA(state, get_byte_zero_page(state)); break;
|
|
|
|
case LDA_ZPX: LDA(state, get_byte_zero_page_x(state)); break;
|
|
|
|
case LDA_ABS: LDA(state, get_byte_absolute(state)); break;
|
|
|
|
case LDA_ABSX: LDA(state, get_byte_absolute_x(state)); break;
|
|
|
|
case LDA_ABSY: LDA(state, get_byte_absolute_y(state)); break;
|
2019-04-14 19:25:23 +00:00
|
|
|
case LDA_INDX: LDA(state, get_byte_indirect_x(state)); break;
|
|
|
|
case LDA_INDY: LDA(state, get_byte_indirect_y(state)); break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case LDX_IMM: LDX(state, fetch_byte(state)); break;
|
2019-04-14 20:04:16 +00:00
|
|
|
case LDX_ZP: LDX(state, get_byte_zero_page(state)); break;
|
|
|
|
case LDX_ZPY: LDX(state, get_byte_zero_page_y(state)); break;
|
2019-04-14 20:20:32 +00:00
|
|
|
case LDX_ABS: LDX(state, get_byte_absolute(state)); break;
|
2019-04-14 20:04:16 +00:00
|
|
|
case LDX_ABSY: LDX(state, get_byte_absolute_y(state)); break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case LDY_IMM: LDY(state, fetch_byte(state)); break;
|
2019-04-14 20:20:32 +00:00
|
|
|
case LDY_ZP: LDY(state, get_byte_zero_page(state)); break;
|
|
|
|
case LDY_ZPX: LDY(state, get_byte_zero_page_x(state)); break;
|
|
|
|
case LDY_ABS: LDY(state, get_byte_absolute(state)); break;
|
|
|
|
case LDY_ABSX: LDY(state, get_byte_absolute_x(state)); break;
|
2019-04-19 09:44:20 +00:00
|
|
|
case LSR_ACC: LSR_A(state); break;
|
|
|
|
case LSR_ZP: LSR_MEM(state, get_address_zero_page(state)); break;
|
|
|
|
case LSR_ZPX: LSR_MEM(state, get_address_zero_page_x(state)); break;
|
|
|
|
case LSR_ABS: LSR_MEM(state, get_address_absolute(state)); break;
|
|
|
|
case LSR_ABSX: LSR_MEM(state, get_address_absolute_x(state)); break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case ORA_IMM: ORA(state, fetch_byte(state)); break;
|
2019-04-14 18:45:24 +00:00
|
|
|
case ORA_ZP: ORA(state, get_byte_zero_page(state)); break;
|
|
|
|
case ORA_ZPX: ORA(state, get_byte_zero_page_x(state)); break;
|
|
|
|
case ORA_ABS: ORA(state, get_byte_absolute(state)); break;
|
|
|
|
case ORA_ABSX: ORA(state, get_byte_absolute_x(state)); break;
|
|
|
|
case ORA_ABSY: ORA(state, get_byte_absolute_y(state)); break;
|
2019-04-14 19:25:23 +00:00
|
|
|
case ORA_INDX: ORA(state, get_byte_indirect_x(state)); break;
|
|
|
|
case ORA_INDY: ORA(state, get_byte_indirect_y(state)); break;
|
2019-04-19 09:55:17 +00:00
|
|
|
case ROL_ACC: ROL_A(state); break;
|
|
|
|
case ROL_ZP: ROL_MEM(state, get_address_zero_page(state)); break;
|
|
|
|
case ROL_ZPX: ROL_MEM(state, get_address_zero_page_x(state)); break;
|
|
|
|
case ROL_ABS: ROL_MEM(state, get_address_absolute(state)); break;
|
|
|
|
case ROL_ABSX: ROL_MEM(state, get_address_absolute_x(state)); break;
|
2019-04-20 06:49:28 +00:00
|
|
|
case ROR_ACC: ROR_A(state); break;
|
|
|
|
case ROR_ZP: ROR_MEM(state, get_address_zero_page(state)); break;
|
|
|
|
case ROR_ZPX: ROR_MEM(state, get_address_zero_page_x(state)); break;
|
|
|
|
case ROR_ABS: ROR_MEM(state, get_address_absolute(state)); break;
|
|
|
|
case ROR_ABSX: ROR_MEM(state, get_address_absolute_x(state)); break;
|
2019-04-27 11:57:47 +00:00
|
|
|
case SBC_IMM: SBC(state, fetch_byte(state)); break;
|
2019-04-19 09:38:52 +00:00
|
|
|
case SBC_ZP: SBC(state, get_byte_zero_page(state)); break;
|
|
|
|
case SBC_ZPX: SBC(state, get_byte_zero_page_x(state)); break;
|
|
|
|
case SBC_ABS: SBC(state, get_byte_absolute(state)); break;
|
|
|
|
case SBC_ABSX: SBC(state, get_byte_absolute_x(state)); break;
|
|
|
|
case SBC_ABSY: SBC(state, get_byte_absolute_y(state)); break;
|
|
|
|
case SBC_INDX: SBC(state, get_byte_indirect_x(state)); break;
|
|
|
|
case SBC_INDY: SBC(state, get_byte_indirect_y(state)); break;
|
2019-04-15 22:09:55 +00:00
|
|
|
case STA_ZP: STA(state, get_address_zero_page(state)); break;
|
|
|
|
case STA_ZPX: STA(state, get_address_zero_page_x(state)); break;
|
|
|
|
case STA_ABS: STA(state, get_address_absolute(state)); break;
|
|
|
|
case STA_ABSX: STA(state, get_address_absolute_x(state)); break;
|
|
|
|
case STA_ABSY: STA(state, get_address_absolute_y(state)); break;
|
|
|
|
case STA_INDX: STA(state, get_address_indirect_x(state)); break;
|
|
|
|
case STA_INDY: STA(state, get_address_indirect_y(state)); break;
|
2019-04-14 21:05:37 +00:00
|
|
|
case STX_ZP: STX(state, get_address_zero_page(state)); break;
|
|
|
|
case STX_ZPY: STX(state, get_address_zero_page_y(state)); break;
|
|
|
|
case STX_ABS: STX(state, get_address_absolute(state)); break;
|
|
|
|
case STY_ZP: STY(state, get_address_zero_page(state)); break;
|
|
|
|
case STY_ZPX: STY(state, get_address_zero_page_x(state)); break;
|
|
|
|
case STY_ABS: STY(state, get_address_absolute(state)); break;
|
2019-04-14 13:15:15 +00:00
|
|
|
|
2019-04-13 21:59:48 +00:00
|
|
|
default:
|
|
|
|
unimplemented_instruction(state); break;
|
2019-04-13 20:00:37 +00:00
|
|
|
}
|
|
|
|
return 0;
|
2019-04-20 06:49:28 +00:00
|
|
|
}
|