├── common ├── test.c ├── mdec │ ├── idct.bin │ └── quant.bin ├── common.h ├── log.h ├── delay.h ├── hexdump.h ├── twister.h ├── delay.c ├── Makefile ├── mdec-tools.h ├── stdint.h ├── io.c ├── exception.hpp ├── io.h ├── timer.h ├── hexdump.cpp ├── mdec-tools.cpp ├── dma.cpp ├── gpu.h ├── mdec.h ├── measure.hpp ├── exception.cpp ├── test.h ├── cop0.hpp └── gpu.cpp ├── cpu ├── cop │ ├── Makefile │ ├── psx.log │ └── main.cpp ├── code-in-io │ ├── Makefile │ ├── code.h │ ├── code.s │ ├── psx.log │ └── main.cpp ├── io-access-bitwidth │ ├── Makefile │ ├── asm.h │ ├── asm.s │ ├── psx.log │ └── main.cpp └── access-time │ ├── Makefile │ ├── psx.log │ └── main.cpp ├── gpu ├── quad │ ├── Makefile │ ├── vram.png │ └── main.c ├── gp0-e1 │ ├── Makefile │ ├── psx.log │ └── main.cpp ├── clipping │ ├── Makefile │ ├── vram.png │ └── main.cpp ├── mask-bit │ ├── Makefile │ ├── psx.log │ └── main.cpp ├── triangle │ ├── Makefile │ ├── vram.png │ └── main.c ├── bandwidth │ ├── Makefile │ ├── psx.log │ └── main.cpp ├── gpustat │ ├── Makefile │ └── psx.log ├── rectangles │ ├── Makefile │ ├── vram.png │ └── main.c ├── clut-cache │ ├── Makefile │ └── vram.png ├── lines │ ├── vram.png │ ├── Makefile │ └── main.c ├── transparency │ ├── Makefile │ ├── vram.png │ └── main.c ├── texture-flip │ ├── Makefile │ ├── vram.png │ └── main.c ├── texture-overflow │ ├── Makefile │ ├── cube.tim │ ├── lena.tim │ ├── vram.png │ └── main.c ├── uv-interpolation │ ├── Makefile │ ├── vram.png │ └── main.c ├── version-detect │ ├── Makefile │ └── main.cpp ├── animated-triangle │ ├── Makefile │ └── main.c ├── vram-to-vram-overlap │ ├── Makefile │ ├── vram.png │ ├── font.h │ ├── font.c │ └── main.cpp └── benchmark │ ├── screenshot.png │ ├── Makefile │ └── type_traits.hpp ├── timers └── Makefile ├── mdec ├── 4bit │ ├── Makefile │ ├── vram.png │ ├── heart.mdec │ ├── heart.png │ ├── psx.log │ ├── heart.h │ └── main.cpp ├── 8bit │ ├── Makefile │ ├── vram.png │ ├── heart.mdec │ ├── heart.png │ ├── psx.log │ ├── heart.h │ └── main.cpp ├── movie │ ├── makefile.15bit │ ├── vram-15bit.png │ ├── vram-24bit.png │ ├── makefile.24bit │ ├── Makefile │ ├── movieToMdec.sh │ └── main.cpp ├── frame │ ├── sunset.jpg │ ├── sunset.mdec │ ├── vram-15bit.png │ ├── vram-24bit.png │ ├── makefile.15bit │ ├── makefile.24bit │ ├── makefile.15bit-dma │ ├── makefile.24bit-dma │ ├── Makefile │ └── main.cpp └── step-by-step-log │ ├── Makefile │ ├── colors.mdec │ ├── symbols.png │ ├── symbols.mdec │ ├── main.cpp │ └── symbols.h ├── spu ├── test │ ├── Makefile │ └── main.c ├── stereo │ ├── Makefile │ ├── voice_1_left.vag │ ├── voice_1_right.vag │ ├── voice_2_left.vag │ ├── voice_2_right.vag │ └── main.c ├── toolbox │ ├── Makefile │ └── spu_reverb.h ├── playback │ ├── Makefile │ └── README.md ├── ram-sandbox │ └── Makefile └── memory-transfer │ ├── Makefile │ └── psx.log ├── dma ├── chopping │ ├── Makefile │ └── main.cpp ├── otc-test │ ├── Makefile │ ├── otc.h │ ├── psx.log │ └── otc.cpp ├── chain-looping │ ├── Makefile │ ├── psx.log │ └── main.cpp └── dpcr │ ├── Makefile │ └── psx.log ├── gte └── test-all │ ├── Makefile │ ├── psx.log │ ├── gte.h │ └── main.c ├── gte-fuzz ├── Makefile ├── common.h ├── gte.h ├── common.c └── gte.s ├── cdrom ├── terminal │ ├── Makefile │ ├── getline.h │ ├── cd.h │ ├── fifo.h │ ├── string.h │ ├── cd.cpp │ └── getline.cpp ├── getloc │ ├── Makefile │ └── psx.log ├── timing │ ├── Makefile │ └── psx.log ├── disc-swap │ ├── Makefile │ ├── psx.log │ └── main.cpp └── volume-regs │ ├── Makefile │ └── cd.s ├── CONTRIBUTORS.md ├── .gitignore ├── timer-dump ├── Makefile ├── timer.h └── timer.s ├── input └── pad │ ├── Makefile │ └── main.cpp ├── common-test.mk ├── tools └── diffvram │ ├── build-ci.sh │ └── main.go ├── .github └── workflows │ └── build.yml ├── LICENSE ├── Makefile ├── common.mk └── README.md /common/test.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | struct TEST __test = {0}; -------------------------------------------------------------------------------- /cpu/cop/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = cop.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/quad/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = quad.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /timers/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = timers.elf 2 | 3 | include ../common-test.mk -------------------------------------------------------------------------------- /gpu/gp0-e1/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = gp0-e1.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /mdec/4bit/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = 4bit.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /mdec/8bit/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = 8bit.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /spu/test/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = test.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /dma/chopping/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = chopping.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /dma/otc-test/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = otc-test.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/clipping/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = clipping.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/mask-bit/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = mask-bit.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/triangle/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = triangle.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gte/test-all/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = test-all.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /cpu/code-in-io/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = code-in-io.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/bandwidth/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = bandwidth.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/gpustat/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = gpustat.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /gpu/rectangles/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = rectangles.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/clut-cache/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = clut-cache.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /gpu/lines/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/lines/vram.png -------------------------------------------------------------------------------- /gpu/quad/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/quad/vram.png -------------------------------------------------------------------------------- /gpu/transparency/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = transparency.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /mdec/4bit/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/4bit/vram.png -------------------------------------------------------------------------------- /mdec/8bit/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/8bit/vram.png -------------------------------------------------------------------------------- /mdec/movie/makefile.15bit: -------------------------------------------------------------------------------- 1 | TARGET = movie-15bit.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /common/mdec/idct.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/common/mdec/idct.bin -------------------------------------------------------------------------------- /dma/chain-looping/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = chain-looping.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /gpu/texture-flip/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = texture-flip.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /gpu/texture-overflow/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = texture-overflow.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/uv-interpolation/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = uv-interpolation.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/version-detect/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = version-detect.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /gte-fuzz/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = gte-fuzz.elf 2 | LIBS += -lpsxgte 3 | 4 | include ../common-test.mk -------------------------------------------------------------------------------- /mdec/4bit/heart.mdec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/4bit/heart.mdec -------------------------------------------------------------------------------- /mdec/4bit/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/4bit/heart.png -------------------------------------------------------------------------------- /mdec/8bit/heart.mdec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/8bit/heart.mdec -------------------------------------------------------------------------------- /mdec/8bit/heart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/8bit/heart.png -------------------------------------------------------------------------------- /gpu/clipping/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/clipping/vram.png -------------------------------------------------------------------------------- /gpu/clut-cache/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/clut-cache/vram.png -------------------------------------------------------------------------------- /gpu/lines/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = lines.elf 2 | LIBS += -lpsxgte 3 | 4 | include ../../common-test.mk -------------------------------------------------------------------------------- /gpu/rectangles/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/rectangles/vram.png -------------------------------------------------------------------------------- /gpu/triangle/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/triangle/vram.png -------------------------------------------------------------------------------- /mdec/frame/sunset.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/frame/sunset.jpg -------------------------------------------------------------------------------- /mdec/frame/sunset.mdec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/frame/sunset.mdec -------------------------------------------------------------------------------- /mdec/step-by-step-log/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = step-by-step-log.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /spu/stereo/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = stereo.elf 2 | LIBS += -lpsxspu 3 | 4 | include ../../common-test.mk -------------------------------------------------------------------------------- /cpu/io-access-bitwidth/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = io-access-bitwidth.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /gpu/animated-triangle/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = animated-triangle.elf 2 | 3 | include ../../common-test.mk 4 | -------------------------------------------------------------------------------- /gpu/texture-flip/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/texture-flip/vram.png -------------------------------------------------------------------------------- /gpu/transparency/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/transparency/vram.png -------------------------------------------------------------------------------- /gpu/vram-to-vram-overlap/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = vram-to-vram-overlap.elf 2 | 3 | include ../../common-test.mk -------------------------------------------------------------------------------- /mdec/frame/vram-15bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/frame/vram-15bit.png -------------------------------------------------------------------------------- /mdec/frame/vram-24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/frame/vram-24bit.png -------------------------------------------------------------------------------- /mdec/movie/vram-15bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/movie/vram-15bit.png -------------------------------------------------------------------------------- /mdec/movie/vram-24bit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/movie/vram-24bit.png -------------------------------------------------------------------------------- /cdrom/terminal/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = terminal.elf 2 | LIBS += -lpsxcd 3 | 4 | include ../../common-test.mk 5 | -------------------------------------------------------------------------------- /cdrom/terminal/getline.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | bool isAscii(char c); 4 | bool getline(char* buf, unsigned length); -------------------------------------------------------------------------------- /dma/dpcr/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = dpcr.elf 2 | 3 | include ../../common-test.mk 4 | 5 | LIBS += -lpsxspu 6 | -------------------------------------------------------------------------------- /gpu/benchmark/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/benchmark/screenshot.png -------------------------------------------------------------------------------- /spu/stereo/voice_1_left.vag: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/spu/stereo/voice_1_left.vag -------------------------------------------------------------------------------- /spu/stereo/voice_1_right.vag: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/spu/stereo/voice_1_right.vag -------------------------------------------------------------------------------- /spu/stereo/voice_2_left.vag: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/spu/stereo/voice_2_left.vag -------------------------------------------------------------------------------- /spu/stereo/voice_2_right.vag: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/spu/stereo/voice_2_right.vag -------------------------------------------------------------------------------- /spu/toolbox/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = toolbox.elf 2 | LIBS += -lpsxspu 3 | 4 | include ../../common-test.mk 5 | -------------------------------------------------------------------------------- /cdrom/getloc/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = getloc.elf 2 | LIBS += -lpsxspu -lpsxcd 3 | 4 | include ../../common-test.mk 5 | -------------------------------------------------------------------------------- /cdrom/timing/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = timing.elf 2 | LIBS += -lpsxspu -lpsxcd 3 | 4 | include ../../common-test.mk 5 | -------------------------------------------------------------------------------- /gpu/texture-overflow/cube.tim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/texture-overflow/cube.tim -------------------------------------------------------------------------------- /gpu/texture-overflow/lena.tim: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/texture-overflow/lena.tim -------------------------------------------------------------------------------- /gpu/texture-overflow/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/texture-overflow/vram.png -------------------------------------------------------------------------------- /gpu/uv-interpolation/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/uv-interpolation/vram.png -------------------------------------------------------------------------------- /CONTRIBUTORS.md: -------------------------------------------------------------------------------- 1 | [Jakub Czekański](https://github.com/JaCzekanski) 2 | [Connor McLaughlin](https://github.com/stenzek) 3 | -------------------------------------------------------------------------------- /cdrom/disc-swap/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = disc-swap.elf 2 | LIBS += -lpsxspu -lpsxcd 3 | 4 | include ../../common-test.mk 5 | -------------------------------------------------------------------------------- /common/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | #include "gpu.h" -------------------------------------------------------------------------------- /gpu/vram-to-vram-overlap/vram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/gpu/vram-to-vram-overlap/vram.png -------------------------------------------------------------------------------- /mdec/movie/makefile.24bit: -------------------------------------------------------------------------------- 1 | TARGET = movie-24bit.elf 2 | 3 | include ../../common-test.mk 4 | 5 | CFLAGS += -DUSE_24BIT 6 | -------------------------------------------------------------------------------- /mdec/step-by-step-log/colors.mdec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/step-by-step-log/colors.mdec -------------------------------------------------------------------------------- /mdec/step-by-step-log/symbols.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/step-by-step-log/symbols.png -------------------------------------------------------------------------------- /cdrom/volume-regs/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = volume-regs.elf 2 | LIBS += -lpsxspu -lpsxcd 3 | 4 | include ../../common-test.mk 5 | -------------------------------------------------------------------------------- /mdec/frame/makefile.15bit: -------------------------------------------------------------------------------- 1 | TARGET = frame-15bit.elf 2 | 3 | include ../../common-test.mk 4 | 5 | CFLAGS += -DCOLOR_DEPTH=15 6 | -------------------------------------------------------------------------------- /mdec/frame/makefile.24bit: -------------------------------------------------------------------------------- 1 | TARGET = frame-24bit.elf 2 | 3 | include ../../common-test.mk 4 | 5 | CFLAGS += -DCOLOR_DEPTH=24 6 | -------------------------------------------------------------------------------- /mdec/step-by-step-log/symbols.mdec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JaCzekanski/ps1-tests/HEAD/mdec/step-by-step-log/symbols.mdec -------------------------------------------------------------------------------- /gpu/benchmark/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = benchmark.elf 2 | 3 | include ../../common-test.mk 4 | 5 | CFLAGS += -Wno-unused-variable 6 | -------------------------------------------------------------------------------- /gte/test-all/psx.log: -------------------------------------------------------------------------------- 1 | gte/test-all 2 | Auto test all GTE valid opcodes/registers 3 | Passed tests: 1150 4 | Failed tests: 0 5 | Done. 6 | -------------------------------------------------------------------------------- /spu/playback/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = playback.elf 2 | LIBS += -lpsxspu 3 | CPPFLAGS += -O2 -std=c++1z 4 | 5 | include ../../common-test.mk 6 | -------------------------------------------------------------------------------- /spu/ram-sandbox/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = ram-sandbox.elf 2 | LIBS += -lpsxspu 3 | CPPFLAGS += -O2 -std=c++1z 4 | 5 | include ../../common-test.mk -------------------------------------------------------------------------------- /common/mdec/quant.bin: -------------------------------------------------------------------------------- 1 | """ ""%&%##"#&&(((00..88:EES""" ""%&%##"#&&(((00..88:EES -------------------------------------------------------------------------------- /spu/memory-transfer/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = memory-transfer.elf 2 | LIBS += -lpsxspu 3 | CPPFLAGS += -O2 -std=c++1z 4 | 5 | include ../../common-test.mk -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | build/ 3 | .vscode/ 4 | .idea/ 5 | 6 | *.a 7 | *.elf 8 | *.exe 9 | *.zip 10 | 11 | *-amd64 12 | *-386 13 | -------------------------------------------------------------------------------- /mdec/frame/makefile.15bit-dma: -------------------------------------------------------------------------------- 1 | TARGET = frame-15bit-dma.elf 2 | 3 | include ../../common-test.mk 4 | 5 | CFLAGS += -DCOLOR_DEPTH=15 -DUSE_MDECOUT_DMA 6 | -------------------------------------------------------------------------------- /mdec/frame/makefile.24bit-dma: -------------------------------------------------------------------------------- 1 | TARGET = frame-24bit-dma.elf 2 | 3 | include ../../common-test.mk 4 | 5 | CFLAGS += -DCOLOR_DEPTH=24 -DUSE_MDECOUT_DMA 6 | -------------------------------------------------------------------------------- /timer-dump/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = timer-dump.elf 2 | 3 | include ../common-test.mk 4 | 5 | asm: 6 | mipsel-unknown-elf-objdump -C -S build/timer-dump.elf > dump.asm -------------------------------------------------------------------------------- /cpu/access-time/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = access-time.elf 2 | 3 | include ../../common-test.mk 4 | 5 | asm: 6 | mipsel-unknown-elf-objdump -C -S build/access-time.elf > dump.asm -------------------------------------------------------------------------------- /timer-dump/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | void DumpTimerValues(); 8 | 9 | #ifdef __cplusplus 10 | } 11 | #endif -------------------------------------------------------------------------------- /spu/playback/README.md: -------------------------------------------------------------------------------- 1 | # Playback binary SPU dump 2 | 3 | 1. Capture SPU dump using Avocado 4 | 2. Convert .bin to .h file `xxd -i spu-dump.bin` > spu-dump.h 5 | 3. `make clean && make` -------------------------------------------------------------------------------- /common/log.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define DEBUG 5 | 6 | #ifdef DEBUG 7 | #define LOG(fmt, ...) printf(fmt, ##__VA_ARGS__) 8 | #else 9 | #define LOG(fmt, ...) 10 | #endif -------------------------------------------------------------------------------- /gte/test-all/gte.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | void GTE_INIT(); 5 | uint32_t GTE_READ(uint8_t reg); 6 | void GTE_WRITE(uint8_t reg, uint32_t value); 7 | void _GTE_OP(uint32_t op); -------------------------------------------------------------------------------- /common/delay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void delay(uint32_t cycles); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | -------------------------------------------------------------------------------- /gpu/mask-bit/psx.log: -------------------------------------------------------------------------------- 1 | gpu/mask-bit 2 | pass - testWriteAndRead 3 | pass - testSetBit 4 | pass - testCheckMaskBit 5 | pass - testCheckIsMaskBitStickyManually 6 | pass - testCheckIsMaskBitStickySetBit 7 | Done. -------------------------------------------------------------------------------- /dma/otc-test/otc.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void waitForDma(DMA::Channel ch); 4 | void setupDmaOtc(uint32_t address, uint16_t wordCount, DMA::CHCR control); 5 | void dmaMasterEnable(DMA::Channel ch, bool enabled); -------------------------------------------------------------------------------- /input/pad/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = pad.elf 2 | #CFLAGS = -g -msoft-float -O2 -D__PLAYSTATION__ -fno-builtin -fdata-sections -ffunction-sections -Wall -Wextra -Wno-strict-aliasing -Wno-sign-compare 3 | 4 | include ../../common-test.mk -------------------------------------------------------------------------------- /cpu/code-in-io/code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void FlushCache(); 9 | void testCode(); 10 | 11 | #ifdef __cplusplus 12 | } 13 | #endif -------------------------------------------------------------------------------- /common/hexdump.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void hexdump(uint8_t* data, size_t length, size_t W = 16, bool ascii = false); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif -------------------------------------------------------------------------------- /cpu/code-in-io/code.s: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | .extern FlushCache 5 | FlushCache: 6 | li $t1, 0x44 7 | li $t2, 0xa0 8 | jr $t2 9 | nop 10 | 11 | .globl testCode 12 | testCode: 13 | jr $ra 14 | nop 15 | -------------------------------------------------------------------------------- /common/twister.h: -------------------------------------------------------------------------------- 1 | #include "stdint.h" 2 | 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void seedMT(uint32_t seed); 9 | uint32_t reloadMT(void); 10 | uint32_t randomMT(void); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif -------------------------------------------------------------------------------- /common/delay.c: -------------------------------------------------------------------------------- 1 | #include "delay.h" 2 | 3 | void __attribute__((optimize("O1"))) delay(uint32_t cycles) 4 | { 5 | uint32_t delay = cycles >> 2; 6 | do { 7 | __asm__ __volatile__ ("nop"); 8 | --delay; 9 | } while (delay != 0); 10 | } -------------------------------------------------------------------------------- /gpu/vram-to-vram-overlap/font.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | 7 | void FntInit(); 8 | void FntPos(int x, int y); 9 | void FntChar(char c); 10 | void FntPrintf(const char* format, ...); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif -------------------------------------------------------------------------------- /mdec/movie/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @$(MAKE) --no-print-directory -f makefile.15bit clean all 3 | @$(MAKE) --no-print-directory -f makefile.24bit clean all 4 | 5 | clean: 6 | @$(MAKE) --no-print-directory -f makefile.15bit clean 7 | @$(MAKE) --no-print-directory -f makefile.24bit clean 8 | -------------------------------------------------------------------------------- /cdrom/disc-swap/psx.log: -------------------------------------------------------------------------------- 1 | cdrom/disc-swap 2 | > Init CD 3 | psxcd: Init Ok! 4 | > CD IRQ=2, status=0x02 5 | *** Open the shell now *** 6 | > Got IRQ 5 (expected 5), status 0x01 7 | *** Close the shell now *** 8 | > Getstat: 0x12 9 | > Getstat: 0x10 10 | > Getstat: 0x00 11 | > Disc inserted? 12 | -------------------------------------------------------------------------------- /cpu/code-in-io/psx.log: -------------------------------------------------------------------------------- 1 | cpu/code-in-io 2 | Test code execution from Scratchpad and various IO ports 3 | pass - testCodeInRam 4 | pass - testCodeInScratchpad 5 | pass - testCodeInMDEC 6 | pass - testCodeInInterrupts 7 | pass - testCodeInSPU 8 | pass - testCodeInDMA0 9 | pass - testCodeInDMAControl 10 | Done. -------------------------------------------------------------------------------- /gpu/benchmark/type_traits.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | template 4 | struct is_same { 5 | static const bool value = false; 6 | }; 7 | 8 | template 9 | struct is_same { 10 | static const bool value = true; 11 | }; 12 | 13 | #define IS_SAME(x,y) is_same::value -------------------------------------------------------------------------------- /mdec/movie/movieToMdec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -e 2 | export PATH=$PATH:/Users/jakub/dev/priv/mdec-tools/cmake-build-relwithdebinfo 3 | ffmpeg -hide_banner -loglevel panic -i bad_apple.mkv -ss 2 -t 00:00:25 -vf "fps=10,scale=256:240" -pix_fmt gray %04d.png 4 | mdec-tools -q=40 --color --movie *.png bad_apple.h 5 | rm *.png 6 | -------------------------------------------------------------------------------- /cpu/io-access-bitwidth/asm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | void asm_write_32(uint32_t address, uint32_t data); 9 | void asm_write_16(uint32_t address, uint32_t data); 10 | void asm_write_8(uint32_t address, uint32_t data); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif -------------------------------------------------------------------------------- /common/Makefile: -------------------------------------------------------------------------------- 1 | include ../common.mk 2 | 3 | TARGET = libcommon.a 4 | 5 | $(TARGET): $(OFILES) 6 | @echo "AR $(TARGET)" 7 | @$(AR) cr $(TARGET) $(OFILES) 8 | @echo "RANLIB $(TARGET)" 9 | @$(RANLIB) $(TARGET) 10 | 11 | all: $(TARGET) 12 | 13 | clean: 14 | rm -Rf build $(TARGET) 15 | 16 | .PHONY: all clean 17 | .DEFAULT_GOAL := $(TARGET) -------------------------------------------------------------------------------- /spu/memory-transfer/psx.log: -------------------------------------------------------------------------------- 1 | spu/memory-transfer 2 | Test SPU memory access using DMA and regular IO. 3 | 4 | pass - testDtcRegister 5 | pass - testManualWriteToSpuRam 6 | pass - testDMAReadFromSpuRam 7 | pass - testDMAWriteToSpuRam 8 | pass - testDMAWriteTiming 9 | pass - testDMAReadTiming 10 | pass - testControlBitsAreCopiedToStatusRegister 11 | Done. -------------------------------------------------------------------------------- /mdec/frame/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | @$(MAKE) --no-print-directory -f makefile.15bit clean all 3 | @$(MAKE) --no-print-directory -f makefile.15bit-dma clean all 4 | @$(MAKE) --no-print-directory -f makefile.24bit clean all 5 | @$(MAKE) --no-print-directory -f makefile.24bit-dma clean all 6 | 7 | clean: 8 | @$(MAKE) --no-print-directory -f makefile.15bit clean 9 | -------------------------------------------------------------------------------- /common/mdec-tools.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | // Convert 8x8 monochrome 4/8bit image to 15bit native pixfmt and copy it to VRAM 9 | void copy4bitBlockToVram(uint8_t* src, int dstX, int dstY); 10 | void copy8bitBlockToVram(uint8_t* src, int dstX, int dstY); 11 | 12 | #ifdef __cplusplus 13 | } 14 | #endif 15 | -------------------------------------------------------------------------------- /gte-fuzz/common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include "stdint.h" 5 | 6 | extern unsigned short buttons, prevButtons; 7 | 8 | void init(); 9 | void display_frame(); 10 | void clearFrameBuffer(); 11 | 12 | bool BUTTON(uint16_t button); 13 | 14 | void FntPos(int x, int y); 15 | void FntChar(char c); 16 | void FntPrintf(const char* format, ...); -------------------------------------------------------------------------------- /cdrom/terminal/cd.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | void cdInit(); 5 | 6 | void cdClearParameterFifo(); 7 | void cdPushParameter(uint8_t param); 8 | void cdCommand(uint8_t cmd); 9 | uint8_t cdReadResponse(); 10 | uint8_t cdGetInt(bool ack = true); 11 | uint8_t cdReadData(); 12 | 13 | void cdWantData(bool wantData); 14 | 15 | bool cdCommandBusy(); 16 | bool cdResponseEmpty(); 17 | bool cdDataEmpty(); -------------------------------------------------------------------------------- /cpu/io-access-bitwidth/asm.s: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | .text 5 | 6 | .globl asm_write_32 7 | asm_write_32: 8 | sw $a1, 0($a0) 9 | 10 | jr $ra 11 | nop 12 | 13 | .globl asm_write_16 14 | asm_write_16: 15 | sh $a1, 0($a0) 16 | 17 | jr $ra 18 | nop 19 | 20 | .globl asm_write_8 21 | asm_write_8: 22 | sb $a1, 0($a0) 23 | 24 | jr $ra 25 | nop 26 | 27 | -------------------------------------------------------------------------------- /common/stdint.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #ifndef __cplusplus 4 | #define true 1 5 | #define false 0 6 | typedef char bool; 7 | #endif 8 | 9 | typedef signed char int8_t; 10 | typedef short int int16_t; 11 | typedef int int32_t; 12 | typedef unsigned char uint8_t; 13 | typedef unsigned short int uint16_t; 14 | typedef unsigned int uint32_t; 15 | typedef uint32_t size_t; 16 | -------------------------------------------------------------------------------- /gpu/gp0-e1/psx.log: -------------------------------------------------------------------------------- 1 | gpu/gp0-e1 2 | pass - testWriteZerosToE1 3 | pass - testWriteOnesToE1 4 | pass - testWriteOnesToE1WithTextureDisable 5 | pass - testTexturedPolygons 6 | pass - testTexturedPolygonsTextureDisable 7 | pass - testTexturedPolygonsDoesNotChangeOtherBits 8 | pass - testTextureDisableBitIsIgnoredWhenNotAllowed 9 | pass - testTextureDisableBitIsWrittenWhenAllowed 10 | pass - testUnsetAllowTextureDisablePreservesBit 11 | pass - testUnsetAllowTextureDisableClearsBitAfterWrite 12 | Done. -------------------------------------------------------------------------------- /dma/chain-looping/psx.log: -------------------------------------------------------------------------------- 1 | dma/chain-looping 2 | Tests CPU behavior with various invalid GPU linked list chains. 3 | 4 | Testing with no DMA active... 5 | Work took 16040 ticks 6 | Testing with empty but complete chain... 7 | Work took 16032 ticks, finished = true, irq = true 8 | Testing single self-referencing chain... 9 | Work took 25632 ticks, finished = false, irq = false 10 | Testing double self-referencing chain... 11 | Work took 25640 ticks, finished = false, irq = false 12 | 13 | -------------------------------------------------------------------------------- /gte/test-all/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "common.h" 5 | #include "gte.h" 6 | 7 | void runTests(); 8 | int main() { 9 | initVideo(320, 240); 10 | printf("\ngte/test-all\n"); 11 | printf("Auto test all GTE valid opcodes/registers\n"); 12 | 13 | GTE_INIT(); 14 | 15 | EnterCriticalSection(); 16 | runTests(); 17 | ExitCriticalSection(); 18 | 19 | printf("Done.\n"); 20 | 21 | while (1) { 22 | VSync(1); 23 | } 24 | 25 | return 0; 26 | } -------------------------------------------------------------------------------- /dma/otc-test/psx.log: -------------------------------------------------------------------------------- 1 | dma/otc-test (DMA Channel 6) 2 | pass - testOtcStandard 3 | pass - testOtcWontStartOnAutomaticMode 4 | pass - testOtcWontStartWithoutStartFlag 5 | pass - testOtcForward 6 | pass - testOtcFromRam 7 | pass - testOtcSyncModeBlocks 8 | pass - testOtcSyncModeLinkedList 9 | pass - testOtcSyncModeReserved 10 | pass - testOtcWhichBitsAreHardwiredToZero 11 | pass - testOtcWhichBitsAreHardwiredToOne 12 | pass - testOtcUnusedControlBitsAreAlwaysZero 13 | pass - testOtcControlBitsAfterTransfer 14 | pass - testOtcStandardWithMasterDisabled 15 | Done. -------------------------------------------------------------------------------- /dma/dpcr/psx.log: -------------------------------------------------------------------------------- 1 | dma/dpcr 2 | Tests DMA transfer behaviour with various DPCR values. 3 | 4 | pass - writeToSPURAM 5 | Testing DMA read with master enable = true, priority = 5 6 | DPCR was 0x3B3B3B33, setting to 0x3B3D3B33 7 | ... transfer complete 8 | pass - testSPUDMARead 9 | Testing DMA read with master enable = false, priority = 5 10 | DPCR was 0x3B3B3B33, setting to 0x3B353B33 11 | ... transfer timed out 12 | Testing DMA read with master enable = false, priority = 0 13 | DPCR was 0x3B3B3B33, setting to 0x3B303B33 14 | ... transfer timed out 15 | Done. 16 | 17 | -------------------------------------------------------------------------------- /cpu/cop/psx.log: -------------------------------------------------------------------------------- 1 | % cpu/cop 2 | % pass - testCop0Disabled 3 | % pass - testCop0Enabled 4 | % pass - testCop0InvalidOpcode 5 | % pass - testSwc0Disabled 6 | % pass - testSwc0Enabled 7 | % pass - testCop1Disabled 8 | % pass - testCop1Enabled 9 | % pass - testCop2Disabled 10 | % pass - testCop2Enabled 11 | % pass - testCop2InvalidOpcode 12 | % pass - testSwc2Disabled 13 | % pass - testSwc2Enabled 14 | % pass - testCop3Disabled 15 | % pass - testCop3Enabled 16 | % pass - testSwc3Disabled 17 | % pass - testSwc3Enabled 18 | % pass - testDisabledCoprocessorThrowsCoprocessorUnusable 19 | % Done. 20 | -------------------------------------------------------------------------------- /common/io.c: -------------------------------------------------------------------------------- 1 | #include "io.h" 2 | 3 | uint32_t read32(uint32_t addr) { 4 | return *((volatile const uint32_t*)addr); 5 | } 6 | 7 | uint16_t read16(uint32_t addr) { 8 | return *((volatile const uint16_t*)addr); 9 | } 10 | 11 | uint8_t read8(uint32_t addr) { 12 | return *((volatile const uint8_t*)addr); 13 | } 14 | 15 | void write32(uint32_t addr, uint32_t val) { 16 | *((volatile uint32_t*)addr) = val; 17 | } 18 | 19 | void write16(uint32_t addr, uint16_t val) { 20 | *((volatile uint16_t*)addr) = val; 21 | } 22 | 23 | void write8(uint32_t addr, uint8_t val) { 24 | *((volatile uint8_t*)addr) = val; 25 | } -------------------------------------------------------------------------------- /spu/toolbox/spu_reverb.h: -------------------------------------------------------------------------------- 1 | /* Z:\Users\jakub\dev\priv\avocado\spu_reverb.bin (2/20/2020 9:27:13 PM) 2 | StartOffset(h): 00000000, EndOffset(h): 0000003F, Length(h): 00000040 */ 3 | 4 | unsigned char spu_reverb[64] = { 5 | 0x3D, 0x03, 0x31, 0x02, 0x00, 0x7E, 0x00, 0x50, 0x00, 0xB4, 0x00, 0xB0, 6 | 0x00, 0x4C, 0x00, 0xB0, 0x00, 0x60, 0x00, 0x54, 0xD6, 0x1E, 0x31, 0x1A, 7 | 0x14, 0x1D, 0x3B, 0x18, 0xC2, 0x1B, 0xB2, 0x16, 0x32, 0x1A, 0xEF, 0x15, 8 | 0xEE, 0x15, 0x55, 0x10, 0x34, 0x13, 0x2D, 0x0F, 0xF6, 0x11, 0x5D, 0x0C, 9 | 0x56, 0x10, 0xE1, 0x0A, 0xE0, 0x0A, 0xA2, 0x07, 0x64, 0x04, 0x32, 0x02, 10 | 0x00, 0x80, 0x00, 0x80 11 | }; 12 | -------------------------------------------------------------------------------- /common/exception.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | #include "cop0.hpp" 4 | 5 | typedef void (*void_fn_ptr)(); 6 | 7 | struct Registers { 8 | uint32_t r[32]; 9 | uint32_t returnPC; 10 | uint32_t hi, lo; 11 | cop0::STATUS sr; 12 | cop0::CAUSE cause; 13 | }; 14 | 15 | struct Thread { 16 | uint32_t flags, flags2; 17 | Registers registers; 18 | uint32_t unknown[9]; 19 | }; 20 | 21 | struct Process { 22 | Thread* thread; 23 | }; 24 | 25 | Thread* getCurrentThread(); 26 | void hookUnresolvedExceptionHandler(void_fn_ptr fn); 27 | bool wasExceptionThrown(); 28 | cop0::CAUSE::Exception getExceptionType(); 29 | void exceptionHandler(); 30 | -------------------------------------------------------------------------------- /mdec/4bit/psx.log: -------------------------------------------------------------------------------- 1 | mdec/4bit (single 8x8 block decode in 4-bit mode) 2 | mdec_reset (MDEC_CTRL <- 0x80000000)... ok 3 | mdec_quantTable(addr=0x80012080, color=1)... ok 4 | mdec_idctTable(addr=0x80012100)... ok 5 | mdec_enableDma (MDEC_CTRL <- 0x60000000)... ok 6 | 8x8 block in 4bit mode: 7 | mdec_decodeDma(addr=0x80012000, lengthInBytes=0x80, colorDepth=0, outputSigned=0, setBit15=0)... ok 8 | mdec_readDecodedDma(addr=0x801ffe0c, bytes=0x20, [blockSize=0x8])... ok 9 | 0: f0 0f ff 00 10 | 4: fd ff ff 0f 11 | 8: ed ff ff 0f 12 | c: fb ff ff 0e 13 | 10: f0 ff ff 00 14 | 14: 00 ff 1f 02 15 | 18: 31 f2 30 02 16 | 1c: 41 34 33 11 17 | mdec_reset (MDEC_CTRL <- 0x80000000)... ok 18 | 19 | Done -------------------------------------------------------------------------------- /common-test.mk: -------------------------------------------------------------------------------- 1 | BASEDIR = $(dir $(lastword $(MAKEFILE_LIST))) 2 | include $(BASEDIR)/common.mk 3 | 4 | INCLUDE += -I$(realpath $(BASEDIR)/common) 5 | LIBDIRS += -L$(realpath $(BASEDIR)/common) 6 | LIBS += -lcommon -lpsxgpu -lpsxetc -lpsxsio -lpsxapi -lpsxgte -lc 7 | 8 | TARGET_EXE := $(TARGET:.elf=.exe) 9 | 10 | build/$(TARGET): $(OFILES) 11 | @echo "LD $(TARGET)" 12 | @$(LD) $(LDFLAGS) $(LIBDIRS) $(OFILES) $(LIBS) -o build/$(TARGET) 13 | 14 | $(TARGET_EXE): build/$(TARGET) 15 | @echo "ELF2X $(TARGET:.elf=.exe)" 16 | @elf2x -q build/$(TARGET) $(TARGET_EXE) 17 | 18 | all: $(TARGET_EXE) 19 | 20 | clean: 21 | rm -rf build $(TARGET) $(TARGET_EXE) 22 | 23 | .PHONY: all clean 24 | .DEFAULT_GOAL := $(TARGET_EXE) 25 | -------------------------------------------------------------------------------- /common/io.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | inline void nop(void) { 9 | __asm__ __volatile__ ("nop"); 10 | } 11 | 12 | inline void brk(void) { 13 | __asm__ __volatile__ ("break"); 14 | } 15 | 16 | inline void softRestart(void) { 17 | __asm__ volatile ("lui $t0, 0xBFC0"); 18 | __asm__ volatile ("jr $t0"); 19 | __asm__ volatile ("nop"); 20 | } 21 | 22 | uint32_t read32(uint32_t addr); 23 | uint16_t read16(uint32_t addr); 24 | uint8_t read8(uint32_t addr); 25 | void write32(uint32_t addr, uint32_t val); 26 | void write16(uint32_t addr, uint16_t val); 27 | void write8(uint32_t addr, uint8_t val); 28 | 29 | #ifdef __cplusplus 30 | } 31 | #endif 32 | -------------------------------------------------------------------------------- /common/timer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #define TIMER_BASE(t) (0x1f801100 + ((t) * 0x10)) 5 | 6 | inline uint16_t initTimer(int timer, int mode) { 7 | uint16_t prevMode = read16(TIMER_BASE(timer) + 4); 8 | write16(TIMER_BASE(timer) + 4, mode << 8); 9 | return prevMode; 10 | } 11 | 12 | inline void restoreTimer(int timer, uint16_t prevMode) { 13 | write16(TIMER_BASE(timer) + 4, prevMode); 14 | } 15 | 16 | inline uint16_t readTimer(int timer) { 17 | return read16(TIMER_BASE(timer)); 18 | } 19 | 20 | inline bool timerDidOverflow(int timer) { 21 | return (read16(TIMER_BASE(timer) + 4) & (1<<12)) != 0; 22 | } 23 | 24 | inline void resetTimer(int timer) { 25 | read16(TIMER_BASE(timer) + 4); // reset overflow flag 26 | write16(TIMER_BASE(timer), 0); 27 | } -------------------------------------------------------------------------------- /common/hexdump.cpp: -------------------------------------------------------------------------------- 1 | #include "hexdump.h" 2 | #include 3 | 4 | static bool isAscii(char c) { 5 | return c >= 32 && c <= 126; 6 | } 7 | 8 | void hexdump(uint8_t* data, size_t length, size_t W, bool ascii) { 9 | const int H = length / W; 10 | for (int y = 0; y= length) break; 14 | printf("%02x ", data[y * W + x]); 15 | } 16 | if (ascii) { 17 | printf(" "); 18 | for (int x = 0; x= length) break; 20 | char byte = data[y * W + x]; 21 | printf("%c", isAscii(byte) ? byte : '.'); 22 | } 23 | } 24 | printf("\n"); 25 | } 26 | } -------------------------------------------------------------------------------- /mdec/8bit/psx.log: -------------------------------------------------------------------------------- 1 | mdec/8bit (single 8x8 block decode in 8-bit mode) 2 | mdec_reset (MDEC_CTRL <- 0x80000000)... ok 3 | mdec_quantTable(addr=0x80012080, color=1)... ok 4 | mdec_idctTable(addr=0x80012100)... ok 5 | mdec_enableDma (MDEC_CTRL <- 0x60000000)... ok 6 | 8x8 block in 8bit mode: 7 | mdec_decodeDma(addr=0x80012000, lengthInBytes=0x80, colorDepth=1, outputSigned=0, setBit15=0)... ok 8 | mdec_readDecodedDma(addr=0x801ffdec, bytes=0x40, [blockSize=0x8])... ok 9 | 0: 00 ff ff 00 ff ff 04 00 10 | 8: c9 ec ef ed ef fc f2 00 11 | 10: d5 db fa e8 fe e8 ff 00 12 | 18: b7 f3 ec ef eb ff e3 00 13 | 20: 00 fb ff f5 f2 ff 03 00 14 | 28: 00 05 ff fc ff 08 1a 00 15 | 30: 0f 28 1e ff 05 2a 23 00 16 | 38: 10 38 40 29 32 32 16 0f 17 | mdec_reset (MDEC_CTRL <- 0x80000000)... ok 18 | 19 | Done -------------------------------------------------------------------------------- /gte-fuzz/gte.h: -------------------------------------------------------------------------------- 1 | #ifndef GTE_H 2 | #define GTE_H 3 | 4 | #include "stdint.h" 5 | 6 | union Command { 7 | struct _ { 8 | uint32_t cmd : 6; 9 | uint32_t : 4; 10 | uint32_t lm : 1; 11 | uint32_t : 2; 12 | uint32_t mvmvaTranslationVector : 2; // 0 - tr, 1 - bk, 2 - fc, 3 - none 13 | uint32_t mvmvaMultiplyVector : 2; // 0 - v0, 1 - v1, 2 - v2, 3 - ir 14 | uint32_t mvmvaMultiplyMatrix : 2; // 0 - rotation, 1 - light, 2 - color, 3 - reserved 15 | uint32_t sf : 1; 16 | uint32_t : 5; 17 | uint32_t : 7; // cop2 18 | } _; 19 | 20 | uint32_t _reg; 21 | }; 22 | 23 | uint32_t GTE_READ(uint8_t reg); 24 | void GTE_WRITE(uint8_t reg, uint32_t value); 25 | void _GTE_OP(uint32_t op); 26 | 27 | #endif -------------------------------------------------------------------------------- /tools/diffvram/build-ci.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | name="diffvram" 4 | docker_image="golang:1.12-alpine" 5 | platforms=("windows/amd64" "linux/amd64" "darwin/amd64") 6 | basedir=$(dirname "$0") 7 | 8 | pushd $basedir 9 | for platform in "${platforms[@]}" 10 | do 11 | platform_split=(${platform//\// }) 12 | export GOOS=${platform_split[0]} 13 | export GOARCH=${platform_split[1]} 14 | output_name=$name'-'$GOOS'-'$GOARCH 15 | if [ $GOOS = "windows" ]; then 16 | output_name+='.exe' 17 | fi 18 | 19 | echo Building $output_name 20 | docker run -e GOOS -e GOARCH -v $(pwd):/build -w /build golang:1.12-alpine go build -o $output_name . 21 | if [ $? -ne 0 ]; then 22 | echo 'An error has occurred! Aborting the script execution...' 23 | exit 1 24 | fi 25 | done 26 | 27 | popd 28 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | name: "Build" 8 | runs-on: ubuntu-22.10 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v2 12 | 13 | - name: Build tests 14 | run: docker run -it -v $(pwd):/build jaczekanski/psn00bsdk:latest make 15 | 16 | - name: Build tools 17 | run: ./tools/diffvram/build-ci.sh 18 | 19 | - name: Create zip 20 | run: find . \( -iname "*.md" -o -iname "*.exe" -o -iname "*.png" -o -iname "*.log" -o -iname "*-amd64" \) -print | zip tests.zip -@ 21 | 22 | - name: Build number 23 | uses: mlilback/build-number@v1 24 | with: 25 | base: 155 26 | run-id: ${GITHUB_RUN_NUMBER} 27 | 28 | - name: Release 29 | uses: softprops/action-gh-release@v1 30 | with: 31 | files: tests.zip 32 | tag_name: build-${BUILD_NUMBER} -------------------------------------------------------------------------------- /mdec/4bit/heart.h: -------------------------------------------------------------------------------- 1 | unsigned char heart_mdec[] = { 2 | 0x1e, 0x04, 0x74, 0x00, 0xbd, 0x00, 0x93, 0x03, 0x24, 0x00, 0x2b, 0x03, 3 | 0x15, 0x00, 0xf9, 0x03, 0xe9, 0x03, 0xda, 0x03, 0xee, 0x03, 0xfe, 0x03, 4 | 0x2b, 0x00, 0x3f, 0x00, 0xc0, 0x03, 0xfe, 0x03, 0xbe, 0x03, 0xfe, 0x03, 5 | 0xca, 0x03, 0xfd, 0x03, 0xf3, 0x03, 0xf3, 0x03, 0xfd, 0x03, 0x07, 0x00, 6 | 0xd7, 0x03, 0x00, 0x00, 0xe0, 0x03, 0xf5, 0x03, 0x05, 0x00, 0x02, 0x00, 7 | 0xec, 0x03, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0xfe, 0x03, 0xf7, 0x03, 8 | 0xff, 0x03, 0xf9, 0x03, 0x01, 0x00, 0xdd, 0x03, 0xd8, 0x03, 0x09, 0x00, 9 | 0x16, 0x00, 0x01, 0x00, 0x13, 0x00, 0xca, 0x03, 0x04, 0x00, 0xfa, 0x03, 10 | 0xfc, 0x03, 0xfe, 0x03, 0x00, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x06, 0x00, 11 | 0xfe, 0x03, 0xfc, 0x03, 0xf2, 0x03, 0xfa, 0x03, 0xf6, 0x03, 0x08, 0x00, 12 | 0xfa, 0x03, 0x15, 0x00, 0x01, 0x00, 0xf5, 0x03 13 | }; 14 | unsigned int heart_mdec_len = 128; 15 | -------------------------------------------------------------------------------- /mdec/8bit/heart.h: -------------------------------------------------------------------------------- 1 | unsigned char heart_mdec[] = { 2 | 0x1e, 0x04, 0x74, 0x00, 0xbd, 0x00, 0x93, 0x03, 0x24, 0x00, 0x2b, 0x03, 3 | 0x15, 0x00, 0xf9, 0x03, 0xe9, 0x03, 0xda, 0x03, 0xee, 0x03, 0xfe, 0x03, 4 | 0x2b, 0x00, 0x3f, 0x00, 0xc0, 0x03, 0xfe, 0x03, 0xbe, 0x03, 0xfe, 0x03, 5 | 0xca, 0x03, 0xfd, 0x03, 0xf3, 0x03, 0xf3, 0x03, 0xfd, 0x03, 0x07, 0x00, 6 | 0xd7, 0x03, 0x00, 0x00, 0xe0, 0x03, 0xf5, 0x03, 0x05, 0x00, 0x02, 0x00, 7 | 0xec, 0x03, 0x07, 0x00, 0x0c, 0x00, 0x08, 0x00, 0xfe, 0x03, 0xf7, 0x03, 8 | 0xff, 0x03, 0xf9, 0x03, 0x01, 0x00, 0xdd, 0x03, 0xd8, 0x03, 0x09, 0x00, 9 | 0x16, 0x00, 0x01, 0x00, 0x13, 0x00, 0xca, 0x03, 0x04, 0x00, 0xfa, 0x03, 10 | 0xfc, 0x03, 0xfe, 0x03, 0x00, 0x00, 0x09, 0x00, 0x0f, 0x00, 0x06, 0x00, 11 | 0xfe, 0x03, 0xfc, 0x03, 0xf2, 0x03, 0xfa, 0x03, 0xf6, 0x03, 0x08, 0x00, 12 | 0xfa, 0x03, 0x15, 0x00, 0x01, 0x00, 0xf5, 0x03 13 | }; 14 | unsigned int heart_mdec_len = 128; 15 | -------------------------------------------------------------------------------- /common/mdec-tools.cpp: -------------------------------------------------------------------------------- 1 | #include "mdec-tools.h" 2 | #include "gpu.h" 3 | 4 | void copy4bitBlockToVram(uint8_t* src, int dstX, int dstY) { 5 | const int W = 8, H = 8; 6 | uint16_t out[8][8]; 7 | for (int y = 0; y < H; y++) { 8 | for (int x = 0; x < W; x++) { 9 | uint8_t nibble = src[y*W/2 + x/2] >> ((x%2)*4); 10 | uint8_t p = (nibble & 0xf) << 1; 11 | out[y][x] = p | (p<<5) | (p<<10); 12 | } 13 | } 14 | vramWriteDMA(dstX, dstY, W, H, (uint16_t*)out); 15 | }; 16 | 17 | void copy8bitBlockToVram(uint8_t* src, int dstX, int dstY) { 18 | const int W = 8, H = 8; 19 | uint16_t out[8][8]; 20 | for (int y = 0; y < H; y++) { 21 | for (int x = 0; x < W; x++) { 22 | uint8_t p = src[y*W + x] >> 3; 23 | out[y][x] = p | (p<<5) | (p<<10); 24 | } 25 | } 26 | vramWriteDMA(dstX, dstY, W, H, (uint16_t*)out); 27 | }; 28 | -------------------------------------------------------------------------------- /timer-dump/timer.s: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | .text 5 | 6 | .globl DumpTimerValues 7 | DumpTimerValues: 8 | 9 | li $a0, 0x1F801100 # Read address 10 | li $a1, 0x1F800000 # Write address 11 | li $a2, 0x1F80105A # SIO_CTRL 12 | 13 | li $v0, 64 # loop count 14 | 15 | # zero # RTS on 16 | li $v1, (1<<5) # RTS off 17 | 18 | 19 | _loop: 20 | 21 | sh $zero, 0($a2) # gpio HIGH 22 | 23 | # Read 4x timer value 24 | lh $t0, 0($a0) 25 | lh $t1, 0($a0) 26 | lh $t2, 0($a0) 27 | lh $t3, 0($a0) 28 | 29 | sh $v1, 0($a2) # gpio LOW 30 | 31 | # Read 4x timer value 32 | lh $t4, 0($a0) 33 | lh $t5, 0($a0) 34 | lh $t6, 0($a0) 35 | lh $t7, 0($a0) 36 | 37 | # Save results to scratchpad 38 | sh $t0, 0($a1) 39 | sh $t1, 2($a1) 40 | sh $t2, 4($a1) 41 | sh $t3, 6($a1) 42 | sh $t4, 8($a1) 43 | sh $t5, 10($a1) 44 | sh $t6, 12($a1) 45 | sh $t7, 14($a1) 46 | 47 | addiu $a1, $a1, 16 48 | subu $v0, $v0, 1 49 | bnez $v0, _loop 50 | 51 | jr $ra 52 | nop 53 | -------------------------------------------------------------------------------- /gpu/gpustat/psx.log: -------------------------------------------------------------------------------- 1 | gpu/gpustat 2 | Bits in GPUSTAT ecription: 3 | Bit 25 - DMA Request 4 | - When DMA Direction == 0 (Off) - always 0 5 | - When DMA Direction == 1 (FIFO) - ? 6 | - When DMA Direction == 2 (CPUtoGP0) - same as Bit 28 7 | - When DMA Direction == 3 (GPUREADtoCPU) - same as Bt 27 8 | Bit 26 - Ready to receive Cmd Word 9 | Bit 27 - Ready to send VRAM to CPU 10 | Bit 28 - Ready to receive DMA Block 11 | Bits 29-30 - DMA Direction (0 - Off, 1 - FIFO, 2 - CPUtoGP0, 3 - GPUREADtoCPU) 12 | 13 | pass - testGpustat_CPU_beforeRender 14 | pass - testGpustat_CPU_dringRender 15 | pass - testGpustat_CPU_afterRender 16 | pass - testGpustat_linkedListDMA_beforeRender 17 | pass - testGpustat_LinkedListDMA_duringRender 18 | pass - testGpustat_LinkedListDA_afterRender 19 | pass - testGpustat_SyncModeDMA_DMAdirection1_beforeRender 20 | pass - testGpustat_SyncModeDMA_DMAdirection1_duringRender 21 | pass - testGpustat_SyncModeDMA_DMAdirection1_afterRender 22 | pass - testGpustat_SyncModeDMA_DMAdirection2_beforeRender 23 | pass - testGpustat_SyncModeDMA_DMAdirection2_duringRender 24 | pass - testGpustat_SyncModeDMA_DMAdirection2_afterRender 25 | Done. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Jakub Czekański 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /dma/otc-test/otc.cpp: -------------------------------------------------------------------------------- 1 | #include "otc.h" 2 | #include 3 | 4 | using namespace DMA; 5 | 6 | void waitForDma(Channel ch) { 7 | volatile CHCR* control = (CHCR*)(0x1F801088 + 0x10 * (int)ch); 8 | 9 | while ( 10 | control->startTrigger == CHCR::StartTrigger::manual && 11 | control->enabled != CHCR::Enabled::completed 12 | ); 13 | } 14 | 15 | // Separate compilation unit for these functions to prevent inlining 16 | void setupDmaOtc(uint32_t address, uint16_t wordCount, CHCR control) { 17 | MADDR addr; 18 | addr.address = address; 19 | 20 | BCR block = BCR::mode0(wordCount); 21 | 22 | waitForDma(Channel::OTC); 23 | 24 | write32(DMA::baseAddr(Channel::OTC), addr._reg); 25 | write32(DMA::blockAddr(Channel::OTC), block._reg); 26 | write32(DMA::controlAddr(Channel::OTC), control._reg); 27 | } 28 | 29 | void dmaMasterEnable(Channel ch, bool enabled) { 30 | uint32_t dmaControl = read32(CONTROL_ADDR); 31 | uint32_t mask = 0b1000 << ((int)ch * 4); 32 | if (enabled) { 33 | dmaControl |= mask; 34 | } else { 35 | dmaControl &= ~mask; 36 | } 37 | write32(CONTROL_ADDR, dmaControl); 38 | } -------------------------------------------------------------------------------- /gpu/bandwidth/psx.log: -------------------------------------------------------------------------------- 1 | gpu/bandwidth 2 | vramToCpu dT: 999.5780 ms (hblanks: 15770), speed: 60 MB/s 3 | cpuToVram dT: 772.12840 ms (hblanks: 12195), speed: 77 MB/s 4 | vramToVram dT: 1212.6640 ms (hblanks: 19132), speed: 49 MB/s 5 | FillScreen GP0(2) dT: 77.940 ms (hblanks: 1216), speed: 779 MB/s 6 | Rectangle dT: 481.12820 ms (hblanks: 7603), speed: 124 MB/s 7 | Rectangle (semitransparent) dT: 725.14500 ms (hblanks: 11455), speed: 82 MB/s 8 | Rectangle textured dT: 959.4980 ms (hblanks: 15138), speed: 62 MB/s 9 | Rectangle textured (semi) dT: 959.5980 ms (hblanks: 15139), speed: 62 MB/s 10 | Polygon quad dT: 489.10580 ms (hblanks: 7727), speed: 122 MB/s 11 | Polygon quad (semi) dT: 738.2360 ms (hblanks: 11648), speed: 81 MB/s 12 | Polygon quad textured dT: 2530.14600 ms (hblanks: 39938), speed: 23 MB/s 13 | Polygon quad textured (semi) dT: 2530.14600 ms (hblanks: 39938), speed: 23 MB/s 14 | Polygon quad (1/4 off screen) dT: 370.6400 ms (hblanks: 5845), speed: 162 MB/s 15 | Polygon quad (1/2 off screen) dT: 251.7220 ms (hblanks: 3968), speed: 239 MB/s 16 | Done -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TOPTARGETS = build clean 2 | 3 | IMAGES = common \ 4 | input/pad \ 5 | cdrom/disc-swap \ 6 | cdrom/getloc \ 7 | cdrom/timing \ 8 | cdrom/terminal \ 9 | cpu/access-time \ 10 | cpu/code-in-io \ 11 | cpu/cop \ 12 | cpu/io-access-bitwidth \ 13 | dma/chain-looping \ 14 | dma/chopping \ 15 | dma/dpcr \ 16 | dma/otc-test \ 17 | gpu/animated-triangle \ 18 | gpu/bandwidth \ 19 | gpu/benchmark \ 20 | gpu/clipping \ 21 | gpu/clut-cache \ 22 | gpu/gp0-e1 \ 23 | gpu/gpustat \ 24 | gpu/lines \ 25 | gpu/mask-bit \ 26 | gpu/quad \ 27 | gpu/rectangles \ 28 | gpu/texture-flip \ 29 | gpu/texture-overflow \ 30 | gpu/transparency \ 31 | gpu/triangle \ 32 | gpu/uv-interpolation \ 33 | gpu/vram-to-vram-overlap \ 34 | gpu/version-detect \ 35 | gte/test-all \ 36 | gte-fuzz \ 37 | mdec/4bit \ 38 | mdec/8bit \ 39 | mdec/frame \ 40 | mdec/movie \ 41 | mdec/step-by-step-log \ 42 | spu/memory-transfer \ 43 | spu/ram-sandbox \ 44 | spu/stereo \ 45 | spu/test \ 46 | spu/toolbox \ 47 | timer-dump \ 48 | timers 49 | 50 | all: $(TOPTARGETS) 51 | 52 | $(TOPTARGETS): $(IMAGES) 53 | $(IMAGES): 54 | @$(MAKE) --no-print-directory -C $@ $(MAKECMDGOALS) 55 | 56 | .PHONY: $(TOPTAGETS) $(IMAGES) 57 | -------------------------------------------------------------------------------- /cpu/access-time/psx.log: -------------------------------------------------------------------------------- 1 | cpu/access-time 2 | Test CPU access time to different parts of memory map. 3 | There are no assertions - please manually compare your results with provided psx.log. 4 | 5 | SEGMENT ( ADDRESS) 8bit 16bit 32bit (cpu cycles per bitsize) 6 | RAM (0x80000000) 5.21 5.3 5.14 7 | BIOS (0xbfc00000) 7.6 12.94 24.94 8 | SCRATCHPAD (0x1f800000) 1.5 1.1 0.94 9 | EXPANSION1 (0x1f000000) 6.94 13.7 25.7 10 | EXPANSION2 (0x1f802000) 10.99 25.99 55.98 11 | EXPANSION3 (0x1fa00000) 6.7 6.1 9.95 12 | DMAC_CTRL (0x1f8010f0) 3.8 3.8 3.1 13 | JOY_STAT (0x1f801044) 3.1 3.1 3.2 14 | SIO_STAT (0x1f801054) 3.2 3.2 2.92 15 | RAM_SIZE (0x1f801060) 3.4 3.4 3.18 16 | I_STAT (0x1f801070) 3.8 3.8 3.1 17 | TIMER0_VAL (0x1f801100) 3.1 3.1 3.2 18 | CDROM_STAT (0x1f801800) 8.0 14.0 25.93 19 | GPUSTAT (0x1f801814) 2.93 2.92 3.8 20 | MDECSTAT (0x1f801824) 3.8 3.8 3.1 21 | SPUCNT (0x1f801daa) 17.99 17.99 38.94 22 | CACHECTRL (0xfffe0130) 0.95 1.9 1.9 23 | Done. -------------------------------------------------------------------------------- /common/dma.cpp: -------------------------------------------------------------------------------- 1 | #include "dma.hpp" 2 | #include "io.h" 3 | 4 | namespace DMA { 5 | void waitForChannel(Channel ch) { 6 | volatile CHCR* control = (CHCR*)(0x1F801088 + 0x10 * (int)ch); 7 | 8 | while (control->enabled != CHCR::Enabled::completed); 9 | } 10 | 11 | void masterEnable(Channel ch, bool enabled) { 12 | uint32_t dmaControl = read32(CONTROL_ADDR); 13 | uint32_t mask = 0b1000 << ((int)ch * 4); 14 | if (enabled) { 15 | dmaControl |= mask; 16 | } else { 17 | dmaControl &= ~mask; 18 | } 19 | write32(CONTROL_ADDR, dmaControl); 20 | } 21 | 22 | void channelIRQEnable(Channel ch, bool enabled) { 23 | uint32_t dicr = read32(0x1F8010F4); 24 | if (enabled) 25 | dicr |= (1u << ((int)ch + 16)) + (1u << ((int)ch + 24)); 26 | else 27 | dicr &= ~(1u << ((int)ch + 16)); 28 | 29 | write32(0x1F8010F4, dicr); 30 | } 31 | 32 | void masterIRQEnable(bool enabled) { 33 | uint32_t dicr = read32(0x1F8010F4); 34 | if (enabled) 35 | dicr |= (1u << 23); 36 | else 37 | dicr &= ~(1u << 23); 38 | 39 | write32(0x1F8010F4, dicr); 40 | } 41 | 42 | bool channelIRQSet(Channel ch) { 43 | uint32_t dicr = read32(0x1F8010F4); 44 | return (dicr & (1u << ((int)ch + 24))) != 0u; 45 | } 46 | 47 | }; 48 | -------------------------------------------------------------------------------- /spu/test/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main() 6 | { 7 | printf("spu/test\n"); 8 | initVideo(320, 240); 9 | 10 | printf("16 bit access\n"); 11 | for (int try = 0; try < 32; try++) { 12 | for (int i = 0; i<16; i++) { 13 | uint16_t v = 1 << i; 14 | write16(0x1F801D80, v); 15 | 16 | delay(10000); 17 | 18 | uint16_t r = read16(0x1F801D80); 19 | 20 | if (v != r) { 21 | printf("0x%04x written, but read 0x%04x\n", v, r); 22 | break; 23 | } 24 | } 25 | } 26 | 27 | printf("Done\n"); 28 | 29 | printf("32 bit access\n"); 30 | for (int try = 0; try < 32; try++) { 31 | for (int i = 0; i<32; i++) { 32 | uint32_t v = 1 << i; 33 | write32(0x1F801D80, v); 34 | 35 | delay(10000); 36 | 37 | uint32_t r = read32(0x1F801D80); 38 | 39 | if (v != r) { 40 | printf("0x%08x written, but read 0x%08x\n", v, r); 41 | break; 42 | } 43 | } 44 | } 45 | 46 | printf("\n\nDone, crashing now...\n"); 47 | __asm__ volatile (".word 0xFC000000"); // Invalid opcode (63) 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /gpu/version-detect/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() { 5 | initVideo(320, 240); 6 | printf("gpu/version-detect\n"); 7 | 8 | // GPU version detection based on nocash documentation. 9 | volatile uint32_t* GP0 = (volatile uint32_t*)0x1F801810; 10 | volatile uint32_t* GP1 = (volatile uint32_t*)0x1F801814; 11 | volatile uint32_t* GPUREAD = (volatile uint32_t*)0x1F801810; 12 | volatile uint32_t* GPUSTAT = (volatile uint32_t*)0x1F801814; 13 | 14 | *GP1 = 0x10000004; 15 | *GP1 = 0x10000007; 16 | 17 | uint32_t res1 = *GPUREAD; 18 | printf("> GPUREAD = 0x%08X\n", res1); 19 | 20 | if ((res1 & 0x00FFFFFF) == 2) { 21 | printf("* GPU version 2 [New 208pin GPU (LATE-PU-8 and up)]\n"); 22 | } else { 23 | *GP0 = (*GPUSTAT & 0x3FFF) | 0xE1001000; 24 | uint32_t dummy = *GPUREAD; 25 | uint32_t res2 = *GPUSTAT; 26 | printf("> dummy=0x%08X, res2=0x%08X\n", dummy, res2); 27 | if (res2 & 0x00001000) 28 | printf("* GPU version 1 [unknown GPU type, maybe some custom arcade/prototype version ?]\n"); 29 | else 30 | printf("* GPU version 0 [Old 160pin GPU (EARLY-PU-8)]\n"); 31 | } 32 | 33 | for (;;) { 34 | VSync(0); 35 | } 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /common/gpu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | #include 4 | 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | typedef struct CPU2VRAM { 10 | unsigned int tag; 11 | unsigned char p0,p1,p2,code; 12 | unsigned short x0,y0; 13 | unsigned short w,h; 14 | unsigned int data; // Single pixel 15 | } CPU2VRAM; 16 | 17 | typedef struct VRAM2CPU { 18 | unsigned int tag; 19 | unsigned char p0,p1,p2,code; 20 | unsigned short x0,y0; 21 | unsigned short w,h; 22 | } VRAM2CPU; 23 | 24 | void initVideo(int width, int height); 25 | void fillRect(int x, int y, int w, int h, int r, int g, int b); 26 | void clearScreenColor(uint8_t r, uint8_t g, uint8_t b); 27 | void clearScreen(); 28 | 29 | void setMaskBitSetting(bool setBit, bool checkBit); 30 | void gpuNop(); 31 | uint32_t ReadGPUstat(); 32 | void writeGP0(uint8_t cmd, uint32_t value); 33 | void writeGP1(uint8_t cmd, uint32_t data); 34 | 35 | uint32_t readGPU(); 36 | void vramPut(int x, int y, uint16_t pixel); 37 | uint32_t vramGet(int x, int y); 38 | void vramReadDMA(int x, int y, int w, int h, uint16_t* ptr); 39 | void vramWrite(int x, int y, int w, int h, uint16_t* ptr); 40 | void vramWriteDMA(int x, int y, int w, int h, uint16_t* ptr); 41 | void vramToVramCopy(int srcX, int srcY, int dstX, int dstY, int w, int h); 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif -------------------------------------------------------------------------------- /gpu/texture-overflow/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lena.h" 3 | #include "cube.h" 4 | 5 | #define SCR_W 320 6 | #define SCR_H 240 7 | 8 | void setTexPage(int x, int y) { 9 | DR_TPAGE e; 10 | unsigned short texpage = getTPage(/* 15bit */ 2, /* semi-transparency mode */ 0, /*x*/x, /*y*/y); 11 | setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ 0, texpage); 12 | DrawPrim(&e); 13 | } 14 | 15 | int main() { 16 | initVideo(SCR_W, SCR_H); 17 | printf("\ngpu/texture-overflow\n"); 18 | 19 | clearScreenColor(0xff, 0x00, 0x00); 20 | 21 | TIM_IMAGE tim; 22 | GetTimInfo((unsigned int*)lena_tim, &tim); 23 | LoadImage(tim.prect, tim.paddr); 24 | 25 | GetTimInfo((unsigned int*)cube_tim, &tim); 26 | LoadImage(tim.prect, tim.paddr); 27 | 28 | for (;;) { 29 | fillRect(0, 0, SCR_W, SCR_H, 0xff, 0xff, 0xff); 30 | 31 | setTexPage(896, 256); 32 | 33 | SPRT s; 34 | setSprt(&s); 35 | setSemiTrans(&s, 0); 36 | setRGB0(&s, 128, 128, 128 ); 37 | s.x0 = 16; 38 | s.y0 = 16; 39 | s.w = 256; 40 | s.h = 128; 41 | s.u0 = 0; 42 | s.v0 = 0; 43 | 44 | DrawPrim(&s); 45 | 46 | VSync(0); 47 | } 48 | return 0; 49 | } 50 | -------------------------------------------------------------------------------- /common/mdec.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | #define MDEC_BASE 0x1f801820 9 | #define MDEC_CMD (MDEC_BASE + 0) 10 | #define MDEC_DATA (MDEC_BASE + 0) 11 | #define MDEC_CTRL (MDEC_BASE + 4) 12 | #define MDEC_STATUS (MDEC_BASE + 4) 13 | 14 | enum ColorDepth { bit_4 = 0, bit_8 = 1, bit_24 = 2, bit_15 = 3 }; 15 | 16 | extern int16_t idct[64]; 17 | extern uint8_t quant[128]; 18 | 19 | // Low level functions 20 | void mdec_reset(); 21 | void mdec_enableDma(); 22 | bool mdec_dataOutFifoEmpty(); 23 | bool mdec_dataInFifoFull(); 24 | bool mdec_cmdFifoFull(); 25 | bool mdec_cmdBusy(); 26 | void mdec_cmd(uint32_t cmd); 27 | void mdec_ctrl(uint32_t ctrl); 28 | uint32_t mdec_read(); 29 | void mdec_quantTable(const uint8_t* table, bool color); 30 | void mdec_idctTable(const int16_t* table); 31 | void mdec_decode(const uint16_t* data, size_t length, enum ColorDepth colorDepth, bool outputSigned, bool setBit15); 32 | void mdec_decodeDma(const uint16_t* data, size_t length, enum ColorDepth colorDepth, bool outputSigned, bool setBit15); 33 | void mdec_readDecoded(uint32_t* data, size_t wordCount); 34 | void mdec_readDecodedDma(uint32_t* data, size_t wordCount); 35 | 36 | size_t getPadMdecFrameLen(size_t size, size_t pad = 0x20 * 4); 37 | uint8_t* padMdecFrame(uint8_t* buf, size_t size); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | -------------------------------------------------------------------------------- /common/measure.hpp: -------------------------------------------------------------------------------- 1 | #include "timer.h" 2 | #include 3 | 4 | enum class MeasureMethod { 5 | CpuClock, 6 | CpuClock8, 7 | HBlank 8 | }; 9 | 10 | // CpuClock - measure in cpu cycles 11 | // CpuClock8 - measure in cpu cycles, granularity is 8 cycles 12 | // HBlank - measure in hblanks 13 | template 14 | uint32_t measure(void (*func)()) { 15 | int TIMER; 16 | if constexpr (method == MeasureMethod::CpuClock) TIMER = 2; 17 | else if constexpr (method == MeasureMethod::CpuClock8) TIMER = 2; 18 | else if constexpr (method == MeasureMethod::HBlank) TIMER = 1; 19 | 20 | int CLOCK_SRC; 21 | if constexpr (method == MeasureMethod::CpuClock) CLOCK_SRC = 0; 22 | else if constexpr (method == MeasureMethod::CpuClock8) CLOCK_SRC = 2; 23 | else if constexpr (method == MeasureMethod::HBlank) CLOCK_SRC = 1; 24 | 25 | EnterCriticalSection(); 26 | uint16_t prevMode = initTimer(TIMER, CLOCK_SRC); 27 | uint32_t timerValue = 0; 28 | 29 | { 30 | resetTimer(TIMER); 31 | 32 | func(); 33 | 34 | timerValue = readTimer(TIMER); 35 | if (timerDidOverflow(TIMER)) timerValue += 0xffff; 36 | } 37 | 38 | restoreTimer(TIMER, prevMode); 39 | ExitCriticalSection(); 40 | 41 | if constexpr (method == MeasureMethod::CpuClock8) timerValue *= 8; 42 | return timerValue; 43 | } -------------------------------------------------------------------------------- /common.mk: -------------------------------------------------------------------------------- 1 | PSN00BSDK ?= /opt/psn00bsdk/ 2 | PREFIX = mipsel-unknown-elf- 3 | INCLUDE := -I$(realpath $(PSN00BSDK)/libpsn00b/include) 4 | LIBDIRS := -L$(realpath $(PSN00BSDK)/libpsn00b) 5 | GCC_VERSION = 7.4.0 6 | GCC_BASE = /usr/local/mipsel-unknown-elf 7 | 8 | CFLAGS ?= -g -msoft-float -O3 -D__PLAYSTATION__ -fno-builtin -fdata-sections -ffunction-sections -Wall -Wextra -Wno-strict-aliasing -Wno-sign-compare 9 | CPPFLAGS ?= $(CFLAGS) -fno-exceptions -std=c++1z 10 | AFLAGS ?= -g -msoft-float 11 | LDFLAGS ?= -g -Ttext=0x80010000 -gc-sections -T $(GCC_BASE)/mipsel-unknown-elf/lib/ldscripts/elf32elmip.x 12 | 13 | # Toolchain programs 14 | CC = $(PREFIX)gcc 15 | CXX = $(PREFIX)g++ 16 | AS = $(PREFIX)as 17 | AR = $(PREFIX)ar 18 | LD = $(PREFIX)ld 19 | RANLIB = $(PREFIX)ranlib 20 | OBJCOPY = $(PREFIX)objcopy 21 | 22 | LIBS ?= 23 | 24 | CFILES = $(notdir $(wildcard *.c)) 25 | CPPFILES = $(notdir $(wildcard *.cpp)) 26 | AFILES = $(notdir $(wildcard *.s)) 27 | OFILES += $(addprefix build/,$(CFILES:.c=.o) $(CPPFILES:.cpp=.o) $(AFILES:.s=.o)) 28 | 29 | build/%.o: %.c 30 | @mkdir -p $(dir $@) 31 | @echo "CC $<" 32 | @$(CC) $(CFLAGS) $(INCLUDE) -c $< -o $@ 33 | 34 | build/%.o: %.cpp 35 | @mkdir -p $(dir $@) 36 | @echo "CXX $<" 37 | @$(CXX) $(CPPFLAGS) $(INCLUDE) -c $< -o $@ 38 | 39 | build/%.o: %.s 40 | @mkdir -p $(dir $@) 41 | @echo "AS $<" 42 | @$(AS) $(AFLAGS) $(INCLUDE) $< -o $@ 43 | -------------------------------------------------------------------------------- /mdec/4bit/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "heart.h" 12 | 13 | int main() { 14 | initVideo(320, 240); 15 | printf("\nmdec/4bit (single 8x8 block decode in 4-bit mode)\n"); 16 | clearScreen(); 17 | 18 | mdec_reset(); 19 | mdec_quantTable(quant, true); 20 | mdec_idctTable(idct); 21 | mdec_enableDma(); 22 | 23 | printf("8x8 block in 4bit mode:\n"); 24 | mdec_decodeDma((uint16_t*)heart_mdec, heart_mdec_len, ColorDepth::bit_4, false, false); 25 | 26 | const int W = 4, H = 8; 27 | uint8_t buffer[H][W]; 28 | mdec_readDecodedDma((uint32_t*)buffer, W*H); 29 | 30 | hexdump((uint8_t*)buffer, sizeof(buffer), W); 31 | copy4bitBlockToVram((uint8_t*)buffer, 32, 32); 32 | 33 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECin, 0); 34 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECout, 0); 35 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU, 0); 36 | DMA::masterEnable(DMA::Channel::MDECout, false); 37 | DMA::masterEnable(DMA::Channel::MDECin, false); 38 | DMA::masterEnable(DMA::Channel::GPU, false); 39 | 40 | mdec_reset(); 41 | printf("\nDone\n"); 42 | for (;;) { 43 | VSync(0); 44 | } 45 | return 0; 46 | } -------------------------------------------------------------------------------- /gpu/vram-to-vram-overlap/font.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | const int fontPosX = 960; 6 | const int fontPosY = 0; 7 | 8 | int fontCharX = 0; 9 | int fontCharY = 0; 10 | 11 | // TODO: refactor font handling to use SDK functions 12 | void FntInit() { 13 | FntLoad(fontPosX, fontPosY); 14 | } 15 | 16 | void FntPos(int x, int y) { 17 | fontCharX = x; 18 | fontCharY = y; 19 | } 20 | 21 | void FntChar(char c) { 22 | if (c == '\n') { 23 | fontCharX = 0; 24 | fontCharY += 8; 25 | return; 26 | } 27 | if (c >= ' ') { 28 | DR_TPAGE e; 29 | unsigned short texpage = getTPage(/* bits */ 0, /* semi transparency */ 0, fontPosX, fontPosY); 30 | setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ 1, texpage); 31 | DrawPrim(&e); 32 | 33 | if (c >= 96) { 34 | c &= ~(1<<5); // To lower 35 | } 36 | char pos = c - 33; 37 | int u = pos%16; 38 | int v = pos/16; 39 | 40 | SPRT_8 t; 41 | setSprt8(&t); 42 | setXY0(&t, fontCharX, fontCharY); 43 | setUV0(&t, u*8, v*8); 44 | setClut(&t, fontPosX, 32); 45 | setRGB0(&t, 255, 255, 255); 46 | 47 | DrawPrim(&t); 48 | } 49 | 50 | fontCharX += 8; 51 | if (fontCharX > 1024) { 52 | fontCharX = 0; 53 | fontCharY += 8; 54 | } 55 | } 56 | 57 | void FntPrintf(const char* format, ...) { 58 | char buffer[256]; 59 | va_list args; 60 | va_start(args, format); 61 | vsprintf(buffer, format, args); 62 | 63 | int len = strlen(buffer); 64 | for (int i = 0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "heart.h" 12 | 13 | int main() { 14 | initVideo(320, 240); 15 | printf("\nmdec/8bit (single 8x8 block decode in 8-bit mode)\n"); 16 | clearScreen(); 17 | 18 | mdec_reset(); 19 | mdec_quantTable(quant, true); 20 | mdec_idctTable(idct); 21 | mdec_enableDma(); 22 | 23 | printf("8x8 block in 8bit mode:\n"); 24 | 25 | // setBit15 - doesn't affect 8bit mode 26 | // outputSigned - does affect 8bit 27 | mdec_decodeDma((uint16_t*)heart_mdec, heart_mdec_len, ColorDepth::bit_8, false, false); 28 | 29 | const int W = 8, H = 8; 30 | uint8_t buffer[H][W]; 31 | mdec_readDecodedDma((uint32_t*)buffer, W*H); 32 | 33 | hexdump((uint8_t*)buffer, sizeof(buffer), 8); 34 | 35 | copy8bitBlockToVram((uint8_t*) buffer, 32, 32); 36 | 37 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECin, 0); 38 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECout, 0); 39 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU, 0); 40 | DMA::masterEnable(DMA::Channel::MDECout, false); 41 | DMA::masterEnable(DMA::Channel::MDECin, false); 42 | DMA::masterEnable(DMA::Channel::GPU, false); 43 | 44 | mdec_reset(); 45 | printf("\nDone\n"); 46 | for (;;) { 47 | VSync(0); 48 | } 49 | return 0; 50 | } -------------------------------------------------------------------------------- /gpu/triangle/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define SCR_W 320 7 | #define SCR_H 240 8 | 9 | #define SQRT3_2 0.866025f 10 | 11 | void drawTriangle(int cx, int cy, int a) 12 | { 13 | float h = a * SQRT3_2; 14 | 15 | int x[3], y[3]; 16 | x[0] = cx - a / 2; y[0] = cy + h / 2; 17 | x[1] = cx + a / 2; y[1] = cy + h / 2; 18 | x[2] = cx; y[2] = cy - h / 2; 19 | 20 | POLY_G3 p; 21 | setPolyG3(&p); 22 | setRGB0(&p, 255, 0, 0); 23 | setRGB1(&p, 0, 255, 0); 24 | setRGB2(&p, 0, 0, 255); 25 | setXY3(&p, 26 | x[0], y[0], 27 | x[1], y[1], 28 | x[2], y[2] 29 | ); 30 | DrawPrim(&p); 31 | } 32 | 33 | void setDithering(int dithering) 34 | { 35 | DR_TPAGE e; 36 | unsigned short texpage = getTPage(/* bitcount - do not care */0, /* semi-transparency mode */ 0, /*x*/0, /*y*/0); 37 | setDrawTPage(&e, /* Drawing to display area */ 1, dithering, texpage); 38 | DrawPrim(&e); 39 | } 40 | 41 | int main() 42 | { 43 | initVideo(SCR_W, SCR_H); 44 | printf("\ngpu/triangle (shading test)\n"); 45 | 46 | for (;;) 47 | { 48 | clearScreenColor(0xff, 0xff, 0xff); 49 | 50 | setDithering(0); 51 | drawTriangle(SCR_W/2, SCR_H/2, 240); 52 | drawTriangle(768, 256, 500); 53 | 54 | setDithering(1); 55 | drawTriangle(SCR_W/2, SCR_H + SCR_H/2, 240); 56 | 57 | VSync(0); 58 | } 59 | return 0; 60 | } 61 | -------------------------------------------------------------------------------- /cdrom/disc-swap/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | // Basic test to determine behavior of CD-ROM controller when the lid is opened. 10 | 11 | void wait_for_disc() { 12 | unsigned char last_result = 0xFF; 13 | bool first = true; 14 | for (;;) 15 | { 16 | unsigned char result[4] = {}; 17 | if (!CdControl(CdlNop, nullptr, result)) 18 | continue; 19 | 20 | if (result[0] != last_result || first) { 21 | printf("> Getstat: 0x%02X\n", result[0]); 22 | last_result = result[0]; 23 | first = false; 24 | } 25 | 26 | if (!(last_result & 0x10)) 27 | break; 28 | } 29 | } 30 | 31 | int main() { 32 | initVideo(320, 240); 33 | printf("\ncdrom/disc-swap\n"); 34 | clearScreen(); 35 | 36 | for (;;) { 37 | printf("> Init CD\n"); 38 | CdInit(); 39 | 40 | unsigned char status; 41 | int irq = CdSync(1, &status); 42 | printf("> CD IRQ=%d, status=0x%02X\n", irq, status); 43 | 44 | if (status & 0x10) { 45 | printf("> Waiting for disc to be inserted...\n"); 46 | wait_for_disc(); 47 | } 48 | 49 | printf("*** Open the shell now ***\n"); 50 | 51 | int last_irq = irq; 52 | while (last_irq == irq) 53 | irq = CdSync(1, &status); 54 | printf("> Got IRQ %d (expected 5), status 0x%02X\n", irq, status); 55 | 56 | printf("*** Close the shell now ***\n"); 57 | wait_for_disc(); 58 | printf("> Disc detected\n"); 59 | } 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /cdrom/terminal/fifo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | template 5 | class fifo { 6 | // Elements are added to the back and are read from the front 7 | T data[length] = {}; 8 | size_t write_ptr = 0; 9 | size_t read_ptr = 0; 10 | bool full = false; 11 | 12 | public: 13 | size_t size() const { 14 | if (write_ptr >= read_ptr) { 15 | return write_ptr - read_ptr; 16 | } else { 17 | return length + write_ptr - read_ptr; 18 | } 19 | } 20 | 21 | bool is_empty() const { return write_ptr == read_ptr && !full; } 22 | 23 | bool is_full() const { return full; } 24 | 25 | void clear() { 26 | write_ptr = 0; 27 | read_ptr = 0; 28 | full = false; 29 | } 30 | 31 | bool add(const T t) { 32 | if (is_full()) { 33 | return false; 34 | } 35 | 36 | data[write_ptr] = t; 37 | write_ptr = (write_ptr + 1) % length; 38 | 39 | full = write_ptr == read_ptr; 40 | 41 | return true; 42 | } 43 | 44 | T get() { 45 | if (is_empty()) { 46 | return 0; 47 | } 48 | 49 | T t = data[read_ptr]; 50 | read_ptr = (read_ptr + 1) % length; 51 | 52 | full = false; 53 | 54 | return t; 55 | } 56 | 57 | T peek(const size_t ptr = 0) const { 58 | if (ptr >= size()) { 59 | return 0; 60 | } 61 | 62 | return data[(read_ptr + ptr) % length]; 63 | } 64 | 65 | T operator[](size_t ptr) const { return peek(ptr); } 66 | }; -------------------------------------------------------------------------------- /cdrom/getloc/psx.log: -------------------------------------------------------------------------------- 1 | cdrom/header-valid-bit 2 | > Initializing CD-ROM controller... 3 | psxcd: Init Ok! 4 | > Testing state of reading after initial reset 5 | > GetStat -> 0x02 6 | > Testing Getloc after initial reset 7 | > GetlocL failed, IRQ = 5, status = 0x02 8 | > GetlocP succeeded - track 01 index 00 [00:00:06] absolute [00:01:68] 9 | > Testing seek... 10 | > Seeking to [00:02:16] (logical) 11 | > Seek result irq=2, status=0x02 12 | > GetStat -> 0x02 13 | > Testing Getloc after seek 14 | > GetlocL succeeded - [00:02:16] mode 2 15 | > GetlocP succeeded - track 01 index 01 [00:00:11] absolute [00:02:11] 16 | > Testing read 17 | > GetStat -> 0x42 18 | > Waiting for read to complete 19 | > GetStat -> 0x02 20 | > Testing GetLoc after reading 21 | > GetlocL succeeded - [40:00:13] mode 2 22 | > GetlocP succeeded - track 01 index 01 [39:58:16] absolute [40:00:16] 23 | > Testing bits after reset 24 | psxcd: Init Ok! 25 | > GetStat -> 0x02 26 | > Testing Getloc after reset 27 | > GetlocL succeeded - [00:01:72] mode 2 28 | > GetlocP succeeded - track 01 index 00 [00:00:07] absolute [00:01:67] 29 | > Testing Getloc after seek to start 30 | > Seeking to [00:00:30] (logical) 31 | > Seek result irq=2, status=0x02 32 | > GetlocL succeeded - [00:00:29] mode 2 33 | > GetlocP succeeded - track 01 index 00 [00:01:41] absolute [00:00:33] 34 | > Testing Getloc after seek to end 35 | > Seeking to [74:00:00] (logical) 36 | > Seek result irq=2, status=0x02 37 | > GetlocL succeeded - [73:59:74] mode 2 38 | > GetlocP succeeded - track aa index 01 [03:34:62] absolute [74:00:03] 39 | > Seeking to [74:30:00] (logical) 40 | > Seek result irq=5, status=0x04 41 | * Seek failed, irq=5, status=0x04 42 | > GetlocL failed, IRQ = 5, status = 0x04 43 | > GetlocP failed, IRQ = 5, status = 0x04 44 | 45 | Test passed 46 | 47 | -------------------------------------------------------------------------------- /gpu/transparency/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define SCR_W 320 4 | #define SCR_H 240 5 | 6 | void setSemiTransparencyMode(int mode) { 7 | DR_TPAGE e; 8 | unsigned short texpage = getTPage(/* bitcount - do not card */0, /* semi-transparency mode */ mode, /*x*/0, /*y*/0); 9 | setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ 0, texpage); 10 | DrawPrim(&e); 11 | } 12 | 13 | const unsigned char bgColors[4] = { 14 | 0, 64, 128, 255, 15 | }; 16 | 17 | int main() { 18 | initVideo(SCR_W, SCR_H); 19 | printf("\ngpu/transparency\n"); 20 | 21 | clearScreen(); 22 | 23 | for (;;) { 24 | // Fill screen with 4 strips of different shade 25 | for (int i = 0; i<4; i++) { 26 | fillRect(SCR_W/4 * i, 0, SCR_W/4, SCR_H, bgColors[i], bgColors[i], bgColors[i]); 27 | } 28 | 29 | // For every semi-transparency (blending) mode 30 | for (int mode = 0; mode <= 3; mode++) { 31 | setSemiTransparencyMode(mode); 32 | 33 | // Draw semi transparent rectangles with different colors 34 | for (int x = 0; x < 8 * 4; x++) { 35 | const int S = 8; 36 | 37 | int r = 128 * ((x>>0)&1); 38 | int g = 128 * ((x>>1)&1); 39 | int b = 128 * ((x>>2)&1); 40 | int y = mode; 41 | 42 | TILE t; 43 | setTile(&t); 44 | setSemiTrans(&t, 1); 45 | setRGB0(&t, r, g, b); 46 | setXY0(&t, 1 + (S+2) * x, 64 + (S+16) * y); 47 | setWH(&t, S, S); 48 | 49 | DrawPrim(&t); 50 | } 51 | } 52 | 53 | VSync(0); 54 | } 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /cdrom/terminal/string.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | extern "C" char *strndup(const char *str, int len); 5 | extern "C" int sscanf(const char *str, const char *fmt, ...); 6 | extern "C" int tolower(int chr); 7 | 8 | struct string { 9 | int len; 10 | char* s; 11 | 12 | string(const char* _s, int _len = -1) { 13 | len = ((_len == -1) ? strlen(_s) : _len); 14 | if (len != 0) { 15 | s = strndup(_s, len); 16 | } else { 17 | s = ""; 18 | } 19 | } 20 | 21 | string(const string& b) { 22 | string(b.s); 23 | } 24 | 25 | string() { 26 | string(""); 27 | } 28 | 29 | ~string() { 30 | if (len != 0) { 31 | free(s); 32 | } 33 | } 34 | 35 | string& operator=(const string& b) { 36 | if (this == &b) return *this; 37 | 38 | len = b.len; 39 | s = strndup(b.s, len); 40 | return *this; 41 | } 42 | 43 | bool equalsIgnoreCase(const char* b) { 44 | if (strlen(b) != len) return false; 45 | for (int i = 0;i 2 && s[0] == '0' && s[1] == 'x') { 66 | if (sscanf(s + 2, "%x", &result) <= 0) return -1; 67 | return result; 68 | } else { 69 | for (int i = 0; i= '0' && s[i]<='9')) return -1; 71 | } 72 | return atoi(s); 73 | } 74 | } 75 | }; -------------------------------------------------------------------------------- /spu/stereo/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "voice_1_left.h" 7 | #include "voice_1_right.h" 8 | #include "voice_2_left.h" 9 | #include "voice_2_right.h" 10 | 11 | uint32_t spuAddress = 0x1000; 12 | 13 | uint32_t uploadToSpuRam(unsigned char buf[], unsigned size) { 14 | uint32_t ptr = spuAddress; 15 | spuAddress += size; 16 | 17 | SpuSetTransferStartAddr(ptr); 18 | 19 | int dataOffset = 64; 20 | SpuWrite(buf+dataOffset, size - dataOffset); 21 | SpuWait(); 22 | 23 | printf("[SPU] Upload %d bytes to SPU RAM (sample at 0x%x)\n", size, ptr); 24 | 25 | return ptr; 26 | } 27 | 28 | void play(uint32_t ptr, int voice, uint16_t leftVolume, uint16_t rightVolume) { 29 | SpuVoiceRaw v; 30 | v.vol.left = leftVolume; 31 | v.vol.right = rightVolume; 32 | v.freq = 22050/10; 33 | v.addr = ptr/8; 34 | v.adsr_param = 0; 35 | 36 | printf("Voice %d (L: 0x%04x, R: 0x%04x)\n", voice + 1, leftVolume, rightVolume); 37 | SpuSetVoiceRaw(voice, &v); 38 | SpuSetKey(1, SPU_KEYCH(voice)); 39 | } 40 | 41 | void delay(int frames) { 42 | for (int i = 0; i 2 | #include 3 | 4 | #define SCR_W 320 5 | #define SCR_H 240 6 | 7 | void setE1(int transparencyMode, int dithering) { 8 | DR_TPAGE e; 9 | unsigned short texpage = getTPage(/* bitcount - do not care */0, /* semi-transparency mode */ transparencyMode, /*x*/0, /*y*/0); 10 | setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ dithering, texpage); 11 | DrawPrim(&e); 12 | } 13 | 14 | 15 | const uint16_t u = 512; 16 | const uint16_t v = 0; 17 | 18 | void interpolateUv(int X, int Y) { 19 | for (int i = 0; i<256; i++) { 20 | int x = X; 21 | int y = Y+i; 22 | int w = i; 23 | 24 | POLY_FT4 p; 25 | setPolyFT4(&p); 26 | setRGB0(&p, 0x80, 0x80, 0x80); 27 | setXY4(&p, 28 | x, y, 29 | x+w, y, 30 | x, y+1, 31 | x+w, y+1 32 | ); 33 | setUV4(&p, 34 | u, v, 35 | u+1, v, 36 | u, v, 37 | u+1, v 38 | ); 39 | setTPage(&p, /* 15bit */ 2, /* b/2+f/2 */ 0, u, v); 40 | DrawPrim(&p); 41 | } 42 | } 43 | void interpolateColor(int X, int Y) { 44 | for (int i = 0; i<256; i++) { 45 | int x = X; 46 | int y = Y + i; 47 | int w = i; 48 | 49 | POLY_G4 p; 50 | setPolyG4(&p); 51 | setRGB0(&p, 0xff, 0x00, 0x00); 52 | setRGB1(&p, 0x00, 0xff, 0x00); 53 | setRGB2(&p, 0xff, 0x00, 0x00); 54 | setRGB3(&p, 0x00, 0xff, 0x00); 55 | setXY4(&p, 56 | x, y, 57 | x+w, y, 58 | x, y+1, 59 | x+w, y+1 60 | ); 61 | DrawPrim(&p); 62 | } 63 | } 64 | 65 | int main() 66 | { 67 | initVideo(SCR_W, SCR_H); 68 | printf("\ngpu/uv-interpolation\n"); 69 | 70 | clearScreen(); 71 | setE1(0, 0); 72 | 73 | vramPut(u+0, v, 0x001f); // full red 74 | vramPut(u+1, v, 0x03E0); // full green 75 | 76 | interpolateUv(0, 0); 77 | interpolateColor(0, 256); 78 | 79 | setE1(0, 1); 80 | interpolateColor(256, 256); 81 | 82 | for (;;) { 83 | VSync(0); 84 | } 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /gpu/quad/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define SCR_W 320 4 | #define SCR_H 240 5 | 6 | POLY_F4 poly; 7 | 8 | int main() { 9 | initVideo(SCR_W, SCR_H); 10 | printf("\ngpu/quad (semi-transparent seam test)\n"); 11 | 12 | clearScreenColor(0xff, 0xff, 0xff); 13 | 14 | // Draw semi-transparent polygon 15 | POLY_F4 *p = &poly; 16 | setPolyF4(p); 17 | setSemiTrans(p, 1); 18 | 19 | int x[4], y[4]; 20 | x[0] = 48; y[0] = 48; 21 | x[1] = 176; y[1] = 32; 22 | x[2] = 64; y[2] = 144; 23 | x[3] = 208; y[3] = 160; 24 | 25 | // Center 26 | setRGB0(p, 0, 0, 0); 27 | setXY4(p, 28 | x[0], y[0], 29 | x[1], y[1], 30 | x[2], y[2], 31 | x[3], y[3] 32 | ); 33 | DrawPrim(p); 34 | 35 | // Left 36 | setRGB0(p, 0xff, 0, 0); 37 | setXY4(p, 38 | 0, 0, 39 | x[0], y[0], 40 | 0, SCR_H, 41 | x[2], y[2] 42 | ); 43 | DrawPrim(p); 44 | 45 | // TOP 46 | setRGB0(p, 0, 0xff, 0); 47 | setXY4(p, 48 | 0, 0, 49 | SCR_W, 0, 50 | x[0], 48, 51 | x[1], y[1] 52 | ); 53 | DrawPrim(p); 54 | 55 | // RIGHT 56 | setRGB0(p, 0, 0, 0xff); 57 | setXY4(p, 58 | x[1], y[1], 59 | SCR_W, 0, 60 | x[3], y[3], 61 | SCR_W, SCR_H 62 | ); 63 | DrawPrim(p); 64 | 65 | // BOTTOM 66 | setRGB0(p, 0xff, 0, 0xff); 67 | setXY4(p, 68 | x[2], y[2], 69 | x[3], y[3], 70 | 0, SCR_H, 71 | SCR_W, SCR_H 72 | ); 73 | DrawPrim(p); 74 | 75 | 76 | // Draw few transparent polygons next to each other 77 | for (int y = 0; y < 2; y++) { 78 | for (int x = 0; x < 8; x++) { 79 | const int S = 16; 80 | unsigned char c = (y == 0) ? 0xa0 : 0xff; 81 | setRGB0(p, c * ((x>>0)&1), c * ((x>>1)&1), c * ((x>>2)&1)); 82 | setXY4(p, 83 | 64 + S*x, 192 + S*y, 84 | 64 + S*x + S, 192 + S*y, 85 | 64 + S*x, 192 + S + S*y, 86 | 64 + S*x + S, 192 + S + S*y 87 | ); 88 | DrawPrim(p); 89 | } 90 | } 91 | 92 | for (;;) { 93 | VSync(0); 94 | } 95 | return 0; 96 | } 97 | -------------------------------------------------------------------------------- /common/exception.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "exception.hpp" 3 | // #define DEBUG 4 | 5 | #ifdef DEBUG 6 | #include 7 | 8 | const char* exceptionName[] = { 9 | "interrupt", // 0 10 | "exception1", // 1 11 | "exception2", // 2 12 | "exception3", // 3 13 | "addressErrorLoad", // 4 14 | "addressErrorStore", // 5 15 | "busErrorInstruction", // 6 16 | "busErrorData", // 7 17 | "syscall", // 8 18 | "breakpoint", // 9 19 | "reservedInstruction", // 10 20 | "coprocessorUnusable", // 11 21 | "arithmeticOverflow", // 12 22 | }; 23 | #endif 24 | 25 | // From __globals table 26 | static uint32_t* A0 = (uint32_t*)0x200; 27 | 28 | void hookUnresolvedExceptionHandler(void_fn_ptr fn) { 29 | A0[0x40] = (uint32_t)fn; 30 | } 31 | 32 | Thread* getCurrentThread() { 33 | Process** processes = (struct Process**)0x108; 34 | return processes[0]->thread; 35 | } 36 | 37 | bool wasExceptionThrown() { 38 | Thread* currentThread = getCurrentThread(); 39 | 40 | bool ret = currentThread->unknown[0]; 41 | currentThread->unknown[0] = 0; 42 | return ret; 43 | } 44 | 45 | cop0::CAUSE::Exception getExceptionType() { 46 | Thread* currentThread = getCurrentThread(); 47 | 48 | return (cop0::CAUSE::Exception)currentThread->unknown[1]; 49 | } 50 | 51 | void exceptionHandler() { 52 | Thread* currentThread = getCurrentThread(); 53 | auto exception = currentThread->registers.cause.exception; 54 | 55 | currentThread->unknown[0] = 1; // Exception was thrown flag 56 | currentThread->unknown[1] = (int)exception; 57 | 58 | #ifdef DEBUG 59 | printf("\n" 60 | "!! Custom exception handler\n" 61 | "!! Exception '%s' (%d) thrown at address 0x%08x\n" 62 | "!! r31 (ra): 0x%08x\n" 63 | "!! COP0 STATUS: 0x%08x\n" 64 | "!! COP0 CAUSE: 0x%08x\n", 65 | exceptionName[(int)exception], 66 | (int)exception, 67 | currentThread->registers.returnPC, 68 | currentThread->registers.r[31], 69 | currentThread->registers.sr._reg, 70 | currentThread->registers.cause._reg 71 | ); 72 | #endif 73 | 74 | if (exception == cop0::CAUSE::Exception::busErrorInstruction) { 75 | currentThread->registers.returnPC = currentThread->registers.r[31]; // return to RA 76 | } else { 77 | currentThread->registers.returnPC += 4; // Skip failing instruction 78 | } 79 | } -------------------------------------------------------------------------------- /gpu/mask-bit/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Check if read pixel == written pixel 5 | void testWriteAndRead() { 6 | int x = 32; 7 | int y = 32; 8 | 9 | setMaskBitSetting(false, false); 10 | 11 | vramPut(x, y, 0x1234); 12 | 13 | assertEquals(vramGet(x, y), 0x1234); 14 | } 15 | 16 | // Check if GP0(0xE6) bit0 (Set mask while drawing) works 17 | void testSetBit() { 18 | int x = 33; 19 | int y = 32; 20 | 21 | setMaskBitSetting(true, false); 22 | vramPut(x, y, 0); 23 | 24 | assertEquals(vramGet(x, y), 0x8000); 25 | } 26 | 27 | // Check if GP0(0xE6) bit1 (Check mask before draw) works 28 | void testCheckMaskBit() { 29 | int x = 34; 30 | int y = 32; 31 | 32 | // Disable mask bit set 33 | setMaskBitSetting(false, false); 34 | vramPut(x, y, 0x8000); // Write mask bit 35 | 36 | // Enable check mask bit 37 | setMaskBitSetting(false, true); 38 | vramPut(x, y, 0x1234); 39 | 40 | assertEquals(vramGet(x, y), 0x8000); 41 | } 42 | 43 | // Check mask bit (written manually) can be overwritten 44 | void testCheckIsMaskBitStickyManually() { 45 | int x = 35; 46 | int y = 32; 47 | 48 | setMaskBitSetting(false, false); 49 | vramPut(x, y, 0x8123); // Write mask bit manually 50 | vramPut(x, y, 0x0456); // Try clearing it 51 | 52 | assertEquals(vramGet(x, y), 0x0456); 53 | } 54 | 55 | // Check mask bit (written automatically) can be overwritten 56 | void testCheckIsMaskBitStickySetBit() { 57 | int x = 36; 58 | int y = 32; 59 | 60 | setMaskBitSetting(true, false); 61 | vramPut(x, y, 0x0000); // Write mask bit using HW 62 | 63 | setMaskBitSetting(false, false); 64 | vramPut(x, y, 0x0456); // Try clearing it 65 | 66 | assertEquals(vramGet(x, y), 0x0456); 67 | } 68 | 69 | void runTests() { 70 | testWriteAndRead(); 71 | testSetBit(); 72 | testCheckMaskBit(); 73 | testCheckIsMaskBitStickyManually(); 74 | testCheckIsMaskBitStickySetBit(); 75 | 76 | printf("Done.\n"); 77 | } 78 | 79 | int main() { 80 | initVideo(320, 240); 81 | printf("\ngpu/mask-bit\n"); 82 | 83 | setMaskBitSetting(false, false); 84 | clearScreen(); 85 | 86 | runTests(); 87 | 88 | for (;;) { 89 | VSync(0); 90 | } 91 | return 0; 92 | } 93 | -------------------------------------------------------------------------------- /common/test.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | struct TEST { 9 | bool quiet; 10 | int failedAssertions; 11 | int passedAssertions; 12 | }; 13 | 14 | extern struct TEST __test; 15 | #ifdef __cplusplus 16 | } 17 | #endif 18 | 19 | #define assertEqualsWithComment(given, expected, comment) \ 20 | [](auto FUNCTION, auto GIVEN, auto EXPECTED) -> bool { \ 21 | if (GIVEN == EXPECTED) { \ 22 | __test.passedAssertions++; \ 23 | if (!__test.quiet) { \ 24 | printf("pass - %s\n", FUNCTION); \ 25 | } \ 26 | return true; \ 27 | } else { \ 28 | __test.failedAssertions++; \ 29 | printf("fail - %s:%d `"#given" == "#expected"`," \ 30 | " given: 0x%x, expected: 0x%x %s\n", \ 31 | FUNCTION, __LINE__, GIVEN, EXPECTED, \ 32 | ((comment)[0] == '\0' ? "" : " - ("#comment")")); \ 33 | return false; \ 34 | } \ 35 | }(__FUNCTION__, given, expected) 36 | 37 | #define assertEquals(given, expected) assertEqualsWithComment(given, expected, "") 38 | 39 | #define assertTrue(given) assertEqualsWithComment(given, true, "") 40 | #define assertFalse(given) assertEqualsWithComment(given, false, "") 41 | 42 | #define TEST_MULTIPLE_BEGIN() \ 43 | []() { \ 44 | __test.quiet = true; \ 45 | }() 46 | 47 | #define TEST_MULTIPLE_END() \ 48 | [](auto FUNCTION) { \ 49 | bool passed = __test.failedAssertions == 0; \ 50 | __test.quiet = false; \ 51 | __test.failedAssertions = 0; \ 52 | __test.passedAssertions = 0; \ 53 | if (passed) { \ 54 | printf("pass - %s\n", FUNCTION); \ 55 | return true; \ 56 | } else { \ 57 | return false; \ 58 | } \ 59 | }(__FUNCTION__) 60 | -------------------------------------------------------------------------------- /input/pad/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define SCR_W 320 10 | #define SCR_H 240 11 | 12 | static DISPENV disp; 13 | static DRAWENV draw; 14 | 15 | static char padBuffer[2][34]; 16 | static unsigned short buttons = 0xffff, prevButtons = 0xffff; 17 | 18 | static bool BUTTON(uint16_t button) 19 | { 20 | return (buttons & button) == 0 && ((prevButtons & button) != 0); 21 | } 22 | 23 | static void ButtonUpdate(void) 24 | { 25 | prevButtons = buttons; 26 | buttons = ((PADTYPE*)padBuffer[0])->btn; 27 | } 28 | 29 | int main() 30 | { 31 | printf("PAD test (PAD1)\n"); 32 | 33 | ResetGraph(0); 34 | SetDefDispEnv(&disp, 0, 0, SCR_W, SCR_H); 35 | SetDefDrawEnv(&draw, 0, 0, SCR_W, SCR_H); 36 | 37 | PutDispEnv(&disp); 38 | PutDrawEnv(&draw); 39 | SetDispMask(1); 40 | 41 | InitPAD(padBuffer[0], 34, padBuffer[1], 34); 42 | StartPAD(); 43 | ChangeClearPAD(0); 44 | 45 | while (1) 46 | { 47 | if (BUTTON(PAD_UP)) { 48 | printf("PAD_UP\n"); 49 | } 50 | if (BUTTON(PAD_DOWN)) { 51 | printf("PAD_DOWN\n"); 52 | } 53 | if (BUTTON(PAD_LEFT)) { 54 | printf("PAD_LEFT\n"); 55 | } 56 | if (BUTTON(PAD_RIGHT)) { 57 | printf("PAD_RIGHT\n"); 58 | } 59 | if (BUTTON(PAD_SQUARE)) { 60 | printf("PAD_SQUARE\n"); 61 | } 62 | if (BUTTON(PAD_TRIANGLE)) { 63 | printf("PAD_TRIANGLE\n"); 64 | } 65 | if (BUTTON(PAD_CROSS)) { 66 | printf("PAD_X\n"); 67 | } 68 | if (BUTTON(PAD_CIRCLE)) { 69 | printf("PAD_CIRCLE\n"); 70 | } 71 | if (BUTTON(PAD_SELECT)) { 72 | printf("PAD_SEL\n"); 73 | } 74 | if (BUTTON(PAD_START)) { 75 | printf("PAD_START\n"); 76 | } 77 | if (BUTTON(PAD_L3)) { 78 | printf("PAD_L3\n"); 79 | } 80 | if (BUTTON(PAD_R3)) { 81 | printf("PAD_R3\n"); 82 | } 83 | if (BUTTON(PAD_L2)) { 84 | printf("PAD_L2\n"); 85 | } 86 | if (BUTTON(PAD_R2)) { 87 | printf("PAD_R2\n"); 88 | } 89 | if (BUTTON(PAD_L1)) { 90 | printf("PAD_L1\n"); 91 | } 92 | if (BUTTON(PAD_R1)) { 93 | printf("PAD_R1\n"); 94 | } 95 | VSync(0); 96 | ButtonUpdate(); 97 | } 98 | return 0; 99 | } -------------------------------------------------------------------------------- /cdrom/timing/psx.log: -------------------------------------------------------------------------------- 1 | cdrom/timing 2 | psxcd: Init Ok! 3 | init ack: min 69456, max 93696, average 75086 4 | init complete: min 138448, max 600632, average 476300 5 | CdlNop: min 24024, max 137104, average 45993 over 100 runs 6 | CdlMute: min 26736, max 150672, average 49548 over 100 runs 7 | CdlDemute: min 27096, max 177328, average 49208 over 100 runs 8 | CdlSetloc: min 33856, max 182160, average 57955 over 100 runs 9 | CdlSetmode: min 25824, max 137776, average 48242 over 100 runs 10 | single-speed timing: Setloc ACK = 50240 ticks, ReadN ACK = 34232 ticks, First Sector = 984136, Remaining Sectors = min 416216 max 468808 avg 446040 ticks, Pause ACK = 28656 ticks, Pause Complete = 1009408 ticks 11 | single-speed timing: Setloc ACK = 40352 ticks, ReadN ACK = 46168 ticks, First Sector = 834728, Remaining Sectors = min 421752 max 469600 avg 446110 ticks, Pause ACK = 28648 ticks, Pause Complete = 1022496 ticks 12 | single-speed timing: Setloc ACK = 118112 ticks, ReadN ACK = 39920 ticks, First Sector = 668488, Remaining Sectors = min 426416 max 469960 avg 446178 ticks, Pause ACK = 28584 ticks, Pause Complete = 1007640 ticks 13 | single-speed timing: Setloc ACK = 49704 ticks, ReadN ACK = 107216 ticks, First Sector = 707368, Remaining Sectors = min 422848 max 464704 avg 446104 ticks, Pause ACK = 43728 ticks, Pause Complete = 1013536 ticks 14 | single-speed timing: Setloc ACK = 51840 ticks, ReadN ACK = 113176 ticks, First Sector = 725800, Remaining Sectors = min 420736 max 470344 avg 446224 ticks, Pause ACK = 28648 ticks, Pause Complete = 1006472 ticks 15 | double-speed timing: Setloc ACK = 39776 ticks, ReadN ACK = 124304 ticks, First Sector = 553960, Remaining Sectors = min 196800 max 246800 avg 222222 ticks, Pause ACK = 43880 ticks, Pause Complete = 1046336 ticks 16 | double-speed timing: Setloc ACK = 51488 ticks, ReadN ACK = 112824 ticks, First Sector = 859112, Remaining Sectors = min 186552 max 239560 avg 222171 ticks, Pause ACK = 38536 ticks, Pause Complete = 1032136 ticks 17 | double-speed timing: Setloc ACK = 52544 ticks, ReadN ACK = 34352 ticks, First Sector = 947912, Remaining Sectors = min 196728 max 249744 avg 222285 ticks, Pause ACK = 43856 ticks, Pause Complete = 1039296 ticks 18 | double-speed timing: Setloc ACK = 39872 ticks, ReadN ACK = 131448 ticks, First Sector = 1024016, Remaining Sectors = min 201032 max 243728 avg 222379 ticks, Pause ACK = 33896 ticks, Pause Complete = 1037440 ticks 19 | double-speed timing: Setloc ACK = 56840 ticks, ReadN ACK = 34320 ticks, First Sector = 941224, Remaining Sectors = min 203384 max 240248 avg 222386 ticks, Pause ACK = 38728 ticks, Pause Complete = 1028832 ticks 20 | 21 | -------------------------------------------------------------------------------- /mdec/movie/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "bad_apple.h" 11 | 12 | #define SCR_W 256 13 | #define SCR_H 240 14 | 15 | uint32_t* buffer = nullptr; 16 | void decodeAndDisplayFrame(uint8_t* frame, size_t frameLen, uint16_t frameWidth, uint16_t frameHeight) { 17 | const int STRIPE_WIDTH = 16; 18 | const int STRIPE_HEIGHT = frameHeight; 19 | 20 | #ifdef USE_24BIT 21 | const ColorDepth depth = ColorDepth::bit_24; 22 | const int copyWidth = STRIPE_WIDTH * 3/2; 23 | #define BYTES_PER_PIXEL 3 24 | #else 25 | const ColorDepth depth = ColorDepth::bit_15; 26 | const int copyWidth = STRIPE_WIDTH; 27 | #define BYTES_PER_PIXEL 2 28 | #endif 29 | 30 | mdec_decodeDma((uint16_t*)frame, frameLen, depth, false, false); 31 | 32 | if (buffer == nullptr) { 33 | buffer = (uint32_t*)malloc(STRIPE_WIDTH * STRIPE_HEIGHT * BYTES_PER_PIXEL / 4 * sizeof(uint32_t)); 34 | } 35 | for (int c = 0; c < frameWidth / STRIPE_WIDTH; c++) { 36 | mdec_readDecodedDma(buffer, STRIPE_WIDTH * STRIPE_HEIGHT * BYTES_PER_PIXEL); 37 | vramWriteDMA(c * copyWidth, 0, copyWidth, STRIPE_HEIGHT, (uint16_t*)buffer); 38 | } 39 | } 40 | 41 | int main() { 42 | SetVideoMode(MODE_NTSC); 43 | initVideo(SCR_W, SCR_H); 44 | printf("\nmdec/frame\n"); 45 | #ifdef USE_24BIT 46 | extern DISPENV disp; 47 | disp.isrgb24 = true; 48 | PutDispEnv(&disp); 49 | printf("Using framebuffer in 24bit mode\n"); 50 | #endif 51 | 52 | clearScreen(); 53 | 54 | mdec_reset(); 55 | mdec_quantTable(quant, true); 56 | mdec_idctTable((int16_t*)idct); 57 | mdec_enableDma(); 58 | 59 | for (int i = 0; i<60*2; i++) { 60 | VSync(0); 61 | } 62 | 63 | for (int i = 0; i 3 | #include 4 | #include 5 | 6 | static int _index = -1; 7 | void writeReg(uint8_t address, uint8_t index, uint8_t data) { 8 | if (_index != index) { 9 | write8(0x1F801800, index); 10 | _index = index; 11 | } 12 | write8(0x1F801800 + address, data); 13 | } 14 | uint8_t readReg(uint8_t address, uint8_t index) { 15 | if (_index != index) { 16 | write8(0x1F801800, index); 17 | _index = index; 18 | } 19 | return read8(0x1F801800 + address); 20 | } 21 | 22 | // Status 23 | #define CD_STAT 0x1F801800 24 | #define BUSY_STS (1<<7) 25 | #define RSLR_RDY (1<<5) 26 | #define DRQ_STS (1<<6) 27 | 28 | // Write 29 | #define INT_EN 2, 1 30 | #define INT_FLAG 3, 1 31 | #define REQUEST_REG 3, 0 32 | 33 | #define ATV0 2, 2 // L to L 34 | #define ATV1 3, 2 // L to R 35 | #define ATV2 1, 3 // R to R 36 | #define ATV3 2, 3 // R to L 37 | #define ADP_CTL 3, 3 38 | 39 | #define COMMAND 1, 0 40 | #define PARAMETER 2, 0 41 | 42 | #define HINT_CTL 3, 1 43 | 44 | // Read 45 | #define RESULT 1, 0 46 | #define HINT_STS 3, 1 47 | 48 | void cdInit() { 49 | EnterCriticalSection(); 50 | 51 | write32(0x1f801018, 0x00020943); // CDROM Delay/Size 52 | write32(0x1f801020, 0x00001325); // COM_DELAY 53 | 54 | writeReg(INT_EN, 0x1f); 55 | writeReg(INT_FLAG, 0x1f); 56 | 57 | cdWantData(false); // Reset data fifo 58 | 59 | writeReg(ATV0, 0x80); 60 | writeReg(ATV1, 0); 61 | writeReg(ATV2, 0x80); 62 | writeReg(ATV3, 0); 63 | writeReg(ADP_CTL, 0x20); // Apply volume 64 | 65 | ExitCriticalSection(); 66 | } 67 | 68 | void cdClearParameterFifo() { 69 | writeReg(INT_FLAG, (1<<6)); 70 | } 71 | 72 | void cdPushParameter(uint8_t param) { 73 | writeReg(PARAMETER, param); 74 | } 75 | 76 | void cdCommand(uint8_t cmd) { 77 | writeReg(COMMAND, cmd); 78 | } 79 | 80 | uint8_t cdReadResponse() { 81 | return readReg(RESULT); 82 | } 83 | 84 | uint8_t cdGetInt(bool ack) { 85 | uint8_t no = readReg(HINT_STS) & 0x1f; 86 | if (ack && no != 0) writeReg(HINT_CTL, no); 87 | return no; 88 | } 89 | 90 | uint8_t cdReadData() { 91 | return read8(0x1f801802); 92 | } 93 | 94 | void cdWantData(bool wantData) { 95 | writeReg(REQUEST_REG, (wantData << 7)); 96 | } 97 | 98 | // Status bits 99 | bool cdCommandBusy() { 100 | return (read8(CD_STAT) & BUSY_STS) != 0; 101 | } 102 | 103 | bool cdResponseEmpty() { 104 | return (read8(CD_STAT) & RSLR_RDY) == 0; 105 | } 106 | 107 | bool cdDataEmpty() { 108 | return (read8(CD_STAT) & DRQ_STS) == 0; 109 | } 110 | -------------------------------------------------------------------------------- /gte-fuzz/common.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "common.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define SCR_W 320 11 | #define SCR_H 240 12 | 13 | static DISPENV disp; 14 | static DRAWENV draw; 15 | 16 | char padBuffer[2][34]; 17 | unsigned short buttons = 0xffff, prevButtons = 0xffff; 18 | 19 | const int fontPosX = 320; 20 | const int fontPosY = 0; 21 | 22 | int fontCharX = 0; 23 | int fontCharY = 0; 24 | 25 | void init() { 26 | ResetGraph(0); 27 | SetDefDispEnv(&disp, 0, 0, SCR_W, SCR_H); 28 | SetDefDrawEnv(&draw, 0, 0, SCR_W, SCR_H); 29 | 30 | PutDispEnv(&disp); 31 | PutDrawEnv(&draw); 32 | SetDispMask(1); 33 | 34 | InitGeom(); 35 | 36 | InitPAD(padBuffer[0], 34, padBuffer[1], 34); 37 | StartPAD(); 38 | ChangeClearPAD(0); 39 | 40 | FntLoad(fontPosX, fontPosY); 41 | } 42 | 43 | void display_frame() 44 | { 45 | VSync(0); 46 | 47 | prevButtons = buttons; 48 | buttons = ((PADTYPE*)padBuffer[0])->btn; 49 | 50 | fontCharX = 0; 51 | fontCharY = 0; 52 | } 53 | 54 | 55 | bool BUTTON(uint16_t button) { 56 | return (buttons & button) == 0 && ((prevButtons & button) != 0); 57 | } 58 | 59 | 60 | void clearFrameBuffer() { 61 | fillRect(0, 0, SCR_W, SCR_H, 0, 0, 0); 62 | } 63 | 64 | void FntPos(int x, int y) { 65 | fontCharX = x; 66 | fontCharY = y; 67 | } 68 | 69 | void FntChar(char c) { 70 | if (c == '\n') { 71 | fontCharX = 0; 72 | fontCharY += 8; 73 | return; 74 | } 75 | if (c >= ' ') { 76 | DR_TPAGE e; 77 | unsigned short texpage = getTPage(/* bits */ 0, /* semi transparency */ 0, fontPosX, fontPosY); 78 | setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ 1, texpage); 79 | DrawPrim(&e); 80 | 81 | if (c >= 96) { 82 | c &= ~(1<<5); // To lower 83 | } 84 | char pos = c - 33; 85 | int u = pos%16; 86 | int v = pos/16; 87 | 88 | SPRT_8 t; 89 | setSprt8(&t); 90 | setXY0(&t, fontCharX, fontCharY); 91 | setUV0(&t, u*8, v*8); 92 | setClut(&t, 320, 32); 93 | setRGB0(&t, 255, 255, 255); 94 | 95 | DrawPrim(&t); 96 | } 97 | 98 | fontCharX += 8; 99 | if (fontCharX > SCR_W) { 100 | fontCharX = 0; 101 | fontCharY += 8; 102 | } 103 | } 104 | 105 | void FntPrintf(const char* format, ...) { 106 | char buffer[256]; 107 | va_list args; 108 | va_start(args, format); 109 | vsprintf(buffer, format, args); 110 | 111 | int len = strlen(buffer); 112 | for (int i = 0; i= 4 { 116 | diffName = os.Args[3] 117 | } 118 | 119 | fdiff, err := os.Create(diffName) 120 | if err != nil { 121 | log.Fatal(err) 122 | return 123 | } 124 | err = png.Encode(fdiff, diffImage) 125 | if err != nil { 126 | log.Fatalf("%s: %s.\n", diffName, err) 127 | return 128 | } 129 | 130 | log.Printf("Diff written to %s", diffName) 131 | os.Exit(2) 132 | return 133 | } 134 | 135 | log.Printf("Images are the same\n") 136 | } 137 | -------------------------------------------------------------------------------- /gpu/rectangles/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "lena.h" 3 | 4 | #define SCR_W 320 5 | #define SCR_H 240 6 | 7 | void setE1(int texPageX, int texPageY, int transparencyMode, int dithering) { 8 | DR_TPAGE e; 9 | unsigned short texpage = getTPage(/* 15bit */ 2, transparencyMode, texPageX, texPageY); 10 | setDrawTPage(&e, /* Drawing to display area */ 1, dithering, texpage); 11 | DrawPrim(&e); 12 | } 13 | 14 | uint32_t randomColor(int i) { 15 | uint8_t r = 32 + (i * 1831) % 192; 16 | uint8_t g = 32 + (i * 2923) % 192; 17 | uint8_t b = 32 + (i * 5637) % 192; 18 | 19 | return (r << 0) | (g << 8) | (b << 16); 20 | } 21 | 22 | // drawRectangles will iterate through every Rectangle GPU command 23 | // and send it to GPU with random but valid arguments 24 | void drawRectangles(int _x, int _y) { 25 | for (int y = 0; y < 12; y++) { 26 | for (int x = 0; x < 16; x++) { 27 | uint8_t type = 0x60 + y * 16 + x; 28 | if (type > 0x7f) return; 29 | 30 | uint32_t color = randomColor(type); 31 | 32 | uint32_t buf[5]; 33 | buf[1] = (type << 24) | color; 34 | buf[2] = ((_y + y*20) << 16) | (_x + x*20); 35 | 36 | int cmdLength = 3; 37 | bool variableSize = ((type & 0b11000) >> 3) == 0; 38 | bool textured = (type & (1<<2)) != 0; 39 | 40 | if (textured) { 41 | uint16_t clut = 0; 42 | uint8_t u = rand()%64; 43 | uint8_t v = rand()%64; 44 | buf[cmdLength++] = (clut << 16) | (v << 8) | u; 45 | } 46 | if (variableSize) { 47 | uint16_t w = 10 + rand()%10; 48 | uint16_t h = 10 + rand()%10; 49 | buf[cmdLength++] = (h << 16) | w; 50 | } 51 | 52 | setcode(buf, type); 53 | setlen(buf, cmdLength - 1); 54 | 55 | DrawPrim(buf); 56 | } 57 | } 58 | } 59 | 60 | int main() { 61 | initVideo(SCR_W, SCR_H); 62 | printf("\ngpu/rectangles\n"); 63 | 64 | clearScreenColor(0xff, 0xff, 0xff); 65 | 66 | // Load texture 67 | TIM_IMAGE tim; 68 | GetTimInfo((unsigned int*)lena_tim, &tim); 69 | LoadImage(tim.prect, tim.paddr); 70 | 71 | for (;;) { 72 | srand(321); 73 | // TODO: Separate test for V/H flipping 74 | // Dithering should be ignored by rectangle commands 75 | setE1(tim.prect->x, tim.prect->y, 0, 0); 76 | drawRectangles(0, 0); 77 | 78 | setE1(tim.prect->x, tim.prect->y, 1, 1); 79 | drawRectangles(0, 64); 80 | 81 | setE1(tim.prect->x, tim.prect->y, 2, 1); 82 | drawRectangles(0, 128); 83 | 84 | setE1(tim.prect->x, tim.prect->y, 3, 1); 85 | drawRectangles(0, 192); 86 | 87 | VSync(0); 88 | } 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /gpu/clipping/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define SCR_W 320 4 | #define SCR_H 240 5 | 6 | typedef struct CLIP { 7 | unsigned int tag; 8 | unsigned int code; 9 | } CLIP; 10 | 11 | void setClipping(int left, int top, int right, int bottom) { 12 | CLIP c; 13 | setlen(&c, 1); 14 | c.code = ((top << 10) & 0xffc00) | (left & 0x3ff); 15 | setcode(&c, 0xe3); 16 | DrawPrim(&c); 17 | 18 | c.code = (((bottom-1) << 10) & 0xffc00) | ((right-1) & 0x3ff); 19 | setcode(&c, 0xe4); 20 | DrawPrim(&c); 21 | } 22 | 23 | void drawQuad(int x, int y, int w, int h) { 24 | POLY_F4 p; 25 | setPolyF4(&p); 26 | setRGB0(&p, rand()%255, rand()%255, rand()%255); 27 | setXY4(&p, 28 | x, y, 29 | x+w, y, 30 | x, y+h, 31 | x+w, y+h 32 | ); 33 | DrawPrim(&p); 34 | } 35 | 36 | void drawRect(int x, int y, int w, int h, int r, int g, int b) { 37 | TILE p; 38 | setTile(&p); 39 | setRGB0(&p, r, g, b); 40 | setXY0(&p, x, y); 41 | setWH(&p, w, h); 42 | DrawPrim(&p); 43 | } 44 | 45 | void drawRect(int x, int y, int w, int h) { 46 | drawRect(x, y, w, h, rand()%255, rand()%255, rand()%255); 47 | } 48 | 49 | void setClippingDebug(int left, int top, int right, int bottom) { 50 | setClipping(0, 0, 1023, 511); // Disable clipping 51 | drawRect(left, top, right - left, bottom - top, 0xff, 0, 0); // Draw debug outline 52 | 53 | setClipping(left, top, right, bottom); 54 | } 55 | 56 | int main() { 57 | initVideo(SCR_W, SCR_H); 58 | printf("\ngpu/clipping - GP0(0xe3), GP0(0xe4) test\n"); 59 | printf("Rectangle GP0(0x60) and Polygon GP0(0x28) are tested\n"); 60 | printf("You shouldn't see red clipping outlines\n"); 61 | printf("All block should be aligned to each other and have exact same dimensions\n"); 62 | 63 | clearScreen(); 64 | fillRect(0, 0, SCR_W, SCR_H, 0xff, 0xff, 0xff); 65 | 66 | const int W = 80; 67 | const int H = 24; 68 | int x = 120; 69 | int y = 24; 70 | 71 | // Top, Left clip, polygon 72 | setClippingDebug(x, y, x + W, y + H); 73 | drawQuad(x-4, y-4, W+4, H+4); 74 | 75 | y += H + 8; 76 | // Right, Bottom clip, polygon 77 | setClippingDebug(x, y, x + W, y + H); 78 | drawQuad(x, y, W+4, H+4); 79 | 80 | y += H + 8; 81 | // Top, Left clip, rect 82 | setClippingDebug(x, y, x + W, y + H); 83 | drawRect(x-4, y-4, W+4, H+4); 84 | 85 | y += H + 8; 86 | // Right, Bottom clip, rect 87 | setClippingDebug(x, y, x + W, y + H); 88 | drawRect(x, y, W+4, H+4); 89 | 90 | // Full width 91 | y += H + 8; 92 | // polygon 93 | setClippingDebug(x, y, x + W, y + H); 94 | drawQuad(0, y, SCR_W, H); 95 | 96 | y += H + 8; 97 | // rect 98 | setClippingDebug(x, y, x + W, y + H); 99 | drawRect(0, y, SCR_W, H); 100 | 101 | for (;;) { 102 | VSync(0); 103 | } 104 | return 0; 105 | } 106 | -------------------------------------------------------------------------------- /cpu/access-time/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static void doNotOptimize(void* p) { 5 | asm volatile("" : : "g"(p) : "memory"); 6 | } 7 | 8 | template 9 | void readAccessTimeBitSize() { 10 | /* 11 | 800100c4: 24020064 li v0,100 12 | asm("nop"); 13 | 800100c8: 00000000 nop 14 | 800100cc: 2442ffff addiu v0,v0,-1 15 | for (int i = 0; i(char const*)+0x50> 17 | 800100d4: 00000000 nop 18 | */ 19 | uint32_t measuredCyclesNop = measure([] { 20 | volatile T* ptr = (T*)(base_address); 21 | for (int i = 0; i(char const*)+0xb8> 35 | 80010140: 00000000 nop 36 | */ 37 | uint32_t measuredCycles = measure([] { 38 | volatile T* ptr = (T*)(base_address); 39 | for (int i = 0; i 52 | void readAccessTime(const char* memoryType) { 53 | printf("%-10s (0x%08x) ", memoryType, base_address); 54 | readAccessTimeBitSize(); 55 | readAccessTimeBitSize(); 56 | readAccessTimeBitSize(); 57 | printf("\n"); 58 | } 59 | 60 | void runTests() { 61 | printf("SEGMENT ( ADDRESS) 8bit 16bit 32bit (cpu cycles per bitsize)\n"); 62 | readAccessTime<0x80000000>("RAM"); 63 | readAccessTime<0xBFC00000>("BIOS"); 64 | readAccessTime<0x1F800000>("SCRATCHPAD"); 65 | readAccessTime<0x1F000000>("EXPANSION1"); 66 | readAccessTime<0x1F802000>("EXPANSION2"); 67 | readAccessTime<0x1FA00000>("EXPANSION3"); 68 | readAccessTime<0x1F8010F0>("DMAC_CTRL"); 69 | readAccessTime<0x1F801044>("JOY_STAT"); 70 | readAccessTime<0x1F801054>("SIO_STAT"); 71 | readAccessTime<0x1F801060>("RAM_SIZE"); 72 | readAccessTime<0x1F801070>("I_STAT"); 73 | readAccessTime<0x1F801100>("TIMER0_VAL"); 74 | readAccessTime<0x1F801800>("CDROM_STAT"); 75 | readAccessTime<0x1F801814>("GPUSTAT"); 76 | readAccessTime<0x1F801824>("MDECSTAT"); 77 | readAccessTime<0x1F801DAA>("SPUCNT"); 78 | readAccessTime<0xFFFE0130>("CACHECTRL"); 79 | 80 | printf("Done.\n"); 81 | } 82 | 83 | int main() { 84 | initVideo(320, 240); 85 | clearScreen(); 86 | printf("\ncpu/access-time\n"); 87 | printf("Test CPU access time to different parts of memory map.\n"); 88 | printf("There are no assertions - please manually compare your results with provided psx.log.\n\n"); 89 | 90 | runTests(); 91 | 92 | for (;;) { 93 | VSync(false); 94 | } 95 | 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /cpu/code-in-io/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "code.h" 8 | 9 | typedef uint32_t (*func)(); 10 | 11 | void memcpy32(uint32_t* dst, uint32_t* src, size_t words) { 12 | for (size_t i = 0; i 2 | #include 3 | #include 4 | 5 | .text 6 | 7 | FlushCache: 8 | li $t1, 0x44 9 | li $t2, 0xa0 10 | jr $t2 11 | 12 | 13 | .globl GTE_READ 14 | # uint32_t GTE_READ(uint8_t reg); 15 | GTE_READ: 16 | addi $sp, -4 17 | sw $ra, 0($sp) 18 | 19 | 20 | # reg < 32 - data 21 | # reg >= 32 - control 22 | 23 | sub $t0, $a0, 32 24 | bgez $t0, read_control 25 | nop 26 | 27 | /* 28 | 00 f8 02 48 29 | ^^ 30 | gte reg number 31 | 32 | 1. andi reg with 31 33 | 2. << 3 34 | 3. load ins addr 35 | 4. store byte ins + 1 36 | */ 37 | 38 | # ############################### 39 | read_data: 40 | and $a0, 31 41 | sll $a0, 3 42 | 43 | la $t0, ins_mfc 44 | sb $a0, 1($t0) 45 | nop 46 | nop 47 | nop 48 | 49 | jal FlushCache 50 | nop 51 | 52 | ins_mfc: 53 | mfc2 $v0, $31 # to r2 (v0) read xx <-- replaced by us 54 | nop 55 | nop 56 | j exitGTE_READ 57 | nop 58 | 59 | 60 | # ############################# 61 | read_control: 62 | sub $a0, 32 63 | and $a0, 31 64 | sll $a0, 3 65 | 66 | la $t0, ins_cfc 67 | sb $a0, 1($t0) 68 | nop 69 | nop 70 | nop 71 | 72 | jal FlushCache 73 | nop 74 | 75 | ins_cfc: 76 | cfc2 $v0, $31 77 | nop 78 | nop 79 | j exitGTE_READ 80 | nop 81 | 82 | 83 | 84 | exitGTE_READ: 85 | lw $ra, 0($sp) 86 | addi $sp, 4 87 | 88 | jr $ra 89 | nop 90 | 91 | 92 | 93 | 94 | 95 | .globl GTE_WRITE 96 | # void GTE_WRITE(uint8_t reg, uint32_t value); 97 | GTE_WRITE: 98 | addi $sp, -4 99 | sw $ra, 0($sp) 100 | 101 | sub $t0, $a0, 32 102 | bgez $t0, write_control 103 | nop 104 | 105 | # ///////////////////////////////// 106 | write_data: 107 | and $a0, 31 108 | sll $a0, 3 109 | 110 | la $t0, ins_mtc 111 | sb $a0, 1($t0) 112 | nop 113 | nop 114 | nop 115 | 116 | jal FlushCache 117 | nop 118 | 119 | ins_mtc: 120 | mtc2 $a1, $31 121 | nop 122 | nop 123 | j exitGTE_WRITE 124 | nop 125 | 126 | 127 | # /////////////////////////////// 128 | write_control: 129 | sub $a0, 32 130 | and $a0, 31 131 | sll $a0, 3 132 | 133 | la $t0, ins_ctc 134 | sb $a0, 1($t0) 135 | nop 136 | nop 137 | nop 138 | 139 | jal FlushCache 140 | nop 141 | 142 | ins_ctc: 143 | ctc2 $a1, $31 144 | nop 145 | nop 146 | j exitGTE_WRITE 147 | nop 148 | 149 | 150 | 151 | exitGTE_WRITE: 152 | lw $ra, 0($sp) 153 | addi $sp, 4 154 | 155 | jr $ra 156 | nop 157 | 158 | 159 | .globl _GTE_OP 160 | # void _GTE_OP(uint32_t op) 161 | _GTE_OP: 162 | addi $sp, -4 163 | sw $ra, 0($sp) 164 | 165 | li $t0, 0x1FFFFFF 166 | and $a0, $t0 167 | 168 | li $t0, 0x4a000000 169 | or $a0, $t0 170 | 171 | la $t0, ins_cop2 172 | sw $a0, 0($t0) 173 | nop 174 | nop 175 | nop 176 | 177 | jal FlushCache 178 | nop 179 | 180 | ins_cop2: 181 | cop2 0xffffff 182 | nop 183 | nop 184 | 185 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 186 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 187 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 188 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 189 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 190 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 191 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 192 | nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; 193 | 194 | lw $ra, 0($sp) 195 | addi $sp, 4 196 | 197 | jr $ra 198 | nop 199 | -------------------------------------------------------------------------------- /mdec/frame/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Frame is padded by mdec-tools 11 | #include "sunset.h" 12 | uint8_t* frame = sunset_mdec; 13 | size_t frame_len = sunset_mdec_len; 14 | 15 | #define SCR_W 320 16 | #define SCR_H 240 17 | 18 | #define USE_MDECIN_DMA // DMA required for now due to MDECin fifo size (32*uint32_t) 19 | // #define USE_MDECOUT_DMA // Works ok with or without DMA (swizzling done in mdec_readDecoded) 20 | #define USE_GPU_DMA // Works ok with or without DMA 21 | 22 | #ifndef COLOR_DEPTH 23 | #error Please define COLOR_DEPTH as 15 or 24 24 | #endif 25 | 26 | int main() { 27 | SetVideoMode(MODE_NTSC); 28 | initVideo(SCR_W, SCR_H); 29 | printf("\nmdec/frame\n"); 30 | #if COLOR_DEPTH == 24 31 | extern DISPENV disp; 32 | disp.isrgb24 = true; 33 | PutDispEnv(&disp); 34 | printf("Using framebuffer in 24bit mode\n"); 35 | #else 36 | printf("Using framebuffer in 15bit mode\n"); 37 | #endif 38 | 39 | clearScreen(); 40 | 41 | mdec_reset(); 42 | mdec_quantTable(quant, true); 43 | mdec_idctTable((int16_t*)idct); 44 | 45 | ColorDepth depth; 46 | #if COLOR_DEPTH == 24 47 | depth = ColorDepth::bit_24; 48 | #elif COLOR_DEPTH == 15 49 | depth = ColorDepth::bit_15; 50 | #endif 51 | 52 | #if defined(USE_MDECIN_DMA) || defined(USE_MDECOUT_DMA) 53 | mdec_enableDma(); 54 | #endif 55 | 56 | const bool outputSigned = false; 57 | const bool setBit15 = false; 58 | #ifdef USE_MDECIN_DMA 59 | mdec_decodeDma((uint16_t*)frame, frame_len, depth, outputSigned, setBit15); 60 | #else 61 | // TODO: It would need to run on separate thread 62 | mdec_decode ((uint16_t*)frame, frame_len, depth, outputSigned, setBit15); 63 | #endif 64 | 65 | // Single macroblock consists of 4 8x8 blocks 66 | // in 15bit mode single pixel is 2 bytes: 4 * 8 * 8 * 2 = 512 bytes = 128 uint32_t 67 | // in 25bit mode single pixel is 4 bytes: 4 * 8 * 8 * 4 = 1024 bytes = 256 uint32_t 68 | #if COLOR_DEPTH == 24 69 | #define BYTES_PER_PIXEL 3 70 | #elif COLOR_DEPTH == 15 71 | #define BYTES_PER_PIXEL 2 72 | #endif 73 | const int FRAME_WIDTH = 320; 74 | const int FRAME_HEIGHT = 240; 75 | 76 | const int STRIPE_WIDTH = 16; 77 | const int STRIPE_HEIGHT = FRAME_HEIGHT; 78 | 79 | int copyWidth = STRIPE_WIDTH; 80 | if (depth == ColorDepth::bit_24) { 81 | copyWidth = STRIPE_WIDTH * 3/2; 82 | } 83 | 84 | uint32_t* buffer = (uint32_t*)malloc(STRIPE_WIDTH * STRIPE_HEIGHT * BYTES_PER_PIXEL / 4 * sizeof(uint32_t)); 85 | for (int c = 0; c < FRAME_WIDTH / 16; c++) { 86 | #ifdef USE_MDECOUT_DMA 87 | mdec_readDecodedDma(buffer, STRIPE_WIDTH * STRIPE_HEIGHT * BYTES_PER_PIXEL); 88 | #else 89 | mdec_readDecoded (buffer, STRIPE_WIDTH * STRIPE_HEIGHT * BYTES_PER_PIXEL); 90 | #endif 91 | 92 | writeGP0(1, 0); 93 | #ifdef USE_GPU_DMA 94 | vramWriteDMA(c * copyWidth, 0, copyWidth, STRIPE_HEIGHT, (uint16_t*)buffer); 95 | #else 96 | vramWrite (c * copyWidth, 0, copyWidth, STRIPE_HEIGHT, (uint16_t*)buffer); 97 | #endif 98 | } 99 | 100 | free(buffer); 101 | 102 | printf("Done\n"); 103 | 104 | // Stop all pending DMA transfers 105 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECin, 0); 106 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECout, 0); 107 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU, 0); 108 | DMA::masterEnable(DMA::Channel::MDECout, false); 109 | DMA::masterEnable(DMA::Channel::MDECin, false); 110 | DMA::masterEnable(DMA::Channel::GPU, false); 111 | 112 | mdec_reset(); 113 | for (;;) { 114 | VSync(0); 115 | } 116 | return 0; 117 | } -------------------------------------------------------------------------------- /cdrom/terminal/getline.cpp: -------------------------------------------------------------------------------- 1 | #include "getline.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define BUFFER_LEN 128 8 | #define HISTORY_SIZE 16 9 | 10 | static int historySize = 0; 11 | static char history[HISTORY_SIZE][BUFFER_LEN] = {}; 12 | 13 | bool isAscii(char c) { 14 | return c >= 32 && c <= 126; 15 | } 16 | 17 | bool getline(char* buf, unsigned length) { 18 | buf[0] = 0; 19 | int ptr = 0; 20 | int escapeCode = 0; 21 | 22 | int historyPtr = -1; 23 | 24 | while (true) { 25 | char c = getchar(); 26 | 27 | if (escapeCode == 0 && c == 27) { 28 | escapeCode = 1; 29 | continue; 30 | } 31 | if (escapeCode == 1) { 32 | if (c == '[') { 33 | escapeCode = 2; 34 | } else { 35 | escapeCode = 0; 36 | } 37 | continue; 38 | } 39 | if (escapeCode == 2) { 40 | auto clearAndPrint = [&](){ 41 | for (int i = 0; i= 0) { 62 | historyPtr--; 63 | clearAndPrint(); 64 | } 65 | } 66 | // else if (c == 'C') putchar(6); // right 67 | else if (c == 'D') { 68 | if (ptr > 0) { 69 | ptr--; 70 | putchar('\b'); // left 71 | } 72 | } 73 | else printf("unknown escape code %d (%c)\n", c, c); 74 | escapeCode = 0; 75 | continue; 76 | } 77 | 78 | if (c == 8 || c == 127) { 79 | if (ptr > 0) { 80 | buf[--ptr] = 0; 81 | putchar('\b'); 82 | putchar(' '); 83 | putchar('\b'); 84 | } 85 | } 86 | else if (c == '\r') { 87 | puts("\r\n"); 88 | if (ptr > 0) { 89 | if (historySize < HISTORY_SIZE) historySize++; 90 | for (int i = historySize; i>0; i--) { 91 | strcpy(history[i], history[i-1]); 92 | } 93 | strcpy(history[0], buf); 94 | } 95 | return true; 96 | } 97 | else if (c == 3) { 98 | buf[0] = 0; 99 | return false; // ctrl+c 100 | } 101 | else if (c == 20) { 102 | printf("\nHISTORY:\n"); 103 | for (int i = 0; i= length-1) { 112 | return true; 113 | } else { 114 | putchar(c); 115 | buf[ptr] = c; 116 | buf[ptr + 1] = 0; 117 | 118 | ptr++; 119 | } 120 | } 121 | else printf("Unhandled code %d\n", c); 122 | } 123 | 124 | return true; 125 | } -------------------------------------------------------------------------------- /gpu/vram-to-vram-overlap/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "font.h" 3 | 4 | // Write sizexsize rect to vram 5 | void writeRect(int dstX, int dstY, int size) { 6 | for (int y = 0; y 33 | constexpr size_t count(T (&)[N]) { return N; } 34 | 35 | constexpr int TEST_W = 3; // Test x from -3 to 3 36 | constexpr int TEST_H = 1; // Test y from -1 to 1 37 | const int COLS = (TEST_W*2 + 1) * (TEST_H*2 + 1); 38 | const int CELL_SIZE = 42; 39 | const int MARGIN = 4; 40 | 41 | void drawDebugInfo() { 42 | // Draw grid, vertical lines 43 | for (int size = 0; size < count(testCases) + 1; size++) { 44 | line( 45 | 0, size * CELL_SIZE, 46 | CELL_SIZE * (COLS+1), size * CELL_SIZE 47 | ); 48 | } 49 | // Horizontal 50 | for (int i = 0; i <= COLS + 1; i++) { 51 | line( 52 | i * CELL_SIZE, 0, 53 | i * CELL_SIZE, count(testCases) * CELL_SIZE 54 | ); 55 | } 56 | 57 | // Labels 58 | for (int t = 0; t < count(testCases); t++) { 59 | FntPos(2, t * CELL_SIZE + 12); 60 | FntPrintf("BLOCK\n %2d\n ", testCases[t]); 61 | if (t == 4) FntPrintf("x+1"); 62 | if (t == 5) FntPrintf("y+1"); 63 | if (t == 6) FntPrintf("xy+1"); 64 | 65 | int i = 1; 66 | for (int y = -TEST_H; y <= TEST_H; y++) { 67 | for (int x = -TEST_W; x <= TEST_W; x++) { 68 | FntPos(i * CELL_SIZE + 4, (t + 1) * CELL_SIZE - 10); 69 | FntPrintf("%2d:%d", x, y); 70 | i++; 71 | } 72 | } 73 | } 74 | } 75 | 76 | #define DRAW_DEBUG 77 | 78 | int main() { 79 | initVideo(640, 480); 80 | printf("\ngpu/vram-to-vram-overlap\n"); 81 | 82 | setMaskBitSetting(false, false); 83 | clearScreen(); 84 | 85 | #ifdef DRAW_DEBUG 86 | FntInit(); 87 | drawDebugInfo(); 88 | #endif 89 | 90 | // Draw test data 91 | for (int t = 0; t < count(testCases); t++) { 92 | for (int i = 0; i 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | int SCR_W = 320; 11 | int SCR_H = 240; 12 | #define OT_LEN 2 13 | 14 | static DISPENV disp[2]; 15 | static DRAWENV draw[2]; 16 | 17 | char pribuff[2][2048]; /* Primitive packet buffers */ 18 | unsigned int ot[2][OT_LEN]; /* Ordering tables */ 19 | char *nextpri; /* Pointer to next packet buffer offset */ 20 | int dbActive; 21 | 22 | int angle = 0; 23 | 24 | #define USE_GTE 25 | 26 | // Init function 27 | void init(void) { 28 | ResetGraph(0); 29 | SetVideoMode(MODE_NTSC); 30 | 31 | SetDefDispEnv(&disp[0], 0, 0, SCR_W, SCR_H); 32 | SetDefDrawEnv(&draw[0], SCR_W, 0, SCR_W, SCR_H); 33 | 34 | SetDefDrawEnv(&draw[1], 0, 0, SCR_W, SCR_H); 35 | SetDefDispEnv(&disp[1], SCR_W, 0, SCR_W, SCR_H); 36 | 37 | for (int i = 0; i<2; i++){ 38 | setRGB0(&draw[i], 255, 255, 255); 39 | draw[i].isbg = 1; 40 | draw[i].dfe=1; 41 | } 42 | 43 | // Clear double buffer counter 44 | dbActive = 0; 45 | 46 | // Apply the GPU environments 47 | PutDispEnv(&disp[dbActive]); 48 | PutDrawEnv(&draw[dbActive]); 49 | 50 | ClearOTagR( ot[0], OT_LEN ); 51 | ClearOTagR( ot[1], OT_LEN ); 52 | nextpri = pribuff[dbActive]; 53 | } 54 | 55 | // Display function 56 | void display(void) 57 | { 58 | DrawSync(0); 59 | VSync(0); 60 | 61 | dbActive = !dbActive; 62 | nextpri = pribuff[dbActive]; 63 | ClearOTagR( ot[dbActive], OT_LEN ); 64 | 65 | PutDrawEnv(&draw[dbActive]); 66 | PutDispEnv(&disp[dbActive]); 67 | 68 | SetDispMask(1); 69 | DrawOTag(ot[1-dbActive] + OT_LEN-1); 70 | } 71 | 72 | void rot2d(struct DVECTOR* v, int angle) { 73 | int x = v->vx; 74 | int y = v->vy; 75 | 76 | int c = icos(angle); 77 | int s = isin(angle); 78 | 79 | v->vx = (x * c - y * s ) / ONE; 80 | v->vy = (x * s + y * c ) / ONE; 81 | } 82 | 83 | void gte_rot2d(struct DVECTOR* v, int angle) { 84 | SVECTOR rotationVec = { 0 }; 85 | VECTOR translationVec = { 0 }; 86 | MATRIX m; 87 | 88 | rotationVec.vz = angle; 89 | 90 | RotMatrix(&rotationVec, &m); 91 | TransMatrix(&m, &translationVec); 92 | gte_SetRotMatrix(&m); // Matrix could be setup once 93 | gte_SetTransMatrix(&m); 94 | 95 | v->vx /= 2; 96 | v->vy /= 2; 97 | gte_ldv0(v); 98 | gte_rtps(); // Rotate 99 | gte_stsxy(v); 100 | } 101 | 102 | void drawTriangle(int cx, int cy, int size) 103 | { 104 | struct DVECTOR v[3] = {0}; 105 | v[0].vx = -0.866f * size; v[0].vy = -0.5f * size; 106 | v[1].vx = 0.866f * size; v[1].vy = -0.5f * size; 107 | v[2].vx = 0; v[2].vy = size; 108 | 109 | for (int i = 0; i<3; i++) { 110 | #ifdef USE_GTE 111 | gte_rot2d(&v[i], angle); 112 | #else 113 | rot2d(&v[i], angle); 114 | #endif 115 | } 116 | 117 | POLY_G3* p = (POLY_G3*)nextpri; 118 | setPolyG3(p); 119 | setRGB0(p, 255, 0, 0); 120 | setRGB1(p, 0, 255, 0); 121 | setRGB2(p, 0, 0, 255); 122 | setXY3(p, 123 | cx + v[0].vx, cy + v[0].vy, 124 | cx + v[1].vx, cy + v[1].vy, 125 | cx + v[2].vx, cy + v[2].vy 126 | ); 127 | addPrim(ot[dbActive] + (OT_LEN-1), p); 128 | 129 | nextpri += sizeof(POLY_G3); 130 | 131 | angle += ONE/360; 132 | if (angle >= ONE) angle = 0; 133 | } 134 | 135 | int main(){ 136 | init(); 137 | printf("\ngpu/animated-triangle\n"); 138 | 139 | #ifdef USE_GTE 140 | printf("Initializing GTE... "); 141 | InitGeom(); 142 | printf("done.\n"); 143 | gte_SetGeomOffset(0, 0); 144 | #endif 145 | 146 | for (;;) { 147 | drawTriangle(SCR_W/2, SCR_H/2, SCR_H/2); 148 | 149 | display(); 150 | } 151 | return 0; 152 | } 153 | -------------------------------------------------------------------------------- /cpu/io-access-bitwidth/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "asm.h" 6 | 7 | template 8 | void writeTo(const char* memoryType) { 9 | auto logValue = [](uint32_t value){ 10 | if (wasExceptionThrown()) { 11 | printf("%-10s ", "--CRASH--"); 12 | } else { 13 | printf("%#10x ", value); 14 | } 15 | }; 16 | 17 | printf("%-10s (0x%08x) ", memoryType, address); 18 | 19 | uint32_t value = 0x12345678; 20 | 21 | T preservedValue = *((volatile T*)address); 22 | 23 | if constexpr (sizeof(T) >= 1) { 24 | *((volatile T*)address) = 0; 25 | asm_write_8(address, value); 26 | uint32_t result8 = *((volatile T*)address); 27 | logValue(result8); 28 | } 29 | 30 | if constexpr (sizeof(T) >= 2) { 31 | *((volatile T*)address) = 0; 32 | asm_write_16(address, value); 33 | uint32_t result16 = *((volatile T*)address); 34 | logValue(result16); 35 | } 36 | 37 | if constexpr (sizeof(T) >= 4) { 38 | *((volatile T*)address) = 0; 39 | asm_write_32(address, value); 40 | uint32_t result32 = *((volatile T*)address); 41 | logValue(result32); 42 | } 43 | 44 | *((volatile T*)address) = preservedValue; 45 | printf("\n"); 46 | } 47 | 48 | template 49 | void runTests() { 50 | printf("\nReading as %dbit, writing as:\n", sizeof(T)*8); 51 | printf("SEGMENT ( ADDRESS) "); 52 | if constexpr (sizeof(T) >= 1) printf("8bit "); 53 | if constexpr (sizeof(T) >= 2) printf("16bit "); 54 | if constexpr (sizeof(T) >= 4) printf("32bit "); 55 | printf("\n"); 56 | 57 | write32(0x1f801020, 0x00001325); // COM_DELAY 58 | 59 | writeTo("RAM"); 60 | writeTo("BIOS"); // RO 61 | writeTo("SCRATCHPAD"); 62 | 63 | // write32(0x1F801000, 0x1F000000); // Exp1 base 64 | // write32(0x1F801008, 0x0013243F); // Exp1 Delay/Size 65 | // writeTo("EXPANSION1"); // Stalls the console ¯\_(ツ)_/¯ 66 | 67 | write32(0x1F801004, 0x1F802000); // Exp2 base 68 | write32(0x1F80101C, 0x00070777); // Exp2 Delay/Size 69 | writeTo("EXPANSION2"); 70 | 71 | write32(0x1F80100C, 0x00003022); // Exp3 Delay/Size 72 | writeTo("EXPANSION3"); 73 | 74 | writeTo("DMA0_ADDR"); 75 | writeTo("DMAC_CTRL"); 76 | writeTo("DMAC_INTR"); 77 | 78 | writeTo("JOY_MODE"); // Crash on 32bit 79 | writeTo("JOY_CTRL"); 80 | writeTo("SIO_MODE"); // Crash on 32bit 81 | writeTo("SIO_CTRL"); 82 | 83 | // writeTo("RAM_SIZE"); // Stalls the console 84 | writeTo("I_MASK"); 85 | writeTo("T0_TARGET"); 86 | 87 | write32(0x1f801018, 0x00020943); // CDROM Delay/Size 88 | writeTo("CDROM_STAT"); 89 | writeTo("GPUSTAT"); 90 | writeTo("MDECSTAT"); 91 | 92 | write32(0x1F801014, 0x220931E1); // SPU Delay/Size 93 | writeTo("SPUCNT"); // Crash on 32bit 94 | 95 | // writeTo("CACHECTRL"); // Stalls the console 96 | } 97 | 98 | int main() { 99 | initVideo(320, 240); 100 | clearScreen(); 101 | printf("\ncpu/io-access-bitwidth\n"); 102 | printf("Test how writes with different bitwidths behaves for different io devices\n"); 103 | printf("Note: Disable \"Exception Handling Surveillance\" in Caetla first\"\n"); 104 | 105 | EnterCriticalSection(); 106 | hookUnresolvedExceptionHandler(exceptionHandler); 107 | wasExceptionThrown(); // Clear flag 108 | 109 | runTests(); 110 | runTests(); 111 | runTests(); 112 | printf("Done.\n"); 113 | 114 | ExitCriticalSection(); 115 | 116 | for (;;) { 117 | VSync(false); 118 | } 119 | 120 | return 0; 121 | } 122 | -------------------------------------------------------------------------------- /dma/chain-looping/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static const char *BoolToString(bool v) { return v ? "true" : "false"; } 10 | 11 | static uint32_t GetAddress(const void *p) { 12 | return reinterpret_cast(p) & 0x1FFFFFFFu; 13 | } 14 | 15 | volatile uint32_t g_dont_optimize_me = 0; 16 | 17 | static uint32_t TimeWork() { 18 | return measure([]() { 19 | g_dont_optimize_me = 0; 20 | for (int i = 0; i < 1000; i++) { 21 | //__asm("nop\n"); 22 | g_dont_optimize_me += i; 23 | } 24 | }); 25 | } 26 | 27 | static void StartLinkedListDMA(uint32_t start_address) { 28 | write32(0x1F801814, 0x04000000); 29 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU, 0); 30 | write32(DMA::CH_BASE_ADDR + 0x10 * (int)DMA::Channel::GPU, 31 | DMA::MADDR(start_address)._reg); 32 | 33 | write32(0x1F801814, 0x04000002); 34 | DMA::channelIRQEnable(DMA::Channel::GPU, true); 35 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU, 36 | DMA::CHCR::GPULinkedList()._reg); 37 | } 38 | 39 | static bool IsGPUDMAFinished() { 40 | uint32_t value = read32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU); 41 | return (value & (1u << 24)) == 0; 42 | } 43 | 44 | static bool HasGPUDMAIRQ() { return DMA::channelIRQSet(DMA::Channel::GPU); } 45 | 46 | static void StopLinkedListDMA() { 47 | write32(0x1F801814, 0x04000000); 48 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU, 0); 49 | } 50 | 51 | void TestNoDMA() { 52 | printf("Testing with no DMA active...\n"); 53 | 54 | uint32_t ticks = TimeWork(); 55 | printf(" Work took %u ticks\n", ticks); 56 | } 57 | 58 | void TestEmptyChain() { 59 | printf("Testing with empty but complete chain...\n"); 60 | 61 | uint32_t chain[2] = {}; 62 | chain[0] = GetAddress(&chain[1]); 63 | chain[1] = 0x00FFFFFFu; 64 | 65 | StartLinkedListDMA(GetAddress(&chain[0])); 66 | uint32_t ticks = TimeWork(); 67 | bool was_finished = IsGPUDMAFinished(); 68 | bool dma_irq = HasGPUDMAIRQ(); 69 | StopLinkedListDMA(); 70 | printf(" Work took %u ticks, finished = %s, irq = %s\n", ticks, 71 | BoolToString(was_finished), BoolToString(dma_irq)); 72 | } 73 | 74 | void TestSingleSelfReferencingChain() { 75 | printf("Testing single self-referencing chain...\n"); 76 | 77 | uint32_t chain[2] = {}; 78 | chain[0] = GetAddress(&chain[0]); 79 | chain[1] = 0x00FFFFFFu; 80 | 81 | StartLinkedListDMA(GetAddress(&chain[0])); 82 | uint32_t ticks = TimeWork(); 83 | bool was_finished = IsGPUDMAFinished(); 84 | bool dma_irq = HasGPUDMAIRQ(); 85 | StopLinkedListDMA(); 86 | printf(" Work took %u ticks, finished = %s, irq = %s\n", ticks, 87 | BoolToString(was_finished), BoolToString(dma_irq)); 88 | } 89 | 90 | void TestDoubleSelfReferencingChain() { 91 | printf("Testing double self-referencing chain...\n"); 92 | 93 | uint32_t chain[3] = {}; 94 | chain[0] = GetAddress(&chain[1]); 95 | chain[1] = GetAddress(&chain[0]); 96 | chain[2] = 0x00FFFFFFu; 97 | 98 | StartLinkedListDMA(GetAddress(&chain[0])); 99 | uint32_t ticks = TimeWork(); 100 | bool was_finished = IsGPUDMAFinished(); 101 | bool dma_irq = HasGPUDMAIRQ(); 102 | StopLinkedListDMA(); 103 | printf(" Work took %u ticks, finished = %s, irq = %s\n", ticks, 104 | BoolToString(was_finished), BoolToString(dma_irq)); 105 | } 106 | 107 | int main() { 108 | initVideo(320, 240); 109 | printf("\ndma/chain-looping\n"); 110 | printf("Tests CPU behavior with various invalid GPU linked list chains.\n\n"); 111 | 112 | clearScreen(); 113 | 114 | DMA::masterIRQEnable(true); 115 | DMA::masterEnable(DMA::Channel::GPU, true); 116 | 117 | EnterCriticalSection(); 118 | TestNoDMA(); 119 | TestEmptyChain(); 120 | TestSingleSelfReferencingChain(); 121 | TestDoubleSelfReferencingChain(); 122 | ExitCriticalSection(); 123 | 124 | DMA::masterEnable(DMA::Channel::GPU, false); 125 | 126 | for (;;) { 127 | VSync(false); 128 | } 129 | 130 | return 0; 131 | } 132 | -------------------------------------------------------------------------------- /gpu/texture-flip/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define SCR_W 320 4 | #define SCR_H 240 5 | 6 | const int texPageX = 640; 7 | const int texPageY = 0; 8 | 9 | uint16_t lastTpage = 0; 10 | void setTextureFlip(bool flipY, bool flipX) { 11 | DR_TPAGE e; 12 | setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ 0, getTPage(/* bits = 15bit */ 2, /* transparencyMode */0, texPageX, texPageY)); 13 | e.code[0] |= (flipX << 12); 14 | e.code[0] |= (flipY << 13); 15 | lastTpage = e.code[0]; 16 | DrawPrim(&e); 17 | } 18 | 19 | void drawRectangle(int x, int y, int w, int h) { 20 | SPRT s; 21 | setSprt(&s); 22 | setSemiTrans(&s, 0); 23 | setRGB0(&s, 128, 128, 128 ); 24 | s.x0 = x; 25 | s.y0 = y; 26 | s.w = w; 27 | s.h = h; 28 | s.u0 = 0; 29 | s.v0 = 0; 30 | DrawPrim(&s); 31 | } 32 | 33 | void drawQuad(int x, int y, int w, int h) { 34 | POLY_FT4 p; 35 | setPolyFT4(&p); 36 | setSemiTrans(&p, 0); 37 | setRGB0(&p, 128, 128, 128 ); 38 | setClut(&p, 0, 0); // Not used 39 | p.tpage = lastTpage; 40 | 41 | p.x0 = x; p.y0 = y; 42 | p.x1 = x+w; p.y1 = y; 43 | p.x2 = x; p.y2 = y+h; 44 | p.x3 = x+w; p.y3 = y+h; 45 | 46 | p.u0 = 0; p.v0 = 0; 47 | p.u1 = w; p.v1 = 0; 48 | p.u2 = 0; p.v2 = h; 49 | p.u3 = w; p.v3 = h; 50 | DrawPrim(&p); 51 | } 52 | 53 | int main() { 54 | initVideo(SCR_W, SCR_H); 55 | printf("\ngpu/texture-flip\n"); 56 | printf("VRAM contents:\n" 57 | "0,0 \n" 58 | "┌--------------------------------------------------------┐\n" 59 | "|┌--------┐ ┌--------┐ ┌---------┐ |\n" 60 | "|| | | | | | |\n" 61 | "|| Rect | | Rect | | texture | |\n" 62 | "|| normal | | x-flip | | | |\n" 63 | "|| | | | | | |\n" 64 | "|| | | | | | |\n" 65 | "│└--------┘ └--------┘ └---------┘ |\n" 66 | "| |\n" 67 | "│┌--------┐ ┌--------┐ ┌--┐ ┌--┐ |\n" 68 | "|| | | | | r| | r| 64x64rect |\n" 69 | "|| Rect | | Rect | └--┘ └--┘ 2nd flipped |\n" 70 | "|| y-flip | | x&y | |\n" 71 | "|| | | flip | ┌--┐ ┌--┐ 64x64 quad |\n" 72 | "|| | | | | q| | q| 2nd flipped |\n" 73 | "|└--------┘ └--------┘ └--┘ └--┘(should be the same)|\n" 74 | "└--------------------------------------------------------┘\n" 75 | " 1023, 1023\n\n"); 76 | 77 | clearScreenColor(0xff, 0xff, 0xff); 78 | 79 | const int W = 256; 80 | const int H = 256; 81 | // Make texture 82 | for (int i = 0; i < 0xffff; i++) { 83 | int x = texPageX + i % W; 84 | int y = texPageY + i / W; 85 | vramPut(x, y, i); 86 | } 87 | 88 | // 0x0 - normal 89 | setTextureFlip(0, 0); 90 | drawRectangle(0, 0, W, H); 91 | 92 | // 260x0 - x flipped 93 | setTextureFlip(0, 1); 94 | drawRectangle(260, 0, W, H); 95 | 96 | // 260x0 - y flipped 97 | setTextureFlip(1, 0); 98 | drawRectangle(0, 260, W, H); 99 | 100 | // 260x260 - x&&y flipped 101 | setTextureFlip(1, 1); 102 | drawRectangle(260, 260, W, H); 103 | 104 | 105 | // 640x260 - normal (small rect) 106 | setTextureFlip(0, 0); 107 | drawRectangle(640, 260, 64, 64); 108 | 109 | // 640x260 - x&&y flipped (small rect) 110 | setTextureFlip(1, 1); 111 | drawRectangle(714, 260, 64, 64); 112 | 113 | 114 | // Check polygons as well, just to be sure 115 | // 640x260 - normal (small polygon) 116 | setTextureFlip(0, 0); 117 | drawQuad(640, 334, 64, 64); 118 | 119 | // 640x260 - x&&y flipped (small polygon) 120 | setTextureFlip(1, 1); 121 | drawQuad(714, 334, 64, 64); 122 | 123 | printf("Done.\n"); 124 | for (;;) { 125 | VSync(0); 126 | } 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /common/cop0.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "stdint.h" 3 | 4 | // From Avocado (src/cpu/cop0.h) 5 | 6 | namespace cop0 { 7 | // cop0r7 DCIC - breakpoint control 8 | union DCIC { 9 | struct { 10 | uint32_t breakpointHit : 1; 11 | uint32_t codeBreakpointHit : 1; 12 | uint32_t dataBreakpointHit : 1; 13 | uint32_t dataReadBreakpointHit : 1; 14 | uint32_t dataWriteBreakpointHit : 1; 15 | uint32_t jumpBreakpointHit : 1; 16 | uint32_t : 6; // not used 17 | 18 | uint32_t jumpRedirection : 2; // 0 - disabled, 1..3 - enabled 19 | 20 | uint32_t : 2; // Unknown 21 | uint32_t : 7; // not used 22 | 23 | uint32_t superMasterEnable1 : 1; // bits 24..29 24 | 25 | uint32_t breakOnCode : 1; 26 | uint32_t breakOnData : 1; 27 | uint32_t breakOnDataRead : 1; 28 | uint32_t breakOnDataWrite : 1; 29 | uint32_t breakOnJump : 1; 30 | 31 | uint32_t masterEnableBreakAnyJump : 1; 32 | uint32_t masterEnableBreakpoints : 1; // bits 24..27 33 | uint32_t superMasterEnable2 : 1; // bits 24..29 34 | }; 35 | 36 | uint32_t _reg; 37 | }; 38 | // cop0r13 cause, ro, bit8-9 are rw 39 | union CAUSE { 40 | enum class Exception { 41 | interrupt = 0, 42 | addressErrorLoad = 4, 43 | addressErrorStore = 5, 44 | busErrorInstruction = 6, 45 | busErrorData = 7, 46 | syscall = 8, 47 | breakpoint = 9, 48 | reservedInstruction = 10, 49 | coprocessorUnusable = 11, 50 | arithmeticOverflow = 12 51 | }; 52 | 53 | struct { 54 | uint32_t : 2; 55 | Exception exception : 5; 56 | uint32_t : 1; 57 | uint32_t interruptPending : 8; 58 | uint32_t : 12; 59 | uint32_t coprocessorNumber : 2; // If coprocessor caused the exception 60 | uint32_t branchTaken : 1; /** When the branchDelay bit is set, the branchTaken Bit determines whether or not the 61 | * branch is taken. A value of one in branchTaken indicates that the branch is 62 | * taken. The Target Address Register holds the return address. 63 | * 64 | * source: L64360 datasheet 65 | */ 66 | uint32_t branchDelay : 1; /** CPU sets this bit to one to indicate that the last exception 67 | * was taken while executing in a branch delay slot. 68 | * 69 | * source: L64360 datasheet 70 | */ 71 | }; 72 | 73 | uint32_t _reg; 74 | }; 75 | 76 | // cop0r12 System status, rw 77 | union STATUS { 78 | enum class Mode : uint32_t { kernel = 0, user = 1 }; 79 | enum class BootExceptionVectors { ram = 0, rom = 1 }; 80 | struct { 81 | uint32_t interruptEnable : 1; 82 | Mode mode : 1; 83 | 84 | uint32_t previousInterruptEnable : 1; 85 | Mode previousMode : 1; 86 | 87 | uint32_t oldInterruptEnable : 1; 88 | Mode oldMode : 1; 89 | 90 | uint32_t : 2; 91 | 92 | uint32_t interruptMask : 8; 93 | uint32_t isolateCache : 1; 94 | uint32_t swappedCache : 1; 95 | uint32_t writeZeroAsParityBits : 1; 96 | uint32_t : 1; // CM 97 | uint32_t cacheParityError : 1; 98 | uint32_t tlbShutdown : 1; // TS 99 | 100 | BootExceptionVectors bootExceptionVectors : 1; 101 | uint32_t : 2; 102 | uint32_t reverseEndianness : 1; 103 | uint32_t : 2; 104 | 105 | uint32_t cop0Enable : 1; 106 | uint32_t cop1Enable : 1; 107 | uint32_t cop2Enable : 1; 108 | uint32_t cop3Enable : 1; 109 | }; 110 | 111 | uint32_t _reg; 112 | }; 113 | } -------------------------------------------------------------------------------- /mdec/step-by-step-log/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "symbols.h" 13 | 14 | extern void mdec_data(uint32_t cmd); 15 | int main() { 16 | // Use UART on PSX for faster printing 17 | // AddSIO(115200); 18 | initVideo(320, 240); 19 | printf("\nmdec/step-by-step-log\n"); 20 | printf("Manually feeds the MDEC data, monitors status register at every step.\n"); 21 | printf("When MDECin FIFO is full, program switches to read mode which dumps decoded image until FIFO out gets empty. \n"); 22 | printf("Decoded blocks are copied manually WITHOUT swizzling, blocks are copied as 16x4 instead of 8x8\n"); 23 | 24 | clearScreen(); 25 | 26 | mdec_reset(); 27 | mdec_quantTable(quant, true); 28 | mdec_idctTable((int16_t*)idct); 29 | 30 | mdec_enableDma(); 31 | 32 | const ColorDepth depth = ColorDepth::bit_15; 33 | const bool outputSigned = false; 34 | const bool setBit15 = false; 35 | 36 | printf("mdec_decode(addr=0x%08x, length=0x%x, colorDepth=%d, outputSigned=%d, setBit15=%d)... \n", symbols_mdec, symbols_mdec_len, depth, outputSigned, setBit15); 37 | size_t lengthWords = symbols_mdec_len / 4; 38 | uint32_t cmd = (1<<29) | (depth<<27) | (outputSigned<<26) | (setBit15 << 25) | (lengthWords & 0xffff); 39 | 40 | while (mdec_cmdBusy()); 41 | mdec_cmd(cmd); 42 | 43 | // Warning: W, H must be set to correct dimensions 44 | int W = 16; 45 | int H = 64; 46 | 47 | const int bytesToRead = W * H * 2; 48 | int bytesToReadRemaining = bytesToRead; 49 | uint32_t image[bytesToRead / 4]; 50 | int imagePtr = 0; 51 | 52 | uint16_t* rlePtr = (uint16_t*)symbols_mdec; 53 | 54 | auto printfStatus = []() { 55 | uint32_t status = read32(MDEC_STATUS); 56 | printf("==== MDEC_STATUS: 0x%08x, " 57 | "dataOutFifoEmpty: %d, " 58 | "dataInFifoFull: %d, " 59 | "cmdBusy: %d, " 60 | "dataInReq: %d, " 61 | "dataOutReq: %d, " 62 | "currentBlock: %d\n", 63 | status, 64 | (status & (1 << 31)) != 0, 65 | (status & (1 << 30)) != 0, 66 | (status & (1 << 29)) != 0, 67 | (status & (1 << 28)) != 0, 68 | (status & (1 << 27)) != 0, 69 | (status >> 16) & 7 70 | ); 71 | }; 72 | 73 | while (true) { 74 | bool waitForImage = false; 75 | printf("\n\n----- MDECin\n"); 76 | for (;lengthWords != 0;lengthWords--) { 77 | printfStatus(); 78 | if (mdec_dataInFifoFull()) { 79 | printf("MDEC: dataInFifoFull, suspending 'mdecIn'\n"); 80 | break; 81 | } 82 | uint32_t word = *rlePtr++; 83 | word |= ((uint32_t)(*rlePtr++)) << 16; 84 | 85 | mdec_data(word); 86 | printf("MDEC_DATA <- 0x%08x\n", word); 87 | delay(10000); 88 | 89 | waitForImage = true; 90 | } 91 | if (waitForImage) { 92 | while (mdec_dataOutFifoEmpty()); 93 | } 94 | 95 | printf("\n\n----- MDECout\n"); 96 | for (; bytesToReadRemaining != 0; bytesToReadRemaining -= 4) { 97 | printfStatus(); 98 | if (mdec_dataOutFifoEmpty()) { 99 | printf("MDEC: dataOutFifoEmpty, suspending 'mdecOut'\n"); 100 | break; 101 | } 102 | uint32_t read = mdec_read(); 103 | printf("MDEC_DATA -> 0x%08x\n", read); 104 | image[imagePtr++] = read; 105 | delay(10000); 106 | } 107 | 108 | if (lengthWords <= 0 && bytesToReadRemaining <= 0) { 109 | break; 110 | } 111 | } 112 | 113 | printfStatus(); 114 | printf("done\n"); 115 | 116 | hexdump((uint8_t*)image, bytesToRead, 32); 117 | writeGP0(1, 0); 118 | vramWriteDMA(0, 0, W, H, (uint16_t*)image); 119 | 120 | // Stop all pending DMA transfers 121 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECin, 0); 122 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::MDECout, 0); 123 | write32(DMA::CH_CONTROL_ADDR + 0x10 * (int)DMA::Channel::GPU, 0); 124 | DMA::masterEnable(DMA::Channel::MDECout, false); 125 | DMA::masterEnable(DMA::Channel::MDECin, false); 126 | DMA::masterEnable(DMA::Channel::GPU, false); 127 | 128 | mdec_reset(); 129 | printf("Done\n"); 130 | for (;;) { 131 | VSync(0); 132 | } 133 | return 0; 134 | } -------------------------------------------------------------------------------- /gpu/gp0-e1/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | const uint32_t E1_MASK = 0b10000111'11111111; 5 | 6 | void drawTexturedPolygon(uint16_t texpage) { 7 | POLY_FT4 p; 8 | setPolyFT4(&p); 9 | setRGB0(&p, 0x80, 0x80, 0x80); 10 | setClut(&p, 0, 0); 11 | setUVWH(&p, 0, 0,255, 255); 12 | setXY4(&p, 13 | 0, 0, 14 | 0, 32, 15 | 32, 0, 16 | 32, 32 17 | ); 18 | p.tpage = texpage; 19 | 20 | DrawPrim(&p); 21 | } 22 | 23 | // Allow setting E1.11 bit 24 | void allowTextureDisable(bool allow) { 25 | writeGP1(0x09, allow); 26 | } 27 | 28 | // Check if writing zeroes to GP0_E1 == what GPSTAT read 29 | void testWriteZerosToE1() { 30 | allowTextureDisable(false); // Disable E1.11 bit 31 | writeGP0(0xe1, 0x000); 32 | 33 | assertEquals((ReadGPUstat() & E1_MASK), 0b00000000'00000000); 34 | } 35 | 36 | // Check if writing ones to GP0_E1 == what GPSTAT read (no "Texture Disable") 37 | void testWriteOnesToE1() { 38 | allowTextureDisable(false); 39 | writeGP0(0xe1, 0xfff); 40 | 41 | assertEquals((ReadGPUstat() & E1_MASK), 0b00000111'11111111); 42 | } 43 | 44 | // Check if writing ones to GP0_E1 == what GPSTAT read (with "Texture Disable") 45 | void testWriteOnesToE1WithTextureDisable() { 46 | allowTextureDisable(true); 47 | writeGP0(0xe1, 0xfff); 48 | 49 | assertEquals((ReadGPUstat() & E1_MASK), 0b10000111'11111111); 50 | } 51 | 52 | // Check which bits in GP0_E1 are changed by Textured Polygon draw commands 53 | // vv - These two bits can be set via GP0_E1, but not via draw command 54 | // 0b10000111'11111111 55 | void testTexturedPolygons() { 56 | allowTextureDisable(false); 57 | writeGP0(0xe1, 0x000); 58 | drawTexturedPolygon(0xffff); 59 | 60 | assertEquals((ReadGPUstat() & E1_MASK), 0b0000001'11111111); 61 | } 62 | 63 | // Check which bits in GP0_E1 are changed by Textured Polygon draw commands (Texture Disable allowed) 64 | void testTexturedPolygonsTextureDisable() { 65 | allowTextureDisable(true); 66 | writeGP0(0xe1, 0x000); 67 | drawTexturedPolygon(0xffff); 68 | 69 | assertEquals((ReadGPUstat() & E1_MASK), 0b10000001'11111111); 70 | } 71 | 72 | // Check if drawing textured polygons doesn't change other bits in E1 register 73 | void testTexturedPolygonsDoesNotChangeOtherBits() { 74 | allowTextureDisable(true); 75 | writeGP0(0xe1,0xfff); 76 | drawTexturedPolygon(0x0000); 77 | 78 | assertEquals((ReadGPUstat() & E1_MASK), 0b00000110'00000000); 79 | } 80 | 81 | // Check if write to "Texture disabled" bit in e1 is ignored when "Allow Texture Disable" is unset 82 | void testTextureDisableBitIsIgnoredWhenNotAllowed() { 83 | allowTextureDisable(false); 84 | writeGP0(0xe1, 1<<11); // Write Texture disabled bit 85 | 86 | assertEquals(ReadGPUstat() & 0b10000000'00000000, 0 << 15); 87 | } 88 | 89 | // Check if write to "Texture disabled" bit in e1 is allowed when "Allow Texture Disable" is set 90 | void testTextureDisableBitIsWrittenWhenAllowed() { 91 | allowTextureDisable(true); 92 | writeGP0(0xe1, 1<<11); 93 | 94 | assertEquals(ReadGPUstat() & 0b10000000'00000000, 1 << 15); 95 | } 96 | 97 | // Check if "Texture disabled" bit is preserved when disabling "Allow Texture Disable" 98 | // Conclusion - "Allow Texture Disable" Bit only prevents write to this bit, read is unaffected 99 | void testUnsetAllowTextureDisablePreservesBit() { 100 | allowTextureDisable(true); 101 | writeGP0(0xe1, 1<<11); 102 | allowTextureDisable(false); 103 | 104 | assertEquals(ReadGPUstat() & 0b10000000'00000000, 1 << 15); 105 | } 106 | 107 | // Check if "Texture disabled" bit is cleared after write if "Allow Texture Disable" is unset 108 | // Note - you cannot preserve this bit in e1 after write 109 | void testUnsetAllowTextureDisableClearsBitAfterWrite() { 110 | allowTextureDisable(true); 111 | writeGP0(0xe1, 1<<11); 112 | allowTextureDisable(false); 113 | writeGP0(0xe1, 0); // Clear Texture disabled bit 114 | 115 | assertEquals(ReadGPUstat() & 0b10000000'00000000, 0); 116 | } 117 | 118 | void runTests() { 119 | testWriteZerosToE1(); 120 | testWriteOnesToE1(); 121 | testWriteOnesToE1WithTextureDisable(); 122 | testTexturedPolygons(); 123 | testTexturedPolygonsTextureDisable(); 124 | testTexturedPolygonsDoesNotChangeOtherBits(); 125 | testTextureDisableBitIsIgnoredWhenNotAllowed(); 126 | testTextureDisableBitIsWrittenWhenAllowed(); 127 | testUnsetAllowTextureDisablePreservesBit(); 128 | testUnsetAllowTextureDisableClearsBitAfterWrite(); 129 | 130 | printf("Done.\n"); 131 | } 132 | 133 | int main() { 134 | initVideo(320, 240); 135 | printf("\ngpu/gp0-e1\n"); 136 | 137 | clearScreen(); 138 | writeGP0(1, 0); // Wait for gpu to complete all commands 139 | 140 | runTests(); 141 | 142 | for (;;) { 143 | VSync(false); 144 | } 145 | return 0; 146 | } 147 | -------------------------------------------------------------------------------- /gpu/lines/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define SCR_W 320 6 | #define SCR_H 240 7 | 8 | void setE1(int transparencyMode, int dithering) { 9 | DR_TPAGE e; 10 | unsigned short texpage = getTPage(/* bitcount - do not care */0, /* semi-transparency mode */ transparencyMode, /*x*/0, /*y*/0); 11 | setDrawTPage(&e, /* Drawing to display area */ 1, /* dithering */ dithering, texpage); 12 | DrawPrim(&e); 13 | } 14 | 15 | void horizontalLines(int startX, int startY) { 16 | for (int y = 0; y < 10; y++) { 17 | LINE_F2 l; 18 | setLineF2(&l); 19 | setRGB0(&l, 0, 0, 0); 20 | 21 | l.x0 = startX; 22 | l.y0 = startY + y * 8; 23 | l.x1 = startX + 80; 24 | l.y1 = startY + y * 8 + y; 25 | 26 | DrawPrim(&l); 27 | } 28 | } 29 | 30 | void verticalLines(int startX, int startY) { 31 | for (int x = 0; x < 10; x++) { 32 | LINE_F2 l; 33 | setLineF2(&l); 34 | setRGB0(&l, 0, 0, 0); 35 | 36 | l.x0 = startX + x * 8; 37 | l.y0 = startY; 38 | l.x1 = startX + x * 8 + x; 39 | l.y1 = startY + 80; 40 | 41 | DrawPrim(&l); 42 | } 43 | } 44 | 45 | void horizontalLines2(int startX, int startY) { 46 | for (int y = 0; y < 20; y++) { 47 | LINE_F2 l; 48 | setLineF2(&l); 49 | setRGB0(&l, 0, 0, 0); 50 | 51 | l.x0 = startX; 52 | l.y0 = startY + y * 4; 53 | l.x1 = startX + y; 54 | l.y1 = startY + y * 4 + 1; 55 | 56 | DrawPrim(&l); 57 | } 58 | } 59 | 60 | void flatLines(int startX, int startY) { 61 | for (int i = 0; i < 64; i++) { 62 | LINE_F2 l; 63 | setLineF2(&l); 64 | setRGB0(&l, 0xaa, 0x00, 0x00); 65 | 66 | l.x0 = startX; 67 | l.y0 = startY + i; 68 | l.x1 = startX + i; 69 | l.y1 = startY + i; 70 | 71 | DrawPrim(&l); 72 | } 73 | } 74 | 75 | void gouraudLines(int startX, int startY) { 76 | for (int i = 0; i < 64; i++) { 77 | LINE_G2 l; 78 | setLineG2(&l); 79 | setRGB0(&l, 0x00, 0x00, 0x00); 80 | setRGB1(&l, 0xff, 0x00, 0x00); 81 | 82 | l.x0 = startX; 83 | l.y0 = startY + i; 84 | l.x1 = startX + i; 85 | l.y1 = startY + i; 86 | 87 | DrawPrim(&l); 88 | } 89 | } 90 | 91 | void flatMultiLine(int startX, int startY, bool transparent) { 92 | LINE_F4 l; 93 | setLineF4(&l); 94 | setSemiTrans(&l, transparent); 95 | 96 | setRGB0(&l, 0xaa, 0, 0); 97 | 98 | l.x0 = startX; 99 | l.y0 = startY; 100 | 101 | l.x1 = startX + 32; 102 | l.y1 = startY; 103 | 104 | l.x2 = startX + 32; 105 | l.y2 = startY + 32; 106 | 107 | l.x3 = startX; 108 | l.y3 = startY; 109 | 110 | DrawPrim(&l); 111 | } 112 | 113 | void gouraudMultiLine(int startX, int startY, bool transparent) { 114 | LINE_G4 l; 115 | setLineG4(&l); 116 | setSemiTrans(&l, transparent); 117 | 118 | setRGB0(&l, 0xff, 0x00, 0x00); 119 | setRGB1(&l, 0x00, 0xff, 0x00); 120 | setRGB2(&l, 0x00, 0x00, 0xff); 121 | setRGB2(&l, 0x00, 0xff, 0xff); 122 | 123 | l.x0 = startX; 124 | l.y0 = startY; 125 | 126 | l.x1 = startX + 32; 127 | l.y1 = startY; 128 | 129 | l.x2 = startX + 32; 130 | l.y2 = startY + 32; 131 | 132 | l.x3 = startX; 133 | l.y3 = startY; 134 | 135 | DrawPrim(&l); 136 | } 137 | 138 | void circle(int cx, int cy, int scale, int segs) { 139 | const int PI = 4096/2; 140 | 141 | LINE_F2 l; 142 | 143 | setLineF2(&l); 144 | setRGB0(&l, 0, 0, 0); 145 | 146 | const int ANGLE = 2 * PI / segs; 147 | const int H_ANGLE = ANGLE / 2; 148 | for (int s = 0; s < segs; s++) { 149 | l.x0 = cx + icos(ANGLE * s - H_ANGLE) / scale; 150 | l.y0 = cy + isin(ANGLE * s - H_ANGLE) / scale; 151 | l.x1 = cx + icos(ANGLE * s + H_ANGLE) / scale; 152 | l.y1 = cy + isin(ANGLE * s + H_ANGLE) / scale; 153 | 154 | DrawPrim(&l); 155 | } 156 | } 157 | 158 | int main() { 159 | initVideo(SCR_W, SCR_H); 160 | InitGeom(); 161 | printf("\ngpu/lines\n"); 162 | 163 | for (;;) { 164 | clearScreenColor(0xff, 0xff, 0xff); 165 | 166 | // Dithering off 167 | setE1(0, 0); 168 | 169 | horizontalLines(16, 16); 170 | verticalLines(110, 16); 171 | horizontalLines2(200, 16); 172 | 173 | setE1(0, 0); 174 | flatLines(16, 100); 175 | gouraudLines(16, 166); 176 | 177 | // Dithering on 178 | setE1(0, 1); 179 | 180 | flatLines(84, 100); 181 | gouraudLines(84, 166); 182 | 183 | flatMultiLine(150, 100, false); // Opaque 184 | flatMultiLine(210, 100, true); // Transparent 185 | 186 | gouraudMultiLine(150, 140, false); // Opaque 187 | gouraudMultiLine(210, 140, true); // Transparent 188 | 189 | circle(200, 200, 140, 16); 190 | 191 | VSync(0); 192 | } 193 | return 0; 194 | } 195 | -------------------------------------------------------------------------------- /gpu/bandwidth/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define SCR_W 320 11 | #define SCR_H 240 12 | 13 | bool semitransparent = false; 14 | 15 | uint32_t getTimer() { 16 | uint32_t value = readTimer(1); 17 | if (timerDidOverflow(1)) value += 0xffff; 18 | return value; 19 | } 20 | 21 | void fillScreen() { 22 | FILL f; 23 | 24 | setFill(&f); 25 | setRGB0(&f, rand()%255, rand()%255, rand()%255); 26 | setXY0(&f, 0, 0); 27 | setWH(&f, SCR_W, SCR_H); 28 | 29 | DrawPrim(&f); 30 | } 31 | 32 | void rectScreen() { 33 | TILE t; 34 | setTile(&t); 35 | setSemiTrans(&t, semitransparent); 36 | setXY0(&t, 0, 0); 37 | setWH(&t, SCR_W, SCR_H); 38 | setRGB0(&t, rand()%255, rand()%255, rand()%255); 39 | 40 | DrawPrim(&t); 41 | } 42 | 43 | void rectTexturedScreen() { 44 | SPRT s; 45 | setSprt(&s); 46 | setSemiTrans(&s, semitransparent); 47 | setXY0(&s, 0, 0); 48 | setWH(&s, SCR_W, SCR_H); 49 | setRGB0(&s, rand()%255, rand()%255, rand()%255); 50 | setClut(&s, 768, 256); 51 | setUV0(&s, 52 | 0, 0 53 | ); 54 | 55 | DrawPrim(&s); 56 | } 57 | 58 | int xOffset = 0; 59 | 60 | void quadScreen() { 61 | POLY_F4 p; 62 | setPolyF4(&p); 63 | setSemiTrans(&p, semitransparent); 64 | setXY4(&p, 65 | xOffset + 0, 0, 66 | xOffset + SCR_W, 0, 67 | xOffset + 0, SCR_H, 68 | xOffset + SCR_W, SCR_H 69 | ); 70 | setRGB0(&p, rand()%255, rand()%255, rand()%255); 71 | 72 | DrawPrim(&p); 73 | } 74 | 75 | #define setUVWHfixed( p, _u0, _v0, _w, _h ) \ 76 | (p)->u0 = _u0, (p)->v0 = _v0, \ 77 | (p)->u1 = _u0+(_w), (p)->v1 = _v0, \ 78 | (p)->u2 = _u0, (p)->v2 = _v0+(_h), \ 79 | (p)->u3 = _u0+(_w), (p)->v3 = _v0+(_h) 80 | 81 | void quadTexturedScreen() { 82 | POLY_FT4 p; 83 | setPolyFT4(&p); 84 | setSemiTrans(&p, semitransparent); 85 | setShadeTex(&p, 1); 86 | setXY4(&p, 87 | 0, 0, 88 | SCR_W, 0, 89 | 0, SCR_H, 90 | SCR_W, SCR_H 91 | ); 92 | setTPage(&p, 2, 0, 512, 256); 93 | setClut(&p, 768, 256); 94 | setUVWHfixed(&p, 95 | 0, 0, 96 | 255, 255 97 | ); 98 | setRGB0(&p, 0x80, 0x80, 0x80);//rand()%255, rand()%255, rand()%255); 99 | 100 | DrawPrim(&p); 101 | } 102 | 103 | constexpr int callCount = 400; 104 | 105 | void calculate(const char* test, uint16_t hblanks) { 106 | const int scanlinesPerFrame = 263; 107 | const int framesPerSecond = 60; 108 | uint32_t diff = hblanks; 109 | uint32_t dt_q = (diff*1000) / (framesPerSecond*scanlinesPerFrame); 110 | uint32_t dt_r = (diff*1000) % (framesPerSecond*scanlinesPerFrame); 111 | 112 | uint32_t bytesPerFrame = SCR_W * SCR_H * 2; 113 | uint32_t bytesSum = bytesPerFrame * callCount; 114 | 115 | uint32_t megaBytesPerSecond; 116 | if (dt_q == 0) { // workaround for missing div 0 handler 117 | megaBytesPerSecond = 99999999; 118 | } else { 119 | megaBytesPerSecond = bytesSum / (dt_q*1024); 120 | } 121 | printf("%-30s dT: %5d.%-5d ms (hblanks: %5d), speed: %d MB/s\n", test, dt_q, dt_r, diff, megaBytesPerSecond); 122 | } 123 | 124 | uint16_t* buffer = (uint16_t*)0x801a0000; 125 | 126 | int main() { 127 | initVideo(SCR_W, SCR_H); 128 | SetVideoMode(MODE_NTSC); 129 | printf("\ngpu/bandwidth\n"); 130 | 131 | uint16_t oldTimer1Mode = initTimer(1, 1); // Timer1, HBlank 132 | 133 | auto test = [](const char* name, void (*func)(), bool semi = false) { 134 | clearScreen(); 135 | 136 | DrawSync(0); 137 | resetTimer(1); 138 | semitransparent = semi; 139 | for (int i = 0; i < callCount; i++) { 140 | func(); 141 | } 142 | calculate(name, getTimer()); 143 | }; 144 | 145 | EnterCriticalSection(); 146 | test("vramToCpu", []() { vramReadDMA(0, 0, SCR_W, SCR_H, buffer); }); 147 | test("cpuToVram", []() { vramWriteDMA(0, 0, SCR_W, SCR_H, buffer); }); 148 | test("vramToVram", []() { vramToVramCopy(0, 0, 320, 0, SCR_W, SCR_H); }); 149 | test("FillScreen GP0(2)", fillScreen); 150 | test("Rectangle", rectScreen, false); 151 | test("Rectangle (semitransparent)", rectScreen, true); 152 | test("Rectangle textured", rectTexturedScreen, false); 153 | test("Rectangle textured (semi)", rectTexturedScreen, true); 154 | test("Polygon quad", quadScreen, false); 155 | test("Polygon quad (semi)", quadScreen, true); 156 | test("Polygon quad textured", quadTexturedScreen, false); 157 | test("Polygon quad textured (semi)", quadTexturedScreen, true); 158 | 159 | xOffset = -SCR_W/4; 160 | test("Polygon quad (1/4 off screen)", quadScreen, false); 161 | 162 | xOffset = -SCR_W/2; 163 | test("Polygon quad (1/2 off screen)", quadScreen, false); 164 | ExitCriticalSection(); 165 | 166 | restoreTimer(1, oldTimer1Mode); 167 | 168 | printf("Done\n"); 169 | for (;;) { 170 | VSync(0); 171 | } 172 | return 0; 173 | } 174 | -------------------------------------------------------------------------------- /common/gpu.cpp: -------------------------------------------------------------------------------- 1 | #include "gpu.h" 2 | #include "dma.hpp" 3 | #include "io.h" 4 | #include 5 | 6 | DISPENV disp; 7 | DRAWENV draw; 8 | 9 | static void setResolution(int w, int h) { 10 | SetDefDispEnv(&disp, 0, 0, w, h); 11 | SetDefDrawEnv(&draw, 0, 0, 1024, 512); 12 | 13 | if (h == 480) { 14 | disp.isinter = true; // Interlace mode 15 | draw.dfe = true; // Drawing to display area (odd and even lines) 16 | } 17 | 18 | PutDispEnv(&disp); 19 | PutDrawEnv(&draw); 20 | } 21 | 22 | void initVideo(int width, int height) 23 | { 24 | ResetGraph(0); 25 | setResolution(width, height); 26 | SetDispMask(1); 27 | } 28 | 29 | void fillRect(int x, int y, int w, int h, int r, int g, int b) { 30 | FILL f; 31 | setFill(&f); 32 | setRGB0(&f, r, g, b); 33 | setXY0(&f, x, y); 34 | setWH(&f, w, h); 35 | 36 | DrawPrim(&f); 37 | } 38 | 39 | void clearScreenColor(uint8_t r, uint8_t g, uint8_t b) { 40 | fillRect(0, 0, 512, 256, r, g, b); 41 | fillRect(512, 0, 512, 256, r, g, b); 42 | fillRect(0, 256, 512, 256, r, g, b); 43 | fillRect(512, 256, 0x3f1, 256, r, g, b); 44 | } 45 | 46 | void clearScreen() { 47 | clearScreenColor(0, 0, 0); 48 | } 49 | 50 | void setMaskBitSetting(bool setBit, bool checkBit) { 51 | DR_MASK mask; 52 | setDrawMask(&mask, setBit, checkBit); 53 | DrawPrim(&mask); 54 | } 55 | 56 | void gpuNop() { 57 | writeGP0(0, 0); 58 | } 59 | 60 | void writeGP0(uint8_t cmd, uint32_t value) { 61 | DR_TPAGE p; 62 | p.code[0] = value; 63 | setlen( &p, 1 ); 64 | setcode( &p, cmd ); 65 | DrawPrim(&p); 66 | } 67 | 68 | void writeGP1(uint8_t cmd, uint32_t data) { 69 | uint32_t *GP1 = (uint32_t*)0x1f801814; 70 | (*GP1) = (cmd << 24) | (data&0xffffff); 71 | } 72 | 73 | uint32_t readGPU() { 74 | uint32_t* GPUREAD = (uint32_t*)0x1f801810; 75 | return *GPUREAD; 76 | } 77 | 78 | void vramPut(int x, int y, uint16_t pixel) { 79 | CPU2VRAM buf; 80 | setcode(&buf, 0xA0); // CPU -> VRAM 81 | setlen(&buf, 4); 82 | 83 | buf.x0 = x; // VRAM position 84 | buf.y0 = y; 85 | buf.w = 1; // Transfer size - 1x1 86 | buf.h = 1; 87 | buf.data = pixel; // pixel (lower 16bit) 88 | 89 | DrawPrim(&buf); 90 | } 91 | 92 | uint32_t vramGet(int x, int y) { 93 | VRAM2CPU buf; 94 | setcode(&buf, 0xC0); // VRAM -> CPU 95 | setlen(&buf, 3); 96 | 97 | buf.x0 = x; // VRAM position 98 | buf.y0 = y; 99 | buf.w = 1; // Transfer size - 1x1 100 | buf.h = 1; 101 | 102 | DrawPrim(&buf); 103 | 104 | writeGP1(4, 3); // DMA Direction - VRAM -> CPU 105 | 106 | // Wait for VRAM to CPU ready 107 | while ((ReadGPUstat() & (1<<27)) == 0); 108 | 109 | return readGPU(); 110 | } 111 | 112 | void vramWrite(int x, int y, int w, int h, uint16_t* ptr) { 113 | CPU2VRAM buf; 114 | setcode(&buf, 0xA0); // CPU -> VRAM 115 | setlen(&buf, 3); 116 | 117 | buf.x0 = x; 118 | buf.y0 = y; 119 | buf.w = w; 120 | buf.h = h; 121 | 122 | DrawPrim(&buf); 123 | 124 | volatile uint32_t *GP0 = (uint32_t*)0x1f801810; 125 | for (int y = 0; y VRAM 138 | setlen(&buf, 3); 139 | 140 | buf.x0 = x; 141 | buf.y0 = y; 142 | buf.w = w; 143 | buf.h = h; 144 | 145 | DrawPrim(&buf); 146 | 147 | writeGP1(4, 2); // DMA Direction - CPU -> VRAM 148 | 149 | using namespace DMA; 150 | DMA::masterEnable(Channel::GPU, true); 151 | DMA::waitForChannel(Channel::GPU); 152 | 153 | write32(baseAddr(Channel::GPU), MADDR((uint32_t)ptr)._reg); 154 | write32(blockAddr(Channel::GPU), BCR::mode1(0x10, w * h / 0x10 / 2)._reg); 155 | write32(controlAddr(Channel::GPU), CHCR::VRAMwrite()._reg); 156 | 157 | DMA::waitForChannel(Channel::GPU); 158 | } 159 | 160 | void vramReadDMA(int x, int y, int w, int h, uint16_t* ptr) { 161 | VRAM2CPU buf; 162 | setcode(&buf, 0xC0); // VRAM -> CPU 163 | setlen(&buf, 3); 164 | 165 | buf.x0 = x; 166 | buf.y0 = y; 167 | buf.w = w; 168 | buf.h = h; 169 | 170 | DrawPrim(&buf); 171 | 172 | writeGP1(4, 3); // DMA Direction - VRAM -> CPU 173 | 174 | // Wait for VRAM to CPU ready 175 | while ((ReadGPUstat() & (1<<27)) == 0); 176 | 177 | using namespace DMA; 178 | DMA::masterEnable(Channel::GPU, true); 179 | DMA::waitForChannel(Channel::GPU); 180 | 181 | write32(baseAddr(Channel::GPU), MADDR((uint32_t)ptr)._reg); 182 | write32(blockAddr(Channel::GPU), BCR::mode1(0x10, w * h / 0x10 / 2)._reg); 183 | write32(controlAddr(Channel::GPU), CHCR::VRAMread()._reg); 184 | 185 | DMA::waitForChannel(Channel::GPU); 186 | } 187 | 188 | void vramToVramCopy(int srcX, int srcY, int dstX, int dstY, int w, int h) 189 | { 190 | VRAM2VRAM buf; 191 | setcode(&buf, 0x80); // VRAM -> VRAM 192 | setlen(&buf, 4); 193 | 194 | buf.x0 = srcX; 195 | buf.y0 = srcY; 196 | buf.x1 = dstX; 197 | buf.y1 = dstY; 198 | buf.w = w; 199 | buf.h = h; 200 | 201 | DrawPrim(&buf); 202 | } 203 | -------------------------------------------------------------------------------- /dma/chopping/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace DMA; 11 | 12 | uint8_t* buffer; 13 | const int VRAM_WIDTH = 1024; 14 | const int SCREEN_WIDTH = 640; 15 | const int SCREEN_HEIGHT = 480; 16 | 17 | const int W = 64; 18 | const int H = 64; 19 | const int TRANSFER_SIZE = W * H * 2; 20 | 21 | int position = 0; 22 | 23 | void beginCpuToVramTransfer() { 24 | writeGP1(1, 0); // Reset command buffer 25 | DrawSync(0); // Wait for completion 26 | 27 | uint16_t x = position % (VRAM_WIDTH / W); 28 | uint16_t y = position / (VRAM_WIDTH / W); 29 | 30 | CPU2VRAM buf; 31 | setcode(&buf, 0xA0); // CPU -> VRAM 32 | setlen(&buf, 3); 33 | setXY0(&buf, x * W, y * H); 34 | setWH(&buf, W, H); 35 | DrawPrim(&buf); 36 | 37 | writeGP1(4, 2); // DMA Direction - CPU -> VRAM 38 | 39 | position++; 40 | } 41 | 42 | CHCR control; // must be global for `measure` 43 | 44 | void prepareSyncMode1(int blockSize) { 45 | beginCpuToVramTransfer(); 46 | 47 | auto addr = MADDR((uint32_t)buffer); 48 | BCR block = BCR::mode1(blockSize, TRANSFER_SIZE / blockSize / 4); 49 | 50 | control = CHCR::VRAMwrite(); 51 | control.syncMode = CHCR::SyncMode::syncBlockToDmaRequests; 52 | 53 | waitForChannel(Channel::GPU); 54 | 55 | write32(CH_BASE_ADDR + 0x10 * (int)Channel::GPU, addr._reg); 56 | write32(CH_BLOCK_ADDR + 0x10 * (int)Channel::GPU, block._reg); 57 | } 58 | 59 | void prepareSyncMode0() { 60 | beginCpuToVramTransfer(); 61 | 62 | auto addr = MADDR((uint32_t)buffer); 63 | BCR block = BCR::mode0(TRANSFER_SIZE / 4); 64 | 65 | control = CHCR::VRAMwrite(); 66 | control.syncMode = CHCR::SyncMode::startImmediately; 67 | 68 | waitForChannel(Channel::GPU); 69 | 70 | write32(CH_BASE_ADDR + 0x10 * (int)Channel::GPU, addr._reg); 71 | write32(CH_BLOCK_ADDR + 0x10 * (int)Channel::GPU, block._reg); 72 | } 73 | 74 | inline void startDmaTransfer() { 75 | write32(CH_CONTROL_ADDR + 0x10 * (int)Channel::GPU, control._reg); 76 | } 77 | 78 | void generateData() { 79 | for (int i = 0; i>8) & 0xff; 83 | } 84 | } 85 | 86 | void runDma() { 87 | const auto cycles = measure([]() { 88 | startDmaTransfer(); 89 | waitForChannel(Channel::GPU); 90 | }); 91 | 92 | uint32_t gpustat = ReadGPUstat(); 93 | bool gpuBusy = !(gpustat & (1<<26)); 94 | 95 | printf("took %5d CPU cycles. %s\n", cycles, gpuBusy ? "(GPU busy)" : ""); 96 | } 97 | 98 | void runTests() { 99 | // SyncMode 1 100 | for (int blockSize = 1; blockSize <= 65; blockSize++) { 101 | if (blockSize == 65) blockSize = 128; 102 | generateData(); 103 | prepareSyncMode1(blockSize); 104 | 105 | printf("DMA2, SyncMode: %d, %4d bytes, blockSize: %3d ... ", 106 | (int)control.syncMode, 107 | TRANSFER_SIZE, 108 | blockSize 109 | ); 110 | 111 | runDma(); 112 | } 113 | 114 | // SyncMode 0 without chopping 115 | { 116 | generateData(); 117 | prepareSyncMode0(); 118 | 119 | printf("DMA2, SyncMode: %d, %4d bytes, no chopping ... ", 120 | (int)control.syncMode, 121 | TRANSFER_SIZE 122 | ); 123 | 124 | runDma(); 125 | } 126 | 127 | // SyncMode 0 with chopping 128 | for (int dmaWindowSize = 0; dmaWindowSize < 8; dmaWindowSize++) { 129 | for (int cpuWindowSize = 0; cpuWindowSize < 8; cpuWindowSize++) { 130 | generateData(); 131 | prepareSyncMode0(); 132 | control.choppingEnable = 1; 133 | control.choppingDmaWindowSize = dmaWindowSize; 134 | control.choppingCpuWindowSize = cpuWindowSize; 135 | 136 | printf("DMA2, SyncMode: %d, %4d bytes, dmaWindow: %3d words, cpuWindow: %3d clks ... ", 137 | (int)control.syncMode, 138 | TRANSFER_SIZE, 139 | 1 << control.choppingDmaWindowSize, 140 | 1 << control.choppingCpuWindowSize 141 | ); 142 | 143 | runDma(); 144 | } 145 | } 146 | 147 | writeGP1(1, 0); 148 | DrawSync(0); 149 | } 150 | 151 | int main() { 152 | SetVideoMode(MODE_NTSC); 153 | initVideo(SCREEN_WIDTH, SCREEN_HEIGHT); 154 | printf("\ndma/chopping (DMA Channel 2 CPU->VRAM, chopping test)\n"); 155 | 156 | clearScreen(); 157 | seedMT(1337); 158 | EnterCriticalSection(); 159 | 160 | masterEnable(Channel::MDECin, false); 161 | masterEnable(Channel::MDECout, false); 162 | masterEnable(Channel::GPU, true); 163 | masterEnable(Channel::CDROM, false); 164 | masterEnable(Channel::SPU, false); 165 | masterEnable(Channel::PIO, false); 166 | masterEnable(Channel::OTC, false); 167 | 168 | buffer = (uint8_t*)malloc(TRANSFER_SIZE); 169 | 170 | runTests(); 171 | 172 | printf("Done.\n"); 173 | 174 | masterEnable(Channel::GPU, false); 175 | ExitCriticalSection(); 176 | 177 | for (;;) { 178 | VSync(false); 179 | } 180 | return 0; 181 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ps1-tests 2 | 3 | Collection of PlayStation 1 tests for emulator development and hardware verification 4 | 5 | # Download 6 | 7 | [Latest release](https://github.com/JaCzekanski/ps1-tests/releases/latest) 8 | 9 | ## Tests 10 | 11 | ### CD-ROM 12 | 13 | Name | Description 14 | -------------------------|------------ 15 | disc-swap | Program to observe behavior of CD-ROM controller when opening/closing the drive cover. 16 | getloc | Program to test the seeking/reading stat bits of the controller and Getloc commands 17 | terminal | UART terminal for low level CDROM interaction 18 | 19 | ### CPU 20 | 21 | Name | Description 22 | -------------------------|------------ 23 | access-time | Test CPU access time to different parts of memory map 24 | code-in-io | Check whether code execution from Scratchpad as various IO ports is possible 25 | cop | Check how CPU behave when accessing missing/disabled coprocessors 26 | io-access-bitwidth | Test how writes with different bitwidths behaves for different io devices 27 | 28 | ### DMA 29 | 30 | Name | Description 31 | -------------------------|------------ 32 | chain-looping | Self referencing GPU OT chain test 33 | chopping | Check SyncMode0 chopping behaviour using GPU VRAM DMA 34 | otc-test | DMA Channel 6 (OTC aka Ordering Table clear) unit tests 35 | 36 | ### GPU 37 | 38 | Name | Description 39 | -------------------------|------------ 40 | animated-triangle | Double buffered rotating triangle 41 | bandwidth | Measure GPU/VRAM bandwidth 42 | benchmark | GPU test to benchmark rasterizer for various commands 43 | clut-cache | CLUT (Palette) cache behavior test 44 | clipping | Test Draw Area/Clipping GP0(0xE3), GP0(0xE4) using rectangle and quad 45 | gp0-e1 | Check if GP0_E1, GPUSTAT and polygon render uses the same register internally 46 | gpustat | Check GPUSTAT busy bits during rendering in different modes (CPU, linked list DMA, sync block DMA (with GPU DMA direction 1 and 2)) 47 | lines | Draws lines using different modes - for verifying Bresenham implementation, color blending, polyline handling 48 | mask-bit | Check Mask bit behavior during VRAM copy operations 49 | quad | Semi-transparent polygon commands - for testing fill rules and transparency handling 50 | rectangles | Draws all combinations of Rectangle commands 51 | texture-flip | Check gp0_e1.13 and gp0_e1.12 texture flip behaviour 52 | texture-overflow | Draws textured rectangle with UV overflowing VRAM width 53 | transparency | Draws rectangles with 4 semi-transparent blending modes 54 | triangle | Draws Gouroud shaded equilateral triangle 55 | uv-interpolate | Check uv/color interpolation accuracy by drawing quads with width in range of 0 - 255 56 | vram-to-vram-overlap | Test GP0(80) VRAM-VRAM copy behaviour in overlapping rects 57 | version-detect | Uses GP1(0x10) and GP0(0xE1) to detect GPU version 58 | 59 | ### GTE 60 | 61 | Name | Description 62 | -------------------------|------------ 63 | gte-fuzz | Executes GTE opcodes with random parameters, can be used to verify against real console 64 | test-all | Test all register/opcodes, generated by gte-fuzz 65 | 66 | ### MDEC 67 | 68 | Name | Description 69 | -------------------------|------------ 70 | 4bit | ♥ Decode single 8x8 block in 4bit mode (sanitized bitstream) 71 | 8bit | ♥ Decode single 8x8 block in 8bit mode (sanitized bitstream) 72 | frame | Framework for testing MDEC decoder, default values uses DMA for all transfers, but it can be reconfigured for PIO as well (requires manual recompilation). Two executables for 15 and 24bit modes (using DMA for MDECin, MDECout and GPU) 73 | movie | Simple MDEC in-ram bitstream player (currently 200 256x240 frames at @ 10FPS) 74 | step-by-step-log | Manually feeds the MDEC data and monitors the MDEC status register at every step. 75 | 76 | ### SPU 77 | 78 | Name | Description 79 | -------------------------|------------ 80 | memory-transfer | Test DMA and regular IO transfers to SPU RAM 81 | ram-sandbox | SPU memory access sandbox (used for memory-transfer test development) 82 | stereo | Play samples on first two voices 83 | test | Check SPU behavior (data is lost randomly on 32bit access, ok on 16bit) 84 | toolbox | SPU register preview and simple voice playback tool 85 | 86 | ### Timer 87 | 88 | Name | Description 89 | -------------------------|------------ 90 | timers | Run Timer0,1,2 using various clock sources and sync modes and time them using busy loops and vblank interrupt 91 | 92 | Note: Make sure your PS-EXE loaded does set default value for Stack Pointer - these .exes has SP set to 0. 93 | 94 | ## Tools 95 | 96 | Name | Description 97 | -------------------------|------------ 98 | diffvram | Diff two images and write diff png if image contents aren't exactly the same 99 | 100 | ## Examples 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | ## Build 112 | 113 | ``` 114 | docker run -it -v $(pwd):/build jaczekanski/psn00bsdk:latest make 115 | ``` 116 | -------------------------------------------------------------------------------- /cdrom/volume-regs/cd.s: -------------------------------------------------------------------------------- 1 | .set noreorder 2 | 3 | .include "hwregs_a.h" 4 | 5 | .section .text 6 | 7 | .global _cd_init_mine 8 | .type _cd_init_mine, @function 9 | _cd_init_mine: 10 | 11 | addiu $sp, -4 12 | sw $ra, 0($sp) 13 | 14 | jal EnterCriticalSection 15 | nop 16 | 17 | lui $a3, IOBASE # Acknowledge all CD IRQs 18 | li $v0, 1 19 | sb $v0, CD_REG0($a3) 20 | li $v0, 0x1f 21 | sb $v0, CD_REG3($a3) 22 | sb $v0, CD_REG2($a3) # Enable all IRQs 23 | 24 | sb $0 , CD_REG0($a3) 25 | sb $0 , CD_REG3($a3) 26 | 27 | li $v0, 0x1325 28 | sw $v0, COM_DELAY($a3) 29 | 30 | la $a1, _cd_handler 31 | jal InterruptCallback 32 | li $a0, 2 33 | 34 | # Clear a bunch of stats 35 | la $v0, _cd_ack_wait 36 | sb $0 , 0($v0) 37 | la $v0, _cd_complt_wait 38 | sb $0 , 0($v0) 39 | la $v0, _cd_last_cmd 40 | sb $0 , 0($v0) 41 | la $v0, _cd_last_mode 42 | sb $0 , 0($v0) 43 | la $v0, _cd_last_int 44 | sb $0 , 0($v0) 45 | 46 | la $v0, _cd_result_ptr 47 | sw $0 , 0($v0) 48 | 49 | # Clear callback hooks 50 | la $v0, _cd_callback_int1_data 51 | sw $0 , 0($v0) 52 | la $v0, _cd_callback_int4 53 | sw $0 , 0($v0) 54 | 55 | la $v0, _cd_read_cb 56 | sw $0 , 0($v0) 57 | 58 | lw $v0, DPCR($a3) 59 | li $v1, 0xB000 60 | or $v0, $v1 61 | sw $v0, DPCR($a3) 62 | 63 | jal ExitCriticalSection 64 | nop 65 | 66 | lw $ra, 0($sp) 67 | addiu $sp, 4 68 | jr $ra 69 | nop 70 | 71 | .type _cd_handler, @function 72 | _cd_handler: 73 | 74 | addiu $sp, -4 75 | sw $ra, 0($sp) 76 | 77 | lui $a3, IOBASE # Print out IRQ number 78 | li $v0, 1 79 | sb $v0, CD_REG0($a3) 80 | 81 | lbu $v0, CD_REG3($a3) 82 | nop 83 | andi $v0, 0x7 84 | 85 | la $v1, _cd_last_int # Save last IRQ value 86 | sb $v0, 0($v1) 87 | 88 | bne $v0, 0x1, .Lno_data 89 | nop 90 | 91 | sb $0 , CD_REG0($a3) # Load data FIFO on INT1 92 | li $v1, 0x80 93 | sb $v1, CD_REG3($a3) 94 | 95 | .Lno_data: 96 | 97 | li $v1, 1 98 | sb $v1, CD_REG0($a3) # Clear CD interrupt and parameter FIFO 99 | li $v1, 0x5f 100 | sb $v1, CD_REG3($a3) 101 | li $v1, 0x40 102 | sb $v1, CD_REG3($a3) 103 | 104 | li $v1, 0 # Delay when clearing parameter FIFO 105 | sw $v1, 0($0) 106 | li $v1, 1 107 | sw $v1, 0($0) 108 | li $v1, 2 109 | sw $v1, 0($0) 110 | li $v1, 3 111 | sw $v1, 0($0) 112 | 113 | beq $v0, 0x1, .Lirq_1 # Data ready 114 | nop 115 | beq $v0, 0x2, .Lirq_2 # Command finish 116 | nop 117 | beq $v0, 0x3, .Lirq_3 # Acknowledge 118 | nop 119 | beq $v0, 0x4, .Lirq_4 # Data/track end 120 | nop 121 | beq $v0, 0x5, .Lirq_5 # Error 122 | nop 123 | 124 | b .Lirq_misc 125 | nop 126 | 127 | .Lirq_1: # Data ready 128 | 129 | jal _cd_fetch_result 130 | nop 131 | 132 | la $v0, _cd_callback_int1_data 133 | lw $v0, 0($v0) 134 | nop 135 | beqz $v0, .Lirq_misc 136 | nop 137 | 138 | la $a0, _cd_last_int 139 | lbu $a0, 0($a0) 140 | la $a1, _cd_result_ptr 141 | lw $a1, 0($a1) 142 | 143 | jalr $v0 144 | addiu $sp, -16 145 | addiu $sp, 16 146 | 147 | b .Lirq_misc 148 | nop 149 | 150 | .Lirq_2: # Command complete 151 | 152 | jal _cd_fetch_result 153 | nop 154 | 155 | la $v0, _cd_complt_wait 156 | sb $0 , 0($v0) 157 | 158 | la $v0, _cd_sync_cb 159 | lw $v0, 0($v0) 160 | nop 161 | beqz $v0, .Lirq_misc 162 | nop 163 | 164 | la $a0, _cd_last_int 165 | lbu $a0, 0($a0) 166 | la $a1, _cd_result_ptr 167 | lw $a1, 0($a1) 168 | jalr $v0 169 | addiu $sp, -16 170 | addiu $sp, 16 171 | 172 | b .Lirq_misc 173 | nop 174 | 175 | .Lirq_3: # Command acknowledge 176 | 177 | jal _cd_fetch_result 178 | nop 179 | 180 | la $v0, _cd_ack_wait 181 | sb $0 , 0($v0) 182 | 183 | b .Lirq_misc 184 | nop 185 | 186 | .Lirq_4: 187 | 188 | jal _cd_fetch_result 189 | nop 190 | 191 | la $v0, _cd_callback_int4 192 | lw $v0, 0($v0) 193 | nop 194 | beqz $v0, .Lirq_misc 195 | nop 196 | 197 | jalr $v0 198 | addiu $sp, -16 199 | addiu $sp, 16 200 | 201 | b .Lirq_misc 202 | nop 203 | 204 | .Lirq_5: # Error 205 | 206 | jal _cd_fetch_result 207 | nop 208 | 209 | la $v0, _cd_complt_wait 210 | lbu $v0, 0($v0) 211 | nop 212 | beqz $v0, .Lno_complete 213 | nop 214 | 215 | la $v0, _cd_sync_cb 216 | lw $v0, 0($v0) 217 | nop 218 | beqz $v0, .Lno_complete 219 | nop 220 | 221 | li $a0, 0x05 # CdlDiskError 222 | la $a1, _cd_result_ptr 223 | lw $a1, 0($a1) 224 | jalr $v0 225 | addiu $sp, -16 226 | addiu $sp, 16 227 | 228 | .Lno_complete: 229 | 230 | la $v0, _cd_complt_wait 231 | sb $0 , 0($v0) 232 | la $v0, _cd_ack_wait 233 | sb $0 , 0($v0) 234 | 235 | la $v0, _cd_callback_int1_data 236 | lw $v0, 0($v0) 237 | nop 238 | beqz $v0, .Lirq_misc 239 | nop 240 | 241 | li $a0, 0x05 # CdlDiskError 242 | la $a1, _cd_result_ptr 243 | lw $a1, 0($a1) 244 | 245 | jalr $v0 246 | addiu $sp, -16 247 | addiu $sp, 16 248 | 249 | .Lirq_misc: 250 | 251 | lw $ra, 0($sp) 252 | addiu $sp, 4 253 | jr $ra 254 | nop 255 | 256 | 257 | _cd_fetch_result: 258 | 259 | lui $a3, IOBASE 260 | 261 | la $a0, _cd_status 262 | lbu $v0, CD_REG1($a3) 263 | 264 | la $v1, _cd_last_int 265 | lbu $v1, 0($v1) 266 | nop 267 | beq $v1, 0x2, .Lirq2_checks 268 | nop 269 | 270 | # IRQ3 checks 271 | 272 | la $v1, _cd_last_cmd 273 | lbu $v1, 0($v1) 274 | nop 275 | beq $v1, 0x10, .Lskip_status 276 | nop 277 | beq $v1, 0x11, .Lskip_status 278 | nop 279 | 280 | b .Lwrite_status 281 | nop 282 | 283 | # IRQ2 checks 284 | 285 | .Lirq2_checks: 286 | 287 | la $v1, _cd_last_cmd 288 | lbu $v1, 0($v1) 289 | nop 290 | beq $v1, 0x1D, .Lskip_status 291 | nop 292 | 293 | .Lwrite_status: 294 | 295 | sb $v0, 0($a0) 296 | 297 | .Lskip_status: 298 | 299 | la $a0, _cd_result_ptr 300 | lw $a0, 0($a0) 301 | nop 302 | beqz $a0, .Lno_result 303 | nop 304 | sb $v0, 0($a0) 305 | addiu $a0, 1 306 | 307 | .Lread_futher_result: 308 | 309 | lbu $v0, CD_REG0($a3) 310 | nop 311 | andi $v0, 0x20 312 | beqz $v0, .Lno_result 313 | nop 314 | 315 | lbu $v0, CD_REG1($a3) 316 | lbu $v1, CD_REG0($a3) 317 | sb $v0, 0($a0) 318 | andi $v1, 0x20 319 | bnez $v1, .Lread_futher_result 320 | addiu $a0, 1 321 | 322 | .Lno_result: 323 | 324 | jr $ra 325 | nop 326 | -------------------------------------------------------------------------------- /cpu/cop/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | cop0::STATUS readCop0Status() { 9 | cop0::STATUS status; 10 | __asm__ __volatile__("mfc0 %0, $12" : "=r"(status._reg)); 11 | return status; 12 | } 13 | 14 | void setCop0Status(cop0::STATUS status) { 15 | __asm__ __volatile__("mtc0 %0, $12" : "+r"(status._reg)); 16 | } 17 | 18 | uint32_t cop0_valid() { 19 | uint32_t val; 20 | __asm__ __volatile__("mfc0 %0, $15" : "=r"(val)); 21 | return val; 22 | } 23 | 24 | void cop0_invalid() { 25 | __asm__ __volatile__(".word ((16 << 26) | (0x1f << 21))"); // cop0 0x1f 26 | } 27 | 28 | uint32_t swc0() { 29 | uint32_t val = 0; 30 | __asm__ __volatile__("swc0 $1, 0( %0 )" : : "r"( val ) : "memory" ); 31 | return val; 32 | } 33 | 34 | 35 | void cop1_valid() { 36 | __asm__ __volatile__(".word (17 << 26)"); // cop1 000000 37 | } 38 | 39 | uint32_t cop2_valid() { 40 | uint32_t val = 0; 41 | __asm__ __volatile__("mfc2 %0, $1" : "=r"(val)); 42 | return val; 43 | } 44 | 45 | void cop2_invalid() { 46 | __asm__ __volatile__(".word ((18 << 26) | (0x1f << 21))"); // cop2 0x1f 47 | } 48 | 49 | 50 | uint32_t swc2() { 51 | uint32_t val = 0; 52 | __asm__ __volatile__("swc2 $1, 0( %0 )" : : "r"( val ) : "memory" ); 53 | return val; 54 | } 55 | 56 | void cop3_valid() { 57 | __asm__ __volatile__(".word (19 << 26)"); // cop3 000000 58 | } 59 | 60 | uint32_t swc3() { 61 | uint32_t val = 0; 62 | __asm__ __volatile__("swc3 $1, 0( %0 )" : : "r"( val ) : "memory" ); 63 | return val; 64 | } 65 | 66 | 67 | template 68 | void setCop() { 69 | EnterCriticalSection(); 70 | 71 | auto status = readCop0Status(); 72 | if constexpr (cop == 0) status.cop0Enable = enabled; 73 | else if constexpr (cop == 1) status.cop1Enable = enabled; 74 | else if constexpr (cop == 2) status.cop2Enable = enabled; 75 | else if constexpr (cop == 3) status.cop3Enable = enabled; 76 | 77 | setCop0Status(status); 78 | 79 | ExitCriticalSection(); 80 | } 81 | 82 | template 83 | void enableCop() { 84 | setCop(); 85 | } 86 | 87 | template 88 | void disableCop() { 89 | setCop(); 90 | } 91 | 92 | // COP0 93 | void testCop0Disabled() { 94 | disableCop<0>(); // cop0Enable toggles Kernel/User availability, cannot be disabled 95 | 96 | cop0_valid(); 97 | assertFalse(wasExceptionThrown()); 98 | } 99 | 100 | void testCop0Enabled() { 101 | enableCop<0>(); 102 | 103 | cop0_valid(); 104 | assertFalse(wasExceptionThrown()); 105 | } 106 | 107 | void testCop0InvalidOpcode() { 108 | enableCop<0>(); 109 | 110 | cop0_invalid(); 111 | assertFalse(wasExceptionThrown()); // ???? 112 | } 113 | 114 | void testSwc0Disabled() { 115 | disableCop<0>(); 116 | 117 | swc0(); 118 | assertTrue(wasExceptionThrown()); 119 | } 120 | 121 | void testSwc0Enabled() { 122 | enableCop<0>(); 123 | 124 | swc0(); 125 | assertFalse(wasExceptionThrown()); 126 | } 127 | 128 | // COP1 129 | void testCop1Disabled() { 130 | disableCop<1>(); 131 | 132 | cop1_valid(); 133 | assertTrue(wasExceptionThrown()); 134 | } 135 | 136 | void testCop1Enabled() { 137 | enableCop<1>(); 138 | 139 | cop1_valid(); 140 | assertFalse(wasExceptionThrown()); 141 | } 142 | 143 | // COP2 144 | void testCop2Disabled() { 145 | disableCop<2>(); 146 | 147 | cop2_valid(); 148 | assertTrue(wasExceptionThrown()); 149 | } 150 | 151 | void testCop2Enabled() { 152 | enableCop<2>(); 153 | 154 | cop2_valid(); 155 | assertFalse(wasExceptionThrown()); 156 | } 157 | 158 | void testCop2InvalidOpcode() { 159 | enableCop<2>(); 160 | 161 | cop2_invalid(); 162 | assertFalse(wasExceptionThrown()); // ?? It should throw? 163 | } 164 | 165 | void testSwc2Disabled() { 166 | disableCop<2>(); 167 | 168 | swc2(); 169 | assertTrue(wasExceptionThrown()); 170 | } 171 | 172 | void testSwc2Enabled() { 173 | enableCop<2>(); 174 | 175 | swc2(); 176 | assertFalse(wasExceptionThrown()); 177 | } 178 | 179 | // COP3 180 | void testCop3Disabled() { 181 | disableCop<3>(); 182 | 183 | cop3_valid(); 184 | assertTrue(wasExceptionThrown()); 185 | } 186 | 187 | void testCop3Enabled() { 188 | enableCop<3>(); 189 | 190 | cop3_valid(); 191 | assertFalse(wasExceptionThrown()); 192 | } 193 | 194 | void testSwc3Disabled() { 195 | disableCop<3>(); 196 | 197 | swc3(); 198 | assertTrue(wasExceptionThrown()); 199 | } 200 | 201 | void testSwc3Enabled() { 202 | enableCop<3>(); 203 | 204 | swc3(); 205 | assertFalse(wasExceptionThrown()); 206 | } 207 | 208 | 209 | void testDisabledCoprocessorThrowsCoprocessorUnusable() { 210 | using Exception = cop0::CAUSE::Exception; 211 | disableCop<3>(); 212 | 213 | cop3_valid(); 214 | assertEquals(getExceptionType(), Exception::coprocessorUnusable); 215 | } 216 | 217 | 218 | void runTests() { 219 | testCop0Disabled(); 220 | testCop0Enabled(); 221 | testCop0InvalidOpcode(); 222 | testSwc0Disabled(); 223 | testSwc0Enabled(); 224 | 225 | testCop1Disabled(); 226 | testCop1Enabled(); 227 | 228 | testCop2Disabled(); 229 | testCop2Enabled(); 230 | testCop2InvalidOpcode(); 231 | testSwc2Disabled(); 232 | testSwc2Enabled(); 233 | 234 | testCop3Disabled(); 235 | testCop3Enabled(); 236 | testSwc3Disabled(); 237 | testSwc3Enabled(); 238 | 239 | testDisabledCoprocessorThrowsCoprocessorUnusable(); 240 | 241 | printf("Done.\n"); 242 | } 243 | 244 | int main() { 245 | initVideo(320, 240); 246 | printf("\ncpu/cop\n"); 247 | 248 | clearScreen(); 249 | 250 | EnterCriticalSection(); 251 | hookUnresolvedExceptionHandler(exceptionHandler); 252 | ExitCriticalSection(); 253 | 254 | wasExceptionThrown(); //Just to clear the flag 255 | runTests(); 256 | 257 | for (;;) { 258 | VSync(false); 259 | } 260 | return 0; 261 | } -------------------------------------------------------------------------------- /mdec/step-by-step-log/symbols.h: -------------------------------------------------------------------------------- 1 | unsigned char symbols_mdec[] = { 2 | 0x00, 0x04, 0x00, 0xf8, 0x00, 0x04, 0x00, 0xf8, 0x00, 0x06, 0x00, 0xf8, 3 | 0xfe, 0x07, 0xed, 0x07, 0x24, 0x00, 0xfb, 0x03, 0x31, 0x00, 0x1d, 0x04, 4 | 0x06, 0x00, 0x23, 0x00, 0x35, 0x00, 0x04, 0x00, 0xb9, 0x03, 0x08, 0x00, 5 | 0x7f, 0x00, 0xe6, 0x07, 0xf6, 0x03, 0xd1, 0x03, 0xf2, 0x03, 0xe3, 0x03, 6 | 0x43, 0x00, 0x05, 0x00, 0xa8, 0x03, 0xf9, 0x03, 0x92, 0x03, 0xff, 0x03, 7 | 0x56, 0x00, 0x12, 0x04, 0x02, 0x00, 0x25, 0x00, 0x1a, 0x00, 0x1e, 0x00, 8 | 0x0a, 0x00, 0x11, 0x00, 0xf5, 0x03, 0xc0, 0x03, 0xf8, 0x03, 0xcb, 0x03, 9 | 0x01, 0x00, 0xb9, 0x03, 0xfa, 0x03, 0x08, 0x00, 0xe8, 0x03, 0xfb, 0x03, 10 | 0xf2, 0x03, 0xf0, 0x03, 0xf7, 0x03, 0x10, 0x00, 0xd9, 0x03, 0x02, 0x00, 11 | 0xc9, 0x03, 0x06, 0x00, 0xed, 0x03, 0x03, 0x00, 0x03, 0x00, 0xf7, 0x03, 12 | 0xfd, 0x03, 0x07, 0x00, 0x08, 0x00, 0x0c, 0x00, 0x0c, 0x00, 0xf7, 0x03, 13 | 0x8e, 0x07, 0x18, 0x01, 0x44, 0x00, 0x64, 0x03, 0x2b, 0x00, 0x15, 0x00, 14 | 0x15, 0x00, 0xfd, 0x03, 0xcd, 0x03, 0xdd, 0x03, 0x09, 0x00, 0x17, 0x00, 15 | 0x40, 0x00, 0x02, 0x00, 0x10, 0x00, 0x0e, 0x00, 0x01, 0x00, 0x0f, 0x00, 16 | 0x2d, 0x00, 0xd1, 0x03, 0x07, 0x00, 0xfb, 0x03, 0xe2, 0x03, 0xdb, 0x03, 17 | 0x05, 0x00, 0x0d, 0x00, 0x01, 0x00, 0x06, 0x00, 0x28, 0x00, 0xff, 0x03, 18 | 0x0a, 0x00, 0x04, 0x00, 0x14, 0x00, 0x02, 0x00, 0x05, 0x00, 0xf6, 0x03, 19 | 0x09, 0x00, 0xf7, 0x03, 0x23, 0x00, 0x09, 0x00, 0x03, 0x00, 0x1a, 0x00, 20 | 0x07, 0x00, 0xf6, 0x03, 0x10, 0x00, 0x0d, 0x00, 0x0c, 0x00, 0xf4, 0x03, 21 | 0xf4, 0x03, 0xfd, 0x03, 0x03, 0x00, 0x19, 0x00, 0xf3, 0x03, 0x05, 0x00, 22 | 0xf8, 0x03, 0x01, 0x00, 0xf8, 0x03, 0x1f, 0x00, 0xfe, 0x03, 0xfd, 0x03, 23 | 0xfa, 0x03, 0x01, 0x00, 0xfc, 0x03, 0x01, 0x00, 0x8e, 0x07, 0x84, 0x03, 24 | 0x44, 0x00, 0x64, 0x03, 0xf0, 0x03, 0x6e, 0x03, 0x60, 0x00, 0xe5, 0x03, 25 | 0xef, 0x03, 0xdd, 0x03, 0x09, 0x00, 0xd8, 0x03, 0x54, 0x00, 0x11, 0x00, 26 | 0x90, 0x03, 0x53, 0x00, 0xf2, 0x03, 0xf1, 0x03, 0x14, 0x00, 0x34, 0x00, 27 | 0x07, 0x00, 0xfb, 0x03, 0x1d, 0x00, 0x0c, 0x00, 0x12, 0x00, 0x0d, 0x00, 28 | 0x0d, 0x00, 0xd4, 0x03, 0x3f, 0x00, 0xfb, 0x03, 0xf6, 0x03, 0xf7, 0x03, 29 | 0xdd, 0x03, 0x20, 0x00, 0xfb, 0x03, 0xf6, 0x03, 0xf6, 0x03, 0xf2, 0x03, 30 | 0xf0, 0x03, 0x09, 0x00, 0x04, 0x00, 0xec, 0x03, 0x0a, 0x00, 0xfd, 0x03, 31 | 0xef, 0x03, 0x08, 0x00, 0xfb, 0x03, 0xfc, 0x03, 0xf2, 0x03, 0xe7, 0x03, 32 | 0x03, 0x00, 0x14, 0x00, 0x04, 0x00, 0x0e, 0x00, 0xf2, 0x03, 0xec, 0x03, 33 | 0xfd, 0x03, 0xff, 0x03, 0x0f, 0x00, 0x08, 0x00, 0xfe, 0x03, 0xff, 0x03, 34 | 0x04, 0x00, 0x02, 0x00, 0x00, 0x04, 0x00, 0xf8, 0x00, 0x04, 0x00, 0xf8, 35 | 0x00, 0x06, 0x00, 0xf8, 0xbf, 0x06, 0x32, 0x04, 0xf2, 0x03, 0x06, 0x07, 36 | 0xbe, 0x07, 0xfc, 0x07, 0x14, 0x08, 0xbf, 0x04, 0x2b, 0x04, 0x05, 0x04, 37 | 0x10, 0x04, 0xe5, 0x03, 0xf1, 0x0f, 0xb5, 0x07, 0xe9, 0x07, 0xfd, 0x07, 38 | 0xed, 0x07, 0x10, 0x04, 0x20, 0x04, 0x08, 0x0c, 0x02, 0x08, 0x0f, 0x04, 39 | 0xef, 0x07, 0xe8, 0x07, 0xf8, 0x13, 0x0d, 0x04, 0x0b, 0x04, 0xfa, 0x0b, 40 | 0x00, 0x00, 0x00, 0xfe, 0x3e, 0x04, 0x6e, 0x00, 0x66, 0x00, 0xb6, 0x03, 41 | 0x08, 0x00, 0xca, 0x03, 0x7f, 0x00, 0xe4, 0x03, 0xea, 0x03, 0x16, 0x00, 42 | 0xdd, 0x03, 0x0c, 0x00, 0xb3, 0x03, 0x2a, 0x00, 0x61, 0x03, 0x04, 0x00, 43 | 0x05, 0x00, 0xdd, 0x03, 0xff, 0x03, 0x0d, 0x00, 0x2a, 0x00, 0xe8, 0x03, 44 | 0x12, 0x00, 0xfd, 0x03, 0xfa, 0x03, 0x33, 0x00, 0xf8, 0x03, 0xde, 0x03, 45 | 0xd5, 0x03, 0xe8, 0x03, 0xbb, 0x03, 0xdc, 0x03, 0xbf, 0x03, 0xbc, 0x03, 46 | 0xf7, 0x03, 0x0d, 0x00, 0x03, 0x00, 0x10, 0x00, 0xd7, 0x03, 0xee, 0x03, 47 | 0xeb, 0x03, 0x04, 0x00, 0x08, 0x04, 0x14, 0x00, 0x15, 0x00, 0x06, 0x00, 48 | 0x0b, 0x00, 0xe9, 0x03, 0xf8, 0x03, 0x0e, 0x00, 0xfb, 0x03, 0x24, 0x00, 49 | 0xfe, 0x03, 0x04, 0x00, 0x0a, 0x00, 0x0b, 0x00, 0x03, 0x00, 0xf6, 0x03, 50 | 0xf4, 0x03, 0xe2, 0x03, 0xf6, 0x03, 0x03, 0x00, 0x02, 0x00, 0x00, 0xfe, 51 | 0x2f, 0x07, 0x0d, 0x00, 0xf7, 0x03, 0x01, 0x00, 0x0b, 0x00, 0xd4, 0x02, 52 | 0xed, 0x03, 0xcf, 0x03, 0x04, 0x00, 0x1e, 0x00, 0xc2, 0x03, 0xfe, 0x03, 53 | 0x1f, 0x00, 0xed, 0x03, 0x8f, 0x00, 0x04, 0x00, 0x3e, 0x00, 0xf9, 0x03, 54 | 0xe6, 0x03, 0xf9, 0x03, 0x2b, 0x00, 0xc9, 0x03, 0xf8, 0x03, 0x1e, 0x00, 55 | 0x03, 0x00, 0xcc, 0x03, 0x03, 0x00, 0xb7, 0x03, 0x0e, 0x00, 0x01, 0x04, 56 | 0x0b, 0x00, 0x0d, 0x00, 0xf7, 0x03, 0xf9, 0x03, 0x10, 0x00, 0xfd, 0x03, 57 | 0x0e, 0x00, 0x0d, 0x00, 0x1a, 0x00, 0xff, 0x03, 0x14, 0x00, 0x0d, 0x00, 58 | 0x06, 0x00, 0xf4, 0x03, 0xfe, 0x03, 0xee, 0x03, 0x0c, 0x00, 0xff, 0x03, 59 | 0x05, 0x00, 0x23, 0x00, 0xfd, 0x03, 0xfe, 0x03, 0xfd, 0x03, 0xf7, 0x03, 60 | 0xed, 0x03, 0xfe, 0x03, 0xf8, 0x03, 0xff, 0x03, 0xfa, 0x03, 0xf4, 0x03, 61 | 0xf8, 0x03, 0xfb, 0x03, 0xfd, 0x03, 0x00, 0xfe, 0x6b, 0x04, 0x61, 0x00, 62 | 0xd5, 0x03, 0xd8, 0x04, 0xe3, 0x07, 0x0c, 0x08, 0xc6, 0x07, 0xb4, 0x07, 63 | 0x13, 0x04, 0xf9, 0x13, 0x21, 0x04, 0x14, 0x04, 0x2e, 0x04, 0xf2, 0x07, 64 | 0x04, 0x18, 0xeb, 0x03, 0xf6, 0x07, 0xf4, 0x07, 0xdd, 0x07, 0x06, 0x18, 65 | 0x07, 0x04, 0x0b, 0x04, 0xfd, 0x13, 0xf9, 0x07, 0x02, 0x08, 0x00, 0xfe, 66 | 0x54, 0x04, 0x4d, 0x00, 0x20, 0x03, 0xff, 0x07, 0xe9, 0x07, 0x40, 0x08, 67 | 0x0f, 0x14, 0xde, 0x13, 0xf5, 0x1f, 0x15, 0x18, 0x00, 0x6c, 0x00, 0xfe, 68 | 0x31, 0x07, 0x00, 0xf8, 0x57, 0x04, 0x00, 0xf8, 0x74, 0x06, 0x00, 0xf8, 69 | 0xa5, 0x07, 0x00, 0xf8, 0x95, 0x07, 0x86, 0x00, 0xba, 0x03, 0x59, 0x04, 70 | 0xd8, 0x07, 0x14, 0x08, 0xe8, 0x07, 0xe1, 0x07, 0x1b, 0x04, 0xf5, 0x13, 71 | 0x0d, 0x04, 0x08, 0x04, 0x13, 0x04, 0xed, 0x07, 0x07, 0x18, 0xf8, 0x03, 72 | 0xfc, 0x07, 0xfb, 0x07, 0xf2, 0x07, 0x02, 0x18, 0x03, 0x04, 0x05, 0x04, 73 | 0xff, 0x13, 0xfd, 0x07, 0x01, 0x08, 0x00, 0xfe, 0xac, 0x07, 0x65, 0x03, 74 | 0xc8, 0x03, 0x9a, 0x07, 0x2e, 0x04, 0x10, 0x08, 0x1b, 0x04, 0x24, 0x04, 75 | 0xe1, 0x07, 0xf8, 0x13, 0xf1, 0x07, 0xf6, 0x07, 0xea, 0x07, 0x16, 0x04, 76 | 0x05, 0x18, 0x0a, 0x00, 0x05, 0x04, 0x05, 0x04, 0x11, 0x04, 0xfd, 0x1b, 77 | 0xfc, 0x07, 0xfb, 0x07, 0x02, 0x10, 0x03, 0x04, 0xff, 0x0b, 0x00, 0xfe, 78 | 0x88, 0x05, 0x00, 0xf8, 0xcb, 0x04, 0x00, 0xf8, 0x00, 0x06, 0x00, 0xf8, 79 | 0xfc, 0x05, 0x00, 0xf8, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 80 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 81 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 82 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 83 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 84 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 85 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 86 | 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 87 | 0x00, 0xfe, 0x00, 0xfe 88 | }; 89 | unsigned int symbols_mdec_len = 1024; 90 | --------------------------------------------------------------------------------