This commit is contained in:
william 2024-01-09 15:56:54 -05:00
parent 4a44443dc7
commit f4279467e8
11 changed files with 608 additions and 522 deletions

View File

@ -25,11 +25,16 @@
</configurations> </configurations>
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="0c3b231e-0637-4ac1-8964-c60fc9e9e691" name="Changes" comment="Memory debugger"> <list default="true" id="0c3b231e-0637-4ac1-8964-c60fc9e9e691" name="Changes" comment="Finished read-only memory debugger">
<change afterPath="$PROJECT_DIR$/cpu/decoding.c" afterDir="false" />
<change afterPath="$PROJECT_DIR$/cpu/decoding.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" /> <change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cpu/CMakeLists.txt" beforeDir="false" afterPath="$PROJECT_DIR$/cpu/CMakeLists.txt" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cpu/cpu.c" beforeDir="false" afterPath="$PROJECT_DIR$/cpu/cpu.c" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cpu/cpu.h" beforeDir="false" afterPath="$PROJECT_DIR$/cpu/cpu.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cpu/op.c" beforeDir="false" afterPath="$PROJECT_DIR$/cpu/op.c" afterDir="false" />
<change beforePath="$PROJECT_DIR$/cpu/op.h" beforeDir="false" afterPath="$PROJECT_DIR$/cpu/op.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/debugger/debugger.c" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/debugger.c" afterDir="false" /> <change beforePath="$PROJECT_DIR$/debugger/debugger.c" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/debugger.c" afterDir="false" />
<change beforePath="$PROJECT_DIR$/debugger/dialog.c" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/dialog.c" afterDir="false" />
<change beforePath="$PROJECT_DIR$/debugger/dialog.h" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/dialog.h" afterDir="false" />
<change beforePath="$PROJECT_DIR$/debugger/memory_view.c" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/memory_view.c" afterDir="false" /> <change beforePath="$PROJECT_DIR$/debugger/memory_view.c" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/memory_view.c" afterDir="false" />
<change beforePath="$PROJECT_DIR$/debugger/memory_view.h" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/memory_view.h" afterDir="false" /> <change beforePath="$PROJECT_DIR$/debugger/memory_view.h" beforeDir="false" afterPath="$PROJECT_DIR$/debugger/memory_view.h" afterDir="false" />
</list> </list>
@ -456,7 +461,7 @@
<workItem from="1704501418104" duration="8204000" /> <workItem from="1704501418104" duration="8204000" />
<workItem from="1704569084127" duration="8903000" /> <workItem from="1704569084127" duration="8903000" />
<workItem from="1704582152049" duration="7863000" /> <workItem from="1704582152049" duration="7863000" />
<workItem from="1704660072645" duration="15399000" /> <workItem from="1704660072645" duration="19497000" />
</task> </task>
<task id="LOCAL-00001" summary="Cpu opcodes implementation"> <task id="LOCAL-00001" summary="Cpu opcodes implementation">
<option name="closed" value="true" /> <option name="closed" value="true" />
@ -498,7 +503,15 @@
<option name="project" value="LOCAL" /> <option name="project" value="LOCAL" />
<updated>1704662439962</updated> <updated>1704662439962</updated>
</task> </task>
<option name="localTasksCounter" value="6" /> <task id="LOCAL-00006" summary="Finished read-only memory debugger">
<option name="closed" value="true" />
<created>1704829582042</created>
<option name="number" value="00006" />
<option name="presentableId" value="LOCAL-00006" />
<option name="project" value="LOCAL" />
<updated>1704829582042</updated>
</task>
<option name="localTasksCounter" value="7" />
<servers /> <servers />
</component> </component>
<component name="TypeScriptGeneratedFilesManager"> <component name="TypeScriptGeneratedFilesManager">
@ -517,7 +530,8 @@
<MESSAGE value="Added logging for operand decoding" /> <MESSAGE value="Added logging for operand decoding" />
<MESSAGE value="Things" /> <MESSAGE value="Things" />
<MESSAGE value="Memory debugger" /> <MESSAGE value="Memory debugger" />
<option name="LAST_COMMIT_MESSAGE" value="Memory debugger" /> <MESSAGE value="Finished read-only memory debugger" />
<option name="LAST_COMMIT_MESSAGE" value="Finished read-only memory debugger" />
</component> </component>
<component name="XDebuggerManager"> <component name="XDebuggerManager">
<breakpoint-manager> <breakpoint-manager>

View File

@ -2,7 +2,9 @@ add_library(CPU
cpu.c cpu.c
op.c op.c
memory.c memory.c
cpu.h) cpu.h
decoding.c
decoding.h)
find_package(log.c) find_package(log.c)
target_link_libraries(CPU log.c::log.c) target_link_libraries(CPU log.c::log.c)

View File

