diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..15a528a --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +NESEmulator \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..79b3c94 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..118fe7c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/nes.iml b/.idea/nes.iml new file mode 100644 index 0000000..f08604b --- /dev/null +++ b/.idea/nes.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..4ce3320 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,164 @@ + + + + + { + "useNewFormat": true +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + "customColor": "", + "associatedIndex": 7 +} + + + + + + + { + "keyToString": { + "ASKED_ADD_EXTERNAL_FILES": "true", + "RunOnceActivity.OpenProjectViewOnStart": "true", + "RunOnceActivity.ShowReadmeOnStart": "true", + "RunOnceActivity.cidr.known.project.marker": "true", + "cf.first.check.clang-format": "false", + "cidr.known.project.marker": "true", + "com.jfrog.conanplugin.addconansupport": "true", + "com.jfrog.conanplugin.automanage.cmake.advanced.settings": "true", + "com.jfrog.conanplugin.conanexecutable": "conan", + "com.jfrog.conanplugin.hasbeensetup": "true", + "git-widget-placeholder": "master", + "last_opened_file_path": "/d/p/nes/CMakeLists.txt", + "node.js.detected.package.eslint": "true", + "node.js.detected.package.tslint": "true", + "node.js.selected.package.eslint": "(autodetect)", + "node.js.selected.package.tslint": "(autodetect)", + "settings.editor.selected.configurable": "preferences.pluginManager", + "vue.rearranger.settings.migration": "true" + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1696036979238 + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..fee3e08 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.10) +project(NESEmulator VERSION 0.1) + +add_subdirectory(cpu) +list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/cpu") + +add_executable(NESEmulator main.c) + +find_package(log.c) + +target_link_libraries(NESEmulator CPU log.c::log.c) +target_include_directories(NESEmulator PUBLIC + "${PROJECT_BINARY_DIR}" + ${EXTRA_INCLUDES}) diff --git a/Makefile b/Makefile deleted file mode 100644 index f26300a..0000000 --- a/Makefile +++ /dev/null @@ -1,30 +0,0 @@ -CC = gcc -BIN = ./bin -OBJ = ./obj -SRC = ./src - -SRCS = $(wildcard $(SRC)/*.c) -OBJS = $(patsubst $(SRC)/%.c,$(OBJ)/%.o,$(SRCS)) -EXE = $(BIN)/emu - -CFLAGS = -Wall -LDLIBS = -lm - -.PHONY: all run clean - -all: $(EXE) - -$(EXE): $(OBJS) | $(BIN) - $(CC) $(LDFLAGS) $^ -o $@ $(LDLIBS) - -$(OBJ)/%.o: $(SRC)/%.c | $(OBJ) - $(CC) $(CFLAGS) -c $< -o $@ - -$(BIN) $(OBJ): - mkdir $@ - -run: $(EXE) - $< - -clean: - rm -rf $(OBJ) $(BIN) diff --git a/conan_provider.cmake b/conan_provider.cmake new file mode 100644 index 0000000..166df6e --- /dev/null +++ b/conan_provider.cmake @@ -0,0 +1,548 @@ +# This file is managed by Conan, contents will be overwritten. +# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements + +set(CONAN_MINIMUM_VERSION 2.0.5) + + +function(detect_os OS OS_API_LEVEL OS_SDK OS_SUBSYSTEM OS_VERSION) + # it could be cross compilation + message(STATUS "CMake-Conan: cmake_system_name=${CMAKE_SYSTEM_NAME}") + if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic") + if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(${OS} Macos PARENT_SCOPE) + elseif(${CMAKE_SYSTEM_NAME} STREQUAL "QNX") + set(${OS} Neutrino PARENT_SCOPE) + elseif(${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN") + set(${OS} Windows PARENT_SCOPE) + set(${OS_SUBSYSTEM} cygwin PARENT_SCOPE) + elseif(${CMAKE_SYSTEM_NAME} MATCHES "^MSYS") + set(${OS} Windows PARENT_SCOPE) + set(${OS_SUBSYSTEM} msys2 PARENT_SCOPE) + else() + set(${OS} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE) + endif() + if(${CMAKE_SYSTEM_NAME} STREQUAL "Android") + string(REGEX MATCH "[0-9]+" _OS_API_LEVEL ${ANDROID_PLATFORM}) + message(STATUS "CMake-Conan: android_platform=${ANDROID_PLATFORM}") + set(${OS_API_LEVEL} ${_OS_API_LEVEL} PARENT_SCOPE) + endif() + if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS") + # CMAKE_OSX_SYSROOT contains the full path to the SDK for MakeFile/Ninja + # generators, but just has the original input string for Xcode. + if(NOT IS_DIRECTORY ${CMAKE_OSX_SYSROOT}) + set(_OS_SDK ${CMAKE_OSX_SYSROOT}) + else() + if(CMAKE_OSX_SYSROOT MATCHES Simulator) + set(apple_platform_suffix simulator) + else() + set(apple_platform_suffix os) + endif() + if(CMAKE_OSX_SYSROOT MATCHES AppleTV) + set(_OS_SDK "appletv${apple_platform_suffix}") + elseif(CMAKE_OSX_SYSROOT MATCHES iPhone) + set(_OS_SDK "iphone${apple_platform_suffix}") + elseif(CMAKE_OSX_SYSROOT MATCHES Watch) + set(_OS_SDK "watch${apple_platform_suffix}") + endif() + endif() + if(DEFINED _OS_SDK) + message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}") + set(${OS_SDK} ${_OS_SDK} PARENT_SCOPE) + endif() + if(DEFINED CMAKE_OSX_DEPLOYMENT_TARGET) + message(STATUS "CMake-Conan: cmake_osx_deployment_target=${CMAKE_OSX_DEPLOYMENT_TARGET}") + set(${OS_VERSION} ${CMAKE_OSX_DEPLOYMENT_TARGET} PARENT_SCOPE) + endif() + endif() + endif() +endfunction() + + +function(detect_arch ARCH) + # CMAKE_OSX_ARCHITECTURES can contain multiple architectures, but Conan only supports one. + # Therefore this code only finds one. If the recipes support multiple architectures, the + # build will work. Otherwise, there will be a linker error for the missing architecture(s). + if(DEFINED CMAKE_OSX_ARCHITECTURES) + string(REPLACE " " ";" apple_arch_list "${CMAKE_OSX_ARCHITECTURES}") + list(LENGTH apple_arch_list apple_arch_count) + if(apple_arch_count GREATER 1) + message(WARNING "CMake-Conan: Multiple architectures detected, this will only work if Conan recipe(s) produce fat binaries.") + endif() + endif() + if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64" OR CMAKE_OSX_ARCHITECTURES MATCHES arm64) + set(_ARCH armv8) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7-a|armv7l" OR CMAKE_OSX_ARCHITECTURES MATCHES armv7) + set(_ARCH armv7) + elseif(CMAKE_OSX_ARCHITECTURES MATCHES armv7s) + set(_ARCH armv7s) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686" OR CMAKE_OSX_ARCHITECTURES MATCHES i386) + set(_ARCH x86) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|amd64|x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES x86_64) + set(_ARCH x86_64) + endif() + message(STATUS "CMake-Conan: cmake_system_processor=${_ARCH}") + set(${ARCH} ${_ARCH} PARENT_SCOPE) +endfunction() + + +function(detect_cxx_standard CXX_STANDARD) + set(${CXX_STANDARD} ${CMAKE_CXX_STANDARD} PARENT_SCOPE) + if(CMAKE_CXX_EXTENSIONS) + set(${CXX_STANDARD} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE) + endif() +endfunction() + +macro(detect_gnu_libstdcxx) + # _CONAN_IS_GNU_LIBSTDCXX true if GNU libstdc++ + check_cxx_source_compiles(" + #include + #if !defined(__GLIBCXX__) && !defined(__GLIBCPP__) + static_assert(false); + #endif + int main(){}" _CONAN_IS_GNU_LIBSTDCXX) + + # _CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI true if C++11 ABI + check_cxx_source_compiles(" + #include + static_assert(sizeof(std::string) != sizeof(void*), \"using libstdc++\"); + int main () {}" _CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI) + + set(_CONAN_GNU_LIBSTDCXX_SUFFIX "") + if(_CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI) + set(_CONAN_GNU_LIBSTDCXX_SUFFIX "11") + endif() + unset (_CONAN_GNU_LIBSTDCXX_IS_CXX11_ABI) +endmacro() + +macro(detect_libcxx) + # _CONAN_IS_LIBCXX true if LLVM libc++ + check_cxx_source_compiles(" + #include + #if !defined(_LIBCPP_VERSION) + static_assert(false); + #endif + int main(){}" _CONAN_IS_LIBCXX) +endmacro() + + +function(detect_lib_cxx OS LIB_CXX) + if(${OS} STREQUAL "Android") + message(STATUS "CMake-Conan: android_stl=${ANDROID_STL}") + set(${LIB_CXX} ${ANDROID_STL} PARENT_SCOPE) + return() + endif() + + include(CheckCXXSourceCompiles) + + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + detect_gnu_libstdcxx() + set(${LIB_CXX} "libstdc++${_CONAN_GNU_LIBSTDCXX_SUFFIX}" PARENT_SCOPE) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "AppleClang") + set(${LIB_CXX} "libc++" PARENT_SCOPE) + elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND NOT CMAKE_SYSTEM_NAME MATCHES "Windows") + # Check for libc++ + detect_libcxx() + if(_CONAN_IS_LIBCXX) + set(${LIB_CXX} "libc++" PARENT_SCOPE) + return() + endif() + + # Check for libstdc++ + detect_gnu_libstdcxx() + if(_CONAN_IS_GNU_LIBSTDCXX) + set(${LIB_CXX} "libstdc++${_CONAN_GNU_LIBSTDCXX_SUFFIX}" PARENT_SCOPE) + return() + endif() + + # TODO: it would be an error if we reach this point + elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") + # Do nothing - compiler.runtime and compiler.runtime_type + # should be handled separately: https://github.com/conan-io/cmake-conan/pull/516 + return() + else() + # TODO: unable to determine, ask user to provide a full profile file instead + endif() +endfunction() + + +function(detect_compiler COMPILER COMPILER_VERSION COMPILER_RUNTIME COMPILER_RUNTIME_TYPE) + if(DEFINED CMAKE_CXX_COMPILER_ID) + set(_COMPILER ${CMAKE_CXX_COMPILER_ID}) + set(_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) + else() + if(NOT DEFINED CMAKE_C_COMPILER_ID) + message(FATAL_ERROR "C or C++ compiler not defined") + endif() + set(_COMPILER ${CMAKE_C_COMPILER_ID}) + set(_COMPILER_VERSION ${CMAKE_C_COMPILER_VERSION}) + endif() + + message(STATUS "CMake-Conan: CMake compiler=${_COMPILER}") + message(STATUS "CMake-Conan: CMake compiler version=${_COMPILER_VERSION}") + + if(_COMPILER MATCHES MSVC) + set(_COMPILER "msvc") + string(SUBSTRING ${MSVC_VERSION} 0 3 _COMPILER_VERSION) + # Configure compiler.runtime and compiler.runtime_type settings for MSVC + if(CMAKE_MSVC_RUNTIME_LIBRARY) + set(_KNOWN_MSVC_RUNTIME_VALUES "") + list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded MultiThreadedDLL) + list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreadedDebug MultiThreadedDebugDLL) + list(APPEND _KNOWN_MSVC_RUNTIME_VALUES MultiThreaded$<$:Debug> MultiThreaded$<$:Debug>DLL) + + # only accept the 6 possible values, otherwise we don't don't know to map this + if(NOT CMAKE_MSVC_RUNTIME_LIBRARY IN_LIST _KNOWN_MSVC_RUNTIME_VALUES) + message(FATAL_ERROR "CMake-Conan: unable to map MSVC runtime: ${CMAKE_MSVC_RUNTIME_LIBRARY} to Conan settings") + endif() + + # Runtime is "dynamic" in all cases if it ends in DLL + if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES ".*DLL$") + set(_COMPILER_RUNTIME "dynamic") + else() + set(_COMPILER_RUNTIME "static") + endif() + + # Only define compiler.runtime_type when explicitly requested + # If a generator expression is used, let Conan handle it conditional on build_type + get_property(_IS_MULTI_CONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(NOT CMAKE_MSVC_RUNTIME_LIBRARY MATCHES ":Debug>") + if(CMAKE_MSVC_RUNTIME_LIBRARY MATCHES "Debug") + set(_COMPILER_RUNTIME_TYPE "Debug") + else() + set(_COMPILER_RUNTIME_TYPE "Release") + endif() + endif() + + unset(_KNOWN_MSVC_RUNTIME_VALUES) + unset(_IS_MULTI_CONFIG_GENERATOR) + endif() + elseif(_COMPILER MATCHES AppleClang) + set(_COMPILER "apple-clang") + string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION}) + list(GET VERSION_LIST 0 _COMPILER_VERSION) + elseif(_COMPILER MATCHES Clang) + set(_COMPILER "clang") + string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION}) + list(GET VERSION_LIST 0 _COMPILER_VERSION) + elseif(_COMPILER MATCHES GNU) + set(_COMPILER "gcc") + string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION}) + list(GET VERSION_LIST 0 _COMPILER_VERSION) + endif() + + message(STATUS "CMake-Conan: [settings] compiler=${_COMPILER}") + message(STATUS "CMake-Conan: [settings] compiler.version=${_COMPILER_VERSION}") + if (_COMPILER_RUNTIME) + message(STATUS "CMake-Conan: [settings] compiler.runtime=${_COMPILER_RUNTIME}") + endif() + if (_COMPILER_RUNTIME_TYPE) + message(STATUS "CMake-Conan: [settings] compiler.runtime_type=${_COMPILER_RUNTIME_TYPE}") + endif() + + set(${COMPILER} ${_COMPILER} PARENT_SCOPE) + set(${COMPILER_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE) + set(${COMPILER_RUNTIME} ${_COMPILER_RUNTIME} PARENT_SCOPE) + set(${COMPILER_RUNTIME_TYPE} ${_COMPILER_RUNTIME_TYPE} PARENT_SCOPE) +endfunction() + +function(detect_build_type BUILD_TYPE) + get_property(_MULTICONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(NOT _MULTICONFIG_GENERATOR) + # Only set when we know we are in a single-configuration generator + # Note: we may want to fail early if `CMAKE_BUILD_TYPE` is not defined + set(${BUILD_TYPE} ${CMAKE_BUILD_TYPE} PARENT_SCOPE) + endif() +endfunction() + +macro(append_compiler_executables_configuration) + set(_conan_c_compiler "") + set(_conan_cpp_compiler "") + if(CMAKE_C_COMPILER) + set(_conan_c_compiler "\"c\":\"${CMAKE_C_COMPILER}\",") + else() + message(WARNING "CMake-Conan: The C compiler is not defined. " + "Please define CMAKE_C_COMPILER or enable the C language.") + endif() + if(CMAKE_CXX_COMPILER) + set(_conan_cpp_compiler "\"cpp\":\"${CMAKE_CXX_COMPILER}\"") + else() + message(WARNING "CMake-Conan: The C++ compiler is not defined. " + "Please define CMAKE_CXX_COMPILER or enable the C++ language.") + endif() + + string(APPEND PROFILE "tools.build:compiler_executables={${_conan_c_compiler}${_conan_cpp_compiler}}\n") + unset(_conan_c_compiler) + unset(_conan_cpp_compiler) +endmacro() + + +function(detect_host_profile output_file) + detect_os(MYOS MYOS_API_LEVEL MYOS_SDK MYOS_SUBSYSTEM MYOS_VERSION) + detect_arch(MYARCH) + detect_compiler(MYCOMPILER MYCOMPILER_VERSION MYCOMPILER_RUNTIME MYCOMPILER_RUNTIME_TYPE) + detect_cxx_standard(MYCXX_STANDARD) + detect_lib_cxx(MYOS MYLIB_CXX) + detect_build_type(MYBUILD_TYPE) + + set(PROFILE "") + string(APPEND PROFILE "[settings]\n") + if(MYARCH) + string(APPEND PROFILE arch=${MYARCH} "\n") + endif() + if(MYOS) + string(APPEND PROFILE os=${MYOS} "\n") + endif() + if(MYOS_API_LEVEL) + string(APPEND PROFILE os.api_level=${MYOS_API_LEVEL} "\n") + endif() + if(MYOS_VERSION) + string(APPEND PROFILE os.version=${MYOS_VERSION} "\n") + endif() + if(MYOS_SDK) + string(APPEND PROFILE os.sdk=${MYOS_SDK} "\n") + endif() + if(MYOS_SUBSYSTEM) + string(APPEND PROFILE os.subsystem=${MYOS_SUBSYSTEM} "\n") + endif() + if(MYCOMPILER) + string(APPEND PROFILE compiler=${MYCOMPILER} "\n") + endif() + if(MYCOMPILER_VERSION) + string(APPEND PROFILE compiler.version=${MYCOMPILER_VERSION} "\n") + endif() + if(MYCOMPILER_RUNTIME) + string(APPEND PROFILE compiler.runtime=${MYCOMPILER_RUNTIME} "\n") + endif() + if(MYCOMPILER_RUNTIME_TYPE) + string(APPEND PROFILE compiler.runtime_type=${MYCOMPILER_RUNTIME_TYPE} "\n") + endif() + if(MYCXX_STANDARD) + string(APPEND PROFILE compiler.cppstd=${MYCXX_STANDARD} "\n") + endif() + if(MYLIB_CXX) + string(APPEND PROFILE compiler.libcxx=${MYLIB_CXX} "\n") + endif() + if(MYBUILD_TYPE) + string(APPEND PROFILE "build_type=${MYBUILD_TYPE}\n") + endif() + + if(NOT DEFINED output_file) + set(_FN "${CMAKE_BINARY_DIR}/profile") + else() + set(_FN ${output_file}) + endif() + + string(APPEND PROFILE "[conf]\n") + string(APPEND PROFILE "tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR}\n") + + # propagate compilers via profile + append_compiler_executables_configuration() + + if(${MYOS} STREQUAL "Android") + string(APPEND PROFILE "tools.android:ndk_path=${CMAKE_ANDROID_NDK}\n") + endif() + + message(STATUS "CMake-Conan: Creating profile ${_FN}") + file(WRITE ${_FN} ${PROFILE}) + message(STATUS "CMake-Conan: Profile: \n${PROFILE}") +endfunction() + + +function(conan_profile_detect_default) + message(STATUS "CMake-Conan: Checking if a default profile exists") + execute_process(COMMAND ${CONAN_COMMAND} profile path default + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_stdout + ERROR_VARIABLE conan_stderr + ECHO_ERROR_VARIABLE # show the text output regardless + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(NOT ${return_code} EQUAL "0") + message(STATUS "CMake-Conan: The default profile doesn't exist, detecting it.") + execute_process(COMMAND ${CONAN_COMMAND} profile detect + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_stdout + ERROR_VARIABLE conan_stderr + ECHO_ERROR_VARIABLE # show the text output regardless + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() +endfunction() + + +function(conan_install) + cmake_parse_arguments(ARGS CONAN_ARGS ${ARGN}) + set(CONAN_OUTPUT_FOLDER ${CMAKE_BINARY_DIR}/conan) + # Invoke "conan install" with the provided arguments + set(CONAN_ARGS ${CONAN_ARGS} -of=${CONAN_OUTPUT_FOLDER}) + message(STATUS "CMake-Conan: conan install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN}") + execute_process(COMMAND ${CONAN_COMMAND} install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN} --format=json + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_stdout + ERROR_VARIABLE conan_stderr + ECHO_ERROR_VARIABLE # show the text output regardless + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan install failed='${return_code}'") + else() + # the files are generated in a folder that depends on the layout used, if + # one is specified, but we don't know a priori where this is. + # TODO: this can be made more robust if Conan can provide this in the json output + string(JSON CONAN_GENERATORS_FOLDER GET ${conan_stdout} graph nodes 0 generators_folder) + # message("conan stdout: ${conan_stdout}") + message(STATUS "CMake-Conan: CONAN_GENERATORS_FOLDER=${CONAN_GENERATORS_FOLDER}") + set_property(GLOBAL PROPERTY CONAN_GENERATORS_FOLDER "${CONAN_GENERATORS_FOLDER}") + # reconfigure on conanfile changes + string(JSON CONANFILE GET ${conan_stdout} graph nodes 0 label) + message(STATUS "CMake-Conan: CONANFILE=${CMAKE_SOURCE_DIR}/${CONANFILE}") + set_property(DIRECTORY ${CMAKE_SOURCE_DIR} APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${CMAKE_SOURCE_DIR}/${CONANFILE}") + # success + set_property(GLOBAL PROPERTY CONAN_INSTALL_SUCCESS TRUE) + endif() +endfunction() + + +function(conan_get_version conan_command conan_current_version) + execute_process( + COMMAND ${conan_command} --version + OUTPUT_VARIABLE conan_output + RESULT_VARIABLE conan_result + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(conan_result) + message(FATAL_ERROR "CMake-Conan: Error when trying to run Conan") + endif() + + string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" conan_version ${conan_output}) + set(${conan_current_version} ${conan_version} PARENT_SCOPE) +endfunction() + + +function(conan_version_check) + set(options ) + set(oneValueArgs MINIMUM CURRENT) + set(multiValueArgs ) + cmake_parse_arguments(CONAN_VERSION_CHECK + "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(NOT CONAN_VERSION_CHECK_MINIMUM) + message(FATAL_ERROR "CMake-Conan: Required parameter MINIMUM not set!") + endif() + if(NOT CONAN_VERSION_CHECK_CURRENT) + message(FATAL_ERROR "CMake-Conan: Required parameter CURRENT not set!") + endif() + + if(CONAN_VERSION_CHECK_CURRENT VERSION_LESS CONAN_VERSION_CHECK_MINIMUM) + message(FATAL_ERROR "CMake-Conan: Conan version must be ${CONAN_VERSION_CHECK_MINIMUM} or later") + endif() +endfunction() + +macro(construct_profile_argument argument_variable profile_list) + set(${argument_variable} "") + if("${profile_list}" STREQUAL "CONAN_HOST_PROFILE") + set(_arg_flag "--profile:host=") + elseif("${profile_list}" STREQUAL "CONAN_BUILD_PROFILE") + set(_arg_flag "--profile:build=") + endif() + + set(_profile_list "${${profile_list}}") + list(TRANSFORM _profile_list REPLACE "auto-cmake" "${CMAKE_BINARY_DIR}/conan_host_profile") + list(TRANSFORM _profile_list PREPEND ${_arg_flag}) + set(${argument_variable} ${_profile_list}) + + unset(_arg_flag) + unset(_profile_list) +endmacro() + + +macro(conan_provide_dependency method package_name) + set_property(GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED TRUE) + get_property(CONAN_INSTALL_SUCCESS GLOBAL PROPERTY CONAN_INSTALL_SUCCESS) + if(NOT CONAN_INSTALL_SUCCESS) + find_program(CONAN_COMMAND "conan" REQUIRED) + conan_get_version(${CONAN_COMMAND} CONAN_CURRENT_VERSION) + conan_version_check(MINIMUM ${CONAN_MINIMUM_VERSION} CURRENT ${CONAN_CURRENT_VERSION}) + message(STATUS "CMake-Conan: first find_package() found. Installing dependencies with Conan") + if("default" IN_LIST CONAN_HOST_PROFILE OR "default" IN_LIST CONAN_BUILD_PROFILE) + conan_profile_detect_default() + endif() + if("auto-cmake" IN_LIST CONAN_HOST_PROFILE) + detect_host_profile(${CMAKE_BINARY_DIR}/conan_host_profile) + endif() + construct_profile_argument(_host_profile_flags CONAN_HOST_PROFILE) + construct_profile_argument(_build_profile_flags CONAN_BUILD_PROFILE) + get_property(_MULTICONFIG_GENERATOR GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) + if(NOT _MULTICONFIG_GENERATOR) + message(STATUS "CMake-Conan: Installing single configuration ${CMAKE_BUILD_TYPE}") + conan_install(${_host_profile_flags} ${_build_profile_flags} --build=missing -g CMakeDeps) + else() + message(STATUS "CMake-Conan: Installing both Debug and Release") + conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Release --build=missing -g CMakeDeps) + conan_install(${_host_profile_flags} ${_build_profile_flags} -s build_type=Debug --build=missing -g CMakeDeps) + endif() + unset(_MULTICONFIG_GENERATOR) + else() + message(STATUS "CMake-Conan: find_package(${ARGV1}) found, 'conan install' already ran") + endif() + + get_property(CONAN_GENERATORS_FOLDER GLOBAL PROPERTY CONAN_GENERATORS_FOLDER) + + # Ensure that we consider Conan-provided packages ahead of any other, + # irrespective of other settings that modify the search order or search paths + # This follows the guidelines from the find_package documentation + # (https://cmake.org/cmake/help/latest/command/find_package.html): + # find_package ( PATHS paths... NO_DEFAULT_PATH) + # find_package () + + # Filter out `REQUIRED` from the argument list, as the first call may fail + set(_find_args "${ARGN}") + list(REMOVE_ITEM _find_args "REQUIRED") + if(NOT "MODULE" IN_LIST _find_args) + find_package(${package_name} ${_find_args} BYPASS_PROVIDER PATHS "${CONAN_GENERATORS_FOLDER}" NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + endif() + + # Invoke find_package a second time - if the first call succeeded, + # this will simply reuse the result. If not, fall back to CMake default search + # behaviour, also allowing modules to be searched. + set(_cmake_module_path_orig "${CMAKE_MODULE_PATH}") + list(PREPEND CMAKE_MODULE_PATH "${CONAN_GENERATORS_FOLDER}") + if(NOT ${package_name}_FOUND) + find_package(${package_name} ${ARGN} BYPASS_PROVIDER) + endif() + + set(CMAKE_MODULE_PATH "${_cmake_module_path_orig}") + unset(_find_args) + unset(_cmake_module_path_orig) + unset(_host_profile_flags) + unset(_build_profile_flags) +endmacro() + + +cmake_language( + SET_DEPENDENCY_PROVIDER conan_provide_dependency + SUPPORTED_METHODS FIND_PACKAGE +) + +macro(conan_provide_dependency_check) + set(_CONAN_PROVIDE_DEPENDENCY_INVOKED FALSE) + get_property(_CONAN_PROVIDE_DEPENDENCY_INVOKED GLOBAL PROPERTY CONAN_PROVIDE_DEPENDENCY_INVOKED) + if(NOT _CONAN_PROVIDE_DEPENDENCY_INVOKED) + message(WARNING "Conan is correctly configured as dependency provider, " + "but Conan has not been invoked. Please add at least one " + "call to `find_package()`.") + if(DEFINED CONAN_COMMAND) + # supress warning in case `CONAN_COMMAND` was specified but unused. + set(_CONAN_COMMAND ${CONAN_COMMAND}) + unset(_CONAN_COMMAND) + endif() + endif() + unset(_CONAN_PROVIDE_DEPENDENCY_INVOKED) +endmacro() + +# Add a deferred call at the end of processing the top-level directory +# to check if the dependency provider was invoked at all. +cmake_language(DEFER DIRECTORY "${CMAKE_SOURCE_DIR}" CALL conan_provide_dependency_check) + +# Configurable variables for Conan profiles +set(CONAN_HOST_PROFILE "default;auto-cmake" CACHE STRING "Conan host profile") +set(CONAN_BUILD_PROFILE "default" CACHE STRING "Conan build profile") diff --git a/conandata.yml b/conandata.yml new file mode 100644 index 0000000..5385094 --- /dev/null +++ b/conandata.yml @@ -0,0 +1,5 @@ +# This file is managed by Conan, contents will be overwritten. +# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements + +requirements: + - "log.c/cci.20200620" \ No newline at end of file diff --git a/conanfile.py b/conanfile.py new file mode 100644 index 0000000..b89a080 --- /dev/null +++ b/conanfile.py @@ -0,0 +1,23 @@ +# This file is managed by Conan, contents will be overwritten. +# To keep your changes, remove these comment lines, but the plugin won't be able to modify your requirements + +from conan import ConanFile +from conan.tools.cmake import cmake_layout, CMakeToolchain + +class ConanApplication(ConanFile): + package_type = "application" + settings = "os", "compiler", "build_type", "arch" + generators = "CMakeDeps" + + def layout(self): + cmake_layout(self) + + def generate(self): + tc = CMakeToolchain(self) + tc.user_presets_path = False + tc.generate() + + def requirements(self): + requirements = self.conan_data.get('requirements', []) + for requirement in requirements: + self.requires(requirement) \ No newline at end of file diff --git a/cpu/CMakeLists.txt b/cpu/CMakeLists.txt new file mode 100644 index 0000000..344b450 --- /dev/null +++ b/cpu/CMakeLists.txt @@ -0,0 +1,4 @@ +add_library(CPU + cpu.c + op.c + mem.c) \ No newline at end of file diff --git a/src/cpu/cpu.c b/cpu/cpu.c similarity index 80% rename from src/cpu/cpu.c rename to cpu/cpu.c index 52e8135..9483412 100644 --- a/src/cpu/cpu.c +++ b/cpu/cpu.c @@ -18,16 +18,10 @@ #include #include -#define test(x) \ - print_##x(x) +#include "../include/cpu/op.h" long cpu_clock = 0; void cpu_step_to(long cycle) { - cpu_clock = cycle; - printf("Clock: %ld", cpu_clock); - - test(f); - // test("b"); } diff --git a/cpu/mem.c b/cpu/mem.c new file mode 100644 index 0000000..acaad3f --- /dev/null +++ b/cpu/mem.c @@ -0,0 +1,26 @@ +// +// Created by william on 30/09/23. +// + +#include "../include/cpu/mem.h" +#include "../include/cpu/op.h" + +#include "../include/cpu/cpu.h" + +unsigned short get_memory_address(addr_mode_t addr_mode, unsigned short operand) { + if (addr_mode == ADDR_MODE_ABSOLUTE) { + cpu_add_cycles(4); + return operand; + } else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_X) { + unsigned char x = cpu_get_registers()->x; + cpu_add_cycles(4); + return operand + x; + } else if (addr_mode == ADDR_MODE_ABSOLUTE_INDEXED_Y) { + unsigned char y = cpu_get_registers()->y; + cpu_add_cycles(4); + return operand + y; + } else if (addr_mode == ADDR_MODE_INDEXED_INDIRECT) { + + } + +} \ No newline at end of file diff --git a/cpu/op.c b/cpu/op.c new file mode 100644 index 0000000..33a18c5 --- /dev/null +++ b/cpu/op.c @@ -0,0 +1,530 @@ +#include "../include/cpu/op.h" + +// Reference: https://www.nesdev.org/wiki/CPU_unofficial_opcodes + +#define IS_OP_CODE_MODE(op, op_code, addr_mode) \ + case op_code: \ + op_ ## op(ADDR_MODE_ ## addr_mode); \ + break; + +#define IS_OP_CODE(op, op_code) \ + IS_OP_CODE_MODE(op, op_code, IMPLICIT) + +#define IS_ALU_OP_CODE_(op, offset, addr_mode) \ + IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## op + offset, addr_mode) + +#define IS_ALU_OP_CODE(op) \ + IS_ALU_OP_CODE_(op, 0x01, INDEXED_INDIRECT) \ + IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \ + IS_ALU_OP_CODE_(op, 0x09, IMMEDIATE) \ + IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \ + IS_ALU_OP_CODE_(op, 0x11, INDIRECT_INDEXED) \ + IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \ + IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \ + IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X) + +#define IS_ALU_OP_CODE_NO_IMMEDIATE(op) \ + IS_ALU_OP_CODE_(op, 0x01, INDEXED_INDIRECT) \ + IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \ + IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \ + IS_ALU_OP_CODE_(op, 0x11, INDIRECT_INDEXED) \ + IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \ + IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \ + IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X) + +#define IS_RMW_OP_CODE_(op, line, offset, addr_mode) \ + IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## line + offset, addr_mode) + +#define IS_RMW_OP_CODE(op, line) \ + IS_RMW_OP_CODE_(op, line, 0x06, ZERO_PAGE) \ + IS_RMW_OP_CODE_(op, line, 0x0a, IMPLICIT) \ + IS_RMW_OP_CODE_(op, line, 0x0e, ABSOLUTE) \ + IS_RMW_OP_CODE_(op, line, 0x16, ZERO_PAGE_INDEXED_X) \ + IS_RMW_OP_CODE_(op, line, 0x1e, ABSOLUTE_INDEXED_X) + +#define IS_UNOFFICIAL_OP_CODE_(op, line, offset, addr_mode) \ + IS_OP_CODE_MODE(op, OP_CODE_BASE_ ## line + offset, addr_mode) + +#define IS_UNOFFICIAL_OP_CODE(op, line) \ + IS_UNOFFICIAL_OP_CODE_(op, line, 0x03, INDEXED_INDIRECT) \ + IS_UNOFFICIAL_OP_CODE_(op, line, 0x07, ZERO_PAGE) \ + IS_UNOFFICIAL_OP_CODE_(op, line, 0x0f, ABSOLUTE) \ + IS_UNOFFICIAL_OP_CODE_(op, line, 0x13, INDIRECT_INDEXED) \ + IS_UNOFFICIAL_OP_CODE_(op, line, 0x17, ZERO_PAGE_INDEXED_X) \ + IS_UNOFFICIAL_OP_CODE_(op, line, 0x1b, ABSOLUTE_INDEXED_Y) \ + IS_UNOFFICIAL_OP_CODE_(op, line, 0x1f, ABSOLUTE_INDEXED_X) + +void op_ADC(addr_mode_t addr_mode) { + +} + +/* === CTRL === */ +void op_BRK(addr_mode_t addr_mode) { + +} + +void op_BPL(addr_mode_t addr_mode) { + +} + +void op_BIT(addr_mode_t addr_mode) { + +} + +void op_BMI(addr_mode_t addr_mode) { + +} + +void op_BVC(addr_mode_t addr_mode) { + +} + +void op_BVS(addr_mode_t addr_mode) { + +} + +void op_BCC(addr_mode_t addr_mode) { + +} + +void op_BCS(addr_mode_t addr_mode) { + +} + +void op_BNE(addr_mode_t addr_mode) { + +} + +void op_BEQ(addr_mode_t addr_mode) { + +} + +void op_PHP(addr_mode_t addr_mode) { + +} + +void op_CLC(addr_mode_t addr_mode) { + +} + +void op_JSR(addr_mode_t addr_mode) { + +} + +void op_PLP(addr_mode_t addr_mode) { + +} + +void op_SEC(addr_mode_t addr_mode) { + +} + +void op_RTI(addr_mode_t addr_mode) { + +} + +void op_PHA(addr_mode_t addr_mode) { + +} + +void op_JMP(addr_mode_t addr_mode) { + +} + +void op_CLI(addr_mode_t addr_mode) { + +} + +void op_RTS(addr_mode_t addr_mode) { + +} + +void op_PLA(addr_mode_t addr_mode) { + +} + +void op_SEI(addr_mode_t addr_mode) { + +} + +void op_STY(addr_mode_t addr_mode) { + +} + +void op_DEY(addr_mode_t addr_mode) { + +} + +void op_TYA(addr_mode_t addr_mode) { + +} + +void op_LDY(addr_mode_t addr_mode) { + +} + +void op_TAY(addr_mode_t addr_mode) { + +} + +void op_CLV(addr_mode_t addr_mode) { + +} + +void op_CPY(addr_mode_t addr_mode) { + +} + +void op_INY(addr_mode_t addr_mode) { + +} + +void op_CLD(addr_mode_t addr_mode) { + +} + +void op_CPX(addr_mode_t addr_mode) { + +} + +void op_INX(addr_mode_t addr_mode) { + +} + +void op_SED(addr_mode_t addr_mode) { + +} + +/* === ALU === */ +void op_ORA(addr_mode_t addr_mode) { + +} + +void op_AND(addr_mode_t addr_mode) { + +} + +void op_EOR(addr_mode_t addr_mode) { + +} + +void op_ADC(addr_mode_t addr_mode) { + +} + +void op_STA(addr_mode_t addr_mode) { + +} + +void op_LDA(addr_mode_t addr_mode) { + +} + +void op_CMP(addr_mode_t addr_mode) { + +} + +void op_SBC(addr_mode_t addr_mode) { + +} + +void op_NOP(addr_mode_t addr_mode) { + +} + +/* RMW */ +void op_ASL(addr_mode_t addr_mode) { + +} + +void op_ROL(addr_mode_t addr_mode) { + +} + +void op_LSR(addr_mode_t addr_mode) { + +} + +void op_ROR(addr_mode_t addr_mode) { + +} + +void op_STX(addr_mode_t addr_mode) { + +} + +void op_TXA(addr_mode_t addr_mode) { + +} + +void op_TXS(addr_mode_t addr_mode) { + +} + +void op_SHX(addr_mode_t addr_mode) { + +} + +void op_LDX(addr_mode_t addr_mode) { + +} + +void op_TAX(addr_mode_t addr_mode) { + +} + +void op_TSX(addr_mode_t addr_mode) { + +} + +void op_DEC(addr_mode_t addr_mode) { + +} + +void op_DEX(addr_mode_t addr_mode) { + +} + +void op_INC(addr_mode_t addr_mode) { + +} + +// Unofficial +void op_STP(addr_mode_t addr_mode) { + +} + +void op_SHY(addr_mode_t addr_mode) { + +} + +void op_SLO(addr_mode_t addr_mode) { + +} + +void op_RLA(addr_mode_t addr_mode) { + +} + +void op_SRE(addr_mode_t addr_mode) { + +} + +void op_RRA(addr_mode_t addr_mode) { + +} + +void op_SAX(addr_mode_t addr_mode) { + +} + +void op_LAX(addr_mode_t addr_mode) { + +} + +void op_DCP(addr_mode_t addr_mode) { + +} + +void op_ISC(addr_mode_t addr_mode) { + +} + +void op_ANC(addr_mode_t addr_mode) { + +} + +void op_ALR(addr_mode_t addr_mode) { + +} + +void op_ARR(addr_mode_t addr_mode) { + +} + +void op_XAA(addr_mode_t addr_mode) { + +} + +void op_AXS(addr_mode_t addr_mode) { + +} + +void op_AHX(addr_mode_t addr_mode) { + +} + +void op_TAS(addr_mode_t addr_mode) { + +} + +void process_op_code(int op) { + switch (op) { + // CTRL + IS_OP_CODE(BRK, 0x00) + IS_OP_CODE(PHP, 0x08) + IS_OP_CODE(CLC, 0x18) + IS_OP_CODE(PLP, 0x28) + IS_OP_CODE(SEC, 0x38) + IS_OP_CODE(RTI, 0x40) + IS_OP_CODE(PHA, 0x48) + IS_OP_CODE(CLI, 0x58) + IS_OP_CODE(RTS, 0x60) + IS_OP_CODE(PLA, 0x68) + IS_OP_CODE(SEI, 0x78) + IS_OP_CODE(DEY, 0x88) + IS_OP_CODE(TYA, 0x98) + IS_OP_CODE(TAY, 0xa8) + IS_OP_CODE(CLV, 0xb8) + IS_OP_CODE(INY, 0xc8) + IS_OP_CODE(CLD, 0xd8) + IS_OP_CODE(INX, 0xe8) + IS_OP_CODE(SED, 0xf8) + + IS_OP_CODE_MODE(JSR, 0x20, ABSOLUTE) + IS_OP_CODE_MODE(BIT, 0x24, ZERO_PAGE) + IS_OP_CODE_MODE(BIT, 0x2c, ABSOLUTE) + IS_OP_CODE_MODE(JMP, 0x4c, ABSOLUTE) + IS_OP_CODE_MODE(JMP, 0x6c, ABSOLUTE_JUMP) + IS_OP_CODE_MODE(STY, 0x84, ZERO_PAGE) + IS_OP_CODE_MODE(STY, 0x8c, ABSOLUTE) + IS_OP_CODE_MODE(STY, 0x94, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(SHY, 0x9c, ABSOLUTE_INDEXED_X) + IS_OP_CODE_MODE(LDY, 0xa0, IMMEDIATE) + IS_OP_CODE_MODE(LDY, 0xa4, ZERO_PAGE) + IS_OP_CODE_MODE(LDY, 0xac, ABSOLUTE) + IS_OP_CODE_MODE(LDY, 0xb4, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(LDY, 0xbc, ABSOLUTE_INDEXED_X) + IS_OP_CODE_MODE(CPY, 0xc0, IMMEDIATE) + IS_OP_CODE_MODE(CPY, 0xc4, ZERO_PAGE) + IS_OP_CODE_MODE(CPY, 0xcc, ABSOLUTE) + IS_OP_CODE_MODE(CPX, 0xe0, IMMEDIATE) + IS_OP_CODE_MODE(CPX, 0xe4, ZERO_PAGE) + IS_OP_CODE_MODE(CPX, 0xec, ABSOLUTE) + + IS_OP_CODE_MODE(BPL, 0x10, RELATIVE) + IS_OP_CODE_MODE(BMI, 0x30, RELATIVE) + IS_OP_CODE_MODE(BVC, 0x50, RELATIVE) + IS_OP_CODE_MODE(BVS, 0x70, RELATIVE) + IS_OP_CODE_MODE(BCC, 0x90, RELATIVE) + IS_OP_CODE_MODE(BCS, 0xb0, RELATIVE) + IS_OP_CODE_MODE(BNE, 0xd0, RELATIVE) + IS_OP_CODE_MODE(BEQ, 0xf0, RELATIVE) + + IS_OP_CODE_MODE(NOP, 0x04, ZERO_PAGE) + IS_OP_CODE_MODE(NOP, 0x0c, ABSOLUTE) + IS_OP_CODE_MODE(NOP, 0x14, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x1c, ABSOLUTE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x34, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x3c, ABSOLUTE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x44, ZERO_PAGE) + IS_OP_CODE_MODE(NOP, 0x54, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x5c, ABSOLUTE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x64, ZERO_PAGE) + IS_OP_CODE_MODE(NOP, 0x74, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x7c, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0x80, IMMEDIATE) + IS_OP_CODE_MODE(NOP, 0xd4, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0xdc, ABSOLUTE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0xf4, ZERO_PAGE_INDEXED_X) + IS_OP_CODE_MODE(NOP, 0xfc, ABSOLUTE_INDEXED_X) + + // ALU + IS_ALU_OP_CODE(ORA) + IS_ALU_OP_CODE(AND) + IS_ALU_OP_CODE(EOR) + IS_ALU_OP_CODE(ADC) + IS_ALU_OP_CODE_NO_IMMEDIATE(STA) + IS_ALU_OP_CODE(LDA) + IS_ALU_OP_CODE(CMP) + IS_ALU_OP_CODE(SBC) + + // RMW + IS_RMW_OP_CODE(ASL, ORA) + IS_RMW_OP_CODE(ROL, AND) + IS_RMW_OP_CODE(LSR, EOR) + IS_RMW_OP_CODE(ROR, ADC) + + IS_OP_CODE(STP, 0x02) + IS_OP_CODE(STP, 0x12) + IS_OP_CODE(NOP, 0x1a) + IS_OP_CODE(STP, 0x22) + IS_OP_CODE(STP, 0x32) + IS_OP_CODE(NOP, 0x3a) + IS_OP_CODE(STP, 0x42) + IS_OP_CODE(STP, 0x52) + IS_OP_CODE(NOP, 0x5a) + IS_OP_CODE(STP, 0x62) + IS_OP_CODE(STP, 0x72) + IS_OP_CODE(NOP, 0x7a) + + IS_OP_CODE_MODE(NOP, 0x82, IMMEDIATE) + IS_OP_CODE_MODE(STX, 0x86, ZERO_PAGE) + IS_OP_CODE(TXA, 0x8a) + IS_OP_CODE_MODE(STX, 0x8e, ABSOLUTE) + IS_OP_CODE(STP, 0x92) + IS_OP_CODE_MODE(STX, 0x96, ZERO_PAGE_INDEXED_Y) + IS_OP_CODE(TSX, 0x9a) + IS_OP_CODE_MODE(SHX, 0x9e, ABSOLUTE_INDEXED_Y) + + IS_OP_CODE_MODE(LDX, 0xa2, IMMEDIATE) + IS_OP_CODE_MODE(LDX, 0xa6, ZERO_PAGE) + IS_OP_CODE(TAX, 0xaa) + IS_OP_CODE_MODE(LDX, 0xae, ABSOLUTE) + IS_OP_CODE(STP, 0xb2) + IS_OP_CODE_MODE(LDX, 0xb6, ZERO_PAGE_INDEXED_Y) + IS_OP_CODE(TSX, 0xba) + IS_OP_CODE_MODE(LDX, 0xbe, ABSOLUTE_INDEXED_Y) + + IS_OP_CODE_MODE(NOP, 0xc2, IMMEDIATE) + IS_OP_CODE_MODE(DEC, 0xc6, ZERO_PAGE) + IS_OP_CODE(DEX, 0xca) + IS_OP_CODE_MODE(DEC, 0xce, ABSOLUTE) + IS_OP_CODE(STP, 0xd2) + IS_OP_CODE_MODE(DEC, 0xd6, ZERO_PAGE_INDEXED_Y) + IS_OP_CODE(NOP, 0xda) + IS_OP_CODE_MODE(DEC, 0xde, ABSOLUTE_INDEXED_Y) + + IS_OP_CODE_MODE(NOP, 0xe2, IMMEDIATE) + IS_OP_CODE_MODE(INC, 0xe6, ZERO_PAGE) + IS_OP_CODE(NOP, 0xea) // The official NOP + IS_OP_CODE_MODE(INC, 0xee, ABSOLUTE) + IS_OP_CODE(STP, 0xf2) + IS_OP_CODE_MODE(INC, 0xf6, ZERO_PAGE_INDEXED_Y) + IS_OP_CODE(NOP, 0xfa) + IS_OP_CODE_MODE(INC, 0xfe, ABSOLUTE_INDEXED_X) + + // Unofficial + IS_UNOFFICIAL_OP_CODE(SLO, ORA) + IS_UNOFFICIAL_OP_CODE(RLA, AND) + IS_UNOFFICIAL_OP_CODE(SRE, EOR) + IS_UNOFFICIAL_OP_CODE(RRA, ADC) + IS_UNOFFICIAL_OP_CODE(DCP, CMP) + IS_UNOFFICIAL_OP_CODE(ISC, SBC) + + IS_OP_CODE_MODE(ANC, 0x0b, IMMEDIATE) + IS_OP_CODE_MODE(ANC, 0x2b, IMMEDIATE) + IS_OP_CODE_MODE(ALR, 0x4b, IMMEDIATE) + IS_OP_CODE_MODE(ARR, 0x6b, IMMEDIATE) + IS_OP_CODE_MODE(AXS, 0xcb, IMMEDIATE) + IS_OP_CODE_MODE(SBC, 0xeb, IMMEDIATE) + + IS_OP_CODE_MODE(SAX, 0x83, INDEXED_INDIRECT) + IS_OP_CODE_MODE(SAX, 0x87, ZERO_PAGE) + IS_OP_CODE_MODE(XAA, 0x8b, IMMEDIATE) + IS_OP_CODE_MODE(SAX, 0x8f, ABSOLUTE) + IS_OP_CODE_MODE(AHX, 0x93, INDIRECT_INDEXED) + IS_OP_CODE_MODE(SAX, 0x97, ZERO_PAGE_INDEXED_Y) + IS_OP_CODE_MODE(TAS, 0x9b, ABSOLUTE_INDEXED_Y) + IS_OP_CODE_MODE(AHX, 0x9f, ABSOLUTE_INDEXED_Y) + + IS_OP_CODE_MODE(LAX, 0xa3, INDEXED_INDIRECT) + IS_OP_CODE_MODE(LAX, 0xa7, ZERO_PAGE) + IS_OP_CODE_MODE(LAX, 0xab, IMMEDIATE) + IS_OP_CODE_MODE(LAX, 0xaf, ABSOLUTE) + IS_OP_CODE_MODE(LAX, 0xb3, INDIRECT_INDEXED) + IS_OP_CODE_MODE(LAX, 0xb7, ZERO_PAGE_INDEXED_Y) + IS_OP_CODE_MODE(LAX, 0xbb, ABSOLUTE_INDEXED_Y) + IS_OP_CODE_MODE(LAX, 0xbf, ABSOLUTE_INDEXED_Y) + } +} diff --git a/include/cpu/cpu.h b/include/cpu/cpu.h new file mode 100644 index 0000000..abc161b --- /dev/null +++ b/include/cpu/cpu.h @@ -0,0 +1,51 @@ +/* + * ===================================================================================== + * + * Filename: cpu.h + * + * Description: 6502 CPU emulator headers + * + * Version: 1.0 + * Created: 2023-09-21 10:12:33 PM + * Revision: none + * Compiler: gcc + * + * Author: William Nolin, + * Organization: + * + * ===================================================================================== + */ + +#ifndef EMU_CPU_H +#define EMU_CPU_H + +// Reference: https://www.nesdev.org/wiki/Status_flags +#define CPU_STATUS_CARRY_MASK = 0x01; +#define CPU_STATUS_ZERO_MASK = 0x02; +#define CPU_STATUS_INTERRUPT_DISABLE_MASK = 0x04; +#define CPU_STATUS_DECIMAL_MASK = 0x08; +#define CPU_STATUS_B_MASK = 0x10; +#define CPU_STATUS_I_MASK = 0x20; +#define CPU_STATUS_OVERFLOW_MASK = 0x40; +#define CPU_STATUS_NEGATIVE_MASK = 0x80; + +// Reference: https://www.nesdev.org/obelisk-6502-guide/registers.html +typedef struct { + unsigned short program_counter; + unsigned char stack_pointer; + unsigned char accumulator; + unsigned char x; + unsigned char y; + unsigned char status; +} cpu_registers_t; + +/** + * @brief Set clock + */ +void cpu_step_to(int cycle); + +void cpu_add_cycles(int count); + +cpu_registers_t* cpu_get_registers(); + +#endif diff --git a/include/cpu/mem.h b/include/cpu/mem.h new file mode 100644 index 0000000..b09141d --- /dev/null +++ b/include/cpu/mem.h @@ -0,0 +1,8 @@ +// +// Created by william on 30/09/23. +// + +#ifndef NESEMULATOR_MEM_H +#define NESEMULATOR_MEM_H + +#endif //NESEMULATOR_MEM_H diff --git a/src/cpu/op.h b/include/cpu/op.h similarity index 76% rename from src/cpu/op.h rename to include/cpu/op.h index 538c049..5a72747 100644 --- a/src/cpu/op.h +++ b/include/cpu/op.h @@ -3,15 +3,15 @@ // The number associated with each op code is the matching line of the ALU op code. // Based on the table here: https://www.nesdev.org/wiki/CPU_unofficial_opcodes -enum op_code { - OP_CODE_ORA = 0x00, - OP_CODE_AND = 0x20, - OP_CODE_EOR = 0x40, - OP_CODE_ADC = 0x60, - OP_CODE_STA = 0x80, - OP_CODE_LDA = 0xa0, - OP_CODE_CMP = 0xc0, - OP_CODE_SBC = 0xe0 +enum op_code_base { + OP_CODE_BASE_ORA = 0x00, + OP_CODE_BASE_AND = 0x20, + OP_CODE_BASE_EOR = 0x40, + OP_CODE_BASE_ADC = 0x60, + OP_CODE_BASE_STA = 0x80, + OP_CODE_BASE_LDA = 0xa0, + OP_CODE_BASE_CMP = 0xc0, + OP_CODE_BASE_SBC = 0xe0 }; typedef enum { diff --git a/src/main.c b/main.c similarity index 74% rename from src/main.c rename to main.c index 212163f..0ad62ed 100644 --- a/src/main.c +++ b/main.c @@ -15,23 +15,14 @@ * * ===================================================================================== */ +#include #include -#include "cpu/cpu.h" - -long master_clock = 0; - -void step() { - master_clock += 1; - cpu_step_to(master_clock); - - return; -} +#include "config.h" +#include "include/cpu/cpu.h" int main() { - while (1) { - step(); - } + cpu_step_to(0); return -1; } diff --git a/obj/cpu.o b/obj/cpu.o deleted file mode 100644 index 5804503..0000000 Binary files a/obj/cpu.o and /dev/null differ diff --git a/obj/main.o b/obj/main.o deleted file mode 100644 index 266645b..0000000 Binary files a/obj/main.o and /dev/null differ diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h deleted file mode 100644 index 8b8bb8d..0000000 --- a/src/cpu/cpu.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * ===================================================================================== - * - * Filename: cpu.h - * - * Description: 6502 CPU emulator headers - * - * Version: 1.0 - * Created: 2023-09-21 10:12:33 PM - * Revision: none - * Compiler: gcc - * - * Author: William Nolin, - * Organization: - * - * ===================================================================================== - */ - -#ifndef EMU_CPU_H -#define EMU_CPU_H - -/** - * @brief Set clock - */ -void cpu_step_to(int cycle); - -#endif diff --git a/src/cpu/op.c b/src/cpu/op.c deleted file mode 100644 index 5b948f4..0000000 --- a/src/cpu/op.c +++ /dev/null @@ -1,83 +0,0 @@ -#include "op.h" - -// Reference: https://www.nesdev.org/wiki/CPU_unofficial_opcodes - -#define IS_OP_CODE_MODE(op, op_code, addr_mode) \ - case op_code: \ - op_ ## op(ADDR_MODE_ ## addr_mode); \ - break; - -#define IS_OP_CODE(op, op_code) \ - IS_OP_CODE_MODE(op, op_code, IMPLICIT) - -#define IS_ALU_OP_CODE_(op, offset, addr_mode) \ - IS_OP_CODE_MODE(op, OP_CODE_ ## op + offset, addr_mode) - -#define IS_ALU_OP_CODE(op) \ - IS_ALU_OP_CODE_(op, 0x01, INDEXED_INDIRECT) \ - IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \ - IS_ALU_OP_CODE_(op, 0x09, IMMEDIATE) \ - IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \ - IS_ALU_OP_CODE_(op, 0x11, INDIRECT_INDEXED) \ - IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \ - IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \ - IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X) - -#define IS_ALU_OP_CODE_NO_IMMEDIATE(op) \ - IS_ALU_OP_CODE_(op, 0x01, INDEXED_INDIRECT) \ - IS_ALU_OP_CODE_(op, 0x05, ZERO_PAGE) \ - IS_ALU_OP_CODE_(op, 0x0d, ABSOLUTE) \ - IS_ALU_OP_CODE_(op, 0x11, INDIRECT_INDEXED) \ - IS_ALU_OP_CODE_(op, 0x15, ZERO_PAGE_INDEXED_X) \ - IS_ALU_OP_CODE_(op, 0x19, ABSOLUTE_INDEXED_Y) \ - IS_ALU_OP_CODE_(op, 0x1d, ABSOLUTE_INDEXED_X) - -void op_ORA(addr_mode_t addr_mode) { - -} - -void op_AND(addr_mode_t addr_mode) { - -} - -void op_EOR(addr_mode_t addr_mode) { - -} - -void op_ADC(addr_mode_t addr_mode) { - -} - -void op_STA(addr_mode_t addr_mode) { - -} - -void op_LDA(addr_mode_t addr_mode) { - -} - -void op_CMP(addr_mode_t addr_mode) { - -} - -void op_SBC(addr_mode_t addr_mode) { - -} - -void process_op_code(int op) { - switch (op) { - // CTRL - IS_OP_CODE(BRK, 0x00) - IS_OP_CODE_MODE(NOP, 0x04, ZERO_PAGE) - - // ALU - IS_ALU_OP_CODE(ORA) - IS_ALU_OP_CODE(AND) - IS_ALU_OP_CODE(EOR) - IS_ALU_OP_CODE(ADC) - IS_ALU_OP_CODE_NO_IMMEDIATE(STA) - IS_ALU_OP_CODE(LDA) - IS_ALU_OP_CODE(CMP) - IS_ALU_OP_CODE(SBC) - } -}