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"
|
|
|
|
#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-13 23:51:50 +00:00
|
|
|
void set_NV_flags(State6502* state, byte value) {
|
|
|
|
//TODO implement V flag
|
|
|
|
if (value) {
|
|
|
|
state->flags.z = 0;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
state->flags.z = 1;
|
|
|
|
}
|
2019-04-13 21:59:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void clear_flags(State6502* state) {
|
2019-04-13 23:51:50 +00:00
|
|
|
memcpy(&state->flags, &state->a, 1);
|
2019-04-13 21:59:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void clear_state(State6502* state) {
|
|
|
|
state->a = 0;
|
|
|
|
state->x = 0;
|
|
|
|
state->y = 0;
|
|
|
|
state->pc = 0;
|
|
|
|
state->sp = 0;
|
|
|
|
clear_flags(state);
|
|
|
|
state->running = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
byte pop_byte(State6502* state) {
|
|
|
|
return state->memory[state->pc++];
|
|
|
|
}
|
|
|
|
|
|
|
|
//bitwise or with accumulator
|
|
|
|
void ORA(State6502 * state, byte operand) {
|
2019-04-13 23:51:50 +00:00
|
|
|
byte result = state->a | operand;
|
2019-04-13 21:59:48 +00:00
|
|
|
set_NV_flags(state, result);
|
2019-04-13 23:51:50 +00:00
|
|
|
state->a = result;
|
|
|
|
}
|
|
|
|
|
|
|
|
//load accumulator
|
2019-04-14 07:38:09 +00:00
|
|
|
void LDA(State6502 * state, byte operand) {
|
2019-04-13 23:51:50 +00:00
|
|
|
state->a = operand;
|
|
|
|
set_NV_flags(state, state->a);
|
|
|
|
}
|
|
|
|
|
|
|
|
word pop_word(State6502 * state) {
|
|
|
|
byte low = pop_byte(state);
|
|
|
|
byte high = pop_byte(state);
|
|
|
|
word result = (high << 8) | low;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2019-04-14 09:55:35 +00:00
|
|
|
word read_word(State6502 * state, word address) {
|
2019-04-14 09:49:24 +00:00
|
|
|
return state->memory[address] | state->memory[address + 1] << 8;
|
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-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
|
|
|
|
case NOP: break; //NOP
|
2019-04-14 08:57:25 +00:00
|
|
|
case ORA_INDX: //ORA, indirect, x
|
2019-04-14 07:38:09 +00:00
|
|
|
{
|
2019-04-14 13:08:29 +00:00
|
|
|
//pre-indexed indirect
|
|
|
|
//zero-page address is added to x register
|
|
|
|
byte indirect_address = pop_byte(state) + state->x;
|
|
|
|
//pointing to address of a word holding the address of the operand
|
|
|
|
word address = read_word(state, indirect_address);
|
2019-04-14 07:38:09 +00:00
|
|
|
ORA(state, state->memory[address]);
|
2019-04-13 21:59:48 +00:00
|
|
|
break;
|
2019-04-14 07:38:09 +00:00
|
|
|
}
|
2019-04-13 22:33:20 +00:00
|
|
|
case ORA_ZP: //ORA, zero page
|
2019-04-13 23:51:50 +00:00
|
|
|
{
|
|
|
|
byte address = pop_byte(state);
|
|
|
|
ORA(state, state->memory[address]);
|
2019-04-13 21:59:48 +00:00
|
|
|
break;
|
2019-04-13 23:51:50 +00:00
|
|
|
}
|
2019-04-14 08:57:25 +00:00
|
|
|
case ORA_INDY: //ORA, indirect, y (post_indexed)
|
2019-04-14 07:38:09 +00:00
|
|
|
{
|
2019-04-14 13:08:29 +00:00
|
|
|
//post-indexed indirect
|
|
|
|
//zero-page address as an argument
|
|
|
|
byte indirect_address = pop_byte(state);
|
|
|
|
//the address and the following byte is read as a word, adding Y register
|
|
|
|
word address = read_word(state, indirect_address) + state->y;
|
2019-04-14 07:38:09 +00:00
|
|
|
ORA(state, state->memory[address]);
|
2019-04-13 23:51:50 +00:00
|
|
|
break;
|
2019-04-14 07:38:09 +00:00
|
|
|
}
|
2019-04-13 23:51:50 +00:00
|
|
|
case ORA_IMM:
|
|
|
|
ORA(state, pop_byte(state));
|
|
|
|
break;
|
2019-04-14 08:57:25 +00:00
|
|
|
case ORA_ZPX:
|
2019-04-13 23:51:50 +00:00
|
|
|
{
|
|
|
|
byte address = pop_byte(state) + state->x;
|
|
|
|
ORA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ORA_ABS:
|
|
|
|
{
|
|
|
|
word address = pop_word(state);
|
|
|
|
ORA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
2019-04-14 08:57:25 +00:00
|
|
|
case ORA_ABSX:
|
2019-04-13 23:51:50 +00:00
|
|
|
{
|
|
|
|
word address = pop_word(state) + state->x;
|
|
|
|
ORA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
2019-04-14 08:57:25 +00:00
|
|
|
case ORA_ABSY:
|
2019-04-13 23:51:50 +00:00
|
|
|
{
|
|
|
|
word address = pop_word(state) + state->y;
|
|
|
|
ORA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LDA_IMM:
|
|
|
|
{
|
2019-04-14 07:38:09 +00:00
|
|
|
LDA(state, pop_byte(state));
|
2019-04-13 23:51:50 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-04-14 08:57:25 +00:00
|
|
|
case LDA_ZP:
|
|
|
|
{
|
|
|
|
byte address = pop_byte(state);
|
|
|
|
LDA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LDA_ZPX:
|
|
|
|
{
|
|
|
|
byte address = pop_byte(state) + state->x;
|
|
|
|
LDA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LDA_ABS:
|
|
|
|
{
|
|
|
|
word address = pop_word(state);
|
|
|
|
LDA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LDA_ABSX:
|
|
|
|
{
|
|
|
|
word address = pop_word(state) + state->x;
|
|
|
|
LDA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LDA_ABSY:
|
|
|
|
{
|
|
|
|
word address = pop_word(state) + state->y;
|
|
|
|
LDA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case LDA_INDX:
|
|
|
|
{
|
2019-04-14 09:49:24 +00:00
|
|
|
//pre-indexed indirect
|
|
|
|
//zero-page address is added to x register
|
|
|
|
byte indirect_address = pop_byte(state) + state->x;
|
|
|
|
//pointing to address of a word holding the address of the operand
|
2019-04-14 09:55:35 +00:00
|
|
|
word address = read_word(state, indirect_address);
|
2019-04-14 09:49:24 +00:00
|
|
|
LDA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
2019-04-14 08:57:25 +00:00
|
|
|
case LDA_INDY:
|
2019-04-14 09:49:24 +00:00
|
|
|
{
|
|
|
|
//post-indexed indirect
|
2019-04-14 10:39:56 +00:00
|
|
|
//zero-page address as an argument
|
2019-04-14 09:49:24 +00:00
|
|
|
byte indirect_address = pop_byte(state);
|
2019-04-14 10:39:56 +00:00
|
|
|
//the address and the following byte is read as a word, adding Y register
|
2019-04-14 09:55:35 +00:00
|
|
|
word address = read_word(state, indirect_address) + state->y;
|
2019-04-14 09:49:24 +00:00
|
|
|
LDA(state, state->memory[address]);
|
|
|
|
break;
|
|
|
|
}
|
2019-04-13 21:59:48 +00:00
|
|
|
default:
|
|
|
|
unimplemented_instruction(state); break;
|
2019-04-13 20:00:37 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|