./ 0000755 0001750 0001750 00000000000 13706454531 007311 5 ustar dan dan ./CMakeLists.txt 0000644 0001750 0001750 00000037464 13706454531 012067 0 ustar dan dan #
# CEN64: Cycle-Accurate Nintendo 64 Emulator.
# Copyright (C) 2015, Tyler J. Stachecki.
#
# This file is subject to the terms and conditions defined in
# 'LICENSE', which is part of this source code package.
#
cmake_minimum_required(VERSION 2.8)
project(cen64 C)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/Modules" ${CMAKE_MODULE_PATH})
if(APPLE)
find_package(OpenGLXQuartz REQUIRED)
# Needed for signal.h on OS X.
add_definitions(-D_DARWIN_C_SOURCE)
else(APPLE)
find_package(OpenGL REQUIRED)
endif(APPLE)
find_package(Iconv REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Threads REQUIRED)
# If using GCC, configure it accordingly.
if (${CMAKE_C_COMPILER_ID} MATCHES GNU)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-common -Wall -Wextra -Wno-unused-parameter -std=c99 -Werror=implicit-function-declaration")
# Include architecture-specify machinery.
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpmachine
OUTPUT_VARIABLE GCC_MACHINE)
string(REGEX MATCH "([a-zA-Z0-9])+" GCC_MACHINE ${GCC_MACHINE})
if (${GCC_MACHINE} MATCHES "x86.*" OR ${GCC_MACHINE} MATCHES "i.86.*")
set(CEN64_ARCH_SUPPORT "Native" CACHE STRING "Architectural extension(s) to use")
set_property(CACHE CEN64_ARCH_SUPPORT PROPERTY STRINGS Native AVX SSE4.1 SSSE3 SSE3 SSE2)
if (${CEN64_ARCH_SUPPORT} MATCHES "SSE2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mssse3")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse3")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE4.1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "AVX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "Native")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
endif ()
# if (${GCC_MACHINE} MATCHES "i.86.*" OR ${GCC_MACHINE} MATCHES "x86.*")
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffixed-xmm8 -ffixed-xmm9 -ffixed-xmm10")
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffixed-xmm11 -ffixed-xmm12 -ffixed-xmm13 -ffixed-xmm14 -ffixed-xmm15")
# endif (${GCC_MACHINE} MATCHES "i.86.*" OR ${GCC_MACHINE} MATCHES "x86.*")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -maccumulate-outgoing-args")
set(CEN64_ARCH_DIR "x86_64")
include_directories(${PROJECT_SOURCE_DIR}/os/unix/x86_64)
endif (${GCC_MACHINE} MATCHES "x86.*" OR ${GCC_MACHINE} MATCHES "i.86.*")
if (${GCC_MACHINE} STREQUAL "arm")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard -mfpu=neon")
include_directories(${PROJECT_SOURCE_DIR}/arch/arm)
include_directories(${PROJECT_SOURCE_DIR}/os/unix/arm)
endif (${GCC_MACHINE} STREQUAL "arm")
# Set architecture-independent flags.
set(CMAKE_C_FLAGS_DEBUG "-ggdb3 -g3 -O0")
set(CMAKE_C_FLAGS_MINSIZEREL "-Os -ffast-math -DNDEBUG -s -fmerge-all-constants")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -ffast-math -DNDEBUG -ggdb3 -g3 -fmerge-all-constants")
set(CMAKE_C_FLAGS_RELEASE "-O3 -ffast-math -DNDEBUG -fmerge-all-constants")
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
# Enable link time optimization on recent versions.
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
OUTPUT_VARIABLE GCC_VERSION)
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-s")
if (GCC_VERSION VERSION_GREATER 4.6 OR GCC_VERSION VERSION_EQUAL 4.6)
set(GCC_FLTO_FLAGS "-flto -fdata-sections -ffunction-sections")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${GCC_FLTO_FLAGS}")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${GCC_FLTO_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -Wl,--gc-sections")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} -Wl,--gc-sections")
endif (GCC_VERSION VERSION_GREATER 4.6 OR GCC_VERSION VERSION_EQUAL 4.6)
# Enable "unsafe" loop optimizations on recent versions.
if (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -funsafe-loop-optimizations")
set(CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} -funsafe-loop-optimizations")
endif (GCC_VERSION VERSION_GREATER 4.8 OR GCC_VERSION VERSION_EQUAL 4.8)
# Check for undefined behaviour when debugging.
if (GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined")
set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} -fsanitize=undefined")
endif (GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
# Use fat LTO objects.
if (GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -ffat-lto-objects")
endif (GCC_VERSION VERSION_GREATER 4.9 OR GCC_VERSION VERSION_EQUAL 4.9)
# Check for const-correctness.
if (GCC_VERSION VERSION_GREATER 5.1 OR GCC_VERSION VERSION_EQUAL 5.1)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror=discarded-qualifiers")
endif (GCC_VERSION VERSION_GREATER 5.1 OR GCC_VERSION VERSION_EQUAL 5.1)
endif (${CMAKE_C_COMPILER_ID} MATCHES GNU)
# If using Clang, configure it accordingly.
if (${CMAKE_C_COMPILER_ID} MATCHES Clang)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Wextra -Wno-unused-parameter -std=c99")
# Include architecture-specify machinery.
execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpmachine
OUTPUT_VARIABLE CLANG_MACHINE)
string(REGEX MATCH "([a-zA-Z0-9])+" CLANG_MACHINE ${CLANG_MACHINE})
if (${CLANG_MACHINE} MATCHES "x86.*" OR ${CLANG_MACHINE} MATCHES "i.86.*")
set(CEN64_ARCH_SUPPORT "Native" CACHE STRING "Architectural extension(s) to use")
set_property(CACHE CEN64_ARCH_SUPPORT PROPERTY STRINGS Native AVX SSE4.1 SSSE3 SSE3 SSE2)
if (${CEN64_ARCH_SUPPORT} MATCHES "SSE2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mssse3")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse3")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE4.1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse4")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "AVX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mavx")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "Native")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=native")
endif ()
set(CEN64_ARCH_DIR "x86_64")
include_directories(${PROJECT_SOURCE_DIR}/os/unix/x86_64)
endif (${CLANG_MACHINE} MATCHES "x86.*" OR ${CLANG_MACHINE} MATCHES "i.86.*")
if (${CLANG_MACHINE} STREQUAL "arm")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=hard -mfpu=neon")
set(CEN64_ARCH_DIR "arm")
include_directories(${PROJECT_SOURCE_DIR}/os/unix/arm)
endif (${CLANG_MACHINE} STREQUAL "arm")
# Set architecture-independent flags.
set(CMAKE_C_FLAGS_DEBUG "-ggdb3 -g3 -O0")
set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -DNDEBUG -ggdb3 -g3")
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "-s")
set(CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "-s")
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
endif (${CMAKE_C_COMPILER_ID} MATCHES Clang)
# If using ICC, configure it accordingly.
if (${CMAKE_C_COMPILER_ID} MATCHES Intel)
set(CMAKE_C_FLAGS "-Wall -Wno-unused-parameter -std=c99")
set(CEN64_ARCH_SUPPORT "Native" CACHE STRING "Architectural extension(s) to use")
set_property(CACHE CEN64_ARCH_SUPPORT PROPERTY STRINGS Native SSE4.1 SSSE3 SSE3 SSE2)
if (${CEN64_ARCH_SUPPORT} MATCHES "SSE2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xSSE2")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xSSSE3")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xSSE3")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE4.1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xSSE4.1")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "AVX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xAVX")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "Native")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xHost")
endif ()
set(CEN64_ARCH_DIR "x86_64")
include_directories(${PROJECT_SOURCE_DIR}/os/unix/x86_64)
# Set architecture-independent flags.
set(CMAKE_C_FLAGS_DEBUG "-g3 -O0")
set(CMAKE_C_FLAGS_MINSIZEREL "-Os -DNDEBUG -ipo -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG -ipo -ffunction-sections -fdata-sections")
set(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -DNDEBUG -ggdb3 -g3 -ipo -ffunction-sections -fdata-sections")
set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
endif (${CMAKE_C_COMPILER_ID} MATCHES Intel)
# If using MSVC, configure it accordingly.
if (MSVC)
set(CEN64_ARCH_SUPPORT "SSE2" CACHE STRING "Architectural extension(s) to use")
set_property(CACHE CEN64_ARCH_SUPPORT PROPERTY STRINGS AVX SSE4.1 SSSE3 SSE3 SSE2)
if (${CEN64_ARCH_SUPPORT} MATCHES "SSE2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D__SSE2__")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D__SSE2__ /D__SSE3__ /D__SSSE3__")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE3")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D__SSE2__ /D__SSE3__")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "SSE4.1")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D__SSE2__ /D__SSE3__ /D__SSSE3__ /D__SSE4_1__")
elseif (${CEN64_ARCH_SUPPORT} MATCHES "AVX")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D__SSE2__ /D__SSE3__ /D__SSSE3__ /D__SSE4_1__ /arch:AVX")
endif ()
enable_language(ASM_MASM) # Are you kidding me? Really?
file(GLOB ASM_SOURCES ${PROJECT_SOURCE_DIR}/os/windows/x86_64/fpu/*.asm)
set(CEN64_ARCH_DIR "x86_64")
include_directories(${PROJECT_SOURCE_DIR}/os/windows/x86_64)
endif (MSVC)
# Print out MMIO register accesses?
option(DEBUG_MMIO_REGISTER_ACCESS "Print message on each MMIO register access?" OFF)
# Use VR4300's busy-wait-detection feature?
option(VR4300_BUSY_WAIT_DETECTION "Detect and special case VR4300 busy wait loops?" ON)
# Build RelWithDebInfo by default so builds are fast out of the box
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
endif(NOT CMAKE_BUILD_TYPE)
# Glob all the files together.
include_directories(${PROJECT_BINARY_DIR})
include_directories(${PROJECT_SOURCE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/arch/${CEN64_ARCH_DIR})
include_directories(${PROJECT_SOURCE_DIR}/os/common)
include_directories(${ICONV_INCLUDE_DIR})
include_directories(${OPENAL_INCLUDE_DIR})
include_directories(${OPENGL_INCLUDE_DIR})
#
# Create lists of files.
#
set(AI_SOURCES
${PROJECT_SOURCE_DIR}/ai/context.c
${PROJECT_SOURCE_DIR}/ai/controller.c
)
set(ARCH_X86_64_SOURCES
${PROJECT_SOURCE_DIR}/arch/x86_64/tlb/tlb.c
${PROJECT_SOURCE_DIR}/arch/x86_64/rsp/vrcpsq.c
${PROJECT_SOURCE_DIR}/arch/x86_64/rsp/vmov.c
${PROJECT_SOURCE_DIR}/arch/x86_64/rsp/vdivh.c
${PROJECT_SOURCE_DIR}/arch/x86_64/rsp/rsp.c
${PROJECT_SOURCE_DIR}/arch/x86_64/rsp/vrsq.c
${PROJECT_SOURCE_DIR}/arch/x86_64/rsp/transpose.c
)
set(BUS_SOURCES
${PROJECT_SOURCE_DIR}/bus/controller.c
${PROJECT_SOURCE_DIR}/bus/memorymap.c
)
set(COMMON_SOURCES
${PROJECT_SOURCE_DIR}/common/debug.c
${PROJECT_SOURCE_DIR}/common/one_hot.c
${PROJECT_SOURCE_DIR}/common/reciprocal.c
)
set(DD_SOURCES
${PROJECT_SOURCE_DIR}/dd/controller.c
)
set(DEVICE_SOURCES
${PROJECT_SOURCE_DIR}/cen64.c
${PROJECT_SOURCE_DIR}/device/cart_db.c
${PROJECT_SOURCE_DIR}/device/device.c
${PROJECT_SOURCE_DIR}/device/netapi.c
${PROJECT_SOURCE_DIR}/device/options.c
${PROJECT_SOURCE_DIR}/device/sha1.c
)
set(OS_SOURCES
${PROJECT_SOURCE_DIR}/os/common/gl_hints.c
${PROJECT_SOURCE_DIR}/os/common/input.c
)
set(OS_POSIX_SOURCES
${PROJECT_SOURCE_DIR}/os/posix/alloc.c
${PROJECT_SOURCE_DIR}/os/posix/cpuid.c
${PROJECT_SOURCE_DIR}/os/posix/local_time.c
${PROJECT_SOURCE_DIR}/os/posix/main.c
${PROJECT_SOURCE_DIR}/os/posix/rom_file.c
${PROJECT_SOURCE_DIR}/os/posix/save_file.c
${PROJECT_SOURCE_DIR}/os/posix/timer.c
)
set(OS_WINAPI_SOURCES
${PROJECT_SOURCE_DIR}/os/winapi/alloc.c
${PROJECT_SOURCE_DIR}/os/winapi/cpuid.c
${PROJECT_SOURCE_DIR}/os/winapi/gl_config.c
${PROJECT_SOURCE_DIR}/os/winapi/gl_window.c
${PROJECT_SOURCE_DIR}/os/winapi/local_time.c
${PROJECT_SOURCE_DIR}/os/winapi/main.c
${PROJECT_SOURCE_DIR}/os/winapi/rom_file.c
${PROJECT_SOURCE_DIR}/os/winapi/save_file.c
${PROJECT_SOURCE_DIR}/os/winapi/timer.c
)
set(OS_X11_SOURCES
${PROJECT_SOURCE_DIR}/os/x11/gl_config.c
${PROJECT_SOURCE_DIR}/os/x11/gl_window.c
)
set(PI_SOURCES
${PROJECT_SOURCE_DIR}/pi/controller.c
${PROJECT_SOURCE_DIR}/pi/is_viewer.c
)
set(RDP_SOURCES
${PROJECT_SOURCE_DIR}/rdp/cpu.c
${PROJECT_SOURCE_DIR}/rdp/interface.c
${PROJECT_SOURCE_DIR}/rdp/n64video.c
)
set(RI_SOURCES
${PROJECT_SOURCE_DIR}/ri/controller.c
)
set(RSP_SOURCES
${PROJECT_SOURCE_DIR}/rsp/cp0.c
${PROJECT_SOURCE_DIR}/rsp/cp2.c
${PROJECT_SOURCE_DIR}/rsp/cpu.c
${PROJECT_SOURCE_DIR}/rsp/decoder.c
${PROJECT_SOURCE_DIR}/rsp/functions.c
${PROJECT_SOURCE_DIR}/rsp/interface.c
${PROJECT_SOURCE_DIR}/rsp/opcodes.c
${PROJECT_SOURCE_DIR}/rsp/pipeline.c
${PROJECT_SOURCE_DIR}/rsp/vfunctions.c
)
set(SI_SOURCES
${PROJECT_SOURCE_DIR}/si/cic.c
${PROJECT_SOURCE_DIR}/si/controller.c
${PROJECT_SOURCE_DIR}/si/pak.c
${PROJECT_SOURCE_DIR}/si/pak_transfer.c
${PROJECT_SOURCE_DIR}/si/gb.c
${PROJECT_SOURCE_DIR}/si/rtc.c
)
set(VI_SOURCES
${PROJECT_SOURCE_DIR}/vi/controller.c
${PROJECT_SOURCE_DIR}/vi/render.c
${PROJECT_SOURCE_DIR}/vi/window.c
)
set(VR4300_SOURCES
${PROJECT_SOURCE_DIR}/vr4300/cp0.c
${PROJECT_SOURCE_DIR}/vr4300/cp1.c
${PROJECT_SOURCE_DIR}/vr4300/cpu.c
${PROJECT_SOURCE_DIR}/vr4300/dcache.c
${PROJECT_SOURCE_DIR}/vr4300/decoder.c
${PROJECT_SOURCE_DIR}/vr4300/fault.c
${PROJECT_SOURCE_DIR}/vr4300/functions.c
${PROJECT_SOURCE_DIR}/vr4300/icache.c
${PROJECT_SOURCE_DIR}/vr4300/interface.c
${PROJECT_SOURCE_DIR}/vr4300/opcodes.c
${PROJECT_SOURCE_DIR}/vr4300/pipeline.c
${PROJECT_SOURCE_DIR}/vr4300/segment.c
)
#
# Build OS_SOURCES list.
#
if (DEFINED WIN32)
include_directories(${PROJECT_SOURCE_DIR}/os/winapi)
set(EXTRA_OS_EXE WIN32)
if (NOT MSVC)
set(EXTRA_OS_LIBS mingw32 opengl32 winmm ws2_32)
else ()
set(EXTRA_OS_LIBS opengl32 winmm ws2_32)
endif ()
list(APPEND OS_SOURCES
${OS_COMMON_SOURCES}
${OS_WINAPI_SOURCES}
)
else ()
include_directories(${PROJECT_SOURCE_DIR}/os/posix)
include_directories(${PROJECT_SOURCE_DIR}/os/x11)
include_directories(${X11_xf86vmode_INCLUDE_PATH})
list(APPEND OS_SOURCES
${OS_COMMON_SOURCES}
${OS_POSIX_SOURCES}
${OS_X11_SOURCES}
)
endif (DEFINED WIN32)
#
# Glob all the files together.
#
if (DEFINED UNIX)
find_package(X11 REQUIRED)
if (${CMAKE_C_COMPILER_ID} MATCHES GNU OR ${CMAKE_C_COMPILER_ID} MATCHES Clang OR ${CMAKE_C_COMPILER_ID} MATCHES Intel)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -D_POSIX_C_SOURCE=200112L -D_BSD_SOURCE -D_DEFAULT_SOURCE")
endif (${CMAKE_C_COMPILER_ID} MATCHES GNU OR ${CMAKE_C_COMPILER_ID} MATCHES Clang OR ${CMAKE_C_COMPILER_ID} MATCHES Intel)
endif (DEFINED UNIX)
#
# Configure the common header.
#
configure_file(
"${PROJECT_SOURCE_DIR}/common.h.in"
"${PROJECT_BINARY_DIR}/common.h"
)
#
# Create the executable.
#
if (NOT MSVC)
set_source_files_properties(${PROJECT_SOURCE_DIR}/rdp/n64video.c PROPERTIES COMPILE_FLAGS -fno-strict-aliasing)
endif (NOT MSVC)
add_executable(cen64
${EXTRA_OS_EXE}
${ASM_SOURCES}
${AI_SOURCES}
${ARCH_X86_64_SOURCES}
${BUS_SOURCES}
${COMMON_SOURCES}
${DD_SOURCES}
${DEVICE_SOURCES}
${OS_SOURCES}
${PI_SOURCES}
${RDP_SOURCES}
${RI_SOURCES}
${RSP_SOURCES}
${SI_SOURCES}
${VI_SOURCES}
${VR4300_SOURCES}
)
target_link_libraries(cen64
${EXTRA_OS_LIBS}
${OPENAL_LIBRARY}
${OPENGL_gl_LIBRARY}
${ICONV_LIBRARIES}
${X11_X11_LIB}
${CMAKE_THREAD_LIBS_INIT}
)
./README.md 0000644 0001750 0001750 00000012126 13706454531 010572 0 ustar dan dan
# Just give me a copy!
* Windows: https://www.cen64.com/uploads/stable/cen64-windows-x86_64.exe
* Linux: https://www.cen64.com/uploads/stable/cen64-debian9-x86_64
* Mac: It works, but unfortunately you have to build it yourself for now.
Buildbot: https://github-buildbot.cen64.com/builders
# About
Yes, _another_ Nintendo 64 emulator. This one, however, aims for _perfect_
emulation by emulating the hardware inside of the Nintendo 64 itself, down
to the register-transfer level (RTL). At the same time, I've tried to keep
things as optimized as possible in hopes that CEN64 will someday run ROMs at
full speed, even on modest systems.
# Why?
CEN64 is my pet project. It's something I pick up whenever I get bored. To me,
what Nintendo and SGI did with this console is nothing short of amazing. The
ingenuity and design of the hardware was well-ahead of it's time, and it is
an absolute blast to reverse-engineer and study. I started this project in
order to learn more about what _really_ went on at the hardware level back in
the (good old) days.
Thank you to every single one of you developers for filling my childhood
with excellent memories. I'd also like to thank the community on all their
hard work and effort spent reverse-engineering this little gem. Without
further ado... "Get N or get out"!
# Development
If you want to contribute, please do! Pull requests are most certainly
welcome. Feel free to add yourself to the CONTRIBUTORS file as well.
# Keyboard controls
* 3D stick: arrow keys (hold shift to "walk")
* A button: X
* B button: C
* Z button: Z
* Start button: enter
* L/R buttons: A/S
* C-pad: TFGH
* D-pad: IJKL
# Build requirements
* CMake
* iconv
* OpenAL
* OpenGL
To build on Fedora 29, do: `sudo dnf install cmake make mesa-libGL-devel openal-soft-devel`
To build for Windows on Fedora 29, do: `sudo dnf install cmake make mingw64-{gcc,iconv,openal}`
To build for Windows on Windows XP..10, do:
1. Install MSYS 1.0.11: https://sourceforge.net/projects/mingw/files/MSYS/Base/msys-core/msys-1.0.11/MSYS-1.0.11.exe/download
* Say yes to post install
* Say no to mingw is installed
* Press enter a few times to finish the install
2. Extract contents of "mingw64" directory to "MSYS\mingw" directory: https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/seh/x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z
3. Copy "MSYS\mingw\bin\mingw32-make.exe" to "MSYS\mingw\bin\make.exe"
4. Extract OpenAL "bin, libs, include" directories to "MSYS\mingw\x86_64-w64-mingw32" directory: https://kcat.strangesoft.net/openal-binaries/openal-soft-1.19.1-bin.zip
5. Extract iconv to "MSYS\home\yourname\libiconv" directory: https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz
6. Run MSYS & type "cd libiconv" Enter, followed by "./configure --disable-shared" Enter, followed by "make install" Enter
7. Extract CMake "bin, doc, man, share" directories to "MSYS" directory: https://github.com/Kitware/CMake/releases/download/v3.13.4/cmake-3.13.4-win64-x64.zip
8. Extract CEN64 source to "MSYS\home\yourname\cen64" directory: https://github.com/n64dev/cen64
9. Run MSYS & type "cd cen64" Enter, followed by "cmake-gui" Enter
10. Add the "MSYS/home/yourname/cen64" directory to "Browse Source..." & "Browse Build...", then Generate MSYS compatible files:
* Add OpenAL "MSYS/mingw/x86_64-w64-mingw32/include/AL" as "OPENAL/OPENAL_INCLUDE_DIR" & "MSYS/mingw/x86_64-w64-mingw32/lib/libOpenAL32.dll.a" as "OPENAL/OPENAL_LIBRARY" (if they are not found)
* Make sure to use libiconv static lib (Not DLL) "MSYS/local/lib/libiconv.a" as "ICONV/ICONV_LIBRARIES"
* Select "SSE4.1" or "AVX" as "Ungrouped Entries/CEN64_ARCH_SUPPORT" & make sure VR4300_BUSY_WAIT_DETECTION is ticked
11. Click "Configure" then click "Generate" to get the makefiles, then quit cmake-gui, & type "make" Enter
# Usage
* How do I run cen64?
You will need a valid pifdata.bin file (NTSC or PAL), & a ROM in .z64 format (in big-endian format).
To run cen64 without multithreading (slower):
cen64 pifdata.bin ROM.z64
To run cen64 with multithreading (faster):
cen64 -multithread pifdata.bin ROM.z64
* How do I run 64DD games?
You will need a valid 64ddipl.bin file (NTSC JPN or USA), & a 64DD disk image file in .ndd format.
cen64 -ddipl 64ddipl.bin -ddrom DISK.ndd pifdata.bin
* How do I setup save files for games?
N64 has various types of save formats used in games...
You will need to specify the save type yourself, cen64 will create the file if it does not exist.
EEP4K:
cen64 -eep4k eep4k.bin pifdata.bin ROM.z64
EEP16K:
cen64 -eep16k eep16k.bin pifdata.bin ROM.z64
FLASH:
cen64 -flash flash.bin pifdata.bin ROM.z64
SRAM:
cen64 -sram sram.bin pifdata.bin ROM.z64
* The game runs, but I get strange errors, like multiple ocarinas in Majora's Mask.
You can fix the issue by using the -flash option on the command line:
cen64 -flash flash.bin pifdata.bin majora.z64
./vr4300/ 0000755 0001750 0001750 00000000000 13706454531 010247 5 ustar dan dan ./vr4300/decoder.h 0000644 0001750 0001750 00000002450 13262010135 012007 0 ustar dan dan //
// vr4300/decoder.h: VR4300 decoder.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef __vr4300_decoder_h__
#define __vr4300_decoder_h__
#include "common.h"
#include "vr4300/opcodes.h"
#define GET_RS(iw) ((iw) >> 21 & 0x1F)
#define GET_RT(iw) ((iw) >> 16 & 0x1F)
#define GET_RD(iw) ((iw) >> 11 & 0x1F)
#define GET_FS(iw) (((iw) >> 11 & 0x1F) + VR4300_REGISTER_CP1_0)
#define GET_FT(iw) (((iw) >> 16 & 0x1F) + VR4300_REGISTER_CP1_0)
#define GET_FD(iw) (((iw) >> 6 & 0x1F) + VR4300_REGISTER_CP1_0)
#define GET_FMT(iw) ((iw) >> 21 & 0x1F)
#define OPCODE_INFO_NONE (0)
#define OPCODE_INFO_FPU (1U << 2)
#define OPCODE_INFO_BRANCH (1U << 31)
#define OPCODE_INFO_NEEDRS (1U << 3)
#define OPCODE_INFO_NEEDFS ((1U << 3) | (1U << 0))
#define OPCODE_INFO_NEEDRT (1U << 4)
#define OPCODE_INFO_NEEDFT ((1U << 4) | (1U << 1))
#define OPCODE_INFO_LOAD (1U << 5)
#define OPCODE_INFO_STORE (1U << 6)
enum vr4300_fmt {
VR4300_FMT_S = 16,
VR4300_FMT_D = 17,
VR4300_FMT_W = 20,
VR4300_FMT_L = 21,
};
struct vr4300_opcode {
uint32_t id;
uint32_t flags;
};
cen64_hot const struct vr4300_opcode* vr4300_decode_instruction(uint32_t);
#endif
./vr4300/segment.c 0000644 0001750 0001750 00000020554 13262010135 012044 0 ustar dan dan //
// vr4300/segment.c: VR4300 MMU segment manager.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "common.h"
#include "vr4300/segment.h"
//
// Note: sseg, ksseg, kseg0, kseg1, and kseg3 do not appear below.
//
// As stated on pages 128, 130, and 134 of the "NEC VR43xx
// Microprocessor User's Manual": "The VR4300 internally uses 64-bit
// addresses. In the 32-bit mode, a 32-bit value with bits 32 through
// 63 sign-extended is used an address."
//
cen64_align(static const struct segment USEGs[], CACHE_LINE_SIZE) = {
/* useg, suseg, kuseg. */ {
0x0000000000000000ULL, /* start */
0x0000000080000000ULL, /* length */
0x0000000000000000ULL, /* offset */
0x20, /* ux mask */
true, /* mapped */
true, /* cached */
/* xuseg, xsuseg, xkuseg. */ }, {
0x0000000000000000ULL, /* start */
0x0000010000000000ULL, /* length */
0x0000000000000000ULL, /* offset */
0x20, /* ux mask */
true, /* mapped */
true, /* cached */
}};
/* xsseg, xksseg. */
static const struct segment XSSEG = {
0x4000000000000000ULL, /* start */
0x0000010000000000ULL, /* length */
0x0000000000000000ULL, /* offset */
0x40, /* sx mask */
true, /* mapped */
true, /* cached */
};
cen64_align(static const struct segment KSEGs[], CACHE_LINE_SIZE) = {
/* (c)kseg0. */ {
0xFFFFFFFF80000000ULL, /* start */
0x0000000020000000ULL, /* length */
0xFFFFFFFF80000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
/* (c)kseg1. */ }, {
0xFFFFFFFFA0000000ULL, /* start */
0x0000000020000000ULL, /* length */
0xFFFFFFFFA0000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
false, /* cached */
/* (c)sseg, (c)ksseg. */ }, {
0xFFFFFFFFC0000000ULL, /* start */
0x0000000020000000ULL, /* length */
0x0000000000000000ULL, /* offset */
0x80, /* kx mask */
true, /* mapped */
true, /* cached */
/* (c)kseg3. */ }, {
0xFFFFFFFFE0000000ULL, /* start */
0x0000000020000000ULL, /* length */
0x0000000000000000ULL, /* offset */
0x80, /* kx mask */
true, /* mapped */
true, /* cached */
}};
static const struct segment XKSEG = {
0xC000000000000000ULL, /* start */
0x0000010000000000ULL, /* length */
0x0000000000000000ULL, /* offset */
0x80, /* kx mask */
true, /* mapped */
true, /* cached */
};
static const struct segment XKPHYS0 = {
0x8000000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0x8000000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
};
static const struct segment XKPHYS1 = {
0x8800000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0x8800000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
};
static const struct segment XKPHYS2 = {
0x9000000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0x9000000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
false, /* cached */
};
static const struct segment XKPHYS3 = {
0x9800000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0x9800000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
};
static const struct segment XKPHYS4 = {
0xA000000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0xA000000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
};
static const struct segment XKPHYS5 = {
0xA800000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0xA800000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
};
static const struct segment XKPHYS6 = {
0xB000000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0xB000000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
};
static const struct segment XKPHYS7 = {
0xB800000000000000ULL, /* start */
0x0000000100000000ULL, /* length */
0xB800000000000000ULL, /* offset */
0x80, /* kx mask */
false, /* mapped */
true, /* cached */
};
static const struct segment *kernel_segs_lut[16] = {
&XKPHYS0,
&XKPHYS1,
&XKPHYS2,
&XKPHYS3,
&XKPHYS4,
&XKPHYS5,
&XKPHYS6,
&XKPHYS7,
&XKSEG,
&XKSEG,
&XKSEG,
&XKSEG,
&XKSEG,
&XKSEG,
&XKSEG,
&XKSEG,
};
// Returns a default segment that should cause
// a cached segment miss and result in a lookup.
const struct segment* get_default_segment(void) {
static const struct segment default_segment = {
1ULL,
0ULL,
0ULL,
0x0,
false,
false,
};
return &default_segment;
}
// Returns the segment given a CP0 status register and a virtual address.
const struct segment* get_segment(uint64_t address, uint32_t cp0_status) {
const struct segment *seg;
// LUT used to determine if we're in a 64-bit mode or not.
// i.e., if we're in supervisor mode, is the ux bit set?
cen64_align(static const uint8_t segment_mode_lut[256], CACHE_LINE_SIZE) = {
#define _ sizeof(*seg)
/*ks:sx:ux | k k k k, s, k, k, k, u, k, k, k, ?, k, k, k */
/* 0: 0: 0 |*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* 0: 0: 1 |*/ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,_,_,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* 0: 1: 0 |*/ 0,0,0,0,0,0,0,0,_,_,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* 0: 1: 1 |*/ 0,0,0,0,0,0,0,0,_,_,0,0,0,0,0,0,_,_,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
/* 1: 0: 0 |*/ _,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,0,0,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
/* 1: 0: 1 |*/ _,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
/* 1: 1: 0 |*/ _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
/* 1: 1: 1 |*/ _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0,0,_,_,_,_,_,_,
#undef _
};
unsigned segment_mode = segment_mode_lut[cp0_status & 0xFF];
unsigned mode_and_flags_mask = cp0_status & 0x1E;
#ifndef NDEBUG
uint64_t sexaddress = (int64_t) ((int32_t) address);
char kernel = (cp0_status & 0x6) || ((cp0_status & 0x18) == 0);
char supervisor = ((cp0_status & 0x6) == 0) && ((cp0_status & 0x18) == 0x8);
char user = ((cp0_status & 0x6) == 0) && ((cp0_status & 0x18) == 0x10);
char use_kx = kernel && (cp0_status & 0x80);
char use_sx = supervisor && (cp0_status & 0x40);
char use_ux = user && (cp0_status & 0x20);
char use_64 = use_kx | use_sx | use_ux;
// Ensure that only one of {kernel, supervisor, user} are produced.
assert(((kernel + supervisor + user) == 1) && "Impossible situation.");
// Ensure that either 64-bit mode is used, or the address is sign-extended.
assert((use_64 || (sexaddress == address)) && "Invalid 32-bit address.");
#endif
// Check for useg/suseg/kuseg or xuseg/xsuseg/xkuseg first.
seg = (const struct segment *) ((uintptr_t) USEGs + segment_mode);
if (address < seg->length)
return seg;
// If we're not in user mode...
else if (mode_and_flags_mask != 0x10) {
seg = &KSEGs[2];
// Assume we're csseg and check for xsseg/xksseg.
if ((address >> 40) == 0x400000)
return &XSSEG;
// If we're in kernel mode, check for ckseg0, ckseg1, and ckseg3.
else if (mode_and_flags_mask != 0x08) {
if (address >= KSEGs[0].start)
return KSEGs + (address >> 29 & 0x3);
// Check for xkseg and xkphys.
else if ((address - XKPHYS0.start) < 0x400000FF80000000ULL)
seg = kernel_segs_lut[address >> 59 & 0xF];
}
// Check matching segment or return invalid.
if (likely((address - seg->start) < seg->length))
return seg;
}
return NULL;
}
./vr4300/pipeline.c 0000644 0001750 0001750 00000041563 13706454531 012231 0 ustar dan dan //
// vr4300/pipeline.c: VR4300 processor pipeline.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "common.h"
#include "bus/controller.h"
#include "vr4300/cp0.h"
#include "vr4300/cpu.h"
#include "vr4300/decoder.h"
#include "vr4300/fault.h"
#include "vr4300/opcodes.h"
#include "vr4300/pipeline.h"
#include "vr4300/segment.h"
typedef void (*pipeline_function)(struct vr4300 *vr4300);
cen64_cold static void vr4300_cycle_slow_wb(struct vr4300 *vr4300);
cen64_cold static void vr4300_cycle_slow_dc(struct vr4300 *vr4300);
static void vr4300_cycle_slow_ex(struct vr4300 *vr4300);
static void vr4300_cycle_slow_rf(struct vr4300 *vr4300);
static void vr4300_cycle_slow_ic(struct vr4300 *vr4300);
static void vr4300_cycle_busywait(struct vr4300 *vr4300);
// Prints out instructions and their virtual address as they are executed.
// Note: Some of these instructions _may_ be speculative and killed later...
//#define PRINT_EXEC
// Instruction cache stage.
cen64_flatten static void vr4300_ic_stage(struct vr4300 *vr4300) {
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
const struct segment *segment = icrf_latch->segment;
struct vr4300_opcode *opcode = &rfex_latch->opcode;
uint64_t pc = icrf_latch->pc;
uint32_t decode_iw;
// Finish decoding instruction in RF.
decode_iw = rfex_latch->iw &= rfex_latch->iw_mask;
*opcode = *vr4300_decode_instruction(decode_iw);
rfex_latch->iw_mask = ~0U;
// Latch common pipeline values.
icrf_latch->common.pc = pc;
icrf_latch->pc = pc + 4;
// If decoding of prior instruction indicates this is a BD slot...
icrf_latch->common.cause_data = (opcode->flags & OPCODE_INFO_BRANCH);
// Look up the segment that we're in.
if ((pc - segment->start) >= segment->length) {
uint32_t cp0_status = vr4300->regs[VR4300_CP0_REGISTER_STATUS];
if (unlikely((segment = get_segment(pc, cp0_status)) == NULL))
VR4300_IADE(vr4300);
// Next stage gets killed either way, so we can safely
// latch a faulty segment and not worry about it.
icrf_latch->segment = segment;
}
}
// Register fetch and decode stage.
static int vr4300_rf_stage(struct vr4300 *vr4300) {
const struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
const struct segment *segment = icrf_latch->segment;
const struct vr4300_icache_line *line;
uint64_t vaddr = icrf_latch->common.pc;
uint32_t paddr;
bool cached;
rfex_latch->common = icrf_latch->common;
// If we're in a mapped region, do a TLB translation.
paddr = vaddr - segment->offset;
cached = segment->cached;
if (segment->mapped) {
unsigned asid = vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI] & 0xFF;
unsigned select, tlb_miss, index;
uint32_t page_mask;
tlb_miss = tlb_probe(&vr4300->cp0.tlb, vaddr, asid, &index);
page_mask = vr4300->cp0.page_mask[index];
select = ((page_mask + 1) & vaddr) != 0;
if (unlikely(tlb_miss || !(vr4300->cp0.state[index][select] & 2))) {
VR4300_ITLB(vr4300, tlb_miss);
return 1;
}
cached = (vr4300->cp0.state[index][select] & 0x38) != 0x10;
paddr = (vr4300->cp0.pfn[index][select]) | (vaddr & page_mask);
}
// If not cached or we miss in the IC, it's an ICB.
line = vr4300_icache_probe(&vr4300->icache, vaddr, paddr);
if (!(line && cached)) {
rfex_latch->paddr = paddr;
rfex_latch->cached = cached;
VR4300_ICB(vr4300);
return 1;
}
memcpy(&rfex_latch->iw, line->data + (paddr & 0x1C),
sizeof(rfex_latch->iw));
return 0;
}
// Execution stage.
static int vr4300_ex_stage(struct vr4300 *vr4300) {
const struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
const struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
uint32_t cp0_status = vr4300->regs[VR4300_CP0_REGISTER_STATUS];
unsigned rs, rt, rslutidx, rtlutidx;
uint64_t rs_reg, rt_reg, temp;
uint32_t flags, iw;
exdc_latch->common = rfex_latch->common;
flags = rfex_latch->opcode.flags;
iw = rfex_latch->iw;
rs = GET_RS(iw);
rt = GET_RT(iw);
if (flags & OPCODE_INFO_FPU) {
cen64_align(static const unsigned fpu_select_lut[2], 8) = {21, 11};
unsigned fr;
// Dealing with FPU state, is CP1 usable?
if (unlikely(!(cp0_status & 0x20000000U))) {
VR4300_CPU(vr4300);
return 1;
}
// Check if one of the sources is an FPU register. Furthermore,
// if Status.FR bit is clear, we depend on even registers only.
fr = (cp0_status >> 26 & 0x1) ^ 0x1;
rtlutidx = flags & 0x2;
rslutidx = flags & 0x1;
rs = (iw >> fpu_select_lut[rslutidx] & 0x1F) | (rslutidx << 6);
rt |= (rtlutidx << 5);
rs &= ~((rslutidx) & fr);
rt &= ~((rtlutidx >> 1) & fr);
}
// Check to see if we should hold off execution due to a LDI.
// MIPS compilers generally optimize this out, so flag as unlikely.
if (unlikely(exdc_latch->request.type == VR4300_BUS_REQUEST_READ && (
((exdc_latch->dest == rs) && (flags & OPCODE_INFO_NEEDRS)) ||
((exdc_latch->dest == rt) && (flags & OPCODE_INFO_NEEDRT))))) {
VR4300_LDI(vr4300);
return 1;
}
// No LDI, so we just need to forward results from DC/WB.
// This is done to preserve RF state and fwd without branching.
temp = vr4300->regs[dcwb_latch->dest];
vr4300->regs[dcwb_latch->dest] = dcwb_latch->result;
vr4300->regs[VR4300_REGISTER_R0] = 0x0000000000000000ULL;
rs_reg = vr4300->regs[rs];
rt_reg = vr4300->regs[rt];
vr4300->regs[dcwb_latch->dest] = temp;
// Finally, execute the instruction.
#ifdef PRINT_EXEC
debug("%.16llX: %s\n", (unsigned long long) rfex_latch->common.pc,
vr4300_opcode_mnemonics[rfex_latch->opcode.id]);
#endif
if (vr4300->profile_samples) {
uint32_t idx = rfex_latch->common.pc - 0x80000000;
idx &= (8 * 1024 * 1024) - 1;
vr4300->profile_samples[idx]++;
}
exdc_latch->dest = VR4300_REGISTER_R0;
exdc_latch->request.type = VR4300_BUS_REQUEST_NONE;
return vr4300_function_table[rfex_latch->opcode.id](
vr4300, iw, rs_reg, rt_reg);
}
// Data cache fetch stage.
static int vr4300_dc_stage(struct vr4300 *vr4300) {
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
uint32_t cp0_status = vr4300->regs[VR4300_CP0_REGISTER_STATUS];
uint32_t cp0_cause = vr4300->regs[VR4300_CP0_REGISTER_CAUSE];
const struct segment *segment = exdc_latch->segment;
bool cached;
dcwb_latch->common = exdc_latch->common;
dcwb_latch->result = exdc_latch->result;
dcwb_latch->dest = exdc_latch->dest;
// The reset exception has a very high priority and will abort basically
// anything that's active, even if we have an interlock or something that's
// current active. Thus, we check for it here and handle it early.
if (unlikely(vr4300->signals & VR4300_SIGNAL_COLDRESET)) {
VR4300_RST(vr4300);
return 1;
}
// Check if we should raise an interrupt (and effectively kill this insn).
if (unlikely(cp0_cause & cp0_status & 0xFF00 &&
(((cp0_status ^ 6) & 0x7) == 0x7))) {
VR4300_INTR(vr4300);
return 1;
}
// Look up the segment that we're in.
if (exdc_latch->request.type != VR4300_BUS_REQUEST_NONE) {
struct vr4300_bus_request *request = &exdc_latch->request;
uint64_t vaddr = exdc_latch->request.vaddr;
struct vr4300_dcache_line *line;
uint32_t paddr;
if ((vaddr - segment->start) >= segment->length) {
if (unlikely((segment = get_segment(vaddr, cp0_status)) == NULL)) {
VR4300_DADE(vr4300);
return 1;
}
exdc_latch->segment = segment;
}
// If we're in a mapped region, do a TLB translation.
paddr = vaddr - segment->offset;
cached = segment->cached;
if (segment->mapped) {
unsigned asid = vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI] & 0xFF;
unsigned select, tlb_inv, tlb_miss, tlb_mod, index;
uint32_t page_mask;
tlb_miss = tlb_probe(&vr4300->cp0.tlb, vaddr, asid, &index);
page_mask = vr4300->cp0.page_mask[index];
select = ((page_mask + 1) & vaddr) != 0;
tlb_inv = !(vr4300->cp0.state[index][select] & 2);
tlb_mod = !(vr4300->cp0.state[index][select] & 4) &&
request->type == VR4300_BUS_REQUEST_WRITE;
if (unlikely(tlb_miss | tlb_inv | tlb_mod)) {
VR4300_DTLB(vr4300, tlb_miss, tlb_inv, tlb_mod);
return 1;
}
cached = ((vr4300->cp0.state[index][select] & 0x38) != 0x10);
paddr = (vr4300->cp0.pfn[index][select]) | (vaddr & page_mask);
}
// Check to see if we should raise a WAT exception.
if (unlikely((paddr & ~0x80000007U) == (vr4300->regs[
VR4300_CP0_REGISTER_WATCHLO] & ~0x80000007U))) {
// We hit the address, just check load/store.
// TODO: Postposted if EXL bit is set.
if (vr4300->regs[VR4300_CP0_REGISTER_WATCHLO] & request->type & 0x3) {
VR4300_WAT(vr4300);
return 1;
}
}
// If not cached or we miss in the DC, it's an DCM.
if (likely(exdc_latch->request.type < VR4300_BUS_REQUEST_CACHE)) {
uint64_t dword, rtemp, wtemp, wdqm;
unsigned shiftamt, rshiftamt, lshiftamt;
uint32_t s_paddr;
line = vr4300_dcache_probe(&vr4300->dcache, vaddr, paddr);
if (cached) {
bool last_cache_was_store = dcwb_latch->last_op_was_cache_store;
dcwb_latch->last_op_was_cache_store = (exdc_latch->request.type ==
VR4300_BUS_REQUEST_WRITE);
if (!line) {
request->paddr = paddr;
exdc_latch->cached = cached;
// Miss: stall for one cycle, then move to the DCM phase.
vr4300->pipeline.cycles_to_stall = 0;
vr4300->regs[PIPELINE_CYCLE_TYPE] = 6;
return 1;
}
// Cached store-to-cached operation will result in a DCB.
if (last_cache_was_store) {
VR4300_DCB(vr4300);
return 1;
}
}
else {
dcwb_latch->last_op_was_cache_store = false;
request->paddr = paddr;
exdc_latch->cached = cached;
VR4300_DCM(vr4300);
return 1;
}
s_paddr = paddr << 3;
paddr &= 0x8;
// Pull out the cache line data, mux stuff around
// to produce the output/update the cache line.
memcpy(&dword, line->data + paddr, sizeof(dword));
shiftamt = (s_paddr ^ (WORD_ADDR_XOR << 3)) & request->access_type;
rshiftamt = (8 - request->size) << 3;
lshiftamt = (s_paddr & (0x7 << 3));
wdqm = request->wdqm << shiftamt;
wtemp = (request->data << shiftamt) & wdqm;
rtemp = ((int64_t) (dword << lshiftamt)
>> rshiftamt) & request->data;
dword = (dword & ~wdqm) | wtemp;
dcwb_latch->result |= rtemp << request->postshift;
memcpy(line->data + paddr, &dword, sizeof(dword));
// We need to mark the line dirty if it's write.
// Fortunately, metadata & 0x2 == dirty, and
// metadata 0x1 == valid. Our requests values are
// read (0x1) and write (0x2), so we can just do
// a simple OR here without impacting anything.
line->metadata |= exdc_latch->request.type;
}
// Not a load/store, so execute cache operation.
else {
unsigned delay;
if ((delay = request->cacheop(vr4300, vaddr, paddr))) {
vr4300->pipeline.cycles_to_stall = delay - 1;
vr4300->regs[PIPELINE_CYCLE_TYPE] = 2;
return 1;
}
}
}
return 0;
}
// Writeback stage.
static int vr4300_wb_stage(struct vr4300 *vr4300) {
const struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
vr4300->regs[dcwb_latch->dest] = dcwb_latch->result;
return 0;
}
// Advances the processor pipeline by one pclock.
// May have exceptions, so check for aborted stages.
void vr4300_cycle_slow_wb(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
struct vr4300_dcwb_latch *dcwb_latch = &pipeline->dcwb_latch;
// If we haven't had exceptions for at least a
// full pipeline's length, switch back to fast mode.
if (pipeline->exception_history++ > 3)
pipeline->fault_present = false;
if (dcwb_latch->common.fault == VR4300_FAULT_NONE) {
if (vr4300_wb_stage(vr4300))
return;
}
vr4300_cycle_slow_dc(vr4300);
}
// Advances the processor pipeline by one pclock.
// May have exceptions, so check for aborted stages.
//
// Starts from DC stage (WB resolved an interlock).
void vr4300_cycle_slow_dc(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
struct vr4300_dcwb_latch *dcwb_latch = &pipeline->dcwb_latch;
struct vr4300_exdc_latch *exdc_latch = &pipeline->exdc_latch;
if (exdc_latch->common.fault == VR4300_FAULT_NONE) {
if (vr4300_dc_stage(vr4300))
return;
}
else {
dcwb_latch->common = exdc_latch->common;
dcwb_latch->dest = 0;
}
vr4300_cycle_slow_ex(vr4300);
}
// Advances the processor pipeline by one pclock.
// May have exceptions, so check for aborted stages.
//
// Starts from EX stage (DC resolved an interlock).
void vr4300_cycle_slow_ex(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
struct vr4300_exdc_latch *exdc_latch = &pipeline->exdc_latch;
struct vr4300_rfex_latch *rfex_latch = &pipeline->rfex_latch;
if (rfex_latch->common.fault == VR4300_FAULT_NONE) {
if (vr4300_ex_stage(vr4300))
return;
}
else {
exdc_latch->common = rfex_latch->common;
exdc_latch->dest = 0;
}
vr4300_cycle_slow_rf(vr4300);
}
// Advances the processor pipeline by one pclock.
// May have exceptions, so check for aborted stages.
//
// Starts from RF stage (EX resolved an interlock).
void vr4300_cycle_slow_rf(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
struct vr4300_rfex_latch *rfex_latch = &pipeline->rfex_latch;
struct vr4300_icrf_latch *icrf_latch = &pipeline->icrf_latch;
if (icrf_latch->common.fault == VR4300_FAULT_NONE) {
if (vr4300_rf_stage(vr4300))
return;
}
else
rfex_latch->common = icrf_latch->common;
vr4300_cycle_slow_ic(vr4300);
}
// Advances the processor pipeline by one pclock.
// May have exceptions, so check for aborted stages.
//
// Starts from IC stage (RF resolved an interlock).
void vr4300_cycle_slow_ic(struct vr4300 *vr4300) {
vr4300->pipeline.icrf_latch.common.fault = VR4300_FAULT_NONE;
vr4300->regs[PIPELINE_CYCLE_TYPE] = 0;
// If IADE is raised, it'll reset the PIPELINE_CYCLE_TYPE
// so we can aggressively force it back to zero first.
vr4300_ic_stage(vr4300);
}
// Special-cased busy wait handler.
void vr4300_cycle_busywait(struct vr4300 *vr4300) {
uint32_t cp0_status = vr4300->regs[VR4300_CP0_REGISTER_STATUS];
uint32_t cp0_cause = vr4300->regs[VR4300_CP0_REGISTER_CAUSE];
// Check if the busy wait period is over (due to an interrupt condition).
if (unlikely(cp0_cause & cp0_status & 0xFF00)
&& (cp0_status & 0x1) && !(cp0_status & 0x6)) {
//debug("Busy wait done @ %llu cycles\n", vr4300->cycles);
VR4300_INTR(vr4300);
}
}
// LUT of stages for fault handling.
cen64_align(static const pipeline_function
pipeline_function_lut[], CACHE_LINE_SIZE) = {
vr4300_cycle_slow_wb,
vr4300_cycle_slow_dc,
vr4300_cycle_slow_ex,
vr4300_cycle_slow_rf,
vr4300_cycle_slow_ic,
vr4300_cycle_busywait,
VR4300_DCM,
};
// Advances the processor pipeline by one pclock.
void vr4300_cycle_(struct vr4300 *vr4300) {
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
// Ordinarily, we would need to check every pipeline stage to see if it is
// aborted, and conditionally not execute it. Since faults are rare, we'll
// only bother checking for aborted stages when we know they can be present.
if (pipeline->fault_present + vr4300->regs[PIPELINE_CYCLE_TYPE])
pipeline_function_lut[vr4300->regs[PIPELINE_CYCLE_TYPE]](vr4300);
else {
if (vr4300_wb_stage(vr4300))
return;
if (vr4300_dc_stage(vr4300))
return;
if (vr4300_ex_stage(vr4300))
return;
if (vr4300_rf_stage(vr4300))
return;
vr4300_ic_stage(vr4300);
}
}
// Collects additional information about the pipeline each cycle.
void vr4300_cycle_extra(struct vr4300 *vr4300, struct vr4300_stats *stats) {
struct vr4300_dcwb_latch *dcwb_latch = &vr4300->pipeline.dcwb_latch;
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
// Collect information for CPI.
stats->executed_instructions +=
!dcwb_latch->common.fault &&
!vr4300->pipeline.cycles_to_stall;
stats->total_cycles++;
// Collect information about executed instructions.
stats->opcode_counts[rfex_latch->opcode.id]++;
}
// Initializes the pipeline with default values.
void vr4300_pipeline_init(struct vr4300_pipeline *pipeline) {
pipeline->icrf_latch.segment = get_default_segment();
pipeline->exdc_latch.segment = get_default_segment();
}
./vr4300/opcodes.md 0000644 0001750 0001750 00000004064 13262010135 012212 0 ustar dan dan //
// vr4300/opcodes.md: VR4300 opcode types and info.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef VR4300_OPCODE_TABLE
#define VR4300_OPCODE_TABLE X(INVALID) \
X(ADD) X(ADDI) X(ADDIU) X(ADDU) X(AND) X(ANDI) X(BC0) X(BC1) X(BC2) \
X(BEQ) X(BEQL) X(BGEZ) X(BGEZAL) X(BGEZALL) X(BGEZL) X(BGTZ) X(BGTZL) \
X(BLEZ) X(BLEZL) X(BLTZ) X(BLTZAL) X(BLTZALL) X(BLTZL) X(BNE) X(BNEL) \
X(BREAK) X(CACHE) X(CFC0) X(CFC1) X(CFC2) X(CP1_ABS) X(CP1_ADD) \
X(CP1_C_EQ) X(CP1_C_F) X(CP1_C_LE) X(CP1_C_LT) X(CP1_C_NGE) \
X(CP1_C_NGL) X(CP1_C_NGLE) X(CP1_C_NGT) X(CP1_C_OLE) X(CP1_C_OLT) \
X(CP1_C_UEQ) X(CP1_C_ULE) X(CP1_C_ULT) X(CP1_C_UN) X(CP1_C_SEQ) \
X(CP1_C_SF) X(CP1_CEIL_L) X(CP1_CEIL_W) X(CP1_CVT_D) X(CP1_CVT_L) \
X(CP1_CVT_S) X(CP1_CVT_W) X(CP1_DIV) X(CP1_FLOOR_L) X(CP1_FLOOR_W) \
X(CP1_MOV) X(CP1_MUL) X(CP1_NEG) X(CP1_ROUND_L) X(CP1_ROUND_W) \
X(CP1_SQRT) X(CP1_SUB) X(CP1_TRUNC_L) X(CP1_TRUNC_W) X(CTC0) X(CTC1) \
X(CTC2) X(DADD) X(DADDI) X(DADDIU) X(DADDU) X(DDIV) X(DDIVU) X(DIV) \
X(DIVU) X(DMFC0) X(DMFC1) X(DMFC2) X(DMTC0) X(DMTC1) X(DMTC2) X(DMULT) \
X(DMULTU) X(DSLL) X(DSLLV) X(DSLL32) X(DSRA) X(DSRAV) X(DSRA32) X(DSRL) \
X(DSRLV) X(DSRL32) X(DSUB) X(DSUBU) X(ERET) X(J) X(JAL) X(JALR) X(JR) \
X(LB) X(LBU) X(LD) X(LDC0) X(LDC1) X(LDC2) X(LDL) X(LDR) X(LH) X(LHU) \
X(LL) X(LLD) X(LUI) X(LW) X(LWC0) X(LWC1) X(LWC2) X(LWL) X(LWR) X(LWU) \
X(MFC0) X(MFC1) X(MFC2) X(MFHI) X(MFLO) X(MTC0) X(MTC1) X(MTC2) X(MTHI) \
X(MTLO) X(MULT) X(MULTU) X(NOR) X(OR) X(ORI) X(SB) X(SC) X(SCD) X(SD) \
X(SDC0) X(SDC1) X(SDC2) X(SDL) X(SDR) X(SH) X(SLL) X(SLLV) X(SLT) \
X(SLTI) X(SLTIU) X(SLTU) X(SRA) X(SRAV) X(SRL) X(SRLV) X(SUB) X(SUBU) \
X(SW) X(SWC0) X(SWC1) X(SWC2) X(SWL) X(SWR) X(SYNC) X(SYSCALL) X(TEQ) \
X(TEQI) X(TGE) X(TGEI) X(TGEIU) X(TGEU) X(TLBP) X(TLBR) X(TLBWI) \
X(TLBWR) X(TLT) X(TLTI) X(TLTIU) X(TLTU) X(TNE) X(TNEI) X(XOR) X(XORI)
#endif
VR4300_OPCODE_TABLE
./vr4300/fault.md 0000644 0001750 0001750 00000001064 13262010135 011666 0 ustar dan dan //
// vr4300/fault.md: VR4300 fault management.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef VR4300_FAULT_LIST
#define VR4300_FAULT_LIST \
X(NONE) X(CP0I) X(RST) X(NMI) X(OVFL) X(TRAP) X(FPE) X(DADE) \
X(DTLB) X(WAT) X(INTR) X(DCM) X(DCB) X(COP) X(DBE) X(SYSC) X(BRPT) \
X(CPU) X(RSVD) X(LDI) X(MCI) X(IADE) X(ITM) X(ICB) X(UNC) X(ITLB) \
X(IBE)
#endif
VR4300_FAULT_LIST
./vr4300/opcodes_priv.h 0000644 0001750 0001750 00000033143 13706454531 013120 0 ustar dan dan //
// vr4300/opcodes_priv.h: VR4300 opcode types and info.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef __vr4300_opcodes_priv_h__
#define __vr4300_opcodes_priv_h__
#include "common.h"
#include "vr4300/opcodes.h"
#define INFO1(x) (OPCODE_INFO_##x)
#define INFO2(x,y) (INFO1(x) | OPCODE_INFO_##y)
#define INFO3(x,y,z) (INFO2(x,y) | OPCODE_INFO_##z)
#define INFO4(x,y,z,a) (INFO3(x,y,z) | OPCODE_INFO_##a)
#define INFO5(x,y,z,a,b) (INFO4(x,y,z,a) | OPCODE_INFO_##b)
#define INVALID VR4300_BUILD_OP(INVALID, INVALID, INFO1(NONE))
#ifdef VR4300_BUSY_WAIT_DETECTION
#define BEQ VR4300_BUILD_OP(BEQ, BEQ_BEQL_BNE_BNEL_BWDETECT, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BEQL VR4300_BUILD_OP(BEQL, BEQ_BEQL_BNE_BNEL_BWDETECT, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BNE VR4300_BUILD_OP(BNE, BEQ_BEQL_BNE_BNEL_BWDETECT, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BNEL VR4300_BUILD_OP(BNEL, BEQ_BEQL_BNE_BNEL_BWDETECT, INFO3(BRANCH, NEEDRS, NEEDRT))
#define J VR4300_BUILD_OP(J, J_JAL_BWDETECT, INFO1(BRANCH))
#define JAL VR4300_BUILD_OP(JAL, J_JAL_BWDETECT, INFO1(BRANCH))
#else
#define BEQ VR4300_BUILD_OP(BEQ, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BEQL VR4300_BUILD_OP(BEQL, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BNE VR4300_BUILD_OP(BNE, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define BNEL VR4300_BUILD_OP(BNEL, BEQ_BEQL_BNE_BNEL, INFO3(BRANCH, NEEDRS, NEEDRT))
#define J VR4300_BUILD_OP(J, J_JAL, INFO1(BRANCH))
#define JAL VR4300_BUILD_OP(JAL, J_JAL, INFO1(BRANCH))
#endif
#define ADD VR4300_BUILD_OP(ADD, ADD_SUB, INFO2(NEEDRS, NEEDRT))
#define ADDI VR4300_BUILD_OP(ADDI, ADDI_SUBI, INFO1(NEEDRS))
#define ADDIU VR4300_BUILD_OP(ADDIU, ADDIU_LUI_SUBIU, INFO1(NEEDRS))
#define ADDU VR4300_BUILD_OP(ADDU, ADDU_SUBU, INFO2(NEEDRS, NEEDRT))
#define AND VR4300_BUILD_OP(AND, AND_OR_XOR, INFO2(NEEDRS, NEEDRT))
#define ANDI VR4300_BUILD_OP(ANDI, ANDI_ORI_XORI, INFO1(NEEDRS))
#define BGEZ VR4300_BUILD_OP(BGEZ, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BGEZAL VR4300_BUILD_OP(BGEZAL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BGEZALL VR4300_BUILD_OP(BGEZALL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BGEZL VR4300_BUILD_OP(BGEZL, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BGTZ VR4300_BUILD_OP(BGTZ, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BGTZL VR4300_BUILD_OP(BGTZL, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BLEZ VR4300_BUILD_OP(BLEZ, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BLEZL VR4300_BUILD_OP(BLEZL, BGTZ_BGTZL_BLEZ_BLEZL, INFO2(BRANCH, NEEDRS))
#define BLTZ VR4300_BUILD_OP(BLTZ, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BLTZAL VR4300_BUILD_OP(BLTZAL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BLTZALL VR4300_BUILD_OP(BLTZALL, BGEZAL_BGEZALL_BLTZAL_BLTZALL, INFO2(BRANCH, NEEDRS))
#define BLTZL VR4300_BUILD_OP(BLTZL, BGEZ_BGEZL_BLTZ_BLTZL, INFO2(BRANCH, NEEDRS))
#define BREAK VR4300_BUILD_OP(BREAK, BREAK, INFO1(NONE))
#define DADD VR4300_BUILD_OP(DADD, DADD_DSUB, INFO2(NEEDRS, NEEDRT))
#define DADDI VR4300_BUILD_OP(DADDI, DADDI_DSUBI, INFO1(NEEDRS))
#define DADDIU VR4300_BUILD_OP(DADDIU, DADDIU_DSUBIU, INFO1(NEEDRS))
#define DADDU VR4300_BUILD_OP(DADDU, DADDU_DSUBU, INFO2(NEEDRS, NEEDRT))
#define DDIV VR4300_BUILD_OP(DDIV, DDIV, INFO2(NEEDRS, NEEDRT))
#define DDIVU VR4300_BUILD_OP(DDIVU, DDIVU, INFO2(NEEDRS, NEEDRT))
#define DIV VR4300_BUILD_OP(DIV, DIV_DIVU, INFO2(NEEDRS, NEEDRT))
#define DIVU VR4300_BUILD_OP(DIVU, DIV_DIVU, INFO2(NEEDRS, NEEDRT))
#define DMULT VR4300_BUILD_OP(DMULT, DMULT, INFO2(NEEDRS, NEEDRT))
#define DMULTU VR4300_BUILD_OP(DMULTU, DMULTU, INFO2(NEEDRS, NEEDRT))
#define DSLL VR4300_BUILD_OP(DSLL, DSLL_DSLL32, INFO1(NEEDRT))
#define DSLLV VR4300_BUILD_OP(DSLLV, DSLLV, INFO2(NEEDRS, NEEDRT))
#define DSLL32 VR4300_BUILD_OP(DSLL32, DSLL_DSLL32, INFO1(NEEDRT))
#define DSRA VR4300_BUILD_OP(DSRA, DSRA_DSRA32, INFO1(NEEDRT))
#define DSRAV VR4300_BUILD_OP(DSRAV, DSRAV, INFO2(NEEDRS, NEEDRT))
#define DSRA32 VR4300_BUILD_OP(DSRA32, DSRA_DSRA32, INFO1(NEEDRT))
#define DSRL VR4300_BUILD_OP(DSRL, DSRL_DSRL32, INFO1(NEEDRT))
#define DSRLV VR4300_BUILD_OP(DSRLV, DSRLV, INFO2(NEEDRS, NEEDRT))
#define DSRL32 VR4300_BUILD_OP(DSRL32, DSRL_DSRL32, INFO1(NEEDRT))
#define DSUB VR4300_BUILD_OP(DSUB, DADD_DSUB, INFO2(NEEDRS, NEEDRT))
#define DSUBU VR4300_BUILD_OP(DSUBU, DADDU_DSUBU, INFO2(NEEDRS, NEEDRT))
#define JALR VR4300_BUILD_OP(JALR, JALR_JR, INFO2(BRANCH, NEEDRS))
#define JR VR4300_BUILD_OP(JR, JALR_JR, INFO2(BRANCH, NEEDRS))
#define LB VR4300_BUILD_OP(LB, LOAD_STORE, INFO2(NEEDRS, LOAD))
#define LBU VR4300_BUILD_OP(LBU, LOAD_STORE, INFO2(NEEDRS, LOAD))
#define LD VR4300_BUILD_OP(LD, LD_SD, INFO2(NEEDRS, LOAD))
#define LDL VR4300_BUILD_OP(LDL, LDL_LDR, INFO3(NEEDRS, NEEDRT, LOAD))
#define LDR VR4300_BUILD_OP(LDR, LDL_LDR, INFO3(NEEDRS, NEEDRT, LOAD))
#define LH VR4300_BUILD_OP(LH, LOAD_STORE, INFO2(NEEDRS, LOAD))
#define LHU VR4300_BUILD_OP(LHU, LOAD_STORE, INFO2(NEEDRS, LOAD))
#define LL VR4300_BUILD_OP(LL, INVALID, INFO1(NONE))
#define LLD VR4300_BUILD_OP(LLD, INVALID, INFO1(NONE))
#define LUI VR4300_BUILD_OP(LUI, ADDIU_LUI_SUBIU, INFO1(NONE))
#define LW VR4300_BUILD_OP(LW, LOAD_STORE, INFO2(NEEDRS, LOAD))
#define LWL VR4300_BUILD_OP(LWL, LWL_LWR, INFO3(NEEDRS, NEEDRT, LOAD))
#define LWR VR4300_BUILD_OP(LWR, LWL_LWR, INFO3(NEEDRS, NEEDRT, LOAD))
#define LWU VR4300_BUILD_OP(LWU, LOAD_STORE, INFO2(NEEDRS, LOAD))
#define MFHI VR4300_BUILD_OP(MFHI, MFHI_MFLO, INFO1(NONE))
#define MFLO VR4300_BUILD_OP(MFLO, MFHI_MFLO, INFO1(NONE))
#define MTHI VR4300_BUILD_OP(MTHI, MTHI_MTLO, INFO1(NEEDRS))
#define MTLO VR4300_BUILD_OP(MTLO, MTHI_MTLO, INFO1(NEEDRS))
#define MULT VR4300_BUILD_OP(MULT, MULT_MULTU, INFO2(NEEDRS, NEEDRT))
#define MULTU VR4300_BUILD_OP(MULTU, MULT_MULTU, INFO2(NEEDRS, NEEDRT))
#define NOR VR4300_BUILD_OP(NOR, NOR, INFO2(NEEDRS, NEEDRT))
#define OR VR4300_BUILD_OP(OR, AND_OR_XOR, INFO2(NEEDRS, NEEDRT))
#define ORI VR4300_BUILD_OP(ORI, ANDI_ORI_XORI, INFO1(NEEDRS))
#define SB VR4300_BUILD_OP(SB, LOAD_STORE, INFO3(NEEDRS, NEEDRT, STORE))
#define SC VR4300_BUILD_OP(SC, INVALID, INFO1(NONE))
#define SCD VR4300_BUILD_OP(SCD, INVALID, INFO1(NONE))
#define SD VR4300_BUILD_OP(SD, LD_SD, INFO3(NEEDRS, NEEDRT, STORE))
#define SDL VR4300_BUILD_OP(SDL, SDL_SDR, INFO3(NEEDRS, NEEDRT, STORE))
#define SDR VR4300_BUILD_OP(SDR, SDL_SDR, INFO3(NEEDRS, NEEDRT, STORE))
#define SH VR4300_BUILD_OP(SH, LOAD_STORE, INFO3(NEEDRS, NEEDRT, STORE))
#define SLL VR4300_BUILD_OP(SLL, SLL_SLLV, INFO1(NEEDRT))
#define SLLV VR4300_BUILD_OP(SLLV, SLL_SLLV, INFO2(NEEDRS, NEEDRT))
#define SLT VR4300_BUILD_OP(SLT, SLT, INFO2(NEEDRS, NEEDRT))
#define SLTI VR4300_BUILD_OP(SLTI, SLTI, INFO1(NEEDRS))
#define SLTIU VR4300_BUILD_OP(SLTIU, SLTIU, INFO1(NEEDRS))
#define SLTU VR4300_BUILD_OP(SLTU, SLTU, INFO2(NEEDRS, NEEDRT))
#define SRA VR4300_BUILD_OP(SRA, SRA, INFO1(NEEDRT))
#define SRAV VR4300_BUILD_OP(SRAV, SRAV, INFO2(NEEDRS, NEEDRT))
#define SRL VR4300_BUILD_OP(SRL, SRL, INFO1(NEEDRT))
#define SRLV VR4300_BUILD_OP(SRLV, SRLV, INFO2(NEEDRS, NEEDRT))
#define SUB VR4300_BUILD_OP(SUB, ADD_SUB, INFO2(NEEDRS, NEEDRT))
#define SUBU VR4300_BUILD_OP(SUBU, ADDU_SUBU, INFO1(NEEDRS))
#define SW VR4300_BUILD_OP(SW, LOAD_STORE, INFO3(NEEDRS, NEEDRT, STORE))
#define SWL VR4300_BUILD_OP(SWL, SWL_SWR, INFO3(NEEDRS, NEEDRT, STORE))
#define SWR VR4300_BUILD_OP(SWR, SWL_SWR, INFO3(NEEDRS, NEEDRT, STORE))
#define SYNC VR4300_BUILD_OP(SYNC, SLL_SLLV, INFO1(NONE))
#define SYSCALL VR4300_BUILD_OP(SYSCALL, SYSCALL, INFO1(NONE))
#define TEQ VR4300_BUILD_OP(TEQ, INVALID, INFO1(NONE))
#define TEQI VR4300_BUILD_OP(TEQI, INVALID, INFO1(NONE))
#define TGE VR4300_BUILD_OP(TGE, INVALID, INFO1(NONE))
#define TGEI VR4300_BUILD_OP(TGEI, INVALID, INFO1(NONE))
#define TGEIU VR4300_BUILD_OP(TGEIU, INVALID, INFO1(NONE))
#define TGEU VR4300_BUILD_OP(TGEU, INVALID, INFO1(NONE))
#define TLT VR4300_BUILD_OP(TLT, INVALID, INFO1(NONE))
#define TLTI VR4300_BUILD_OP(TLTI, INVALID, INFO1(NONE))
#define TLTIU VR4300_BUILD_OP(TLTIU, INVALID, INFO1(NONE))
#define TLTU VR4300_BUILD_OP(TLTU, INVALID, INFO1(NONE))
#define TNE VR4300_BUILD_OP(TNE, INVALID, INFO1(NONE))
#define TNEI VR4300_BUILD_OP(TNEI, INVALID, INFO1(NONE))
#define XOR VR4300_BUILD_OP(XOR, AND_OR_XOR, INFO2(NEEDRS, NEEDRT))
#define XORI VR4300_BUILD_OP(XORI, ANDI_ORI_XORI, INFO1(NEEDRS))
#define BC0 VR4300_BUILD_OP(BC0, INVALID, INFO1(BRANCH))
#define CFC0 VR4300_BUILD_OP(CFC0, INVALID, INFO1(NONE))
#define CTC0 VR4300_BUILD_OP(CTC0, INVALID, INFO1(NONE))
#define DMFC0 VR4300_BUILD_OP(DMFC0, DMFC0, INFO1(NONE))
#define DMTC0 VR4300_BUILD_OP(DMTC0, DMTC0, INFO1(NEEDRT))
#define LDC0 VR4300_BUILD_OP(LDC0, INVALID, INFO1(LOAD))
#define LWC0 VR4300_BUILD_OP(LWC0, INVALID, INFO1(LOAD))
#define MFC0 VR4300_BUILD_OP(MFC0, MFC0, INFO1(NONE))
#define MTC0 VR4300_BUILD_OP(MTC0, MTC0, INFO1(NEEDRT))
#define SDC0 VR4300_BUILD_OP(SDC0, INVALID, INFO1(STORE))
#define SWC0 VR4300_BUILD_OP(SWC0, INVALID, INFO1(STORE))
#define CACHE VR4300_BUILD_OP(CACHE, CACHE, INFO1(NEEDRS))
#define ERET VR4300_BUILD_OP(ERET, ERET, INFO1(NONE))
#define TLBP VR4300_BUILD_OP(TLBP, TLBP, INFO1(NONE))
#define TLBR VR4300_BUILD_OP(TLBR, TLBR, INFO1(NONE))
#define TLBWI VR4300_BUILD_OP(TLBWI, TLBWI, INFO1(NONE))
#define TLBWR VR4300_BUILD_OP(TLBWR, TLBWR, INFO1(NONE))
#define BC1 VR4300_BUILD_OP(BC1, BC1, INFO2(FPU, BRANCH))
#define CFC1 VR4300_BUILD_OP(CFC1, CFC1, INFO2(FPU, NONE))
#define CTC1 VR4300_BUILD_OP(CTC1, CTC1, INFO2(FPU, NONE))
#define DMFC1 VR4300_BUILD_OP(DMFC1, DMFC1, INFO2(FPU, NEEDFS))
#define DMTC1 VR4300_BUILD_OP(DMTC1, DMTC1, INFO2(FPU, NEEDRT))
#define LDC1 VR4300_BUILD_OP(LDC1, LDC1, INFO3(FPU, NEEDRS, LOAD))
#define LWC1 VR4300_BUILD_OP(LWC1, LWC1, INFO4(FPU, NEEDRS, NEEDFT, LOAD))
#define MFC1 VR4300_BUILD_OP(MFC1, MFC1, INFO2(FPU, NEEDFS))
#define MTC1 VR4300_BUILD_OP(MTC1, MTC1, INFO3(FPU, NEEDFS, NEEDRT))
#define SDC1 VR4300_BUILD_OP(SDC1, SDC1, INFO4(FPU, NEEDRS, NEEDFT, STORE))
#define SWC1 VR4300_BUILD_OP(SWC1, SWC1, INFO4(FPU, NEEDRS, NEEDFT, STORE))
#define CP1_ABS VR4300_BUILD_OP(CP1_ABS, CP1_ABS, INFO3(FPU, FPU, NEEDFS))
#define CP1_ADD VR4300_BUILD_OP(CP1_ADD, CP1_ADD, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_EQ VR4300_BUILD_OP(CP1_C_EQ, CP1_C_EQ_C_SEQ, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_F VR4300_BUILD_OP(CP1_C_F, CP1_C_F_C_SF, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_LE VR4300_BUILD_OP(CP1_C_LE, CP1_C_OLE_C_LE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_LT VR4300_BUILD_OP(CP1_C_LT, CP1_C_OLT_C_LT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGE VR4300_BUILD_OP(CP1_C_NGE, CP1_C_ULT_C_NGE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGL VR4300_BUILD_OP(CP1_C_NGL, CP1_C_UEQ_C_NGL, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGLE VR4300_BUILD_OP(CP1_C_NGLE, CP1_C_UN_C_NGLE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_NGT VR4300_BUILD_OP(CP1_C_NGT, CP1_C_ULE_C_NGT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_OLE VR4300_BUILD_OP(CP1_C_OLE, CP1_C_OLE_C_LE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_OLT VR4300_BUILD_OP(CP1_C_OLT, CP1_C_OLT_C_LT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_SEQ VR4300_BUILD_OP(CP1_C_SEQ, CP1_C_EQ_C_SEQ, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_SF VR4300_BUILD_OP(CP1_C_SF, CP1_C_F_C_SF, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_UEQ VR4300_BUILD_OP(CP1_C_UEQ, CP1_C_UEQ_C_NGL, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_ULE VR4300_BUILD_OP(CP1_C_ULE, CP1_C_ULE_C_NGT, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_ULT VR4300_BUILD_OP(CP1_C_ULT, CP1_C_ULT_C_NGE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_C_UN VR4300_BUILD_OP(CP1_C_UN, CP1_C_UN_C_NGLE, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_CEIL_L VR4300_BUILD_OP(CP1_CEIL_L, CP1_CEIL_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_CEIL_W VR4300_BUILD_OP(CP1_CEIL_W, CP1_CEIL_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_D VR4300_BUILD_OP(CP1_CVT_D, CP1_CVT_D, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_L VR4300_BUILD_OP(CP1_CVT_L, CP1_CVT_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_S VR4300_BUILD_OP(CP1_CVT_S, CP1_CVT_S, INFO3(FPU, FPU, NEEDFS))
#define CP1_CVT_W VR4300_BUILD_OP(CP1_CVT_W, CP1_CVT_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_DIV VR4300_BUILD_OP(CP1_DIV, CP1_DIV, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_FLOOR_L VR4300_BUILD_OP(CP1_FLOOR_L, CP1_FLOOR_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_FLOOR_W VR4300_BUILD_OP(CP1_FLOOR_W, CP1_FLOOR_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_MOV VR4300_BUILD_OP(CP1_MOV, CP1_MOV, INFO3(FPU, FPU, NEEDFS))
#define CP1_MUL VR4300_BUILD_OP(CP1_MUL, CP1_MUL, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_NEG VR4300_BUILD_OP(CP1_NEG, CP1_NEG, INFO3(FPU, FPU, NEEDFS))
#define CP1_ROUND_L VR4300_BUILD_OP(CP1_ROUND_L, CP1_ROUND_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_ROUND_W VR4300_BUILD_OP(CP1_ROUND_W, CP1_ROUND_W, INFO3(FPU, FPU, NEEDFS))
#define CP1_SQRT VR4300_BUILD_OP(CP1_SQRT, CP1_SQRT, INFO3(FPU, FPU, NEEDFS))
#define CP1_SUB VR4300_BUILD_OP(CP1_SUB, CP1_SUB, INFO3(FPU, NEEDFS, NEEDFT))
#define CP1_TRUNC_L VR4300_BUILD_OP(CP1_TRUNC_L, CP1_TRUNC_L, INFO3(FPU, FPU, NEEDFS))
#define CP1_TRUNC_W VR4300_BUILD_OP(CP1_TRUNC_W, CP1_TRUNC_W, INFO3(FPU, FPU, NEEDFS))
#define BC2 VR4300_BUILD_OP(BC1, INVALID, INFO1(BRANCH))
#define CFC2 VR4300_BUILD_OP(CFC2, INVALID, INFO1(NONE))
#define CTC2 VR4300_BUILD_OP(CTC2, INVALID, INFO1(NONE))
#define DMFC2 VR4300_BUILD_OP(DMFC2, INVALID, INFO1(NONE))
#define DMTC2 VR4300_BUILD_OP(DMTC2, INVALID, INFO1(NONE))
#define LDC2 VR4300_BUILD_OP(LDC2, INVALID, INFO1(NONE))
#define LWC2 VR4300_BUILD_OP(LWC2, INVALID, INFO1(NONE))
#define MFC2 VR4300_BUILD_OP(MFC2, INVALID, INFO1(NONE))
#define MTC2 VR4300_BUILD_OP(MTC2, INVALID, INFO1(NONE))
#define SDC2 VR4300_BUILD_OP(SDC2, INVALID, INFO1(NONE))
#define SWC2 VR4300_BUILD_OP(SWC2, INVALID, INFO1(NONE))
#endif
./vr4300/pipeline.h 0000644 0001750 0001750 00000004061 13262010135 012207 0 ustar dan dan //
// vr4300/pipeline.h: VR4300 processor pipeline.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef __vr4300_pipeline_h__
#define __vr4300_pipeline_h__
#include "common.h"
#include "vr4300/decoder.h"
#include "vr4300/fault.h"
#include "vr4300/segment.h"
struct vr4300;
typedef int (*vr4300_cacheop_func_t)(
struct vr4300 *vr4300, uint64_t vaddr, uint32_t paddr);
enum vr4300_bus_request_type {
VR4300_BUS_REQUEST_NONE,
VR4300_BUS_REQUEST_READ,
VR4300_BUS_REQUEST_WRITE,
VR4300_BUS_REQUEST_CACHE = 4,
VR4300_BUS_REQUEST_CACHE_IDX = 4,
VR4300_BUS_REQUEST_CACHE_WRITE = 5,
};
enum vr4300_access_type {
VR4300_ACCESS_WORD = 1 << 5,
VR4300_ACCESS_DWORD = 0
};
struct vr4300_bus_request {
uint64_t vaddr;
uint64_t data;
uint64_t wdqm;
vr4300_cacheop_func_t cacheop;
uint32_t paddr;
enum vr4300_access_type access_type;
enum vr4300_bus_request_type type;
unsigned size, postshift;
};
struct vr4300_latch {
uint64_t pc;
enum vr4300_fault_id fault;
uint32_t cause_data;
};
struct vr4300_icrf_latch {
struct vr4300_latch common;
const struct segment *segment;
uint64_t pc;
};
struct vr4300_rfex_latch {
struct vr4300_latch common;
struct vr4300_opcode opcode;
uint32_t iw, iw_mask, paddr;
bool cached;
};
struct vr4300_exdc_latch {
struct vr4300_latch common;
const struct segment *segment;
int64_t result;
uint32_t dest;
struct vr4300_bus_request request;
bool cached;
};
struct vr4300_dcwb_latch {
struct vr4300_latch common;
int64_t result;
uint32_t dest;
bool last_op_was_cache_store;
};
struct vr4300_pipeline {
struct vr4300_dcwb_latch dcwb_latch;
struct vr4300_exdc_latch exdc_latch;
struct vr4300_rfex_latch rfex_latch;
struct vr4300_icrf_latch icrf_latch;
unsigned exception_history;
unsigned cycles_to_stall;
bool fault_present;
};
cen64_cold void vr4300_pipeline_init(struct vr4300_pipeline *pipeline);
#endif
./vr4300/cp0.c 0000644 0001750 0001750 00000022777 13706454531 011114 0 ustar dan dan //
// vr4300/cp0.c: VR4300 system control coprocessor.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "common.h"
#include "tlb/tlb.h"
#include "vr4300/cp0.h"
#include "vr4300/cpu.h"
static const uint64_t vr4300_cp0_reg_masks[32] = {
0x000000008000003FULL, // 0: VR4300_CP0_REGISTER_INDEX
0x000000000000003FULL, // 1: VR4300_CP0_REGISTER_RANDOM
0x000000007FFFFFFFULL, // 2: VR4300_CP0_REGISTER_ENTRYLO0
0x000000007FFFFFFFULL, // 3: VR4300_CP0_REGISTER_ENTRYLO1
0xFFFFFFFFFFFFFFF0ULL, // 4: VR4300_CP0_REGISTER_CONTEXT
0x0000000001FFE000ULL, // 5: VR4300_CP0_REGISTER_PAGEMASK
0xFFFFFFFFFFFFFFFFULL, // 6: VR4300_CP0_REGISTER_WIRED
0x0000000000000BADULL, // 7:
0xFFFFFFFFFFFFFFFFULL, // 8: VR4300_CP0_REGISTER_BADVADDR
0x00000000FFFFFFFFULL, // 9: VR4300_CP0_REGISTER_COUNT
0xC00000FFFFFFE0FFULL, // 10: VR4300_CP0_REGISTER_ENTRYHI
0x00000000FFFFFFFFULL, // 11: VR4300_CP0_REGISTER_COMPARE
0x00000000FFFFFFFFULL, // 12: VR4300_CP0_REGISTER_STATUS
0x00000000B000FFFFULL, // 13: VR4300_CP0_REGISTER_CAUSE
0xFFFFFFFFFFFFFFFFULL, // 14: VR4300_CP0_REGISTER_EPC
0x000000000000FFFFULL, // 15; VR4300_CP0_REGISTER_PRID
0x000000007FFFFFFFULL, // 16: VR4300_CP0_REGISTER_CONFIG
0x00000000FFFFFFFFULL, // 17: VR4300_CP0_REGISTER_LLADDR
0x00000000FFFFFFFBULL, // 18: VR4300_CP0_REGISTER_WATCHLO
0x000000000000000FULL, // 19: VR4300_CP0_REGISTER_WATCHHI
0xFFFFFFFFFFFFFFFFULL, // 20: VR4300_CP0_REGISTER_XCONTEXT
0x0000000000000BADULL, // 21:
0x0000000000000BADULL, // 22:
0x0000000000000BADULL, // 23:
0x0000000000000BADULL, // 24:
0x0000000000000BADULL, // 25:
0x0000000000000000ULL, // 26: VR4300_CP0_REGISTER_PARITYERROR
0x0000000000000000ULL, // 27: VR4300_CP0_REGISTER_CACHEERR
0x000000000FFFFFC0ULL, // 28: VR4300_CP0_REGISTER_TAGLO
0x0000000000000000ULL, // 29: VR4300_CP0_REGISTER_TAGHI
0xFFFFFFFFFFFFFFFFULL, // 30: VR4300_CP0_REGISTER_ERROREPC
0x0000000000000BADULL, // 31
};
static inline uint64_t mask_reg(unsigned reg, uint64_t data) {
return vr4300_cp0_reg_masks[reg] & data;
};
//
// DMFC0
//
int VR4300_DMFC0(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
unsigned dest = GET_RT(iw);
unsigned src = GET_RD(iw);
if (src == (VR4300_CP0_REGISTER_COUNT - VR4300_REGISTER_CP0_0)) {
exdc_latch->result = (uint32_t)
(vr4300->regs[VR4300_CP0_REGISTER_COUNT] >> 1);
}
else if (vr4300_cp0_reg_masks[src] == 0x0000000000000BADULL)
exdc_latch->result = vr4300->regs[VR4300_REGISTER_CP0_0 + 7];
else {
exdc_latch->result = mask_reg(src,
vr4300->regs[VR4300_REGISTER_CP0_0 + src]);
}
exdc_latch->dest = dest;
return 0;
}
//
// DMTC0
//
int VR4300_DMTC0(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
unsigned dest = GET_RD(iw);
switch (dest + VR4300_REGISTER_CP0_0)
{
case VR4300_CP0_REGISTER_CAUSE:
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x0300;
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] |= rt & 0x0300;
return 0;
case VR4300_CP0_REGISTER_COMPARE:
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x8000;
break;
case VR4300_CP0_REGISTER_STATUS:
icrf_latch->segment = get_segment(icrf_latch->common.pc, rt);
exdc_latch->segment = get_default_segment();
break;
}
if (vr4300_cp0_reg_masks[dest] == 0x0000000000000BADULL)
vr4300->regs[VR4300_REGISTER_CP0_0 + 7] = rt;
else
vr4300->regs[VR4300_REGISTER_CP0_0 + dest] = rt;
return 0;
}
//
// ERET
//
int VR4300_ERET(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_rfex_latch *rfex_latch = &vr4300->pipeline.rfex_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
struct vr4300_pipeline *pipeline = &vr4300->pipeline;
int32_t status = vr4300->regs[VR4300_CP0_REGISTER_STATUS];
if (status & 0x4) {
icrf_latch->pc = vr4300->regs[VR4300_CP0_REGISTER_ERROREPC];
status &= ~0x4;
}
else {
icrf_latch->pc = vr4300->regs[VR4300_CP0_REGISTER_EPC];
status &= ~0x2;
}
// Until we delay CP0 writes, we have to kill ourselves
// to prevent squashing this instruction the next cycle.
exdc_latch->common.fault = ~0;
rfex_latch->common.fault = ~0;
vr4300->regs[PIPELINE_CYCLE_TYPE] = 4;
pipeline->exception_history = 0;
pipeline->fault_present = true;
vr4300->regs[VR4300_CP0_REGISTER_STATUS] = status;
pipeline->icrf_latch.segment = get_segment(icrf_latch->pc, status);
pipeline->exdc_latch.segment = get_default_segment();
// vr4300->llbit = 0;
return 1;
}
//
// MFC0
//
int VR4300_MFC0(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
unsigned dest = GET_RT(iw);
unsigned src = GET_RD(iw);
if (src == (VR4300_CP0_REGISTER_COUNT - VR4300_REGISTER_CP0_0)) {
exdc_latch->result = (int32_t)
(vr4300->regs[VR4300_CP0_REGISTER_COUNT] >> 1);
}
else if (vr4300_cp0_reg_masks[src] == 0x0000000000000BADULL)
exdc_latch->result = (int32_t) vr4300->regs[VR4300_REGISTER_CP0_0 + 7];
else {
exdc_latch->result = (int32_t) mask_reg(src,
vr4300->regs[VR4300_REGISTER_CP0_0 + src]);
}
exdc_latch->dest = (int32_t) dest;
return 0;
}
//
// MTC0
//
int VR4300_MTC0(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
struct vr4300_icrf_latch *icrf_latch = &vr4300->pipeline.icrf_latch;
struct vr4300_exdc_latch *exdc_latch = &vr4300->pipeline.exdc_latch;
unsigned dest = GET_RD(iw);
switch (dest + VR4300_REGISTER_CP0_0)
{
case VR4300_CP0_REGISTER_CAUSE:
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x0300;
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] |= (int32_t)rt & 0x0300;
return 0;
case VR4300_CP0_REGISTER_COMPARE:
vr4300->regs[VR4300_CP0_REGISTER_CAUSE] &= ~0x8000;
break;
case VR4300_CP0_REGISTER_STATUS:
icrf_latch->segment = get_segment(icrf_latch->common.pc, rt);
exdc_latch->segment = get_default_segment();
break;
}
if (vr4300_cp0_reg_masks[dest] == 0x0000000000000BADULL)
vr4300->regs[VR4300_REGISTER_CP0_0 + 7] = (int32_t) rt;
else
vr4300->regs[VR4300_REGISTER_CP0_0 + dest] = (int32_t) rt;
return 0;
}
//
// TLBP
//
int VR4300_TLBP(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
uint64_t entry_hi = mask_reg(10, vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI]);
unsigned index;
vr4300->regs[VR4300_CP0_REGISTER_INDEX] |= 0x80000000U;
if (!tlb_probe(&vr4300->cp0.tlb, entry_hi, entry_hi & 0xFF, &index))
vr4300->regs[VR4300_CP0_REGISTER_INDEX] = index;
return 0;
}
//
// TLBR
//
int VR4300_TLBR(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
unsigned index = vr4300->regs[VR4300_CP0_REGISTER_INDEX] & 0x3F;
uint64_t entry_hi;
uint32_t page_mask = (vr4300->cp0.page_mask[index] << 1) & 0x1FFE000U;
uint32_t pfn0 = vr4300->cp0.pfn[index][0];
uint32_t pfn1 = vr4300->cp0.pfn[index][1];
uint8_t state0 = vr4300->cp0.state[index][0];
uint8_t state1 = vr4300->cp0.state[index][1];
tlb_read(&vr4300->cp0.tlb, index, &entry_hi);
vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI] = entry_hi;
vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO0] = (pfn0 >> 6) | state0;
vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO1] = (pfn1 >> 6) | state1;
vr4300->regs[VR4300_CP0_REGISTER_PAGEMASK] = page_mask;
return 0;
}
//
// TLBWI
//
int VR4300_TLBWI(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
uint64_t entry_hi = mask_reg(10, vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI]);
uint64_t entry_lo_0 = mask_reg(2, vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO0]);
uint64_t entry_lo_1 = mask_reg(3, vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO1]);
uint32_t page_mask = mask_reg(5, vr4300->regs[VR4300_CP0_REGISTER_PAGEMASK]);
unsigned index = vr4300->regs[VR4300_CP0_REGISTER_INDEX] & 0x3F;
tlb_write(&vr4300->cp0.tlb, index, entry_hi, entry_lo_0, entry_lo_1, page_mask);
vr4300->cp0.page_mask[index] = (page_mask | 0x1FFF) >> 1;
vr4300->cp0.pfn[index][0] = (entry_lo_0 << 6) & ~0xFFFU;
vr4300->cp0.pfn[index][1] = (entry_lo_1 << 6) & ~0xFFFU;
vr4300->cp0.state[index][0] = entry_lo_0 & 0x3F;
vr4300->cp0.state[index][1] = entry_lo_1 & 0x3F;
return 0;
}
//
// TLBWR
//
int VR4300_TLBWR(struct vr4300 *vr4300,
uint32_t iw, uint64_t rs, uint64_t rt) {
uint64_t entry_hi = mask_reg(10, vr4300->regs[VR4300_CP0_REGISTER_ENTRYHI]);
uint64_t entry_lo_0 = mask_reg(2, vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO0]);
uint64_t entry_lo_1 = mask_reg(3, vr4300->regs[VR4300_CP0_REGISTER_ENTRYLO1]);
uint32_t page_mask = mask_reg(5, vr4300->regs[VR4300_CP0_REGISTER_PAGEMASK]);
unsigned index = vr4300->regs[VR4300_CP0_REGISTER_WIRED] & 0x3F;
index = rand() % (32 - index) + index;
tlb_write(&vr4300->cp0.tlb, index, entry_hi, entry_lo_0, entry_lo_1, page_mask);
vr4300->cp0.page_mask[index] = (page_mask | 0x1FFF) >> 1;
vr4300->cp0.pfn[index][0] = (entry_lo_0 << 6) & ~0xFFFU;
vr4300->cp0.pfn[index][1] = (entry_lo_1 << 6) & ~0xFFFU;
vr4300->cp0.state[index][0] = entry_lo_0 & 0x3F;
vr4300->cp0.state[index][1] = entry_lo_1 & 0x3F;
return 0;
}
// Initializes the coprocessor.
void vr4300_cp0_init(struct vr4300 *vr4300) {
tlb_init(&vr4300->cp0.tlb);
}
./vr4300/segment.h 0000644 0001750 0001750 00000001145 13262010135 012044 0 ustar dan dan //
// vr4300/segment.h: VR4300 MMU segment manager.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef __vr4300_segment_h__
#define __vr4300_segment_h__
#include "common.h"
struct segment {
uint64_t start;
uint64_t length;
uint64_t offset;
uint8_t xmode_mask;
bool mapped;
bool cached;
};
const struct segment* get_default_segment(void);
const struct segment* get_segment(uint64_t address, uint32_t cp0_status);
#endif
./vr4300/TODO.txt 0000644 0001750 0001750 00000000252 13262010135 011535 0 ustar dan dan - Fix/verify killed stages during exceptions. If debugging mode is enabled,
there are a lot of spurious bus_read_word messages that are concerning to
say the least.
./vr4300/dcache.c 0000644 0001750 0001750 00000012701 13262010135 011604 0 ustar dan dan //
// vr4300/dcache.c: VR4300 instruction cache.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#include "common.h"
#include "vr4300/dcache.h"
static inline struct vr4300_dcache_line* get_line(
struct vr4300_dcache *dcache, uint64_t vaddr);
static inline uint32_t get_tag(const struct vr4300_dcache_line *line);
static inline bool is_valid(const struct vr4300_dcache_line *line);
static void invalidate_line(struct vr4300_dcache_line *line);
static bool is_dirty(const struct vr4300_dcache_line *line);
static void set_dirty(struct vr4300_dcache_line *line);
static void set_tag(struct vr4300_dcache_line *line, uint32_t tag);
static void set_taglo(struct vr4300_dcache_line *line, uint32_t taglo);
static void validate_line(struct vr4300_dcache_line *line, uint32_t tag);
// Returns the line for a given virtual address.
struct vr4300_dcache_line* get_line(
struct vr4300_dcache *dcache, uint64_t vaddr) {
return dcache->lines + (vaddr >> 4 & 0x1FF);
}
// Returns the physical tag associated with the line.
uint32_t get_tag(const struct vr4300_dcache_line *line) {
return line->metadata & ~0xFFFU;
}
// Invalidates the line, but leaves the physical tag untouched.
void invalidate_line(struct vr4300_dcache_line *line) {
line->metadata &= ~0x1;
}
// Returns true if the line is valid, otherwise returns false.
bool is_dirty(const struct vr4300_dcache_line *line) {
return (line->metadata & 0x2) == 0x2;
}
// Returns true if the line is valid, otherwise returns false.
bool is_valid(const struct vr4300_dcache_line *line) {
return (line->metadata & 0x1) == 0x1;
}
// Sets the state of the line to dirty.
void set_dirty(struct vr4300_dcache_line *line) {
line->metadata |= 0x2;
}
// Sets the tag of the specified line, retaining current valid bit.
void set_tag(struct vr4300_dcache_line *line, uint32_t tag) {
line->metadata = tag | (line->metadata & 0x1);
}
// Sets the tag of the specified line and valid bit.
void set_taglo(struct vr4300_dcache_line *line, uint32_t taglo) {
line->metadata = (taglo << 4 & 0xFFFFF000U) | (taglo >> 7 & 0x1) | (taglo >> 5 & 0x2);
}
// Sets the line's physical tag and validates the line.
static void validate_line(struct vr4300_dcache_line *line, uint32_t tag) {
line->metadata = tag | 0x1;
}
// Sets the physical tag associated with the line, marks as dirty.
void vr4300_dcache_create_dirty_exclusive(
struct vr4300_dcache *dcache, uint64_t vaddr, uint32_t paddr) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
set_tag(line, paddr & ~0xFFFU);
line->metadata |= 0x3;
}
// Fills an instruction cache line with data.
void vr4300_dcache_fill(struct vr4300_dcache *dcache,
uint64_t vaddr, uint32_t paddr, const void *data) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
memcpy(line->data, data, sizeof(line->data));
validate_line(line, paddr & ~0xFFFU);
}
// Returns the tag of the line associated with vaddr.
uint32_t vr4300_dcache_get_tag(const struct vr4300_dcache_line *line, uint64_t vaddr) {
return get_tag(line) | (vaddr & 0xFF0U);
}
// Gets the physical tag associated with the line.
uint32_t vr4300_dcache_get_taglo(struct vr4300_dcache *dcache, uint64_t vaddr) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
uint32_t taglo = ((line->metadata & 0x1) << 1) | ((line->metadata & 0x2) >> 1);
return (taglo << 6) | (line->metadata >> 4 & 0x0FFFFF00U);
}
// Initializes the instruction cache.
void vr4300_dcache_init(struct vr4300_dcache *dcache) {
}
// Invalidates an instruction cache line (regardless if hit or miss).
void vr4300_dcache_invalidate(struct vr4300_dcache_line *line) {
invalidate_line(line);
}
// Invalidates an instruction cache line (only on a hit).
void vr4300_dcache_invalidate_hit(struct vr4300_dcache *dcache,
uint64_t vaddr, uint32_t paddr) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
uint32_t ptag = get_tag(line);
if (ptag == (paddr & ~0xFFFU) && is_valid(line))
invalidate_line(line);
}
// Probes the instruction cache for a matching line.
struct vr4300_dcache_line* vr4300_dcache_probe(
struct vr4300_dcache *dcache, uint64_t vaddr, uint32_t paddr) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
uint32_t ptag = get_tag(line);
// Virtually index, and physically tagged.
if (ptag == (paddr & ~0xFFFU) && is_valid(line))
return line;
return NULL;
}
// Marks the line as dirty.
void vr4300_dcache_set_dirty(struct vr4300_dcache_line *line) {
set_dirty(line);
}
// Sets the physical tag associated with the line.
void vr4300_dcache_set_taglo(struct vr4300_dcache *dcache,
uint64_t vaddr, uint32_t taglo) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
set_taglo(line, taglo);
}
// Returns the line if it's dirty and valid.
// Call before replacement of writeback entry.
struct vr4300_dcache_line *vr4300_dcache_should_flush_line(
struct vr4300_dcache *dcache, uint64_t vaddr) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
return is_dirty(line) && is_valid(line)
? line : NULL;
}
// Writes back the block if the line is valid, then invalidates the line.
struct vr4300_dcache_line *vr4300_dcache_wb_invalidate(
struct vr4300_dcache *dcache, uint64_t vaddr) {
struct vr4300_dcache_line *line = get_line(dcache, vaddr);
if (is_valid(line)) {
invalidate_line(line);
return line;
}
return NULL;
}
./vr4300/cp0.h 0000644 0001750 0001750 00000004321 13262010135 011063 0 ustar dan dan //
// vr4300/cp0.h: VR4300 system control coprocessor.
//
// CEN64: Cycle-Accurate Nintendo 64 Emulator.
// Copyright (C) 2015, Tyler J. Stachecki.
//
// This file is subject to the terms and conditions defined in
// 'LICENSE', which is part of this source code package.
//
#ifndef __vr4300_cp0_h__
#define __vr4300_cp0_h__
#include "common.h"
#include "tlb/tlb.h"
struct vr4300;
struct vr4300_cp0 {
struct cen64_tlb tlb;
uint32_t page_mask[32];
uint32_t pfn[32][2];
uint8_t state[32][2];
};
// Registers list.
enum vr4300_cp0_register {
VR4300_CP0_REGISTER_INDEX = 32,
VR4300_CP0_REGISTER_RANDOM = 33,
VR4300_CP0_REGISTER_ENTRYLO0 = 34,
VR4300_CP0_REGISTER_ENTRYLO1 = 35,
VR4300_CP0_REGISTER_CONTEXT = 36,
VR4300_CP0_REGISTER_PAGEMASK = 37,
VR4300_CP0_REGISTER_WIRED = 38,
VR4300_CP0_REGISTER_BADVADDR = 40,
VR4300_CP0_REGISTER_COUNT = 41,
VR4300_CP0_REGISTER_ENTRYHI = 42,
VR4300_CP0_REGISTER_COMPARE = 43,
VR4300_CP0_REGISTER_STATUS = 44,
VR4300_CP0_REGISTER_CAUSE = 45,
VR4300_CP0_REGISTER_EPC = 46,
VR4300_CP0_REGISTER_PRID = 47,
VR4300_CP0_REGISTER_CONFIG = 48,
VR4300_CP0_REGISTER_LLADDR = 49,
VR4300_CP0_REGISTER_WATCHLO = 50,
VR4300_CP0_REGISTER_WATCHHI = 51,
VR4300_CP0_REGISTER_XCONTEXT = 52,
VR4300_CP0_REGISTER_PARITYERROR = 58,
VR4300_CP0_REGISTER_CACHEERR = 59,
VR4300_CP0_REGISTER_TAGLO = 60,
VR4300_CP0_REGISTER_TAGHI = 61,
VR4300_CP0_REGISTER_ERROREPC = 62,
NUM_VR4300_CP0_REGISTERS = 32,
};
int VR4300_DMFC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_DMTC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_ERET(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_MFC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_MTC0(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_TLBP(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_TLBR(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_TLBWI(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
int VR4300_TLBWR(struct vr4300 *vr4300, uint32_t iw, uint64_t rs, uint64_t rt);
cen64_cold void vr4300_cp0_init(struct vr4300 *vr4300);
#endif
./vr4300/docs/ 0000755 0001750 0001750 00000000000 13262010135 011160 5 ustar dan dan ./vr4300/docs/vr43xx.pdf 0000644 0001750 0001750 00010313403 13262010135 013036 0 ustar dan dan %PDF-1.2
%âãÏÓ
3709 0 obj
<<
/Linearized 1
/O 3713
/H [ 14582 7462 ]
/L 2201347
/E 94741
/N 655
/T 2127047
>>
endobj
xref
3709 695
0000000016 00000 n
0000014275 00000 n
0000014395 00000 n
0000014539 00000 n
0000022044 00000 n
0000022291 00000 n
0000022361 00000 n
0000022449 00000 n
0000022549 00000 n
0000022681 00000 n
0000022751 00000 n
0000022821 00000 n
0000022998 00000 n
0000023068 00000 n
0000023246 00000 n
0000023400 00000 n
0000023549 00000 n
0000023619 00000 n
0000023794 00000 n
0000023900 00000 n
0000024005 00000 n
0000024115 00000 n
0000024185 00000 n
0000024302 00000 n
0000024372 00000 n
0000024442 00000 n
0000024512 00000 n
0000024582 00000 n
0000024687 00000 n
0000024783 00000 n
0000024893 00000 n
0000024963 00000 n
0000025033 00000 n
0000025103 00000 n
0000025173 00000 n
0000025274 00000 n
0000025391 00000 n
0000025512 00000 n
0000025582 00000 n
0000025702 00000 n
0000025772 00000 n
0000025842 00000 n
0000025912 00000 n
0000026074 00000 n
0000026144 00000 n
0000026299 00000 n
0000026447 00000 n
0000026517 00000 n
0000026692 00000 n
0000026791 00000 n
0000026885 00000 n
0000027035 00000 n
0000027105 00000 n
0000027219 00000 n
0000027289 00000 n
0000027402 00000 n
0000027472 00000 n
0000027596 00000 n
0000027666 00000 n
0000027774 00000 n
0000027844 00000 n
0000027914 00000 n
0000027984 00000 n
0000028054 00000 n
0000028171 00000 n
0000028277 00000 n
0000028347 00000 n
0000028417 00000 n
0000028487 00000 n
0000028595 00000 n
0000028712 00000 n
0000028838 00000 n
0000028908 00000 n
0000029082 00000 n
0000029152 00000 n
0000029273 00000 n
0000029343 00000 n
0000029464 00000 n
0000029534 00000 n
0000029653 00000 n
0000029723 00000 n
0000029793 00000 n
0000029863 00000 n
0000029996 00000 n
0000030066 00000 n
0000030197 00000 n
0000030267 00000 n
0000030337 00000 n
0000030518 00000 n
0000030588 00000 n
0000030770 00000 n
0000030877 00000 n
0000031000 00000 n
0000031120 00000 n
0000031190 00000 n
0000031335 00000 n
0000031405 00000 n
0000031537 00000 n
0000031607 00000 n
0000031743 00000 n
0000031813 00000 n
0000031883 00000 n
0000031953 00000 n
0000032023 00000 n
0000032193 00000 n
0000032315 00000 n
0000032439 00000 n
0000032559 00000 n
0000032629 00000 n
0000032778 00000 n
0000032848 00000 n
0000032977 00000 n
0000033047 00000 n
0000033179 00000 n
0000033249 00000 n
0000033381 00000 n
0000033451 00000 n
0000033521 00000 n
0000033591 00000 n
0000033661 00000 n
0000033826 00000 n
0000033951 00000 n
0000034021 00000 n
0000034128 00000 n
0000034232 00000 n
0000034354 00000 n
0000034424 00000 n
0000034494 00000 n
0000034564 00000 n
0000034634 00000 n
0000034802 00000 n
0000034913 00000 n
0000035084 00000 n
0000035203 00000 n
0000035273 00000 n
0000035396 00000 n
0000035522 00000 n
0000035592 00000 n
0000035662 00000 n
0000035786 00000 n
0000035856 00000 n
0000035986 00000 n
0000036056 00000 n
0000036126 00000 n
0000036196 00000 n
0000036266 00000 n
0000036437 00000 n
0000036558 00000 n
0000036671 00000 n
0000036741 00000 n
0000036918 00000 n
0000037036 00000 n
0000037106 00000 n
0000037216 00000 n
0000037323 00000 n
0000037446 00000 n
0000037516 00000 n
0000037636 00000 n
0000037706 00000 n
0000037834 00000 n
0000037904 00000 n
0000038032 00000 n
0000038102 00000 n
0000038223 00000 n
0000038293 00000 n
0000038363 00000 n
0000038433 00000 n
0000038503 00000 n
0000038573 00000 n
0000038642 00000 n
0000038808 00000 n
0000038907 00000 n
0000039066 00000 n
0000039136 00000 n
0000039334 00000 n
0000039447 00000 n
0000039572 00000 n
0000039642 00000 n
0000039712 00000 n
0000039782 00000 n
0000039959 00000 n
0000040084 00000 n
0000040209 00000 n
0000040355 00000 n
0000040425 00000 n
0000040548 00000 n
0000040618 00000 n
0000040740 00000 n
0000040810 00000 n
0000040948 00000 n
0000041018 00000 n
0000041088 00000 n
0000041158 00000 n
0000041228 00000 n
0000041393 00000 n
0000041488 00000 n
0000041558 00000 n
0000041628 00000 n
0000041812 00000 n
0000041941 00000 n
0000042049 00000 n
0000042119 00000 n
0000042189 00000 n
0000042258 00000 n
0000042439 00000 n
0000042566 00000 n
0000042688 00000 n
0000042836 00000 n
0000042905 00000 n
0000043054 00000 n
0000043123 00000 n
0000043192 00000 n
0000043261 00000 n
0000043330 00000 n
0000043527 00000 n
0000043652 00000 n
0000043802 00000 n
0000043969 00000 n
0000044038 00000 n
0000044204 00000 n
0000044273 00000 n
0000044342 00000 n
0000044411 00000 n
0000044480 00000 n
0000044647 00000 n
0000044764 00000 n
0000044885 00000 n
0000045022 00000 n
0000045091 00000 n
0000045227 00000 n
0000045296 00000 n
0000045430 00000 n
0000045499 00000 n
0000045638 00000 n
0000045707 00000 n
0000045846 00000 n
0000045915 00000 n
0000046052 00000 n
0000046121 00000 n
0000046190 00000 n
0000046259 00000 n
0000046328 00000 n
0000046507 00000 n
0000046607 00000 n
0000046716 00000 n
0000046854 00000 n
0000046923 00000 n
0000047039 00000 n
0000047108 00000 n
0000047223 00000 n
0000047292 00000 n
0000047361 00000 n
0000047430 00000 n
0000047499 00000 n
0000047673 00000 n
0000047781 00000 n
0000047884 00000 n
0000048012 00000 n
0000048081 00000 n
0000048205 00000 n
0000048274 00000 n
0000048403 00000 n
0000048472 00000 n
0000048600 00000 n
0000048669 00000 n
0000048738 00000 n
0000048807 00000 n
0000048876 00000 n
0000049053 00000 n
0000049167 00000 n
0000049291 00000 n
0000049419 00000 n
0000049488 00000 n
0000049629 00000 n
0000049698 00000 n
0000049767 00000 n
0000049836 00000 n
0000049905 00000 n
0000050013 00000 n
0000050121 00000 n
0000050239 00000 n
0000050308 00000 n
0000050438 00000 n
0000050507 00000 n
0000050628 00000 n
0000050697 00000 n
0000050766 00000 n
0000050835 00000 n
0000050904 00000 n
0000050973 00000 n
0000051108 00000 n
0000051216 00000 n
0000051386 00000 n
0000051455 00000 n
0000051632 00000 n
0000051739 00000 n
0000051924 00000 n
0000052070 00000 n
0000052139 00000 n
0000052262 00000 n
0000052390 00000 n
0000052459 00000 n
0000052528 00000 n
0000052656 00000 n
0000052725 00000 n
0000052794 00000 n
0000052966 00000 n
0000053090 00000 n
0000053159 00000 n
0000053278 00000 n
0000053391 00000 n
0000053530 00000 n
0000053599 00000 n
0000053668 00000 n
0000053737 00000 n
0000053806 00000 n
0000053875 00000 n
0000053944 00000 n
0000054123 00000 n
0000054230 00000 n
0000054384 00000 n
0000054453 00000 n
0000054625 00000 n
0000054726 00000 n
0000054836 00000 n
0000054974 00000 n
0000055043 00000 n
0000055173 00000 n
0000055242 00000 n
0000055365 00000 n
0000055434 00000 n
0000055563 00000 n
0000055632 00000 n
0000055752 00000 n
0000055821 00000 n
0000055890 00000 n
0000055959 00000 n
0000056028 00000 n
0000056131 00000 n
0000056230 00000 n
0000056345 00000 n
0000056414 00000 n
0000056483 00000 n
0000056552 00000 n
0000056621 00000 n
0000056690 00000 n
0000056869 00000 n
0000056976 00000 n
0000057093 00000 n
0000057223 00000 n
0000057292 00000 n
0000057361 00000 n
0000057528 00000 n
0000057597 00000 n
0000057691 00000 n
0000057818 00000 n
0000057946 00000 n
0000058015 00000 n
0000058142 00000 n
0000058211 00000 n
0000058345 00000 n
0000058414 00000 n
0000058550 00000 n
0000058619 00000 n
0000058746 00000 n
0000058815 00000 n
0000058884 00000 n
0000058953 00000 n
0000059022 00000 n
0000059091 00000 n
0000059265 00000 n
0000059360 00000 n
0000059476 00000 n
0000059545 00000 n
0000059708 00000 n
0000059830 00000 n
0000059899 00000 n
0000060037 00000 n
0000060157 00000 n
0000060285 00000 n
0000060354 00000 n
0000060479 00000 n
0000060548 00000 n
0000060679 00000 n
0000060748 00000 n
0000060873 00000 n
0000060942 00000 n
0000061011 00000 n
0000061080 00000 n
0000061205 00000 n
0000061274 00000 n
0000061343 00000 n
0000061511 00000 n
0000061580 00000 n
0000061714 00000 n
0000061843 00000 n
0000061980 00000 n
0000062049 00000 n
0000062194 00000 n
0000062263 00000 n
0000062400 00000 n
0000062469 00000 n
0000062538 00000 n
0000062607 00000 n
0000062676 00000 n
0000062745 00000 n
0000062925 00000 n
0000063042 00000 n
0000063172 00000 n
0000063241 00000 n
0000063406 00000 n
0000063475 00000 n
0000063654 00000 n
0000063758 00000 n
0000063867 00000 n
0000063988 00000 n
0000064057 00000 n
0000064189 00000 n
0000064258 00000 n
0000064392 00000 n
0000064461 00000 n
0000064582 00000 n
0000064651 00000 n
0000064789 00000 n
0000064858 00000 n
0000064994 00000 n
0000065063 00000 n
0000065190 00000 n
0000065259 00000 n
0000065386 00000 n
0000065455 00000 n
0000065581 00000 n
0000065650 00000 n
0000065770 00000 n
0000065839 00000 n
0000065968 00000 n
0000066037 00000 n
0000066181 00000 n
0000066250 00000 n
0000066375 00000 n
0000066444 00000 n
0000066569 00000 n
0000066638 00000 n
0000066766 00000 n
0000066835 00000 n
0000066967 00000 n
0000067036 00000 n
0000067105 00000 n
0000067174 00000 n
0000067302 00000 n
0000067371 00000 n
0000067481 00000 n
0000067628 00000 n
0000067770 00000 n
0000067839 00000 n
0000067978 00000 n
0000068047 00000 n
0000068176 00000 n
0000068245 00000 n
0000068393 00000 n
0000068462 00000 n
0000068613 00000 n
0000068682 00000 n
0000068807 00000 n
0000068876 00000 n
0000069001 00000 n
0000069070 00000 n
0000069197 00000 n
0000069266 00000 n
0000069391 00000 n
0000069460 00000 n
0000069586 00000 n
0000069655 00000 n
0000069724 00000 n
0000069793 00000 n
0000069862 00000 n
0000069931 00000 n
0000070000 00000 n
0000070164 00000 n
0000070286 00000 n
0000070431 00000 n
0000070500 00000 n
0000070673 00000 n
0000070780 00000 n
0000070886 00000 n
0000071002 00000 n
0000071071 00000 n
0000071223 00000 n
0000071292 00000 n
0000071445 00000 n
0000071514 00000 n
0000071661 00000 n
0000071730 00000 n
0000071856 00000 n
0000071925 00000 n
0000072082 00000 n
0000072151 00000 n
0000072275 00000 n
0000072344 00000 n
0000072520 00000 n
0000072589 00000 n
0000072714 00000 n
0000072783 00000 n
0000072852 00000 n
0000072921 00000 n
0000072990 00000 n
0000073174 00000 n
0000073269 00000 n
0000073338 00000 n
0000073407 00000 n
0000073511 00000 n
0000073633 00000 n
0000073775 00000 n
0000073844 00000 n
0000073980 00000 n
0000074049 00000 n
0000074118 00000 n
0000074187 00000 n
0000074256 00000 n
0000074325 00000 n
0000074505 00000 n
0000074643 00000 n
0000074742 00000 n
0000074811 00000 n
0000074943 00000 n
0000075012 00000 n
0000075180 00000 n
0000075249 00000 n
0000075347 00000 n
0000075498 00000 n
0000075679 00000 n
0000075807 00000 n
0000075915 00000 n
0000075984 00000 n
0000076130 00000 n
0000076199 00000 n
0000076330 00000 n
0000076399 00000 n
0000076523 00000 n
0000076592 00000 n
0000076718 00000 n
0000076787 00000 n
0000076856 00000 n
0000076988 00000 n
0000077121 00000 n
0000077190 00000 n
0000077333 00000 n
0000077402 00000 n
0000077527 00000 n
0000077596 00000 n
0000077722 00000 n
0000077791 00000 n
0000077918 00000 n
0000077987 00000 n
0000078113 00000 n
0000078182 00000 n
0000078251 00000 n
0000078320 00000 n
0000078389 00000 n
0000078526 00000 n
0000078681 00000 n
0000078750 00000 n
0000078889 00000 n
0000078958 00000 n
0000079106 00000 n
0000079175 00000 n
0000079323 00000 n
0000079392 00000 n
0000079542 00000 n
0000079611 00000 n
0000079761 00000 n
0000079830 00000 n
0000079899 00000 n
0000079968 00000 n
0000080037 00000 n
0000080129 00000 n
0000080198 00000 n
0000080267 00000 n
0000080433 00000 n
0000080544 00000 n
0000080694 00000 n
0000080763 00000 n
0000080875 00000 n
0000081009 00000 n
0000081138 00000 n
0000081207 00000 n
0000081332 00000 n
0000081401 00000 n
0000081531 00000 n
0000081600 00000 n
0000081732 00000 n
0000081801 00000 n
0000081870 00000 n
0000081939 00000 n
0000082008 00000 n
0000082077 00000 n
0000082237 00000 n
0000082353 00000 n
0000082499 00000 n
0000082568 00000 n
0000082681 00000 n
0000082804 00000 n
0000082957 00000 n
0000083026 00000 n
0000083158 00000 n
0000083227 00000 n
0000083364 00000 n
0000083433 00000 n
0000083502 00000 n
0000083571 00000 n
0000083640 00000 n
0000083747 00000 n
0000083815 00000 n
0000083918 00000 n
0000084026 00000 n
0000084095 00000 n
0000084273 00000 n
0000084342 00000 n
0000084505 00000 n
0000084629 00000 n
0000084734 00000 n
0000084803 00000 n
0000084872 00000 n
0000084994 00000 n
0000085063 00000 n
0000085180 00000 n
0000085283 00000 n
0000085418 00000 n
0000085487 00000 n
0000085624 00000 n
0000085693 00000 n
0000085825 00000 n
0000085894 00000 n
0000086028 00000 n
0000086097 00000 n
0000086215 00000 n
0000086284 00000 n
0000086353 00000 n
0000086422 00000 n
0000086545 00000 n
0000086614 00000 n
0000086683 00000 n
0000086751 00000 n
0000086884 00000 n
0000086952 00000 n
0000087020 00000 n
0000087089 00000 n
0000087255 00000 n
0000087419 00000 n
0000087488 00000 n
0000087626 00000 n
0000087736 00000 n
0000087883 00000 n
0000087952 00000 n
0000088021 00000 n
0000088090 00000 n
0000088159 00000 n
0000088276 00000 n
0000088386 00000 n
0000088511 00000 n
0000088645 00000 n
0000088714 00000 n
0000088783 00000 n
0000088852 00000 n
0000088921 00000 n
0000089101 00000 n
0000089170 00000 n
0000089288 00000 n
0000089412 00000 n
0000089481 00000 n
0000089550 00000 n
0000089619 00000 n
0000089689 00000 n
0000089824 00000 n
0000089847 00000 n
0000089970 00000 n
0000090530 00000 n
0000090553 00000 n
0000091104 00000 n
0000091127 00000 n
0000091647 00000 n
0000091670 00000 n
0000092168 00000 n
0000092191 00000 n
0000092687 00000 n
0000092710 00000 n
0000092828 00000 n
0000092914 00000 n
0000093402 00000 n
0000093425 00000 n
0000094020 00000 n
0000094043 00000 n
0000094483 00000 n
0000014582 00000 n
0000022020 00000 n
trailer
<<
/Size 4404
/Info 3560 0 R
/Encrypt 3711 0 R
/Root 3710 0 R
/Prev 2127035
/ID[<8cd20de7b0d5bae1802b496ab0f4b6ae><8cd20de7b0d5bae1802b496ab0f4b6ae>]
>>
startxref
0
%%EOF
3710 0 obj
<<
/Type /Catalog
/Pages 3561 0 R
/Outlines 3714 0 R
/PageMode /UseOutlines
/Names 3712 0 R
>>
endobj
3711 0 obj
<<
/Filter /Standard
/V 1
/R 2
/O (ÚÅ‘C¹Ï «$·CAŠ6ÑÊÛÓíÂEòȱA<²)
/U (Á¸Úà2 \\¿~§îÌ–Õ2àD×Í^{A¸uT¯Úô.¬ç)
/P 65524
>>
endobj
3712 0 obj
<<
/Dests 3559 0 R
>>
endobj
4402 0 obj
<< /S 11614 /T 13131 /O 14074 /E 14090 /Filter /FlateDecode /Length 4403 0 R >>
stream
“¨I©Ò[yü—™a«¡e,ײÍÕ Ìù,©D•PÅ4¯SŸGr>.uJò)шm6»VX»;g¨Dþª1sDSöITGvDaÕ”2Ь‡ÙLc»œ´=¬|“€ó§L6oŠpêû©<:”Yp~ãtn®(m†ÓdZeT®EÄYLåOF»»?m‰h›ŒÑê‰ÌŒek¤†XÊ5/²[¨ãW¹Óæ˜E±"{l]aÜ- N5GÀE6ÍŒù¦w~‘éÊƒÌØ0ºŠ=…x˜j‹llSF˜î›9ÅA+>ÝŽ|Žz
“4¥åh[¾è¤X¢”þ¢rå÷5Ô4¦‰¹w˜w[.§‹èB¸!h}v6V}Üï‘,et}G’d¯C«”˲dY½ÙÖ¯Òç)³éB`½Ëù=ˆî~¢Çè{ûlœÛæ¥wRÄ kÁYlAÞmKCÿ÷º ¦!4´¹aÕ1†óaÞGZS‘%øAˆ J=dÀAw;
+à+ZŸŸ”z·P»í<çªaºØ
p!h”KJ÷a7®‰—(+p8Øôu2ìdGW D<ñ»²zê7oŽù
¤çÍâ²'®|cËŸ[Æ ËÔ¥!õãZå°ð—õ©Ð“ÿ¨“+Ñs/Ñ÷gIÐ¥C¶Þ×°¿‚ÛĶkWjEÊÐédûL€ë Ëæ×¼ÚC3nBFÓÔŸ7i§ÔÙh%|gmÀØÕ+k½)Æûær‡Ïf–½ÿX׸êúv ëNøuËl
¥?ð618´ã€µl,ª—JrIÐ1v)Ñ…d@ S3ÿ§‡¿ÏÜë!oQMî#;Ymm‚âG„ вۋ¦£Ãšˆ|--«ŒûL–©*Vj{,᯳ÂcŸ_è¨é~ìÃÇØÿÇvíÈö¯z%iÛ®o>ÒíÖæ ßå9KèýN.šNZ‡Ùl‹²˜¨k÷:Ѐ.¥x“Á¸çù¤eìÑioæï5/Mc¤'žqøakt£k*@?yA~pTFé{޽©¼)‹ïiwV%j
"KB,¨7U•®<öûJ"#Y²¢ü+±&:¿ÎˆÐÏ´gÒî™ZÊ<áï5[זּiÌì¹ï‰õ/6~™v´÷ÐĆÎIõûƒŠ»RùáÖ2Á ò›½ É.hšê¯Dö÷jãÖç°Ÿ¼†òú¦üëû÷âfïƒ4îc'žsE^bÏhÃÝòV”1pÁçÝdÓB:»BKÍÒâgª»÷ÿ¸€PÒÝxy™[< oÊR—eÖ:û;ëV”„¶ª¡L„Êý¼“ 8Ù´_@Veíz%h8§pÒ¿oƒ yŠ~;öÈŽK~Š_ûï?«¢ 'Ÿ=ü°Òvu‘;’e[x¾¨ù–8=¸6½Ï—ÄGtÒŸù2¿¤°GW;ò}Es÷Hmƒpȵ¯?ÎÌì°Ö#àwRøÌþ„gm‹PÁ¯Må8D> í3ÅDä£ûS¶7È9Ü÷ÕJ©âVØÁÛ`ï úÍ7Óú»ñðø>õ'Xä'²¡#ŸY½Ïñ/8É
ŠK ÉÞéY5ä¡v«