@ -5,6 +5,7 @@
#include "cpu.h" #include "cpu.h"
#include "memory.h" #include "memory.h"
#include "op.h" #include "op.h"
#include "decoding.h"
/* /*
* ===================================================================================== * =====================================================================================
@ -138,15 +139,4 @@ void cpu_stack_pop_context(System *system) {
address pc = cpu_stack_pop(system) << 8; address pc = cpu_stack_pop(system) << 8;
pc += lo; pc += lo;
system->cpu.program_counter = pc; system->cpu.program_counter = pc;
}
char *operand_name(Operand *operand) {
switch (operand->type) {
case OPERAND_TYPE_ACCUMULATOR:
return "Accumulator";
case OPERAND_TYPE_IMMEDIATE:
return "Immediate";
case OPERAND_TYPE_ADDRESS:
return "Address";
}
} }

View File

@ -19,25 +19,13 @@
#define CPU_STACK_ADDR 0x0100 #define CPU_STACK_ADDR 0x0100
enum OperandType {
OPERAND_TYPE_ACCUMULATOR,
OPERAND_TYPE_IMMEDIATE,
OPERAND_TYPE_ADDRESS
};
typedef struct {
word value;
enum OperandType type;
bool is_page_crossing;
} Operand;
/** /**
* Gets the name of the type of an operand, for logging. * Gets the name of the type of an operand, for logging.
* *
* @param operand The operand * @param operand The operand
* @return The name of the operand's type. * @return The name of the operand's type.
*/ */
char *operand_name(Operand *operand); //char *operand_name(Operand *operand);
/** /**
* Gets a flag from the CPU registers. * Gets a flag from the CPU registers.

482
cpu/decoding.c Normal file
View File

@ -0,0 +1,482 @@
//
// Created by william on 1/9/24.
//
#include "decoding.h"
#include <assert.h>
#include <log.h>
address decode_operand_addr(System *system, AddressingMode addr_mode, bool *page_crossing) {
CPU registers = system->cpu;
address operand_addr;
if (addr_mode == ADDR_MODE_ZERO_PAGE) {
operand_addr = cpu_get_next_byte(system);
} else if (addr_mode == ADDR_MODE_ZERO_PAGE_INDEXED_X) {
operand_addr = (cpu_get_next_byte(system) + registers.x) & 0xff;
} else if (addr_mode == ADDR_MODE_ZERO_PAGE_INDEXED_Y) {
operand_addr = (cpu_get_next_byte(system) + registers.y) & 0xff;
} else if (addr_mode == ADDR_MODE_ABSOLUTE) {
operand_addr = cpu_get_next_word(system);
} else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_X) {
word addr = cpu_get_next_word(system);
word new_addr = addr + registers.x;
*page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
operand_addr = new_addr;
} else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_Y) {
word addr = cpu_get_next_word(system);
word new_addr = addr + registers.y;
*page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
operand_addr = new_addr;
} else if (addr_mode == ADDR_MODE_INDIRECT_JUMP) {
word addr = cpu_get_next_word(system);
if ((addr & 0xff) == 0xff) {
// Error in NES CPU for JMP op
word result = mem_get_byte(system, addr);
result += mem_get_byte(system, addr & 0xff00) << 8;
operand_addr = result;
} else {
operand_addr = mem_get_word(system, addr);
}
} else if (addr_mode == ADDR_MODE_INDIRECT_X) {
byte arg_addr = cpu_get_next_byte(system);
word addr = mem_get_byte(system, (arg_addr + system->cpu.x) & 0xff);
addr += mem_get_byte(system, (arg_addr + system->cpu.x + 1) & 0xff) << 8;
operand_addr = addr;
} else if (addr_mode == ADDR_MODE_INDIRECT_Y) {
byte arg_addr = cpu_get_next_byte(system);
word addr = mem_get_byte(system, arg_addr) + (mem_get_byte(system, (arg_addr + 1) & 0xff) << 8);
word new_addr = addr + registers.y;
*page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
operand_addr = new_addr;
} else {
assert(false);
}
log_trace("Operand address: %#02x, Addressing mode: %s", operand_addr, get_addr_mode_name(addr_mode));
return operand_addr;
}
Operand decode_operand(System *system, AddressingMode addr_mode) {
Operand operand;
if (addr_mode == ADDR_MODE_ACCUMULATOR) {
operand.type = OPERAND_TYPE_ACCUMULATOR;
operand.value = 0;
operand.is_page_crossing = false;
} else if (addr_mode == ADDR_MODE_IMMEDIATE) {
operand.type = OPERAND_TYPE_IMMEDIATE;
operand.value = cpu_get_next_byte(system);
operand.is_page_crossing = false;
} else {
operand.type = OPERAND_TYPE_ADDRESS;
operand.value = decode_operand_addr(system, addr_mode, &operand.is_page_crossing);
}
log_trace("Operand type: %s, value: %#02x", operand_name(&operand), operand.value);
return operand;
}
byte read_operand(System *system, Operand operand) {
switch (operand.type) {
case OPERAND_TYPE_ACCUMULATOR:
return system->cpu.accumulator;
case OPERAND_TYPE_IMMEDIATE:
return (byte) operand.value;
case OPERAND_TYPE_ADDRESS:
return mem_get_byte(system, operand.value);
default:
assert(false);
}
}
char *get_addr_mode_name(AddressingMode addr_mode) {
switch (addr_mode) {
case ADDR_MODE_ABSOLUTE:
return "a";
case ADDR_MODE_ABSOLUTE_INDEXED_X:
return "a,x";
case ADDR_MODE_ABSOLUTE_INDEXED_Y:
return "a,y";
case ADDR_MODE_ACCUMULATOR:
return "A";
case ADDR_MODE_IMMEDIATE:
return "#";
case ADDR_MODE_IMPLICIT:
return " ";
case ADDR_MODE_INDIRECT_X:
return "(d,x)";
case ADDR_MODE_INDIRECT_Y:
return "(d,y)";
case ADDR_MODE_INDIRECT_JUMP:
return "(a)";
case ADDR_MODE_RELATIVE:
return "label";
case ADDR_MODE_ZERO_PAGE:
return "d";
case ADDR_MODE_ZERO_PAGE_INDEXED_X:
return "d,x";
case ADDR_MODE_ZERO_PAGE_INDEXED_Y:
return "d,y";
}
}
char *operand_name(Operand *operand) {
switch (operand->type) {
case OPERAND_TYPE_ACCUMULATOR:
return "Accumulator";
case OPERAND_TYPE_IMMEDIATE:
return "Immediate";
case OPERAND_TYPE_ADDRESS:
return "Address";
}
}
char *get_op_code_name(byte op) {
switch (op) {
case 0x00:
return "BRK";
case 0x08:
return "PHP";
case 0x0b:
case 0x2b:
return "ANC";
case 0x10:
return "BPL";
case 0x18:
return "CLC";
case 0x20:
return "JSR";
case 0x24:
case 0x2c:
return "BIT";
case 0x28:
return "PLP";
case 0x30:
return "BMI";
case 0x38:
return "SEC";
case 0x40:
return "RTI";
case 0x48:
return "PHA";
case 0x4c:
case 0x6c:
return "JMP";
case 0x50:
return "BVC";
case 0x58:
return "CLI";
case 0x60:
return "RTS";
case 0x68:
return "PLA";
case 0x70:
return "BVS";
case 0x78:
return "SEI";
case 0x84:
case 0x8c:
case 0x94:
return "STY";
case 0x88:
return "DEY";
case 0x90:
return "BCC";
case 0x98:
return "TYA";
case 0x9c:
return "SHY";
case 0xa0:
case 0xa4:
case 0xac:
case 0xb4:
case 0xbc:
return "LDY";
case 0xa8:
return "TAY";
case 0xb0:
return "BCS";
case 0xb8:
return "CLV";
case 0xc0:
case 0xc4:
case 0xcc:
return "CPY";
case 0xc8:
return "INY";
case 0xd0:
return "BNE";
case 0xd8:
return "CLD";
case 0xe0:
case 0xe4:
case 0xec:
return "CPX";
case 0xe8:
return "INX";
case 0xf0:
return "BEQ";
case 0xf8:
return "SED";
case 0x01:
case 0x05:
case 0x09:
case 0x0d:
case 0x11:
case 0x15:
case 0x19:
case 0x1d:
return "ORA";
case 0x21:
case 0x25:
case 0x29:
case 0x2d:
case 0x31:
case 0x35:
case 0x39:
case 0x3d:
return "AND";
case 0x41:
case 0x45:
case 0x49:
case 0x4d:
case 0x51:
case 0x55:
case 0x59:
case 0x5d:
return "EOR";
case 0x61:
case 0x65:
case 0x69:
case 0x6d:
case 0x71:
case 0x75:
case 0x79:
case 0x7d:
return "ADC";
case 0x81:
case 0x85:
case 0x8d:
case 0x91:
case 0x95:
case 0x99:
case 0x9d:
return "STA";
case 0xa1:
case 0xa5:
case 0xa9:
case 0xad:
case 0xb1:
case 0xb5:
case 0xb9:
case 0xbd:
return "LDA";
case 0xc1:
case 0xc5:
case 0xc9:
case 0xcd:
case 0xd1:
case 0xd5:
case 0xd9:
case 0xdd:
return "CMP";
case 0xe1:
case 0xe5:
case 0xe9:
case 0xed:
case 0xf1:
case 0xf5:
case 0xf9:
case 0xfd:
return "SBC";
case 0x03:
case 0x07:
case 0x0f:
case 0x13:
case 0x17:
case 0x1b:
case 0x1f:
return "SLO";
case 0x23:
case 0x27:
case 0x2f:
case 0x33:
case 0x37:
case 0x3b:
case 0x3f:
return "RLA";
case 0x43:
case 0x47:
case 0x4f:
case 0x53:
case 0x57:
case 0x5b:
case 0x5f:
return "SRE";
case 0x4b:
return "ALR";
case 0x63:
case 0x67:
case 0x6f:
case 0x73:
case 0x77:
case 0x7b:
case 0x7f:
return "RRA";
case 0x6b:
return "ARR";
case 0x83:
case 0x87:
case 0x8f:
case 0x97:
return "SAX";
case 0x8b:
return "XAA";
case 0x93:
case 0x9f:
return "AHX";
case 0x9b:
return "TAS";
case 0xa3:
case 0xa7:
case 0xab:
case 0xaf:
case 0xb3:
case 0xb7:
case 0xbb:
case 0xbf:
return "LAX";
case 0xc3:
case 0xc7:
case 0xcf:
case 0xd3:
case 0xd7:
case 0xdb:
case 0xdf:
return "DCP";
case 0xcb:
return "AXS";
case 0xe3:
case 0xe7:
case 0xef:
case 0xf3:
case 0xf7:
case 0xfb:
case 0xff:
return "ISC";
case 0xeb:
return "SBC";
case 0x06:
case 0x0a:
case 0x0e:
case 0x16:
case 0x1e:
return "ASL";
case 0x26:
case 0x2a:
case 0x2e:
case 0x36:
case 0x3e:
return "ROL";
case 0x46:
case 0x4a:
case 0x4e:
case 0x56:
case 0x5e:
return "LSR";
case 0x66:
case 0x6a:
case 0x6e:
case 0x76:
case 0x7e:
return "ROR";
case 0x86:
case 0x8e:
case 0x96:
return "STX";
case 0x8a:
return "TXA";
case 0x9a:
case 0xba:
return "TSX";
case 0x9e:
return "SHX";
case 0xa2:
case 0xa6:
case 0xae:
case 0xb6:
case 0xbe:
return "LDX";
case 0xaa:
return "TAX";
case 0xc6:
case 0xca:
case 0xce:
case 0xd6:
case 0xde:
return "DEC";
case 0xe6:
case 0xee:
case 0xf6:
case 0xfe:
return "INC";
case 0x02:
case 0x12:
case 0x22:
case 0x32:
case 0x42:
case 0x52:
case 0x62:
case 0x72:
case 0x92:
case 0xb2:
case 0xd2:
case 0xf2:
return "STP";
case 0x04:
case 0x0c:
case 0x14:
case 0x1c:
case 0x1a:
case 0x34:
case 0x3a:
case 0x3c:
case 0x44:
case 0x54:
case 0x5a:
case 0x5c:
case 0x64:
case 0x74:
case 0x7a:
case 0x7c:
case 0x80:
case 0x82:
case 0x89:
case 0xc2:
case 0xd4:
case 0xda:
case 0xdc:
case 0xe2:
case 0xea:
case 0xf4:
case 0xfa:
case 0xfc:
return "NOP";
default:
assert(false);
}
}

52
cpu/decoding.h Normal file
View File

@ -0,0 +1,52 @@
//
// Created by william on 1/9/24.
//
#ifndef NESEMULATOR_DECODING_H
#define NESEMULATOR_DECODING_H
#include "../include/types.h"
#include "../include/system.h"
#include "cpu.h"
typedef enum {
ADDR_MODE_ABSOLUTE, // a
ADDR_MODE_ABSOLUTE_INDEXED_X, // a,x
ADDR_MODE_ABSOLUTE_INDEXED_Y, // a,y
ADDR_MODE_ACCUMULATOR, // A
ADDR_MODE_IMMEDIATE, // #i
ADDR_MODE_IMPLICIT, // Imp
ADDR_MODE_INDIRECT_X, // (d,x)
ADDR_MODE_INDIRECT_JUMP, //
ADDR_MODE_INDIRECT_Y, // (d),y
ADDR_MODE_RELATIVE, // label
ADDR_MODE_ZERO_PAGE, // d
ADDR_MODE_ZERO_PAGE_INDEXED_X, // d,x
ADDR_MODE_ZERO_PAGE_INDEXED_Y, // d,y
} AddressingMode;
enum OperandType {
OPERAND_TYPE_ACCUMULATOR,
OPERAND_TYPE_IMMEDIATE,
OPERAND_TYPE_ADDRESS
};
typedef struct {
word value;
enum OperandType type;
bool is_page_crossing;
} Operand;
address decode_operand_addr(System *system, AddressingMode addr_mode, bool *page_crossing);
Operand decode_operand(System *system, AddressingMode addr_mode);
byte read_operand(System *system, Operand operand);
char *get_addr_mode_name(AddressingMode addr_mode);
char *operand_name(Operand *operand);
char *get_op_code_name(byte op);
#endif //NESEMULATOR_DECODING_H

466
cpu/op.c
View File

@ -4,6 +4,7 @@
#include "op.h" #include "op.h"
#include "cpu.h" #include "cpu.h"
#include "decoding.h"
// Reference: https://www.nesdev.org/wiki/CPU_unofficial_opcodes // Reference: https://www.nesdev.org/wiki/CPU_unofficial_opcodes
// https://www.middle-engine.com/blog/posts/2020/06/23/programming-the-nes-the-6502-in-detail // https://www.middle-engine.com/blog/posts/2020/06/23/programming-the-nes-the-6502-in-detail
@ -60,130 +61,6 @@
IS_UNOFFICIAL_OP_CODE_(op, line, 0x1b, ABSOLUTE_INDEXED_Y) \ IS_UNOFFICIAL_OP_CODE_(op, line, 0x1b, ABSOLUTE_INDEXED_Y) \
IS_UNOFFICIAL_OP_CODE_(op, line, 0x1f, ABSOLUTE_INDEXED_X) IS_UNOFFICIAL_OP_CODE_(op, line, 0x1f, ABSOLUTE_INDEXED_X)
char *addr_mode_name(AddressingMode addr_mode) {
switch (addr_mode) {
case ADDR_MODE_ABSOLUTE:
return "Absolute";
case ADDR_MODE_ABSOLUTE_JUMP:
return "Absolute Jump";
case ADDR_MODE_ABSOLUTE_INDEXED_X:
return "Absolute Indexed X";
case ADDR_MODE_ABSOLUTE_INDEXED_Y:
return "Absolute Indexed Y";
case ADDR_MODE_ACCUMULATOR:
return "Accumulator";
case ADDR_MODE_IMMEDIATE:
return "Immediate";
case ADDR_MODE_IMPLICIT:
return "Implicit";
case ADDR_MODE_INDIRECT_X:
return "Indirect X";
case ADDR_MODE_INDIRECT_JUMP:
return "Indirect Jump";
case ADDR_MODE_INDIRECT_Y:
return "Indirect Y";
case ADDR_MODE_RELATIVE:
return "Relative";
case ADDR_MODE_ZERO_PAGE:
return "Zero Page";
case ADDR_MODE_ZERO_PAGE_INDEXED_X:
return "Zero Page X";
case ADDR_MODE_ZERO_PAGE_INDEXED_Y:
return "Zero Page Y";
}
}
address decode_operand_addr(System *system, AddressingMode addr_mode, bool *page_crossing) {
CPU registers = system->cpu;
address operand_addr;
if (addr_mode == ADDR_MODE_ZERO_PAGE) {
operand_addr = cpu_get_next_byte(system);
} else if (addr_mode == ADDR_MODE_ZERO_PAGE_INDEXED_X) {
operand_addr = (cpu_get_next_byte(system) + registers.x) & 0xff;
} else if (addr_mode == ADDR_MODE_ZERO_PAGE_INDEXED_Y) {
operand_addr = (cpu_get_next_byte(system) + registers.y) & 0xff;
} else if (addr_mode == ADDR_MODE_ABSOLUTE || addr_mode == ADDR_MODE_ABSOLUTE_JUMP) {
operand_addr = cpu_get_next_word(system);
} else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_X) {
word addr = cpu_get_next_word(system);
word new_addr = addr + registers.x;
*page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
operand_addr = new_addr;
} else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_Y) {
word addr = cpu_get_next_word(system);
word new_addr = addr + registers.y;
*page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
operand_addr = new_addr;
} else if (addr_mode == ADDR_MODE_INDIRECT_JUMP) {
word addr = cpu_get_next_word(system);
if ((addr & 0xff) == 0xff) {
// Error in NES CPU for JMP op
word result = mem_get_byte(system, addr);
result += mem_get_byte(system, addr & 0xff00) << 8;
operand_addr = result;
} else {
operand_addr = mem_get_word(system, addr);
}
} else if (addr_mode == ADDR_MODE_INDIRECT_X) {
byte arg_addr = cpu_get_next_byte(system);
word addr = mem_get_byte(system, (arg_addr + system->cpu.x) & 0xff);
addr += mem_get_byte(system, (arg_addr + system->cpu.x + 1) & 0xff) << 8;
operand_addr = addr;
} else if (addr_mode == ADDR_MODE_INDIRECT_Y) {
byte arg_addr = cpu_get_next_byte(system);
word addr = mem_get_byte(system, arg_addr) + (mem_get_byte(system, (arg_addr + 1) & 0xff) << 8);
word new_addr = addr + registers.y;
*page_crossing = (addr & 0xff00) != (new_addr & 0xff00);
operand_addr = new_addr;
} else {
assert(false);
}
log_trace("Operand address: %#02x, Addressing mode: %s", operand_addr, addr_mode_name(addr_mode));
return operand_addr;
}
Operand decode_operand(System *system, AddressingMode addr_mode) {
Operand operand;
if (addr_mode == ADDR_MODE_ACCUMULATOR) {
operand.type = OPERAND_TYPE_ACCUMULATOR;
operand.value = 0;
operand.is_page_crossing = false;
} else if (addr_mode == ADDR_MODE_IMMEDIATE) {
operand.type = OPERAND_TYPE_IMMEDIATE;
operand.value = cpu_get_next_byte(system);
operand.is_page_crossing = false;
} else {
operand.type = OPERAND_TYPE_ADDRESS;
operand.value = decode_operand_addr(system, addr_mode, &operand.is_page_crossing);
}
log_trace("Operand type: %s, value: %#02x", operand_name(&operand), operand.value);
return operand;
}
byte read_operand(System *system, Operand operand) {
switch (operand.type) {
case OPERAND_TYPE_ACCUMULATOR:
return system->cpu.accumulator;
case OPERAND_TYPE_IMMEDIATE:
return (byte) operand.value;
case OPERAND_TYPE_ADDRESS:
return mem_get_byte(system, operand.value);
default:
assert(false);
}
}
void write_operand(System *system, Operand operand, byte value) { void write_operand(System *system, Operand operand, byte value) {
switch (operand.type) { switch (operand.type) {
case OPERAND_TYPE_ACCUMULATOR: case OPERAND_TYPE_ACCUMULATOR:
@ -1226,347 +1103,6 @@ void process_op_code(System *system, byte op) {
IS_OP_CODE_MODE(LAS, 0xbb, ABSOLUTE_INDEXED_Y) IS_OP_CODE_MODE(LAS, 0xbb, ABSOLUTE_INDEXED_Y)
IS_OP_CODE_MODE(LAX, 0xbf, ABSOLUTE_INDEXED_Y) IS_OP_CODE_MODE(LAX, 0xbf, ABSOLUTE_INDEXED_Y)
default:
assert(false);
}
}
char *get_op_code_name(byte op) {
switch (op) {
case 0x00:
return "BRK";
case 0x08:
return "PHP";
case 0x0b:
case 0x2b:
return "ANC";
case 0x10:
return "BPL";
case 0x18:
return "CLC";
case 0x20:
return "JSR";
case 0x24:
case 0x2c:
return "BIT";
case 0x28:
return "PLP";
case 0x30:
return "BMI";
case 0x38:
return "SEC";
case 0x40:
return "RTI";
case 0x48:
return "PHA";
case 0x4c:
case 0x6c:
return "JMP";
case 0x50:
return "BVC";
case 0x58:
return "CLI";
case 0x60:
return "RTS";
case 0x68:
return "PLA";
case 0x70:
return "BVS";
case 0x78:
return "SEI";
case 0x84:
case 0x8c:
case 0x94:
return "STY";
case 0x88:
return "DEY";
case 0x90:
return "BCC";
case 0x98:
return "TYA";
case 0x9c:
return "SHY";
case 0xa0:
case 0xa4:
case 0xac:
case 0xb4:
case 0xbc:
return "LDY";
case 0xa8:
return "TAY";
case 0xb0:
return "BCS";
case 0xb8:
return "CLV";
case 0xc0:
case 0xc4:
case 0xcc:
return "CPY";
case 0xc8:
return "INY";
case 0xd0:
return "BNE";
case 0xd8:
return "CLD";
case 0xe0:
case 0xe4:
case 0xec:
return "CPX";
case 0xe8:
return "INX";
case 0xf0:
return "BEQ";
case 0xf8:
return "SED";
case 0x01:
case 0x05:
case 0x09:
case 0x0d:
case 0x11:
case 0x15:
case 0x19:
case 0x1d:
return "ORA";
case 0x21:
case 0x25:
case 0x29:
case 0x2d:
case 0x31:
case 0x35:
case 0x39:
case 0x3d:
return "AND";
case 0x41:
case 0x45:
case 0x49:
case 0x4d:
case 0x51:
case 0x55:
case 0x59:
case 0x5d:
return "EOR";
case 0x61:
case 0x65:
case 0x69:
case 0x6d:
case 0x71:
case 0x75:
case 0x79:
case 0x7d:
return "ADC";
case 0x81:
case 0x85:
case 0x8d:
case 0x91:
case 0x95:
case 0x99:
case 0x9d:
return "STA";
case 0xa1:
case 0xa5:
case 0xa9:
case 0xad:
case 0xb1:
case 0xb5:
case 0xb9:
case 0xbd:
return "LDA";
case 0xc1:
case 0xc5:
case 0xc9:
case 0xcd:
case 0xd1:
case 0xd5:
case 0xd9:
case 0xdd:
return "CMP";
case 0xe1:
case 0xe5:
case 0xe9:
case 0xed:
case 0xf1:
case 0xf5:
case 0xf9:
case 0xfd:
return "SBC";
case 0x03:
case 0x07:
case 0x0f:
case 0x13:
case 0x17:
case 0x1b:
case 0x1f:
return "SLO";
case 0x23:
case 0x27:
case 0x2f:
case 0x33:
case 0x37:
case 0x3b:
case 0x3f:
return "RLA";
case 0x43:
case 0x47:
case 0x4f:
case 0x53:
case 0x57:
case 0x5b:
case 0x5f:
return "SRE";
case 0x4b:
return "ALR";
case 0x63:
case 0x67:
case 0x6f:
case 0x73:
case 0x77:
case 0x7b:
case 0x7f:
return "RRA";
case 0x6b:
return "ARR";
case 0x83:
case 0x87:
case 0x8f:
case 0x97:
return "SAX";
case 0x8b:
return "XAA";
case 0x93:
case 0x9f:
return "AHX";
case 0x9b:
return "TAS";
case 0xa3:
case 0xa7:
case 0xab:
case 0xaf:
case 0xb3:
case 0xb7:
case 0xbb:
case 0xbf:
return "LAX";
case 0xc3:
case 0xc7:
case 0xcf:
case 0xd3:
case 0xd7:
case 0xdb:
case 0xdf:
return "DCP";
case 0xcb:
return "AXS";
case 0xe3:
case 0xe7:
case 0xef:
case 0xf3:
case 0xf7:
case 0xfb:
case 0xff:
return "ISC";
case 0xeb:
return "SBC";
case 0x06:
case 0x0a:
case 0x0e:
case 0x16:
case 0x1e:
return "ASL";
case 0x26:
case 0x2a:
case 0x2e:
case 0x36:
case 0x3e:
return "ROL";
case 0x46:
case 0x4a:
case 0x4e:
case 0x56:
case 0x5e:
return "LSR";
case 0x66:
case 0x6a:
case 0x6e:
case 0x76:
case 0x7e:
return "ROR";
case 0x86:
case 0x8e:
case 0x96:
return "STX";
case 0x8a:
return "TXA";
case 0x9a:
case 0xba:
return "TSX";
case 0x9e:
return "SHX";
case 0xa2:
case 0xa6:
case 0xae:
case 0xb6:
case 0xbe:
return "LDX";
case 0xaa:
return "TAX";
case 0xc6:
case 0xca:
case 0xce:
case 0xd6:
case 0xde:
return "DEC";
case 0xe6:
case 0xee:
case 0xf6:
case 0xfe:
return "INC";
case 0x02:
case 0x12:
case 0x22:
case 0x32:
case 0x42:
case 0x52:
case 0x62:
case 0x72:
case 0x92:
case 0xb2:
case 0xd2:
case 0xf2:
return "STP";
case 0x04:
case 0x0c:
case 0x14:
case 0x1c:
case 0x1a:
case 0x34:
case 0x3a:
case 0x3c:
case 0x44:
case 0x54:
case 0x5a:
case 0x5c:
case 0x64:
case 0x74:
case 0x7a:
case 0x7c:
case 0x80:
case 0x82:
case 0x89:
case 0xc2:
case 0xd4:
case 0xda:
case 0xdc:
case 0xe2:
case 0xea:
case 0xf4:
case 0xfa:
case 0xfc:
return "NOP";
default: default:
assert(false); assert(false);
} }

View File

@ -16,24 +16,6 @@ enum op_code_base {
OP_CODE_BASE_SBC = 0xe0 OP_CODE_BASE_SBC = 0xe0
}; };
typedef enum {
ADDR_MODE_ABSOLUTE, // a
ADDR_MODE_ABSOLUTE_JUMP, // (a)
ADDR_MODE_ABSOLUTE_INDEXED_X, // a,x
ADDR_MODE_ABSOLUTE_INDEXED_Y, // a,y
ADDR_MODE_ACCUMULATOR, // A
ADDR_MODE_IMMEDIATE, // #i
ADDR_MODE_IMPLICIT, // Imp
ADDR_MODE_INDIRECT_X, // (d,x)
ADDR_MODE_INDIRECT_JUMP, //
ADDR_MODE_INDIRECT_Y, // (d),y
ADDR_MODE_RELATIVE, // label
ADDR_MODE_ZERO_PAGE, // d
ADDR_MODE_ZERO_PAGE_INDEXED_X, // d,x
ADDR_MODE_ZERO_PAGE_INDEXED_Y, // d,y
} AddressingMode;
void process_op_code(System *system, byte op); void process_op_code(System *system, byte op);
char* get_op_code_name(byte op);
#endif #endif

View File

@ -36,19 +36,19 @@ void start_debugger(System *system) {
int keycode; int keycode;
while ((keycode = getch()) != CTRL_KEY_EXIT) { while ((keycode = getch()) != CTRL_KEY_EXIT) {
if (keycode == KEY_UP) { if (keycode == KEY_UP) {
memory_view_move_cursor(&view, 0, -1); memory_view_move_cursor(&view, 0, MEMORY_VIEW_DIRECTION_DOWN);
} }
if (keycode == KEY_DOWN) { if (keycode == KEY_DOWN) {
memory_view_move_cursor(&view, 0, 1); memory_view_move_cursor(&view, 0, MEMORY_VIEW_DIRECTION_UP);
} }
if (keycode == KEY_LEFT) { if (keycode == KEY_LEFT) {
memory_view_move_cursor(&view, -1, 0); memory_view_move_cursor(&view, MEMORY_VIEW_DIRECTION_LEFT, 0);
} }
if (keycode == KEY_RIGHT) { if (keycode == KEY_RIGHT) {
memory_view_move_cursor(&view, 1, 0); memory_view_move_cursor(&view, MEMORY_VIEW_DIRECTION_RIGHT, 0);
} }
if (keycode == CTRL_KEY_G) { if (keycode == CTRL_KEY_G) {

View File

@ -93,13 +93,13 @@ void memory_view_scroll(MemoryView *view, char direction) {
} }
void memory_view_move_cursor(MemoryView *view, char horizontal, char vertical) { void memory_view_move_cursor(MemoryView *view, char horizontal, char vertical) {
if (horizontal == 1 && view->cursor_x == 0xf || if (horizontal == MEMORY_VIEW_DIRECTION_UP && view->cursor_x == 0xf ||
horizontal == -1 && view->cursor_x == 0) { horizontal == MEMORY_VIEW_DIRECTION_DOWN && view->cursor_x == 0) {
return; return;
} }
if (vertical == 1 && view->cursor_y == 0xf || if (vertical == MEMORY_VIEW_DIRECTION_RIGHT && view->cursor_y == 0xf ||
vertical == -1 && view->cursor_y == 0) { vertical == MEMORY_VIEW_DIRECTION_LEFT && view->cursor_y == 0) {
memory_view_scroll(view, vertical); memory_view_scroll(view, vertical);
return; return;
} }

View File

@ -16,6 +16,8 @@
#define MEMORY_VIEW_DIRECTION_UP 1 #define MEMORY_VIEW_DIRECTION_UP 1
#define MEMORY_VIEW_DIRECTION_DOWN (-1) #define MEMORY_VIEW_DIRECTION_DOWN (-1)
#define MEMORY_VIEW_DIRECTION_RIGHT 1
#define MEMORY_VIEW_DIRECTION_LEFT (-1)
typedef struct memory_view { typedef struct memory_view {
PANEL *panel; PANEL *panel;
@ -25,16 +27,54 @@ typedef struct memory_view {
char cursor_y; char cursor_y;
} MemoryView; } MemoryView;
/**
* Initializes a memory view for a system RAM.
* The viewer base address will be set to 0x0000, and the cursor (0, 0).
* The content of the memory will be printed on a new curses window.
* @param view A pointer to the view to initialize
* @param ram A pointer to the RAM
*/
void memory_view_init(MemoryView *view, ram ram); void memory_view_init(MemoryView *view, ram ram);
/**
* Prints the RAM content from the viewer base address.
*
* @param view
*/
void memory_view_print(MemoryView *view); void memory_view_print(MemoryView *view);
/**
* Sets the viewer base address to the target address page (the first byte) and prints the RAM.
*
* @param view
* @param target The target address to print
*/
void memory_view_goto(MemoryView *view, address target); void memory_view_goto(MemoryView *view, address target);
/**
* Scrolls the base address up or down by steps of 0x10.
*
* @param view
* @param direction The scroll direction
*/
void memory_view_scroll(MemoryView *view, char direction); void memory_view_scroll(MemoryView *view, char direction);
/**
* Moves the cursor up, down, right or left.
*
* @param view
* @param horizontal
* @param vertical
*/
void memory_view_move_cursor(MemoryView *view, char horizontal, char vertical); void memory_view_move_cursor(MemoryView *view, char horizontal, char vertical);
/**
* Moves the cursor to a specific memory address.
* The view will not be scrolled if the target address is not displayed.
*
* @param view
* @param target
*/
void memory_view_set_cursor_addr(MemoryView *view, address target); void memory_view_set_cursor_addr(MemoryView *view, address target);
#endif //NESEMULATOR_MEMORY_VIEW_H #endif //NESEMULATOR_MEMORY_VIEW_H