mirror of
https://github.com/simple64/simple64.git
synced 2026-09-08 05:12:43 +02:00
update core
This commit is contained in:
+98
-64
@@ -20,31 +20,47 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- cc: GCC
|
||||
platform: x64
|
||||
bits: 64
|
||||
- cc: GCC
|
||||
platform: x86
|
||||
bits: 32
|
||||
- cc: Clang
|
||||
name: Linux / ${{ matrix.cc }} / x64 | x86
|
||||
runs-on: ubuntu-20.04
|
||||
platform: x64
|
||||
bits: 64
|
||||
- cc: Clang
|
||||
platform: x86
|
||||
bits: 32
|
||||
name: Linux / ${{ matrix.cc }} / ${{ matrix.platform }}
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Get build dependencies and arrange the environment
|
||||
run: |
|
||||
sudo dpkg --add-architecture i386
|
||||
if [[ "${{ matrix.platform }}" == "x86" ]]; then sudo dpkg --add-architecture i386; fi
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install libfreetype6-dev libgl1-mesa-dev libglu1-mesa-dev libpng-dev libsdl1.2-dev libsdl2-dev nasm zlib1g-dev
|
||||
sudo apt-get --reinstall -y install gcc-multilib g++-multilib libc6 libc6-dev-i386 libfreetype6:i386 libgl1-mesa-glx:i386 libglu1-mesa:i386 libpng16-16:i386 libsdl1.2debian:i386 libsdl2-2.0-0:i386 zlib1g:i386
|
||||
LINK="sudo ln -s -T"
|
||||
cd /usr/lib/i386-linux-gnu
|
||||
if ! [[ -f libfreetype.so ]]; then ${LINK} libfreetype.so.6.17.1 libfreetype.so; fi
|
||||
if ! [[ -f libGL.so ]]; then ${LINK} libGL.so.1.7.0 libGL.so; fi
|
||||
if ! [[ -f libGLU.so ]]; then ${LINK} libGLU.so.1.3.1 libGLU.so; fi
|
||||
if ! [[ -f libpng16.so ]]; then ${LINK} libpng16.so.16.37.0 libpng16.so; fi
|
||||
if ! [[ -f libSDL.so ]]; then ${LINK} libSDL-1.2.so.0.11.4 libSDL.so; fi
|
||||
if ! [[ -f libSDL2.so ]]; then ${LINK} libSDL2-2.0.so.0.10.0 libSDL2.so; fi
|
||||
if ! [[ -f libz.so ]]; then ${LINK} libz.so.1.2.11 libz.so; fi
|
||||
cd /usr/include/SDL2
|
||||
if ! [[ -f _real_SDL_config.h ]]; then ${LINK} ../x86_64-linux-gnu/SDL2/_real_SDL_config.h _real_SDL_config.h; fi
|
||||
if [[ "${{ matrix.platform }}" == "x86" ]]; then
|
||||
sudo apt-get --reinstall -y install gcc-multilib g++-multilib libc6 libc6-dev-i386 libfreetype6:i386 libgl1-mesa-glx:i386 libglu1-mesa:i386 libpng16-16:i386 libsdl1.2debian:i386 libsdl2-2.0-0:i386 zlib1g:i386
|
||||
LINK="sudo ln -s -T"
|
||||
cd /usr/lib/i386-linux-gnu
|
||||
if ! [[ -f libfreetype.so ]]; then ${LINK} libfreetype.so.6.18.1 libfreetype.so; fi
|
||||
if ! [[ -f libGL.so ]]; then ${LINK} libGL.so.1.7.0 libGL.so; fi
|
||||
if ! [[ -f libGLU.so ]]; then ${LINK} libGLU.so.1.3.1 libGLU.so; fi
|
||||
if ! [[ -f libpng16.so ]]; then ${LINK} libpng16.so.16.37.0 libpng16.so; fi
|
||||
if ! [[ -f libSDL.so ]]; then ${LINK} libSDL-1.2.so.0.11.4 libSDL.so; fi
|
||||
if ! [[ -f libSDL2.so ]]; then ${LINK} libSDL2-2.0.so.0.18.2 libSDL2.so; fi
|
||||
if ! [[ -f libz.so ]]; then ${LINK} libz.so.1.2.11 libz.so; fi
|
||||
cd /usr/include/SDL2
|
||||
if ! [[ -f _real_SDL_config.h ]]; then ${LINK} ../x86_64-linux-gnu/SDL2/_real_SDL_config.h _real_SDL_config.h; fi
|
||||
fi
|
||||
sudo ldconfig
|
||||
- name: Build and related stuff
|
||||
run: |
|
||||
if [[ ${{ matrix.bits }} -eq 32 ]]; then export OPTFLAGS="-O2 -flto -mtune=pentium4"; else export OPTFLAGS="-O2 -flto -mtune=core2"; fi
|
||||
G_REV=$(git rev-parse --short HEAD)
|
||||
echo "G_REV=${G_REV}" >> "${GITHUB_ENV}"
|
||||
ORIG="$(pwd)"
|
||||
if [[ "${{ matrix.cc }}" == "GCC" ]]; then
|
||||
CC="gcc"
|
||||
CXX="g++"
|
||||
@@ -52,40 +68,45 @@ jobs:
|
||||
CC="clang"
|
||||
CXX="clang++"
|
||||
fi
|
||||
if [[ ${{ matrix.bits }} -eq 32 ]]; then export PIC="1"; fi
|
||||
${CC} --version
|
||||
for TSK in 1 2 3 4 5 6 7 8
|
||||
SDL="sdl"
|
||||
MSG="1.2"
|
||||
mkdir tmp
|
||||
for DYN in 0 1 0 1
|
||||
do
|
||||
unset PIC
|
||||
if [[ ${TSK} -le 4 ]]; then
|
||||
SDL="sdl"
|
||||
MSG="SDL1.2"
|
||||
if [[ ${DYN} -eq 0 ]]; then
|
||||
export POSTFIX="-old"
|
||||
else
|
||||
SDL="sdl2"
|
||||
MSG="SDL2"
|
||||
fi
|
||||
if [[ "${DYN}" == "0" ]]; then
|
||||
DYN="1"
|
||||
unset POSTFIX
|
||||
MSG="${MSG} / NEW_DYNAREC"
|
||||
else
|
||||
DYN="0"
|
||||
if [[ "${BITS}" == "64" ]]; then BITS="32"; else BITS="64"; fi
|
||||
fi
|
||||
if [[ ${BITS} -eq 32 ]]; then
|
||||
if [[ "${CC}" == "clang" ]]; then export PIC="1"; fi
|
||||
MSG="x86 / ${MSG}"
|
||||
else
|
||||
MSG="x64 / ${MSG}"
|
||||
fi
|
||||
echo ""
|
||||
echo ":: ${{ matrix.cc }} ${MSG} ::"
|
||||
echo ":: ${{ matrix.cc }} ${{ matrix.platform }} / SDL${MSG} ::"
|
||||
echo ""
|
||||
make -C projects/unix clean
|
||||
make NEW_DYNAREC="${DYN}" -C projects/unix clean
|
||||
echo ""
|
||||
make CC="${CC}" CXX="${CXX}" BITS="${BITS}" SDL_CONFIG="${SDL}-config" NEW_DYNAREC="${DYN}" -C projects/unix all
|
||||
make CC="${CC}" CXX="${CXX}" BITS="${{ matrix.bits }}" SDL_CONFIG="${SDL}-config" NEW_DYNAREC="${DYN}" -C projects/unix all -j4
|
||||
echo ""
|
||||
ls -gG projects/unix/*.so*
|
||||
ldd projects/unix/libmupen64plus.so.2.0.0
|
||||
make BITS="${{ matrix.bits }}" NEW_DYNAREC="${DYN}" -C projects/unix install DESTDIR="${ORIG}/tmp"
|
||||
echo ""
|
||||
cd tmp/usr/local/lib
|
||||
ls -gG libmupen64plus${POSTFIX}.so*
|
||||
ldd libmupen64plus${POSTFIX}.so.2.0.0
|
||||
if [[ ${DYN} -eq 1 ]]; then
|
||||
SDL="sdl2"
|
||||
MSG="2"
|
||||
fi
|
||||
cd "${ORIG}"
|
||||
done
|
||||
mkdir pkg
|
||||
if [[ "${CC}" == "gcc" ]]; then tar cvzf pkg/mupen64plus-core-${{ matrix.platform }}-g${G_REV}.tar.gz -C tmp/ "usr"; fi
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mupen64plus-core-${{ matrix.platform }}-g${{ env.G_REV }}
|
||||
path: pkg/*
|
||||
if-no-files-found: ignore
|
||||
|
||||
MSYS2:
|
||||
strategy:
|
||||
@@ -106,13 +127,14 @@ jobs:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MINGW${{ matrix.bits }}
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
libtool
|
||||
make
|
||||
mingw-w64-${{ matrix.cross }}-gcc
|
||||
mingw-w64-${{ matrix.cross }}-toolchain
|
||||
@@ -123,26 +145,28 @@ jobs:
|
||||
mingw-w64-${{ matrix.cross }}-zlib
|
||||
- name: Build and related stuff
|
||||
run: |
|
||||
export OPTFLAGS="-O2 -flto"
|
||||
if [[ ${{ matrix.bits }} -eq 32 ]]; then export OPTFLAGS="-O2 -flto -mtune=pentium4"; else export OPTFLAGS="-O2 -flto -mtune=core2"; fi
|
||||
echo "G_REV=$(git rev-parse --short HEAD)" >> "${GITHUB_ENV}"
|
||||
ORIG="$(pwd)"
|
||||
CC="gcc"
|
||||
CXX="g++"
|
||||
${CC} --version
|
||||
mkdir backup
|
||||
LIB="-old"
|
||||
mkdir tmp
|
||||
export POSTFIX="-old"
|
||||
for DYN in 0 1
|
||||
do
|
||||
echo ""
|
||||
echo ":: ${{ matrix.cc }} ${{ matrix.platform }} / SDL2${MSG} ::"
|
||||
echo ""
|
||||
make -C projects/unix clean
|
||||
make NEW_DYNAREC="${DYN}" -C projects/unix clean
|
||||
echo ""
|
||||
make CC="${CC}" CXX="${CXX}" BITS="${{ matrix.bits }}" NEW_DYNAREC="${DYN}" -C projects/unix all
|
||||
make CC="${CC}" CXX="${CXX}" BITS="${{ matrix.bits }}" NEW_DYNAREC="${DYN}" -C projects/unix all -j4
|
||||
echo ""
|
||||
cp projects/unix/*.dll backup/mupen64plus${LIB}.dll
|
||||
ls -gG backup/mupen64plus${LIB}.dll
|
||||
ldd backup/mupen64plus${LIB}.dll
|
||||
unset LIB
|
||||
make BITS="${{ matrix.bits }}" NEW_DYNAREC="${DYN}" -C projects/unix install PLUGINDIR="" SHAREDIR="" BINDIR="" MANDIR="" LIBDIR="" APPSDIR="" ICONSDIR="icons" INCDIR="api" LDCONFIG="true" DESTDIR="${ORIG}/tmp"
|
||||
echo ""
|
||||
ls -gG tmp/mupen64plus${POSTFIX}.dll
|
||||
ldd tmp/mupen64plus${POSTFIX}.dll
|
||||
unset POSTFIX
|
||||
MSG=" / NEW_DYNAREC"
|
||||
done
|
||||
- name: Copy binaries, dependencies, etc...
|
||||
@@ -162,14 +186,14 @@ jobs:
|
||||
cp -r "${DAT}" ../pkg/
|
||||
done
|
||||
fi
|
||||
cd ../backup
|
||||
cd ../tmp
|
||||
for BIN in *.dll
|
||||
do
|
||||
echo ":: Copying ${BIN}"
|
||||
cp "${BIN}" ../pkg/
|
||||
done
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mupen64plus-core-msys2-${{ matrix.platform }}-g${{ env.G_REV }}
|
||||
path: pkg/*
|
||||
@@ -189,8 +213,8 @@ jobs:
|
||||
run:
|
||||
shell: cmd
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: microsoft/setup-msbuild@v1.0.3
|
||||
- uses: actions/checkout@v3
|
||||
- uses: microsoft/setup-msbuild@v1
|
||||
# with:
|
||||
# vs-version: 16.11
|
||||
- name: Build and related stuff
|
||||
@@ -226,19 +250,19 @@ jobs:
|
||||
copy "..\..\mupen64plus-win32-deps\SDL2_net-2.0.1\lib\${{ matrix.platform }}\*.dll" .
|
||||
copy "..\..\mupen64plus-win32-deps\zlib-1.2.11\lib\${{ matrix.platform }}\*.dll" .
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: mupen64plus-core-msvc-${{ matrix.platform }}-g${{ env.G_REV }}
|
||||
path: pkg/*
|
||||
|
||||
Nightly-build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [MSYS2, MSVC]
|
||||
needs: [Linux, MSYS2, MSVC]
|
||||
if: github.ref == 'refs/heads/master'
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
path: binaries
|
||||
- name: Get some tools
|
||||
@@ -251,20 +275,30 @@ jobs:
|
||||
cd binaries
|
||||
for BIN in *
|
||||
do
|
||||
echo ":: Creating ${BIN}.zip"
|
||||
cd "${BIN}"
|
||||
zip -r "../../pkg/${BIN}.zip" *
|
||||
if [[ "${BIN:17:4}" == "msys" ]]; then
|
||||
echo ":: Creating ${BIN}.zip"
|
||||
zip -r "../../pkg/${BIN}.zip" *
|
||||
elif [[ "${BIN:17:4}" == "msvc" ]]; then
|
||||
echo ":: Creating ${BIN}.zip"
|
||||
zip -r "../../pkg/${BIN}.zip" *
|
||||
else
|
||||
echo ":: Recovering ${BIN}.tar.gz"
|
||||
mv *.tar.gz ../../pkg/
|
||||
fi
|
||||
cd ..
|
||||
done
|
||||
cd ../pkg
|
||||
echo ""
|
||||
for BIN in *.zip
|
||||
for BIN in *
|
||||
do
|
||||
ls -gG ${BIN}
|
||||
tigerdeep -l ${BIN} >> ${BIN:0:16}.tiger.txt
|
||||
sha256sum ${BIN} >> ${BIN:0:16}.sha256.txt
|
||||
sha512sum ${BIN} >> ${BIN:0:16}.sha512.txt
|
||||
tigerdeep -l ${BIN} >> ../${BIN:0:16}.tiger.txt
|
||||
sha256sum ${BIN} >> ../${BIN:0:16}.sha256.txt
|
||||
sha512sum ${BIN} >> ../${BIN:0:16}.sha512.txt
|
||||
done
|
||||
mv ../*.tiger.txt .
|
||||
mv ../*.sha*.txt .
|
||||
echo ""
|
||||
echo "TIGER:"
|
||||
cat *.tiger.txt
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -160,6 +160,8 @@
|
||||
<ClCompile Include="..\..\src\main\util.c" />
|
||||
<ClCompile Include="..\..\src\main\workqueue.c" />
|
||||
<ClCompile Include="..\..\src\device\memory\memory.c" />
|
||||
<ClCompile Include="..\..\src\device\memory\dcache.c" />
|
||||
<ClCompile Include="..\..\src\device\memory\icache.c" />
|
||||
<ClCompile Include="..\..\src\osal\dynamiclib_unix.c">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
|
||||
|
||||
@@ -177,6 +177,12 @@
|
||||
<ClCompile Include="..\..\src\device\memory\memory.c">
|
||||
<Filter>device\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\device\memory\dcache.c">
|
||||
<Filter>device\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\device\memory\icache.c">
|
||||
<Filter>device\memory</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\osal\dynamiclib_unix.c">
|
||||
<Filter>osal</Filter>
|
||||
</ClCompile>
|
||||
|
||||
@@ -182,7 +182,6 @@ ifeq ($(ARCH_DETECTED), 64BITS_32)
|
||||
endif
|
||||
ifneq ($(OS), OSX)
|
||||
ifeq ($(OS), MINGW)
|
||||
CFLAGS += -march=i686
|
||||
LDFLAGS += -Wl,-m,i386pe
|
||||
else
|
||||
CFLAGS += -m32
|
||||
@@ -551,6 +550,8 @@ SOURCE = \
|
||||
$(SRCDIR)/device/gb/mbc3_rtc.c \
|
||||
$(SRCDIR)/device/gb/m64282fp.c \
|
||||
$(SRCDIR)/device/memory/memory.c \
|
||||
$(SRCDIR)/device/memory/dcache.c \
|
||||
$(SRCDIR)/device/memory/icache.c \
|
||||
$(SRCDIR)/device/pif/bootrom_hle.c \
|
||||
$(SRCDIR)/device/pif/cic.c \
|
||||
$(SRCDIR)/device/pif/n64_cic_nus_6105.c \
|
||||
@@ -805,7 +806,7 @@ uninstall:
|
||||
$(RM) "$(DESTDIR)$(SHAREDIR)/mupencheat.txt"
|
||||
|
||||
clean:
|
||||
$(RM) -r $(TARGET) $(SONAME) $(OBJDIR) $(SRCDIR)/asm_defines/asm_defines_*
|
||||
$(RM) -r $(TARGET) $(SONAME) _obj $(OBJDIR) $(SRCDIR)/asm_defines/asm_defines_*
|
||||
|
||||
# build dependency files
|
||||
CFLAGS += -MD -MP
|
||||
|
||||
@@ -447,7 +447,7 @@ EXPORT uint32_t CALL DebugVirtualToPhysical(uint32_t address)
|
||||
struct r4300_core* r4300 = &dev->r4300;
|
||||
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
address = virtual_to_physical_address(r4300, address, 0);
|
||||
address = virtual_to_physical_address(r4300, address, 0, &(uint8_t){0});
|
||||
if (address == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -425,7 +425,6 @@ EXPORT m64p_error CALL CoreGetRomSettings(m64p_rom_settings *RomSettings, int Ro
|
||||
RomSettings->transferpak = entry->transferpak;
|
||||
RomSettings->mempak = entry->mempak;
|
||||
RomSettings->disableextramem = entry->disableextramem;
|
||||
RomSettings->countperop = entry->countperop;
|
||||
RomSettings->savetype = entry->savetype;
|
||||
RomSettings->sidmaduration = entry->sidmaduration;
|
||||
RomSettings->aidmamodifier = entry->aidmamodifier;
|
||||
|
||||
@@ -280,7 +280,6 @@ typedef struct
|
||||
unsigned char mempak; /* 0 - No, 1 - Yes boolean for memory pak support. */
|
||||
unsigned char biopak; /* 0 - No, 1 - Yes boolean for bio pak support. */
|
||||
unsigned char disableextramem; /* 0 - No, 1 - Yes boolean for disabling 4MB expansion RAM pack */
|
||||
unsigned int countperop; /* Number of CPU cycles per instruction. */
|
||||
unsigned int sidmaduration; /* Default SI DMA duration */
|
||||
unsigned int aidmamodifier; /* Percentage modifier for AI DMA duration */
|
||||
unsigned int rspdelaytime; /* Cycles to delay RSP when needed */
|
||||
|
||||
@@ -113,7 +113,6 @@ DEFINE(cp0, regs);
|
||||
DEFINE(cp0, next_interrupt);
|
||||
#endif
|
||||
DEFINE(cp0, last_addr);
|
||||
DEFINE(cp0, count_per_op);
|
||||
DEFINE(cp0, tlb);
|
||||
|
||||
DEFINE(tlb, entries);
|
||||
|
||||
@@ -188,51 +188,45 @@ void write_cart_dom2(void* opaque, uint32_t address, uint32_t value, uint32_t ma
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int cart_dom2_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void cart_dom2_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
struct cart* cart = (struct cart*)opaque;
|
||||
unsigned int cycles;
|
||||
|
||||
if (cart->use_flashram != 1)
|
||||
{
|
||||
cycles = sram_dma_read(&cart->sram, dram, dram_addr, cart_addr, length);
|
||||
sram_dma_read(&cart->sram, dram, dram_addr, cart_addr, length);
|
||||
cart->use_flashram = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cycles = flashram_dma_read(&cart->flashram, dram, dram_addr, cart_addr, length);
|
||||
flashram_dma_read(&cart->flashram, dram, dram_addr, cart_addr, length);
|
||||
}
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
unsigned int cart_dom2_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void cart_dom2_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
struct cart* cart = (struct cart*)opaque;
|
||||
unsigned int cycles;
|
||||
|
||||
if (cart->use_flashram != 1)
|
||||
{
|
||||
cycles = sram_dma_write(&cart->sram, dram, dram_addr, cart_addr, length);
|
||||
sram_dma_write(&cart->sram, dram, dram_addr, cart_addr, length);
|
||||
cart->use_flashram = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
cycles = flashram_dma_write(&cart->flashram, dram, dram_addr, cart_addr, length);
|
||||
flashram_dma_write(&cart->flashram, dram, dram_addr, cart_addr, length);
|
||||
}
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
unsigned int cart_dom3_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void cart_dom3_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
struct cart* cart = (struct cart*)opaque;
|
||||
return cart_rom_dma_read(&cart->cart_rom, dram, dram_addr, cart_addr, length);
|
||||
cart_rom_dma_read(&cart->cart_rom, dram, dram_addr, cart_addr, length);
|
||||
}
|
||||
|
||||
unsigned int cart_dom3_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void cart_dom3_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
struct cart* cart = (struct cart*)opaque;
|
||||
return cart_rom_dma_write(&cart->cart_rom, dram, dram_addr, cart_addr, length);
|
||||
cart_rom_dma_write(&cart->cart_rom, dram, dram_addr, cart_addr, length);
|
||||
}
|
||||
|
||||
|
||||
@@ -72,10 +72,10 @@ void poweron_cart(struct cart* cart);
|
||||
void read_cart_dom2(void* opaque, uint32_t address, uint32_t* value);
|
||||
void write_cart_dom2(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
|
||||
|
||||
unsigned int cart_dom2_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int cart_dom2_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int cart_dom3_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int cart_dom3_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void cart_dom2_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void cart_dom2_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void cart_dom3_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void cart_dom3_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
|
||||
extern const struct joybus_device_interface
|
||||
g_ijoybus_device_cart;
|
||||
|
||||
@@ -78,20 +78,17 @@ void write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mas
|
||||
|
||||
/* Mark IO as busy */
|
||||
cart_rom->pi->regs[PI_STATUS_REG] |= PI_STATUS_IO_BUSY;
|
||||
cp0_update_count(cart_rom->r4300);
|
||||
add_interrupt_event(&cart_rom->r4300->cp0, PI_INT, 0x1000);
|
||||
}
|
||||
|
||||
unsigned int cart_rom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void cart_rom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
cart_addr &= CART_ROM_ADDR_MASK;
|
||||
|
||||
DebugMessage(M64MSG_WARNING, "DMA Writing to CART_ROM: 0x%" PRIX32 " -> 0x%" PRIX32 " (0x%" PRIX32 ")", dram_addr, cart_addr, length);
|
||||
|
||||
return /* length / 8 */0x1000;
|
||||
}
|
||||
|
||||
unsigned int cart_rom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void cart_rom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
size_t i;
|
||||
struct cart_rom* cart_rom = (struct cart_rom*)opaque;
|
||||
@@ -122,7 +119,5 @@ unsigned int cart_rom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr,
|
||||
/* invalidate cached code */
|
||||
invalidate_r4300_cached_code(cart_rom->r4300, 0x80000000 + dram_addr, length);
|
||||
invalidate_r4300_cached_code(cart_rom->r4300, 0xa0000000 + dram_addr, length);
|
||||
|
||||
return (length / 8) + add_random_interrupt_time(cart_rom->r4300);
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ void poweron_cart_rom(struct cart_rom* cart_rom);
|
||||
void read_cart_rom(void* opaque, uint32_t address, uint32_t* value);
|
||||
void write_cart_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
|
||||
|
||||
unsigned int cart_rom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int cart_rom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void cart_rom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void cart_rom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -181,7 +181,7 @@ void write_flashram(void* opaque, uint32_t address, uint32_t value, uint32_t mas
|
||||
}
|
||||
|
||||
|
||||
unsigned int flashram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void flashram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
size_t i;
|
||||
struct flashram* flashram = (struct flashram*)opaque;
|
||||
@@ -216,11 +216,9 @@ unsigned int flashram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr,
|
||||
DebugMessage(M64MSG_WARNING, "unknown Flashram DMA Write (mode=%x) @%08x <- %08x length=%08x",
|
||||
flashram->mode, dram_addr, cart_addr, length);
|
||||
}
|
||||
|
||||
return /* length / 8 */0x1000;
|
||||
}
|
||||
|
||||
unsigned int flashram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void flashram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
struct flashram* flashram = (struct flashram*)opaque;
|
||||
unsigned int i;
|
||||
@@ -236,7 +234,5 @@ unsigned int flashram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_
|
||||
DebugMessage(M64MSG_WARNING, "unknown Flashram DMA Read (mode=%x) @%08x <- %08x length=%08x",
|
||||
flashram->mode, cart_addr, dram_addr, length);
|
||||
}
|
||||
|
||||
return /* length / 8 */0x1000;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ void format_flashram(uint8_t* flash);
|
||||
void read_flashram(void* opaque, uint32_t address, uint32_t* value);
|
||||
void write_flashram(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
|
||||
|
||||
unsigned int flashram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int flashram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void flashram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void flashram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,7 @@ void init_sram(struct sram* sram,
|
||||
sram->istorage = istorage;
|
||||
}
|
||||
|
||||
unsigned int sram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void sram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
size_t i;
|
||||
struct sram* sram = (struct sram*)opaque;
|
||||
@@ -55,11 +55,9 @@ unsigned int sram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr
|
||||
}
|
||||
|
||||
sram->istorage->save(sram->storage, cart_addr, length);
|
||||
|
||||
return /* length / 8 */0x1000;
|
||||
}
|
||||
|
||||
unsigned int sram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void sram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
size_t i;
|
||||
struct sram* sram = (struct sram*)opaque;
|
||||
@@ -70,8 +68,6 @@ unsigned int sram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uin
|
||||
for (i = 0; i < length; ++i) {
|
||||
dram[(dram_addr+i)^S8] = mem[(cart_addr+i)^S8];
|
||||
}
|
||||
|
||||
return /* length / 8 */0x1000;
|
||||
}
|
||||
|
||||
void read_sram(void* opaque, uint32_t address, uint32_t* value)
|
||||
|
||||
@@ -39,8 +39,8 @@ void format_sram(uint8_t* sram);
|
||||
void init_sram(struct sram* sram,
|
||||
void* storage, const struct storage_backend_interface* istorage);
|
||||
|
||||
unsigned int sram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int sram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void sram_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void sram_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void read_sram(void* opaque, uint32_t address, uint32_t* value);
|
||||
void write_sram(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
|
||||
|
||||
|
||||
@@ -547,7 +547,7 @@ void write_dd_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask)
|
||||
DebugMessage(M64MSG_VERBOSE, "DD ROM: %08X <- %08x & %08x", address, value, mask);
|
||||
}
|
||||
|
||||
unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
struct dd_controller* dd = (struct dd_controller*)opaque;
|
||||
uint8_t* mem;
|
||||
@@ -562,29 +562,22 @@ unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_ad
|
||||
}
|
||||
else if (cart_addr == MM_DD_MS_RAM) {
|
||||
/* MS is not emulated, we silence warnings for now */
|
||||
/* Recommended Count Per Op = 1, this seems to break very easily */
|
||||
return (length * 63) / 25;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
DebugMessage(M64MSG_ERROR, "Unknown DD dma read dram=%08x cart=%08x length=%08x",
|
||||
dram_addr, cart_addr, length);
|
||||
|
||||
/* Recommended Count Per Op = 1, this seems to break very easily */
|
||||
return (length * 63) / 25;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
mem[(cart_addr + i) ^ S8] = dram[(dram_addr + i) ^ S8];
|
||||
}
|
||||
|
||||
/* Recommended Count Per Op = 1, this seems to break very easily */
|
||||
return (length * 63) / 25;
|
||||
}
|
||||
|
||||
unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
void dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length)
|
||||
{
|
||||
struct dd_controller* dd = (struct dd_controller*)opaque;
|
||||
unsigned int cycles;
|
||||
const uint8_t* mem;
|
||||
size_t i;
|
||||
|
||||
@@ -606,20 +599,13 @@ unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, u
|
||||
DebugMessage(M64MSG_ERROR, "Unknown DD dma write dram=%08x cart=%08x length=%08x",
|
||||
dram_addr, cart_addr, length);
|
||||
|
||||
/* Recommended Count Per Op = 1, this seems to break very easily */
|
||||
return (length * 63) / 25;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Recommended Count Per Op = 1, this seems to break very easily */
|
||||
cycles = (length * 63) / 25;
|
||||
}
|
||||
else {
|
||||
/* DD ROM */
|
||||
cart_addr = (cart_addr - MM_DD_ROM);
|
||||
mem = (const uint8_t*)dd->rom;
|
||||
|
||||
/* Recommended Count Per Op = 1, this seems to break very easily */
|
||||
cycles = (length * 63) / 25;
|
||||
}
|
||||
|
||||
for (i = 0; i < length; ++i) {
|
||||
@@ -628,8 +614,6 @@ unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, u
|
||||
|
||||
invalidate_r4300_cached_code(dd->r4300, R4300_KSEG0 + dram_addr, length);
|
||||
invalidate_r4300_cached_code(dd->r4300, R4300_KSEG1 + dram_addr, length);
|
||||
|
||||
return cycles;
|
||||
}
|
||||
|
||||
void dd_on_pi_cart_addr_write(struct dd_controller* dd, uint32_t address)
|
||||
|
||||
@@ -117,8 +117,8 @@ void write_dd_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask
|
||||
void read_dd_rom(void* opaque, uint32_t address, uint32_t* value);
|
||||
void write_dd_rom(void* opaque, uint32_t address, uint32_t value, uint32_t mask);
|
||||
|
||||
unsigned int dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void dd_dom_dma_read(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void dd_dom_dma_write(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
|
||||
void dd_on_pi_cart_addr_write(struct dd_controller* dd, uint32_t address);
|
||||
void dd_update_bm(void* opaque);
|
||||
|
||||
@@ -82,8 +82,6 @@ void init_device(struct device* dev,
|
||||
void* base,
|
||||
/* r4300 */
|
||||
unsigned int emumode,
|
||||
unsigned int count_per_op,
|
||||
unsigned int count_per_op_denom_pot,
|
||||
int no_compiled_jump,
|
||||
int randomize_interrupt,
|
||||
uint32_t start_address,
|
||||
@@ -182,7 +180,7 @@ void init_device(struct device* dev,
|
||||
init_rdram(&dev->rdram, mem_base_u32(base, MM_RDRAM_DRAM), dram_size, &dev->r4300);
|
||||
|
||||
init_r4300(&dev->r4300, &dev->mem, &dev->mi, &dev->rdram, interrupt_handlers,
|
||||
emumode, count_per_op, count_per_op_denom_pot, no_compiled_jump, randomize_interrupt, start_address);
|
||||
emumode, no_compiled_jump, randomize_interrupt, start_address);
|
||||
init_rdp(&dev->dp, &dev->sp, &dev->mi, &dev->mem, &dev->rdram, &dev->r4300);
|
||||
init_rsp(&dev->sp, mem_base_u32(base, MM_RSP_MEM), &dev->mi, &dev->dp, &dev->ri, rsp_delay_time);
|
||||
init_ai(&dev->ai, &dev->mi, &dev->ri, &dev->vi, aout, iaout, dma_modifier);
|
||||
|
||||
@@ -120,8 +120,6 @@ void init_device(struct device* dev,
|
||||
void* base,
|
||||
/* r4300 */
|
||||
unsigned int emumode,
|
||||
unsigned int count_per_op,
|
||||
unsigned int count_per_op_denom_pot,
|
||||
int no_compiled_jump,
|
||||
int randomize_interrupt,
|
||||
uint32_t start_address,
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - dcache.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2022 loganmc10 *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "device/r4300/r4300_core.h"
|
||||
#include "device/memory/memory.h"
|
||||
|
||||
void init_dcache(struct datacache *lines)
|
||||
{
|
||||
memset(lines, 0, 512 * sizeof(lines[0]));
|
||||
for (uint32_t i = 0; i < 512; ++i)
|
||||
lines[i].index = i << 4 & UINT32_C(0xFF0);
|
||||
}
|
||||
|
||||
void dcache_writeback(struct r4300_core* r4300, struct datacache *line)
|
||||
{
|
||||
cp0_add_count(r4300, 22, 0);
|
||||
line->dirty = 0;
|
||||
uint32_t cache_address = line->tag | line->index;
|
||||
invalidate_r4300_cached_code(r4300, cache_address, 16);
|
||||
invalidate_r4300_cached_code(r4300, cache_address ^ UINT32_C(0x20000000), 16);
|
||||
cache_address &= UINT32_C(0x1ffffffc);
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, cache_address);
|
||||
mem_write32(handler, cache_address | UINT32_C(0x0), line->words[0], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x4), line->words[1], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x8), line->words[2], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0xC), line->words[3], ~UINT32_C(0));
|
||||
}
|
||||
|
||||
uint32_t dcache_hit(struct datacache *line, uint32_t address)
|
||||
{
|
||||
return line->valid && line->tag == (address & ~UINT32_C(0xFFF));
|
||||
}
|
||||
|
||||
static void dcache_fill(struct datacache *line, struct r4300_core* r4300, uint32_t address)
|
||||
{
|
||||
cp0_add_count(r4300, 22, 0);
|
||||
line->valid = 1;
|
||||
line->dirty = 0;
|
||||
line->tag = address & ~UINT32_C(0xFFF);
|
||||
uint32_t cache_address = line->tag | line->index;
|
||||
cache_address &= UINT32_C(0x1ffffffc);
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, cache_address);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x0), &line->words[0]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x4), &line->words[1]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x8), &line->words[2]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0xC), &line->words[3]);
|
||||
}
|
||||
|
||||
void dcache_read32(struct r4300_core* r4300, uint32_t address, uint32_t *value)
|
||||
{
|
||||
struct datacache *line = &r4300->mem->dcache[(address >> 4) & UINT32_C(0x1FF)];
|
||||
if(!dcache_hit(line, address))
|
||||
{
|
||||
if(line->valid && line->dirty)
|
||||
dcache_writeback(r4300, line);
|
||||
dcache_fill(line, r4300, address);
|
||||
}
|
||||
else
|
||||
cp0_add_count(r4300, 0, 1);
|
||||
*value = line->words[(address >> 2) & UINT32_C(3)];
|
||||
}
|
||||
|
||||
void dcache_write32(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t mask)
|
||||
{
|
||||
struct datacache *line = &r4300->mem->dcache[(address >> 4) & UINT32_C(0x1FF)];
|
||||
if(!dcache_hit(line, address))
|
||||
{
|
||||
if(line->valid && line->dirty)
|
||||
dcache_writeback(r4300, line);
|
||||
dcache_fill(line, r4300, address);
|
||||
}
|
||||
else
|
||||
cp0_add_count(r4300, 0, 1);
|
||||
masked_write(&line->words[(address >> 2) & UINT32_C(3)], value, mask);
|
||||
line->dirty = 1;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - dcache.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2022 loganmc10 *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef M64P_DEVICE_MEMORY_DCACHE_H
|
||||
#define M64P_DEVICE_MEMORY_DCACHE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct r4300_core;
|
||||
|
||||
struct datacache
|
||||
{
|
||||
uint8_t valid;
|
||||
uint8_t dirty;
|
||||
uint32_t tag;
|
||||
uint16_t index;
|
||||
uint32_t words[4];
|
||||
};
|
||||
|
||||
void init_dcache(struct datacache *lines);
|
||||
void dcache_writeback(struct r4300_core* r4300, struct datacache *line);
|
||||
uint32_t dcache_hit(struct datacache *line, uint32_t address);
|
||||
void dcache_read32(struct r4300_core* r4300, uint32_t address, uint32_t *value);
|
||||
void dcache_write32(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t mask);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,100 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - icache.c *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2022 loganmc10 *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "device/r4300/r4300_core.h"
|
||||
#include "device/memory/memory.h"
|
||||
|
||||
void init_icache(struct instcache *lines)
|
||||
{
|
||||
memset(lines, 0, 512 * sizeof(lines[0]));
|
||||
for (uint32_t i = 0; i < 512; ++i)
|
||||
lines[i].index = i << 5 & UINT32_C(0xFE0);
|
||||
}
|
||||
|
||||
void icache_writeback(struct r4300_core* r4300, struct instcache *line)
|
||||
{
|
||||
cp0_add_count(r4300, 24, 0);
|
||||
uint32_t cache_address = line->tag | line->index;
|
||||
invalidate_r4300_cached_code(r4300, cache_address, 32);
|
||||
invalidate_r4300_cached_code(r4300, cache_address ^ UINT32_C(0x20000000), 32);
|
||||
cache_address &= UINT32_C(0x1ffffffc);
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, cache_address);
|
||||
mem_write32(handler, cache_address | UINT32_C(0x0), line->words[0], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x4), line->words[1], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x8), line->words[2], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0xC), line->words[3], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x10), line->words[4], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x14), line->words[5], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x18), line->words[6], ~UINT32_C(0));
|
||||
mem_write32(handler, cache_address | UINT32_C(0x1C), line->words[7], ~UINT32_C(0));
|
||||
}
|
||||
|
||||
uint32_t icache_hit(struct instcache *line, uint32_t address)
|
||||
{
|
||||
return line->valid && line->tag == (address & ~UINT32_C(0xFFF));
|
||||
}
|
||||
|
||||
void icache_fill(struct instcache *line, struct r4300_core* r4300, uint32_t address)
|
||||
{
|
||||
cp0_add_count(r4300, 24, 0);
|
||||
line->valid = 1;
|
||||
line->tag = address & ~UINT32_C(0xFFF);
|
||||
uint32_t cache_address = line->tag | line->index;
|
||||
cache_address &= UINT32_C(0x1ffffffc);
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, cache_address);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x0), &line->words[0]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x4), &line->words[1]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x8), &line->words[2]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0xC), &line->words[3]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x10), &line->words[4]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x14), &line->words[5]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x18), &line->words[6]);
|
||||
mem_read32(handler, cache_address | UINT32_C(0x1C), &line->words[7]);
|
||||
}
|
||||
|
||||
uint32_t* icache_fetch(struct r4300_core* r4300, uint32_t address)
|
||||
{
|
||||
struct instcache *line = &r4300->mem->icache[(address >> 5) & UINT32_C(0x1FF)];
|
||||
if(!icache_hit(line, address))
|
||||
icache_fill(line, r4300, address);
|
||||
else
|
||||
cp0_add_count(r4300, 1, 0);
|
||||
|
||||
return &line->words[address >> 2 & 7];
|
||||
}
|
||||
|
||||
void icache_step(struct r4300_core* r4300, uint32_t address)
|
||||
{
|
||||
struct instcache *line = &r4300->mem->icache[(address >> 5) & UINT32_C(0x1FF)];
|
||||
uint8_t cached = 0;
|
||||
r4300_translate_address(r4300, &address, &cached, 2, 0);
|
||||
if (cached)
|
||||
{
|
||||
if(!icache_hit(line, address))
|
||||
icache_fill(line, r4300, address);
|
||||
else
|
||||
cp0_add_count(r4300, 1, 0);
|
||||
}
|
||||
else
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
* Mupen64plus - icache.h *
|
||||
* Mupen64Plus homepage: https://mupen64plus.org/ *
|
||||
* Copyright (C) 2022 loganmc10 *
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program; if not, write to the *
|
||||
* Free Software Foundation, Inc., *
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef M64P_DEVICE_MEMORY_ICACHE_H
|
||||
#define M64P_DEVICE_MEMORY_ICACHE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct r4300_core;
|
||||
|
||||
struct instcache
|
||||
{
|
||||
uint8_t valid;
|
||||
uint32_t tag;
|
||||
uint16_t index;
|
||||
uint32_t words[8];
|
||||
};
|
||||
|
||||
void init_icache(struct instcache *lines);
|
||||
void icache_writeback(struct r4300_core* r4300, struct instcache *line);
|
||||
uint32_t icache_hit(struct instcache *line, uint32_t address);
|
||||
void icache_fill(struct instcache *line, struct r4300_core* r4300, uint32_t address);
|
||||
uint32_t* icache_fetch(struct r4300_core* r4300, uint32_t address);
|
||||
void icache_step(struct r4300_core* r4300, uint32_t address);
|
||||
|
||||
#endif
|
||||
@@ -180,6 +180,9 @@ void init_memory(struct memory* mem,
|
||||
for(m = 0; m < mappings_count; ++m) {
|
||||
apply_mem_mapping(mem, &mappings[m]);
|
||||
}
|
||||
|
||||
init_dcache(&mem->dcache[0]);
|
||||
init_icache(&mem->icache[0]);
|
||||
}
|
||||
|
||||
static void map_region(struct memory* mem,
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dcache.h"
|
||||
#include "icache.h"
|
||||
#include "osal/preproc.h"
|
||||
|
||||
enum { RDRAM_MAX_SIZE = 0x800000 };
|
||||
@@ -53,6 +55,8 @@ struct memory
|
||||
{
|
||||
struct mem_handler handlers[0x10000];
|
||||
void* base;
|
||||
struct datacache dcache[512];
|
||||
struct instcache icache[512];
|
||||
|
||||
#ifdef DBG
|
||||
int memtype[0x10000];
|
||||
|
||||
@@ -279,7 +279,6 @@ static void process_cic_challenge(struct pif* pif)
|
||||
void poweron_pif(struct pif* pif)
|
||||
{
|
||||
memset(pif->ram, 0, PIF_RAM_SIZE);
|
||||
pif->update_counter = 0;
|
||||
|
||||
reset_pif(pif, 0); /* cold reset */
|
||||
}
|
||||
@@ -309,7 +308,6 @@ void write_pif_mem(void* opaque, uint32_t address, uint32_t value, uint32_t mask
|
||||
|
||||
pif->si->dma_dir = SI_DMA_WRITE;
|
||||
|
||||
cp0_update_count(pif->r4300);
|
||||
pif->si->regs[SI_STATUS_REG] |= (SI_STATUS_DMA_BUSY | SI_STATUS_IO_BUSY);
|
||||
add_interrupt_event(&pif->r4300->cp0, SI_INT, pif->si->dma_duration);
|
||||
}
|
||||
@@ -368,13 +366,6 @@ void process_pif_ram(struct pif* pif)
|
||||
pif->ram[0x3f] &= ~clrmask;
|
||||
}
|
||||
|
||||
static void update_pif_counter(struct pif* pif)
|
||||
{
|
||||
/* check if controller 0 was polled for input */
|
||||
if (pif->channels[0].tx && (pif->channels[0].tx_buf[0] == JCMD_CONTROLLER_READ))
|
||||
++pif->update_counter;
|
||||
}
|
||||
|
||||
void update_pif_ram(struct pif* pif)
|
||||
{
|
||||
size_t k;
|
||||
@@ -388,7 +379,6 @@ void update_pif_ram(struct pif* pif)
|
||||
if (input.readController) {
|
||||
input.readController(-1, NULL);
|
||||
}
|
||||
update_pif_counter(pif);
|
||||
|
||||
netplay_update_input(pif);
|
||||
|
||||
|
||||
@@ -59,8 +59,6 @@ struct pif
|
||||
|
||||
struct cic cic;
|
||||
|
||||
uint32_t update_counter;
|
||||
|
||||
struct r4300_core* r4300;
|
||||
struct si_controller* si;
|
||||
};
|
||||
|
||||
@@ -83,8 +83,8 @@ void cached_interp_##name(void) \
|
||||
(*r4300_pc_struct(r4300))++; \
|
||||
r4300->delay_slot=1; \
|
||||
UPDATE_DEBUGGER(); \
|
||||
icache_step(r4300, (*r4300_pc_struct(r4300))->addr); \
|
||||
(*r4300_pc_struct(r4300))->ops(); \
|
||||
cp0_update_count(r4300); \
|
||||
r4300->delay_slot=0; \
|
||||
if (take_jump && !r4300->skip_jump) \
|
||||
{ \
|
||||
@@ -94,7 +94,6 @@ void cached_interp_##name(void) \
|
||||
else \
|
||||
{ \
|
||||
(*r4300_pc_struct(r4300)) += 2; \
|
||||
cp0_update_count(r4300); \
|
||||
} \
|
||||
r4300->cp0.last_addr = *r4300_pc(r4300); \
|
||||
if (*r4300_cp0_cycle_count(&r4300->cp0) >= 0) gen_interrupt(r4300); \
|
||||
@@ -116,8 +115,8 @@ void cached_interp_##name##_OUT(void) \
|
||||
(*r4300_pc_struct(r4300))++; \
|
||||
r4300->delay_slot=1; \
|
||||
UPDATE_DEBUGGER(); \
|
||||
icache_step(r4300, (*r4300_pc_struct(r4300))->addr); \
|
||||
(*r4300_pc_struct(r4300))->ops(); \
|
||||
cp0_update_count(r4300); \
|
||||
r4300->delay_slot=0; \
|
||||
if (take_jump && !r4300->skip_jump) \
|
||||
{ \
|
||||
@@ -127,7 +126,6 @@ void cached_interp_##name##_OUT(void) \
|
||||
else \
|
||||
{ \
|
||||
(*r4300_pc_struct(r4300)) += 2; \
|
||||
cp0_update_count(r4300); \
|
||||
} \
|
||||
r4300->cp0.last_addr = *r4300_pc(r4300); \
|
||||
if (*r4300_cp0_cycle_count(&r4300->cp0) >= 0) gen_interrupt(r4300); \
|
||||
@@ -142,7 +140,6 @@ void cached_interp_##name##_IDLE(void) \
|
||||
if (cop1 && check_cop1_unusable(r4300)) return; \
|
||||
if (take_jump) \
|
||||
{ \
|
||||
cp0_update_count(r4300); \
|
||||
if(*cp0_cycle_count < 0) \
|
||||
{ \
|
||||
cp0_regs[CP0_COUNT_REG] -= *cp0_cycle_count; \
|
||||
@@ -203,6 +200,7 @@ void cached_interp_FIN_BLOCK(void)
|
||||
#endif
|
||||
Used by dynarec only, check should be unnecessary
|
||||
*/
|
||||
icache_step(r4300, (*r4300_pc_struct(r4300))->addr);
|
||||
(*r4300_pc_struct(r4300))->ops();
|
||||
}
|
||||
else
|
||||
@@ -219,6 +217,7 @@ Used by dynarec only, check should be unnecessary
|
||||
*/
|
||||
if (!r4300->skip_jump)
|
||||
{
|
||||
icache_step(r4300, (*r4300_pc_struct(r4300))->addr);
|
||||
(*r4300_pc_struct(r4300))->ops();
|
||||
r4300->cached_interp.actual = blk;
|
||||
(*r4300_pc_struct(r4300)) = inst+1;
|
||||
@@ -231,7 +230,7 @@ Used by dynarec only, check should be unnecessary
|
||||
void cached_interp_NOTCOMPILED(void)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t *mem = fast_mem_access(r4300, r4300->cached_interp.blocks[*r4300_pc(r4300)>>12]->start);
|
||||
uint32_t *mem = fast_mem_access(r4300, r4300->cached_interp.blocks[*r4300_pc(r4300)>>12]->start, 0);
|
||||
#ifdef DBG
|
||||
DebugMessage(M64MSG_INFO, "NOTCOMPILED: addr = %x ops = %lx", *r4300_pc(r4300), (long) (*r4300_pc_struct(r4300))->ops);
|
||||
#endif
|
||||
@@ -250,6 +249,7 @@ void cached_interp_NOTCOMPILED(void)
|
||||
The preceeding update_debugger SHOULD be unnecessary since it should have been
|
||||
called before NOTCOMPILED would have been executed
|
||||
*/
|
||||
icache_step(r4300, (*r4300_pc_struct(r4300))->addr);
|
||||
(*r4300_pc_struct(r4300))->ops();
|
||||
}
|
||||
|
||||
@@ -514,6 +514,7 @@ enum r4300_opcode r4300_decode(struct precomp_instr* inst, struct r4300_core* r4
|
||||
case R4300_OP_LWC1:
|
||||
case R4300_OP_SDC1:
|
||||
case R4300_OP_SWC1:
|
||||
case R4300_OP_CACHE:
|
||||
idec_u53(iw, idec->u53[2], &inst->f.lf.base);
|
||||
idec_u53(iw, idec->u53[1], &inst->f.lf.ft);
|
||||
inst->f.lf.offset = (uint16_t)iw;
|
||||
@@ -672,7 +673,6 @@ enum r4300_opcode r4300_decode(struct precomp_instr* inst, struct r4300_core* r4
|
||||
break;
|
||||
|
||||
case R4300_OP_BREAK:
|
||||
case R4300_OP_CACHE:
|
||||
case R4300_OP_ERET:
|
||||
case R4300_OP_SYNC:
|
||||
case R4300_OP_SYSCALL:
|
||||
@@ -714,7 +714,7 @@ static uint32_t update_invalid_addr(struct r4300_core* r4300, uint32_t addr)
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t paddr = virtual_to_physical_address(r4300, addr, 2);
|
||||
uint32_t paddr = virtual_to_physical_address(r4300, addr, 2, &(uint8_t){0});
|
||||
if (paddr)
|
||||
{
|
||||
uint32_t beg_paddr = paddr - (addr - (addr & ~0xfff));
|
||||
@@ -799,7 +799,7 @@ void cached_interp_init_block(struct r4300_core* r4300, uint32_t address)
|
||||
|
||||
if (b->end < UINT32_C(0x80000000) || b->start >= UINT32_C(0xc0000000))
|
||||
{
|
||||
uint32_t paddr = virtual_to_physical_address(r4300, b->start, 2);
|
||||
uint32_t paddr = virtual_to_physical_address(r4300, b->start, 2, &(uint8_t){0});
|
||||
|
||||
r4300->cached_interp.invalid_code[paddr>>12] = 0;
|
||||
cached_interp_init_block(r4300, paddr);
|
||||
@@ -854,7 +854,7 @@ void cached_interp_recompile_block(struct r4300_core* r4300, const uint32_t* iw,
|
||||
|
||||
if (block_start_in_tlb)
|
||||
{
|
||||
uint32_t address2 = virtual_to_physical_address(r4300, inst->addr, 0);
|
||||
uint32_t address2 = virtual_to_physical_address(r4300, inst->addr, 0, &(uint8_t){0});
|
||||
if (r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops == cached_interp_NOTCOMPILED) {
|
||||
r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops = cached_interp_NOTCOMPILED2;
|
||||
}
|
||||
@@ -992,12 +992,13 @@ void run_cached_interpreter(struct r4300_core* r4300)
|
||||
{
|
||||
#ifdef COMPARE_CORE
|
||||
if ((*r4300_pc_struct(r4300))->ops == cached_interp_FIN_BLOCK && ((*r4300_pc_struct(r4300))->addr < 0x80000000 || (*r4300_pc_struct(r4300))->addr >= 0xc0000000))
|
||||
virtual_to_physical_address(r4300, (*r4300_pc_struct(r4300))->addr, 2);
|
||||
virtual_to_physical_address(r4300, (*r4300_pc_struct(r4300))->addr, 2, &(uint8_t){0});
|
||||
CoreCompareCallback();
|
||||
#endif
|
||||
#ifdef DBG
|
||||
if (g_DebuggerActive) update_debugger((*r4300_pc_struct(r4300))->addr);
|
||||
#endif
|
||||
icache_step(r4300, (*r4300_pc_struct(r4300))->addr);
|
||||
(*r4300_pc_struct(r4300))->ops();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,10 +36,8 @@
|
||||
#endif
|
||||
|
||||
/* global functions */
|
||||
void init_cp0(struct cp0* cp0, unsigned int count_per_op, unsigned int count_per_op_denom_pot, struct new_dynarec_hot_state* new_dynarec_hot_state, const struct interrupt_handler* interrupt_handlers)
|
||||
void init_cp0(struct cp0* cp0, struct new_dynarec_hot_state* new_dynarec_hot_state, const struct interrupt_handler* interrupt_handlers)
|
||||
{
|
||||
cp0->count_per_op = count_per_op;
|
||||
cp0->count_per_op_denom_pot = count_per_op_denom_pot;
|
||||
#ifdef NEW_DYNAREC
|
||||
cp0->new_dynarec_hot_state = new_dynarec_hot_state;
|
||||
#endif
|
||||
@@ -73,6 +71,7 @@ void poweron_cp0(struct cp0* cp0)
|
||||
cp0->interrupt_unsafe_state = 0;
|
||||
*cp0_next_interrupt = 0;
|
||||
*cp0_cycle_count = 0;
|
||||
cp0->half_count = 0;
|
||||
cp0->last_addr = UINT32_C(0xbfc00000);
|
||||
|
||||
init_interrupt(cp0);
|
||||
@@ -125,41 +124,22 @@ int check_cop1_unusable(struct r4300_core* r4300)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cp0_update_count(struct r4300_core* r4300)
|
||||
void cp0_add_count(struct r4300_core* r4300, uint32_t count, uint8_t half)
|
||||
{
|
||||
struct cp0* cp0 = &r4300->cp0;
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(cp0);
|
||||
|
||||
#ifdef NEW_DYNAREC
|
||||
if (r4300->emumode != EMUMODE_DYNAREC)
|
||||
if (half)
|
||||
{
|
||||
#endif
|
||||
uint32_t count = ((*r4300_pc(r4300) - cp0->last_addr) >> 2) * cp0->count_per_op;
|
||||
if (r4300->cp0.count_per_op_denom_pot) {
|
||||
count += (1 << r4300->cp0.count_per_op_denom_pot) - 1;
|
||||
count >>= r4300->cp0.count_per_op_denom_pot;
|
||||
}
|
||||
cp0_regs[CP0_COUNT_REG] += count;
|
||||
*r4300_cp0_cycle_count(cp0) += count;
|
||||
cp0->last_addr = *r4300_pc(r4300);
|
||||
#ifdef NEW_DYNAREC
|
||||
cp0->half_count ^= 1;
|
||||
half = cp0->half_count;
|
||||
}
|
||||
else
|
||||
cp0_regs[CP0_COUNT_REG] = *r4300_cp0_next_interrupt(cp0) + *r4300_cp0_cycle_count(cp0);
|
||||
#endif
|
||||
|
||||
#ifdef COMPARE_CORE
|
||||
if (r4300->delay_slot)
|
||||
CoreCompareCallback();
|
||||
#endif
|
||||
/*#ifdef DBG
|
||||
if (g_DebuggerActive && !r4300->delay_slot) update_debugger(*r4300_pc(r4300));
|
||||
#endif
|
||||
*/
|
||||
cp0_regs[CP0_COUNT_REG] += count + half;
|
||||
*r4300_cp0_cycle_count(cp0) += count + half;
|
||||
}
|
||||
|
||||
static void exception_epilog(struct r4300_core* r4300)
|
||||
{
|
||||
cp0_add_count(r4300, 1, 0);
|
||||
#ifndef NO_ASM
|
||||
#ifndef NEW_DYNAREC
|
||||
if (r4300->emumode == EMUMODE_DYNAREC)
|
||||
@@ -193,10 +173,6 @@ void TLB_refill_exception(struct r4300_core* r4300, uint32_t address, int w)
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
int usual_handler = 0, i;
|
||||
|
||||
if (r4300->emumode != EMUMODE_DYNAREC && w != 2) {
|
||||
cp0_update_count(r4300);
|
||||
}
|
||||
|
||||
cp0_regs[CP0_CAUSE_REG] = (w == 1)
|
||||
? CP0_CAUSE_EXCCODE_TLBS
|
||||
: CP0_CAUSE_EXCCODE_TLBL;
|
||||
@@ -276,7 +252,6 @@ void exception_general(struct r4300_core* r4300)
|
||||
{
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_STATUS_REG] |= CP0_STATUS_EXL;
|
||||
|
||||
cp0_regs[CP0_EPC_REG] = *r4300_pc(r4300);
|
||||
|
||||
@@ -201,10 +201,9 @@ struct cp0
|
||||
#endif
|
||||
|
||||
uint32_t last_addr;
|
||||
unsigned int count_per_op;
|
||||
unsigned int count_per_op_denom_pot;
|
||||
|
||||
struct tlb tlb;
|
||||
uint8_t half_count;
|
||||
};
|
||||
|
||||
#ifndef NEW_DYNAREC
|
||||
@@ -217,7 +216,7 @@ struct cp0
|
||||
offsetof(struct new_dynarec_hot_state, cp0_regs))
|
||||
#endif
|
||||
|
||||
void init_cp0(struct cp0* cp0, unsigned int count_per_op, unsigned int count_per_op_denom_pot, struct new_dynarec_hot_state* new_dynarec_hot_state, const struct interrupt_handler* interrupt_handlers);
|
||||
void init_cp0(struct cp0* cp0, struct new_dynarec_hot_state* new_dynarec_hot_state, const struct interrupt_handler* interrupt_handlers);
|
||||
void poweron_cp0(struct cp0* cp0);
|
||||
|
||||
uint32_t* r4300_cp0_regs(struct cp0* cp0);
|
||||
@@ -231,7 +230,7 @@ int* r4300_cp0_cycle_count(struct cp0* cp0);
|
||||
|
||||
int check_cop1_unusable(struct r4300_core* r4300);
|
||||
|
||||
void cp0_update_count(struct r4300_core* r4300);
|
||||
void cp0_add_count(struct r4300_core* r4300, uint32_t count, uint8_t half);
|
||||
|
||||
void TLB_refill_exception(struct r4300_core* r4300, uint32_t address, int w);
|
||||
void exception_general(struct r4300_core* r4300);
|
||||
|
||||
@@ -278,11 +278,11 @@ void translate_event_queue(struct cp0* cp0, unsigned int base)
|
||||
cp0_regs[CP0_COUNT_REG] = base;
|
||||
add_interrupt_event_count(cp0, SPECIAL_INT, ((cp0_regs[CP0_COUNT_REG] & UINT32_C(0x80000000)) ^ UINT32_C(0x80000000)));
|
||||
|
||||
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
cp0_regs[CP0_COUNT_REG] += cp0->count_per_op;
|
||||
*cp0_cycle_count += cp0->count_per_op;
|
||||
/* Add 2 to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
cp0_regs[CP0_COUNT_REG] += 2;
|
||||
*cp0_cycle_count += 2;
|
||||
add_interrupt_event_count(cp0, COMPARE_INT, cp0_regs[CP0_COMPARE_REG]);
|
||||
cp0_regs[CP0_COUNT_REG] -= cp0->count_per_op;
|
||||
cp0_regs[CP0_COUNT_REG] -= 2;
|
||||
|
||||
/* Update next interrupt in case first event is COMPARE_INT */
|
||||
*cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - cp0->q.first->data.count;
|
||||
@@ -399,11 +399,11 @@ void compare_int_handler(void* opaque)
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0);
|
||||
|
||||
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
cp0_regs[CP0_COUNT_REG] += r4300->cp0.count_per_op;
|
||||
*cp0_cycle_count += r4300->cp0.count_per_op;
|
||||
/* Add 2 to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
cp0_regs[CP0_COUNT_REG] += 2;
|
||||
*cp0_cycle_count += 2;
|
||||
add_interrupt_event_count(&r4300->cp0, COMPARE_INT, cp0_regs[CP0_COMPARE_REG]);
|
||||
cp0_regs[CP0_COUNT_REG] -= r4300->cp0.count_per_op;
|
||||
cp0_regs[CP0_COUNT_REG] -= 2;
|
||||
|
||||
/* Update next interrupt in case first event is COMPARE_INT */
|
||||
*cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - r4300->cp0.q.first->data.count;
|
||||
|
||||
@@ -105,7 +105,7 @@ DECLARE_INSTRUCTION(NI)
|
||||
{
|
||||
DECLARE_R4300
|
||||
DebugMessage(M64MSG_ERROR, "NI() @ 0x%" PRIX32, PCADDR);
|
||||
DebugMessage(M64MSG_ERROR, "opcode not implemented: %" PRIX32 ":%" PRIX32, PCADDR, *fast_mem_access(r4300, PCADDR));
|
||||
DebugMessage(M64MSG_ERROR, "opcode not implemented: %" PRIX32 ":%" PRIX32, PCADDR, *fast_mem_access(r4300, PCADDR, 0));
|
||||
*r4300_stop(r4300) = 1;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ DECLARE_INSTRUCTION(NI)
|
||||
DECLARE_INSTRUCTION(RESERVED)
|
||||
{
|
||||
DECLARE_R4300
|
||||
DebugMessage(M64MSG_ERROR, "reserved opcode: %" PRIX32 ":%" PRIX32, PCADDR, *fast_mem_access(r4300, PCADDR));
|
||||
DebugMessage(M64MSG_ERROR, "reserved opcode: %" PRIX32 ":%" PRIX32, PCADDR, *fast_mem_access(r4300, PCADDR, 0));
|
||||
*r4300_stop(r4300) = 1;
|
||||
}
|
||||
|
||||
@@ -591,6 +591,7 @@ DECLARE_INSTRUCTION(NOR)
|
||||
{
|
||||
DECLARE_R4300
|
||||
rrd = ~(rrs | rrt);
|
||||
cp0_add_count(r4300, 28, 1);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -723,6 +724,7 @@ DECLARE_INSTRUCTION(MULT)
|
||||
temp = rrs32 * (int64_t)rrt32;
|
||||
*r4300_mult_hi(r4300) = temp >> 32;
|
||||
*r4300_mult_lo(r4300) = SE32(temp);
|
||||
cp0_add_count(r4300, 2, 1);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -733,6 +735,7 @@ DECLARE_INSTRUCTION(MULTU)
|
||||
temp = (uint32_t) rrs * (uint64_t) ((uint32_t) rrt);
|
||||
*r4300_mult_hi(r4300) = (int64_t) temp >> 32;
|
||||
*r4300_mult_lo(r4300) = SE32(temp);
|
||||
cp0_add_count(r4300, 2, 1);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -780,6 +783,7 @@ DECLARE_INSTRUCTION(DMULT)
|
||||
if (!*r4300_mult_lo(r4300)) { (*r4300_mult_hi(r4300))++; }
|
||||
else { *r4300_mult_lo(r4300) = ~*r4300_mult_lo(r4300) + 1; }
|
||||
}
|
||||
cp0_add_count(r4300, 4, 0);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -808,6 +812,7 @@ DECLARE_INSTRUCTION(DMULTU)
|
||||
*r4300_mult_lo(r4300) = result1 | (result2 << 32);
|
||||
*r4300_mult_hi(r4300) = (result3 & UINT64_C(0xFFFFFFFF)) | (result4 << 32);
|
||||
|
||||
cp0_add_count(r4300, 4, 0);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -832,6 +837,7 @@ DECLARE_INSTRUCTION(DIV)
|
||||
*r4300_mult_lo(r4300) = rrs32 < 0 ? 1 : -1;
|
||||
*r4300_mult_hi(r4300) = SE32(rrs32);
|
||||
}
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -848,6 +854,7 @@ DECLARE_INSTRUCTION(DIVU)
|
||||
*r4300_mult_lo(r4300) = -1;
|
||||
*r4300_mult_hi(r4300) = SE32(rrs32);
|
||||
}
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -872,6 +879,7 @@ DECLARE_INSTRUCTION(DDIV)
|
||||
*r4300_mult_lo(r4300) = rrs < 0 ? 1 : -1;
|
||||
*r4300_mult_hi(r4300) = rrs;
|
||||
}
|
||||
cp0_add_count(r4300, 34, 1);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -888,6 +896,7 @@ DECLARE_INSTRUCTION(DDIVU)
|
||||
*r4300_mult_lo(r4300) = -1;
|
||||
*r4300_mult_hi(r4300) = rrs;
|
||||
}
|
||||
cp0_add_count(r4300, 34, 1);
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -959,6 +968,83 @@ DECLARE_JUMP(BC1TL, PCADDR + (iimmediate+1)*4, ((*r4300_cp1_fcr31(&r4300->cp1))
|
||||
DECLARE_INSTRUCTION(CACHE)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t lslfaddr = (uint32_t) r4300_regs(r4300)[lfbase] + lfoffset;
|
||||
if (r4300_translate_address(r4300, &lslfaddr, &(uint8_t){0}, 2, 0))
|
||||
return; // TLB exception
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
const unsigned char lslfft = lfft;
|
||||
struct datacache *dcache_line = &r4300->mem->dcache[lslfaddr >> 4 & UINT32_C(0x1FF)];
|
||||
struct instcache *icache_line = &r4300->mem->icache[lslfaddr >> 5 & UINT32_C(0x1FF)];
|
||||
switch (lslfft)
|
||||
{
|
||||
case 0x00: //icache index invalidate
|
||||
icache_line->valid = 0;
|
||||
break;
|
||||
case 0x04: //icache load tag
|
||||
masked_write(&cp0_regs[CP0_TAGLO_REG], icache_line->valid << 7, UINT32_C(0x80));
|
||||
masked_write(&cp0_regs[CP0_TAGLO_REG], 0, UINT32_C(0x40));
|
||||
masked_write(&cp0_regs[CP0_TAGLO_REG], icache_line->tag >> 4, UINT32_C(0xFFFFF00));
|
||||
break;
|
||||
case 0x08: //icache store tag
|
||||
icache_line->valid = (cp0_regs[CP0_TAGLO_REG] & UINT32_C(0x80)) >> 7;
|
||||
icache_line->tag = (cp0_regs[CP0_TAGLO_REG] & UINT32_C(0xFFFFF00)) << 4;
|
||||
break;
|
||||
case 0x10: //icache hit invalidate
|
||||
if(icache_hit(icache_line, lslfaddr))
|
||||
icache_line->valid = 0;
|
||||
break;
|
||||
case 0x14: //icache fill
|
||||
icache_fill(icache_line, r4300, lslfaddr);
|
||||
break;
|
||||
case 0x18: //icache hit write back
|
||||
if(icache_hit(icache_line, lslfaddr))
|
||||
icache_writeback(r4300, icache_line);
|
||||
break;
|
||||
case 0x01: //dcache index write back invalidate
|
||||
if (dcache_line->dirty && dcache_line->valid)
|
||||
dcache_writeback(r4300, dcache_line);
|
||||
dcache_line->valid = 0;
|
||||
break;
|
||||
case 0x05: //dcache index load tag
|
||||
masked_write(&cp0_regs[CP0_TAGLO_REG], dcache_line->valid << 7, UINT32_C(0x80));
|
||||
masked_write(&cp0_regs[CP0_TAGLO_REG], dcache_line->dirty << 6, UINT32_C(0x40));
|
||||
masked_write(&cp0_regs[CP0_TAGLO_REG], dcache_line->tag >> 4, UINT32_C(0xFFFFF00));
|
||||
break;
|
||||
case 0x09: //dcache index store tag
|
||||
dcache_line->valid = (cp0_regs[CP0_TAGLO_REG] & UINT32_C(0x80)) >> 7;
|
||||
dcache_line->dirty = (cp0_regs[CP0_TAGLO_REG] & UINT32_C(0x40)) >> 6;
|
||||
dcache_line->tag = (cp0_regs[CP0_TAGLO_REG] & UINT32_C(0xFFFFF00)) << 4;
|
||||
break;
|
||||
case 0x0D: //dcache create dirty exclusive
|
||||
if(!dcache_hit(dcache_line, lslfaddr) && dcache_line->dirty)
|
||||
dcache_writeback(r4300, dcache_line);
|
||||
dcache_line->tag = lslfaddr & ~UINT32_C(0xFFF);
|
||||
dcache_line->valid = 1;
|
||||
dcache_line->dirty = 1;
|
||||
break;
|
||||
case 0x11: //dcache hit invalidate
|
||||
if(dcache_hit(dcache_line, lslfaddr))
|
||||
{
|
||||
dcache_line->valid = 0;
|
||||
dcache_line->dirty = 0;
|
||||
}
|
||||
break;
|
||||
case 0x15: //dcache hit write back invalidate
|
||||
if(dcache_hit(dcache_line, lslfaddr))
|
||||
{
|
||||
if(dcache_line->dirty)
|
||||
dcache_writeback(r4300, dcache_line);
|
||||
dcache_line->valid = 0;
|
||||
}
|
||||
break;
|
||||
case 0x19: //dcache hit write back
|
||||
if(dcache_hit(dcache_line, lslfaddr))
|
||||
{
|
||||
if(dcache_line->dirty)
|
||||
dcache_writeback(r4300, dcache_line);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ADD_TO_PC(1);
|
||||
}
|
||||
|
||||
@@ -968,7 +1054,6 @@ DECLARE_INSTRUCTION(ERET)
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
int* cp0_cycle_count = r4300_cp0_cycle_count(&r4300->cp0);
|
||||
|
||||
cp0_update_count(r4300);
|
||||
if (cp0_regs[CP0_STATUS_REG] & CP0_STATUS_ERL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "error in ERET");
|
||||
@@ -1191,8 +1276,7 @@ DECLARE_INSTRUCTION(TLBWR)
|
||||
{
|
||||
DECLARE_R4300
|
||||
uint32_t* cp0_regs = r4300_cp0_regs(&r4300->cp0);
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/2 % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
TLBWrite(r4300, cp0_regs[CP0_RANDOM_REG]);
|
||||
ADD_TO_PC(1);
|
||||
@@ -1217,12 +1301,10 @@ DECLARE_INSTRUCTION(MFC0)
|
||||
switch(rfs)
|
||||
{
|
||||
case CP0_RANDOM_REG:
|
||||
cp0_update_count(r4300);
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
cp0_regs[CP0_RANDOM_REG] = (cp0_regs[CP0_COUNT_REG]/2 % (32 - cp0_regs[CP0_WIRED_REG]))
|
||||
+ cp0_regs[CP0_WIRED_REG];
|
||||
break;
|
||||
case CP0_COUNT_REG:
|
||||
cp0_update_count(r4300);
|
||||
break;
|
||||
}
|
||||
rrt = SE32(cp0_regs[rfs]);
|
||||
@@ -1267,7 +1349,6 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
case CP0_BADVADDR_REG:
|
||||
break;
|
||||
case CP0_COUNT_REG:
|
||||
cp0_update_count(r4300);
|
||||
r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_R4300;
|
||||
if (*cp0_cycle_count >= 0) { gen_interrupt(r4300); }
|
||||
r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_R4300;
|
||||
@@ -1277,14 +1358,13 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
cp0_regs[CP0_ENTRYHI_REG] = rrt32 & UINT32_C(0xFFFFE0FF);
|
||||
break;
|
||||
case CP0_COMPARE_REG:
|
||||
cp0_update_count(r4300);
|
||||
remove_event(&r4300->cp0.q, COMPARE_INT);
|
||||
|
||||
/* Add count_per_op to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
cp0_regs[CP0_COUNT_REG] += r4300->cp0.count_per_op;
|
||||
*cp0_cycle_count += r4300->cp0.count_per_op;
|
||||
/* Add 2 to avoid wrong event order in case CP0_COUNT_REG == CP0_COMPARE_REG */
|
||||
cp0_regs[CP0_COUNT_REG] += 2;
|
||||
*cp0_cycle_count += 2;
|
||||
add_interrupt_event_count(&r4300->cp0, COMPARE_INT, rrt32);
|
||||
cp0_regs[CP0_COUNT_REG] -= r4300->cp0.count_per_op;
|
||||
cp0_regs[CP0_COUNT_REG] -= 2;
|
||||
|
||||
/* Update next interrupt in case first event is COMPARE_INT */
|
||||
*cp0_cycle_count = cp0_regs[CP0_COUNT_REG] - r4300->cp0.q.first->data.count;
|
||||
@@ -1297,7 +1377,6 @@ DECLARE_INSTRUCTION(MTC0)
|
||||
|
||||
cp0_regs[CP0_STATUS_REG] = rrt32;
|
||||
ADD_TO_PC(1);
|
||||
cp0_update_count(r4300);
|
||||
r4300_check_interrupt(r4300, CP0_CAUSE_IP2, r4300->mi->regs[MI_INTR_REG] & r4300->mi->regs[MI_INTR_MASK_REG]); // ???
|
||||
r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_R4300;
|
||||
if (*cp0_cycle_count >= 0) { gen_interrupt(r4300); }
|
||||
|
||||
@@ -1858,7 +1858,6 @@ void* ERET_new(void)
|
||||
struct r4300_core* r4300 = &g_dev.r4300;
|
||||
struct new_dynarec_hot_state* state = &r4300->new_dynarec_hot_state;
|
||||
|
||||
cp0_update_count(r4300);
|
||||
if (state->cp0_regs[CP0_STATUS_REG] & CP0_STATUS_ERL)
|
||||
{
|
||||
DebugMessage(M64MSG_ERROR, "error in ERET");
|
||||
@@ -1976,7 +1975,6 @@ static void TLBWR_new(int pcaddr, int count)
|
||||
unsigned int i;
|
||||
UPDATE_COUNT_IN
|
||||
state->pcaddr = pcaddr;
|
||||
cp0_update_count(r4300);
|
||||
state->cp0_regs[CP0_RANDOM_REG] = (state->cp0_regs[CP0_COUNT_REG]/r4300->cp0.count_per_op % (32 - state->cp0_regs[CP0_WIRED_REG])) + state->cp0_regs[CP0_WIRED_REG];
|
||||
/* Remove old entries */
|
||||
unsigned int old_start_even=r4300->cp0.tlb.entries[state->cp0_regs[CP0_RANDOM_REG]&0x3F].start_even;
|
||||
@@ -3021,7 +3019,6 @@ void dynarec_gen_interrupt(void)
|
||||
{
|
||||
struct r4300_core* r4300 = &g_dev.r4300;
|
||||
struct new_dynarec_hot_state* state = &r4300->new_dynarec_hot_state;
|
||||
cp0_update_count(r4300);
|
||||
uint32_t page = ((state->cp0_regs[CP0_COUNT_REG]>>19)&0x1fc);
|
||||
unsigned int *candidate = (unsigned int *)&restore_candidate[page];
|
||||
page <<= 3;
|
||||
|
||||
@@ -59,7 +59,6 @@ static void InterpretOpcode(struct r4300_core* r4300);
|
||||
r4300->interp_PC.addr += 4; \
|
||||
r4300->delay_slot=1; \
|
||||
InterpretOpcode(r4300); \
|
||||
cp0_update_count(r4300); \
|
||||
r4300->delay_slot=0; \
|
||||
if (take_jump && !r4300->skip_jump) \
|
||||
{ \
|
||||
@@ -69,7 +68,6 @@ static void InterpretOpcode(struct r4300_core* r4300);
|
||||
else \
|
||||
{ \
|
||||
r4300->interp_PC.addr += 8; \
|
||||
cp0_update_count(r4300); \
|
||||
} \
|
||||
r4300->cp0.last_addr = r4300->interp_PC.addr; \
|
||||
if (*r4300_cp0_cycle_count(&r4300->cp0) >= 0) gen_interrupt(r4300); \
|
||||
@@ -82,7 +80,6 @@ static void InterpretOpcode(struct r4300_core* r4300);
|
||||
if (cop1 && check_cop1_unusable(r4300)) return; \
|
||||
if (take_jump) \
|
||||
{ \
|
||||
cp0_update_count(r4300); \
|
||||
if(*cp0_cycle_count < 0) \
|
||||
{ \
|
||||
cp0_regs[CP0_COUNT_REG] -= *cp0_cycle_count; \
|
||||
@@ -108,7 +105,7 @@ static void InterpretOpcode(struct r4300_core* r4300);
|
||||
* relative to the instruction in the delay slot, so 1 instruction backwards
|
||||
* (-1) goes back to the jump. */
|
||||
#define IS_RELATIVE_IDLE_LOOP(r4300, op, addr) \
|
||||
(IMM16S_OF(op) == -1 && *fast_mem_access((r4300), (addr) + 4) == 0)
|
||||
(IMM16S_OF(op) == -1 && *fast_mem_access((r4300), (addr) + 4, 0) == 0)
|
||||
|
||||
/* Determines whether an absolute jump in a 26-bit immediate goes back to the
|
||||
* same instruction without doing any work in its delay slot. The jump is
|
||||
@@ -117,7 +114,7 @@ static void InterpretOpcode(struct r4300_core* r4300);
|
||||
#define IS_ABSOLUTE_IDLE_LOOP(r4300, op, addr) \
|
||||
(JUMP_OF(op) == ((addr) & UINT32_C(0x0FFFFFFF)) >> 2 \
|
||||
&& ((addr) & UINT32_C(0x0FFFFFFF)) != UINT32_C(0x0FFFFFFC) \
|
||||
&& *fast_mem_access((r4300), (addr) + 4) == 0)
|
||||
&& *fast_mem_access((r4300), (addr) + 4, 0) == 0)
|
||||
|
||||
/* These macros parse opcode fields. */
|
||||
#define rrt r4300_regs(r4300)[RT_OF(op)]
|
||||
@@ -164,7 +161,7 @@ static void InterpretOpcode(struct r4300_core* r4300);
|
||||
|
||||
void InterpretOpcode(struct r4300_core* r4300)
|
||||
{
|
||||
uint32_t* op_address = fast_mem_access(r4300, *r4300_pc(r4300));
|
||||
uint32_t* op_address = fast_mem_access(r4300, *r4300_pc(r4300), 1);
|
||||
if (op_address == NULL)
|
||||
return;
|
||||
uint32_t op = *op_address;
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
#include <time.h>
|
||||
|
||||
void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers,
|
||||
unsigned int emumode, unsigned int count_per_op, unsigned int count_per_op_denom_pot, int no_compiled_jump, int randomize_interrupt, uint32_t start_address)
|
||||
unsigned int emumode, int no_compiled_jump, int randomize_interrupt, uint32_t start_address)
|
||||
{
|
||||
struct new_dynarec_hot_state* new_dynarec_hot_state =
|
||||
#ifdef NEW_DYNAREC
|
||||
@@ -51,7 +51,7 @@ void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controll
|
||||
#endif
|
||||
|
||||
r4300->emumode = emumode;
|
||||
init_cp0(&r4300->cp0, count_per_op, count_per_op_denom_pot, new_dynarec_hot_state, interrupt_handlers);
|
||||
init_cp0(&r4300->cp0, new_dynarec_hot_state, interrupt_handlers);
|
||||
init_cp1(&r4300->cp1, new_dynarec_hot_state);
|
||||
|
||||
#ifndef NEW_DYNAREC
|
||||
@@ -63,6 +63,7 @@ void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controll
|
||||
r4300->rdram = rdram;
|
||||
r4300->randomize_interrupt = randomize_interrupt;
|
||||
r4300->start_address = start_address;
|
||||
r4300->clock_rate = 93750000 / 2;
|
||||
srand((unsigned int) time(NULL));
|
||||
}
|
||||
|
||||
@@ -277,19 +278,38 @@ unsigned int get_r4300_emumode(struct r4300_core* r4300)
|
||||
return r4300->emumode;
|
||||
}
|
||||
|
||||
uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address)
|
||||
uint8_t r4300_translate_address(struct r4300_core* r4300, uint32_t* address, uint8_t* cached, uint8_t tlb_mode, uint8_t write)
|
||||
{
|
||||
if ((*address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
if (write)
|
||||
invalidate_r4300_cached_code(r4300, *address, write);
|
||||
*address = virtual_to_physical_address(r4300, *address, tlb_mode, cached);
|
||||
if (*address == 0) // TLB exception
|
||||
return 1;
|
||||
} else if (!(*address & UINT32_C(0x20000000)))
|
||||
*cached = 1;
|
||||
|
||||
if (write)
|
||||
{
|
||||
invalidate_r4300_cached_code(r4300, *address, write);
|
||||
invalidate_r4300_cached_code(r4300, *address ^ UINT32_C(0x20000000), write);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address, uint8_t use_cache)
|
||||
{
|
||||
/* This code is performance critical, specially on pure interpreter mode.
|
||||
* Removing error checking saves some time, but the emulator may crash. */
|
||||
uint8_t cached = 0;
|
||||
if (r4300_translate_address(r4300, &address, &cached, 2, 0))
|
||||
return NULL; // TLB exception
|
||||
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
address = virtual_to_physical_address(r4300, address, 2);
|
||||
if (address == 0) // TLB exception
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (use_cache && cached)
|
||||
return icache_fetch(r4300, address);
|
||||
if (use_cache && !cached)
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
|
||||
return mem_base_u32(r4300->mem->base, address);
|
||||
}
|
||||
|
||||
@@ -299,17 +319,19 @@ uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address)
|
||||
*/
|
||||
int r4300_read_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t* value)
|
||||
{
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
address = virtual_to_physical_address(r4300, address, 0);
|
||||
if (address == 0) {
|
||||
return 0;
|
||||
}
|
||||
uint8_t cached = 0;
|
||||
if (r4300_translate_address(r4300, &address, &cached, 0, 0))
|
||||
return 0; // TLB exception
|
||||
|
||||
if (cached)
|
||||
dcache_read32(r4300, address & ~UINT32_C(3), value);
|
||||
else
|
||||
{
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
mem_read32(mem_get_handler(r4300->mem, address), address & ~UINT32_C(3), value);
|
||||
}
|
||||
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
|
||||
mem_read32(mem_get_handler(r4300->mem, address), address & ~UINT32_C(3), value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -317,6 +339,7 @@ int r4300_read_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t
|
||||
int r4300_read_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t* value)
|
||||
{
|
||||
uint32_t w[2];
|
||||
uint8_t cached = 0;
|
||||
|
||||
/* XXX: unaligned dword accesses should trigger a address error,
|
||||
* but inaccurate timing of the core can lead to unaligned address on reset
|
||||
@@ -325,18 +348,22 @@ int r4300_read_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_
|
||||
DebugMessage(M64MSG_WARNING, "Unaligned dword read %08x", address);
|
||||
}
|
||||
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
address = virtual_to_physical_address(r4300, address, 0);
|
||||
if (address == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (r4300_translate_address(r4300, &address, &cached, 0, 0))
|
||||
return 0; // TLB exception
|
||||
|
||||
if (cached)
|
||||
{
|
||||
dcache_read32(r4300, address + 0, &w[0]);
|
||||
dcache_read32(r4300, address + 4, &w[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, address);
|
||||
mem_read32(handler, address + 0, &w[0]);
|
||||
mem_read32(handler, address + 4, &w[1]);
|
||||
}
|
||||
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, address);
|
||||
mem_read32(handler, address + 0, &w[0]);
|
||||
mem_read32(handler, address + 4, &w[1]);
|
||||
|
||||
*value = ((uint64_t)w[0] << 32) | w[1];
|
||||
|
||||
@@ -349,29 +376,26 @@ int r4300_read_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_
|
||||
*/
|
||||
int r4300_write_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t value, uint32_t mask)
|
||||
{
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
uint8_t cached = 0;
|
||||
if (r4300_translate_address(r4300, &address, &cached, 1, 4))
|
||||
return 0; // TLB exception
|
||||
|
||||
invalidate_r4300_cached_code(r4300, address, 4);
|
||||
|
||||
address = virtual_to_physical_address(r4300, address, 1);
|
||||
if (address == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (cached)
|
||||
dcache_write32(r4300, address & ~UINT32_C(3), value, mask);
|
||||
else
|
||||
{
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
mem_write32(mem_get_handler(r4300->mem, address), address & ~UINT32_C(3), value, mask);
|
||||
}
|
||||
|
||||
invalidate_r4300_cached_code(r4300, address, 4);
|
||||
invalidate_r4300_cached_code(r4300, address ^ UINT32_C(0x20000000), 4);
|
||||
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
|
||||
mem_write32(mem_get_handler(r4300->mem, address), address & ~UINT32_C(3), value, mask);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Write aligned dword to memory */
|
||||
int r4300_write_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t value, uint64_t mask)
|
||||
{
|
||||
uint8_t cached = 0;
|
||||
/* XXX: unaligned dword accesses should trigger a address error,
|
||||
* but inaccurate timing of the core can lead to unaligned address on reset
|
||||
* so just emit a warning and keep going */
|
||||
@@ -379,24 +403,22 @@ int r4300_write_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64
|
||||
DebugMessage(M64MSG_WARNING, "Unaligned dword write %08x", address);
|
||||
}
|
||||
|
||||
if ((address & UINT32_C(0xc0000000)) != UINT32_C(0x80000000)) {
|
||||
if (r4300_translate_address(r4300, &address, &cached, 1, 8))
|
||||
return 0; // TLB exception
|
||||
|
||||
invalidate_r4300_cached_code(r4300, address, 8);
|
||||
|
||||
address = virtual_to_physical_address(r4300, address, 1);
|
||||
if (address == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (cached)
|
||||
{
|
||||
dcache_write32(r4300, address + 0, value >> 32, mask >> 32);
|
||||
dcache_write32(r4300, address + 4, (uint32_t) value, (uint32_t) mask);
|
||||
}
|
||||
else
|
||||
{
|
||||
cp0_add_count(r4300, 18, 1);
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, address);
|
||||
mem_write32(handler, address + 0, value >> 32, mask >> 32);
|
||||
mem_write32(handler, address + 4, (uint32_t) value, (uint32_t) mask);
|
||||
}
|
||||
|
||||
invalidate_r4300_cached_code(r4300, address, 8);
|
||||
invalidate_r4300_cached_code(r4300, address ^ UINT32_C(0x20000000), 8);
|
||||
|
||||
address &= UINT32_C(0x1ffffffc);
|
||||
|
||||
const struct mem_handler* handler = mem_get_handler(r4300->mem, address);
|
||||
mem_write32(handler, address + 0, value >> 32, mask >> 32);
|
||||
mem_write32(handler, address + 4, (uint32_t) value, (uint32_t) mask );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -197,6 +197,7 @@ struct r4300_core
|
||||
uint32_t randomize_interrupt;
|
||||
|
||||
uint32_t start_address;
|
||||
uint32_t clock_rate;
|
||||
};
|
||||
|
||||
#define R4300_KSEG0 UINT32_C(0x80000000)
|
||||
@@ -211,7 +212,7 @@ struct r4300_core
|
||||
offsetof(struct new_dynarec_hot_state, regs))
|
||||
#endif
|
||||
|
||||
void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers, unsigned int emumode, unsigned int count_per_op, unsigned int count_per_op_denom_pot, int no_compiled_jump, int randomize_interrupt, uint32_t start_address);
|
||||
void init_r4300(struct r4300_core* r4300, struct memory* mem, struct mi_controller* mi, struct rdram* rdram, const struct interrupt_handler* interrupt_handlers, unsigned int emumode, int no_compiled_jump, int randomize_interrupt, uint32_t start_address);
|
||||
void poweron_r4300(struct r4300_core* r4300);
|
||||
|
||||
void run_r4300(struct r4300_core* r4300);
|
||||
@@ -229,7 +230,9 @@ unsigned int get_r4300_emumode(struct r4300_core* r4300);
|
||||
/* Returns a pointer to a block of contiguous memory
|
||||
* Can access RDRAM, SP_DMEM, SP_IMEM and ROM, using TLB if necessary
|
||||
* Useful for getting fast access to a zone with executable code. */
|
||||
uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address);
|
||||
uint32_t *fast_mem_access(struct r4300_core* r4300, uint32_t address, uint8_t use_cache);
|
||||
|
||||
uint8_t r4300_translate_address(struct r4300_core* r4300, uint32_t* address, uint8_t* cached, uint8_t tlb_mode, uint8_t write);
|
||||
|
||||
int r4300_read_aligned_word(struct r4300_core* r4300, uint32_t address, uint32_t* value);
|
||||
int r4300_read_aligned_dword(struct r4300_core* r4300, uint32_t address, uint64_t* value);
|
||||
|
||||
@@ -578,7 +578,7 @@ void dynarec_init_block(struct r4300_core* r4300, uint32_t address)
|
||||
r4300->cached_interp.invalid_code[b->start>>12] = 0;
|
||||
if (b->end < UINT32_C(0x80000000) || b->start >= UINT32_C(0xc0000000))
|
||||
{
|
||||
uint32_t paddr = virtual_to_physical_address(r4300, b->start, 2);
|
||||
uint32_t paddr = virtual_to_physical_address(r4300, b->start, 2, &(uint8_t){0});
|
||||
r4300->cached_interp.invalid_code[paddr>>12] = 0;
|
||||
dynarec_init_block(r4300, paddr);
|
||||
|
||||
@@ -655,7 +655,7 @@ void dynarec_recompile_block(struct r4300_core* r4300, const uint32_t* iw, struc
|
||||
|
||||
if (block_start_in_tlb)
|
||||
{
|
||||
uint32_t address2 = virtual_to_physical_address(r4300, r4300->recomp.dst->addr, 0);
|
||||
uint32_t address2 = virtual_to_physical_address(r4300, r4300->recomp.dst->addr, 0, &(uint8_t){0});
|
||||
if (r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops == r4300->cached_interp.not_compiled) {
|
||||
r4300->cached_interp.blocks[address2>>12]->block[(address2&UINT32_C(0xFFF))/4].ops = r4300->cached_interp.not_compiled2;
|
||||
}
|
||||
@@ -923,7 +923,6 @@ int dynarec_check_cop1_unusable(void)
|
||||
/* Parameterless version of cp0_update_count to ease usage in dynarec. */
|
||||
void dynarec_cp0_update_count(void)
|
||||
{
|
||||
cp0_update_count(&g_dev.r4300);
|
||||
}
|
||||
|
||||
/* Parameterless version of gen_interrupt to ease usage in dynarec. */
|
||||
|
||||
@@ -34,6 +34,8 @@ void poweron_tlb(struct tlb* tlb)
|
||||
memset(tlb->entries, 0, 32 * sizeof(tlb->entries[0]));
|
||||
memset(tlb->LUT_r, 0, 0x100000 * sizeof(tlb->LUT_r[0]));
|
||||
memset(tlb->LUT_w, 0, 0x100000 * sizeof(tlb->LUT_w[0]));
|
||||
memset(tlb->r_cached, 0, 0x100000 * sizeof(tlb->r_cached[0]));
|
||||
memset(tlb->w_cached, 0, 0x100000 * sizeof(tlb->w_cached[0]));
|
||||
}
|
||||
|
||||
void tlb_unmap(struct tlb* tlb, size_t entry)
|
||||
@@ -47,19 +49,31 @@ void tlb_unmap(struct tlb* tlb, size_t entry)
|
||||
if (e->v_even)
|
||||
{
|
||||
for (i=e->start_even; i<e->end_even; i += 0x1000)
|
||||
{
|
||||
tlb->LUT_r[i>>12] = 0;
|
||||
tlb->r_cached[i>>12] = 0;
|
||||
}
|
||||
if (e->d_even)
|
||||
for (i=e->start_even; i<e->end_even; i += 0x1000)
|
||||
{
|
||||
tlb->LUT_w[i>>12] = 0;
|
||||
tlb->w_cached[i>>12] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (e->v_odd)
|
||||
{
|
||||
for (i=e->start_odd; i<e->end_odd; i += 0x1000)
|
||||
{
|
||||
tlb->LUT_r[i>>12] = 0;
|
||||
tlb->r_cached[i>>12] = 0;
|
||||
}
|
||||
if (e->d_odd)
|
||||
for (i=e->start_odd; i<e->end_odd; i += 0x1000)
|
||||
{
|
||||
tlb->LUT_w[i>>12] = 0;
|
||||
tlb->w_cached[i>>12] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,10 +92,16 @@ void tlb_map(struct tlb* tlb, size_t entry)
|
||||
e->phys_even < 0x20000000)
|
||||
{
|
||||
for (i=e->start_even;i<e->end_even;i+=0x1000)
|
||||
{
|
||||
tlb->LUT_r[i>>12] = UINT32_C(0x80000000) | (e->phys_even + (i - e->start_even) + 0xFFF);
|
||||
tlb->r_cached[i>>12] = e->c_even != 2;
|
||||
}
|
||||
if (e->d_even)
|
||||
for (i=e->start_even;i<e->end_even;i+=0x1000)
|
||||
{
|
||||
tlb->LUT_w[i>>12] = UINT32_C(0x80000000) | (e->phys_even + (i - e->start_even) + 0xFFF);
|
||||
tlb->w_cached[i>>12] = e->c_even != 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,15 +112,21 @@ void tlb_map(struct tlb* tlb, size_t entry)
|
||||
e->phys_odd < 0x20000000)
|
||||
{
|
||||
for (i=e->start_odd;i<e->end_odd;i+=0x1000)
|
||||
{
|
||||
tlb->LUT_r[i>>12] = UINT32_C(0x80000000) | (e->phys_odd + (i - e->start_odd) + 0xFFF);
|
||||
tlb->r_cached[i>>12] = e->c_odd != 2;
|
||||
}
|
||||
if (e->d_odd)
|
||||
for (i=e->start_odd;i<e->end_odd;i+=0x1000)
|
||||
{
|
||||
tlb->LUT_w[i>>12] = UINT32_C(0x80000000) | (e->phys_odd + (i - e->start_odd) + 0xFFF);
|
||||
tlb->w_cached[i>>12] = e->c_odd != 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w)
|
||||
uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w, uint8_t *cached)
|
||||
{
|
||||
const struct tlb* tlb = &r4300->cp0.tlb;
|
||||
unsigned int addr = address >> 12;
|
||||
@@ -130,12 +156,18 @@ uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address,
|
||||
if (w == 1)
|
||||
{
|
||||
if (tlb->LUT_w[addr])
|
||||
{
|
||||
*cached = tlb->w_cached[addr];
|
||||
return (tlb->LUT_w[addr] & UINT32_C(0xFFFFF000)) | (address & UINT32_C(0xFFF));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tlb->LUT_r[addr])
|
||||
{
|
||||
*cached = tlb->r_cached[addr];
|
||||
return (tlb->LUT_r[addr] & UINT32_C(0xFFFFF000)) | (address & UINT32_C(0xFFF));
|
||||
}
|
||||
}
|
||||
//printf("tlb exception !!! @ %x, %x, add:%x\n", address, w, r4300->pc->addr);
|
||||
//getchar();
|
||||
|
||||
@@ -57,6 +57,8 @@ struct tlb
|
||||
struct tlb_entry entries[32];
|
||||
uint32_t LUT_r[0x100000];
|
||||
uint32_t LUT_w[0x100000];
|
||||
uint8_t r_cached[0x100000];
|
||||
uint8_t w_cached[0x100000];
|
||||
};
|
||||
|
||||
void poweron_tlb(struct tlb* tlb);
|
||||
@@ -64,6 +66,6 @@ void poweron_tlb(struct tlb* tlb);
|
||||
void tlb_unmap(struct tlb* tlb, size_t entry);
|
||||
void tlb_map(struct tlb* tlb, size_t entry);
|
||||
|
||||
uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w);
|
||||
uint32_t virtual_to_physical_address(struct r4300_core* r4300, uint32_t address, int w, uint8_t *cached);
|
||||
|
||||
#endif /* M64P_DEVICE_R4300_TLB_H */
|
||||
|
||||
@@ -45,7 +45,6 @@ static uint32_t get_remaining_dma_length(struct ai_controller* ai)
|
||||
if (ai->fifo[0].duration == 0)
|
||||
return 0;
|
||||
|
||||
cp0_update_count(ai->mi->r4300);
|
||||
next_ai_event = get_event(&ai->mi->r4300->cp0.q, AI_INT);
|
||||
if (next_ai_event == NULL)
|
||||
return 0;
|
||||
@@ -64,9 +63,9 @@ static unsigned int get_dma_duration(struct ai_controller* ai)
|
||||
{
|
||||
unsigned int samples_per_sec = ai->vi->clock / (1 + ai->regs[AI_DACRATE_REG]);
|
||||
unsigned int bytes_per_sample = 4; /* XXX: assume 16bit stereo - should depends on bitrate instead */
|
||||
unsigned int cpu_counts_per_sec = ai->vi->delay == 0 ? ai->vi->clock : ai->vi->delay * ai->vi->expected_refresh_rate; /* estimate cpu counts/sec using VI */
|
||||
unsigned int length = (ai->regs[AI_LEN_REG] & ~UINT32_C(7)) - 8;
|
||||
|
||||
return ai->regs[AI_LEN_REG] * (cpu_counts_per_sec / (bytes_per_sample * samples_per_sec));
|
||||
return length * (ai->mi->r4300->clock_rate / (bytes_per_sample * samples_per_sec));
|
||||
}
|
||||
|
||||
|
||||
@@ -94,7 +93,6 @@ static void do_dma(struct ai_controller* ai, struct ai_dma* dma)
|
||||
ai->delayed_carry = 0;
|
||||
|
||||
/* schedule end of dma event */
|
||||
cp0_update_count(ai->mi->r4300);
|
||||
add_interrupt_event(&ai->mi->r4300->cp0, AI_INT, dma->duration);
|
||||
}
|
||||
|
||||
|
||||
@@ -105,7 +105,6 @@ void write_mi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask
|
||||
update_mi_intr_mask(&mi->regs[MI_INTR_MASK_REG], value & mask);
|
||||
|
||||
r4300_check_interrupt(mi->r4300, CP0_CAUSE_IP2, mi->regs[MI_INTR_REG] & mi->regs[MI_INTR_MASK_REG]);
|
||||
cp0_update_count(mi->r4300);
|
||||
if (*cp0_cycle_count >= 0) gen_interrupt(mi->r4300);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,54 @@ int validate_pi_request(struct pi_controller* pi)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static uint32_t dma_pi_calculate_cycles(struct pi_controller* pi, uint32_t length)
|
||||
{
|
||||
uint32_t cycles = 0;
|
||||
uint8_t domain = 0;
|
||||
uint32_t latency;
|
||||
uint32_t pulse_width;
|
||||
uint32_t release;
|
||||
uint32_t page_size;
|
||||
uint32_t pages;
|
||||
if (pi->regs[PI_CART_ADDR_REG] >= 0x1FC04000 && pi->regs[PI_CART_ADDR_REG] < 0x80000000)
|
||||
domain = 1;
|
||||
else if (pi->regs[PI_CART_ADDR_REG] >= 0x10000000 && pi->regs[PI_CART_ADDR_REG] < 0x1FC00000)
|
||||
domain = 1;
|
||||
else if (pi->regs[PI_CART_ADDR_REG] >= 0x08000000 && pi->regs[PI_CART_ADDR_REG] < 0x10000000)
|
||||
domain = 2;
|
||||
else if (pi->regs[PI_CART_ADDR_REG] >= 0x06000000 && pi->regs[PI_CART_ADDR_REG] < 0x08000000)
|
||||
domain = 1;
|
||||
else if (pi->regs[PI_CART_ADDR_REG] >= 0x05000000 && pi->regs[PI_CART_ADDR_REG] < 0x06000000)
|
||||
domain = 2;
|
||||
else
|
||||
{
|
||||
DebugMessage(M64MSG_WARNING, "Unknown PI DMA domain: 0x%x", pi->regs[PI_CART_ADDR_REG]);
|
||||
return length / 8;
|
||||
}
|
||||
|
||||
if (domain == 1)
|
||||
{
|
||||
latency = pi->regs[PI_BSD_DOM1_LAT_REG] + 1;
|
||||
pulse_width = pi->regs[PI_BSD_DOM1_PWD_REG] + 1;
|
||||
release = pi->regs[PI_BSD_DOM1_RLS_REG] + 1;
|
||||
page_size = 2 ^ (pi->regs[PI_BSD_DOM1_PGS_REG] + 2);
|
||||
}
|
||||
else if (domain == 2)
|
||||
{
|
||||
latency = pi->regs[PI_BSD_DOM2_LAT_REG] + 1;
|
||||
pulse_width = pi->regs[PI_BSD_DOM2_PWD_REG] + 1;
|
||||
release = pi->regs[PI_BSD_DOM2_RLS_REG] + 1;
|
||||
page_size = 2 ^ (pi->regs[PI_BSD_DOM2_PGS_REG] + 2);
|
||||
}
|
||||
pages = length / page_size;
|
||||
|
||||
cycles += (14 + latency) * pages;
|
||||
cycles += (pulse_width + release) * (length / 2);
|
||||
cycles += 5 * pages;
|
||||
cycles /= 2;
|
||||
return cycles;
|
||||
}
|
||||
|
||||
static void dma_pi_read(struct pi_controller* pi)
|
||||
{
|
||||
if (!validate_pi_request(pi))
|
||||
@@ -73,7 +121,7 @@ static void dma_pi_read(struct pi_controller* pi)
|
||||
/* PI seems to treat the first 128 bytes differently, see https://n64brew.dev/wiki/Peripheral_Interface#Unaligned_DMA_transfer */
|
||||
if (length >= 0x7f && (length & 1))
|
||||
length += 1;
|
||||
unsigned int cycles = handler->dma_read(opaque, dram, dram_addr, cart_addr, length);
|
||||
handler->dma_read(opaque, dram, dram_addr, cart_addr, length);
|
||||
|
||||
/* Mark DMA as busy */
|
||||
pi->regs[PI_STATUS_REG] |= PI_STATUS_DMA_BUSY;
|
||||
@@ -82,7 +130,7 @@ static void dma_pi_read(struct pi_controller* pi)
|
||||
pi->regs[PI_CART_ADDR_REG] = (pi->regs[PI_CART_ADDR_REG] + length + 1) & ~1;
|
||||
|
||||
/* schedule end of dma interrupt event */
|
||||
cp0_update_count(pi->mi->r4300);
|
||||
uint32_t cycles = dma_pi_calculate_cycles(pi, length);
|
||||
add_interrupt_event(&pi->mi->r4300->cp0, PI_INT, cycles);
|
||||
}
|
||||
|
||||
@@ -111,7 +159,7 @@ static void dma_pi_write(struct pi_controller* pi)
|
||||
length += 1;
|
||||
if (length <= 0x80)
|
||||
length -= dram_addr & 0x7;
|
||||
unsigned int cycles = handler->dma_write(opaque, dram, dram_addr, cart_addr, length);
|
||||
handler->dma_write(opaque, dram, dram_addr, cart_addr, length);
|
||||
|
||||
post_framebuffer_write(&pi->dp->fb, dram_addr, length);
|
||||
|
||||
@@ -122,7 +170,7 @@ static void dma_pi_write(struct pi_controller* pi)
|
||||
pi->regs[PI_CART_ADDR_REG] = (pi->regs[PI_CART_ADDR_REG] + length + 1) & ~1;
|
||||
|
||||
/* schedule end of dma interrupt event */
|
||||
cp0_update_count(pi->mi->r4300);
|
||||
uint32_t cycles = dma_pi_calculate_cycles(pi, length);
|
||||
add_interrupt_event(&pi->mi->r4300->cp0, PI_INT, cycles);
|
||||
}
|
||||
|
||||
@@ -146,6 +194,12 @@ void init_pi(struct pi_controller* pi,
|
||||
void poweron_pi(struct pi_controller* pi)
|
||||
{
|
||||
memset(pi->regs, 0, PI_REGS_COUNT*sizeof(uint32_t));
|
||||
pi->regs[PI_BSD_DOM1_LAT_REG] = 0xFF;
|
||||
pi->regs[PI_BSD_DOM1_PWD_REG] = 0xFF;
|
||||
pi->regs[PI_BSD_DOM1_PGS_REG] = 0x03;
|
||||
pi->regs[PI_BSD_DOM2_LAT_REG] = 0xFF;
|
||||
pi->regs[PI_BSD_DOM2_PWD_REG] = 0xFF;
|
||||
pi->regs[PI_BSD_DOM2_PGS_REG] = 0x03;
|
||||
}
|
||||
|
||||
void read_pi_regs(void* opaque, uint32_t address, uint32_t* value)
|
||||
|
||||
@@ -66,8 +66,8 @@ enum
|
||||
|
||||
struct pi_dma_handler
|
||||
{
|
||||
unsigned int (*dma_read)(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
unsigned int (*dma_write)(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void (*dma_read)(void* opaque, const uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
void (*dma_write)(void* opaque, uint8_t* dram, uint32_t dram_addr, uint32_t cart_addr, uint32_t length);
|
||||
};
|
||||
|
||||
typedef void (*pi_dma_handler_getter)(struct cart* cart, struct dd_controller* dd, uint32_t address, void** opaque, const struct pi_dma_handler** handler);
|
||||
|
||||
@@ -80,8 +80,7 @@ static void do_sp_dma(struct rsp_core* sp, const struct sp_dma* dma)
|
||||
}
|
||||
|
||||
/* schedule end of dma event */
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, RSP_DMA_EVT, (count * length) / 8);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, RSP_DMA_EVT, ((count * length) / 16) + 4);
|
||||
}
|
||||
|
||||
static void fifo_push(struct rsp_core* sp, uint32_t dir)
|
||||
@@ -312,6 +311,7 @@ void do_SP_Task(struct rsp_core* sp)
|
||||
uint32_t save_pc = sp->regs2[SP_PC_REG] & ~0xfff;
|
||||
|
||||
uint32_t sp_delay_time;
|
||||
uint32_t saved_status = sp->regs[SP_STATUS_REG];
|
||||
|
||||
if (sp->mem[0xfc0/4] == 1)
|
||||
{
|
||||
@@ -335,11 +335,10 @@ void do_SP_Task(struct rsp_core* sp)
|
||||
if (sp->dp->dpc_regs[DPC_STATUS_REG] & DPC_STATUS_FREEZE) {
|
||||
sp->dp->do_on_unfreeze |= DELAY_DP_INT;
|
||||
} else {
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, DP_INT, 4000);
|
||||
}
|
||||
}
|
||||
sp_delay_time = 1000;
|
||||
sp_delay_time = 4000;
|
||||
|
||||
protect_framebuffers(&sp->dp->fb);
|
||||
}
|
||||
@@ -356,7 +355,7 @@ void do_SP_Task(struct rsp_core* sp)
|
||||
#endif
|
||||
sp->regs2[SP_PC_REG] |= save_pc;
|
||||
|
||||
sp_delay_time = 4000;
|
||||
sp_delay_time = 8000;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -367,7 +366,6 @@ void do_SP_Task(struct rsp_core* sp)
|
||||
sp_delay_time = 0;
|
||||
}
|
||||
|
||||
cp0_update_count(sp->mi->r4300);
|
||||
if (sp->mi->regs[MI_INTR_REG] & MI_INTR_SP)
|
||||
{
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, SP_INT, sp_delay_time);
|
||||
@@ -388,16 +386,18 @@ void do_SP_Task(struct rsp_core* sp)
|
||||
add_interrupt_event(&sp->mi->r4300->cp0, RSP_TSK_EVT, sp_delay_time);
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state |= INTR_UNSAFE_RSP_TASK;
|
||||
}
|
||||
|
||||
sp->rsp_status = sp->regs[SP_STATUS_REG] & (SP_STATUS_BROKE | SP_STATUS_HALT);
|
||||
sp->regs[SP_STATUS_REG] &= ~(SP_STATUS_BROKE | SP_STATUS_HALT);
|
||||
sp->rsp_status = sp->regs[SP_STATUS_REG];
|
||||
if (sp->regs[SP_STATUS_REG] & (SP_STATUS_HALT | SP_STATUS_BROKE))
|
||||
{
|
||||
sp->regs[SP_STATUS_REG] = saved_status;
|
||||
}
|
||||
}
|
||||
|
||||
void rsp_interrupt_event(void* opaque)
|
||||
{
|
||||
struct rsp_core* sp = (struct rsp_core*)opaque;
|
||||
|
||||
sp->regs[SP_STATUS_REG] |= sp->rsp_status;
|
||||
sp->regs[SP_STATUS_REG] = sp->rsp_status;
|
||||
sp->rsp_status = 0;
|
||||
sp->mi->r4300->cp0.interrupt_unsafe_state &= ~INTR_UNSAFE_RSP;
|
||||
raise_rcp_interrupt(sp->mi, MI_INTR_SP);
|
||||
|
||||
@@ -80,7 +80,6 @@ static void dma_si_write(struct si_controller* si)
|
||||
|
||||
copy_pif_rdram(si);
|
||||
|
||||
cp0_update_count(si->mi->r4300);
|
||||
si->regs[SI_STATUS_REG] |= SI_STATUS_DMA_BUSY;
|
||||
add_interrupt_event(&si->mi->r4300->cp0, SI_INT, si->dma_duration + add_random_interrupt_time(si->mi->r4300));
|
||||
}
|
||||
@@ -94,7 +93,6 @@ static void dma_si_read(struct si_controller* si)
|
||||
|
||||
update_pif_ram(si->pif);
|
||||
|
||||
cp0_update_count(si->mi->r4300);
|
||||
si->regs[SI_STATUS_REG] |= SI_STATUS_DMA_BUSY;
|
||||
add_interrupt_event(&si->mi->r4300->cp0, SI_INT, si->dma_duration + add_random_interrupt_time(si->mi->r4300));
|
||||
}
|
||||
@@ -174,14 +172,3 @@ void si_end_of_dma_event(void* opaque)
|
||||
si->regs[SI_STATUS_REG] |= SI_STATUS_INTERRUPT;
|
||||
raise_rcp_interrupt(si->mi, MI_INTR_SI);
|
||||
}
|
||||
|
||||
void si_dynamic_dma_duration(struct si_controller* si)
|
||||
{
|
||||
/* try to keep controller polling to 1 per VI */
|
||||
if (si->pif->update_counter > 1)
|
||||
si->dma_duration += 1000;
|
||||
else if (si->pif->update_counter < 1 && si->dma_duration > 0x900)
|
||||
si->dma_duration -= 1000;
|
||||
|
||||
si->pif->update_counter = 0;
|
||||
}
|
||||
|
||||
@@ -89,6 +89,4 @@ void write_si_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask
|
||||
|
||||
void si_end_of_dma_event(void* opaque);
|
||||
|
||||
void si_dynamic_dma_duration(struct si_controller* si);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -61,7 +61,6 @@ void set_vi_vertical_interrupt(struct vi_controller* vi)
|
||||
{
|
||||
if (!get_event(&vi->mi->r4300->cp0.q, VI_INT) && (vi->regs[VI_V_INTR_REG] < vi->regs[VI_V_SYNC_REG]))
|
||||
{
|
||||
cp0_update_count(vi->mi->r4300);
|
||||
add_interrupt_event(&vi->mi->r4300->cp0, VI_INT, vi->delay);
|
||||
}
|
||||
}
|
||||
@@ -80,7 +79,7 @@ void poweron_vi(struct vi_controller* vi)
|
||||
{
|
||||
memset(vi->regs, 0, VI_REGS_COUNT*sizeof(uint32_t));
|
||||
vi->field = 0;
|
||||
vi->delay = 0;
|
||||
vi->delay = vi->mi->r4300->clock_rate / vi->expected_refresh_rate;
|
||||
vi->count_per_scanline = 0;
|
||||
}
|
||||
|
||||
@@ -94,7 +93,6 @@ void read_vi_regs(void* opaque, uint32_t address, uint32_t* value)
|
||||
{
|
||||
uint32_t* next_vi = get_event(&vi->mi->r4300->cp0.q, VI_INT);
|
||||
if (next_vi != NULL) {
|
||||
cp0_update_count(vi->mi->r4300);
|
||||
vi->regs[VI_CURRENT_REG] = (vi->delay - (*next_vi - cp0_regs[CP0_COUNT_REG])) / vi->count_per_scanline;
|
||||
|
||||
/* wrap around VI_CURRENT_REG if needed */
|
||||
@@ -140,8 +138,7 @@ void write_vi_regs(void* opaque, uint32_t address, uint32_t value, uint32_t mask
|
||||
if ((vi->regs[VI_V_SYNC_REG] & mask) != (value & mask))
|
||||
{
|
||||
masked_write(&vi->regs[VI_V_SYNC_REG], value, mask);
|
||||
vi->count_per_scanline = (vi->clock / vi->expected_refresh_rate) / (vi->regs[VI_V_SYNC_REG] + 1);
|
||||
vi->delay = (vi->regs[VI_V_SYNC_REG] + 1) * vi->count_per_scanline;
|
||||
vi->count_per_scanline = (vi->mi->r4300->clock_rate / vi->expected_refresh_rate) / (vi->regs[VI_V_SYNC_REG] + 1);
|
||||
set_vi_vertical_interrupt(vi);
|
||||
}
|
||||
return;
|
||||
@@ -165,7 +162,6 @@ void vi_vertical_interrupt_event(void* opaque)
|
||||
|
||||
/* allow main module to do things on VI event */
|
||||
new_vi();
|
||||
si_dynamic_dma_duration(vi->si);
|
||||
|
||||
/* toggle vi field if in interlaced mode */
|
||||
vi->field ^= (vi->regs[VI_STATUS_REG] >> 6) & 0x1;
|
||||
|
||||
@@ -347,8 +347,6 @@ int main_set_core_defaults(void)
|
||||
#endif
|
||||
ConfigSetDefaultBool(g_CoreConfig, "NoCompiledJump", 0, "Disable compiled jump commands in dynamic recompiler (should be set to False) ");
|
||||
ConfigSetDefaultBool(g_CoreConfig, "DisableExtraMem", 0, "Disable 4MB expansion RAM pack. May be necessary for some games");
|
||||
ConfigSetDefaultInt(g_CoreConfig, "CountPerOp", 0, "Force number of cycles per emulated instruction");
|
||||
ConfigSetDefaultInt(g_CoreConfig, "CountPerOpDenomPot", 0, "Reduce number of cycles per update by power of two when set greater than 0 (overclock)");
|
||||
ConfigSetDefaultBool(g_CoreConfig, "AutoStateSlotIncrement", 0, "Increment the save state slot after each save operation");
|
||||
ConfigSetDefaultInt(g_CoreConfig, "CurrentStateSlot", 0, "Save state slot (0-9) to use when saving/loading the emulator state");
|
||||
ConfigSetDefaultBool(g_CoreConfig, "EnableDebugger", 0, "Activate the R4300 debugger when ROM execution begins, if core was built with Debugger support");
|
||||
@@ -1474,8 +1472,6 @@ m64p_error main_run(void)
|
||||
{
|
||||
size_t i, k;
|
||||
size_t rdram_size;
|
||||
uint32_t count_per_op;
|
||||
uint32_t count_per_op_denom_pot;
|
||||
uint32_t emumode;
|
||||
uint32_t disable_extra_mem;
|
||||
int32_t si_dma_duration;
|
||||
@@ -1523,8 +1519,6 @@ m64p_error main_run(void)
|
||||
no_compiled_jump = ConfigGetParamBool(g_CoreConfig, "NoCompiledJump");
|
||||
//We disable any randomness for netplay
|
||||
randomize_interrupt = !netplay_is_init() ? ConfigGetParamBool(g_CoreConfig, "RandomizeInterrupt") : 0;
|
||||
count_per_op = ConfigGetParamInt(g_CoreConfig, "CountPerOp");
|
||||
count_per_op_denom_pot = ConfigGetParamInt(g_CoreConfig, "CountPerOpDenomPot");
|
||||
|
||||
if (ROM_SETTINGS.disableextramem)
|
||||
disable_extra_mem = ROM_SETTINGS.disableextramem;
|
||||
@@ -1534,18 +1528,14 @@ m64p_error main_run(void)
|
||||
|
||||
rdram_size = (disable_extra_mem == 0) ? 0x800000 : 0x400000;
|
||||
|
||||
if (count_per_op <= 0)
|
||||
count_per_op = ROM_SETTINGS.countperop;
|
||||
|
||||
if (count_per_op_denom_pot > 11)
|
||||
count_per_op_denom_pot = 11;
|
||||
|
||||
si_dma_duration = ConfigGetParamInt(g_CoreConfig, "SiDmaDuration");
|
||||
if (si_dma_duration < 0)
|
||||
si_dma_duration = ROM_SETTINGS.sidmaduration;
|
||||
|
||||
rsp_delay_time = ROM_SETTINGS.rspdelaytime;
|
||||
|
||||
uint32_t count_per_op; //UNUSED
|
||||
uint32_t count_per_op_denom_pot; //UNUSED
|
||||
//During netplay, player 1 is the source of truth for these settings
|
||||
netplay_sync_settings(&count_per_op, &count_per_op_denom_pot, &disable_extra_mem, &si_dma_duration, &emumode, &no_compiled_jump, &rsp_delay_time);
|
||||
|
||||
@@ -1789,8 +1779,6 @@ m64p_error main_run(void)
|
||||
init_device(&g_dev,
|
||||
g_mem_base,
|
||||
emumode,
|
||||
count_per_op,
|
||||
count_per_op_denom_pot,
|
||||
no_compiled_jump,
|
||||
randomize_interrupt,
|
||||
g_start_address,
|
||||
|
||||
@@ -46,12 +46,10 @@
|
||||
|
||||
#define CHUNKSIZE 1024*128 /* Read files 128KB at a time. */
|
||||
|
||||
/* Number of cpu cycles per instruction */
|
||||
enum { DEFAULT_COUNT_PER_OP = 2 };
|
||||
/* by default, extra mem is enabled */
|
||||
enum { DEFAULT_DISABLE_EXTRA_MEM = 0 };
|
||||
/* Default SI DMA duration */
|
||||
enum { DEFAULT_SI_DMA_DURATION = 0x900 };
|
||||
enum { DEFAULT_SI_DMA_DURATION = 0x3000 };
|
||||
/* Default AI DMA modifier */
|
||||
enum { DEFAULT_AI_DMA_MODIFIER = 100 };
|
||||
/* Default RSP delay time */
|
||||
@@ -189,7 +187,6 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size)
|
||||
ROM_SETTINGS.transferpak = entry->transferpak;
|
||||
ROM_SETTINGS.mempak = entry->mempak;
|
||||
ROM_SETTINGS.biopak = entry->biopak;
|
||||
ROM_SETTINGS.countperop = entry->countperop;
|
||||
ROM_SETTINGS.disableextramem = entry->disableextramem;
|
||||
ROM_SETTINGS.sidmaduration = entry->sidmaduration;
|
||||
ROM_SETTINGS.aidmamodifier = entry->aidmamodifier;
|
||||
@@ -208,7 +205,6 @@ m64p_error open_rom(const unsigned char* romimage, unsigned int size)
|
||||
ROM_SETTINGS.transferpak = 0;
|
||||
ROM_SETTINGS.mempak = 1;
|
||||
ROM_SETTINGS.biopak = 0;
|
||||
ROM_SETTINGS.countperop = DEFAULT_COUNT_PER_OP;
|
||||
ROM_SETTINGS.disableextramem = DEFAULT_DISABLE_EXTRA_MEM;
|
||||
ROM_SETTINGS.sidmaduration = DEFAULT_SI_DMA_DURATION;
|
||||
ROM_SETTINGS.aidmamodifier = DEFAULT_AI_DMA_MODIFIER;
|
||||
@@ -338,12 +334,6 @@ static size_t romdatabase_resolve_round(void)
|
||||
entry->entry.set_flags |= ROMDATABASE_ENTRY_RUMBLE;
|
||||
}
|
||||
|
||||
if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_COUNTEROP) &&
|
||||
isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_COUNTEROP)) {
|
||||
entry->entry.countperop = ref->countperop;
|
||||
entry->entry.set_flags |= ROMDATABASE_ENTRY_COUNTEROP;
|
||||
}
|
||||
|
||||
if (!isset_bitmask(entry->entry.set_flags, ROMDATABASE_ENTRY_CHEATS) &&
|
||||
isset_bitmask(ref->set_flags, ROMDATABASE_ENTRY_CHEATS)) {
|
||||
if (ref->cheats)
|
||||
@@ -482,7 +472,6 @@ void romdatabase_open(void)
|
||||
search->entry.savetype = SAVETYPE_EEPROM_4K;
|
||||
search->entry.players = 4;
|
||||
search->entry.rumble = 1;
|
||||
search->entry.countperop = DEFAULT_COUNT_PER_OP;
|
||||
search->entry.disableextramem = DEFAULT_DISABLE_EXTRA_MEM;
|
||||
search->entry.cheats = NULL;
|
||||
search->entry.transferpak = 0;
|
||||
@@ -598,15 +587,6 @@ void romdatabase_open(void)
|
||||
DebugMessage(M64MSG_WARNING, "ROM Database: Invalid rumble string on line %i", lineno);
|
||||
}
|
||||
}
|
||||
else if(!strcmp(l.name, "CountPerOp"))
|
||||
{
|
||||
if (string_to_int(l.value, &value) && value > 0 && value <= 4) {
|
||||
search->entry.countperop = value;
|
||||
search->entry.set_flags |= ROMDATABASE_ENTRY_COUNTEROP;
|
||||
} else {
|
||||
DebugMessage(M64MSG_WARNING, "ROM Database: Invalid CountPerOp on line %i", lineno);
|
||||
}
|
||||
}
|
||||
else if (!strcmp(l.name, "DisableExtraMem"))
|
||||
{
|
||||
search->entry.disableextramem = atoi(l.value);
|
||||
@@ -680,7 +660,7 @@ void romdatabase_open(void)
|
||||
}
|
||||
else if(!strcmp(l.name, "SiDmaDuration"))
|
||||
{
|
||||
if (string_to_int(l.value, &value) && value >= 0 && value <= 0x10000) {
|
||||
if (string_to_int(l.value, &value) && value >= 0 && value <= 0x30000) {
|
||||
search->entry.sidmaduration = value;
|
||||
search->entry.set_flags |= ROMDATABASE_ENTRY_SIDMADURATION;
|
||||
} else {
|
||||
|
||||
@@ -107,7 +107,6 @@ typedef struct
|
||||
unsigned char savetype;
|
||||
unsigned char players; /* Local players 0-4, 2/3/4 way Netplay indicated by 5/6/7. */
|
||||
unsigned char rumble; /* 0 - No, 1 - Yes boolean for rumble support. */
|
||||
unsigned char countperop;
|
||||
unsigned char disableextramem;
|
||||
unsigned char transferpak; /* 0 - No, 1 - Yes boolean for transferpak support. */
|
||||
unsigned char mempak; /* 0 - No, 1 - Yes boolean for mempak support. */
|
||||
@@ -125,7 +124,6 @@ typedef struct
|
||||
#define ROMDATABASE_ENTRY_SAVETYPE BIT(3)
|
||||
#define ROMDATABASE_ENTRY_PLAYERS BIT(4)
|
||||
#define ROMDATABASE_ENTRY_RUMBLE BIT(5)
|
||||
#define ROMDATABASE_ENTRY_COUNTEROP BIT(6)
|
||||
#define ROMDATABASE_ENTRY_CHEATS BIT(7)
|
||||
#define ROMDATABASE_ENTRY_EXTRAMEM BIT(8)
|
||||
#define ROMDATABASE_ENTRY_TRANSFERPAK BIT(9)
|
||||
|
||||
Reference in New Issue
Block a user