Codebase list libretro-beetle-psx / cef7887
Import Upstream version 0.9.38.6+git20151019 Jeremy Bicha 5 years ago
198 changed file(s) with 63399 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 DEBUG = 0
1 FRONTEND_SUPPORTS_RGB565 = 1
2
3 CORE_DIR := .
4 HAVE_GRIFFIN = 0
5
6 ifeq ($(platform),)
7 platform = unix
8 ifeq ($(shell uname -a),)
9 platform = win
10 else ifneq ($(findstring Darwin,$(shell uname -a)),)
11 platform = osx
12 arch = intel
13 ifeq ($(shell uname -p),powerpc)
14 arch = ppc
15 endif
16 else ifneq ($(findstring MINGW,$(shell uname -a)),)
17 platform = win
18 endif
19 endif
20
21 ifneq ($(platform), osx)
22 ifeq ($(findstring Haiku,$(shell uname -a)),)
23 PTHREAD_FLAGS = -pthread
24 endif
25 endif
26
27 NEED_CD = 1
28 NEED_TREMOR = 1
29 NEED_BPP = 32
30 WANT_NEW_API = 1
31 NEED_DEINTERLACER = 1
32 NEED_THREADING = 1
33 CORE_DEFINE := -DWANT_PSX_EMU
34 TARGET_NAME := mednafen_psx_libretro
35
36 ifeq ($(platform), unix)
37 TARGET := $(TARGET_NAME).so
38 fpic := -fPIC
39 SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T
40 ifneq ($(shell uname -p | grep -E '((i.|x)86|amd64)'),)
41 IS_X86 = 1
42 endif
43 LDFLAGS += $(PTHREAD_FLAGS)
44 FLAGS += $(PTHREAD_FLAGS) -DHAVE_MKDIR
45 else ifeq ($(platform), osx)
46 TARGET := $(TARGET_NAME).dylib
47 fpic := -fPIC
48 SHARED := -dynamiclib
49 LDFLAGS += $(PTHREAD_FLAGS)
50 FLAGS += $(PTHREAD_FLAGS) -DHAVE_MKDIR
51 ifeq ($(arch),ppc)
52 ENDIANNESS_DEFINES := -DMSB_FIRST
53 OLD_GCC := 1
54 else
55 endif
56 OSXVER = `sw_vers -productVersion | cut -d. -f 2`
57 OSX_LT_MAVERICKS = `(( $(OSXVER) <= 9)) && echo "YES"`
58 ifeq ($(OSX_LT_MAVERICKS),"YES")
59 fpic += -mmacosx-version-min=10.5
60 endif
61
62 # iOS
63 else ifneq (,$(findstring ios,$(platform)))
64
65 TARGET := $(TARGET_NAME)_ios.dylib
66 fpic := -fPIC
67 SHARED := -dynamiclib
68 LDFLAGS += $(PTHREAD_FLAGS)
69 FLAGS += $(PTHREAD_FLAGS)
70
71 ifeq ($(IOSSDK),)
72 IOSSDK := $(shell xcrun -sdk iphoneos -show-sdk-path)
73 endif
74
75 CC = cc -arch armv7 -isysroot $(IOSSDK)
76 CXX = c++ -arch armv7 -isysroot $(IOSSDK)
77 IPHONEMINVER :=
78 ifeq ($(platform),ios9)
79 IPHONEMINVER = -miphoneos-version-min=8.0
80 else
81 IPHONEMINVER = -miphoneos-version-min=5.0
82 endif
83 LDFLAGS += $(IPHONEMINVER)
84 FLAGS += $(IPHONEMINVER)
85 CC += $(IPHONEMINVER)
86 CXX += $(IPHONEMINVER)
87 else ifeq ($(platform), qnx)
88 TARGET := $(TARGET_NAME)_qnx.so
89 fpic := -fPIC
90 SHARED := -lcpp -lm -shared -Wl,--no-undefined -Wl,--version-script=link.T
91 #LDFLAGS += $(PTHREAD_FLAGS)
92 #FLAGS += $(PTHREAD_FLAGS) -DHAVE_MKDIR
93 FLAGS += -DHAVE_MKDIR
94 CC = qcc -Vgcc_ntoarmv7le
95 CXX = QCC -Vgcc_ntoarmv7le_cpp
96 AR = QCC -Vgcc_ntoarmv7le
97 FLAGS += -D__BLACKBERRY_QNX__ -marm -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp
98 else ifeq ($(platform), ps3)
99 TARGET := $(TARGET_NAME)_ps3.a
100 CC = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-gcc.exe
101 CXX = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-g++.exe
102 AR = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-ar.exe
103 ENDIANNESS_DEFINES := -DMSB_FIRST
104 OLD_GCC := 1
105 FLAGS += -DHAVE_MKDIR -DARCH_POWERPC_ALTIVEC
106 STATIC_LINKING = 1
107 else ifeq ($(platform), sncps3)
108 TARGET := $(TARGET_NAME)_ps3.a
109 CC = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
110 CXX = $(CELL_SDK)/host-win32/sn/bin/ps3ppusnc.exe
111 AR = $(CELL_SDK)/host-win32/sn/bin/ps3snarl.exe
112 ENDIANNESS_DEFINES := -DMSB_FIRST
113 CXXFLAGS += -Xc+=exceptions
114 OLD_GCC := 1
115 NO_GCC := 1
116 FLAGS += -DHAVE_MKDIR -DARCH_POWERPC_ALTIVEC
117 STATIC_LINKING = 1
118 else ifeq ($(platform), psl1ght)
119 TARGET := $(TARGET_NAME)_psl1ght.a
120 CC = $(PS3DEV)/ppu/bin/ppu-gcc$(EXE_EXT)
121 CXX = $(PS3DEV)/ppu/bin/ppu-g++$(EXE_EXT)
122 AR = $(PS3DEV)/ppu/bin/ppu-ar$(EXE_EXT)
123 ENDIANNESS_DEFINES := -DMSB_FIRST
124 FLAGS += -DHAVE_MKDIR
125 STATIC_LINKING = 1
126
127 # PSP
128 else ifeq ($(platform), psp1)
129 TARGET := $(TARGET_NAME)_psp1.a
130 CC = psp-gcc$(EXE_EXT)
131 CXX = psp-g++$(EXE_EXT)
132 AR = psp-ar$(EXE_EXT)
133 FLAGS += -DPSP -G0
134 FLAGS += -DHAVE_MKDIR
135 STATIC_LINKING = 1
136 EXTRA_INCLUDES := -I$(shell psp-config --pspsdk-path)/include
137
138 # Vita
139 else ifeq ($(platform), vita)
140 TARGET := $(TARGET_NAME)_vita.a
141 CC = arm-vita-eabi-gcc$(EXE_EXT)
142 CXX = arm-vita-eabi-g++$(EXE_EXT)
143 AR = arm-vita-eabi-ar$(EXE_EXT)
144 FLAGS += -DVITA
145 FLAGS += -DHAVE_MKDIR
146 STATIC_LINKING = 1
147
148 else ifeq ($(platform), xenon)
149 TARGET := $(TARGET_NAME)_xenon360.a
150 CC = xenon-gcc$(EXE_EXT)
151 CXX = xenon-g++$(EXE_EXT)
152 AR = xenon-ar$(EXE_EXT)
153 ENDIANNESS_DEFINES += -D__LIBXENON__ -m32 -D__ppc__ -DMSB_FIRST
154 LIBS := $(PTHREAD_FLAGS)
155 FLAGS += -DHAVE_MKDIR
156 STATIC_LINKING = 1
157 else ifeq ($(platform), ngc)
158 TARGET := $(TARGET_NAME)_ngc.a
159 CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
160 CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
161 AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
162 ENDIANNESS_DEFINES += -DGEKKO -DHW_DOL -mrvl -mcpu=750 -meabi -mhard-float -DMSB_FIRST
163
164 EXTRA_INCLUDES := -I$(DEVKITPRO)/libogc/include
165 FLAGS += -DHAVE_MKDIR
166 STATIC_LINKING = 1
167 else ifeq ($(platform), wii)
168 TARGET := $(TARGET_NAME)_wii.a
169 CC = $(DEVKITPPC)/bin/powerpc-eabi-gcc$(EXE_EXT)
170 CXX = $(DEVKITPPC)/bin/powerpc-eabi-g++$(EXE_EXT)
171 AR = $(DEVKITPPC)/bin/powerpc-eabi-ar$(EXE_EXT)
172 ENDIANNESS_DEFINES += -DGEKKO -DHW_RVL -mrvl -mcpu=750 -meabi -mhard-float -DMSB_FIRST
173
174 EXTRA_INCLUDES := -I$(DEVKITPRO)/libogc/include
175 FLAGS += -DHAVE_MKDIR
176 STATIC_LINKING = 1
177 else ifneq (,$(findstring armv,$(platform)))
178 TARGET := $(TARGET_NAME).so
179 fpic := -fPIC
180 SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T
181 CC = gcc
182 LDFLAGS += $(PTHREAD_FLAGS)
183 FLAGS += $(PTHREAD_FLAGS) -DHAVE_MKDIR
184 IS_X86 = 0
185 ifneq (,$(findstring cortexa8,$(platform)))
186 FLAGS += -marm -mcpu=cortex-a8
187 ASFLAGS += -mcpu=cortex-a8
188 else ifneq (,$(findstring cortexa9,$(platform)))
189 FLAGS += -marm -mcpu=cortex-a9
190 ASFLAGS += -mcpu=cortex-a9
191 endif
192 FLAGS += -marm
193 ifneq (,$(findstring neon,$(platform)))
194 FLAGS += -mfpu=neon
195 ASFLAGS += -mfpu=neon
196 HAVE_NEON = 1
197 endif
198 ifneq (,$(findstring softfloat,$(platform)))
199 FLAGS += -mfloat-abi=softfp
200 else ifneq (,$(findstring hardfloat,$(platform)))
201 FLAGS += -mfloat-abi=hard
202 endif
203 FLAGS += -DARM
204 else
205 TARGET := $(TARGET_NAME).dll
206 CC = gcc
207 CXX = g++
208 IS_X86 = 1
209 SHARED := -shared -Wl,--no-undefined -Wl,--version-script=link.T
210 LDFLAGS += -static-libgcc -static-libstdc++ -lwinmm
211 FLAGS += -DHAVE__MKDIR
212 endif
213
214 include Makefile.common
215
216 WARNINGS := -Wall \
217 -Wno-sign-compare \
218 -Wno-unused-variable \
219 -Wno-unused-function \
220 -Wno-uninitialized \
221 $(NEW_GCC_WARNING_FLAGS) \
222 -Wno-strict-aliasing
223
224 EXTRA_GCC_FLAGS := -funroll-loops
225
226 ifeq ($(NO_GCC),1)
227 EXTRA_GCC_FLAGS :=
228 WARNINGS :=
229 else
230 EXTRA_GCC_FLAGS := -g
231 endif
232
233 OBJECTS := $(SOURCES_CXX:.cpp=.o) $(SOURCES_C:.c=.o)
234
235 all: $(TARGET)
236
237 ifeq ($(DEBUG),0)
238 FLAGS += -O2 $(EXTRA_GCC_FLAGS)
239 else
240 FLAGS += -O0
241 endif
242
243 LDFLAGS += $(fpic) $(SHARED)
244 FLAGS += $(fpic) $(NEW_GCC_FLAGS)
245 FLAGS += $(INCFLAGS)
246
247 FLAGS += $(ENDIANNESS_DEFINES) -DSIZEOF_DOUBLE=8 $(WARNINGS) -DMEDNAFEN_VERSION=\"0.9.31\" -DPACKAGE=\"mednafen\" -DMEDNAFEN_VERSION_NUMERIC=931 -DPSS_STYLE=1 -DMPC_FIXED_POINT $(CORE_DEFINE) -DSTDC_HEADERS -D__STDC_LIMIT_MACROS -D__LIBRETRO__ -D_LOW_ACCURACY_ $(EXTRA_INCLUDES) $(SOUND_DEFINE) -D__STDC_CONSTANT_MACROS
248
249 CXXFLAGS += $(FLAGS)
250 CFLAGS += $(FLAGS)
251
252 $(TARGET): $(OBJECTS)
253 ifeq ($(STATIC_LINKING), 1)
254 $(AR) rcs $@ $(OBJECTS)
255 else
256 $(CXX) -o $@ $^ $(LDFLAGS)
257 endif
258
259 %.o: %.cpp
260 $(CXX) -c -o $@ $< $(CXXFLAGS)
261
262 %.o: %.c
263 $(CC) -c -o $@ $< $(CFLAGS)
264
265 clean:
266 rm -f $(TARGET) $(OBJECTS)
267
268 .PHONY: clean
0 SOURCES_CXX :=
1 SOURCES_C :=
2
3 LIBRETRO_DIR := $(CORE_DIR)/libretro-common
4 MEDNAFEN_DIR := $(CORE_DIR)/mednafen
5 CORE_EMU_DIR := $(MEDNAFEN_DIR)/psx
6
7 INCFLAGS := -I$(CORE_DIR) -I$(MEDNAFEN_DIR) -I$(MEDNAFEN_DIR)/include -I$(MEDNAFEN_DIR)/intl -I$(MEDNAFEN_DIR)/hw_sound -I$(MEDNAFEN_DIR)/hw_cpu -I$(MEDNAFEN_DIR)/hw_misc -I$(LIBRETRO_DIR)/include
8
9 ifeq ($(HAVE_GRIFFIN),1)
10 SOURCES_CXX += beetle_psx_griffin.cpp \
11 $(CORE_EMU_DIR)/dma.cpp \
12 $(CORE_EMU_DIR)/sio.cpp
13 else
14 SOURCES_CXX += $(CORE_EMU_DIR)/irq.cpp \
15 $(CORE_EMU_DIR)/timer.cpp \
16 $(CORE_EMU_DIR)/dma.cpp \
17 $(CORE_EMU_DIR)/frontio.cpp \
18 $(CORE_EMU_DIR)/sio.cpp \
19 $(CORE_EMU_DIR)/cpu.cpp \
20 $(CORE_EMU_DIR)/gte.cpp \
21 $(CORE_EMU_DIR)/cdc.cpp \
22 $(CORE_EMU_DIR)/spu.cpp \
23 $(CORE_EMU_DIR)/gpu.cpp \
24 $(CORE_EMU_DIR)/mdec.cpp \
25 $(CORE_EMU_DIR)/input/gamepad.cpp \
26 $(CORE_EMU_DIR)/input/dualanalog.cpp \
27 $(CORE_EMU_DIR)/input/dualshock.cpp \
28 $(CORE_EMU_DIR)/input/justifier.cpp \
29 $(CORE_EMU_DIR)/input/guncon.cpp \
30 $(CORE_EMU_DIR)/input/negcon.cpp \
31 $(CORE_EMU_DIR)/input/memcard.cpp \
32 $(CORE_EMU_DIR)/input/multitap.cpp \
33 $(CORE_EMU_DIR)/input/mouse.cpp
34 endif
35
36 ifeq ($(DEBUG), 1)
37 SOURCES_CXX += \
38 $(CORE_EMU_DIR)/dis.cpp
39 endif
40
41 ifeq ($(NEED_THREADING), 1)
42 FLAGS += -DWANT_THREADING
43 endif
44
45 ifeq ($(NEED_CRC32), 1)
46 FLAGS += -DWANT_CRC32
47 SOURCES_C += $(CORE_DIR)/scrc32.c
48 endif
49
50 ifeq ($(NEED_DEINTERLACER), 1)
51 FLAGS += -DNEED_DEINTERLACER
52 endif
53
54 ifeq ($(IS_X86), 1)
55 FLAGS += -DARCH_X86
56 endif
57
58 ifeq ($(NEED_BPP), 8)
59 FLAGS += -DWANT_8BPP
60 endif
61
62 ifeq ($(NEED_BPP), 16)
63 FLAGS += -DWANT_16BPP
64 endif
65
66 ifeq ($(NEED_BPP), 32)
67 FLAGS += -DWANT_32BPP
68 endif
69
70 ifeq ($(WANT_NEW_API), 1)
71 FLAGS += -DWANT_NEW_API
72 endif
73
74 ifeq ($(NO_COMPUTED_GOTO), 1)
75 FLAGS += -DNO_COMPUTED_GOTO
76 endif
77
78 ifeq ($(FRONTEND_SUPPORTS_RGB565), 1)
79 FLAGS += -DFRONTEND_SUPPORTS_RGB565
80 endif
81
82
83 ifeq ($(NEED_CD), 1)
84 ifneq ($(HAVE_GRIFFIN),1)
85 SOURCES_CXX += $(MEDNAFEN_DIR)/cdrom/CDAccess.cpp \
86 $(MEDNAFEN_DIR)/cdrom/CDAccess_Image.cpp \
87 $(MEDNAFEN_DIR)/cdrom/CDAccess_CCD.cpp \
88 $(MEDNAFEN_DIR)/cdrom/SimpleFIFO.cpp \
89 $(MEDNAFEN_DIR)/cdrom/audioreader.cpp \
90 $(MEDNAFEN_DIR)/cdrom/misc.cpp \
91 $(MEDNAFEN_DIR)/cdrom/cdromif.cpp
92
93 SOURCES_C += \
94 $(MEDNAFEN_DIR)/cdrom/CDUtility.c \
95 $(MEDNAFEN_DIR)/cdrom/galois.c \
96 $(MEDNAFEN_DIR)/cdrom/l-ec.c \
97 $(MEDNAFEN_DIR)/cdrom/lec.c \
98 $(MEDNAFEN_DIR)/cdrom/recover-raw.c \
99 $(MEDNAFEN_DIR)/cdrom/edc_crc32.c
100 endif
101 FLAGS += -DNEED_CD
102 endif
103
104 ifeq ($(NEED_TREMOR), 1)
105 SOURCES_C += $(wildcard $(MEDNAFEN_DIR)/tremor/*.c)
106 FLAGS += -DNEED_TREMOR
107 endif
108
109
110 ifneq ($(HAVE_GRIFFIN), 1)
111 SOURCES_CXX += \
112 $(MEDNAFEN_DIR)/error.cpp \
113 $(MEDNAFEN_DIR)/settings.cpp \
114 $(MEDNAFEN_DIR)/general.cpp \
115 $(MEDNAFEN_DIR)/FileStream.cpp \
116 $(MEDNAFEN_DIR)/MemoryStream.cpp \
117 $(MEDNAFEN_DIR)/Stream.cpp \
118 $(MEDNAFEN_DIR)/state.cpp \
119 $(MEDNAFEN_DIR)/mempatcher.cpp \
120 $(MEDNAFEN_DIR)/video/Deinterlacer.cpp \
121 $(MEDNAFEN_DIR)/video/surface.cpp \
122 $(CORE_DIR)/libretro.cpp
123
124 SOURCES_C += \
125 $(MEDNAFEN_DIR)/file.c \
126 $(MEDNAFEN_DIR)/md5.c \
127 $(MEDNAFEN_DIR)/mednafen-endian.c
128 endif
129
130 SOURCES_C += $(MEDNAFEN_DIR)/trio/trio.c \
131 $(MEDNAFEN_DIR)/trio/triostr.c
132
133 ifeq ($(HAVE_GRIFFIN), 1)
134 SOURCES_C += beetle_psx_griffin_c.c
135 endif
136
137 ifneq ($(STATIC_LINKING), 1)
138 SOURCES_C += $(LIBRETRO_DIR)/file/retro_file.c \
139 $(LIBRETRO_DIR)/file/retro_stat.c
140
141 ifeq ($(NEED_THREADING), 1)
142 SOURCES_C += $(LIBRETRO_DIR)/rthreads/rthreads.c
143 endif
144 endif
0 # Beetle PSX libretro
1
2 This is fork of Mednafen PSX. It has been ported to the libretro API.
3 It currently runs on Linux, OSX and possibly Windows.
4
5 ## Running
6
7 To run this core, the "system directory" must be defined if running in RetroArch.
8 The PSX BIOS must be placed there, $sysdir/SCPH550{0,1,2} for Japanese, NA and EU regions respectively.
9
10 Memory cards will be saved to "save directory", memory card #1 is saved using libretro's standard interface. The rest of memory cards are saved using Mednafen's starndard mechanism. You might have to rename your old
11 memory cards to gamename.srm. Alternatively you may just rename it from gamename.gamenamehash.0.mcr to gamename.gamenamehash.1.mcr and load them off the corresponding slot.
12
13 Core now supports save states. Keep in mind states might result on loss your memorycards if you are careless.
14
15 ## Loading ISOs
16
17 Beetle differs from other PS1 emulators in that it needs a cue-sheets that points to an image file, usually an .iso/.bin file.
18 If you have e.g. <tt>foo.iso</tt>, you should create a foo.cue, and fill this in:
19
20 FILE "foo.iso" BINARY
21 TRACK 01 MODE1/2352
22 INDEX 01 00:00:00
23
24 After that, you can load the <tt>foo.cue</tt> file as a ROM.
25 Note that this is a dirty hack and will not work on all games.
26 Ideally, make sure to use rips that have cue-sheets.
27
28 ## Suggested Firmware
29
30 - scph5500.bin (8dd7d5296a650fac7319bce665a6a53c)
31 - scph5501.bin (490f666e1afb15b7362b406ed1cea246)
32 - scph5502.bin (32736f17079d0b2b7024407c39bd3050)
33
34 ## Options
35
36 * CD Image Cache - Loads the complete image in memory at startup
37 * PSX Dithering - Enables Dithering
38 * PSX Initial Scanline - Sets the first scanline to be drawn on screen
39 * PSX Initial Scanline PAL - Sets the first scanline to be drawn on screen for PAL systems
40 * PSX Last Scanline - Sets the last scanline to be drawn on screen
41 * PSX Last Scanline PAL - Sets the last scanline to be drawn on screen for PAL systems
42 * Dualshock analog toggle - Enables/Disables the analog button from Dualshock controllers, if disabled analogs are always on, if enabled you can toggle it's state with START+SELECT+L1+L2+R1+R2
43 * Port 1 PSX Enable Multitap - Enables/Disables multitap functionality on port 1
44 * Port 2 PSX Enable Multitap - Enables/Disables multitap functionality on port 2
0
1 #include "mednafen/psx/irq.cpp"
2 #include "mednafen/psx/timer.cpp"
3 #include "mednafen/psx/frontio.cpp"
4 #include "mednafen/psx/cpu.cpp"
5 #include "mednafen/psx/gte.cpp"
6 #include "mednafen/psx/dis.cpp"
7 #include "mednafen/psx/cdc.cpp"
8 #include "mednafen/psx/spu.cpp"
9 #include "mednafen/psx/gpu.cpp"
10 #include "mednafen/psx/mdec.cpp"
11 #include "mednafen/psx/input/gamepad.cpp"
12 #include "mednafen/psx/input/dualanalog.cpp"
13 #include "mednafen/psx/input/dualshock.cpp"
14 #include "mednafen/psx/input/justifier.cpp"
15 #include "mednafen/psx/input/guncon.cpp"
16 #include "mednafen/psx/input/negcon.cpp"
17 #include "mednafen/psx/input/memcard.cpp"
18 #include "mednafen/psx/input/multitap.cpp"
19 #include "mednafen/psx/input/mouse.cpp"
20
21 #include "mednafen/error.cpp"
22 #include "mednafen/math_ops.cpp"
23 #include "mednafen/settings.cpp"
24 #include "mednafen/general.cpp"
25 #include "mednafen/FileStream.cpp"
26 #include "mednafen/MemoryStream.cpp"
27 #include "mednafen/Stream.cpp"
28 #include "mednafen/state.cpp"
29
30 #ifdef NEED_CD
31 #include "mednafen/cdrom/CDAccess.cpp"
32 #include "mednafen/cdrom/CDAccess_Image.cpp"
33 #include "mednafen/cdrom/CDAccess_CCD.cpp"
34 #include "mednafen/cdrom/SimpleFIFO.cpp"
35 #include "mednafen/cdrom/audioreader.cpp"
36 #include "mednafen/cdrom/cdromif.cpp"
37 #include "mednafen/cdrom/misc.cpp"
38 #endif
39
40 #include "mednafen/mempatcher.cpp"
41 #include "mednafen/video/Deinterlacer.cpp"
42 #include "mednafen/video/surface.cpp"
43 #include "mednafen/md5.cpp"
44
45 #include "libretro.cpp"
0 #include "mednafen/tremor/codebook.c"
1 #include "mednafen/tremor/floor0.c"
2 #include "mednafen/tremor/floor1.c"
3 #include "mednafen/tremor/mdct.c"
4 #include "mednafen/tremor/registry.c"
5 #include "mednafen/tremor/mapping0.c"
6 #include "mednafen/tremor/info.c"
7 #include "mednafen/tremor/res012.c"
8 #include "mednafen/tremor/framing.c"
9 #include "mednafen/tremor/block.c"
10 #include "mednafen/tremor/sharedbook.c"
11 #include "mednafen/tremor/synthesis.c"
12 #include "mednafen/tremor/vorbisfile.c"
13 #include "mednafen/tremor/bitwise.c"
14 #include "mednafen/tremor/window.c"
15
16 #include "mednafen/file.c"
17 #include "mednafen/mednafen-endian.c"
18 #include "mednafen/trio/trio.c"
19 #include "mednafen/trio/triostr.c"
20
21 #include "threads.c"
22 #include "scrc32.c"
23
24 #ifdef NEED_CD
25 #include "mednafen/cdrom/CDUtility.c"
26 #include "mednafen/cdrom/edc_crc32.c"
27 #include "mednafen/cdrom/l-ec.c"
28 #include "mednafen/cdrom/lec.c"
29 #include "mednafen/cdrom/recover-raw.c"
30 #include "mednafen/cdrom/galois.c"
31 #endif
0 LOCAL_PATH := $(call my-dir)
1 DEBUG = 0
2 FRONTEND_SUPPORTS_RGB565 = 1
3 FAST = 1
4
5 include $(CLEAR_VARS)
6
7 ifeq ($(TARGET_ARCH),arm)
8 ANDROID_FLAGS := -DANDROID_ARM
9 LOCAL_ARM_MODE := arm
10 endif
11
12 ifeq ($(TARGET_ARCH),x86)
13 ANDROID_FLAGS := -DANDROID_X86
14 IS_X86 = 1
15 endif
16
17 ifeq ($(TARGET_ARCH),mips)
18 ANDROID_FLAGS := -DANDROID_MIPS -D__mips__ -D__MIPSEL__
19 endif
20
21 LOCAL_CXXFLAGS += $(ANDROID_FLAGS)
22 LOCAL_CFLAGS += $(ANDROID_FLAGS)
23
24 CORE_DIR := ..
25 LOCAL_MODULE := libretro
26
27 PTHREAD_FLAGS = -pthread
28 NEED_CD = 1
29 NEED_BPP = 32
30 WANT_NEW_API = 1
31 NEED_DEINTERLACER = 1
32 NEED_THREADING = 1
33 NEED_TREMOR = 1
34 CORE_DEFINE := -DWANT_PSX_EMU
35
36 TARGET_NAME := mednafen_psx_libretro
37
38 include ../Makefile.common
39
40 LOCAL_SRC_FILES += $(SOURCES_CXX) $(SOURCES_C)
41 EXTRA_GCC_FLAGS := -funroll-loops
42
43 ifeq ($(DEBUG),0)
44 FLAGS += -O3 $(EXTRA_GCC_FLAGS)
45 else
46 FLAGS += -O0 -g
47 endif
48
49 LDFLAGS += $(fpic) $(SHARED)
50 FLAGS += $(fpic) $(NEW_GCC_FLAGS) $(INCFLAGS)
51
52 FLAGS += $(ENDIANNESS_DEFINES) -DSIZEOF_DOUBLE=8 $(WARNINGS) -DMEDNAFEN_VERSION=\"0.9.26\" -DPACKAGE=\"mednafen\" -DMEDNAFEN_VERSION_NUMERIC=926 -DPSS_STYLE=1 -DMPC_FIXED_POINT $(CORE_DEFINE) -DSTDC_HEADERS -D__STDC_LIMIT_MACROS -D__LIBRETRO__ -DNDEBUG -D_LOW_ACCURACY_ $(SOUND_DEFINE) -D__STDC_CONSTANT_MACROS
53
54 LOCAL_CFLAGS = $(FLAGS)
55 LOCAL_CXXFLAGS = $(FLAGS) -fexceptions
56
57 include $(BUILD_SHARED_LIBRARY)
0 APP_STL := gnustl_static
1 APP_ABI := all
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (retro_file.c).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #if defined(_WIN32)
28 # ifdef _MSC_VER
29 # define setmode _setmode
30 # endif
31 # ifdef _XBOX
32 # include <xtl.h>
33 # define INVALID_FILE_ATTRIBUTES -1
34 # else
35 # include <io.h>
36 # include <fcntl.h>
37 # include <direct.h>
38 # include <windows.h>
39 # endif
40 #elif defined(VITA)
41 # include <psp2/io/fcntl.h>
42 # include <psp2/io/dirent.h>
43
44 #define PSP_O_RDONLY PSP2_O_RDONLY
45 #define PSP_O_RDWR PSP2_O_RDWR
46 #define PSP_O_CREAT PSP2_O_CREAT
47 #define PSP_O_WRONLY PSP2_O_WRONLY
48 #define PSP_O_TRUNC PSP2_O_TRUNC
49 #else
50 # if defined(PSP)
51 # include <pspiofilemgr.h>
52 # endif
53 # include <sys/types.h>
54 # include <sys/stat.h>
55 # include <dirent.h>
56 # include <unistd.h>
57 #endif
58
59 #ifdef __CELLOS_LV2__
60 #include <cell/cell_fs.h>
61 #else
62 #include <fcntl.h>
63 #endif
64
65 #ifdef RARCH_INTERNAL
66 #include <retro_log.h>
67 #endif
68
69 #include <retro_file.h>
70
71 #if 1
72 #define HAVE_BUFFERED_IO 1
73 #endif
74
75 struct RFILE
76 {
77 #if defined(PSP) || defined(VITA)
78 SceUID fd;
79 #elif defined(__CELLOS_LV2__)
80 int fd;
81 #elif defined(HAVE_BUFFERED_IO)
82 FILE *fd;
83 #else
84 int fd;
85 #endif
86 };
87
88 int retro_get_fd(RFILE *stream)
89 {
90 if (!stream)
91 return -1;
92 #if defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__)
93 return stream->fd;
94 #elif defined(HAVE_BUFFERED_IO)
95 return fileno(stream->fd);
96 #else
97 return stream->fd;
98 #endif
99 }
100
101 RFILE *retro_fopen(const char *path, unsigned mode, ssize_t len)
102 {
103 int flags = 0;
104 int mode_int = 0;
105 const char *mode_str = NULL;
106 RFILE *stream = (RFILE*)calloc(1, sizeof(*stream));
107
108 if (!stream)
109 return NULL;
110
111 (void)mode_str;
112 (void)mode_int;
113 (void)flags;
114
115 switch (mode)
116 {
117 case RFILE_MODE_READ:
118 #if defined(VITA) || defined(PSP)
119 mode_int = 0777;
120 flags = PSP_O_RDONLY;
121 #elif defined(__CELLOS_LV2__)
122 mode_int = 0777;
123 flags = CELL_FS_O_RDONLY;
124 #elif defined(HAVE_BUFFERED_IO)
125 mode_str = "rb";
126 #else
127 flags = O_RDONLY;
128 #endif
129 break;
130 case RFILE_MODE_WRITE:
131 #if defined(VITA) || defined(PSP)
132 mode_int = 0777;
133 flags = PSP_O_CREAT | PSP_O_WRONLY | PSP_O_TRUNC;
134 #elif defined(__CELLOS_LV2__)
135 mode_int = 0777;
136 flags = CELL_FS_O_CREAT | CELL_FS_O_WRONLY | CELL_FS_O_TRUNC;
137 #elif defined(HAVE_BUFFERED_IO)
138 mode_str = "wb";
139 #else
140 flags = O_WRONLY | O_CREAT | O_TRUNC | S_IRUSR | S_IWUSR;
141 #endif
142 break;
143 case RFILE_MODE_READ_WRITE:
144 #if defined(VITA) || defined(PSP)
145 mode_int = 0777;
146 flags = PSP_O_RDWR;
147 #elif defined(__CELLOS_LV2__)
148 mode_int = 0777;
149 flags = CELL_FS_O_RDWR;
150 #elif defined(HAVE_BUFFERED_IO)
151 mode_str = "w+";
152 #else
153 flags = O_RDWR;
154 #ifdef _WIN32
155 flags |= O_BINARY;
156 #endif
157 #endif
158 break;
159 }
160
161 #if defined(VITA) || defined(PSP)
162 stream->fd = sceIoOpen(path, flags, mode_int);
163 #elif defined(__CELLOS_LV2__)
164 cellFsOpen(path, flags, &stream->fd, NULL, 0);
165 #elif defined(HAVE_BUFFERED_IO)
166 stream->fd = fopen(path, mode_str);
167 #else
168 stream->fd = open(path, flags);
169 #endif
170
171 #if defined(HAVE_BUFFERED_IO)
172 if (!stream->fd)
173 goto error;
174 #else
175 if (stream->fd == -1)
176 goto error;
177 #endif
178
179 return stream;
180
181 error:
182 retro_fclose(stream);
183 return NULL;
184 }
185
186 ssize_t retro_fseek(RFILE *stream, ssize_t offset, int whence)
187 {
188 int ret = 0;
189 if (!stream)
190 return -1;
191
192 (void)ret;
193
194 #if defined(VITA) || defined(PSP)
195 ret = sceIoLseek(stream->fd, (SceOff)offset, whence);
196 if (ret == -1)
197 return -1;
198 return 0;
199 #elif defined(__CELLOS_LV2__)
200 uint64_t pos = 0;
201 if (cellFsLseek(stream->fd, offset, whence, &pos) != CELL_FS_SUCCEEDED)
202 return -1;
203 return 0;
204 #elif defined(HAVE_BUFFERED_IO)
205 return fseek(stream->fd, (long)offset, whence);
206 #else
207 ret = lseek(stream->fd, offset, whence);
208 if (ret == -1)
209 return -1;
210 return 0;
211 #endif
212 }
213
214 ssize_t retro_ftell(RFILE *stream)
215 {
216 if (!stream)
217 return -1;
218 #if defined(VITA) || defined(PSP)
219 return sceIoLseek(stream->fd, 0, SEEK_CUR);
220 #elif defined(__CELLOS_LV2__)
221 uint64_t pos = 0;
222 if (cellFsLseek(stream->fd, 0, CELL_FS_SEEK_CUR, &pos) != CELL_FS_SUCCEEDED)
223 return -1;
224 return 0;
225 #elif defined(HAVE_BUFFERED_IO)
226 return ftell(stream->fd);
227 #else
228 return lseek(stream->fd, 0, SEEK_CUR);
229 #endif
230 }
231
232 void retro_frewind(RFILE *stream)
233 {
234 retro_fseek(stream, 0L, SEEK_SET);
235 }
236
237 ssize_t retro_fread(RFILE *stream, void *s, size_t len)
238 {
239 if (!stream || !s)
240 return -1;
241 #if defined(VITA) || defined(PSP)
242 return sceIoRead(stream->fd, s, len);
243 #elif defined(__CELLOS_LV2__)
244 uint64_t bytes_written;
245 if (cellFsRead(stream->fd, s, len, &bytes_written) != CELL_FS_SUCCEEDED)
246 return -1;
247 return bytes_written;
248 #elif defined(HAVE_BUFFERED_IO)
249 return fread(s, 1, len, stream->fd);
250 #else
251 return read(stream->fd, s, len);
252 #endif
253 }
254
255 ssize_t retro_fwrite(RFILE *stream, const void *s, size_t len)
256 {
257 if (!stream)
258 return -1;
259 #if defined(VITA) || defined(PSP)
260 return sceIoWrite(stream->fd, s, len);
261 #elif defined(__CELLOS_LV2__)
262 uint64_t bytes_written;
263 if (cellFsWrite(stream->fd, s, len, &bytes_written) != CELL_FS_SUCCEEDED)
264 return -1;
265 return bytes_written;
266 #elif defined(HAVE_BUFFERED_IO)
267 return fwrite(s, 1, len, stream->fd);
268 #else
269 return write(stream->fd, s, len);
270 #endif
271 }
272
273 int retro_fclose(RFILE *stream)
274 {
275 if (!stream)
276 return -1;
277
278 #if defined(VITA) || defined(PSP)
279 if (stream->fd > 0)
280 sceIoClose(stream->fd);
281 #elif defined(__CELLOS_LV2__)
282 if (stream->fd > 0)
283 cellFsClose(stream->fd);
284 #elif defined(HAVE_BUFFERED_IO)
285 if (stream->fd)
286 fclose(stream->fd);
287 #else
288 if (stream->fd > 0)
289 close(stream->fd);
290 #endif
291 free(stream);
292
293 return 0;
294 }
295
296 /**
297 * retro_read_file:
298 * @path : path to file.
299 * @buf : buffer to allocate and read the contents of the
300 * file into. Needs to be freed manually.
301 *
302 * Read the contents of a file into @buf.
303 *
304 * Returns: number of items read, -1 on error.
305 */
306 int retro_read_file(const char *path, void **buf, ssize_t *len)
307 {
308 ssize_t ret = 0;
309 ssize_t content_buf_size = 0;
310 void *content_buf = NULL;
311 RFILE *file = retro_fopen(path, RFILE_MODE_READ, -1);
312
313 if (!file)
314 goto error;
315
316 if (retro_fseek(file, 0, SEEK_END) != 0)
317 goto error;
318
319 content_buf_size = retro_ftell(file);
320 if (content_buf_size < 0)
321 goto error;
322
323 retro_frewind(file);
324
325 content_buf = malloc(content_buf_size + 1);
326
327 if (!content_buf)
328 goto error;
329
330 if ((ret = retro_fread(file, content_buf, content_buf_size)) < content_buf_size)
331 {
332 #ifdef RARCH_INTERNAL
333 RARCH_WARN("Didn't read whole file: %s.\n", path);
334 #else
335 printf("Didn't read whole file: %s.\n", path);
336 #endif
337 }
338
339 if (!content_buf)
340 goto error;
341
342 *buf = content_buf;
343
344 /* Allow for easy reading of strings to be safe.
345 * Will only work with sane character formatting (Unix). */
346 ((char*)content_buf)[content_buf_size] = '\0';
347
348 if (retro_fclose(file) != 0)
349 printf("Failed to close file stream.\n");
350
351 if (len)
352 *len = ret;
353
354 return 1;
355
356 error:
357 retro_fclose(file);
358 if (content_buf)
359 free(content_buf);
360 if (len)
361 *len = -1;
362 *buf = NULL;
363 return 0;
364 }
365
366 /**
367 * retro_write_file:
368 * @path : path to file.
369 * @data : contents to write to the file.
370 * @size : size of the contents.
371 *
372 * Writes data to a file.
373 *
374 * Returns: true (1) on success, false (0) otherwise.
375 */
376 bool retro_write_file(const char *path, const void *data, ssize_t size)
377 {
378 ssize_t ret = 0;
379 RFILE *file = retro_fopen(path, RFILE_MODE_WRITE, -1);
380 if (!file)
381 return false;
382
383 ret = retro_fwrite(file, data, size);
384 retro_fclose(file);
385
386 return (ret == size);
387 }
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (retro_stat.c).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <errno.h>
26
27 #if defined(_WIN32)
28 #ifdef _MSC_VER
29 #define setmode _setmode
30 #endif
31 #ifdef _XBOX
32 #include <xtl.h>
33 #define INVALID_FILE_ATTRIBUTES -1
34 #else
35 #include <io.h>
36 #include <fcntl.h>
37 #include <direct.h>
38 #include <windows.h>
39 #endif
40 #elif defined(VITA)
41 #define SCE_ERROR_ERRNO_EEXIST 0x80010011
42 #include <psp2/io/fcntl.h>
43 #include <psp2/io/dirent.h>
44 #include <psp2/io/stat.h>
45 #else
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <unistd.h>
49 #endif
50
51 #if defined(PSP)
52 #include <pspkernel.h>
53 #endif
54
55 #ifdef __HAIKU__
56 #include <kernel/image.h>
57 #endif
58
59 #if defined(__CELLOS_LV2__)
60 #include <cell/cell_fs.h>
61 #endif
62
63 #if defined(VITA)
64 #define FIO_S_ISDIR PSP2_S_ISDIR
65 #endif
66
67 #if (defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)) || defined(__QNX__) || defined(PSP)
68 #include <unistd.h> /* stat() is defined here */
69 #endif
70
71 #include <retro_miscellaneous.h>
72 #include <boolean.h>
73
74 enum stat_mode
75 {
76 IS_DIRECTORY = 0,
77 IS_CHARACTER_SPECIAL,
78 IS_VALID
79 };
80
81 static bool path_stat(const char *path, enum stat_mode mode, int32_t *size)
82 {
83 #if defined(VITA) || defined(PSP)
84 SceIoStat buf;
85 char *tmp = strdup(path);
86 size_t len = strlen(tmp);
87 if (tmp[len-1] == '/')
88 tmp[len-1]='\0';
89
90 if (sceIoGetstat(tmp, &buf) < 0)
91 {
92 free(tmp);
93 return false;
94 }
95 free(tmp);
96
97 #elif defined(__CELLOS_LV2__)
98 CellFsStat buf;
99 if (cellFsStat(path, &buf) < 0)
100 return false;
101 #elif defined(_WIN32)
102 WIN32_FILE_ATTRIBUTE_DATA file_info;
103 GET_FILEEX_INFO_LEVELS fInfoLevelId = GetFileExInfoStandard;
104 DWORD ret = GetFileAttributesEx(path, fInfoLevelId, &file_info);
105 if (ret == 0)
106 return false;
107 #else
108 struct stat buf;
109 if (stat(path, &buf) < 0)
110 return false;
111 #endif
112
113 #if defined(_WIN32)
114 if (size)
115 *size = file_info.nFileSizeLow;
116 #else
117 if (size)
118 *size = buf.st_size;
119 #endif
120
121 switch (mode)
122 {
123 case IS_DIRECTORY:
124 #if defined(VITA) || defined(PSP)
125 return FIO_S_ISDIR(buf.st_mode);
126 #elif defined(__CELLOS_LV2__)
127 return ((buf.st_mode & S_IFMT) == S_IFDIR);
128 #elif defined(_WIN32)
129 return (file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
130 #else
131 return S_ISDIR(buf.st_mode);
132 #endif
133 case IS_CHARACTER_SPECIAL:
134 #if defined(VITA) || defined(PSP) || defined(__CELLOS_LV2__) || defined(_WIN32)
135 return false;
136 #else
137 return S_ISCHR(buf.st_mode);
138 #endif
139 case IS_VALID:
140 return true;
141 }
142
143 return false;
144 }
145
146 /**
147 * path_is_directory:
148 * @path : path
149 *
150 * Checks if path is a directory.
151 *
152 * Returns: true (1) if path is a directory, otherwise false (0).
153 */
154 bool path_is_directory(const char *path)
155 {
156 return path_stat(path, IS_DIRECTORY, NULL);
157 }
158
159 bool path_is_character_special(const char *path)
160 {
161 return path_stat(path, IS_CHARACTER_SPECIAL, NULL);
162 }
163
164 bool path_is_valid(const char *path)
165 {
166 return path_stat(path, IS_VALID, NULL);
167 }
168
169 int32_t path_get_size(const char *path)
170 {
171 int32_t filesize = 0;
172 if (path_stat(path, IS_VALID, &filesize))
173 return filesize;
174
175 return -1;
176 }
177
178 /**
179 * path_mkdir_norecurse:
180 * @dir : directory
181 *
182 * Create directory on filesystem.
183 *
184 * Returns: true (1) if directory could be created, otherwise false (0).
185 **/
186 bool mkdir_norecurse(const char *dir)
187 {
188 int ret;
189 #if defined(_WIN32)
190 ret = _mkdir(dir);
191 #elif defined(IOS)
192 ret = mkdir(dir, 0755);
193 #elif defined(VITA) || defined(PSP)
194 ret = sceIoMkdir(dir, 0777);
195 #else
196 ret = mkdir(dir, 0750);
197 #endif
198 /* Don't treat this as an error. */
199 #if defined(VITA)
200 if ((ret == SCE_ERROR_ERRNO_EEXIST) && path_is_directory(dir))
201 ret = 0;
202 #elif defined(PSP)
203 if ((ret == -1) && path_is_directory(dir))
204 ret = 0;
205 #else
206 if (ret < 0 && errno == EEXIST && path_is_directory(dir))
207 ret = 0;
208 #endif
209 if (ret < 0)
210 printf("mkdir(%s) error: %s.\n", dir, strerror(errno));
211 return ret == 0;
212 }
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (retro_file.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef __RETRO_FILE_H
23 #define __RETRO_FILE_H
24
25 #include <stdint.h>
26 #include <stddef.h>
27
28 #include <sys/types.h>
29
30 #include <boolean.h>
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 typedef struct RFILE RFILE;
37
38 enum
39 {
40 RFILE_MODE_READ = 0,
41 RFILE_MODE_WRITE,
42 RFILE_MODE_READ_WRITE
43 };
44
45 RFILE *retro_fopen(const char *path, unsigned mode, ssize_t len);
46
47 ssize_t retro_fseek(RFILE *stream, ssize_t offset, int whence);
48
49 ssize_t retro_fread(RFILE *stream, void *s, size_t len);
50
51 ssize_t retro_fwrite(RFILE *stream, const void *s, size_t len);
52
53 ssize_t retro_ftell(RFILE *stream);
54
55 void retro_frewind(RFILE *stream);
56
57 int retro_fclose(RFILE *stream);
58
59 int retro_read_file(const char *path, void **buf, ssize_t *len);
60
61 bool retro_write_file(const char *path, const void *data, ssize_t size);
62
63 int retro_get_fd(RFILE *stream);
64
65 #ifdef __cplusplus
66 }
67 #endif
68
69 #endif
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (retro_inline.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef __LIBRETRO_SDK_INLINE_H
23 #define __LIBRETRO_SDK_INLINE_H
24
25 #ifndef INLINE
26
27 #if !defined(__cplusplus) && defined(_WIN32)
28 #define INLINE _inline
29 #elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
30 #define INLINE inline
31 #elif defined(__GNUC__)
32 #define INLINE __inline__
33 #else
34 #define INLINE
35 #endif
36
37 #endif
38 #endif
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (retro_miscellaneous.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef __RARCH_MISCELLANEOUS_H
23 #define __RARCH_MISCELLANEOUS_H
24
25 #include <stdint.h>
26
27 #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
28 #include <sys/timer.h>
29 #elif defined(XENON)
30 #include <time/time.h>
31 #elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
32 #include <unistd.h>
33 #elif defined(PSP)
34 #include <pspthreadman.h>
35 #elif defined(VITA)
36 #include <psp2/kernel/threadmgr.h>
37 #elif defined(_3DS)
38 #include <3ds.h>
39 #else
40 #include <time.h>
41 #endif
42
43 #if defined(_WIN32) && !defined(_XBOX)
44 #define WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46 #elif defined(_WIN32) && defined(_XBOX)
47 #include <Xtl.h>
48 #endif
49
50 #include <limits.h>
51
52 #ifdef _MSC_VER
53 #include <compat/msvc.h>
54 #endif
55 #include <retro_inline.h>
56
57 #ifndef PATH_MAX_LENGTH
58 #define PATH_MAX_LENGTH 4096
59 #endif
60
61 #ifndef max
62 #define max(a, b) ((a) > (b) ? (a) : (b))
63 #endif
64
65 #ifndef min
66 #define min(a, b) ((a) < (b) ? (a) : (b))
67 #endif
68
69 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
70 #define RARCH_SCALE_BASE 256
71
72 /**
73 * retro_sleep:
74 * @msec : amount in milliseconds to sleep
75 *
76 * Sleeps for a specified amount of milliseconds (@msec).
77 **/
78 static INLINE void retro_sleep(unsigned msec)
79 {
80 #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
81 sys_timer_usleep(1000 * msec);
82 #elif defined(PSP) || defined(VITA)
83 sceKernelDelayThread(1000 * msec);
84 #elif defined(_3DS)
85 svcSleepThread(1000000 * (s64)msec);
86 #elif defined(_WIN32)
87 Sleep(msec);
88 #elif defined(XENON)
89 udelay(1000 * msec);
90 #elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
91 usleep(1000 * msec);
92 #else
93 struct timespec tv = {0};
94 tv.tv_sec = msec / 1000;
95 tv.tv_nsec = (msec % 1000) * 1000000;
96 nanosleep(&tv, NULL);
97 #endif
98 }
99
100 /**
101 * next_pow2:
102 * @v : initial value
103 *
104 * Get next power of 2 value based on initial value.
105 *
106 * Returns: next power of 2 value (derived from @v).
107 **/
108 static INLINE uint32_t next_pow2(uint32_t v)
109 {
110 v--;
111 v |= v >> 1;
112 v |= v >> 2;
113 v |= v >> 4;
114 v |= v >> 8;
115 v |= v >> 16;
116 v++;
117 return v;
118 }
119
120 /**
121 * prev_pow2:
122 * @v : initial value
123 *
124 * Get previous power of 2 value based on initial value.
125 *
126 * Returns: previous power of 2 value (derived from @v).
127 **/
128 static INLINE uint32_t prev_pow2(uint32_t v)
129 {
130 v |= v >> 1;
131 v |= v >> 2;
132 v |= v >> 4;
133 v |= v >> 8;
134 v |= v >> 16;
135 return v - (v >> 1);
136 }
137
138 /* Helper macros and struct to keep track of many booleans.
139 * To check for multiple bits, use &&, not &.
140 * For OR, | can be used. */
141 typedef struct
142 {
143 uint32_t data[8];
144 } rarch_bits_t;
145
146 #define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7)))
147 #define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
148 #define BIT_GET(a, bit) ((a)[(bit) >> 3] & (1 << ((bit) & 7)))
149
150 #define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
151 #define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
152 #define BIT16_GET(a, bit) (!!((a) & (1 << ((bit) & 15))))
153 #define BIT16_CLEAR_ALL(a) ((a) = 0)
154
155 #define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
156 #define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
157 #define BIT32_GET(a, bit) (!!((a) & (1 << ((bit) & 31))))
158 #define BIT32_CLEAR_ALL(a) ((a) = 0)
159
160 #define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63)))
161 #define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
162 #define BIT64_GET(a, bit) (!!((a) & (UINT64_C(1) << ((bit) & 63))))
163 #define BIT64_CLEAR_ALL(a) ((a) = 0)
164
165 #define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31))
166 #define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
167 #define BIT128_GET(a, bit) ((a).data[(bit) >> 5] & (1 << ((bit) & 31)))
168 #define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a));
169
170 #endif
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (retro_stat.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef __RETRO_STAT_H
23 #define __RETRO_STAT_H
24
25 #include <stdint.h>
26 #include <stddef.h>
27
28 #include <boolean.h>
29
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33
34 /**
35 * path_is_directory:
36 * @path : path
37 *
38 * Checks if path is a directory.
39 *
40 * Returns: true (1) if path is a directory, otherwise false (0).
41 */
42 bool path_is_directory(const char *path);
43
44 bool path_is_character_special(const char *path);
45
46 bool path_is_valid(const char *path);
47
48 int32_t path_get_size(const char *path);
49
50 /**
51 * path_mkdir_norecurse:
52 * @dir : directory
53 *
54 * Create directory on filesystem.
55 *
56 * Returns: true (1) if directory could be created, otherwise false (0).
57 **/
58 bool mkdir_norecurse(const char *dir);
59
60 #ifdef __cplusplus
61 }
62 #endif
63
64 #endif
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (rthreads.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef __LIBRETRO_SDK_RTHREADS_H__
23 #define __LIBRETRO_SDK_RTHREADS_H__
24
25 #include <boolean.h>
26 #include <stdint.h>
27 #include <retro_inline.h>
28 #include <retro_miscellaneous.h>
29
30 #if defined(__cplusplus) && !defined(_MSC_VER)
31 extern "C" {
32 #endif
33
34 typedef struct sthread sthread_t;
35 typedef struct slock slock_t;
36 typedef struct scond scond_t;
37
38 /**
39 * sthread_create:
40 * @start_routine : thread entry callback function
41 * @userdata : pointer to userdata that will be made
42 * available in thread entry callback function
43 *
44 * Create a new thread.
45 *
46 * Returns: pointer to new thread if successful, otherwise NULL.
47 */
48 sthread_t *sthread_create(void (*thread_func)(void*), void *userdata);
49
50 /**
51 * sthread_detach:
52 * @thread : pointer to thread object
53 *
54 * Detach a thread. When a detached thread terminates, its
55 * resource sare automatically released back to the system
56 * without the need for another thread to join with the
57 * terminated thread.
58 *
59 * Returns: 0 on success, otherwise it returns a non-zero error number.
60 */
61 int sthread_detach(sthread_t *thread);
62
63 /**
64 * sthread_join:
65 * @thread : pointer to thread object
66 *
67 * Join with a terminated thread. Waits for the thread specified by
68 * @thread to terminate. If that thread has already terminated, then
69 * it will return immediately. The thread specified by @thread must
70 * be joinable.
71 *
72 * Returns: 0 on success, otherwise it returns a non-zero error number.
73 */
74 void sthread_join(sthread_t *thread);
75
76 /**
77 * slock_new:
78 *
79 * Create and initialize a new mutex. Must be manually
80 * freed.
81 *
82 * Returns: pointer to a new mutex if successful, otherwise NULL.
83 **/
84 slock_t *slock_new(void);
85
86 /**
87 * slock_free:
88 * @lock : pointer to mutex object
89 *
90 * Frees a mutex.
91 **/
92 void slock_free(slock_t *lock);
93
94 /**
95 * slock_lock:
96 * @lock : pointer to mutex object
97 *
98 * Locks a mutex. If a mutex is already locked by
99 * another thread, the calling thread shall block until
100 * the mutex becomes available.
101 **/
102 void slock_lock(slock_t *lock);
103
104 /**
105 * slock_unlock:
106 * @lock : pointer to mutex object
107 *
108 * Unlocks a mutex.
109 **/
110 void slock_unlock(slock_t *lock);
111
112 /**
113 * scond_new:
114 *
115 * Creates and initializes a condition variable. Must
116 * be manually freed.
117 *
118 * Returns: pointer to new condition variable on success,
119 * otherwise NULL.
120 **/
121 scond_t *scond_new(void);
122
123 /**
124 * scond_free:
125 * @cond : pointer to condition variable object
126 *
127 * Frees a condition variable.
128 **/
129 void scond_free(scond_t *cond);
130
131 /**
132 * scond_wait:
133 * @cond : pointer to condition variable object
134 * @lock : pointer to mutex object
135 *
136 * Block on a condition variable (i.e. wait on a condition).
137 **/
138 void scond_wait(scond_t *cond, slock_t *lock);
139
140 /**
141 * scond_wait_timeout:
142 * @cond : pointer to condition variable object
143 * @lock : pointer to mutex object
144 * @timeout_us : timeout (in microseconds)
145 *
146 * Try to block on a condition variable (i.e. wait on a condition) until
147 * @timeout_us elapses.
148 *
149 * Returns: false (0) if timeout elapses before condition variable is
150 * signaled or broadcast, otherwise true (1).
151 **/
152 bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);
153
154 /**
155 * scond_broadcast:
156 * @cond : pointer to condition variable object
157 *
158 * Broadcast a condition. Unblocks all threads currently blocked
159 * on the specified condition variable @cond.
160 **/
161 int scond_broadcast(scond_t *cond);
162
163 /**
164 * scond_signal:
165 * @cond : pointer to condition variable object
166 *
167 * Signal a condition. Unblocks at least one of the threads currently blocked
168 * on the specified condition variable @cond.
169 **/
170 void scond_signal(scond_t *cond);
171
172 #if defined(__cplusplus) && !defined(_MSC_VER)
173 }
174 #endif
175
176 #endif
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (gx_pthread.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef _GX_PTHREAD_WRAP_GX_
23 #define _GX_PTHREAD_WRAP_GX_
24
25 #include <ogcsys.h>
26 #include <gccore.h>
27 #include <ogc/cond.h>
28 #include <retro_inline.h>
29
30 #ifndef OSThread
31 #define OSThread lwp_t
32 #endif
33
34 #ifndef OSCond
35 #define OSCond lwpq_t
36 #endif
37
38 #ifndef OSThreadQueue
39 #define OSThreadQueue lwpq_t
40 #endif
41
42 #ifndef OSInitMutex
43 #define OSInitMutex(mutex) LWP_MutexInit(mutex, 0)
44 #endif
45
46 #ifndef OSLockMutex
47 #define OSLockMutex(mutex) LWP_MutexLock(mutex)
48 #endif
49
50 #ifndef OSUnlockMutex
51 #define OSUnlockMutex(mutex) LWP_MutexUnlock(mutex)
52 #endif
53
54 #ifndef OSTryLockMutex
55 #define OSTryLockMutex(mutex) LWP_MutexTryLock(mutex)
56 #endif
57
58 #ifndef OSInitCond
59 #define OSInitCond(cond) LWP_CondInit(cond)
60 #endif
61
62 #if 0
63 #ifndef OSSignalCond
64 #define OSSignalCond(cond) LWP_ThreadSignal(cond)
65 #endif
66 #endif
67
68 #ifndef OSWaitCond
69 #define OSWaitCond(cond, mutex) LWP_CondWait(cond, mutex)
70 #endif
71
72 #ifndef OSInitThreadQueue
73 #define OSInitThreadQueue(queue) LWP_InitQueue(queue)
74 #endif
75
76 #ifndef OSSleepThread
77 #define OSSleepThread(queue) LWP_ThreadSleep(queue)
78 #endif
79
80 #ifndef OSJoinThread
81 #define OSJoinThread(thread, val) LWP_JoinThread(thread, val)
82 #endif
83
84 #ifndef OSSignalCond
85 #define OSSignalCond(thread) LWP_CondSignal(thread)
86 #endif
87
88 #ifndef OSCreateThread
89 #define OSCreateThread(thread, func, intarg, ptrarg, stackbase, stacksize, priority, attrs) LWP_CreateThread(thread, func, ptrarg, stackbase, stacksize, priority)
90 #endif
91
92 #define STACKSIZE (8 * 1024)
93
94 typedef OSThread pthread_t;
95 typedef mutex_t pthread_mutex_t;
96 typedef void* pthread_mutexattr_t;
97 typedef int pthread_attr_t;
98 typedef OSCond pthread_cond_t;
99 typedef OSCond pthread_condattr_t;
100
101 static INLINE int pthread_create(pthread_t *thread,
102 const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
103 {
104 *thread = 0;
105 return OSCreateThread(thread, start_routine, 0 /* unused */, arg,
106 0, STACKSIZE, 64, 0 /* unused */);
107 }
108
109 static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
110 const pthread_mutexattr_t *attr)
111 {
112 return OSInitMutex(mutex);
113 }
114
115 static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
116 {
117 return LWP_MutexDestroy(*mutex);
118 }
119
120 static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
121 {
122 return OSLockMutex(*mutex);
123 }
124
125 static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
126 {
127 return OSUnlockMutex(*mutex);
128 }
129
130 static INLINE void pthread_exit(void *retval)
131 {
132 /* FIXME: No LWP equivalent for this? */
133 (void)retval;
134 }
135
136 static INLINE int pthread_detach(pthread_t thread)
137 {
138 /* FIXME: pthread_detach equivalent missing? */
139 (void)thread;
140 return 0;
141 }
142
143 static INLINE int pthread_join(pthread_t thread, void **retval)
144 {
145 return OSJoinThread(thread, retval);
146 }
147
148 static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
149 {
150 return OSTryLockMutex(*mutex);
151 }
152
153 static INLINE int pthread_cond_wait(pthread_cond_t *cond,
154 pthread_mutex_t *mutex)
155 {
156 return OSWaitCond(*cond, *mutex);
157 }
158
159 static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
160 pthread_mutex_t *mutex, const struct timespec *abstime)
161 {
162 return LWP_CondTimedWait(*cond, *mutex, abstime);
163 }
164
165 static INLINE int pthread_cond_init(pthread_cond_t *cond,
166 const pthread_condattr_t *attr)
167 {
168 return OSInitCond(cond);
169 }
170
171 static INLINE int pthread_cond_signal(pthread_cond_t *cond)
172 {
173 OSSignalCond(*cond);
174 return 0;
175 }
176
177 static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
178 {
179 return LWP_CondBroadcast(*cond);
180 }
181
182 static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
183 {
184 return LWP_CondDestroy(*cond);
185 }
186
187 #endif
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (psp_pthread.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 /* FIXME: unfinished on PSP, mutexes and condition variables basically a stub. */
23 #ifndef _PSP_PTHREAD_WRAP__
24 #define _PSP_PTHREAD_WRAP__
25
26 #ifdef VITA
27 #include <psp2/kernel/threadmgr.h>
28 #else
29 #include <pspkernel.h>
30 #include <pspthreadman.h>
31 #include <pspthreadman_kernel.h>
32 #endif
33 #include <stdio.h>
34 #include <retro_inline.h>
35
36 #define STACKSIZE (64 * 1024)
37
38 typedef SceUID pthread_t;
39 typedef SceUID pthread_mutex_t;
40 typedef void* pthread_mutexattr_t;
41 typedef int pthread_attr_t;
42 typedef SceUID pthread_cond_t;
43 typedef SceUID pthread_condattr_t;
44
45 /* Use pointer values to create unique names for threads/mutexes */
46 char name_buffer[256];
47
48 typedef void* (*sthreadEntry)(void *argp);
49
50 typedef struct
51 {
52 void* arg;
53 sthreadEntry start_routine;
54 } sthread_args_struct;
55
56
57 static int psp_thread_wrap(SceSize args, void *argp)
58 {
59 sthread_args_struct* sthread_args = (sthread_args_struct*)argp;
60
61 return (int)sthread_args->start_routine(sthread_args->arg);
62 }
63
64 static INLINE int pthread_create(pthread_t *thread,
65 const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg)
66 {
67 sprintf(name_buffer, "0x%08X", (uint32_t) thread);
68
69 *thread = sceKernelCreateThread(name_buffer,
70 psp_thread_wrap, 0x20, STACKSIZE, 0, NULL);
71
72 sthread_args_struct sthread_args;
73 sthread_args.arg = arg;
74 sthread_args.start_routine = start_routine;
75
76 return sceKernelStartThread(*thread, sizeof(sthread_args), &sthread_args);
77 }
78
79 static INLINE int pthread_mutex_init(pthread_mutex_t *mutex,
80 const pthread_mutexattr_t *attr)
81 {
82 sprintf(name_buffer, "0x%08X", (uint32_t) mutex);
83
84 #ifdef VITA
85 return *mutex = sceKernelCreateMutex(name_buffer, 0, 0, 0);
86 #else
87 return *mutex = sceKernelCreateSema(name_buffer, 0, 1, 1, NULL);
88 #endif
89 }
90
91 static INLINE int pthread_mutex_destroy(pthread_mutex_t *mutex)
92 {
93 #ifdef VITA
94 return sceKernelDeleteMutex(*mutex);
95 #else
96 return sceKernelDeleteSema(*mutex);
97 #endif
98 }
99
100 static INLINE int pthread_mutex_lock(pthread_mutex_t *mutex)
101 {
102 #ifdef VITA
103 return sceKernelLockMutex(*mutex, 1, 0);
104 #else
105 /* FIXME: stub */
106 return 1;
107 #endif
108 }
109
110 static INLINE int pthread_mutex_unlock(pthread_mutex_t *mutex)
111 {
112 #ifdef VITA
113 return sceKernelUnlockMutex(*mutex, 1);
114 #else
115 /* FIXME: stub */
116 return 1;
117 #endif
118 }
119
120
121 static INLINE int pthread_join(pthread_t thread, void **retval)
122 {
123 int exit_status;
124 SceUInt timeout = (SceUInt)-1;
125
126 sceKernelWaitThreadEnd(thread, &timeout);
127 exit_status = sceKernelGetThreadExitStatus(thread);
128 sceKernelDeleteThread(thread);
129 return exit_status;
130 }
131
132 static INLINE int pthread_mutex_trylock(pthread_mutex_t *mutex)
133 {
134 #ifdef VITA
135 return sceKernelTryLockMutex(*mutex, 1 /* not sure about this last param */);
136 #else
137 /* FIXME: stub */
138 return 1;
139 #endif
140 }
141
142 static INLINE int pthread_cond_wait(pthread_cond_t *cond,
143 pthread_mutex_t *mutex)
144 {
145 sceKernelDelayThread(10000);
146 return 1;
147 }
148
149 static INLINE int pthread_cond_timedwait(pthread_cond_t *cond,
150 pthread_mutex_t *mutex, const struct timespec *abstime)
151 {
152 //FIXME: stub
153 return 1;
154 }
155
156 static INLINE int pthread_cond_init(pthread_cond_t *cond,
157 const pthread_condattr_t *attr)
158 {
159 //FIXME: stub
160 return 1;
161 }
162
163 static INLINE int pthread_cond_signal(pthread_cond_t *cond)
164 {
165 //FIXME: stub
166 return 1;
167 }
168
169 static INLINE int pthread_cond_broadcast(pthread_cond_t *cond)
170 {
171 //FIXME: stub
172 return 1;
173 }
174
175 static INLINE int pthread_cond_destroy(pthread_cond_t *cond)
176 {
177 //FIXME: stub
178 return 1;
179 }
180
181
182 static INLINE int pthread_detach(pthread_t thread)
183 {
184 return 1;
185 }
186
187 static INLINE void pthread_exit(void *retval)
188 {
189 (void)retval;
190 }
191
192 #endif //_PSP_PTHREAD_WRAP__
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (rthreads.c).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #include <stdlib.h>
23
24 #include <rthreads/rthreads.h>
25
26 #if defined(_WIN32)
27 #ifdef _XBOX
28 #include <xtl.h>
29 #else
30 #define WIN32_LEAN_AND_MEAN
31 #include <windows.h>
32 #endif
33 #elif defined(GEKKO)
34 #include "gx_pthread.h"
35 #elif defined(PSP)
36 #include "psp_pthread.h"
37 #else
38 #include <pthread.h>
39 #include <time.h>
40 #endif
41
42 #ifdef __MACH__
43 #include <mach/clock.h>
44 #include <mach/mach.h>
45 #endif
46
47 struct thread_data
48 {
49 void (*func)(void*);
50 void *userdata;
51 };
52
53 struct sthread
54 {
55 #ifdef _WIN32
56 HANDLE thread;
57 #else
58 pthread_t id;
59 #endif
60 };
61
62 struct slock
63 {
64 #ifdef _WIN32
65 HANDLE lock;
66 #else
67 pthread_mutex_t lock;
68 #endif
69 };
70
71 struct scond
72 {
73 #ifdef _WIN32
74 HANDLE event;
75 #else
76 pthread_cond_t cond;
77 #endif
78 };
79
80 #ifdef _WIN32
81 static DWORD CALLBACK thread_wrap(void *data_)
82 #else
83 static void *thread_wrap(void *data_)
84 #endif
85 {
86 struct thread_data *data = (struct thread_data*)data_;
87 if (!data)
88 return 0;
89 data->func(data->userdata);
90 free(data);
91 return 0;
92 }
93
94 /**
95 * sthread_create:
96 * @start_routine : thread entry callback function
97 * @userdata : pointer to userdata that will be made
98 * available in thread entry callback function
99 *
100 * Create a new thread.
101 *
102 * Returns: pointer to new thread if successful, otherwise NULL.
103 */
104 sthread_t *sthread_create(void (*thread_func)(void*), void *userdata)
105 {
106 sthread_t *thread = (sthread_t*)calloc(1, sizeof(*thread));
107 struct thread_data *data;
108 if (!thread)
109 return NULL;
110
111 data = (struct thread_data*)calloc(1, sizeof(*data));
112 if (!data)
113 {
114 free(thread);
115 return NULL;
116 }
117
118 data->func = thread_func;
119 data->userdata = userdata;
120
121 #ifdef _WIN32
122 thread->thread = CreateThread(NULL, 0, thread_wrap, data, 0, NULL);
123 if (!thread->thread)
124 #else
125 if (pthread_create(&thread->id, NULL, thread_wrap, data) < 0)
126 #endif
127 {
128 free(data);
129 free(thread);
130 return NULL;
131 }
132
133 return thread;
134 }
135
136 /**
137 * sthread_detach:
138 * @thread : pointer to thread object
139 *
140 * Detach a thread. When a detached thread terminates, its
141 * resource sare automatically released back to the system
142 * without the need for another thread to join with the
143 * terminated thread.
144 *
145 * Returns: 0 on success, otherwise it returns a non-zero error number.
146 */
147 int sthread_detach(sthread_t *thread)
148 {
149 #ifdef _WIN32
150 CloseHandle(thread->thread);
151 free(thread);
152 return 0;
153 #else
154 return pthread_detach(thread->id);
155 #endif
156 }
157
158 /**
159 * sthread_join:
160 * @thread : pointer to thread object
161 *
162 * Join with a terminated thread. Waits for the thread specified by
163 * @thread to terminate. If that thread has already terminated, then
164 * it will return immediately. The thread specified by @thread must
165 * be joinable.
166 *
167 * Returns: 0 on success, otherwise it returns a non-zero error number.
168 */
169 void sthread_join(sthread_t *thread)
170 {
171 #ifdef _WIN32
172 WaitForSingleObject(thread->thread, INFINITE);
173 CloseHandle(thread->thread);
174 #else
175 pthread_join(thread->id, NULL);
176 #endif
177 free(thread);
178 }
179
180 /**
181 * slock_new:
182 *
183 * Create and initialize a new mutex. Must be manually
184 * freed.
185 *
186 * Returns: pointer to a new mutex if successful, otherwise NULL.
187 **/
188 slock_t *slock_new(void)
189 {
190 slock_t *lock = (slock_t*)calloc(1, sizeof(*lock));
191 if (!lock)
192 return NULL;
193
194 #ifdef _WIN32
195 lock->lock = CreateMutex(NULL, FALSE, NULL);
196 if (!lock->lock)
197 #else
198 if (pthread_mutex_init(&lock->lock, NULL) < 0)
199 #endif
200 {
201 free(lock);
202 return NULL;
203 }
204
205 return lock;
206 }
207
208 /**
209 * slock_free:
210 * @lock : pointer to mutex object
211 *
212 * Frees a mutex.
213 **/
214 void slock_free(slock_t *lock)
215 {
216 if (!lock)
217 return;
218
219 #ifdef _WIN32
220 CloseHandle(lock->lock);
221 #else
222 pthread_mutex_destroy(&lock->lock);
223 #endif
224 free(lock);
225 }
226
227 /**
228 * slock_lock:
229 * @lock : pointer to mutex object
230 *
231 * Locks a mutex. If a mutex is already locked by
232 * another thread, the calling thread shall block until
233 * the mutex becomes available.
234 **/
235 void slock_lock(slock_t *lock)
236 {
237 #ifdef _WIN32
238 WaitForSingleObject(lock->lock, INFINITE);
239 #else
240 pthread_mutex_lock(&lock->lock);
241 #endif
242 }
243
244 /**
245 * slock_unlock:
246 * @lock : pointer to mutex object
247 *
248 * Unlocks a mutex.
249 **/
250 void slock_unlock(slock_t *lock)
251 {
252 #ifdef _WIN32
253 ReleaseMutex(lock->lock);
254 #else
255 pthread_mutex_unlock(&lock->lock);
256 #endif
257 }
258
259 /**
260 * scond_new:
261 *
262 * Creates and initializes a condition variable. Must
263 * be manually freed.
264 *
265 * Returns: pointer to new condition variable on success,
266 * otherwise NULL.
267 **/
268 scond_t *scond_new(void)
269 {
270 scond_t *cond = (scond_t*)calloc(1, sizeof(*cond));
271 if (!cond)
272 return NULL;
273
274 #ifdef _WIN32
275 cond->event = CreateEvent(NULL, FALSE, FALSE, NULL);
276 if (!cond->event)
277 #else
278 if (pthread_cond_init(&cond->cond, NULL) < 0)
279 #endif
280 {
281 free(cond);
282 return NULL;
283 }
284
285 return cond;
286 }
287
288 /**
289 * scond_free:
290 * @cond : pointer to condition variable object
291 *
292 * Frees a condition variable.
293 **/
294 void scond_free(scond_t *cond)
295 {
296 if (!cond)
297 return;
298
299 #ifdef _WIN32
300 CloseHandle(cond->event);
301 #else
302 pthread_cond_destroy(&cond->cond);
303 #endif
304 free(cond);
305 }
306
307 /**
308 * scond_wait:
309 * @cond : pointer to condition variable object
310 * @lock : pointer to mutex object
311 *
312 * Block on a condition variable (i.e. wait on a condition).
313 **/
314 void scond_wait(scond_t *cond, slock_t *lock)
315 {
316 #ifdef _WIN32
317 WaitForSingleObject(cond->event, 0);
318
319 SignalObjectAndWait(lock->lock, cond->event, INFINITE, FALSE);
320 slock_lock(lock);
321 #else
322 pthread_cond_wait(&cond->cond, &lock->lock);
323 #endif
324 }
325
326 /**
327 * scond_broadcast:
328 * @cond : pointer to condition variable object
329 *
330 * Broadcast a condition. Unblocks all threads currently blocked
331 * on the specified condition variable @cond.
332 **/
333 int scond_broadcast(scond_t *cond)
334 {
335 #ifdef _WIN32
336 /* FIXME _- check how this function should differ
337 * from scond_signal implementation. */
338 SetEvent(cond->event);
339 return 0;
340 #else
341 return pthread_cond_broadcast(&cond->cond);
342 #endif
343 }
344
345 /**
346 * scond_signal:
347 * @cond : pointer to condition variable object
348 *
349 * Signal a condition. Unblocks at least one of the threads currently blocked
350 * on the specified condition variable @cond.
351 **/
352 void scond_signal(scond_t *cond)
353 {
354 #ifdef _WIN32
355 SetEvent(cond->event);
356 #else
357 pthread_cond_signal(&cond->cond);
358 #endif
359 }
360
361 /**
362 * scond_wait_timeout:
363 * @cond : pointer to condition variable object
364 * @lock : pointer to mutex object
365 * @timeout_us : timeout (in microseconds)
366 *
367 * Try to block on a condition variable (i.e. wait on a condition) until
368 * @timeout_us elapses.
369 *
370 * Returns: false (0) if timeout elapses before condition variable is
371 * signaled or broadcast, otherwise true (1).
372 **/
373 bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us)
374 {
375 #ifdef _WIN32
376 DWORD ret;
377
378 WaitForSingleObject(cond->event, 0);
379 ret = SignalObjectAndWait(lock->lock, cond->event,
380 (DWORD)(timeout_us) / 1000, FALSE);
381
382 slock_lock(lock);
383 return ret == WAIT_OBJECT_0;
384 #else
385 int ret;
386 int64_t seconds, remainder;
387 struct timespec now = {0};
388
389 #ifdef __MACH__
390 /* OSX doesn't have clock_gettime. */
391 clock_serv_t cclock;
392 mach_timespec_t mts;
393
394 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
395 clock_get_time(cclock, &mts);
396 mach_port_deallocate(mach_task_self(), cclock);
397 now.tv_sec = mts.tv_sec;
398 now.tv_nsec = mts.tv_nsec;
399 #elif defined(__CELLOS_LV2__)
400 sys_time_sec_t s;
401 sys_time_nsec_t n;
402
403 sys_time_get_current_time(&s, &n);
404 now.tv_sec = s;
405 now.tv_nsec = n;
406 #elif defined(__mips__)
407 struct timeval tm;
408
409 gettimeofday(&tm, NULL);
410 now.tv_sec = tm.tv_sec;
411 now.tv_nsec = tm.tv_usec * 1000;
412 #elif !defined(GEKKO)
413 /* timeout on libogc is duration, not end time. */
414 clock_gettime(CLOCK_REALTIME, &now);
415 #endif
416
417 seconds = timeout_us / INT64_C(1000000);
418 remainder = timeout_us % INT64_C(1000000);
419
420 now.tv_sec += seconds;
421 now.tv_nsec += remainder * INT64_C(1000);
422
423 ret = pthread_cond_timedwait(&cond->cond, &lock->lock, &now);
424 return (ret == 0);
425 #endif
426 }
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (xenon_sdl_threads.c).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 // libSDLxenon doesn't implement this yet :[. Implement it very stupidly for now. ;)
23
24 #include "SDL_thread.h"
25 #include "SDL_mutex.h"
26 #include <stdlib.h>
27 #include <boolean.h>
28
29 SDL_cond *SDL_CreateCond(void)
30 {
31 bool *sleeping = calloc(1, sizeof(*sleeping));
32 return (SDL_cond*)sleeping;
33 }
34
35 void SDL_DestroyCond(SDL_cond *sleeping)
36 {
37 free(sleeping);
38 }
39
40 int SDL_CondWait(SDL_cond *cond, SDL_mutex *lock)
41 {
42 (void)lock;
43 volatile bool *sleeping = (volatile bool*)cond;
44
45 SDL_mutexV(lock);
46 *sleeping = true;
47 while (*sleeping); /* Yeah, we all love busyloops don't we? ._. */
48 SDL_mutexP(lock);
49
50 return 0;
51 }
52
53 int SDL_CondSignal(SDL_cond *cond)
54 {
55 *(volatile bool*)cond = false;
56 return 0;
57 }
58
0 #include "mednafen/mednafen.h"
1 #include "mednafen/mempatcher.h"
2 #include "mednafen/git.h"
3 #include "mednafen/general.h"
4 #include "mednafen/md5.h"
5 #include "mednafen/msvc_compat.h"
6 #ifdef NEED_DEINTERLACER
7 #include "mednafen/video/Deinterlacer.h"
8 #endif
9 #include "libretro.h"
10 #include <rthreads/rthreads.h>
11 #include <retro_stat.h>
12
13 struct retro_perf_callback perf_cb;
14 retro_get_cpu_features_t perf_get_cpu_features_cb = NULL;
15 retro_log_printf_t log_cb;
16 static retro_video_refresh_t video_cb;
17 static retro_audio_sample_t audio_cb;
18 static retro_audio_sample_batch_t audio_batch_cb;
19 static retro_environment_t environ_cb;
20 static retro_input_poll_t input_poll_cb;
21 static retro_input_state_t input_state_cb;
22 static retro_rumble_interface rumble;
23 static unsigned players = 2;
24
25 unsigned char widescreen_hack;
26 unsigned char widescreen_auto_ar;
27 unsigned char widescreen_auto_ar_old;
28
29 static bool is_pal;
30
31 char retro_save_directory[4096];
32 char retro_base_directory[4096];
33 static char retro_cd_base_directory[4096];
34 static char retro_cd_path[4096];
35 char retro_cd_base_name[4096];
36 #ifdef _WIN32
37 static char retro_slash = '\\';
38 #else
39 static char retro_slash = '/';
40 #endif
41
42 static void extract_basename(char *buf, const char *path, size_t size)
43 {
44 const char *base = strrchr(path, '/');
45 if (!base)
46 base = strrchr(path, '\\');
47 if (!base)
48 base = path;
49
50 if (*base == '\\' || *base == '/')
51 base++;
52
53 strncpy(buf, base, size - 1);
54 buf[size - 1] = '\0';
55
56 char *ext = strrchr(buf, '.');
57 if (ext)
58 *ext = '\0';
59 }
60
61 static void extract_directory(char *buf, const char *path, size_t size)
62 {
63 strncpy(buf, path, size - 1);
64 buf[size - 1] = '\0';
65
66 char *base = strrchr(buf, '/');
67 if (!base)
68 base = strrchr(buf, '\\');
69
70 if (base)
71 *base = '\0';
72 else
73 buf[0] = '\0';
74 }
75
76 /* start of Mednafen psx.cpp */
77
78 /* Mednafen - Multi-system Emulator
79 *
80 * This program is free software; you can redistribute it and/or modify
81 * it under the terms of the GNU General Public License as published by
82 * the Free Software Foundation; either version 2 of the License, or
83 * (at your option) any later version.
84 *
85 * This program is distributed in the hope that it will be useful,
86 * but WITHOUT ANY WARRANTY; without even the implied warranty of
87 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
88 * GNU General Public License for more details.
89 *
90 * You should have received a copy of the GNU General Public License
91 * along with this program; if not, write to the Free Software
92 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
93 */
94
95 #include "mednafen/psx/psx.h"
96 #include "mednafen/psx/mdec.h"
97 #include "mednafen/psx/frontio.h"
98 #include "mednafen/psx/timer.h"
99 #include "mednafen/psx/sio.h"
100 #include "mednafen/psx/cdc.h"
101 #include "mednafen/psx/spu.h"
102 #include "mednafen/mempatcher.h"
103
104 #include <stdarg.h>
105 #include <ctype.h>
106
107 bool setting_apply_analog_toggle = false;
108 bool use_mednafen_memcard0_method = false;
109
110 extern MDFNGI EmulatedPSX;
111 MDFNGI *MDFNGameInfo = &EmulatedPSX;
112
113 enum
114 {
115 REGION_JP = 0,
116 REGION_NA = 1,
117 REGION_EU = 2,
118 };
119
120 #if PSX_DBGPRINT_ENABLE
121 static unsigned psx_dbg_level = 0;
122
123 void PSX_DBG(unsigned level, const char *format, ...)
124 {
125 if(psx_dbg_level >= level)
126 {
127 va_list ap;
128 va_start(ap, format);
129 trio_vprintf(format, ap);
130 va_end(ap);
131 }
132 }
133 #else
134 static unsigned const psx_dbg_level = 0;
135 #endif
136
137 /* Based off(but not the same as) public-domain "JKISS" PRNG. */
138 struct MDFN_PseudoRNG
139 {
140 uint32_t x,y,z,c;
141 uint64_t lcgo;
142 };
143
144 static MDFN_PseudoRNG PSX_PRNG;
145
146 uint32_t PSX_GetRandU32(uint32_t mina, uint32_t maxa)
147 {
148 uint32_t tmp;
149 const uint32_t range_m1 = maxa - mina;
150 uint32_t range_mask = range_m1;
151
152 range_mask |= range_mask >> 1;
153 range_mask |= range_mask >> 2;
154 range_mask |= range_mask >> 4;
155 range_mask |= range_mask >> 8;
156 range_mask |= range_mask >> 16;
157
158 do
159 {
160 uint64_t t = 4294584393ULL * PSX_PRNG.z + PSX_PRNG.c;
161
162 PSX_PRNG.x = 314527869 * PSX_PRNG.x + 1234567;
163 PSX_PRNG.y ^= PSX_PRNG.y << 5;
164 PSX_PRNG.y ^= PSX_PRNG.y >> 7;
165 PSX_PRNG.y ^= PSX_PRNG.y << 22;
166 PSX_PRNG.c = t >> 32;
167 PSX_PRNG.z = t;
168 PSX_PRNG.lcgo = (19073486328125ULL * PSX_PRNG.lcgo) + 1;
169 tmp = ((PSX_PRNG.x + PSX_PRNG.y + PSX_PRNG.z) ^ (PSX_PRNG.lcgo >> 16)) & range_mask;
170 } while(tmp > range_m1);
171
172 return(mina + tmp);
173 }
174
175 static std::vector<CDIF*> *cdifs = NULL;
176 static std::vector<const char *> cdifs_scex_ids;
177 static bool CD_TrayOpen;
178 static int CD_SelectedDisc; // -1 for no disc
179
180 static uint64_t Memcard_PrevDC[8];
181 static int64_t Memcard_SaveDelay[8];
182
183 PS_CPU *CPU = NULL;
184 PS_SPU *SPU = NULL;
185 PS_GPU *GPU = NULL;
186 PS_CDC *CDC = NULL;
187 FrontIO *FIO = NULL;
188
189 static MultiAccessSizeMem<512 * 1024, uint32, false> *BIOSROM = NULL;
190 static MultiAccessSizeMem<65536, uint32, false> *PIOMem = NULL;
191
192 MultiAccessSizeMem<2048 * 1024, uint32, false> MainRAM;
193
194 static uint32_t TextMem_Start;
195 static std::vector<uint8> TextMem;
196
197 static const uint32_t SysControl_Mask[9] = { 0x00ffffff, 0x00ffffff, 0xffffffff, 0x2f1fffff,
198 0xffffffff, 0x2f1fffff, 0x2f1fffff, 0xffffffff,
199 0x0003ffff };
200
201 static const uint32_t SysControl_OR[9] = { 0x1f000000, 0x1f000000, 0x00000000, 0x00000000,
202 0x00000000, 0x00000000, 0x00000000, 0x00000000,
203 0x00000000 };
204
205 static struct
206 {
207 union
208 {
209 struct
210 {
211 uint32_t PIO_Base; // 0x1f801000 // BIOS Init: 0x1f000000, Writeable bits: 0x00ffffff(assumed, verify), FixedOR = 0x1f000000
212 uint32_t Unknown0; // 0x1f801004 // BIOS Init: 0x1f802000, Writeable bits: 0x00ffffff, FixedOR = 0x1f000000
213 uint32_t Unknown1; // 0x1f801008 // BIOS Init: 0x0013243f, ????
214 uint32_t Unknown2; // 0x1f80100c // BIOS Init: 0x00003022, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000
215
216 uint32_t BIOS_Mapping; // 0x1f801010 // BIOS Init: 0x0013243f, ????
217 uint32_t SPU_Delay; // 0x1f801014 // BIOS Init: 0x200931e1, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000 - Affects bus timing on access to SPU
218 uint32_t CDC_Delay; // 0x1f801018 // BIOS Init: 0x00020843, Writeable bits: 0x2f1fffff, FixedOR = 0x00000000
219 uint32_t Unknown4; // 0x1f80101c // BIOS Init: 0x00070777, ????
220 uint32_t Unknown5; // 0x1f801020 // BIOS Init: 0x00031125(but rewritten with other values often), Writeable bits: 0x0003ffff, FixedOR = 0x00000000 -- Possibly CDC related
221 };
222 uint32_t Regs[9];
223 };
224 } SysControl;
225
226 static unsigned DMACycleSteal = 0; // Doesn't need to be saved in save states, since it's calculated in the ForceEventUpdates() call chain.
227
228 void PSX_SetDMACycleSteal(unsigned stealage)
229 {
230 if (stealage > 200) // Due to 8-bit limitations in the CPU core.
231 stealage = 200;
232
233 DMACycleSteal = stealage;
234 }
235
236 //
237 // Event stuff
238 //
239
240 static int32_t Running; // Set to -1 when not desiring exit, and 0 when we are.
241
242 struct event_list_entry
243 {
244 uint32_t which;
245 int32_t event_time;
246 event_list_entry *prev;
247 event_list_entry *next;
248 };
249
250 static event_list_entry events[PSX_EVENT__COUNT];
251
252 static void EventReset(void)
253 {
254 unsigned i;
255 for(i = 0; i < PSX_EVENT__COUNT; i++)
256 {
257 events[i].which = i;
258
259 if(i == PSX_EVENT__SYNFIRST)
260 events[i].event_time = 0;
261 else if(i == PSX_EVENT__SYNLAST)
262 events[i].event_time = 0x7FFFFFFF;
263 else
264 events[i].event_time = PSX_EVENT_MAXTS;
265
266 events[i].prev = (i > 0) ? &events[i - 1] : NULL;
267 events[i].next = (i < (PSX_EVENT__COUNT - 1)) ? &events[i + 1] : NULL;
268 }
269 }
270
271 //static void RemoveEvent(event_list_entry *e)
272 //{
273 // e->prev->next = e->next;
274 // e->next->prev = e->prev;
275 //}
276
277 static void RebaseTS(const int32_t timestamp)
278 {
279 unsigned i;
280 for(i = 0; i < PSX_EVENT__COUNT; i++)
281 {
282 if(i == PSX_EVENT__SYNFIRST || i == PSX_EVENT__SYNLAST)
283 continue;
284
285 assert(events[i].event_time > timestamp);
286 events[i].event_time -= timestamp;
287 }
288
289 CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time);
290 }
291
292 void PSX_SetEventNT(const int type, const int32_t next_timestamp)
293 {
294 event_list_entry *e = &events[type];
295
296 if(next_timestamp < e->event_time)
297 {
298 event_list_entry *fe = e;
299
300 do
301 {
302 fe = fe->prev;
303 }while(next_timestamp < fe->event_time);
304
305 // Remove this event from the list, temporarily of course.
306 e->prev->next = e->next;
307 e->next->prev = e->prev;
308
309 // Insert into the list, just after "fe".
310 e->prev = fe;
311 e->next = fe->next;
312 fe->next->prev = e;
313 fe->next = e;
314
315 e->event_time = next_timestamp;
316 }
317 else if(next_timestamp > e->event_time)
318 {
319 event_list_entry *fe = e;
320
321 do
322 {
323 fe = fe->next;
324 } while(next_timestamp > fe->event_time);
325
326 // Remove this event from the list, temporarily of course
327 e->prev->next = e->next;
328 e->next->prev = e->prev;
329
330 // Insert into the list, just BEFORE "fe".
331 e->prev = fe->prev;
332 e->next = fe;
333 fe->prev->next = e;
334 fe->prev = e;
335
336 e->event_time = next_timestamp;
337 }
338
339 CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time & Running);
340 }
341
342 // Called from debug.cpp too.
343 void ForceEventUpdates(const int32_t timestamp)
344 {
345 PSX_SetEventNT(PSX_EVENT_GPU, GPU->Update(timestamp));
346 PSX_SetEventNT(PSX_EVENT_CDC, CDC->Update(timestamp));
347
348 PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(timestamp));
349
350 PSX_SetEventNT(PSX_EVENT_DMA, DMA_Update(timestamp));
351
352 PSX_SetEventNT(PSX_EVENT_FIO, FIO->Update(timestamp));
353
354 CPU->SetEventNT(events[PSX_EVENT__SYNFIRST].next->event_time);
355 }
356
357 bool MDFN_FASTCALL PSX_EventHandler(const int32_t timestamp)
358 {
359 event_list_entry *e = events[PSX_EVENT__SYNFIRST].next;
360
361 while(timestamp >= e->event_time) // If Running = 0, PSX_EventHandler() may be called even if there isn't an event per-se, so while() instead of do { ... } while
362 {
363 int32_t nt;
364 event_list_entry *prev = e->prev;
365
366 switch(e->which)
367 {
368 default:
369 abort();
370 case PSX_EVENT_GPU:
371 nt = GPU->Update(e->event_time);
372 break;
373 case PSX_EVENT_CDC:
374 nt = CDC->Update(e->event_time);
375 break;
376 case PSX_EVENT_TIMER:
377 nt = TIMER_Update(e->event_time);
378 break;
379 case PSX_EVENT_DMA:
380 nt = DMA_Update(e->event_time);
381 break;
382 case PSX_EVENT_FIO:
383 nt = FIO->Update(e->event_time);
384 break;
385 }
386
387 PSX_SetEventNT(e->which, nt);
388
389 // Order of events can change due to calling PSX_SetEventNT(), this prev business ensures we don't miss an event due to reordering.
390 e = prev->next;
391 }
392
393 return(Running);
394 }
395
396
397 void PSX_RequestMLExit(void)
398 {
399 Running = 0;
400 CPU->SetEventNT(0);
401 }
402
403
404 //
405 // End event stuff
406 //
407
408
409 // Remember to update MemPeek<>() when we change address decoding in MemRW()
410 template<typename T, bool IsWrite, bool Access24> static INLINE void MemRW(int32_t &timestamp, uint32_t A, uint32_t &V)
411 {
412 #if 0
413 if(IsWrite)
414 printf("Write%d: %08x(orig=%08x), %08x\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A, V);
415 else
416 printf("Read%d: %08x(orig=%08x)\n", (int)(sizeof(T) * 8), A & mask[A >> 29], A);
417 #endif
418
419 if(!IsWrite)
420 timestamp += DMACycleSteal;
421
422 //if(A == 0xa0 && IsWrite)
423 // DBG_Break();
424
425 if(A < 0x00800000)
426 {
427 if(IsWrite)
428 {
429 //timestamp++; // Best-case timing.
430 }
431 else
432 {
433 timestamp += 3;
434 }
435
436 if(Access24)
437 {
438 if(IsWrite)
439 MainRAM.WriteU24(A & 0x1FFFFF, V);
440 else
441 V = MainRAM.ReadU24(A & 0x1FFFFF);
442 }
443 else
444 {
445 if(IsWrite)
446 MainRAM.Write<T>(A & 0x1FFFFF, V);
447 else
448 V = MainRAM.Read<T>(A & 0x1FFFFF);
449 }
450
451 return;
452 }
453
454 if(A >= 0x1FC00000 && A <= 0x1FC7FFFF)
455 {
456 if(!IsWrite)
457 {
458 if(Access24)
459 V = BIOSROM->ReadU24(A & 0x7FFFF);
460 else
461 V = BIOSROM->Read<T>(A & 0x7FFFF);
462 }
463
464 return;
465 }
466
467 if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
468 PSX_EventHandler(timestamp);
469
470 if(A >= 0x1F801000 && A <= 0x1F802FFF)
471 {
472
473 //if(IsWrite)
474 // printf("HW Write%d: %08x %08x\n", (unsigned int)(sizeof(T)*8), (unsigned int)A, (unsigned int)V);
475 //else
476 // printf("HW Read%d: %08x\n", (unsigned int)(sizeof(T)*8), (unsigned int)A);
477
478 if(A >= 0x1F801C00 && A <= 0x1F801FFF) // SPU
479 {
480 if(sizeof(T) == 4 && !Access24)
481 {
482 if(IsWrite)
483 {
484 //timestamp += 15;
485
486 //if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
487 // PSX_EventHandler(timestamp);
488
489 SPU->Write(timestamp, A | 0, V);
490 SPU->Write(timestamp, A | 2, V >> 16);
491 }
492 else
493 {
494 timestamp += 36;
495
496 if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
497 PSX_EventHandler(timestamp);
498
499 V = SPU->Read(timestamp, A) | (SPU->Read(timestamp, A | 2) << 16);
500 }
501 }
502 else
503 {
504 if(IsWrite)
505 {
506 //timestamp += 8;
507
508 //if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
509 // PSX_EventHandler(timestamp);
510
511 SPU->Write(timestamp, A & ~1, V);
512 }
513 else
514 {
515 timestamp += 16; // Just a guess, need to test.
516
517 if(timestamp >= events[PSX_EVENT__SYNFIRST].next->event_time)
518 PSX_EventHandler(timestamp);
519
520 V = SPU->Read(timestamp, A & ~1);
521 }
522 }
523 return;
524 } // End SPU
525
526
527 // CDC: TODO - 8-bit access.
528 if(A >= 0x1f801800 && A <= 0x1f80180F)
529 {
530 if(!IsWrite)
531 {
532 timestamp += 6 * sizeof(T); //24;
533 }
534
535 if(IsWrite)
536 CDC->Write(timestamp, A & 0x3, V);
537 else
538 V = CDC->Read(timestamp, A & 0x3);
539
540 return;
541 }
542
543 if(A >= 0x1F801810 && A <= 0x1F801817)
544 {
545 if(!IsWrite)
546 timestamp++;
547
548 if(IsWrite)
549 GPU->Write(timestamp, A, V);
550 else
551 V = GPU->Read(timestamp, A);
552
553 return;
554 }
555
556 if(A >= 0x1F801820 && A <= 0x1F801827)
557 {
558 if(!IsWrite)
559 timestamp++;
560
561 if(IsWrite)
562 MDEC_Write(timestamp, A, V);
563 else
564 V = MDEC_Read(timestamp, A);
565
566 return;
567 }
568
569 if(A >= 0x1F801000 && A <= 0x1F801023)
570 {
571 unsigned index = (A & 0x1F) >> 2;
572
573 if(!IsWrite)
574 timestamp++;
575
576 //if(A == 0x1F801014 && IsWrite)
577 // fprintf(stderr, "%08x %08x\n",A,V);
578
579 if(IsWrite)
580 {
581 V <<= (A & 3) * 8;
582 SysControl.Regs[index] = V & SysControl_Mask[index];
583 }
584 else
585 {
586 V = SysControl.Regs[index] | SysControl_OR[index];
587 V >>= (A & 3) * 8;
588 }
589 return;
590 }
591
592 if(A >= 0x1F801040 && A <= 0x1F80104F)
593 {
594 if(!IsWrite)
595 timestamp++;
596
597 if(IsWrite)
598 FIO->Write(timestamp, A, V);
599 else
600 V = FIO->Read(timestamp, A);
601 return;
602 }
603
604 if(A >= 0x1F801050 && A <= 0x1F80105F)
605 {
606 if(!IsWrite)
607 timestamp++;
608
609 #if 0
610 if(IsWrite)
611 {
612 PSX_WARNING("[SIO] Write: 0x%08x 0x%08x %u", A, V, (unsigned)sizeof(T));
613 }
614 else
615 {
616 PSX_WARNING("[SIO] Read: 0x%08x", A);
617 }
618 #endif
619
620 if(IsWrite)
621 SIO_Write(timestamp, A, V);
622 else
623 V = SIO_Read(timestamp, A);
624 return;
625 }
626
627 #if 0
628 if(A >= 0x1F801060 && A <= 0x1F801063)
629 {
630 if(IsWrite)
631 {
632
633 }
634 else
635 {
636
637 }
638
639 return;
640 }
641 #endif
642
643 if(A >= 0x1F801070 && A <= 0x1F801077) // IRQ
644 {
645 if(!IsWrite)
646 timestamp++;
647
648 if(IsWrite)
649 ::IRQ_Write(A, V);
650 else
651 V = ::IRQ_Read(A);
652 return;
653 }
654
655 if(A >= 0x1F801080 && A <= 0x1F8010FF) // DMA
656 {
657 if(!IsWrite)
658 timestamp++;
659
660 if(IsWrite)
661 DMA_Write(timestamp, A, V);
662 else
663 V = DMA_Read(timestamp, A);
664
665 return;
666 }
667
668 if(A >= 0x1F801100 && A <= 0x1F80113F) // Root counters
669 {
670 if(!IsWrite)
671 timestamp++;
672
673 if(IsWrite)
674 TIMER_Write(timestamp, A, V);
675 else
676 V = TIMER_Read(timestamp, A);
677
678 return;
679 }
680 }
681
682
683 if(A >= 0x1F000000 && A <= 0x1F7FFFFF)
684 {
685 if(!IsWrite)
686 {
687 //if((A & 0x7FFFFF) <= 0x84)
688 //PSX_WARNING("[PIO] Read%d from 0x%08x at time %d", (int)(sizeof(T) * 8), A, timestamp);
689
690 V = ~0U; // A game this affects: Tetris with Cardcaptor Sakura
691
692 if(PIOMem)
693 {
694 if((A & 0x7FFFFF) < 65536)
695 {
696 if(Access24)
697 V = PIOMem->ReadU24(A & 0x7FFFFF);
698 else
699 V = PIOMem->Read<T>(A & 0x7FFFFF);
700 }
701 else if((A & 0x7FFFFF) < (65536 + TextMem.size()))
702 {
703 if(Access24)
704 V = MDFN_de24lsb(&TextMem[(A & 0x7FFFFF) - 65536]);
705 else switch(sizeof(T))
706 {
707 case 1: V = TextMem[(A & 0x7FFFFF) - 65536]; break;
708 case 2: V = MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break;
709 case 4: V = MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536]); break;
710 }
711 }
712 }
713 }
714 return;
715 }
716
717 if(A == 0xFFFE0130) // Per tests on PS1, ignores the access(sort of, on reads the value is forced to 0 if not aligned) if not aligned to 4-bytes.
718 {
719 if(!IsWrite)
720 V = CPU->GetBIU();
721 else
722 CPU->SetBIU(V);
723
724 return;
725 }
726
727 if(IsWrite)
728 {
729 PSX_WARNING("[MEM] Unknown write%d to %08x at time %d, =%08x(%d)", (int)(sizeof(T) * 8), A, timestamp, V, V);
730 }
731 else
732 {
733 V = 0;
734 PSX_WARNING("[MEM] Unknown read%d from %08x at time %d", (int)(sizeof(T) * 8), A, timestamp);
735 }
736 }
737
738 void MDFN_FASTCALL PSX_MemWrite8(int32_t timestamp, uint32_t A, uint32_t V)
739 {
740 MemRW<uint8, true, false>(timestamp, A, V);
741 }
742
743 void MDFN_FASTCALL PSX_MemWrite16(int32_t timestamp, uint32_t A, uint32_t V)
744 {
745 MemRW<uint16, true, false>(timestamp, A, V);
746 }
747
748 void MDFN_FASTCALL PSX_MemWrite24(int32_t timestamp, uint32_t A, uint32_t V)
749 {
750 MemRW<uint32, true, true>(timestamp, A, V);
751 }
752
753 void MDFN_FASTCALL PSX_MemWrite32(int32_t timestamp, uint32_t A, uint32_t V)
754 {
755 MemRW<uint32, true, false>(timestamp, A, V);
756 }
757
758 uint8_t MDFN_FASTCALL PSX_MemRead8(int32_t &timestamp, uint32_t A)
759 {
760 uint32_t V;
761
762 MemRW<uint8, false, false>(timestamp, A, V);
763
764 return(V);
765 }
766
767 uint16_t MDFN_FASTCALL PSX_MemRead16(int32_t &timestamp, uint32_t A)
768 {
769 uint32_t V;
770
771 MemRW<uint16, false, false>(timestamp, A, V);
772
773 return(V);
774 }
775
776 uint32_t MDFN_FASTCALL PSX_MemRead24(int32_t &timestamp, uint32_t A)
777 {
778 uint32_t V;
779
780 MemRW<uint32, false, true>(timestamp, A, V);
781
782 return(V);
783 }
784
785 uint32_t MDFN_FASTCALL PSX_MemRead32(int32_t &timestamp, uint32_t A)
786 {
787 uint32_t V;
788
789 MemRW<uint32, false, false>(timestamp, A, V);
790
791 return(V);
792 }
793
794 template<typename T, bool Access24> static INLINE uint32_t MemPeek(int32_t timestamp, uint32_t A)
795 {
796 if(A < 0x00800000)
797 {
798 if(Access24)
799 return(MainRAM.ReadU24(A & 0x1FFFFF));
800 return(MainRAM.Read<T>(A & 0x1FFFFF));
801 }
802
803 if(A >= 0x1FC00000 && A <= 0x1FC7FFFF)
804 {
805 if(Access24)
806 return(BIOSROM->ReadU24(A & 0x7FFFF));
807 return(BIOSROM->Read<T>(A & 0x7FFFF));
808 }
809
810 if(A >= 0x1F801000 && A <= 0x1F802FFF)
811 {
812 if(A >= 0x1F801C00 && A <= 0x1F801FFF) // SPU
813 {
814 // TODO
815
816 } // End SPU
817
818
819 // CDC: TODO - 8-bit access.
820 if(A >= 0x1f801800 && A <= 0x1f80180F)
821 {
822 // TODO
823
824 }
825
826 if(A >= 0x1F801810 && A <= 0x1F801817)
827 {
828 // TODO
829
830 }
831
832 if(A >= 0x1F801820 && A <= 0x1F801827)
833 {
834 // TODO
835
836 }
837
838 if(A >= 0x1F801000 && A <= 0x1F801023)
839 {
840 unsigned index = (A & 0x1F) >> 2;
841 return((SysControl.Regs[index] | SysControl_OR[index]) >> ((A & 3) * 8));
842 }
843
844 if(A >= 0x1F801040 && A <= 0x1F80104F)
845 {
846 // TODO
847
848 }
849
850 if(A >= 0x1F801050 && A <= 0x1F80105F)
851 {
852 // TODO
853
854 }
855
856
857 if(A >= 0x1F801070 && A <= 0x1F801077) // IRQ
858 {
859 // TODO
860
861 }
862
863 if(A >= 0x1F801080 && A <= 0x1F8010FF) // DMA
864 {
865 // TODO
866
867 }
868
869 if(A >= 0x1F801100 && A <= 0x1F80113F) // Root counters
870 {
871 // TODO
872
873 }
874 }
875
876
877 if(A >= 0x1F000000 && A <= 0x1F7FFFFF)
878 {
879 if(PIOMem)
880 {
881 if((A & 0x7FFFFF) < 65536)
882 {
883 if(Access24)
884 return(PIOMem->ReadU24(A & 0x7FFFFF));
885 return(PIOMem->Read<T>(A & 0x7FFFFF));
886 }
887 else if((A & 0x7FFFFF) < (65536 + TextMem.size()))
888 {
889 if(Access24)
890 return(MDFN_de24lsb(&TextMem[(A & 0x7FFFFF) - 65536]));
891 else switch(sizeof(T))
892 {
893 case 1:
894 return(TextMem[(A & 0x7FFFFF) - 65536]);
895 case 2:
896 return(MDFN_de16lsb(&TextMem[(A & 0x7FFFFF) - 65536]));
897 case 4:
898 return(MDFN_de32lsb(&TextMem[(A & 0x7FFFFF) - 65536]));
899 }
900 }
901 }
902 return(~0U);
903 }
904
905 if(A == 0xFFFE0130)
906 return CPU->GetBIU();
907
908 return(0);
909 }
910
911 uint8_t PSX_MemPeek8(uint32_t A)
912 {
913 return MemPeek<uint8, false>(0, A);
914 }
915
916 uint16_t PSX_MemPeek16(uint32_t A)
917 {
918 return MemPeek<uint16, false>(0, A);
919 }
920
921 uint32_t PSX_MemPeek32(uint32_t A)
922 {
923 return MemPeek<uint32, false>(0, A);
924 }
925
926 // FIXME: Add PSX_Reset() and FrontIO::Reset() so that emulated input devices don't get power-reset on reset-button reset.
927 static void PSX_Power(void)
928 {
929 unsigned i;
930
931 PSX_PRNG.x = 123456789;
932 PSX_PRNG.y = 987654321;
933 PSX_PRNG.z = 43219876;
934 PSX_PRNG.c = 6543217;
935 PSX_PRNG.lcgo = 0xDEADBEEFCAFEBABEULL;
936
937 memset(MainRAM.data32, 0, 2048 * 1024);
938
939 for(i = 0; i < 9; i++)
940 SysControl.Regs[i] = 0;
941
942 CPU->Power();
943
944 EventReset();
945
946 TIMER_Power();
947
948 DMA_Power();
949
950 FIO->Power();
951 SIO_Power();
952
953 MDEC_Power();
954 CDC->Power();
955 GPU->Power();
956 //SPU->Power(); // Called from CDC->Power()
957 IRQ_Power();
958
959 ForceEventUpdates(0);
960 }
961
962
963 void PSX_GPULineHook(const int32_t timestamp, const int32_t line_timestamp, bool vsync, uint32_t *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider)
964 {
965 FIO->GPULineHook(timestamp, line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock, pix_clock_divider);
966 }
967
968 static bool TestMagic(const char *name, MDFNFILE *fp)
969 {
970 if(GET_FSIZE_PTR(fp) < 0x800)
971 return(false);
972
973 if(memcmp(GET_FDATA_PTR(fp), "PS-X EXE", 8))
974 return(false);
975
976 return(true);
977 }
978
979 static bool TestMagicCD(std::vector<CDIF *> *CDInterfaces)
980 {
981 uint8_t buf[2048];
982 TOC toc;
983 int dt;
984
985 TOC_Clear(&toc);
986
987 (*CDInterfaces)[0]->ReadTOC(&toc);
988
989 dt = TOC_FindTrackByLBA(&toc, 4);
990
991 if(dt > 0 && !(toc.tracks[dt].control & 0x4))
992 return(false);
993
994 if((*CDInterfaces)[0]->ReadSector(buf, 4, 1) != 0x2)
995 return(false);
996
997 if(strncmp((char *)buf + 10, "Licensed by", strlen("Licensed by")))
998 return(false);
999
1000 //if(strncmp((char *)buf + 32, "Sony", 4))
1001 // return(false);
1002
1003 //for(int i = 0; i < 2048; i++)
1004 // printf("%d, %02x %c\n", i, buf[i], buf[i]);
1005 //exit(1);
1006
1007 #if 0
1008 {
1009 uint8_t buf[2048 * 7];
1010
1011 if((*cdifs)[0]->ReadSector(buf, 5, 7) == 0x2)
1012 {
1013 printf("CRC32: 0x%08x\n", (uint32)crc32(0, &buf[0], 0x3278));
1014 }
1015 }
1016 #endif
1017
1018 return(true);
1019 }
1020
1021 static const char *CalcDiscSCEx_BySYSTEMCNF(CDIF *c, unsigned *rr)
1022 {
1023 const char *ret = NULL;
1024 Stream *fp = NULL;
1025
1026 uint8_t pvd[2048];
1027 unsigned pvd_search_count = 0;
1028
1029 fp = c->MakeStream(0, ~0U);
1030 fp->seek(0x8000, SEEK_SET);
1031
1032 do
1033 {
1034 if((pvd_search_count++) == 32)
1035 throw MDFN_Error(0, "PVD search count limit met.");
1036
1037 fp->read(pvd, 2048);
1038
1039 if(memcmp(&pvd[1], "CD001", 5))
1040 throw MDFN_Error(0, "Not ISO-9660");
1041
1042 if(pvd[0] == 0xFF)
1043 throw MDFN_Error(0, "Missing Primary Volume Descriptor");
1044 } while(pvd[0] != 0x01);
1045 //[156 ... 189], 34 bytes
1046 uint32_t rdel = MDFN_de32lsb(&pvd[0x9E]);
1047 uint32_t rdel_len = MDFN_de32lsb(&pvd[0xA6]);
1048
1049 if(rdel_len >= (1024 * 1024 * 10)) // Arbitrary sanity check.
1050 throw MDFN_Error(0, "Root directory table too large");
1051
1052 fp->seek((int64)rdel * 2048, SEEK_SET);
1053 //printf("%08x, %08x\n", rdel * 2048, rdel_len);
1054 while(fp->tell() < (((int64)rdel * 2048) + rdel_len))
1055 {
1056 uint8_t len_dr = fp->get_u8();
1057 uint8_t dr[256 + 1];
1058
1059 memset(dr, 0xFF, sizeof(dr));
1060
1061 if(!len_dr)
1062 break;
1063
1064 memset(dr, 0, sizeof(dr));
1065 dr[0] = len_dr;
1066 fp->read(dr + 1, len_dr - 1);
1067
1068 uint8_t len_fi = dr[0x20];
1069
1070 if(len_fi == 12 && !memcmp(&dr[0x21], "SYSTEM.CNF;1", 12))
1071 {
1072 uint32_t file_lba = MDFN_de32lsb(&dr[0x02]);
1073 //uint32_t file_len = MDFN_de32lsb(&dr[0x0A]);
1074 uint8_t fb[2048 + 1];
1075 char *bootpos;
1076
1077 memset(fb, 0, sizeof(fb));
1078 fp->seek(file_lba * 2048, SEEK_SET);
1079 fp->read(fb, 2048);
1080
1081 bootpos = strstr((char*)fb, "BOOT") + 4;
1082 while(*bootpos == ' ' || *bootpos == '\t') bootpos++;
1083 if(*bootpos == '=')
1084 {
1085 bootpos++;
1086 while(*bootpos == ' ' || *bootpos == '\t') bootpos++;
1087 if(!strncasecmp(bootpos, "cdrom:\\", 7))
1088 {
1089 bootpos += 7;
1090 char *tmp;
1091
1092 if((tmp = strchr(bootpos, '_'))) *tmp = 0;
1093 if((tmp = strchr(bootpos, '.'))) *tmp = 0;
1094 if((tmp = strchr(bootpos, ';'))) *tmp = 0;
1095 //puts(bootpos);
1096
1097 if(strlen(bootpos) == 4 && bootpos[0] == 'S' && (bootpos[1] == 'C' || bootpos[1] == 'L' || bootpos[1] == 'I'))
1098 {
1099 switch(bootpos[2])
1100 {
1101 case 'E': if(rr)
1102 *rr = REGION_EU;
1103 ret = "SCEE";
1104 goto Breakout;
1105
1106 case 'U': if(rr)
1107 *rr = REGION_NA;
1108 ret = "SCEA";
1109 goto Breakout;
1110
1111 case 'K': // Korea?
1112 case 'B':
1113 case 'P': if(rr)
1114 *rr = REGION_JP;
1115 ret = "SCEI";
1116 goto Breakout;
1117 }
1118 }
1119 }
1120 }
1121
1122 //puts((char*)fb);
1123 //puts("ASOFKOASDFKO");
1124 }
1125 }
1126
1127 Breakout:
1128 if(fp)
1129 {
1130 delete fp;
1131 fp = NULL;
1132 }
1133
1134 return(ret);
1135 }
1136
1137 static unsigned CalcDiscSCEx(void)
1138 {
1139 const char *prev_valid_id = NULL;
1140 unsigned ret_region = MDFN_GetSettingI("psx.region_default");
1141
1142 cdifs_scex_ids.clear();
1143
1144 if(cdifs)
1145 for(unsigned i = 0; i < cdifs->size(); i++)
1146 {
1147 uint8_t buf[2048];
1148 uint8_t fbuf[2048 + 1];
1149 const char *id = CalcDiscSCEx_BySYSTEMCNF((*cdifs)[i], (i == 0) ? &ret_region : NULL);
1150
1151 memset(fbuf, 0, sizeof(fbuf));
1152
1153 if(id == NULL && (*cdifs)[i]->ReadSector(buf, 4, 1) == 0x2)
1154 {
1155 unsigned ipos, opos;
1156 for(ipos = 0, opos = 0; ipos < 0x48; ipos++)
1157 {
1158 if(buf[ipos] > 0x20 && buf[ipos] < 0x80)
1159 {
1160 fbuf[opos++] = tolower(buf[ipos]);
1161 }
1162 }
1163
1164 fbuf[opos++] = 0;
1165
1166 PSX_DBG(PSX_DBG_SPARSE, "License string: %s", (char *)fbuf);
1167
1168 if(strstr((char *)fbuf, "licensedby") != NULL)
1169 {
1170 if(strstr((char *)fbuf, "america") != NULL)
1171 {
1172 id = "SCEA";
1173 if(!i)
1174 ret_region = REGION_NA;
1175 }
1176 else if(strstr((char *)fbuf, "europe") != NULL)
1177 {
1178 id = "SCEE";
1179 if(!i)
1180 ret_region = REGION_EU;
1181 }
1182 else if(strstr((char *)fbuf, "japan") != NULL)
1183 {
1184 id = "SCEI"; // ?
1185 if(!i)
1186 ret_region = REGION_JP;
1187 }
1188 else if(strstr((char *)fbuf, "sonycomputerentertainmentinc.") != NULL)
1189 {
1190 id = "SCEI";
1191 if(!i)
1192 ret_region = REGION_JP;
1193 }
1194 else // Failure case
1195 {
1196 if(prev_valid_id != NULL)
1197 id = prev_valid_id;
1198 else
1199 {
1200 switch(ret_region) // Less than correct, but meh, what can we do.
1201 {
1202 case REGION_JP:
1203 id = "SCEI";
1204 break;
1205
1206 case REGION_NA:
1207 id = "SCEA";
1208 break;
1209
1210 case REGION_EU:
1211 id = "SCEE";
1212 break;
1213 }
1214 }
1215 }
1216 }
1217 }
1218
1219 if(id != NULL)
1220 prev_valid_id = id;
1221
1222 cdifs_scex_ids.push_back(id);
1223 }
1224
1225 return ret_region;
1226 }
1227
1228 static void InitCommon(std::vector<CDIF *> *CDInterfaces, const bool EmulateMemcards = true, const bool WantPIOMem = false)
1229 {
1230 unsigned region, i;
1231 bool emulate_memcard[8];
1232 bool emulate_multitap[2];
1233 int sls, sle;
1234
1235 #if PSX_DBGPRINT_ENABLE
1236 psx_dbg_level = MDFN_GetSettingUI("psx.dbg_level");
1237 #endif
1238
1239 for(i = 0; i < 8; i++)
1240 {
1241 char buf[64];
1242 snprintf(buf, sizeof(buf), "psx.input.port%u.memcard", i + 1);
1243 emulate_memcard[i] = EmulateMemcards && MDFN_GetSettingB(buf);
1244 }
1245
1246 for(i = 0; i < 2; i++)
1247 {
1248 char buf[64];
1249 snprintf(buf, sizeof(buf), "psx.input.pport%u.multitap", i + 1);
1250 emulate_multitap[i] = MDFN_GetSettingB(buf);
1251 }
1252
1253
1254 cdifs = CDInterfaces;
1255 region = CalcDiscSCEx();
1256
1257 if(!MDFN_GetSettingB("psx.region_autodetect"))
1258 region = MDFN_GetSettingI("psx.region_default");
1259
1260 sls = MDFN_GetSettingI((region == REGION_EU) ? "psx.slstartp" : "psx.slstart");
1261 sle = MDFN_GetSettingI((region == REGION_EU) ? "psx.slendp" : "psx.slend");
1262
1263 if(sls > sle)
1264 {
1265 int tmp = sls;
1266 sls = sle;
1267 sle = tmp;
1268 }
1269
1270 CPU = new PS_CPU();
1271 SPU = new PS_SPU();
1272 GPU = new PS_GPU(region == REGION_EU, sls, sle);
1273 CDC = new PS_CDC();
1274 FIO = new FrontIO(emulate_memcard, emulate_multitap);
1275 FIO->SetAMCT(MDFN_GetSettingB("psx.input.analog_mode_ct"));
1276 for(unsigned i = 0; i < 8; i++)
1277 {
1278 char buf[64];
1279 snprintf(buf, sizeof(buf), "psx.input.port%u.gun_chairs", i + 1);
1280 FIO->SetCrosshairsColor(i, MDFN_GetSettingUI(buf));
1281 }
1282
1283 DMA_Init();
1284
1285 GPU->FillVideoParams(&EmulatedPSX);
1286
1287 CD_TrayOpen = true;
1288 CD_SelectedDisc = -1;
1289
1290 if(cdifs)
1291 {
1292 CD_TrayOpen = false;
1293 CD_SelectedDisc = 0;
1294 }
1295
1296 CDC->SetDisc(true, NULL, NULL);
1297 CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL,
1298 (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL);
1299
1300
1301 BIOSROM = new MultiAccessSizeMem<512 * 1024, uint32, false>();
1302 PIOMem = NULL;
1303
1304 if(WantPIOMem)
1305 PIOMem = new MultiAccessSizeMem<65536, uint32, false>();
1306
1307 for(uint32_t ma = 0x00000000; ma < 0x00800000; ma += 2048 * 1024)
1308 {
1309 CPU->SetFastMap(MainRAM.data32, 0x00000000 + ma, 2048 * 1024);
1310 CPU->SetFastMap(MainRAM.data32, 0x80000000 + ma, 2048 * 1024);
1311 CPU->SetFastMap(MainRAM.data32, 0xA0000000 + ma, 2048 * 1024);
1312 }
1313
1314 CPU->SetFastMap(BIOSROM->data32, 0x1FC00000, 512 * 1024);
1315 CPU->SetFastMap(BIOSROM->data32, 0x9FC00000, 512 * 1024);
1316 CPU->SetFastMap(BIOSROM->data32, 0xBFC00000, 512 * 1024);
1317
1318 if(PIOMem)
1319 {
1320 CPU->SetFastMap(PIOMem->data32, 0x1F000000, 65536);
1321 CPU->SetFastMap(PIOMem->data32, 0x9F000000, 65536);
1322 CPU->SetFastMap(PIOMem->data32, 0xBF000000, 65536);
1323 }
1324
1325
1326 MDFNMP_Init(1024, ((uint64)1 << 29) / 1024);
1327 MDFNMP_AddRAM(2048 * 1024, 0x00000000, MainRAM.data8);
1328 #if 0
1329 MDFNMP_AddRAM(1024, 0x1F800000, ScratchRAM.data8);
1330 #endif
1331
1332 const char *biospath_sname;
1333
1334 if(region == REGION_JP)
1335 biospath_sname = "psx.bios_jp";
1336 else if(region == REGION_EU)
1337 biospath_sname = "psx.bios_eu";
1338 else if(region == REGION_NA)
1339 biospath_sname = "psx.bios_na";
1340 else
1341 abort();
1342
1343 {
1344 const char *biospath = MDFN_MakeFName(MDFNMKF_FIRMWARE, 0, MDFN_GetSettingS(biospath_sname).c_str());
1345 FileStream BIOSFile(biospath, MODE_READ);
1346
1347 BIOSFile.read(BIOSROM->data8, 512 * 1024);
1348 }
1349
1350 i = 0;
1351
1352 if (!use_mednafen_memcard0_method)
1353 {
1354 FIO->LoadMemcard(0);
1355 i = 1;
1356 }
1357
1358 for(; i < 8; i++)
1359 {
1360 char ext[64];
1361 const char *memcard = NULL;
1362 snprintf(ext, sizeof(ext), "%d.mcr", i);
1363 memcard = MDFN_MakeFName(MDFNMKF_SAV, 0, ext);
1364 FIO->LoadMemcard(i, memcard);
1365 }
1366
1367 for(i = 0; i < 8; i++)
1368 {
1369 Memcard_PrevDC[i] = FIO->GetMemcardDirtyCount(i);
1370 Memcard_SaveDelay[i] = -1;
1371 }
1372
1373
1374 #ifdef WANT_DEBUGGER
1375 DBG_Init();
1376 #endif
1377 PSX_Power();
1378 }
1379
1380 static void LoadEXE(const uint8_t *data, const uint32_t size, bool ignore_pcsp = false)
1381 {
1382 uint32 PC = MDFN_de32lsb(&data[0x10]);
1383 uint32 SP = MDFN_de32lsb(&data[0x30]);
1384 uint32 TextStart = MDFN_de32lsb(&data[0x18]);
1385 uint32 TextSize = MDFN_de32lsb(&data[0x1C]);
1386
1387 if(ignore_pcsp)
1388 log_cb(RETRO_LOG_INFO, "TextStart=0x%08x\nTextSize=0x%08x\n", TextStart, TextSize);
1389 else
1390 log_cb(RETRO_LOG_INFO, "PC=0x%08x\nSP=0x%08x\nTextStart=0x%08x\nTextSize=0x%08x\n", PC, SP, TextStart, TextSize);
1391
1392 TextStart &= 0x1FFFFF;
1393
1394 if(TextSize > 2048 * 1024)
1395 throw(MDFN_Error(0, "Text section too large"));
1396
1397 if(TextSize > (size - 0x800))
1398 throw(MDFN_Error(0, "Text section recorded size is larger than data available in file. Header=0x%08x, Available=0x%08x", TextSize, size - 0x800));
1399
1400 if(TextSize < (size - 0x800))
1401 throw(MDFN_Error(0, "Text section recorded size is smaller than data available in file. Header=0x%08x, Available=0x%08x", TextSize, size - 0x800));
1402
1403 if(!TextMem.size())
1404 {
1405 TextMem_Start = TextStart;
1406 TextMem.resize(TextSize);
1407 }
1408
1409 if(TextStart < TextMem_Start)
1410 {
1411 uint32 old_size = TextMem.size();
1412
1413 //printf("RESIZE: 0x%08x\n", TextMem_Start - TextStart);
1414
1415 TextMem.resize(old_size + TextMem_Start - TextStart);
1416 memmove(&TextMem[TextMem_Start - TextStart], &TextMem[0], old_size);
1417
1418 TextMem_Start = TextStart;
1419 }
1420
1421 if(TextMem.size() < (TextStart - TextMem_Start + TextSize))
1422 TextMem.resize(TextStart - TextMem_Start + TextSize);
1423
1424 memcpy(&TextMem[TextStart - TextMem_Start], data + 0x800, TextSize);
1425
1426 // BIOS patch
1427 BIOSROM->WriteU32(0x6990, (3 << 26) | ((0xBF001000 >> 2) & ((1 << 26) - 1)));
1428 #if 0
1429 BIOSROM->WriteU32(0x691C, (3 << 26) | ((0xBF001000 >> 2) & ((1 << 26) - 1)));
1430 #endif
1431
1432 uint8 *po;
1433
1434 po = &PIOMem->data8[0x0800];
1435
1436 MDFN_en32lsb(po, (0x0 << 26) | (31 << 21) | (0x8 << 0)); // JR
1437 po += 4;
1438 MDFN_en32lsb(po, 0); // NOP(kinda)
1439 po += 4;
1440
1441 po = &PIOMem->data8[0x1000];
1442
1443 // Load cacheable-region target PC into r2
1444 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (0x9F001010 >> 16)); // LUI
1445 po += 4;
1446 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (0x9F001010 & 0xFFFF)); // ORI
1447 po += 4;
1448
1449 // Jump to r2
1450 MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR
1451 po += 4;
1452 MDFN_en32lsb(po, 0); // NOP(kinda)
1453 po += 4;
1454
1455 //
1456 // 0x9F001010:
1457 //
1458
1459 // Load source address into r8
1460 uint32 sa = 0x9F000000 + 65536;
1461 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (sa >> 16)); // LUI
1462 po += 4;
1463 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (8 << 16) | (sa & 0xFFFF)); // ORI
1464 po += 4;
1465
1466 // Load dest address into r9
1467 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem_Start >> 16)); // LUI
1468 po += 4;
1469 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (9 << 16) | (TextMem_Start & 0xFFFF)); // ORI
1470 po += 4;
1471
1472 // Load size into r10
1473 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (TextMem.size() >> 16)); // LUI
1474 po += 4;
1475 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (10 << 16) | (TextMem.size() & 0xFFFF)); // ORI
1476 po += 4;
1477
1478 //
1479 // Loop begin
1480 //
1481
1482 MDFN_en32lsb(po, (0x24 << 26) | (8 << 21) | (1 << 16)); // LBU to r1
1483 po += 4;
1484
1485 MDFN_en32lsb(po, (0x08 << 26) | (10 << 21) | (10 << 16) | 0xFFFF); // Decrement size
1486 po += 4;
1487
1488 MDFN_en32lsb(po, (0x28 << 26) | (9 << 21) | (1 << 16)); // SB from r1
1489 po += 4;
1490
1491 MDFN_en32lsb(po, (0x08 << 26) | (8 << 21) | (8 << 16) | 0x0001); // Increment source addr
1492 po += 4;
1493
1494 MDFN_en32lsb(po, (0x05 << 26) | (0 << 21) | (10 << 16) | (-5 & 0xFFFF));
1495 po += 4;
1496 MDFN_en32lsb(po, (0x08 << 26) | (9 << 21) | (9 << 16) | 0x0001); // Increment dest addr
1497 po += 4;
1498
1499 //
1500 // Loop end
1501 //
1502
1503 // Load SP into r29
1504 if(ignore_pcsp)
1505 {
1506 po += 16;
1507 }
1508 else
1509 {
1510 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | (SP >> 16)); // LUI
1511 po += 4;
1512 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (29 << 16) | (SP & 0xFFFF)); // ORI
1513 po += 4;
1514
1515 // Load PC into r2
1516 MDFN_en32lsb(po, (0xF << 26) | (0 << 21) | (1 << 16) | ((PC >> 16) | 0x8000)); // LUI
1517 po += 4;
1518 MDFN_en32lsb(po, (0xD << 26) | (1 << 21) | (2 << 16) | (PC & 0xFFFF)); // ORI
1519 po += 4;
1520 }
1521
1522 // Half-assed instruction cache flush. ;)
1523 for(unsigned i = 0; i < 1024; i++)
1524 {
1525 MDFN_en32lsb(po, 0);
1526 po += 4;
1527 }
1528
1529
1530
1531 // Jump to r2
1532 MDFN_en32lsb(po, (0x0 << 26) | (2 << 21) | (0x8 << 0)); // JR
1533 po += 4;
1534 MDFN_en32lsb(po, 0); // NOP(kinda)
1535 po += 4;
1536 }
1537
1538 static void Cleanup(void);
1539 static int Load(const char *name, MDFNFILE *fp)
1540 {
1541 const bool IsPSF = false;
1542
1543 if(!TestMagic(name, fp))
1544 throw MDFN_Error(0, _("File format is unknown to module \"%s\"."), MDFNGameInfo->shortname);
1545
1546 InitCommon(NULL, !IsPSF, true);
1547
1548 TextMem.resize(0);
1549
1550 if(GET_FSIZE_PTR(fp) >= 0x800)
1551 LoadEXE(GET_FDATA_PTR(fp), GET_FSIZE_PTR(fp));
1552
1553 return(1);
1554 }
1555
1556 static int LoadCD(std::vector<CDIF *> *CDInterfaces)
1557 {
1558 InitCommon(CDInterfaces);
1559 MDFNGameInfo->GameType = GMT_CDROM;
1560
1561 return(1);
1562 }
1563
1564 static void Cleanup(void)
1565 {
1566 TextMem.resize(0);
1567
1568
1569 if(CDC)
1570 delete CDC;
1571 CDC = NULL;
1572
1573 if(SPU)
1574 delete SPU;
1575 SPU = NULL;
1576
1577 if(GPU)
1578 delete GPU;
1579 GPU = NULL;
1580
1581 if(CPU)
1582 delete CPU;
1583 CPU = NULL;
1584
1585 if(FIO)
1586 delete FIO;
1587 FIO = NULL;
1588
1589 DMA_Kill();
1590
1591 if(BIOSROM)
1592 delete BIOSROM;
1593 BIOSROM = NULL;
1594
1595 if(PIOMem)
1596 delete PIOMem;
1597 PIOMem = NULL;
1598
1599 cdifs = NULL;
1600 }
1601
1602 static void CloseGame(void)
1603 {
1604 int i;
1605 for(i = 0; i < 8; i++)
1606 {
1607 if (i == 0 && !use_mednafen_memcard0_method)
1608 {
1609 FIO->SaveMemcard(i);
1610 continue;
1611 }
1612
1613 // If there's an error saving one memcard, don't skip trying to save the other, since it might succeed and
1614 // we can reduce potential data loss!
1615 try
1616 {
1617 char ext[64];
1618 const char *memcard = NULL;
1619 snprintf(ext, sizeof(ext), "%d.mcr", i);
1620 memcard = MDFN_MakeFName(MDFNMKF_SAV, 0, ext);
1621 FIO->SaveMemcard(i, memcard);
1622 }
1623 catch(std::exception &e)
1624 {
1625 log_cb(RETRO_LOG_ERROR, "%s\n", e.what());
1626 }
1627 }
1628
1629 Cleanup();
1630 }
1631
1632 static void SetInput(int port, const char *type, void *ptr)
1633 {
1634 FIO->SetInput(port, type, ptr);
1635 }
1636
1637 static int StateAction(StateMem *sm, int load, int data_only)
1638 {
1639 #if 0
1640 if(!MDFN_GetSettingB("psx.clobbers_lament"))
1641 {
1642 return(0);
1643 }
1644 #endif
1645
1646 SFORMAT StateRegs[] =
1647 {
1648 SFVAR(CD_TrayOpen),
1649 SFVAR(CD_SelectedDisc),
1650 SFARRAY(MainRAM.data8, 1024 * 2048),
1651 SFARRAY32(SysControl.Regs, 9),
1652 SFVAR(PSX_PRNG.lcgo),
1653 SFVAR(PSX_PRNG.x),
1654 SFVAR(PSX_PRNG.y),
1655 SFVAR(PSX_PRNG.z),
1656 SFVAR(PSX_PRNG.c),
1657 SFEND
1658 };
1659
1660
1661 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MAIN");
1662
1663 // Call SetDisc() BEFORE we load CDC state, since SetDisc() has emulation side effects. We might want to clean this up in the future.
1664 if(load)
1665 {
1666 if(!cdifs || CD_SelectedDisc >= (int)cdifs->size())
1667 CD_SelectedDisc = -1;
1668
1669 CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL,
1670 (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL);
1671 }
1672
1673 // TODO: Remember to increment dirty count in memory card state loading routine.
1674
1675 ret &= CPU->StateAction(sm, load, data_only);
1676 ret &= DMA_StateAction(sm, load, data_only);
1677 ret &= TIMER_StateAction(sm, load, data_only);
1678 ret &= SIO_StateAction(sm, load, data_only);
1679
1680 ret &= CDC->StateAction(sm, load, data_only);
1681 ret &= MDEC_StateAction(sm, load, data_only);
1682 ret &= GPU->StateAction(sm, load, data_only);
1683 ret &= SPU->StateAction(sm, load, data_only);
1684
1685 ret &= FIO->StateAction(sm, load, data_only);
1686
1687 ret &= IRQ_StateAction(sm, load, data_only); // Do it last.
1688
1689 if(load)
1690 {
1691 ForceEventUpdates(0); // FIXME to work with debugger step mode.
1692 }
1693
1694 return(ret);
1695 }
1696
1697 static void CDInsertEject(void)
1698 {
1699 CD_TrayOpen = !CD_TrayOpen;
1700
1701 for(unsigned disc = 0; disc < cdifs->size(); disc++)
1702 {
1703 if(!(*cdifs)[disc]->Eject(CD_TrayOpen))
1704 {
1705 MDFN_DispMessage(_("Eject error."));
1706 CD_TrayOpen = !CD_TrayOpen;
1707 }
1708 }
1709
1710 if(CD_TrayOpen)
1711 MDFN_DispMessage(_("Virtual CD Drive Tray Open"));
1712 else
1713 MDFN_DispMessage(_("Virtual CD Drive Tray Closed"));
1714
1715 CDC->SetDisc(CD_TrayOpen, (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? (*cdifs)[CD_SelectedDisc] : NULL,
1716 (CD_SelectedDisc >= 0 && !CD_TrayOpen) ? cdifs_scex_ids[CD_SelectedDisc] : NULL);
1717 }
1718
1719 static void CDEject(void)
1720 {
1721 if(!CD_TrayOpen)
1722 CDInsertEject();
1723 }
1724
1725 static void CDSelect(void)
1726 {
1727 if(cdifs && CD_TrayOpen)
1728 {
1729 CD_SelectedDisc = (CD_SelectedDisc + 1) % (cdifs->size() + 1);
1730
1731 if((unsigned)CD_SelectedDisc == cdifs->size())
1732 CD_SelectedDisc = -1;
1733
1734 if(CD_SelectedDisc == -1)
1735 MDFN_DispMessage(_("Disc absence selected."));
1736 else
1737 MDFN_DispMessage(_("Disc %d of %d selected."), CD_SelectedDisc + 1, (int)cdifs->size());
1738 }
1739 }
1740
1741 static void DoSimpleCommand(int cmd)
1742 {
1743 switch(cmd)
1744 {
1745 case MDFN_MSC_RESET:
1746 PSX_Power();
1747 break;
1748 case MDFN_MSC_POWER:
1749 PSX_Power();
1750 break;
1751 case MDFN_MSC_INSERT_DISK:
1752 CDInsertEject();
1753 break;
1754 case MDFN_MSC_SELECT_DISK:
1755 CDSelect();
1756 break;
1757 case MDFN_MSC_EJECT_DISK:
1758 CDEject();
1759 break;
1760 }
1761 }
1762
1763 static void GSCondCode(MemoryPatch* patch, const char* cc, const unsigned len, const uint32 addr, const uint16 val)
1764 {
1765 char tmp[256];
1766
1767 if(patch->conditions.size() > 0)
1768 patch->conditions.append(", ");
1769
1770 if(len == 2)
1771 trio_snprintf(tmp, 256, "%u L 0x%08x %s 0x%04x", len, addr, cc, val & 0xFFFFU);
1772 else
1773 trio_snprintf(tmp, 256, "%u L 0x%08x %s 0x%02x", len, addr, cc, val & 0xFFU);
1774
1775 patch->conditions.append(tmp);
1776 }
1777
1778 static bool DecodeGS(const std::string& cheat_string, MemoryPatch* patch)
1779 {
1780 uint64 code = 0;
1781 unsigned nybble_count = 0;
1782
1783 for(unsigned i = 0; i < cheat_string.size(); i++)
1784 {
1785 if(cheat_string[i] == ' ' || cheat_string[i] == '-' || cheat_string[i] == ':')
1786 continue;
1787
1788 nybble_count++;
1789 code <<= 4;
1790
1791 if(cheat_string[i] >= '0' && cheat_string[i] <= '9')
1792 code |= cheat_string[i] - '0';
1793 else if(cheat_string[i] >= 'a' && cheat_string[i] <= 'f')
1794 code |= cheat_string[i] - 'a' + 0xA;
1795 else if(cheat_string[i] >= 'A' && cheat_string[i] <= 'F')
1796 code |= cheat_string[i] - 'A' + 0xA;
1797 else
1798 {
1799 if(cheat_string[i] & 0x80)
1800 log_cb(RETRO_LOG_ERROR, "[Mednafen]: Invalid character in GameShark code..\n");
1801 else
1802 log_cb(RETRO_LOG_ERROR, "[Mednafen]: Invalid character in GameShark code: %c.\n", cheat_string[i]);
1803 return false;
1804 }
1805 }
1806
1807 if(nybble_count != 12)
1808 {
1809 log_cb(RETRO_LOG_ERROR, "GameShark code is of an incorrect length.\n");
1810 return false;
1811 }
1812
1813 const uint8 code_type = code >> 40;
1814 const uint64 cl = code & 0xFFFFFFFFFFULL;
1815
1816 patch->bigendian = false;
1817 patch->compare = 0;
1818
1819 if(patch->type == 'T')
1820 {
1821 if(code_type != 0x80)
1822 log_cb(RETRO_LOG_ERROR, "Unrecognized GameShark code type for second part to copy bytes code.\n");
1823
1824 patch->addr = cl >> 16;
1825 return(false);
1826 }
1827
1828 switch(code_type)
1829 {
1830 default:
1831 log_cb(RETRO_LOG_ERROR, "GameShark code type 0x%02X is currently not supported.\n", code_type);
1832
1833 return(false);
1834
1835 // TODO:
1836 case 0x10: // 16-bit increment
1837 patch->length = 2;
1838 patch->type = 'A';
1839 patch->addr = cl >> 16;
1840 patch->val = cl & 0xFFFF;
1841 return(false);
1842
1843 case 0x11: // 16-bit decrement
1844 patch->length = 2;
1845 patch->type = 'A';
1846 patch->addr = cl >> 16;
1847 patch->val = (0 - cl) & 0xFFFF;
1848 return(false);
1849
1850 case 0x20: // 8-bit increment
1851 patch->length = 1;
1852 patch->type = 'A';
1853 patch->addr = cl >> 16;
1854 patch->val = cl & 0xFF;
1855 return(false);
1856
1857 case 0x21: // 8-bit decrement
1858 patch->length = 1;
1859 patch->type = 'A';
1860 patch->addr = cl >> 16;
1861 patch->val = (0 - cl) & 0xFF;
1862 return(false);
1863 //
1864 //
1865 //
1866
1867 case 0x30: // 8-bit constant
1868 patch->length = 1;
1869 patch->type = 'R';
1870 patch->addr = cl >> 16;
1871 patch->val = cl & 0xFF;
1872 return(false);
1873
1874 case 0x80: // 16-bit constant
1875 patch->length = 2;
1876 patch->type = 'R';
1877 patch->addr = cl >> 16;
1878 patch->val = cl & 0xFFFF;
1879 return(false);
1880
1881 case 0x50: // Repeat thingy
1882 {
1883 const uint8 wcount = (cl >> 24) & 0xFF;
1884 const uint8 addr_inc = (cl >> 16) & 0xFF;
1885 const uint8 val_inc = (cl >> 0) & 0xFF;
1886
1887 patch->mltpl_count = wcount;
1888 patch->mltpl_addr_inc = addr_inc;
1889 patch->mltpl_val_inc = val_inc;
1890 }
1891 return(true);
1892
1893 case 0xC2: // Copy
1894 {
1895 const uint16 ccount = cl & 0xFFFF;
1896
1897 patch->type = 'T';
1898 patch->val = 0;
1899 patch->length = 1;
1900
1901 patch->copy_src_addr = cl >> 16;
1902 patch->copy_src_addr_inc = 1;
1903
1904 patch->mltpl_count = ccount;
1905 patch->mltpl_addr_inc = 1;
1906 patch->mltpl_val_inc = 0;
1907 }
1908 return(true);
1909
1910 case 0xD0: // 16-bit == condition
1911 GSCondCode(patch, "==", 2, cl >> 16, cl);
1912 return(true);
1913
1914 case 0xD1: // 16-bit != condition
1915 GSCondCode(patch, "!=", 2, cl >> 16, cl);
1916 return(true);
1917
1918 case 0xD2: // 16-bit < condition
1919 GSCondCode(patch, "<", 2, cl >> 16, cl);
1920 return(true);
1921
1922 case 0xD3: // 16-bit > condition
1923 GSCondCode(patch, ">", 2, cl >> 16, cl);
1924 return(true);
1925
1926
1927
1928 case 0xE0: // 8-bit == condition
1929 GSCondCode(patch, "==", 1, cl >> 16, cl);
1930 return(true);
1931
1932 case 0xE1: // 8-bit != condition
1933 GSCondCode(patch, "!=", 1, cl >> 16, cl);
1934 return(true);
1935
1936 case 0xE2: // 8-bit < condition
1937 GSCondCode(patch, "<", 1, cl >> 16, cl);
1938 return(true);
1939
1940 case 0xE3: // 8-bit > condition
1941 GSCondCode(patch, ">", 1, cl >> 16, cl);
1942 return(true);
1943
1944 }
1945 }
1946
1947 static CheatFormatStruct CheatFormats[] =
1948 {
1949 { "GameShark", "Sharks with lamprey eels for eyes.", DecodeGS },
1950 };
1951
1952 static CheatFormatInfoStruct CheatFormatInfo =
1953 {
1954 1,
1955 CheatFormats
1956 };
1957
1958 static const FileExtensionSpecStruct KnownExtensions[] =
1959 {
1960 { ".psf", "PSF1 Rip" },
1961 { ".psx", "PS-X Executable" },
1962 { ".exe", "PS-X Executable" },
1963 { NULL, NULL }
1964 };
1965
1966 static const MDFNSetting_EnumList Region_List[] =
1967 {
1968 { "jp", REGION_JP, "Japan" },
1969 { "na", REGION_NA, "North America" },
1970 { "eu", REGION_EU, "Europe" },
1971 { NULL, 0 },
1972 };
1973
1974 #if 0
1975 static const MDFNSetting_EnumList MultiTap_List[] =
1976 {
1977 { "0", 0, "Disabled" },
1978 { "1", 1, "Enabled" },
1979 { "auto", 0, "Automatically-enable multitap.", "NOT IMPLEMENTED YET(currently equivalent to 0") },
1980 { NULL, 0 },
1981 };
1982 #endif
1983
1984 static MDFNSetting PSXSettings[] =
1985 {
1986 { "psx.input.mouse_sensitivity", MDFNSF_NOFLAGS, "Emulated mouse sensitivity.", NULL, MDFNST_FLOAT, "1.00", NULL, NULL },
1987
1988 { "psx.input.analog_mode_ct", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Enable analog mode combo-button alternate toggle.", "When enabled, instead of the configured Analog mode toggle button for the emulated DualShock, use a combination of buttons to toggle it instead. When Select, Start, and all four shoulder buttons are held down for about 1 second, the mode will toggle.", MDFNST_BOOL, "0", NULL, NULL },
1989
1990 { "psx.input.pport1.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Enable multitap on PSX port 1.", "Makes 3 more virtual ports available.\n\nNOTE: Enabling multitap in games that don't fully support it may cause deleterious effects.", MDFNST_BOOL, "0", NULL, NULL }, //MDFNST_ENUM, "auto", NULL, NULL, NULL, NULL, MultiTap_List },
1991 { "psx.input.pport2.multitap", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Enable multitap on PSX port 2.", "Makes 3 more virtual ports available.\n\nNOTE: Enabling multitap in games that don't fully support it may cause deleterious effects.", MDFNST_BOOL, "0", NULL, NULL },
1992
1993 { "psx.input.port1.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 1.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
1994 { "psx.input.port2.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 2.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
1995 { "psx.input.port3.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 3.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
1996 { "psx.input.port4.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 4.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
1997 { "psx.input.port5.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 5.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
1998 { "psx.input.port6.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 6.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
1999 { "psx.input.port7.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 7.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
2000 { "psx.input.port8.memcard", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Emulate memcard on virtual port 8.", NULL, MDFNST_BOOL, "1", NULL, NULL, },
2001
2002
2003 { "psx.input.port1.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 1.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0xFF0000", "0x000000", "0x1000000" },
2004 { "psx.input.port2.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 2.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0x00FF00", "0x000000", "0x1000000" },
2005 { "psx.input.port3.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 3.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0xFF00FF", "0x000000", "0x1000000" },
2006 { "psx.input.port4.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 4.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0xFF8000", "0x000000", "0x1000000" },
2007 { "psx.input.port5.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 5.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0xFFFF00", "0x000000", "0x1000000" },
2008 { "psx.input.port6.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 6.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0x00FFFF", "0x000000", "0x1000000" },
2009 { "psx.input.port7.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 7.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0x0080FF", "0x000000", "0x1000000" },
2010 { "psx.input.port8.gun_chairs", MDFNSF_NOFLAGS, "Crosshairs color for lightgun on virtual port 8.", "A value of 0x1000000 disables crosshair drawing.", MDFNST_UINT, "0x8000FF", "0x000000", "0x1000000" },
2011
2012 { "psx.region_autodetect", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Attempt to auto-detect region of game.", NULL, MDFNST_BOOL, "1" },
2013 { "psx.region_default", MDFNSF_EMU_STATE | MDFNSF_UNTRUSTED_SAFE, "Default region to use.", "Used if region autodetection fails or is disabled.", MDFNST_ENUM, "jp", NULL, NULL, NULL, NULL, Region_List },
2014
2015 { "psx.bios_jp", MDFNSF_EMU_STATE, "Path to the Japan SCPH-5500 ROM BIOS", NULL, MDFNST_STRING, "scph5500.bin" },
2016 { "psx.bios_na", MDFNSF_EMU_STATE, "Path to the North America SCPH-5501 ROM BIOS", "SHA1 0555c6fae8906f3f09baf5988f00e55f88e9f30b", MDFNST_STRING, "scph5501.bin" },
2017 { "psx.bios_eu", MDFNSF_EMU_STATE, "Path to the Europe SCPH-5502 ROM BIOS", NULL, MDFNST_STRING, "scph5502.bin" },
2018
2019 { "psx.spu.resamp_quality", MDFNSF_NOFLAGS, "SPU output resampler quality.",
2020 "0 is lowest quality and CPU usage, 10 is highest quality and CPU usage. The resampler that this setting refers to is used for converting from 44.1KHz to the sampling rate of the host audio device Mednafen is using. Changing Mednafen's output rate, via the \"sound.rate\" setting, to \"44100\" will bypass the resampler, which will decrease CPU usage by Mednafen, and can increase or decrease audio quality, depending on various operating system and hardware factors.", MDFNST_UINT, "5", "0", "10" },
2021
2022
2023 { "psx.slstart", MDFNSF_NOFLAGS, "First displayed scanline in NTSC mode.", NULL, MDFNST_INT, "0", "0", "239" },
2024 { "psx.slend", MDFNSF_NOFLAGS, "Last displayed scanline in NTSC mode.", NULL, MDFNST_INT, "239", "0", "239" },
2025
2026 { "psx.slstartp", MDFNSF_NOFLAGS, "First displayed scanline in PAL mode.", NULL, MDFNST_INT, "0", "0", "287" },
2027 { "psx.slendp", MDFNSF_NOFLAGS, "Last displayed scanline in PAL mode.", NULL, MDFNST_INT, "287", "0", "287" },
2028
2029 #if PSX_DBGPRINT_ENABLE
2030 { "psx.dbg_level", MDFNSF_NOFLAGS, "Debug printf verbosity level.", NULL, MDFNST_UINT, "0", "0", "4" },
2031 #endif
2032
2033 { "psx.clobbers_lament", MDFNSF_NOFLAGS, "Enable experimental save state functionality.", "Save states will destroy your saved game/memory card data if you're careless, and that will make clobber sad. Poor clobber.", MDFNST_BOOL, "0" },
2034
2035 { NULL },
2036 };
2037
2038 // Note for the future: If we ever support PSX emulation with non-8-bit RGB color components, or add a new linear RGB colorspace to MDFN_PixelFormat, we'll need
2039 // to buffer the intermediate 24-bit non-linear RGB calculation into an array and pass that into the GPULineHook stuff, otherwise netplay could break when
2040 // an emulated GunCon is used. This IS assuming, of course, that we ever implement save state support so that netplay actually works at all...
2041 MDFNGI EmulatedPSX =
2042 {
2043 "psx",
2044 "Sony PlayStation",
2045 KnownExtensions,
2046 MODPRIO_INTERNAL_HIGH,
2047 #ifdef WANT_DEBUGGER
2048 &PSX_DBGInfo,
2049 #else
2050 NULL,
2051 #endif
2052 &FIO_InputInfo,
2053 Load,
2054 TestMagic,
2055 LoadCD,
2056 TestMagicCD,
2057 CloseGame,
2058 NULL, //ToggleLayer,
2059 "GPU\0", //"Background Scroll\0Foreground Scroll\0Sprites\0",
2060 NULL,
2061 NULL,
2062 NULL,
2063 NULL,
2064 NULL,
2065 NULL,
2066 false,
2067 StateAction,
2068 NULL,
2069 SetInput,
2070 DoSimpleCommand,
2071 PSXSettings,
2072 MDFN_MASTERCLOCK_FIXED(33868800),
2073 0,
2074
2075 true, // Multires possible?
2076
2077 //
2078 // Note: Following video settings will be overwritten during game load.
2079 //
2080 0, // lcm_width
2081 0, // lcm_height
2082 NULL, // Dummy
2083
2084 320, // Nominal width
2085 240, // Nominal height
2086
2087 0, // Framebuffer width
2088 0, // Framebuffer height
2089 //
2090 //
2091 //
2092
2093 2, // Number of output sound channels
2094
2095 };
2096
2097 /* end of Mednafen psx.cpp */
2098
2099 //forward decls
2100 extern void Emulate(EmulateSpecStruct *espec);
2101 extern void SetInput(int port, const char *type, void *ptr);
2102
2103
2104 static bool overscan;
2105 static double last_sound_rate;
2106
2107 static MDFN_Surface *surf;
2108
2109 static bool failed_init;
2110
2111 char *psx_analog_type;
2112
2113 #define RETRO_DEVICE_PS1PAD RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0)
2114 #define RETRO_DEVICE_DUALANALOG RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG, 0)
2115 #define RETRO_DEVICE_DUALSHOCK RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG, 1)
2116 #define RETRO_DEVICE_FLIGHTSTICK RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG, 2)
2117
2118 ;
2119
2120 #ifdef NEED_DEINTERLACER
2121 static bool PrevInterlaced;
2122 static Deinterlacer deint;
2123 #endif
2124
2125 #define MEDNAFEN_CORE_NAME_MODULE "psx"
2126 #define MEDNAFEN_CORE_NAME "Mednafen PSX"
2127 #define MEDNAFEN_CORE_VERSION "v0.9.38.6"
2128 #define MEDNAFEN_CORE_EXTENSIONS "cue|toc|ccd|m3u"
2129 #define MEDNAFEN_CORE_GEOMETRY_BASE_W 320
2130 #define MEDNAFEN_CORE_GEOMETRY_BASE_H 240
2131 #define MEDNAFEN_CORE_GEOMETRY_MAX_W 700
2132 #define MEDNAFEN_CORE_GEOMETRY_MAX_H 576
2133 #define MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO (4.0 / 3.0)
2134
2135 static void check_system_specs(void)
2136 {
2137 // Hints that we need a fairly powerful system to run this.
2138 unsigned level = 15;
2139 environ_cb(RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL, &level);
2140 }
2141
2142 static unsigned disk_get_num_images(void)
2143 {
2144 return cdifs ? cdifs->size() : 0;
2145 }
2146
2147 static bool eject_state;
2148 static bool disk_set_eject_state(bool ejected)
2149 {
2150 log_cb(RETRO_LOG_INFO, "[Mednafen]: Ejected: %u.\n", ejected);
2151 if (ejected == eject_state)
2152 return false;
2153
2154 DoSimpleCommand(ejected ? MDFN_MSC_EJECT_DISK : MDFN_MSC_INSERT_DISK);
2155 eject_state = ejected;
2156 return true;
2157 }
2158
2159 static bool disk_get_eject_state(void)
2160 {
2161 return eject_state;
2162 }
2163
2164 static unsigned disk_get_image_index(void)
2165 {
2166 // PSX global. Hacky.
2167 return CD_SelectedDisc;
2168 }
2169
2170 static bool disk_set_image_index(unsigned index)
2171 {
2172 CD_SelectedDisc = index;
2173 if (CD_SelectedDisc > disk_get_num_images())
2174 CD_SelectedDisc = disk_get_num_images();
2175
2176 // Very hacky. CDSelect command will increment first.
2177 CD_SelectedDisc--;
2178
2179 DoSimpleCommand(MDFN_MSC_SELECT_DISK);
2180 return true;
2181 }
2182
2183 // Mednafen PSX really doesn't support adding disk images on the fly ...
2184 // Hack around this.
2185 static void update_md5_checksum(CDIF *iface)
2186 {
2187 uint8 LayoutMD5[16];
2188 md5_context layout_md5;
2189 CD_TOC toc;
2190
2191 md5_starts(&layout_md5);
2192
2193 TOC_Clear(&toc);
2194
2195 iface->ReadTOC(&toc);
2196
2197 md5_update_u32_as_lsb(&layout_md5, toc.first_track);
2198 md5_update_u32_as_lsb(&layout_md5, toc.last_track);
2199 md5_update_u32_as_lsb(&layout_md5, toc.tracks[100].lba);
2200
2201 for (uint32 track = toc.first_track; track <= toc.last_track; track++)
2202 {
2203 md5_update_u32_as_lsb(&layout_md5, toc.tracks[track].lba);
2204 md5_update_u32_as_lsb(&layout_md5, toc.tracks[track].control & 0x4);
2205 }
2206
2207 md5_finish(&layout_md5, LayoutMD5);
2208 memcpy(MDFNGameInfo->MD5, LayoutMD5, 16);
2209
2210 char *md5 = md5_asciistr(MDFNGameInfo->MD5);
2211 log_cb(RETRO_LOG_INFO, "[Mednafen]: Updated md5 checksum: %s.\n", md5);
2212 }
2213
2214 // Untested ...
2215 static bool disk_replace_image_index(unsigned index, const struct retro_game_info *info)
2216 {
2217 if (index >= disk_get_num_images())
2218 return false;
2219
2220 if (!eject_state)
2221 return false;
2222
2223 if (!info)
2224 {
2225 delete cdifs->at(index);
2226 cdifs->erase(cdifs->begin() + index);
2227 if (index < CD_SelectedDisc)
2228 CD_SelectedDisc--;
2229
2230 // Poke into psx.cpp
2231 CalcDiscSCEx();
2232 return true;
2233 }
2234
2235 try
2236 {
2237 CDIF *iface = CDIF_Open(info->path, false, false);
2238 delete cdifs->at(index);
2239 cdifs->at(index) = iface;
2240 CalcDiscSCEx();
2241
2242 /* If we replace, we want the "swap disk manually effect". */
2243 extract_basename(retro_cd_base_name, info->path, sizeof(retro_cd_base_name));
2244 /* Ugly, but needed to get proper disk swapping effect. */
2245 update_md5_checksum(iface);
2246 return true;
2247 }
2248 catch (const std::exception &e)
2249 {
2250 return false;
2251 }
2252 }
2253
2254 static bool disk_add_image_index(void)
2255 {
2256 cdifs->push_back(NULL);
2257 return true;
2258 }
2259
2260 static struct retro_disk_control_callback disk_interface = {
2261 disk_set_eject_state,
2262 disk_get_eject_state,
2263 disk_get_image_index,
2264 disk_set_image_index,
2265 disk_get_num_images,
2266 disk_replace_image_index,
2267 disk_add_image_index,
2268 };
2269
2270 static void fallback_log(enum retro_log_level level, const char *fmt, ...)
2271 {
2272 }
2273
2274
2275 void retro_init(void)
2276 {
2277 struct retro_log_callback log;
2278 if (environ_cb(RETRO_ENVIRONMENT_GET_LOG_INTERFACE, &log))
2279 log_cb = log.log;
2280 else
2281 log_cb = fallback_log;
2282
2283 #ifdef NEED_CD
2284 CDUtility_Init();
2285 #endif
2286
2287 eject_state = false;
2288
2289 const char *dir = NULL;
2290
2291 if (environ_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir) && dir)
2292 {
2293 snprintf(retro_base_directory, sizeof(retro_base_directory), "%s", dir);
2294 }
2295 else
2296 {
2297 /* TODO: Add proper fallback */
2298 log_cb(RETRO_LOG_WARN, "System directory is not defined. Fallback on using same dir as ROM for system directory later ...\n");
2299 failed_init = true;
2300 }
2301
2302 if (environ_cb(RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY, &dir) && dir)
2303 {
2304 // If save directory is defined use it, otherwise use system directory
2305 if (dir)
2306 snprintf(retro_save_directory, sizeof(retro_save_directory), "%s", dir);
2307 else
2308 snprintf(retro_save_directory, sizeof(retro_save_directory), "%s", retro_base_directory);
2309 }
2310 else
2311 {
2312 /* TODO: Add proper fallback */
2313 log_cb(RETRO_LOG_WARN, "Save directory is not defined. Fallback on using SYSTEM directory ...\n");
2314 snprintf(retro_save_directory, sizeof(retro_save_directory), "%s", retro_base_directory);
2315 }
2316
2317 environ_cb(RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE, &disk_interface);
2318
2319 if (environ_cb(RETRO_ENVIRONMENT_GET_PERF_INTERFACE, &perf_cb))
2320 perf_get_cpu_features_cb = perf_cb.get_cpu_features;
2321 else
2322 perf_get_cpu_features_cb = NULL;
2323
2324 setting_initial_scanline = 0;
2325 setting_last_scanline = 239;
2326 setting_initial_scanline_pal = 0;
2327 setting_last_scanline_pal = 287;
2328
2329 check_system_specs();
2330 }
2331
2332 void retro_reset(void)
2333 {
2334 DoSimpleCommand(MDFN_MSC_RESET);
2335 }
2336
2337 bool retro_load_game_special(unsigned, const struct retro_game_info *, size_t)
2338 {
2339 return false;
2340 }
2341
2342 static bool old_cdimagecache = false;
2343
2344 static bool boot = true;
2345
2346 // shared memory cards support
2347 static bool shared_memorycards = false;
2348 static bool shared_memorycards_toggle = false;
2349
2350 static void check_variables(void)
2351 {
2352 struct retro_variable var = {0};
2353
2354 extern void PSXDitherApply(bool);
2355
2356 var.key = "beetle_psx_cdimagecache";
2357
2358 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2359 {
2360 bool cdimage_cache = true;
2361 if (strcmp(var.value, "enabled") == 0)
2362 cdimage_cache = true;
2363 else if (strcmp(var.value, "disabled") == 0)
2364 cdimage_cache = false;
2365 if (cdimage_cache != old_cdimagecache)
2366 {
2367 old_cdimagecache = cdimage_cache;
2368 }
2369 }
2370
2371 var.key = "beetle_psx_widescreen_hack";
2372
2373 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2374 {
2375 if (strcmp(var.value, "enabled") == 0)
2376 widescreen_hack = true;
2377 else if (strcmp(var.value, "disabled") == 0)
2378 widescreen_hack = false;
2379 }
2380 else
2381 widescreen_hack = false;
2382
2383 var.key = "beetle_psx_widescreen_auto_ar";
2384
2385 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2386 {
2387 if (strcmp(var.value, "enabled") == 0 && widescreen_hack)
2388 widescreen_auto_ar = true;
2389 else if (strcmp(var.value, "disabled") == 0)
2390 widescreen_auto_ar = false;
2391 }
2392 else
2393 widescreen_auto_ar = false;
2394
2395 var.key = "beetle_psx_analog_toggle";
2396
2397 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2398 {
2399 if ((strcmp(var.value, "enabled") == 0)
2400 && setting_psx_analog_toggle != 1)
2401 {
2402 setting_psx_analog_toggle = 1;
2403 setting_apply_analog_toggle = true;
2404 }
2405 else if ((strcmp(var.value, "disabled") == 0)
2406 && setting_psx_analog_toggle != 0)
2407 {
2408 setting_psx_analog_toggle = 0;
2409 setting_apply_analog_toggle = true;
2410 }
2411 }
2412
2413 var.key = "beetle_psx_enable_multitap_port1";
2414
2415 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2416 {
2417 if (strcmp(var.value, "enabled") == 0)
2418 setting_psx_multitap_port_1 = true;
2419 else if (strcmp(var.value, "disabled") == 0)
2420 setting_psx_multitap_port_1 = false;
2421 }
2422
2423 var.key = "beetle_psx_enable_multitap_port2";
2424
2425 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2426 {
2427 if (strcmp(var.value, "enabled") == 0)
2428 setting_psx_multitap_port_2 = true;
2429 else if (strcmp(var.value, "disabled") == 0)
2430 setting_psx_multitap_port_2 = false;
2431 }
2432
2433 var.key = "beetle_psx_initial_scanline";
2434
2435 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2436 {
2437 setting_initial_scanline = atoi(var.value);
2438 }
2439
2440 var.key = "beetle_psx_last_scanline";
2441
2442 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2443 {
2444 setting_last_scanline = atoi(var.value);
2445 }
2446
2447 var.key = "beetle_psx_initial_scanline_pal";
2448
2449 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2450 {
2451 setting_initial_scanline_pal = atoi(var.value);
2452 }
2453
2454 var.key = "beetle_psx_last_scanline_pal";
2455
2456 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2457 {
2458 setting_last_scanline_pal = atoi(var.value);
2459 }
2460
2461 if(setting_psx_multitap_port_1)
2462 {
2463 if(setting_psx_multitap_port_2)
2464 players = 8;
2465 else
2466 players = 4;
2467 }
2468 else
2469 {
2470 if(setting_psx_multitap_port_2)
2471 players = 4;
2472 else
2473 players = 2;
2474 }
2475
2476 var.key = "beetle_psx_use_mednafen_memcard0_method";
2477
2478 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2479 {
2480 if (strcmp(var.value, "libretro") == 0)
2481 use_mednafen_memcard0_method = false;
2482 else if (strcmp(var.value, "mednafen") == 0)
2483 use_mednafen_memcard0_method = true;
2484 }
2485
2486 //this option depends on beetle_psx_use_mednafen_memcard0_method being disabled so it should be evaluated that
2487 var.key = "beetle_psx_shared_memory_cards";
2488
2489 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
2490 {
2491
2492 if (strcmp(var.value, "enabled") == 0)
2493 {
2494 if(boot)
2495 {
2496 if(use_mednafen_memcard0_method)
2497 shared_memorycards_toggle = true;
2498 }
2499 else
2500 {
2501 if(use_mednafen_memcard0_method)
2502 shared_memorycards_toggle = true;
2503 }
2504 }
2505 else if (strcmp(var.value, "disabled") == 0)
2506 {
2507 if(boot)
2508 shared_memorycards_toggle = false;
2509 else
2510 {
2511 shared_memorycards = false;
2512 }
2513 }
2514 }
2515 }
2516
2517 #ifdef NEED_CD
2518 static void ReadM3U(std::vector<std::string> &file_list, std::string path, unsigned depth = 0)
2519 {
2520 std::string dir_path;
2521 char linebuf[2048];
2522 FILE *fp = fopen(path.c_str(), "rb");
2523
2524 if (fp == NULL)
2525 return;
2526
2527 MDFN_GetFilePathComponents(path, &dir_path);
2528
2529 while(fgets(linebuf, sizeof(linebuf), fp) != NULL)
2530 {
2531 std::string efp;
2532
2533 if(linebuf[0] == '#') continue;
2534 MDFN_rtrim(linebuf);
2535 if(linebuf[0] == 0) continue;
2536
2537 efp = MDFN_EvalFIP(dir_path, std::string(linebuf));
2538
2539 if(efp.size() >= 4 && efp.substr(efp.size() - 4) == ".m3u")
2540 {
2541 if(efp == path)
2542 {
2543 log_cb(RETRO_LOG_ERROR, "M3U at \"%s\" references self.\n", efp.c_str());
2544 goto end;
2545 }
2546
2547 if(depth == 99)
2548 {
2549 log_cb(RETRO_LOG_ERROR, "M3U load recursion too deep!\n");
2550 goto end;
2551 }
2552
2553 ReadM3U(file_list, efp, depth++);
2554 }
2555 else
2556 file_list.push_back(efp);
2557 }
2558
2559 end:
2560 fclose(fp);
2561 }
2562
2563 #ifdef NEED_CD
2564 static std::vector<CDIF *> CDInterfaces; // FIXME: Cleanup on error out.
2565 #endif
2566 // TODO: LoadCommon()
2567
2568 MDFNGI *MDFNI_LoadCD(const char *force_module, const char *devicename)
2569 {
2570 uint8 LayoutMD5[16];
2571
2572 log_cb(RETRO_LOG_INFO, "Loading %s...\n", devicename ? devicename : "PHYSICAL CD");
2573
2574 try
2575 {
2576 if(devicename && strlen(devicename) > 4 && !strcasecmp(devicename + strlen(devicename) - 4, ".m3u"))
2577 {
2578 std::vector<std::string> file_list;
2579
2580 ReadM3U(file_list, devicename);
2581
2582 for(unsigned i = 0; i < file_list.size(); i++)
2583 {
2584 CDInterfaces.push_back(CDIF_Open(file_list[i].c_str(), false, old_cdimagecache));
2585 }
2586 }
2587 else
2588 {
2589 CDInterfaces.push_back(CDIF_Open(devicename, false, old_cdimagecache));
2590 }
2591 }
2592 catch(std::exception &e)
2593 {
2594 log_cb(RETRO_LOG_ERROR, "Error opening CD.\n");
2595 return(0);
2596 }
2597
2598 //
2599 // Print out a track list for all discs. //
2600 for(unsigned i = 0; i < CDInterfaces.size(); i++)
2601 {
2602 TOC toc;
2603 TOC_Clear(&toc);
2604
2605 CDInterfaces[i]->ReadTOC(&toc);
2606
2607 log_cb(RETRO_LOG_DEBUG, "CD %d Layout:\n", i + 1);
2608
2609 for(int32 track = toc.first_track; track <= toc.last_track; track++)
2610 {
2611 log_cb(RETRO_LOG_DEBUG, "Track %2d, LBA: %6d %s\n", track, toc.tracks[track].lba, (toc.tracks[track].control & 0x4) ? "DATA" : "AUDIO");
2612 }
2613
2614 log_cb(RETRO_LOG_DEBUG, "Leadout: %6d\n", toc.tracks[100].lba);
2615 }
2616
2617 // Calculate layout MD5. The system emulation LoadCD() code is free to ignore this value and calculate
2618 // its own, or to use it to look up a game in its database.
2619 {
2620 md5_context layout_md5;
2621
2622 md5_starts(&layout_md5);
2623
2624 for(unsigned i = 0; i < CDInterfaces.size(); i++)
2625 {
2626 CD_TOC toc;
2627
2628 TOC_Clear(&toc);
2629 CDInterfaces[i]->ReadTOC(&toc);
2630
2631 md5_update_u32_as_lsb(&layout_md5, toc.first_track);
2632 md5_update_u32_as_lsb(&layout_md5, toc.last_track);
2633 md5_update_u32_as_lsb(&layout_md5, toc.tracks[100].lba);
2634
2635 for(uint32 track = toc.first_track; track <= toc.last_track; track++)
2636 {
2637 md5_update_u32_as_lsb(&layout_md5, toc.tracks[track].lba);
2638 md5_update_u32_as_lsb(&layout_md5, toc.tracks[track].control & 0x4);
2639 }
2640 }
2641
2642 md5_finish(&layout_md5, LayoutMD5);
2643 }
2644
2645 // This if statement will be true if force_module references a system without CDROM support.
2646 if(!MDFNGameInfo->LoadCD)
2647 {
2648 log_cb(RETRO_LOG_ERROR, "Specified system \"%s\" doesn't support CDs!", force_module);
2649 return 0;
2650 }
2651
2652 // TODO: include module name in hash
2653 memcpy(MDFNGameInfo->MD5, LayoutMD5, 16);
2654
2655 if(!(MDFNGameInfo->LoadCD(&CDInterfaces)))
2656 {
2657 for(unsigned i = 0; i < CDInterfaces.size(); i++)
2658 delete CDInterfaces[i];
2659 CDInterfaces.clear();
2660
2661 MDFNGameInfo = NULL;
2662 return(0);
2663 }
2664
2665 //MDFNI_SetLayerEnableMask(~0ULL);
2666
2667 MDFN_LoadGameCheats(NULL);
2668 MDFNMP_InstallReadPatches();
2669
2670 return(MDFNGameInfo);
2671 }
2672 #endif
2673
2674 static MDFNGI *MDFNI_LoadGame(const char *force_module, const char *name)
2675 {
2676 MDFNFILE *GameFile = file_open(name);
2677
2678 if(!GameFile)
2679 goto error;
2680
2681 #ifdef NEED_CD
2682 if(strlen(name) > 4 && (!strcasecmp(name + strlen(name) - 4, ".cue") || !strcasecmp(name + strlen(name) - 4, ".ccd") || !strcasecmp(name + strlen(name) - 4, ".toc") || !strcasecmp(name + strlen(name) - 4, ".m3u")))
2683 return(MDFNI_LoadCD(force_module, name));
2684 #endif
2685
2686 if(MDFNGameInfo->Load(name, GameFile) <= 0)
2687 goto error;
2688
2689 file_close(GameFile);
2690 GameFile = NULL;
2691
2692 if(!MDFNGameInfo->name)
2693 {
2694 unsigned int x;
2695 char *tmp;
2696
2697 MDFNGameInfo->name = (UTF8 *)strdup(GetFNComponent(name));
2698
2699 for(x=0;x<strlen((char *)MDFNGameInfo->name);x++)
2700 {
2701 if(MDFNGameInfo->name[x] == '_')
2702 MDFNGameInfo->name[x] = ' ';
2703 }
2704 if((tmp = strrchr((char *)MDFNGameInfo->name, '.')))
2705 *tmp = 0;
2706 }
2707
2708 return(MDFNGameInfo);
2709
2710 error:
2711 if (GameFile)
2712 file_close(GameFile);
2713 GameFile = NULL;
2714 MDFNGameInfo = NULL;
2715 return NULL;
2716 }
2717
2718 #define MAX_PLAYERS 8
2719 #define MAX_BUTTONS 16
2720
2721 union
2722 {
2723 uint32_t u32[MAX_PLAYERS][1 + 8 + 1]; // Buttons + Axes + Rumble
2724 uint8_t u8[MAX_PLAYERS][(1 + 8 + 1) * sizeof(uint32_t)];
2725 } static buf;
2726
2727 static uint16_t input_buf[MAX_PLAYERS] = {0};
2728
2729
2730 bool retro_load_game(const struct retro_game_info *info)
2731 {
2732 char tocbasepath[4096];
2733 if (failed_init)
2734 return false;
2735
2736 struct retro_input_descriptor desc[] = {
2737 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2738 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2739 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2740 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2741 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2742 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2743 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2744 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2745 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2746 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2747 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2748 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2749 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2750 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2751 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2752 { 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2753 { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2754 { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2755 { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2756 { 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2757
2758
2759 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2760 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2761 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2762 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2763 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2764 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2765 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2766 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2767 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2768 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2769 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2770 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2771 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2772 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2773 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2774 { 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2775 { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2776 { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2777 { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2778 { 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2779
2780 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2781 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2782 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2783 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2784 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2785 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2786 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2787 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2788 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2789 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2790 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2791 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2792 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2793 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2794 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2795 { 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2796 { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2797 { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2798 { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2799 { 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2800
2801 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2802 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2803 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2804 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2805 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2806 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2807 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2808 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2809 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2810 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2811 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2812 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2813 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2814 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2815 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2816 { 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2817 { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2818 { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2819 { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2820 { 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2821
2822 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2823 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2824 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2825 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2826 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2827 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2828 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2829 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2830 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2831 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2832 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2833 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2834 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2835 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2836 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2837 { 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2838 { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2839 { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2840 { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2841 { 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2842
2843 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2844 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2845 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2846 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2847 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2848 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2849 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2850 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2851 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2852 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2853 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2854 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2855 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2856 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2857 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2858 { 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2859 { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2860 { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2861 { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2862 { 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2863
2864 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2865 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2866 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2867 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2868 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2869 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2870 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2871 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2872 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2873 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2874 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2875 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2876 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2877 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2878 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2879 { 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2880 { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2881 { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2882 { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2883 { 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2884
2885 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
2886 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
2887 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
2888 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
2889 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
2890 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
2891 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
2892 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
2893 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
2894 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
2895 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
2896 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
2897 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
2898 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
2899 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
2900 { 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
2901 { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
2902 { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
2903 { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
2904 { 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
2905
2906 { 0 },
2907 };
2908
2909 environ_cb(RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc);
2910
2911 enum retro_pixel_format fmt = RETRO_PIXEL_FORMAT_XRGB8888;
2912 if (!environ_cb(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &fmt))
2913 return false;
2914
2915 overscan = false;
2916 environ_cb(RETRO_ENVIRONMENT_GET_OVERSCAN, &overscan);
2917
2918 extract_basename(retro_cd_base_name, info->path, sizeof(retro_cd_base_name));
2919 extract_directory(retro_cd_base_directory, info->path, sizeof(retro_cd_base_directory));
2920
2921 snprintf(tocbasepath, sizeof(tocbasepath), "%s%c%s.toc", retro_cd_base_directory, retro_slash, retro_cd_base_name);
2922
2923 if (path_is_valid(tocbasepath))
2924 snprintf(retro_cd_path, sizeof(retro_cd_path), "%s", tocbasepath);
2925 else
2926 snprintf(retro_cd_path, sizeof(retro_cd_path), "%s", info->path);
2927
2928 log_cb(RETRO_LOG_INFO, "PATH IS NOW!!!!! %s\n", retro_cd_path);
2929
2930 check_variables();
2931 //make sure shared memory cards and save states are enabled only at startup
2932 shared_memorycards = shared_memorycards_toggle;
2933
2934 if (environ_cb(RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble) && log_cb)
2935 log_cb(RETRO_LOG_INFO, "Rumble interface supported!\n");
2936
2937 if (!MDFNI_LoadGame(MEDNAFEN_CORE_NAME_MODULE, retro_cd_path))
2938 return false;
2939
2940 MDFN_LoadGameCheats(NULL);
2941 MDFNMP_InstallReadPatches();
2942
2943 MDFN_PixelFormat pix_fmt(MDFN_COLORSPACE_RGB, 16, 8, 0, 24);
2944
2945 is_pal = (CalcDiscSCEx() == REGION_EU);
2946 surf = new MDFN_Surface(NULL, MEDNAFEN_CORE_GEOMETRY_MAX_W, is_pal ? MEDNAFEN_CORE_GEOMETRY_MAX_H : 480, MEDNAFEN_CORE_GEOMETRY_MAX_W, pix_fmt);
2947
2948 #ifdef NEED_DEINTERLACER
2949 PrevInterlaced = false;
2950 deint.ClearState();
2951 #endif
2952
2953 //SetInput(0, "gamepad", &input_buf[0]);
2954 //SetInput(1, "gamepad", &input_buf[1]);
2955
2956 for (unsigned i = 0; i < players; i++)
2957 {
2958 SetInput(i, "gamepad", &input_buf[i]);
2959 }
2960 boot = false;
2961 return true;
2962 }
2963
2964 void retro_unload_game(void)
2965 {
2966 if(!MDFNGameInfo)
2967 return;
2968
2969 MDFN_FlushGameCheats(0);
2970
2971 MDFNGameInfo->CloseGame();
2972
2973 if(MDFNGameInfo->name)
2974 free(MDFNGameInfo->name);
2975 MDFNGameInfo->name = NULL;
2976
2977 MDFNMP_Kill();
2978
2979 MDFNGameInfo = NULL;
2980
2981 #ifdef NEED_CD
2982 for(unsigned i = 0; i < CDInterfaces.size(); i++)
2983 delete CDInterfaces[i];
2984 CDInterfaces.clear();
2985 #endif
2986
2987 retro_cd_base_directory[0] = '\0';
2988 retro_cd_path[0] = '\0';
2989 retro_cd_base_name[0] = '\0';
2990 }
2991
2992
2993 // Hardcoded for PSX. No reason to parse lots of structures ...
2994 // See mednafen/psx/input/gamepad.cpp
2995 static void update_input(void)
2996 {
2997 //input_buf[0] = 0;
2998 //input_buf[1] = 0;
2999
3000 for (unsigned j = 0; j < players; j++)
3001 {
3002 input_buf[j] = 0;
3003 }
3004
3005 static unsigned map[] = {
3006 RETRO_DEVICE_ID_JOYPAD_SELECT,
3007 RETRO_DEVICE_ID_JOYPAD_L3,
3008 RETRO_DEVICE_ID_JOYPAD_R3,
3009 RETRO_DEVICE_ID_JOYPAD_START,
3010 RETRO_DEVICE_ID_JOYPAD_UP,
3011 RETRO_DEVICE_ID_JOYPAD_RIGHT,
3012 RETRO_DEVICE_ID_JOYPAD_DOWN,
3013 RETRO_DEVICE_ID_JOYPAD_LEFT,
3014 RETRO_DEVICE_ID_JOYPAD_L2,
3015 RETRO_DEVICE_ID_JOYPAD_R2,
3016 RETRO_DEVICE_ID_JOYPAD_L,
3017 RETRO_DEVICE_ID_JOYPAD_R,
3018 RETRO_DEVICE_ID_JOYPAD_X,
3019 RETRO_DEVICE_ID_JOYPAD_A,
3020 RETRO_DEVICE_ID_JOYPAD_B,
3021 RETRO_DEVICE_ID_JOYPAD_Y,
3022 };
3023
3024 for (unsigned j = 0; j < players; j++)
3025 {
3026 for (unsigned i = 0; i < MAX_BUTTONS; i++)
3027 input_buf[j] |= input_state_cb(j, RETRO_DEVICE_JOYPAD, 0, map[i]) ? (1 << i) : 0;
3028 }
3029
3030 // Buttons.
3031 //buf.u8[0][0] = (input_buf[0] >> 0) & 0xff;
3032 //buf.u8[0][1] = (input_buf[0] >> 8) & 0xff;
3033 //buf.u8[1][0] = (input_buf[1] >> 0) & 0xff;
3034 //buf.u8[1][1] = (input_buf[1] >> 8) & 0xff;
3035
3036 for (unsigned j = 0; j < players; j++)
3037 {
3038 buf.u8[j][0] = (input_buf[j] >> 0) & 0xff;
3039 buf.u8[j][1] = (input_buf[j] >> 8) & 0xff;
3040 }
3041
3042 // Analogs
3043 for (unsigned j = 0; j < players; j++)
3044 {
3045 int analog_left_x = input_state_cb(j, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT,
3046 RETRO_DEVICE_ID_ANALOG_X);
3047
3048 int analog_left_y = input_state_cb(j, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT,
3049 RETRO_DEVICE_ID_ANALOG_Y);
3050
3051 int analog_right_x = input_state_cb(j, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT,
3052 RETRO_DEVICE_ID_ANALOG_X);
3053
3054 int analog_right_y = input_state_cb(j, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT,
3055 RETRO_DEVICE_ID_ANALOG_Y);
3056
3057 uint32_t r_right = analog_right_x > 0 ? analog_right_x : 0;
3058 uint32_t r_left = analog_right_x < 0 ? -analog_right_x : 0;
3059 uint32_t r_down = analog_right_y > 0 ? analog_right_y : 0;
3060 uint32_t r_up = analog_right_y < 0 ? -analog_right_y : 0;
3061
3062 uint32_t l_right = analog_left_x > 0 ? analog_left_x : 0;
3063 uint32_t l_left = analog_left_x < 0 ? -analog_left_x : 0;
3064 uint32_t l_down = analog_left_y > 0 ? analog_left_y : 0;
3065 uint32_t l_up = analog_left_y < 0 ? -analog_left_y : 0;
3066
3067 buf.u32[j][1] = r_right;
3068 buf.u32[j][2] = r_left;
3069 buf.u32[j][3] = r_down;
3070 buf.u32[j][4] = r_up;
3071
3072 buf.u32[j][5] = l_right;
3073 buf.u32[j][6] = l_left;
3074 buf.u32[j][7] = l_down;
3075 buf.u32[j][8] = l_up;
3076 }
3077
3078 //fprintf(stderr, "Rumble strong: %u, weak: %u.\n", buf.u8[0][9 * 4 + 1], buf.u8[0][9 * 4]);
3079 if (rumble.set_rumble_state)
3080 {
3081 // Appears to be correct.
3082 //rumble.set_rumble_state(0, RETRO_RUMBLE_WEAK, buf.u8[0][9 * 4] * 0x101);
3083 //rumble.set_rumble_state(0, RETRO_RUMBLE_STRONG, buf.u8[0][9 * 4 + 1] * 0x101);
3084 //rumble.set_rumble_state(1, RETRO_RUMBLE_WEAK, buf.u8[1][9 * 4] * 0x101);
3085 //rumble.set_rumble_state(1, RETRO_RUMBLE_STRONG, buf.u8[1][9 * 4 + 1] * 0x101);
3086
3087 for (unsigned j = 0; j < players; j++)
3088 {
3089 rumble.set_rumble_state(j, RETRO_RUMBLE_WEAK, buf.u8[j][9 * 4] * 0x101);
3090 rumble.set_rumble_state(j, RETRO_RUMBLE_STRONG, buf.u8[j][9 * 4 + 1] * 0x101);
3091 }
3092 }
3093 }
3094
3095 static uint64_t video_frames, audio_frames;
3096 #define SOUND_CHANNELS 2
3097
3098 void retro_run(void)
3099 {
3100 bool updated = false;
3101 if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE, &updated) && updated)
3102 {
3103 widescreen_auto_ar_old = widescreen_auto_ar;
3104 check_variables();
3105
3106 if (widescreen_auto_ar != widescreen_auto_ar_old)
3107 {
3108 struct retro_system_av_info new_av_info;
3109 retro_get_system_av_info(&new_av_info);
3110 environ_cb(RETRO_ENVIRONMENT_SET_GEOMETRY, &new_av_info);
3111 }
3112 }
3113
3114 if (setting_apply_analog_toggle)
3115 {
3116 FIO->SetAMCT(setting_psx_analog_toggle);
3117 setting_apply_analog_toggle = false;
3118 }
3119
3120 input_poll_cb();
3121
3122 update_input();
3123
3124 static int32 rects[MEDNAFEN_CORE_GEOMETRY_MAX_H];
3125 rects[0] = ~0;
3126
3127 EmulateSpecStruct spec = {0};
3128 spec.surface = surf;
3129 spec.SoundRate = 44100;
3130 spec.SoundBuf = NULL;
3131 spec.LineWidths = rects;
3132 spec.SoundBufMaxSize = 0;
3133 spec.SoundVolume = 1.0;
3134 spec.soundmultiplier = 1.0;
3135 spec.SoundBufSize = 0;
3136 spec.VideoFormatChanged = false;
3137 spec.SoundFormatChanged = false;
3138
3139 EmulateSpecStruct *espec = (EmulateSpecStruct*)&spec;
3140 /* start of Emulate */
3141 int32_t timestamp = 0;
3142
3143 espec->skip = false;
3144 MDFNGameInfo->mouse_sensitivity = MDFN_GetSettingF("psx.input.mouse_sensitivity");
3145
3146 MDFNMP_ApplyPeriodicCheats();
3147
3148
3149 espec->MasterCycles = 0;
3150 espec->SoundBufSize = 0;
3151
3152 FIO->UpdateInput();
3153 GPU->StartFrame(espec);
3154
3155 Running = -1;
3156 timestamp = CPU->Run(timestamp);
3157
3158 assert(timestamp);
3159
3160 ForceEventUpdates(timestamp);
3161 if(GPU->GetScanlineNum() < 100)
3162 PSX_DBG(PSX_DBG_ERROR, "[BUUUUUUUG] Frame timing end glitch; scanline=%u, st=%u\n", GPU->GetScanlineNum(), timestamp);
3163
3164 //printf("scanline=%u, st=%u\n", GPU->GetScanlineNum(), timestamp);
3165
3166 espec->SoundBufSize = IntermediateBufferPos;
3167 IntermediateBufferPos = 0;
3168
3169 CDC->ResetTS();
3170 TIMER_ResetTS();
3171 DMA_ResetTS();
3172 GPU->ResetTS();
3173 FIO->ResetTS();
3174
3175 RebaseTS(timestamp);
3176
3177 espec->MasterCycles = timestamp;
3178
3179 // Save memcards if dirty.
3180 for(int i = 0; i < players; i++)
3181 {
3182 uint64_t new_dc = FIO->GetMemcardDirtyCount(i);
3183
3184 if(new_dc > Memcard_PrevDC[i])
3185 {
3186 Memcard_PrevDC[i] = new_dc;
3187 Memcard_SaveDelay[i] = 0;
3188 }
3189
3190 if(Memcard_SaveDelay[i] >= 0)
3191 {
3192 Memcard_SaveDelay[i] += timestamp;
3193 if(Memcard_SaveDelay[i] >= (33868800 * 2)) // Wait until about 2 seconds of no new writes.
3194 {
3195 char ext[64];
3196 const char *memcard = NULL;
3197
3198 log_cb(RETRO_LOG_INFO, "Saving memcard %d...\n", i);
3199
3200 if (i == 0 && !use_mednafen_memcard0_method)
3201 {
3202 FIO->SaveMemcard(i);
3203 Memcard_SaveDelay[i] = -1;
3204 Memcard_PrevDC[i] = 0;
3205 continue;
3206 }
3207
3208 snprintf(ext, sizeof(ext), "%d.mcr", i);
3209 memcard = MDFN_MakeFName(MDFNMKF_SAV, 0, ext);
3210 FIO->SaveMemcard(i, memcard);
3211 Memcard_SaveDelay[i] = -1;
3212 Memcard_PrevDC[i] = 0;
3213 }
3214 }
3215 }
3216
3217 /* end of Emulate */
3218
3219 #ifdef NEED_DEINTERLACER
3220 if (spec.InterlaceOn)
3221 {
3222 if (!PrevInterlaced)
3223 deint.ClearState();
3224
3225 deint.Process(spec.surface, spec.DisplayRect, spec.LineWidths, spec.InterlaceField);
3226
3227 PrevInterlaced = true;
3228
3229 spec.InterlaceOn = false;
3230 spec.InterlaceField = 0;
3231 }
3232 else
3233 PrevInterlaced = false;
3234 #endif
3235
3236 int16_t *interbuf = (int16_t*)&IntermediateBuffer;
3237
3238 // PSX is rather special, and needs specific handling ...
3239
3240 unsigned width = rects[0]; // spec.DisplayRect.w is 0. Only rects[0].w seems to return something sane.
3241 unsigned height = spec.DisplayRect.h;
3242 //fprintf(stderr, "(%u x %u)\n", width, height);
3243 // PSX core inserts padding on left and right (overscan). Optionally crop this.
3244
3245 const uint32_t *pix = surf->pixels;
3246 if (!overscan)
3247 {
3248 // 320 width -> 350 width.
3249 // 364 width -> 400 width.
3250 // 256 width -> 280 width.
3251 // 560 width -> 512 width.
3252 // 640 width -> 700 width.
3253 // Rectify this.
3254 switch (width)
3255 {
3256 // The shifts are not simply (padded_width - real_width) / 2.
3257 case 280:
3258 pix += 10;
3259 width = 256;
3260 break;
3261
3262 case 350:
3263 pix += 14;
3264 width = 320;
3265 break;
3266
3267 case 400:
3268 pix += 15;
3269 width = 364;
3270 break;
3271
3272
3273 case 560:
3274 pix += 26;
3275 width = 512;
3276 break;
3277
3278 case 700:
3279 pix += 33;
3280 width = 640;
3281 break;
3282
3283 default:
3284 // This shouldn't happen.
3285 break;
3286 }
3287
3288 if (is_pal)
3289 {
3290 // Attempt to remove black bars.
3291 // These numbers are arbitrary since the bars differ some by game.
3292 // Changes aspect ratio in the process.
3293 height -= 36;
3294 pix += 5 * (MEDNAFEN_CORE_GEOMETRY_MAX_W << 2);
3295 }
3296 }
3297 video_cb(pix, width, height, MEDNAFEN_CORE_GEOMETRY_MAX_W << 2);
3298
3299 video_frames++;
3300 audio_frames += spec.SoundBufSize;
3301
3302 audio_batch_cb(interbuf, spec.SoundBufSize);
3303 }
3304
3305 void retro_get_system_info(struct retro_system_info *info)
3306 {
3307 memset(info, 0, sizeof(*info));
3308 info->library_name = MEDNAFEN_CORE_NAME;
3309 info->library_version = MEDNAFEN_CORE_VERSION;
3310 info->need_fullpath = true;
3311 info->valid_extensions = MEDNAFEN_CORE_EXTENSIONS;
3312 info->block_extract = false;
3313 }
3314
3315 void retro_get_system_av_info(struct retro_system_av_info *info)
3316 {
3317 memset(info, 0, sizeof(*info));
3318 info->timing.fps = is_pal ? 49.842 : 59.941;
3319 info->timing.sample_rate = 44100;
3320 info->geometry.base_width = MEDNAFEN_CORE_GEOMETRY_BASE_W;
3321 info->geometry.base_height = MEDNAFEN_CORE_GEOMETRY_BASE_H;
3322 info->geometry.max_width = MEDNAFEN_CORE_GEOMETRY_MAX_W;
3323 info->geometry.max_height = MEDNAFEN_CORE_GEOMETRY_MAX_H;
3324 info->geometry.aspect_ratio = !widescreen_auto_ar ? MEDNAFEN_CORE_GEOMETRY_ASPECT_RATIO : (float)16/9;
3325 }
3326
3327 void retro_deinit(void)
3328 {
3329 delete surf;
3330 surf = NULL;
3331
3332 log_cb(RETRO_LOG_INFO, "[%s]: Samples / Frame: %.5f\n",
3333 MEDNAFEN_CORE_NAME, (double)audio_frames / video_frames);
3334 log_cb(RETRO_LOG_INFO, "[%s]: Estimated FPS: %.5f\n",
3335 MEDNAFEN_CORE_NAME, (double)video_frames * 44100 / audio_frames);
3336 }
3337
3338 unsigned retro_get_region(void)
3339 {
3340 if (is_pal)
3341 return RETRO_REGION_PAL;
3342 return RETRO_REGION_NTSC;
3343 }
3344
3345 unsigned retro_api_version(void)
3346 {
3347 return RETRO_API_VERSION;
3348 }
3349
3350 void retro_set_controller_port_device(unsigned in_port, unsigned device)
3351 {
3352 switch (device)
3353 {
3354 case RETRO_DEVICE_JOYPAD:
3355 case RETRO_DEVICE_PS1PAD:
3356 log_cb(RETRO_LOG_INFO, "[%s]: Selected controller type standard gamepad.\n", MEDNAFEN_CORE_NAME);
3357 SetInput(in_port, "gamepad", &buf.u8[in_port]);
3358 break;
3359 case RETRO_DEVICE_DUALANALOG:
3360 log_cb(RETRO_LOG_INFO, "[%s]: Selected controller type Dual Analog.\n", MEDNAFEN_CORE_NAME);
3361 SetInput(in_port, "dualanalog", &buf.u8[in_port]);
3362 break;
3363 case RETRO_DEVICE_DUALSHOCK:
3364 log_cb(RETRO_LOG_INFO, "[%s]: Selected controller type DualShock.\n", MEDNAFEN_CORE_NAME);
3365 SetInput(in_port, "dualshock", &buf.u8[in_port]);
3366 break;
3367 case RETRO_DEVICE_FLIGHTSTICK:
3368 log_cb(RETRO_LOG_INFO, "[%s]: Selected controller type FlightStick.\n", MEDNAFEN_CORE_NAME);
3369 SetInput(in_port, "analogjoy", &buf.u8[in_port]);
3370 break;
3371 default:
3372 log_cb(RETRO_LOG_WARN, "[%s]: Unsupported controller device %u, falling back to gamepad.\n", MEDNAFEN_CORE_NAME,device);
3373 }
3374
3375 if (rumble.set_rumble_state)
3376 {
3377 rumble.set_rumble_state(in_port, RETRO_RUMBLE_STRONG, 0);
3378 rumble.set_rumble_state(in_port, RETRO_RUMBLE_WEAK, 0);
3379 buf.u32[in_port][9] = 0;
3380 }
3381 }
3382
3383 void retro_set_environment(retro_environment_t cb)
3384 {
3385 environ_cb = cb;
3386
3387 static const struct retro_variable vars[] = {
3388 { "beetle_psx_cdimagecache", "CD Image Cache (restart); disabled|enabled" },
3389 { "beetle_psx_widescreen_hack", "Widescreen mode hack; disabled|enabled" },
3390 { "beetle_psx_widescreen_auto_ar", "Widescreen hack auto aspect ratio; disabled|enabled" },
3391 { "beetle_psx_use_mednafen_memcard0_method", "Memcard 0 method; libretro|mednafen" },
3392 { "beetle_psx_shared_memory_cards", "Shared memcards (restart); disabled|enabled" },
3393 { "beetle_psx_initial_scanline", "Initial scanline; 0|1|2|3|4|5|6|7|8|9|10|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40" },
3394 { "beetle_psx_initial_scanline_pal", "Initial scanline PAL; 0|1|2|3|4|5|6|7|8|9|10|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|32|33|34|35|36|37|38|39|40" },
3395 { "beetle_psx_last_scanline", "Last scanline; 239|238|237|236|235|234|232|231|230|229|228|227|226|225|224|223|222|221|220|219|218|217|216|215|214|213|212|211|210" },
3396 { "beetle_psx_last_scanline_pal", "Last scanline PAL; 287|286|285|284|283|283|282|281|280|279|278|277|276|275|274|273|272|271|270|269|268|267|266|265|264|263|262|261|260" },
3397 { "beetle_psx_analog_toggle", "Dualshock analog toggle; disabled|enabled" },
3398 { "beetle_psx_enable_multitap_port1", "Port 1: Multitap enable; disabled|enabled" },
3399 { "beetle_psx_enable_multitap_port2", "Port 2: Multitap enable; disabled|enabled" },
3400 { NULL, NULL },
3401 };
3402 static const struct retro_controller_description pads[] = {
3403 { "PS1 Joypad", RETRO_DEVICE_JOYPAD },
3404 { "DualAnalog", RETRO_DEVICE_DUALANALOG },
3405 { "DualShock", RETRO_DEVICE_DUALSHOCK },
3406 { "FlightStick", RETRO_DEVICE_FLIGHTSTICK },
3407 };
3408
3409 static const struct retro_controller_info ports[] = {
3410 { pads, 4 },
3411 { pads, 4 },
3412 { pads, 4 },
3413 { pads, 4 },
3414 { pads, 4 },
3415 { pads, 4 },
3416 { pads, 4 },
3417 { pads, 4 },
3418 { 0 },
3419 };
3420
3421 cb(RETRO_ENVIRONMENT_SET_VARIABLES, (void*)vars);
3422 environ_cb(RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports);
3423 }
3424
3425 void retro_set_audio_sample(retro_audio_sample_t cb)
3426 {
3427 audio_cb = cb;
3428 }
3429
3430 void retro_set_audio_sample_batch(retro_audio_sample_batch_t cb)
3431 {
3432 audio_batch_cb = cb;
3433 }
3434
3435 void retro_set_input_poll(retro_input_poll_t cb)
3436 {
3437 input_poll_cb = cb;
3438 }
3439
3440 void retro_set_input_state(retro_input_state_t cb)
3441 {
3442 input_state_cb = cb;
3443 }
3444
3445 void retro_set_video_refresh(retro_video_refresh_t cb)
3446 {
3447 video_cb = cb;
3448 }
3449
3450 static size_t serialize_size;
3451
3452 size_t retro_serialize_size(void)
3453 {
3454 StateMem st;
3455 memset(&st, 0, sizeof(st));
3456
3457 if (!MDFNSS_SaveSM(&st, 0, 0, NULL, NULL, NULL))
3458 {
3459 return 0;
3460 }
3461
3462 free(st.data);
3463 return serialize_size = st.len;
3464 }
3465
3466 bool retro_serialize(void *data, size_t size)
3467 {
3468 /* it seems that mednafen can realloc pointers sent to it?
3469 since we don't know the disposition of void* data (is it safe to realloc?) we have to manage a new buffer here */
3470 StateMem st;
3471 memset(&st, 0, sizeof(st));
3472 st.data = (uint8_t*)malloc(size);
3473 st.malloced = size;
3474
3475 bool ret = MDFNSS_SaveSM(&st, 0, 0, NULL, NULL, NULL);
3476
3477 /* there are still some errors with the save states, the size seems to change on some games for now just log when this happens */
3478 if (st.len != size)
3479 log_cb(RETRO_LOG_WARN, "warning, save state size has changed\n");
3480
3481 memcpy(data,st.data,size);
3482 free(st.data);
3483 return ret;
3484
3485 }
3486 bool retro_unserialize(const void *data, size_t size)
3487 {
3488 StateMem st;
3489 memset(&st, 0, sizeof(st));
3490 st.data = (uint8_t*)data;
3491 st.len = size;
3492
3493 return MDFNSS_LoadSM(&st, 0, 0);
3494 }
3495
3496 void *retro_get_memory_data(unsigned type)
3497 {
3498 uint8_t *data;
3499
3500 switch (type)
3501 {
3502 case RETRO_MEMORY_SAVE_RAM:
3503 if (use_mednafen_memcard0_method)
3504 return NULL;
3505 return FIO->GetMemcardDevice(0)->GetNVData();
3506 default:
3507 break;
3508 }
3509 return NULL;
3510 }
3511
3512 size_t retro_get_memory_size(unsigned type)
3513 {
3514 switch (type)
3515 {
3516 case RETRO_MEMORY_SAVE_RAM:
3517 if (use_mednafen_memcard0_method)
3518 return 0;
3519 return (1 << 17);
3520 default:
3521 break;
3522 }
3523
3524 return 0;
3525 }
3526
3527 void retro_cheat_reset(void)
3528 {}
3529
3530 void retro_cheat_set(unsigned, bool, const char *)
3531 {}
3532
3533 #ifdef _WIN32
3534 static void sanitize_path(std::string &path)
3535 {
3536 size_t size = path.size();
3537 for (size_t i = 0; i < size; i++)
3538 if (path[i] == '/')
3539 path[i] = '\\';
3540 }
3541 #endif
3542
3543 // Use a simpler approach to make sure that things go right for libretro.
3544 const char *MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1)
3545 {
3546 static char fullpath[4096];
3547
3548 fullpath[0] = '\0';
3549
3550 switch (type)
3551 {
3552 case MDFNMKF_SAV:
3553 snprintf(fullpath, sizeof(fullpath), "%s%c%s.%s",
3554 retro_save_directory,
3555 retro_slash,
3556 (!shared_memorycards) ? retro_cd_base_name : "mednafen_psx_libretro_shared",
3557 cd1);
3558 break;
3559 case MDFNMKF_FIRMWARE:
3560 snprintf(fullpath, sizeof(fullpath), "%s%c%s", retro_base_directory, retro_slash, cd1);
3561 break;
3562 default:
3563 break;
3564 }
3565
3566 return fullpath;
3567 }
3568
3569 void MDFND_DispMessage(unsigned char *str)
3570 {
3571 const char *strc = (const char*)str;
3572 struct retro_message msg =
3573 {
3574 strc,
3575 180
3576 };
3577
3578 environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
3579 }
3580
3581 void MDFN_DispMessage(const char *format, ...)
3582 {
3583 struct retro_message msg;
3584 va_list ap;
3585 va_start(ap,format);
3586 char *str = NULL;
3587 const char *strc = NULL;
3588
3589 trio_vasprintf(&str, format,ap);
3590 va_end(ap);
3591 strc = str;
3592
3593 msg.frames = 180;
3594 msg.msg = strc;
3595
3596 environ_cb(RETRO_ENVIRONMENT_SET_MESSAGE, &msg);
3597 }
0 /* Copyright (C) 2010-2014 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this libretro API header (libretro.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef LIBRETRO_H__
23 #define LIBRETRO_H__
24
25 #include <stdint.h>
26 #include <stddef.h>
27 #include <limits.h>
28
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32
33 #ifndef __cplusplus
34 #if defined(_MSC_VER) && !defined(SN_TARGET_PS3)
35 /* Hack applied for MSVC when compiling in C89 mode
36 * as it isn't C99-compliant. */
37 #define bool unsigned char
38 #define true 1
39 #define false 0
40 #else
41 #include <stdbool.h>
42 #endif
43 #endif
44
45 /* Used for checking API/ABI mismatches that can break libretro
46 * implementations.
47 * It is not incremented for compatible changes to the API.
48 */
49 #define RETRO_API_VERSION 1
50
51 /*
52 * Libretro's fundamental device abstractions.
53 *
54 * Libretro's input system consists of some standardized device types,
55 * such as a joypad (with/without analog), mouse, keyboard, lightgun
56 * and a pointer.
57 *
58 * The functionality of these devices are fixed, and individual cores
59 * map their own concept of a controller to libretro's abstractions.
60 * This makes it possible for frontends to map the abstract types to a
61 * real input device, and not having to worry about binding input
62 * correctly to arbitrary controller layouts.
63 */
64
65 #define RETRO_DEVICE_TYPE_SHIFT 8
66 #define RETRO_DEVICE_MASK ((1 << RETRO_DEVICE_TYPE_SHIFT) - 1)
67 #define RETRO_DEVICE_SUBCLASS(base, id) (((id + 1) << RETRO_DEVICE_TYPE_SHIFT) | base)
68
69 /* Input disabled. */
70 #define RETRO_DEVICE_NONE 0
71
72 /* The JOYPAD is called RetroPad. It is essentially a Super Nintendo
73 * controller, but with additional L2/R2/L3/R3 buttons, similar to a
74 * PS1 DualShock. */
75 #define RETRO_DEVICE_JOYPAD 1
76
77 /* The mouse is a simple mouse, similar to Super Nintendo's mouse.
78 * X and Y coordinates are reported relatively to last poll (poll callback).
79 * It is up to the libretro implementation to keep track of where the mouse
80 * pointer is supposed to be on the screen.
81 * The frontend must make sure not to interfere with its own hardware
82 * mouse pointer.
83 */
84 #define RETRO_DEVICE_MOUSE 2
85
86 /* KEYBOARD device lets one poll for raw key pressed.
87 * It is poll based, so input callback will return with the current
88 * pressed state.
89 * For event/text based keyboard input, see
90 * RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
91 */
92 #define RETRO_DEVICE_KEYBOARD 3
93
94 /* Lightgun X/Y coordinates are reported relatively to last poll,
95 * similar to mouse. */
96 #define RETRO_DEVICE_LIGHTGUN 4
97
98 /* The ANALOG device is an extension to JOYPAD (RetroPad).
99 * Similar to DualShock it adds two analog sticks.
100 * This is treated as a separate device type as it returns values in the
101 * full analog range of [-0x8000, 0x7fff]. Positive X axis is right.
102 * Positive Y axis is down.
103 * Only use ANALOG type when polling for analog values of the axes.
104 */
105 #define RETRO_DEVICE_ANALOG 5
106
107 /* Abstracts the concept of a pointing mechanism, e.g. touch.
108 * This allows libretro to query in absolute coordinates where on the
109 * screen a mouse (or something similar) is being placed.
110 * For a touch centric device, coordinates reported are the coordinates
111 * of the press.
112 *
113 * Coordinates in X and Y are reported as:
114 * [-0x7fff, 0x7fff]: -0x7fff corresponds to the far left/top of the screen,
115 * and 0x7fff corresponds to the far right/bottom of the screen.
116 * The "screen" is here defined as area that is passed to the frontend and
117 * later displayed on the monitor.
118 *
119 * The frontend is free to scale/resize this screen as it sees fit, however,
120 * (X, Y) = (-0x7fff, -0x7fff) will correspond to the top-left pixel of the
121 * game image, etc.
122 *
123 * To check if the pointer coordinates are valid (e.g. a touch display
124 * actually being touched), PRESSED returns 1 or 0.
125 *
126 * If using a mouse on a desktop, PRESSED will usually correspond to the
127 * left mouse button, but this is a frontend decision.
128 * PRESSED will only return 1 if the pointer is inside the game screen.
129 *
130 * For multi-touch, the index variable can be used to successively query
131 * more presses.
132 * If index = 0 returns true for _PRESSED, coordinates can be extracted
133 * with _X, _Y for index = 0. One can then query _PRESSED, _X, _Y with
134 * index = 1, and so on.
135 * Eventually _PRESSED will return false for an index. No further presses
136 * are registered at this point. */
137 #define RETRO_DEVICE_POINTER 6
138
139 /* Buttons for the RetroPad (JOYPAD).
140 * The placement of these is equivalent to placements on the
141 * Super Nintendo controller.
142 * L2/R2/L3/R3 buttons correspond to the PS1 DualShock. */
143 #define RETRO_DEVICE_ID_JOYPAD_B 0
144 #define RETRO_DEVICE_ID_JOYPAD_Y 1
145 #define RETRO_DEVICE_ID_JOYPAD_SELECT 2
146 #define RETRO_DEVICE_ID_JOYPAD_START 3
147 #define RETRO_DEVICE_ID_JOYPAD_UP 4
148 #define RETRO_DEVICE_ID_JOYPAD_DOWN 5
149 #define RETRO_DEVICE_ID_JOYPAD_LEFT 6
150 #define RETRO_DEVICE_ID_JOYPAD_RIGHT 7
151 #define RETRO_DEVICE_ID_JOYPAD_A 8
152 #define RETRO_DEVICE_ID_JOYPAD_X 9
153 #define RETRO_DEVICE_ID_JOYPAD_L 10
154 #define RETRO_DEVICE_ID_JOYPAD_R 11
155 #define RETRO_DEVICE_ID_JOYPAD_L2 12
156 #define RETRO_DEVICE_ID_JOYPAD_R2 13
157 #define RETRO_DEVICE_ID_JOYPAD_L3 14
158 #define RETRO_DEVICE_ID_JOYPAD_R3 15
159
160 /* Index / Id values for ANALOG device. */
161 #define RETRO_DEVICE_INDEX_ANALOG_LEFT 0
162 #define RETRO_DEVICE_INDEX_ANALOG_RIGHT 1
163 #define RETRO_DEVICE_ID_ANALOG_X 0
164 #define RETRO_DEVICE_ID_ANALOG_Y 1
165
166 /* Id values for MOUSE. */
167 #define RETRO_DEVICE_ID_MOUSE_X 0
168 #define RETRO_DEVICE_ID_MOUSE_Y 1
169 #define RETRO_DEVICE_ID_MOUSE_LEFT 2
170 #define RETRO_DEVICE_ID_MOUSE_RIGHT 3
171 #define RETRO_DEVICE_ID_MOUSE_WHEELUP 4
172 #define RETRO_DEVICE_ID_MOUSE_WHEELDOWN 5
173 #define RETRO_DEVICE_ID_MOUSE_MIDDLE 6
174
175 /* Id values for LIGHTGUN types. */
176 #define RETRO_DEVICE_ID_LIGHTGUN_X 0
177 #define RETRO_DEVICE_ID_LIGHTGUN_Y 1
178 #define RETRO_DEVICE_ID_LIGHTGUN_TRIGGER 2
179 #define RETRO_DEVICE_ID_LIGHTGUN_CURSOR 3
180 #define RETRO_DEVICE_ID_LIGHTGUN_TURBO 4
181 #define RETRO_DEVICE_ID_LIGHTGUN_PAUSE 5
182 #define RETRO_DEVICE_ID_LIGHTGUN_START 6
183
184 /* Id values for POINTER. */
185 #define RETRO_DEVICE_ID_POINTER_X 0
186 #define RETRO_DEVICE_ID_POINTER_Y 1
187 #define RETRO_DEVICE_ID_POINTER_PRESSED 2
188
189 /* Returned from retro_get_region(). */
190 #define RETRO_REGION_NTSC 0
191 #define RETRO_REGION_PAL 1
192
193 /* Id values for LANGUAGE */
194 enum retro_language
195 {
196 RETRO_LANGUAGE_ENGLISH = 0,
197 RETRO_LANGUAGE_JAPANESE = 1,
198 RETRO_LANGUAGE_FRENCH = 2,
199 RETRO_LANGUAGE_SPANISH = 3,
200 RETRO_LANGUAGE_GERMAN = 4,
201 RETRO_LANGUAGE_ITALIAN = 5,
202 RETRO_LANGUAGE_DUTCH = 6,
203 RETRO_LANGUAGE_PORTUGUESE = 7,
204 RETRO_LANGUAGE_RUSSIAN = 8,
205 RETRO_LANGUAGE_KOREAN = 9,
206 RETRO_LANGUAGE_CHINESE_TRADITIONAL = 10,
207 RETRO_LANGUAGE_CHINESE_SIMPLIFIED = 11,
208 RETRO_LANGUAGE_LAST,
209
210 /* Ensure sizeof(enum) == sizeof(int) */
211 RETRO_LANGUAGE_DUMMY = INT_MAX
212 };
213
214 /* Passed to retro_get_memory_data/size().
215 * If the memory type doesn't apply to the
216 * implementation NULL/0 can be returned.
217 */
218 #define RETRO_MEMORY_MASK 0xff
219
220 /* Regular save RAM. This RAM is usually found on a game cartridge,
221 * backed up by a battery.
222 * If save game data is too complex for a single memory buffer,
223 * the SAVE_DIRECTORY (preferably) or SYSTEM_DIRECTORY environment
224 * callback can be used. */
225 #define RETRO_MEMORY_SAVE_RAM 0
226
227 /* Some games have a built-in clock to keep track of time.
228 * This memory is usually just a couple of bytes to keep track of time.
229 */
230 #define RETRO_MEMORY_RTC 1
231
232 /* System ram lets a frontend peek into a game systems main RAM. */
233 #define RETRO_MEMORY_SYSTEM_RAM 2
234
235 /* Video ram lets a frontend peek into a game systems video RAM (VRAM). */
236 #define RETRO_MEMORY_VIDEO_RAM 3
237
238 /* Keysyms used for ID in input state callback when polling RETRO_KEYBOARD. */
239 enum retro_key
240 {
241 RETROK_UNKNOWN = 0,
242 RETROK_FIRST = 0,
243 RETROK_BACKSPACE = 8,
244 RETROK_TAB = 9,
245 RETROK_CLEAR = 12,
246 RETROK_RETURN = 13,
247 RETROK_PAUSE = 19,
248 RETROK_ESCAPE = 27,
249 RETROK_SPACE = 32,
250 RETROK_EXCLAIM = 33,
251 RETROK_QUOTEDBL = 34,
252 RETROK_HASH = 35,
253 RETROK_DOLLAR = 36,
254 RETROK_AMPERSAND = 38,
255 RETROK_QUOTE = 39,
256 RETROK_LEFTPAREN = 40,
257 RETROK_RIGHTPAREN = 41,
258 RETROK_ASTERISK = 42,
259 RETROK_PLUS = 43,
260 RETROK_COMMA = 44,
261 RETROK_MINUS = 45,
262 RETROK_PERIOD = 46,
263 RETROK_SLASH = 47,
264 RETROK_0 = 48,
265 RETROK_1 = 49,
266 RETROK_2 = 50,
267 RETROK_3 = 51,
268 RETROK_4 = 52,
269 RETROK_5 = 53,
270 RETROK_6 = 54,
271 RETROK_7 = 55,
272 RETROK_8 = 56,
273 RETROK_9 = 57,
274 RETROK_COLON = 58,
275 RETROK_SEMICOLON = 59,
276 RETROK_LESS = 60,
277 RETROK_EQUALS = 61,
278 RETROK_GREATER = 62,
279 RETROK_QUESTION = 63,
280 RETROK_AT = 64,
281 RETROK_LEFTBRACKET = 91,
282 RETROK_BACKSLASH = 92,
283 RETROK_RIGHTBRACKET = 93,
284 RETROK_CARET = 94,
285 RETROK_UNDERSCORE = 95,
286 RETROK_BACKQUOTE = 96,
287 RETROK_a = 97,
288 RETROK_b = 98,
289 RETROK_c = 99,
290 RETROK_d = 100,
291 RETROK_e = 101,
292 RETROK_f = 102,
293 RETROK_g = 103,
294 RETROK_h = 104,
295 RETROK_i = 105,
296 RETROK_j = 106,
297 RETROK_k = 107,
298 RETROK_l = 108,
299 RETROK_m = 109,
300 RETROK_n = 110,
301 RETROK_o = 111,
302 RETROK_p = 112,
303 RETROK_q = 113,
304 RETROK_r = 114,
305 RETROK_s = 115,
306 RETROK_t = 116,
307 RETROK_u = 117,
308 RETROK_v = 118,
309 RETROK_w = 119,
310 RETROK_x = 120,
311 RETROK_y = 121,
312 RETROK_z = 122,
313 RETROK_DELETE = 127,
314
315 RETROK_KP0 = 256,
316 RETROK_KP1 = 257,
317 RETROK_KP2 = 258,
318 RETROK_KP3 = 259,
319 RETROK_KP4 = 260,
320 RETROK_KP5 = 261,
321 RETROK_KP6 = 262,
322 RETROK_KP7 = 263,
323 RETROK_KP8 = 264,
324 RETROK_KP9 = 265,
325 RETROK_KP_PERIOD = 266,
326 RETROK_KP_DIVIDE = 267,
327 RETROK_KP_MULTIPLY = 268,
328 RETROK_KP_MINUS = 269,
329 RETROK_KP_PLUS = 270,
330 RETROK_KP_ENTER = 271,
331 RETROK_KP_EQUALS = 272,
332
333 RETROK_UP = 273,
334 RETROK_DOWN = 274,
335 RETROK_RIGHT = 275,
336 RETROK_LEFT = 276,
337 RETROK_INSERT = 277,
338 RETROK_HOME = 278,
339 RETROK_END = 279,
340 RETROK_PAGEUP = 280,
341 RETROK_PAGEDOWN = 281,
342
343 RETROK_F1 = 282,
344 RETROK_F2 = 283,
345 RETROK_F3 = 284,
346 RETROK_F4 = 285,
347 RETROK_F5 = 286,
348 RETROK_F6 = 287,
349 RETROK_F7 = 288,
350 RETROK_F8 = 289,
351 RETROK_F9 = 290,
352 RETROK_F10 = 291,
353 RETROK_F11 = 292,
354 RETROK_F12 = 293,
355 RETROK_F13 = 294,
356 RETROK_F14 = 295,
357 RETROK_F15 = 296,
358
359 RETROK_NUMLOCK = 300,
360 RETROK_CAPSLOCK = 301,
361 RETROK_SCROLLOCK = 302,
362 RETROK_RSHIFT = 303,
363 RETROK_LSHIFT = 304,
364 RETROK_RCTRL = 305,
365 RETROK_LCTRL = 306,
366 RETROK_RALT = 307,
367 RETROK_LALT = 308,
368 RETROK_RMETA = 309,
369 RETROK_LMETA = 310,
370 RETROK_LSUPER = 311,
371 RETROK_RSUPER = 312,
372 RETROK_MODE = 313,
373 RETROK_COMPOSE = 314,
374
375 RETROK_HELP = 315,
376 RETROK_PRINT = 316,
377 RETROK_SYSREQ = 317,
378 RETROK_BREAK = 318,
379 RETROK_MENU = 319,
380 RETROK_POWER = 320,
381 RETROK_EURO = 321,
382 RETROK_UNDO = 322,
383
384 RETROK_LAST,
385
386 RETROK_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
387 };
388
389 enum retro_mod
390 {
391 RETROKMOD_NONE = 0x0000,
392
393 RETROKMOD_SHIFT = 0x01,
394 RETROKMOD_CTRL = 0x02,
395 RETROKMOD_ALT = 0x04,
396 RETROKMOD_META = 0x08,
397
398 RETROKMOD_NUMLOCK = 0x10,
399 RETROKMOD_CAPSLOCK = 0x20,
400 RETROKMOD_SCROLLOCK = 0x40,
401
402 RETROKMOD_DUMMY = INT_MAX /* Ensure sizeof(enum) == sizeof(int) */
403 };
404
405 /* If set, this call is not part of the public libretro API yet. It can
406 * change or be removed at any time. */
407 #define RETRO_ENVIRONMENT_EXPERIMENTAL 0x10000
408 /* Environment callback to be used internally in frontend. */
409 #define RETRO_ENVIRONMENT_PRIVATE 0x20000
410
411 /* Environment commands. */
412 #define RETRO_ENVIRONMENT_SET_ROTATION 1 /* const unsigned * --
413 * Sets screen rotation of graphics.
414 * Is only implemented if rotation can be accelerated by hardware.
415 * Valid values are 0, 1, 2, 3, which rotates screen by 0, 90, 180,
416 * 270 degrees counter-clockwise respectively.
417 */
418 #define RETRO_ENVIRONMENT_GET_OVERSCAN 2 /* bool * --
419 * Boolean value whether or not the implementation should use overscan,
420 * or crop away overscan.
421 */
422 #define RETRO_ENVIRONMENT_GET_CAN_DUPE 3 /* bool * --
423 * Boolean value whether or not frontend supports frame duping,
424 * passing NULL to video frame callback.
425 */
426
427 /* Environ 4, 5 are no longer supported (GET_VARIABLE / SET_VARIABLES),
428 * and reserved to avoid possible ABI clash.
429 */
430
431 #define RETRO_ENVIRONMENT_SET_MESSAGE 6 /* const struct retro_message * --
432 * Sets a message to be displayed in implementation-specific manner
433 * for a certain amount of 'frames'.
434 * Should not be used for trivial messages, which should simply be
435 * logged via RETRO_ENVIRONMENT_GET_LOG_INTERFACE (or as a
436 * fallback, stderr).
437 */
438 #define RETRO_ENVIRONMENT_SHUTDOWN 7 /* N/A (NULL) --
439 * Requests the frontend to shutdown.
440 * Should only be used if game has a specific
441 * way to shutdown the game from a menu item or similar.
442 */
443 #define RETRO_ENVIRONMENT_SET_PERFORMANCE_LEVEL 8
444 /* const unsigned * --
445 * Gives a hint to the frontend how demanding this implementation
446 * is on a system. E.g. reporting a level of 2 means
447 * this implementation should run decently on all frontends
448 * of level 2 and up.
449 *
450 * It can be used by the frontend to potentially warn
451 * about too demanding implementations.
452 *
453 * The levels are "floating".
454 *
455 * This function can be called on a per-game basis,
456 * as certain games an implementation can play might be
457 * particularly demanding.
458 * If called, it should be called in retro_load_game().
459 */
460 #define RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY 9
461 /* const char ** --
462 * Returns the "system" directory of the frontend.
463 * This directory can be used to store system specific
464 * content such as BIOSes, configuration data, etc.
465 * The returned value can be NULL.
466 * If so, no such directory is defined,
467 * and it's up to the implementation to find a suitable directory.
468 *
469 * NOTE: Some cores used this folder also for "save" data such as
470 * memory cards, etc, for lack of a better place to put it.
471 * This is now discouraged, and if possible, cores should try to
472 * use the new GET_SAVE_DIRECTORY.
473 */
474 #define RETRO_ENVIRONMENT_SET_PIXEL_FORMAT 10
475 /* const enum retro_pixel_format * --
476 * Sets the internal pixel format used by the implementation.
477 * The default pixel format is RETRO_PIXEL_FORMAT_0RGB1555.
478 * This pixel format however, is deprecated (see enum retro_pixel_format).
479 * If the call returns false, the frontend does not support this pixel
480 * format.
481 *
482 * This function should be called inside retro_load_game() or
483 * retro_get_system_av_info().
484 */
485 #define RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS 11
486 /* const struct retro_input_descriptor * --
487 * Sets an array of retro_input_descriptors.
488 * It is up to the frontend to present this in a usable way.
489 * The array is terminated by retro_input_descriptor::description
490 * being set to NULL.
491 * This function can be called at any time, but it is recommended
492 * to call it as early as possible.
493 */
494 #define RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK 12
495 /* const struct retro_keyboard_callback * --
496 * Sets a callback function used to notify core about keyboard events.
497 */
498 #define RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE 13
499 /* const struct retro_disk_control_callback * --
500 * Sets an interface which frontend can use to eject and insert
501 * disk images.
502 * This is used for games which consist of multiple images and
503 * must be manually swapped out by the user (e.g. PSX).
504 */
505 #define RETRO_ENVIRONMENT_SET_HW_RENDER 14
506 /* struct retro_hw_render_callback * --
507 * Sets an interface to let a libretro core render with
508 * hardware acceleration.
509 * Should be called in retro_load_game().
510 * If successful, libretro cores will be able to render to a
511 * frontend-provided framebuffer.
512 * The size of this framebuffer will be at least as large as
513 * max_width/max_height provided in get_av_info().
514 * If HW rendering is used, pass only RETRO_HW_FRAME_BUFFER_VALID or
515 * NULL to retro_video_refresh_t.
516 */
517 #define RETRO_ENVIRONMENT_GET_VARIABLE 15
518 /* struct retro_variable * --
519 * Interface to acquire user-defined information from environment
520 * that cannot feasibly be supported in a multi-system way.
521 * 'key' should be set to a key which has already been set by
522 * SET_VARIABLES.
523 * 'data' will be set to a value or NULL.
524 */
525 #define RETRO_ENVIRONMENT_SET_VARIABLES 16
526 /* const struct retro_variable * --
527 * Allows an implementation to signal the environment
528 * which variables it might want to check for later using
529 * GET_VARIABLE.
530 * This allows the frontend to present these variables to
531 * a user dynamically.
532 * This should be called as early as possible (ideally in
533 * retro_set_environment).
534 *
535 * 'data' points to an array of retro_variable structs
536 * terminated by a { NULL, NULL } element.
537 * retro_variable::key should be namespaced to not collide
538 * with other implementations' keys. E.g. A core called
539 * 'foo' should use keys named as 'foo_option'.
540 * retro_variable::value should contain a human readable
541 * description of the key as well as a '|' delimited list
542 * of expected values.
543 *
544 * The number of possible options should be very limited,
545 * i.e. it should be feasible to cycle through options
546 * without a keyboard.
547 *
548 * First entry should be treated as a default.
549 *
550 * Example entry:
551 * { "foo_option", "Speed hack coprocessor X; false|true" }
552 *
553 * Text before first ';' is description. This ';' must be
554 * followed by a space, and followed by a list of possible
555 * values split up with '|'.
556 *
557 * Only strings are operated on. The possible values will
558 * generally be displayed and stored as-is by the frontend.
559 */
560 #define RETRO_ENVIRONMENT_GET_VARIABLE_UPDATE 17
561 /* bool * --
562 * Result is set to true if some variables are updated by
563 * frontend since last call to RETRO_ENVIRONMENT_GET_VARIABLE.
564 * Variables should be queried with GET_VARIABLE.
565 */
566 #define RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME 18
567 /* const bool * --
568 * If true, the libretro implementation supports calls to
569 * retro_load_game() with NULL as argument.
570 * Used by cores which can run without particular game data.
571 * This should be called within retro_set_environment() only.
572 */
573 #define RETRO_ENVIRONMENT_GET_LIBRETRO_PATH 19
574 /* const char ** --
575 * Retrieves the absolute path from where this libretro
576 * implementation was loaded.
577 * NULL is returned if the libretro was loaded statically
578 * (i.e. linked statically to frontend), or if the path cannot be
579 * determined.
580 * Mostly useful in cooperation with SET_SUPPORT_NO_GAME as assets can
581 * be loaded without ugly hacks.
582 */
583
584 /* Environment 20 was an obsolete version of SET_AUDIO_CALLBACK.
585 * It was not used by any known core at the time,
586 * and was removed from the API. */
587 #define RETRO_ENVIRONMENT_SET_AUDIO_CALLBACK 22
588 /* const struct retro_audio_callback * --
589 * Sets an interface which is used to notify a libretro core about audio
590 * being available for writing.
591 * The callback can be called from any thread, so a core using this must
592 * have a thread safe audio implementation.
593 * It is intended for games where audio and video are completely
594 * asynchronous and audio can be generated on the fly.
595 * This interface is not recommended for use with emulators which have
596 * highly synchronous audio.
597 *
598 * The callback only notifies about writability; the libretro core still
599 * has to call the normal audio callbacks
600 * to write audio. The audio callbacks must be called from within the
601 * notification callback.
602 * The amount of audio data to write is up to the implementation.
603 * Generally, the audio callback will be called continously in a loop.
604 *
605 * Due to thread safety guarantees and lack of sync between audio and
606 * video, a frontend can selectively disallow this interface based on
607 * internal configuration. A core using this interface must also
608 * implement the "normal" audio interface.
609 *
610 * A libretro core using SET_AUDIO_CALLBACK should also make use of
611 * SET_FRAME_TIME_CALLBACK.
612 */
613 #define RETRO_ENVIRONMENT_SET_FRAME_TIME_CALLBACK 21
614 /* const struct retro_frame_time_callback * --
615 * Lets the core know how much time has passed since last
616 * invocation of retro_run().
617 * The frontend can tamper with the timing to fake fast-forward,
618 * slow-motion, frame stepping, etc.
619 * In this case the delta time will use the reference value
620 * in frame_time_callback..
621 */
622 #define RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE 23
623 /* struct retro_rumble_interface * --
624 * Gets an interface which is used by a libretro core to set
625 * state of rumble motors in controllers.
626 * A strong and weak motor is supported, and they can be
627 * controlled indepedently.
628 */
629 #define RETRO_ENVIRONMENT_GET_INPUT_DEVICE_CAPABILITIES 24
630 /* uint64_t * --
631 * Gets a bitmask telling which device type are expected to be
632 * handled properly in a call to retro_input_state_t.
633 * Devices which are not handled or recognized always return
634 * 0 in retro_input_state_t.
635 * Example bitmask: caps = (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG).
636 * Should only be called in retro_run().
637 */
638 #define RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE (25 | RETRO_ENVIRONMENT_EXPERIMENTAL)
639 /* struct retro_sensor_interface * --
640 * Gets access to the sensor interface.
641 * The purpose of this interface is to allow
642 * setting state related to sensors such as polling rate,
643 * enabling/disable it entirely, etc.
644 * Reading sensor state is done via the normal
645 * input_state_callback API.
646 */
647 #define RETRO_ENVIRONMENT_GET_CAMERA_INTERFACE (26 | RETRO_ENVIRONMENT_EXPERIMENTAL)
648 /* struct retro_camera_callback * --
649 * Gets an interface to a video camera driver.
650 * A libretro core can use this interface to get access to a
651 * video camera.
652 * New video frames are delivered in a callback in same
653 * thread as retro_run().
654 *
655 * GET_CAMERA_INTERFACE should be called in retro_load_game().
656 *
657 * Depending on the camera implementation used, camera frames
658 * will be delivered as a raw framebuffer,
659 * or as an OpenGL texture directly.
660 *
661 * The core has to tell the frontend here which types of
662 * buffers can be handled properly.
663 * An OpenGL texture can only be handled when using a
664 * libretro GL core (SET_HW_RENDER).
665 * It is recommended to use a libretro GL core when
666 * using camera interface.
667 *
668 * The camera is not started automatically. The retrieved start/stop
669 * functions must be used to explicitly
670 * start and stop the camera driver.
671 */
672 #define RETRO_ENVIRONMENT_GET_LOG_INTERFACE 27
673 /* struct retro_log_callback * --
674 * Gets an interface for logging. This is useful for
675 * logging in a cross-platform way
676 * as certain platforms cannot use use stderr for logging.
677 * It also allows the frontend to
678 * show logging information in a more suitable way.
679 * If this interface is not used, libretro cores should
680 * log to stderr as desired.
681 */
682 #define RETRO_ENVIRONMENT_GET_PERF_INTERFACE 28
683 /* struct retro_perf_callback * --
684 * Gets an interface for performance counters. This is useful
685 * for performance logging in a cross-platform way and for detecting
686 * architecture-specific features, such as SIMD support.
687 */
688 #define RETRO_ENVIRONMENT_GET_LOCATION_INTERFACE 29
689 /* struct retro_location_callback * --
690 * Gets access to the location interface.
691 * The purpose of this interface is to be able to retrieve
692 * location-based information from the host device,
693 * such as current latitude / longitude.
694 */
695 #define RETRO_ENVIRONMENT_GET_CONTENT_DIRECTORY 30
696 /* const char ** --
697 * Returns the "content" directory of the frontend.
698 * This directory can be used to store specific assets that the
699 * core relies upon, such as art assets,
700 * input data, etc etc.
701 * The returned value can be NULL.
702 * If so, no such directory is defined,
703 * and it's up to the implementation to find a suitable directory.
704 */
705 #define RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY 31
706 /* const char ** --
707 * Returns the "save" directory of the frontend.
708 * This directory can be used to store SRAM, memory cards,
709 * high scores, etc, if the libretro core
710 * cannot use the regular memory interface (retro_get_memory_data()).
711 *
712 * NOTE: libretro cores used to check GET_SYSTEM_DIRECTORY for
713 * similar things before.
714 * They should still check GET_SYSTEM_DIRECTORY if they want to
715 * be backwards compatible.
716 * The path here can be NULL. It should only be non-NULL if the
717 * frontend user has set a specific save path.
718 */
719 #define RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO 32
720 /* const struct retro_system_av_info * --
721 * Sets a new av_info structure. This can only be called from
722 * within retro_run().
723 * This should *only* be used if the core is completely altering the
724 * internal resolutions, aspect ratios, timings, sampling rate, etc.
725 * Calling this can require a full reinitialization of video/audio
726 * drivers in the frontend,
727 *
728 * so it is important to call it very sparingly, and usually only with
729 * the users explicit consent.
730 * An eventual driver reinitialize will happen so that video and
731 * audio callbacks
732 * happening after this call within the same retro_run() call will
733 * target the newly initialized driver.
734 *
735 * This callback makes it possible to support configurable resolutions
736 * in games, which can be useful to
737 * avoid setting the "worst case" in max_width/max_height.
738 *
739 * ***HIGHLY RECOMMENDED*** Do not call this callback every time
740 * resolution changes in an emulator core if it's
741 * expected to be a temporary change, for the reasons of possible
742 * driver reinitialization.
743 * This call is not a free pass for not trying to provide
744 * correct values in retro_get_system_av_info(). If you need to change
745 * things like aspect ratio or nominal width/height,
746 * use RETRO_ENVIRONMENT_SET_GEOMETRY, which is a softer variant
747 * of SET_SYSTEM_AV_INFO.
748 *
749 * If this returns false, the frontend does not acknowledge a
750 * changed av_info struct.
751 */
752 #define RETRO_ENVIRONMENT_SET_PROC_ADDRESS_CALLBACK 33
753 /* const struct retro_get_proc_address_interface * --
754 * Allows a libretro core to announce support for the
755 * get_proc_address() interface.
756 * This interface allows for a standard way to extend libretro where
757 * use of environment calls are too indirect,
758 * e.g. for cases where the frontend wants to call directly into the core.
759 *
760 * If a core wants to expose this interface, SET_PROC_ADDRESS_CALLBACK
761 * **MUST** be called from within retro_set_environment().
762 */
763 #define RETRO_ENVIRONMENT_SET_SUBSYSTEM_INFO 34
764 /* const struct retro_subsystem_info * --
765 * This environment call introduces the concept of libretro "subsystems".
766 * A subsystem is a variant of a libretro core which supports
767 * different kinds of games.
768 * The purpose of this is to support e.g. emulators which might
769 * have special needs, e.g. Super Nintendo's Super GameBoy, Sufami Turbo.
770 * It can also be used to pick among subsystems in an explicit way
771 * if the libretro implementation is a multi-system emulator itself.
772 *
773 * Loading a game via a subsystem is done with retro_load_game_special(),
774 * and this environment call allows a libretro core to expose which
775 * subsystems are supported for use with retro_load_game_special().
776 * A core passes an array of retro_game_special_info which is terminated
777 * with a zeroed out retro_game_special_info struct.
778 *
779 * If a core wants to use this functionality, SET_SUBSYSTEM_INFO
780 * **MUST** be called from within retro_set_environment().
781 */
782 #define RETRO_ENVIRONMENT_SET_CONTROLLER_INFO 35
783 /* const struct retro_controller_info * --
784 * This environment call lets a libretro core tell the frontend
785 * which controller types are recognized in calls to
786 * retro_set_controller_port_device().
787 *
788 * Some emulators such as Super Nintendo
789 * support multiple lightgun types which must be specifically
790 * selected from.
791 * It is therefore sometimes necessary for a frontend to be able
792 * to tell the core about a special kind of input device which is
793 * not covered by the libretro input API.
794 *
795 * In order for a frontend to understand the workings of an input device,
796 * it must be a specialized type
797 * of the generic device types already defined in the libretro API.
798 *
799 * Which devices are supported can vary per input port.
800 * The core must pass an array of const struct retro_controller_info which
801 * is terminated with a blanked out struct. Each element of the struct
802 * corresponds to an ascending port index to
803 * retro_set_controller_port_device().
804 * Even if special device types are set in the libretro core,
805 * libretro should only poll input based on the base input device types.
806 */
807 #define RETRO_ENVIRONMENT_SET_MEMORY_MAPS (36 | RETRO_ENVIRONMENT_EXPERIMENTAL)
808 /* const struct retro_memory_map * --
809 * This environment call lets a libretro core tell the frontend
810 * about the memory maps this core emulates.
811 * This can be used to implement, for example, cheats in a core-agnostic way.
812 *
813 * Should only be used by emulators; it doesn't make much sense for
814 * anything else.
815 * It is recommended to expose all relevant pointers through
816 * retro_get_memory_* as well.
817 *
818 * Can be called from retro_init and retro_load_game.
819 */
820 #define RETRO_ENVIRONMENT_SET_GEOMETRY 37
821 /* const struct retro_game_geometry * --
822 * This environment call is similar to SET_SYSTEM_AV_INFO for changing
823 * video parameters, but provides a guarantee that drivers will not be
824 * reinitialized.
825 * This can only be called from within retro_run().
826 *
827 * The purpose of this call is to allow a core to alter nominal
828 * width/heights as well as aspect ratios on-the-fly, which can be
829 * useful for some emulators to change in run-time.
830 *
831 * max_width/max_height arguments are ignored and cannot be changed
832 * with this call as this could potentially require a reinitialization or a
833 * non-constant time operation.
834 * If max_width/max_height are to be changed, SET_SYSTEM_AV_INFO is required.
835 *
836 * A frontend must guarantee that this environment call completes in
837 * constant time.
838 */
839 #define RETRO_ENVIRONMENT_GET_USERNAME 38
840 /* const char **
841 * Returns the specified username of the frontend, if specified by the user.
842 * This username can be used as a nickname for a core that has online facilities
843 * or any other mode where personalization of the user is desirable.
844 * The returned value can be NULL.
845 * If this environ callback is used by a core that requires a valid username,
846 * a default username should be specified by the core.
847 */
848 #define RETRO_ENVIRONMENT_GET_LANGUAGE 39
849 /* unsigned * --
850 * Returns the specified language of the frontend, if specified by the user.
851 * It can be used by the core for localization purposes.
852 */
853
854 #define RETRO_MEMDESC_CONST (1 << 0) /* The frontend will never change this memory area once retro_load_game has returned. */
855 #define RETRO_MEMDESC_BIGENDIAN (1 << 1) /* The memory area contains big endian data. Default is little endian. */
856 #define RETRO_MEMDESC_ALIGN_2 (1 << 16) /* All memory access in this area is aligned to their own size, or 2, whichever is smaller. */
857 #define RETRO_MEMDESC_ALIGN_4 (2 << 16)
858 #define RETRO_MEMDESC_ALIGN_8 (3 << 16)
859 #define RETRO_MEMDESC_MINSIZE_2 (1 << 24) /* All memory in this region is accessed at least 2 bytes at the time. */
860 #define RETRO_MEMDESC_MINSIZE_4 (2 << 24)
861 #define RETRO_MEMDESC_MINSIZE_8 (3 << 24)
862 struct retro_memory_descriptor
863 {
864 uint64_t flags;
865
866 /* Pointer to the start of the relevant ROM or RAM chip.
867 * It's strongly recommended to use 'offset' if possible, rather than
868 * doing math on the pointer.
869 *
870 * If the same byte is mapped my multiple descriptors, their descriptors
871 * must have the same pointer.
872 * If 'start' does not point to the first byte in the pointer, put the
873 * difference in 'offset' instead.
874 *
875 * May be NULL if there's nothing usable here (e.g. hardware registers and
876 * open bus). No flags should be set if the pointer is NULL.
877 * It's recommended to minimize the number of descriptors if possible,
878 * but not mandatory. */
879 void *ptr;
880 size_t offset;
881
882 /* This is the location in the emulated address space
883 * where the mapping starts. */
884 size_t start;
885
886 /* Which bits must be same as in 'start' for this mapping to apply.
887 * The first memory descriptor to claim a certain byte is the one
888 * that applies.
889 * A bit which is set in 'start' must also be set in this.
890 * Can be zero, in which case each byte is assumed mapped exactly once.
891 * In this case, 'len' must be a power of two. */
892 size_t select;
893
894 /* If this is nonzero, the set bits are assumed not connected to the
895 * memory chip's address pins. */
896 size_t disconnect;
897
898 /* This one tells the size of the current memory area.
899 * If, after start+disconnect are applied, the address is higher than
900 * this, the highest bit of the address is cleared.
901 *
902 * If the address is still too high, the next highest bit is cleared.
903 * Can be zero, in which case it's assumed to be infinite (as limited
904 * by 'select' and 'disconnect'). */
905 size_t len;
906
907 /* To go from emulated address to physical address, the following
908 * order applies:
909 * Subtract 'start', pick off 'disconnect', apply 'len', add 'offset'.
910 *
911 * The address space name must consist of only a-zA-Z0-9_-,
912 * should be as short as feasible (maximum length is 8 plus the NUL),
913 * and may not be any other address space plus one or more 0-9A-F
914 * at the end.
915 * However, multiple memory descriptors for the same address space is
916 * allowed, and the address space name can be empty. NULL is treated
917 * as empty.
918 *
919 * Address space names are case sensitive, but avoid lowercase if possible.
920 * The same pointer may exist in multiple address spaces.
921 *
922 * Examples:
923 * blank+blank - valid (multiple things may be mapped in the same namespace)
924 * 'Sp'+'Sp' - valid (multiple things may be mapped in the same namespace)
925 * 'A'+'B' - valid (neither is a prefix of each other)
926 * 'S'+blank - valid ('S' is not in 0-9A-F)
927 * 'a'+blank - valid ('a' is not in 0-9A-F)
928 * 'a'+'A' - valid (neither is a prefix of each other)
929 * 'AR'+blank - valid ('R' is not in 0-9A-F)
930 * 'ARB'+blank - valid (the B can't be part of the address either, because
931 * there is no namespace 'AR')
932 * blank+'B' - not valid, because it's ambigous which address space B1234
933 * would refer to.
934 * The length can't be used for that purpose; the frontend may want
935 * to append arbitrary data to an address, without a separator. */
936 const char *addrspace;
937 };
938
939 /* The frontend may use the largest value of 'start'+'select' in a
940 * certain namespace to infer the size of the address space.
941 *
942 * If the address space is larger than that, a mapping with .ptr=NULL
943 * should be at the end of the array, with .select set to all ones for
944 * as long as the address space is big.
945 *
946 * Sample descriptors (minus .ptr, and RETRO_MEMFLAG_ on the flags):
947 * SNES WRAM:
948 * .start=0x7E0000, .len=0x20000
949 * (Note that this must be mapped before the ROM in most cases; some of the
950 * ROM mappers
951 * try to claim $7E0000, or at least $7E8000.)
952 * SNES SPC700 RAM:
953 * .addrspace="S", .len=0x10000
954 * SNES WRAM mirrors:
955 * .flags=MIRROR, .start=0x000000, .select=0xC0E000, .len=0x2000
956 * .flags=MIRROR, .start=0x800000, .select=0xC0E000, .len=0x2000
957 * SNES WRAM mirrors, alternate equivalent descriptor:
958 * .flags=MIRROR, .select=0x40E000, .disconnect=~0x1FFF
959 * (Various similar constructions can be created by combining parts of
960 * the above two.)
961 * SNES LoROM (512KB, mirrored a couple of times):
962 * .flags=CONST, .start=0x008000, .select=0x408000, .disconnect=0x8000, .len=512*1024
963 * .flags=CONST, .start=0x400000, .select=0x400000, .disconnect=0x8000, .len=512*1024
964 * SNES HiROM (4MB):
965 * .flags=CONST, .start=0x400000, .select=0x400000, .len=4*1024*1024
966 * .flags=CONST, .offset=0x8000, .start=0x008000, .select=0x408000, .len=4*1024*1024
967 * SNES ExHiROM (8MB):
968 * .flags=CONST, .offset=0, .start=0xC00000, .select=0xC00000, .len=4*1024*1024
969 * .flags=CONST, .offset=4*1024*1024, .start=0x400000, .select=0xC00000, .len=4*1024*1024
970 * .flags=CONST, .offset=0x8000, .start=0x808000, .select=0xC08000, .len=4*1024*1024
971 * .flags=CONST, .offset=4*1024*1024+0x8000, .start=0x008000, .select=0xC08000, .len=4*1024*1024
972 * Clarify the size of the address space:
973 * .ptr=NULL, .select=0xFFFFFF
974 * .len can be implied by .select in many of them, but was included for clarity.
975 */
976
977 struct retro_memory_map
978 {
979 const struct retro_memory_descriptor *descriptors;
980 unsigned num_descriptors;
981 };
982
983 struct retro_controller_description
984 {
985 /* Human-readable description of the controller. Even if using a generic
986 * input device type, this can be set to the particular device type the
987 * core uses. */
988 const char *desc;
989
990 /* Device type passed to retro_set_controller_port_device(). If the device
991 * type is a sub-class of a generic input device type, use the
992 * RETRO_DEVICE_SUBCLASS macro to create an ID.
993 *
994 * E.g. RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 1). */
995 unsigned id;
996 };
997
998 struct retro_controller_info
999 {
1000 const struct retro_controller_description *types;
1001 unsigned num_types;
1002 };
1003
1004 struct retro_subsystem_memory_info
1005 {
1006 /* The extension associated with a memory type, e.g. "psram". */
1007 const char *extension;
1008
1009 /* The memory type for retro_get_memory(). This should be at
1010 * least 0x100 to avoid conflict with standardized
1011 * libretro memory types. */
1012 unsigned type;
1013 };
1014
1015 struct retro_subsystem_rom_info
1016 {
1017 /* Describes what the content is (SGB BIOS, GB ROM, etc). */
1018 const char *desc;
1019
1020 /* Same definition as retro_get_system_info(). */
1021 const char *valid_extensions;
1022
1023 /* Same definition as retro_get_system_info(). */
1024 bool need_fullpath;
1025
1026 /* Same definition as retro_get_system_info(). */
1027 bool block_extract;
1028
1029 /* This is set if the content is required to load a game.
1030 * If this is set to false, a zeroed-out retro_game_info can be passed. */
1031 bool required;
1032
1033 /* Content can have multiple associated persistent
1034 * memory types (retro_get_memory()). */
1035 const struct retro_subsystem_memory_info *memory;
1036 unsigned num_memory;
1037 };
1038
1039 struct retro_subsystem_info
1040 {
1041 /* Human-readable string of the subsystem type, e.g. "Super GameBoy" */
1042 const char *desc;
1043
1044 /* A computer friendly short string identifier for the subsystem type.
1045 * This name must be [a-z].
1046 * E.g. if desc is "Super GameBoy", this can be "sgb".
1047 * This identifier can be used for command-line interfaces, etc.
1048 */
1049 const char *ident;
1050
1051 /* Infos for each content file. The first entry is assumed to be the
1052 * "most significant" content for frontend purposes.
1053 * E.g. with Super GameBoy, the first content should be the GameBoy ROM,
1054 * as it is the most "significant" content to a user.
1055 * If a frontend creates new file paths based on the content used
1056 * (e.g. savestates), it should use the path for the first ROM to do so. */
1057 const struct retro_subsystem_rom_info *roms;
1058
1059 /* Number of content files associated with a subsystem. */
1060 unsigned num_roms;
1061
1062 /* The type passed to retro_load_game_special(). */
1063 unsigned id;
1064 };
1065
1066 typedef void (*retro_proc_address_t)(void);
1067
1068 /* libretro API extension functions:
1069 * (None here so far).
1070 *
1071 * Get a symbol from a libretro core.
1072 * Cores should only return symbols which are actual
1073 * extensions to the libretro API.
1074 *
1075 * Frontends should not use this to obtain symbols to standard
1076 * libretro entry points (static linking or dlsym).
1077 *
1078 * The symbol name must be equal to the function name,
1079 * e.g. if void retro_foo(void); exists, the symbol must be called "retro_foo".
1080 * The returned function pointer must be cast to the corresponding type.
1081 */
1082 typedef retro_proc_address_t (*retro_get_proc_address_t)(const char *sym);
1083
1084 struct retro_get_proc_address_interface
1085 {
1086 retro_get_proc_address_t get_proc_address;
1087 };
1088
1089 enum retro_log_level
1090 {
1091 RETRO_LOG_DEBUG = 0,
1092 RETRO_LOG_INFO,
1093 RETRO_LOG_WARN,
1094 RETRO_LOG_ERROR,
1095
1096 RETRO_LOG_DUMMY = INT_MAX
1097 };
1098
1099 /* Logging function. Takes log level argument as well. */
1100 typedef void (*retro_log_printf_t)(enum retro_log_level level,
1101 const char *fmt, ...);
1102
1103 struct retro_log_callback
1104 {
1105 retro_log_printf_t log;
1106 };
1107
1108 /* Performance related functions */
1109
1110 /* ID values for SIMD CPU features */
1111 #define RETRO_SIMD_SSE (1 << 0)
1112 #define RETRO_SIMD_SSE2 (1 << 1)
1113 #define RETRO_SIMD_VMX (1 << 2)
1114 #define RETRO_SIMD_VMX128 (1 << 3)
1115 #define RETRO_SIMD_AVX (1 << 4)
1116 #define RETRO_SIMD_NEON (1 << 5)
1117 #define RETRO_SIMD_SSE3 (1 << 6)
1118 #define RETRO_SIMD_SSSE3 (1 << 7)
1119 #define RETRO_SIMD_MMX (1 << 8)
1120 #define RETRO_SIMD_MMXEXT (1 << 9)
1121 #define RETRO_SIMD_SSE4 (1 << 10)
1122 #define RETRO_SIMD_SSE42 (1 << 11)
1123 #define RETRO_SIMD_AVX2 (1 << 12)
1124 #define RETRO_SIMD_VFPU (1 << 13)
1125 #define RETRO_SIMD_PS (1 << 14)
1126 #define RETRO_SIMD_AES (1 << 15)
1127
1128 typedef uint64_t retro_perf_tick_t;
1129 typedef int64_t retro_time_t;
1130
1131 struct retro_perf_counter
1132 {
1133 const char *ident;
1134 retro_perf_tick_t start;
1135 retro_perf_tick_t total;
1136 retro_perf_tick_t call_cnt;
1137
1138 bool registered;
1139 };
1140
1141 /* Returns current time in microseconds.
1142 * Tries to use the most accurate timer available.
1143 */
1144 typedef retro_time_t (*retro_perf_get_time_usec_t)(void);
1145
1146 /* A simple counter. Usually nanoseconds, but can also be CPU cycles.
1147 * Can be used directly if desired (when creating a more sophisticated
1148 * performance counter system).
1149 * */
1150 typedef retro_perf_tick_t (*retro_perf_get_counter_t)(void);
1151
1152 /* Returns a bit-mask of detected CPU features (RETRO_SIMD_*). */
1153 typedef uint64_t (*retro_get_cpu_features_t)(void);
1154
1155 /* Asks frontend to log and/or display the state of performance counters.
1156 * Performance counters can always be poked into manually as well.
1157 */
1158 typedef void (*retro_perf_log_t)(void);
1159
1160 /* Register a performance counter.
1161 * ident field must be set with a discrete value and other values in
1162 * retro_perf_counter must be 0.
1163 * Registering can be called multiple times. To avoid calling to
1164 * frontend redundantly, you can check registered field first. */
1165 typedef void (*retro_perf_register_t)(struct retro_perf_counter *counter);
1166
1167 /* Starts a registered counter. */
1168 typedef void (*retro_perf_start_t)(struct retro_perf_counter *counter);
1169
1170 /* Stops a registered counter. */
1171 typedef void (*retro_perf_stop_t)(struct retro_perf_counter *counter);
1172
1173 /* For convenience it can be useful to wrap register, start and stop in macros.
1174 * E.g.:
1175 * #ifdef LOG_PERFORMANCE
1176 * #define RETRO_PERFORMANCE_INIT(perf_cb, name) static struct retro_perf_counter name = {#name}; if (!name.registered) perf_cb.perf_register(&(name))
1177 * #define RETRO_PERFORMANCE_START(perf_cb, name) perf_cb.perf_start(&(name))
1178 * #define RETRO_PERFORMANCE_STOP(perf_cb, name) perf_cb.perf_stop(&(name))
1179 * #else
1180 * ... Blank macros ...
1181 * #endif
1182 *
1183 * These can then be used mid-functions around code snippets.
1184 *
1185 * extern struct retro_perf_callback perf_cb; * Somewhere in the core.
1186 *
1187 * void do_some_heavy_work(void)
1188 * {
1189 * RETRO_PERFORMANCE_INIT(cb, work_1;
1190 * RETRO_PERFORMANCE_START(cb, work_1);
1191 * heavy_work_1();
1192 * RETRO_PERFORMANCE_STOP(cb, work_1);
1193 *
1194 * RETRO_PERFORMANCE_INIT(cb, work_2);
1195 * RETRO_PERFORMANCE_START(cb, work_2);
1196 * heavy_work_2();
1197 * RETRO_PERFORMANCE_STOP(cb, work_2);
1198 * }
1199 *
1200 * void retro_deinit(void)
1201 * {
1202 * perf_cb.perf_log(); * Log all perf counters here for example.
1203 * }
1204 */
1205
1206 struct retro_perf_callback
1207 {
1208 retro_perf_get_time_usec_t get_time_usec;
1209 retro_get_cpu_features_t get_cpu_features;
1210
1211 retro_perf_get_counter_t get_perf_counter;
1212 retro_perf_register_t perf_register;
1213 retro_perf_start_t perf_start;
1214 retro_perf_stop_t perf_stop;
1215 retro_perf_log_t perf_log;
1216 };
1217
1218 /* FIXME: Document the sensor API and work out behavior.
1219 * It will be marked as experimental until then.
1220 */
1221 enum retro_sensor_action
1222 {
1223 RETRO_SENSOR_ACCELEROMETER_ENABLE = 0,
1224 RETRO_SENSOR_ACCELEROMETER_DISABLE,
1225
1226 RETRO_SENSOR_DUMMY = INT_MAX
1227 };
1228
1229 /* Id values for SENSOR types. */
1230 #define RETRO_SENSOR_ACCELEROMETER_X 0
1231 #define RETRO_SENSOR_ACCELEROMETER_Y 1
1232 #define RETRO_SENSOR_ACCELEROMETER_Z 2
1233
1234 typedef bool (*retro_set_sensor_state_t)(unsigned port,
1235 enum retro_sensor_action action, unsigned rate);
1236
1237 typedef float (*retro_sensor_get_input_t)(unsigned port, unsigned id);
1238
1239 struct retro_sensor_interface
1240 {
1241 retro_set_sensor_state_t set_sensor_state;
1242 retro_sensor_get_input_t get_sensor_input;
1243 };
1244
1245 enum retro_camera_buffer
1246 {
1247 RETRO_CAMERA_BUFFER_OPENGL_TEXTURE = 0,
1248 RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER,
1249
1250 RETRO_CAMERA_BUFFER_DUMMY = INT_MAX
1251 };
1252
1253 /* Starts the camera driver. Can only be called in retro_run(). */
1254 typedef bool (*retro_camera_start_t)(void);
1255
1256 /* Stops the camera driver. Can only be called in retro_run(). */
1257 typedef void (*retro_camera_stop_t)(void);
1258
1259 /* Callback which signals when the camera driver is initialized
1260 * and/or deinitialized.
1261 * retro_camera_start_t can be called in initialized callback.
1262 */
1263 typedef void (*retro_camera_lifetime_status_t)(void);
1264
1265 /* A callback for raw framebuffer data. buffer points to an XRGB8888 buffer.
1266 * Width, height and pitch are similar to retro_video_refresh_t.
1267 * First pixel is top-left origin.
1268 */
1269 typedef void (*retro_camera_frame_raw_framebuffer_t)(const uint32_t *buffer,
1270 unsigned width, unsigned height, size_t pitch);
1271
1272 /* A callback for when OpenGL textures are used.
1273 *
1274 * texture_id is a texture owned by camera driver.
1275 * Its state or content should be considered immutable, except for things like
1276 * texture filtering and clamping.
1277 *
1278 * texture_target is the texture target for the GL texture.
1279 * These can include e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE, and possibly
1280 * more depending on extensions.
1281 *
1282 * affine points to a packed 3x3 column-major matrix used to apply an affine
1283 * transform to texture coordinates. (affine_matrix * vec3(coord_x, coord_y, 1.0))
1284 * After transform, normalized texture coord (0, 0) should be bottom-left
1285 * and (1, 1) should be top-right (or (width, height) for RECTANGLE).
1286 *
1287 * GL-specific typedefs are avoided here to avoid relying on gl.h in
1288 * the API definition.
1289 */
1290 typedef void (*retro_camera_frame_opengl_texture_t)(unsigned texture_id,
1291 unsigned texture_target, const float *affine);
1292
1293 struct retro_camera_callback
1294 {
1295 /* Set by libretro core.
1296 * Example bitmask: caps = (1 << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE) | (1 << RETRO_CAMERA_BUFFER_RAW_FRAMEBUFFER).
1297 */
1298 uint64_t caps;
1299
1300 unsigned width; /* Desired resolution for camera. Is only used as a hint. */
1301 unsigned height;
1302 retro_camera_start_t start; /* Set by frontend. */
1303 retro_camera_stop_t stop; /* Set by frontend. */
1304
1305 /* Set by libretro core if raw framebuffer callbacks will be used. */
1306 retro_camera_frame_raw_framebuffer_t frame_raw_framebuffer;
1307 /* Set by libretro core if OpenGL texture callbacks will be used. */
1308 retro_camera_frame_opengl_texture_t frame_opengl_texture;
1309
1310 /* Set by libretro core. Called after camera driver is initialized and
1311 * ready to be started.
1312 * Can be NULL, in which this callback is not called.
1313 */
1314 retro_camera_lifetime_status_t initialized;
1315
1316 /* Set by libretro core. Called right before camera driver is
1317 * deinitialized.
1318 * Can be NULL, in which this callback is not called.
1319 */
1320 retro_camera_lifetime_status_t deinitialized;
1321 };
1322
1323 /* Sets the interval of time and/or distance at which to update/poll
1324 * location-based data.
1325 *
1326 * To ensure compatibility with all location-based implementations,
1327 * values for both interval_ms and interval_distance should be provided.
1328 *
1329 * interval_ms is the interval expressed in milliseconds.
1330 * interval_distance is the distance interval expressed in meters.
1331 */
1332 typedef void (*retro_location_set_interval_t)(unsigned interval_ms,
1333 unsigned interval_distance);
1334
1335 /* Start location services. The device will start listening for changes to the
1336 * current location at regular intervals (which are defined with
1337 * retro_location_set_interval_t). */
1338 typedef bool (*retro_location_start_t)(void);
1339
1340 /* Stop location services. The device will stop listening for changes
1341 * to the current location. */
1342 typedef void (*retro_location_stop_t)(void);
1343
1344 /* Get the position of the current location. Will set parameters to
1345 * 0 if no new location update has happened since the last time. */
1346 typedef bool (*retro_location_get_position_t)(double *lat, double *lon,
1347 double *horiz_accuracy, double *vert_accuracy);
1348
1349 /* Callback which signals when the location driver is initialized
1350 * and/or deinitialized.
1351 * retro_location_start_t can be called in initialized callback.
1352 */
1353 typedef void (*retro_location_lifetime_status_t)(void);
1354
1355 struct retro_location_callback
1356 {
1357 retro_location_start_t start;
1358 retro_location_stop_t stop;
1359 retro_location_get_position_t get_position;
1360 retro_location_set_interval_t set_interval;
1361
1362 retro_location_lifetime_status_t initialized;
1363 retro_location_lifetime_status_t deinitialized;
1364 };
1365
1366 enum retro_rumble_effect
1367 {
1368 RETRO_RUMBLE_STRONG = 0,
1369 RETRO_RUMBLE_WEAK = 1,
1370
1371 RETRO_RUMBLE_DUMMY = INT_MAX
1372 };
1373
1374 /* Sets rumble state for joypad plugged in port 'port'.
1375 * Rumble effects are controlled independently,
1376 * and setting e.g. strong rumble does not override weak rumble.
1377 * Strength has a range of [0, 0xffff].
1378 *
1379 * Returns true if rumble state request was honored.
1380 * Calling this before first retro_run() is likely to return false. */
1381 typedef bool (*retro_set_rumble_state_t)(unsigned port,
1382 enum retro_rumble_effect effect, uint16_t strength);
1383
1384 struct retro_rumble_interface
1385 {
1386 retro_set_rumble_state_t set_rumble_state;
1387 };
1388
1389 /* Notifies libretro that audio data should be written. */
1390 typedef void (*retro_audio_callback_t)(void);
1391
1392 /* True: Audio driver in frontend is active, and callback is
1393 * expected to be called regularily.
1394 * False: Audio driver in frontend is paused or inactive.
1395 * Audio callback will not be called until set_state has been
1396 * called with true.
1397 * Initial state is false (inactive).
1398 */
1399 typedef void (*retro_audio_set_state_callback_t)(bool enabled);
1400
1401 struct retro_audio_callback
1402 {
1403 retro_audio_callback_t callback;
1404 retro_audio_set_state_callback_t set_state;
1405 };
1406
1407 /* Notifies a libretro core of time spent since last invocation
1408 * of retro_run() in microseconds.
1409 *
1410 * It will be called right before retro_run() every frame.
1411 * The frontend can tamper with timing to support cases like
1412 * fast-forward, slow-motion and framestepping.
1413 *
1414 * In those scenarios the reference frame time value will be used. */
1415 typedef int64_t retro_usec_t;
1416 typedef void (*retro_frame_time_callback_t)(retro_usec_t usec);
1417 struct retro_frame_time_callback
1418 {
1419 retro_frame_time_callback_t callback;
1420 /* Represents the time of one frame. It is computed as
1421 * 1000000 / fps, but the implementation will resolve the
1422 * rounding to ensure that framestepping, etc is exact. */
1423 retro_usec_t reference;
1424 };
1425
1426 /* Pass this to retro_video_refresh_t if rendering to hardware.
1427 * Passing NULL to retro_video_refresh_t is still a frame dupe as normal.
1428 * */
1429 #define RETRO_HW_FRAME_BUFFER_VALID ((void*)-1)
1430
1431 /* Invalidates the current HW context.
1432 * Any GL state is lost, and must not be deinitialized explicitly.
1433 * If explicit deinitialization is desired by the libretro core,
1434 * it should implement context_destroy callback.
1435 * If called, all GPU resources must be reinitialized.
1436 * Usually called when frontend reinits video driver.
1437 * Also called first time video driver is initialized,
1438 * allowing libretro core to initialize resources.
1439 */
1440 typedef void (*retro_hw_context_reset_t)(void);
1441
1442 /* Gets current framebuffer which is to be rendered to.
1443 * Could change every frame potentially.
1444 */
1445 typedef uintptr_t (*retro_hw_get_current_framebuffer_t)(void);
1446
1447 /* Get a symbol from HW context. */
1448 typedef retro_proc_address_t (*retro_hw_get_proc_address_t)(const char *sym);
1449
1450 enum retro_hw_context_type
1451 {
1452 RETRO_HW_CONTEXT_NONE = 0,
1453 /* OpenGL 2.x. Driver can choose to use latest compatibility context. */
1454 RETRO_HW_CONTEXT_OPENGL = 1,
1455 /* OpenGL ES 2.0. */
1456 RETRO_HW_CONTEXT_OPENGLES2 = 2,
1457 /* Modern desktop core GL context. Use version_major/
1458 * version_minor fields to set GL version. */
1459 RETRO_HW_CONTEXT_OPENGL_CORE = 3,
1460 /* OpenGL ES 3.0 */
1461 RETRO_HW_CONTEXT_OPENGLES3 = 4,
1462 /* OpenGL ES 3.1+. Set version_major/version_minor. For GLES2 and GLES3,
1463 * use the corresponding enums directly. */
1464 RETRO_HW_CONTEXT_OPENGLES_VERSION = 5,
1465
1466 RETRO_HW_CONTEXT_DUMMY = INT_MAX
1467 };
1468
1469 struct retro_hw_render_callback
1470 {
1471 /* Which API to use. Set by libretro core. */
1472 enum retro_hw_context_type context_type;
1473
1474 /* Called when a context has been created or when it has been reset.
1475 * An OpenGL context is only valid after context_reset() has been called.
1476 *
1477 * When context_reset is called, OpenGL resources in the libretro
1478 * implementation are guaranteed to be invalid.
1479 *
1480 * It is possible that context_reset is called multiple times during an
1481 * application lifecycle.
1482 * If context_reset is called without any notification (context_destroy),
1483 * the OpenGL context was lost and resources should just be recreated
1484 * without any attempt to "free" old resources.
1485 */
1486 retro_hw_context_reset_t context_reset;
1487
1488 /* Set by frontend. */
1489 retro_hw_get_current_framebuffer_t get_current_framebuffer;
1490
1491 /* Set by frontend. */
1492 retro_hw_get_proc_address_t get_proc_address;
1493
1494 /* Set if render buffers should have depth component attached. */
1495 bool depth;
1496
1497 /* Set if stencil buffers should be attached. */
1498 bool stencil;
1499
1500 /* If depth and stencil are true, a packed 24/8 buffer will be added.
1501 * Only attaching stencil is invalid and will be ignored. */
1502
1503 /* Use conventional bottom-left origin convention. If false,
1504 * standard libretro top-left origin semantics are used. */
1505 bool bottom_left_origin;
1506
1507 /* Major version number for core GL context or GLES 3.1+. */
1508 unsigned version_major;
1509
1510 /* Minor version number for core GL context or GLES 3.1+. */
1511 unsigned version_minor;
1512
1513 /* If this is true, the frontend will go very far to avoid
1514 * resetting context in scenarios like toggling fullscreen, etc.
1515 */
1516 bool cache_context;
1517
1518 /* The reset callback might still be called in extreme situations
1519 * such as if the context is lost beyond recovery.
1520 *
1521 * For optimal stability, set this to false, and allow context to be
1522 * reset at any time.
1523 */
1524
1525 /* A callback to be called before the context is destroyed in a
1526 * controlled way by the frontend. */
1527 retro_hw_context_reset_t context_destroy;
1528
1529 /* OpenGL resources can be deinitialized cleanly at this step.
1530 * context_destroy can be set to NULL, in which resources will
1531 * just be destroyed without any notification.
1532 *
1533 * Even when context_destroy is non-NULL, it is possible that
1534 * context_reset is called without any destroy notification.
1535 * This happens if context is lost by external factors (such as
1536 * notified by GL_ARB_robustness).
1537 *
1538 * In this case, the context is assumed to be already dead,
1539 * and the libretro implementation must not try to free any OpenGL
1540 * resources in the subsequent context_reset.
1541 */
1542
1543 /* Creates a debug context. */
1544 bool debug_context;
1545 };
1546
1547 /* Callback type passed in RETRO_ENVIRONMENT_SET_KEYBOARD_CALLBACK.
1548 * Called by the frontend in response to keyboard events.
1549 * down is set if the key is being pressed, or false if it is being released.
1550 * keycode is the RETROK value of the char.
1551 * character is the text character of the pressed key. (UTF-32).
1552 * key_modifiers is a set of RETROKMOD values or'ed together.
1553 *
1554 * The pressed/keycode state can be indepedent of the character.
1555 * It is also possible that multiple characters are generated from a
1556 * single keypress.
1557 * Keycode events should be treated separately from character events.
1558 * However, when possible, the frontend should try to synchronize these.
1559 * If only a character is posted, keycode should be RETROK_UNKNOWN.
1560 *
1561 * Similarily if only a keycode event is generated with no corresponding
1562 * character, character should be 0.
1563 */
1564 typedef void (*retro_keyboard_event_t)(bool down, unsigned keycode,
1565 uint32_t character, uint16_t key_modifiers);
1566
1567 struct retro_keyboard_callback
1568 {
1569 retro_keyboard_event_t callback;
1570 };
1571
1572 /* Callbacks for RETRO_ENVIRONMENT_SET_DISK_CONTROL_INTERFACE.
1573 * Should be set for implementations which can swap out multiple disk
1574 * images in runtime.
1575 *
1576 * If the implementation can do this automatically, it should strive to do so.
1577 * However, there are cases where the user must manually do so.
1578 *
1579 * Overview: To swap a disk image, eject the disk image with
1580 * set_eject_state(true).
1581 * Set the disk index with set_image_index(index). Insert the disk again
1582 * with set_eject_state(false).
1583 */
1584
1585 /* If ejected is true, "ejects" the virtual disk tray.
1586 * When ejected, the disk image index can be set.
1587 */
1588 typedef bool (*retro_set_eject_state_t)(bool ejected);
1589
1590 /* Gets current eject state. The initial state is 'not ejected'. */
1591 typedef bool (*retro_get_eject_state_t)(void);
1592
1593 /* Gets current disk index. First disk is index 0.
1594 * If return value is >= get_num_images(), no disk is currently inserted.
1595 */
1596 typedef unsigned (*retro_get_image_index_t)(void);
1597
1598 /* Sets image index. Can only be called when disk is ejected.
1599 * The implementation supports setting "no disk" by using an
1600 * index >= get_num_images().
1601 */
1602 typedef bool (*retro_set_image_index_t)(unsigned index);
1603
1604 /* Gets total number of images which are available to use. */
1605 typedef unsigned (*retro_get_num_images_t)(void);
1606
1607 struct retro_game_info;
1608
1609 /* Replaces the disk image associated with index.
1610 * Arguments to pass in info have same requirements as retro_load_game().
1611 * Virtual disk tray must be ejected when calling this.
1612 *
1613 * Replacing a disk image with info = NULL will remove the disk image
1614 * from the internal list.
1615 * As a result, calls to get_image_index() can change.
1616 *
1617 * E.g. replace_image_index(1, NULL), and previous get_image_index()
1618 * returned 4 before.
1619 * Index 1 will be removed, and the new index is 3.
1620 */
1621 typedef bool (*retro_replace_image_index_t)(unsigned index,
1622 const struct retro_game_info *info);
1623
1624 /* Adds a new valid index (get_num_images()) to the internal disk list.
1625 * This will increment subsequent return values from get_num_images() by 1.
1626 * This image index cannot be used until a disk image has been set
1627 * with replace_image_index. */
1628 typedef bool (*retro_add_image_index_t)(void);
1629
1630 struct retro_disk_control_callback
1631 {
1632 retro_set_eject_state_t set_eject_state;
1633 retro_get_eject_state_t get_eject_state;
1634
1635 retro_get_image_index_t get_image_index;
1636 retro_set_image_index_t set_image_index;
1637 retro_get_num_images_t get_num_images;
1638
1639 retro_replace_image_index_t replace_image_index;
1640 retro_add_image_index_t add_image_index;
1641 };
1642
1643 enum retro_pixel_format
1644 {
1645 /* 0RGB1555, native endian.
1646 * 0 bit must be set to 0.
1647 * This pixel format is default for compatibility concerns only.
1648 * If a 15/16-bit pixel format is desired, consider using RGB565. */
1649 RETRO_PIXEL_FORMAT_0RGB1555 = 0,
1650
1651 /* XRGB8888, native endian.
1652 * X bits are ignored. */
1653 RETRO_PIXEL_FORMAT_XRGB8888 = 1,
1654
1655 /* RGB565, native endian.
1656 * This pixel format is the recommended format to use if a 15/16-bit
1657 * format is desired as it is the pixel format that is typically
1658 * available on a wide range of low-power devices.
1659 *
1660 * It is also natively supported in APIs like OpenGL ES. */
1661 RETRO_PIXEL_FORMAT_RGB565 = 2,
1662
1663 /* Ensure sizeof() == sizeof(int). */
1664 RETRO_PIXEL_FORMAT_UNKNOWN = INT_MAX
1665 };
1666
1667 struct retro_message
1668 {
1669 const char *msg; /* Message to be displayed. */
1670 unsigned frames; /* Duration in frames of message. */
1671 };
1672
1673 /* Describes how the libretro implementation maps a libretro input bind
1674 * to its internal input system through a human readable string.
1675 * This string can be used to better let a user configure input. */
1676 struct retro_input_descriptor
1677 {
1678 /* Associates given parameters with a description. */
1679 unsigned port;
1680 unsigned device;
1681 unsigned index;
1682 unsigned id;
1683
1684 /* Human readable description for parameters.
1685 * The pointer must remain valid until
1686 * retro_unload_game() is called. */
1687 const char *description;
1688 };
1689
1690 struct retro_system_info
1691 {
1692 /* All pointers are owned by libretro implementation, and pointers must
1693 * remain valid until retro_deinit() is called. */
1694
1695 const char *library_name; /* Descriptive name of library. Should not
1696 * contain any version numbers, etc. */
1697 const char *library_version; /* Descriptive version of core. */
1698
1699 const char *valid_extensions; /* A string listing probably content
1700 * extensions the core will be able to
1701 * load, separated with pipe.
1702 * I.e. "bin|rom|iso".
1703 * Typically used for a GUI to filter
1704 * out extensions. */
1705
1706 /* If true, retro_load_game() is guaranteed to provide a valid pathname
1707 * in retro_game_info::path.
1708 * ::data and ::size are both invalid.
1709 *
1710 * If false, ::data and ::size are guaranteed to be valid, but ::path
1711 * might not be valid.
1712 *
1713 * This is typically set to true for libretro implementations that must
1714 * load from file.
1715 * Implementations should strive for setting this to false, as it allows
1716 * the frontend to perform patching, etc. */
1717 bool need_fullpath;
1718
1719 /* If true, the frontend is not allowed to extract any archives before
1720 * loading the real content.
1721 * Necessary for certain libretro implementations that load games
1722 * from zipped archives. */
1723 bool block_extract;
1724 };
1725
1726 struct retro_game_geometry
1727 {
1728 unsigned base_width; /* Nominal video width of game. */
1729 unsigned base_height; /* Nominal video height of game. */
1730 unsigned max_width; /* Maximum possible width of game. */
1731 unsigned max_height; /* Maximum possible height of game. */
1732
1733 float aspect_ratio; /* Nominal aspect ratio of game. If
1734 * aspect_ratio is <= 0.0, an aspect ratio
1735 * of base_width / base_height is assumed.
1736 * A frontend could override this setting,
1737 * if desired. */
1738 };
1739
1740 struct retro_system_timing
1741 {
1742 double fps; /* FPS of video content. */
1743 double sample_rate; /* Sampling rate of audio. */
1744 };
1745
1746 struct retro_system_av_info
1747 {
1748 struct retro_game_geometry geometry;
1749 struct retro_system_timing timing;
1750 };
1751
1752 struct retro_variable
1753 {
1754 /* Variable to query in RETRO_ENVIRONMENT_GET_VARIABLE.
1755 * If NULL, obtains the complete environment string if more
1756 * complex parsing is necessary.
1757 * The environment string is formatted as key-value pairs
1758 * delimited by semicolons as so:
1759 * "key1=value1;key2=value2;..."
1760 */
1761 const char *key;
1762
1763 /* Value to be obtained. If key does not exist, it is set to NULL. */
1764 const char *value;
1765 };
1766
1767 struct retro_game_info
1768 {
1769 const char *path; /* Path to game, UTF-8 encoded.
1770 * Usually used as a reference.
1771 * May be NULL if rom was loaded from stdin
1772 * or similar.
1773 * retro_system_info::need_fullpath guaranteed
1774 * that this path is valid. */
1775 const void *data; /* Memory buffer of loaded game. Will be NULL
1776 * if need_fullpath was set. */
1777 size_t size; /* Size of memory buffer. */
1778 const char *meta; /* String of implementation specific meta-data. */
1779 };
1780
1781 /* Callbacks */
1782
1783 /* Environment callback. Gives implementations a way of performing
1784 * uncommon tasks. Extensible. */
1785 typedef bool (*retro_environment_t)(unsigned cmd, void *data);
1786
1787 /* Render a frame. Pixel format is 15-bit 0RGB1555 native endian
1788 * unless changed (see RETRO_ENVIRONMENT_SET_PIXEL_FORMAT).
1789 *
1790 * Width and height specify dimensions of buffer.
1791 * Pitch specifices length in bytes between two lines in buffer.
1792 *
1793 * For performance reasons, it is highly recommended to have a frame
1794 * that is packed in memory, i.e. pitch == width * byte_per_pixel.
1795 * Certain graphic APIs, such as OpenGL ES, do not like textures
1796 * that are not packed in memory.
1797 */
1798 typedef void (*retro_video_refresh_t)(const void *data, unsigned width,
1799 unsigned height, size_t pitch);
1800
1801 /* Renders a single audio frame. Should only be used if implementation
1802 * generates a single sample at a time.
1803 * Format is signed 16-bit native endian.
1804 */
1805 typedef void (*retro_audio_sample_t)(int16_t left, int16_t right);
1806
1807 /* Renders multiple audio frames in one go.
1808 *
1809 * One frame is defined as a sample of left and right channels, interleaved.
1810 * I.e. int16_t buf[4] = { l, r, l, r }; would be 2 frames.
1811 * Only one of the audio callbacks must ever be used.
1812 */
1813 typedef size_t (*retro_audio_sample_batch_t)(const int16_t *data,
1814 size_t frames);
1815
1816 /* Polls input. */
1817 typedef void (*retro_input_poll_t)(void);
1818
1819 /* Queries for input for player 'port'. device will be masked with
1820 * RETRO_DEVICE_MASK.
1821 *
1822 * Specialization of devices such as RETRO_DEVICE_JOYPAD_MULTITAP that
1823 * have been set with retro_set_controller_port_device()
1824 * will still use the higher level RETRO_DEVICE_JOYPAD to request input.
1825 */
1826 typedef int16_t (*retro_input_state_t)(unsigned port, unsigned device,
1827 unsigned index, unsigned id);
1828
1829 /* Sets callbacks. retro_set_environment() is guaranteed to be called
1830 * before retro_init().
1831 *
1832 * The rest of the set_* functions are guaranteed to have been called
1833 * before the first call to retro_run() is made. */
1834 void retro_set_environment(retro_environment_t);
1835 void retro_set_video_refresh(retro_video_refresh_t);
1836 void retro_set_audio_sample(retro_audio_sample_t);
1837 void retro_set_audio_sample_batch(retro_audio_sample_batch_t);
1838 void retro_set_input_poll(retro_input_poll_t);
1839 void retro_set_input_state(retro_input_state_t);
1840
1841 /* Library global initialization/deinitialization. */
1842 void retro_init(void);
1843 void retro_deinit(void);
1844
1845 /* Must return RETRO_API_VERSION. Used to validate ABI compatibility
1846 * when the API is revised. */
1847 unsigned retro_api_version(void);
1848
1849 /* Gets statically known system info. Pointers provided in *info
1850 * must be statically allocated.
1851 * Can be called at any time, even before retro_init(). */
1852 void retro_get_system_info(struct retro_system_info *info);
1853
1854 /* Gets information about system audio/video timings and geometry.
1855 * Can be called only after retro_load_game() has successfully completed.
1856 * NOTE: The implementation of this function might not initialize every
1857 * variable if needed.
1858 * E.g. geom.aspect_ratio might not be initialized if core doesn't
1859 * desire a particular aspect ratio. */
1860 void retro_get_system_av_info(struct retro_system_av_info *info);
1861
1862 /* Sets device to be used for player 'port'.
1863 * By default, RETRO_DEVICE_JOYPAD is assumed to be plugged into all
1864 * available ports.
1865 * Setting a particular device type is not a guarantee that libretro cores
1866 * will only poll input based on that particular device type. It is only a
1867 * hint to the libretro core when a core cannot automatically detect the
1868 * appropriate input device type on its own. It is also relevant when a
1869 * core can change its behavior depending on device type. */
1870 void retro_set_controller_port_device(unsigned port, unsigned device);
1871
1872 /* Resets the current game. */
1873 void retro_reset(void);
1874
1875 /* Runs the game for one video frame.
1876 * During retro_run(), input_poll callback must be called at least once.
1877 *
1878 * If a frame is not rendered for reasons where a game "dropped" a frame,
1879 * this still counts as a frame, and retro_run() should explicitly dupe
1880 * a frame if GET_CAN_DUPE returns true.
1881 * In this case, the video callback can take a NULL argument for data.
1882 */
1883 void retro_run(void);
1884
1885 /* Returns the amount of data the implementation requires to serialize
1886 * internal state (save states).
1887 * Between calls to retro_load_game() and retro_unload_game(), the
1888 * returned size is never allowed to be larger than a previous returned
1889 * value, to ensure that the frontend can allocate a save state buffer once.
1890 */
1891 size_t retro_serialize_size(void);
1892
1893 /* Serializes internal state. If failed, or size is lower than
1894 * retro_serialize_size(), it should return false, true otherwise. */
1895 bool retro_serialize(void *data, size_t size);
1896 bool retro_unserialize(const void *data, size_t size);
1897
1898 void retro_cheat_reset(void);
1899 void retro_cheat_set(unsigned index, bool enabled, const char *code);
1900
1901 /* Loads a game. */
1902 bool retro_load_game(const struct retro_game_info *game);
1903
1904 /* Loads a "special" kind of game. Should not be used,
1905 * except in extreme cases. */
1906 bool retro_load_game_special(
1907 unsigned game_type,
1908 const struct retro_game_info *info, size_t num_info
1909 );
1910
1911 /* Unloads a currently loaded game. */
1912 void retro_unload_game(void);
1913
1914 /* Gets region of game. */
1915 unsigned retro_get_region(void);
1916
1917 /* Gets region of memory. */
1918 void *retro_get_memory_data(unsigned id);
1919 size_t retro_get_memory_size(unsigned id);
1920
1921 #ifdef __cplusplus
1922 }
1923 #endif
1924
1925 #endif
0 {
1 global: retro_*;
2 local: *;
3 };
4
0 // TODO/WIP
1
2 /* Mednafen - Multi-system Emulator
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 #include "mednafen.h"
21 #include "Stream.h"
22 #include "FileStream.h"
23
24 #include <stdarg.h>
25 #include <string.h>
26
27 FileStream::FileStream(const char *path, const int mode): OpenedMode(mode)
28 {
29 fp = retro_fopen(path, (mode == MODE_WRITE) ? RFILE_MODE_WRITE : RFILE_MODE_READ, -1);
30
31 if (!fp)
32 {
33 ErrnoHolder ene(errno);
34
35 throw(MDFN_Error(ene.Errno(), "Error opening file %s", ene.StrError()));
36 }
37
38 original_path = strdup(path);
39 }
40
41 FileStream::~FileStream()
42 {
43 if (original_path)
44 free(original_path);
45 original_path = NULL;
46 }
47
48 uint64_t FileStream::attributes(void)
49 {
50 uint64_t ret = ATTRIBUTE_SEEKABLE;
51
52 switch(OpenedMode)
53 {
54 case MODE_READ:
55 ret |= ATTRIBUTE_READABLE;
56 break;
57 case MODE_WRITE_SAFE:
58 case MODE_WRITE:
59 ret |= ATTRIBUTE_WRITEABLE;
60 break;
61 }
62
63 return ret;
64 }
65
66 uint64_t FileStream::read(void *data, uint64_t count, bool error_on_eos)
67 {
68 if (!fp)
69 return 0;
70 return retro_fread(fp, data, count);
71 }
72
73 void FileStream::write(const void *data, uint64_t count)
74 {
75 if (!fp)
76 return;
77 retro_fwrite(fp, data, count);
78 }
79
80 void FileStream::seek(int64_t offset, int whence)
81 {
82 if (!fp)
83 return;
84 retro_fseek(fp, offset, whence);
85 }
86
87 int64_t FileStream::tell(void)
88 {
89 if (!fp)
90 return -1;
91 return retro_ftell(fp);
92 }
93
94 int64_t FileStream::size(void)
95 {
96 if (!original_path)
97 return -1;
98
99 return path_get_size(original_path);
100 }
101
102 void FileStream::close(void)
103 {
104 if (!fp)
105 return;
106 retro_fclose(fp);
107 }
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 // TODO/WIP
18
19 #ifndef __MDFN_FILESTREAM_H
20 #define __MDFN_FILESTREAM_H
21
22 #include <retro_file.h>
23 #include <retro_stat.h>
24
25 #include "Stream.h"
26
27 class FileStream : public Stream
28 {
29 public:
30 FileStream(const char *path, const int mode);
31 virtual ~FileStream();
32
33 virtual uint64_t attributes(void);
34
35 virtual uint64_t read(void *data, uint64_t count, bool error_on_eos = true);
36 virtual void write(const void *data, uint64_t count);
37 virtual void seek(int64_t offset, int whence);
38 virtual int64_t tell(void);
39 virtual int64_t size(void);
40 virtual void close(void);
41
42 private:
43 RFILE *fp;
44 char *original_path;
45 const int OpenedMode;
46 };
47
48
49
50 #endif
0 #include <stdint.h>
1 #include "MemoryStream.h"
2 #include "msvc_compat.h"
3
4 /*
5 TODO:
6 Write and Seek expansion that fail should not corrupt the state.
7
8 Copy and assignment constructor fixes.
9 */
10
11 // TODO 128-bit integers for range checking?
12
13
14 MemoryStream::MemoryStream() : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
15 {
16 data_buffer_size = 0;
17 data_buffer_alloced = 64;
18 if(!(data_buffer = (uint8*)realloc(data_buffer, (size_t)data_buffer_alloced)))
19 throw MDFN_Error(ErrnoHolder(errno));
20 }
21
22 MemoryStream::MemoryStream(uint64 size_hint) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
23 {
24 data_buffer_size = 0;
25 data_buffer_alloced = (size_hint > SIZE_MAX) ? SIZE_MAX : size_hint;
26
27 if(!(data_buffer = (uint8*)realloc(data_buffer, (size_t)data_buffer_alloced)))
28 throw MDFN_Error(ErrnoHolder(errno));
29 }
30
31 MemoryStream::MemoryStream(Stream *stream) : data_buffer(NULL), data_buffer_size(0), data_buffer_alloced(0), position(0)
32 {
33 if((position = stream->tell()) != 0)
34 stream->seek(0, SEEK_SET);
35
36 data_buffer_size = stream->size();
37 data_buffer_alloced = data_buffer_size;
38 if(!(data_buffer = (uint8*)realloc(data_buffer, (size_t)data_buffer_alloced)))
39 throw MDFN_Error(ErrnoHolder(errno));
40
41 stream->read(data_buffer, data_buffer_size);
42
43 stream->close();
44 delete stream;
45 }
46
47 MemoryStream::MemoryStream(const MemoryStream *zs)
48 {
49 data_buffer_size = zs->data_buffer_size;
50 data_buffer_alloced = zs->data_buffer_alloced;
51 if(!(data_buffer = (uint8*)malloc((size_t)data_buffer_alloced)))
52 throw MDFN_Error(ErrnoHolder(errno));
53
54 memcpy(data_buffer, zs->data_buffer, (size_t)data_buffer_size);
55
56 position = zs->position;
57 }
58
59 MemoryStream::~MemoryStream()
60 {
61 if(data_buffer)
62 {
63 free(data_buffer);
64 data_buffer = NULL;
65 }
66 }
67
68 uint64 MemoryStream::attributes(void)
69 {
70 return (ATTRIBUTE_READABLE | ATTRIBUTE_WRITEABLE | ATTRIBUTE_SEEKABLE);
71 }
72
73
74 uint8 *MemoryStream::map(void)
75 {
76 return data_buffer;
77 }
78
79 void MemoryStream::unmap(void)
80 {
81
82 }
83
84
85 INLINE void MemoryStream::grow_if_necessary(uint64 new_required_size)
86 {
87 if(new_required_size > data_buffer_size)
88 {
89 if(new_required_size > data_buffer_alloced)
90 {
91 uint64 new_required_alloced = round_up_pow2(new_required_size);
92 uint8 *new_data_buffer;
93
94 // first condition will happen at new_required_size > (UINT64_C(1) << 63) due to round_up_pow2() "wrapping".
95 // second condition can occur when running on a 32-bit system.
96 if(new_required_alloced < new_required_size || new_required_alloced > SIZE_MAX)
97 new_required_alloced = SIZE_MAX;
98
99 // If constrained alloc size isn't enough, throw an out-of-memory/address-space type error.
100 if(new_required_alloced < new_required_size)
101 throw MDFN_Error(ErrnoHolder(ENOMEM));
102
103 if(!(new_data_buffer = (uint8*)realloc(data_buffer, (size_t)new_required_alloced)))
104 throw MDFN_Error(ErrnoHolder(errno));
105
106 //
107 // Assign all in one go after the realloc() so we don't leave our object in an inconsistent state if the realloc() fails.
108 //
109 data_buffer = new_data_buffer;
110 data_buffer_size = new_required_size;
111 data_buffer_alloced = new_required_alloced;
112 }
113 else
114 data_buffer_size = new_required_size;
115 }
116 }
117
118 uint64 MemoryStream::read(void *data, uint64 count, bool error_on_eos)
119 {
120 if(count > data_buffer_size)
121 {
122 count = data_buffer_size;
123 }
124
125 if((uint64)position > (data_buffer_size - count))
126 {
127 count = data_buffer_size - position;
128 }
129
130 memmove(data, &data_buffer[position], (size_t)count);
131 position += count;
132
133 return count;
134 }
135
136 void MemoryStream::write(const void *data, uint64 count)
137 {
138 uint64 nrs = position + count;
139
140 if(nrs < position)
141 throw MDFN_Error(ErrnoHolder(EFBIG));
142
143 grow_if_necessary(nrs);
144
145 memmove(&data_buffer[position], data, (size_t)count);
146 position += count;
147 }
148
149 void MemoryStream::seek(int64 offset, int whence)
150 {
151 int64 new_position;
152
153 switch(whence)
154 {
155 case SEEK_SET:
156 new_position = offset;
157 break;
158
159 case SEEK_CUR:
160 new_position = position + offset;
161 break;
162
163 case SEEK_END:
164 new_position = data_buffer_size + offset;
165 break;
166 }
167
168 if(new_position < 0)
169 throw MDFN_Error(ErrnoHolder(EINVAL));
170 else
171 grow_if_necessary(new_position);
172
173 position = new_position;
174 }
175
176 int64 MemoryStream::tell(void)
177 {
178 return position;
179 }
180
181 int64 MemoryStream::size(void)
182 {
183 return data_buffer_size;
184 }
185
186 void MemoryStream::close(void)
187 {
188
189 }
190
191
192 int MemoryStream::get_line(std::string &str)
193 {
194 str.clear(); // or str.resize(0)??
195
196 while(position < data_buffer_size)
197 {
198 uint8 c = data_buffer[position++];
199
200 if(c == '\r' || c == '\n' || c == 0)
201 return(c);
202
203 str.push_back(c); // Should be faster than str.append(1, c)
204 }
205
206 return(-1);
207 }
208
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 // TODO/WIP
18
19 #ifndef _MEMORY_STREAM_H
20 #define _MEMORY_STREAM_H
21
22 #include "Stream.h"
23
24 class MemoryStream : public Stream
25 {
26 public:
27
28 MemoryStream();
29 MemoryStream(uint64 size_hint);
30 MemoryStream(Stream *stream); // Will create a MemoryStream equivalent of the contents of "stream", and then "delete stream".
31 // Will only work if stream->tell() == 0, or if "stream" is seekable.
32 // stream will be deleted even if this constructor throws.
33
34 MemoryStream(const MemoryStream *zs);
35 MemoryStream & operator=(const MemoryStream *zs);
36
37 virtual ~MemoryStream();
38
39 virtual uint64 attributes(void);
40
41 virtual uint8 *map(void);
42 virtual void unmap(void);
43
44 virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
45 virtual void write(const void *data, uint64 count);
46 virtual void seek(int64 offset, int whence);
47 virtual int64 tell(void);
48 virtual int64 size(void);
49 virtual void close(void);
50
51 virtual int get_line(std::string &str);
52
53 private:
54 uint8 *data_buffer;
55 uint64 data_buffer_size;
56 uint64 data_buffer_alloced;
57
58 int64 position;
59
60 void grow_if_necessary(uint64 new_required_size);
61 };
62
63 #endif
0 // TODO/WIP
1
2 /* Mednafen - Multi-system Emulator
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "mednafen.h"
20 #include "Stream.h"
21
22 Stream::Stream()
23 {
24
25 }
26
27 Stream::~Stream()
28 {
29
30 }
31
32 int Stream::get_line(std::string &str)
33 {
34 uint8_t c;
35
36 str.clear(); // or str.resize(0)??
37
38 while(read(&c, sizeof(c), false) > 0)
39 {
40 if(c == '\r' || c == '\n' || c == 0)
41 return(c);
42
43 str.push_back(c);
44 }
45
46 return(-1);
47 }
0 #ifndef __MDFN_STREAM_H
1 #define __MDFN_STREAM_H
2
3 // TODO/WIP
4
5 // TODO?: BufferedStream, no virtual functions, yes inline functions, constructor takes a Stream* argument.
6
7 #include "mednafen.h"
8 #include <errno.h>
9
10 #include <stdio.h> // For SEEK_* defines, which we will use in Stream out of FORCE OF HABIT.
11
12 #define MODE_READ 0
13 #define MODE_WRITE 1
14 #define MODE_WRITE_SAFE 2
15
16 class Stream
17 {
18 public:
19
20 Stream();
21 virtual ~Stream();
22
23 enum
24 {
25 ATTRIBUTE_READABLE = 0,
26 ATTRIBUTE_WRITEABLE,
27 ATTRIBUTE_SEEKABLE
28 };
29 virtual uint64_t attributes(void) = 0;
30
31 virtual uint64_t read(void *data, uint64_t count, bool error_on_eos = true) = 0;
32 virtual void write(const void *data, uint64_t count) = 0;
33
34 virtual void seek(int64_t offset, int whence) = 0;
35 virtual int64_t tell(void) = 0;
36 virtual int64_t size(void) = 0;
37 virtual void close(void) = 0; // Flushes(in the case of writeable streams) and closes the stream.
38 // Necessary since this operation can fail(running out of disk space, for instance),
39 // and throw an exception in the destructor would be a Bad Idea(TM).
40 //
41 // Manually calling this function isn't strictly necessary, but recommended when the
42 // stream is writeable; it will be called automatically from the destructor, with any
43 // exceptions thrown caught and logged.
44
45 //
46 // Utility functions(TODO):
47 //
48 INLINE uint8_t get_u8(void)
49 {
50 uint8_t ret;
51
52 read(&ret, sizeof(ret));
53
54 return ret;
55 }
56
57 INLINE void put_u8(uint8_t c)
58 {
59 write(&c, sizeof(c));
60 }
61
62
63 template<typename T>
64 INLINE T get_NE(void)
65 {
66 T ret;
67
68 read(&ret, sizeof(ret));
69
70 return ret;
71 }
72
73 template<typename T>
74 INLINE void put_NE(T c)
75 {
76 write(&c, sizeof(c));
77 }
78
79
80 template<typename T>
81 INLINE T get_RE(void)
82 {
83 uint8_t tmp[sizeof(T)];
84 T ret = 0;
85
86 read(tmp, sizeof(tmp));
87
88 for(unsigned i = 0; i < sizeof(T); i++)
89 ret |= (T)tmp[i] << (i * 8);
90
91 return ret;
92 }
93
94 template<typename T>
95 INLINE void put_RE(T c)
96 {
97 uint8_t tmp[sizeof(T)];
98
99 for(unsigned i = 0; i < sizeof(T); i++)
100 tmp[i] = ((uint8_t *)&c)[sizeof(T) - 1 - i];
101
102 write(tmp, sizeof(tmp));
103 }
104
105 template<typename T>
106 INLINE T get_LE(void)
107 {
108 #ifdef MSB_FIRST
109 return get_RE<T>();
110 #else
111 return get_NE<T>();
112 #endif
113 }
114
115 template<typename T>
116 INLINE void put_LE(T c)
117 {
118 #ifdef MSB_FIRST
119 return put_RE<T>(c);
120 #else
121 return put_NE<T>(c);
122 #endif
123 }
124
125 template<typename T>
126 INLINE T get_BE(void)
127 {
128 #ifdef MSB_FIRST
129 return get_NE<T>();
130 #else
131 return get_RE<T>();
132 #endif
133 }
134
135 template<typename T>
136 INLINE void put_BE(T c)
137 {
138 #ifdef MSB_FIRST
139 return put_NE<T>(c);
140 #else
141 return put_RE<T>(c);
142 #endif
143 }
144
145 // Reads a line into "str", overwriting its contents; returns the line-end char('\n' or '\r' or '\0'), or -1 on EOF.
146 // The line-end char won't be added to "str".
147 // It's up to the caller to handle extraneous empty lines caused by DOS-format text lines(\r\n).
148 // ("str" is passed by reference for the possibility of improved performance by reusing alloced memory for the std::string, though part
149 // of it would be up to the STL implementation).
150 // Implemented as virtual so that a higher-performance version can be implemented if possible(IE with MemoryStream)
151 virtual int get_line(std::string &str);
152 };
153 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17
18 #include <sys/stat.h>
19 #ifdef _WIN32
20 #include <direct.h>
21 #else
22 #include <unistd.h>
23 #endif
24
25 #include "../mednafen.h"
26
27 #include "CDAccess.h"
28 #include "CDAccess_Image.h"
29 #include "CDAccess_CCD.h"
30
31 CDAccess::CDAccess()
32 {
33
34 }
35
36 CDAccess::~CDAccess()
37 {
38
39 }
40
41 CDAccess *cdaccess_open_image(const char *path, bool image_memcache)
42 {
43 CDAccess *ret = NULL;
44
45 if(strlen(path) >= 4 && !strcasecmp(path + strlen(path) - 4, ".ccd"))
46 ret = new CDAccess_CCD(path, image_memcache);
47 else
48 ret = new CDAccess_Image(path, image_memcache);
49
50 return ret;
51 }
0 #ifndef __MDFN_CDROMFILE_H
1 #define __MDFN_CDROMFILE_H
2
3 #include <stdio.h>
4 #include <stdint.h>
5
6 #include "CDUtility.h"
7 #include "misc.h"
8
9 class CDAccess
10 {
11 public:
12
13 CDAccess();
14 virtual ~CDAccess();
15
16 virtual void Read_Raw_Sector(uint8_t *buf, int32_t lba) = 0;
17
18 virtual void Read_TOC(TOC *toc) = 0;
19
20 virtual void Eject(bool eject_status) = 0; // Eject a disc if it's physical, otherwise NOP. Returns true on success(or NOP), false on error
21
22 private:
23 CDAccess(const CDAccess&); // No copy constructor.
24 CDAccess& operator=(const CDAccess&); // No assignment operator.
25 };
26
27 CDAccess *cdaccess_open_image(const char *path, bool image_memcache);
28
29 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../mednafen.h"
18 #include "../general.h"
19 #include "../msvc_compat.h"
20 #include "CDAccess_CCD.h"
21 #include "CDUtility.h"
22
23 #include <limits>
24 #include <limits.h>
25 #include <map>
26
27 typedef std::map<std::string, std::string> CCD_Section;
28
29 template<typename T>
30 static T CCD_ReadInt(CCD_Section &s, const std::string &propname, const bool have_defval = false, const int defval = 0)
31 {
32 const char *vp;
33 char *ep = NULL;
34 int scan_base = 10;
35 size_t scan_offset = 0;
36 long ret = 0;
37 CCD_Section::iterator zit = s.find(propname);
38
39 if(zit == s.end())
40 {
41 if(have_defval)
42 return defval;
43 throw MDFN_Error(0, _("Missing property: %s"), propname.c_str());
44 }
45
46 const std::string &v = zit->second;
47
48 if(v.length() >= 3 && v[0] == '0' && v[1] == 'x')
49 {
50 scan_base = 16;
51 scan_offset = 2;
52 }
53
54 vp = v.c_str() + scan_offset;
55
56 if(std::numeric_limits<T>::is_signed)
57 ret = strtol(vp, &ep, scan_base);
58 else
59 ret = strtoul(vp, &ep, scan_base);
60
61 if(!vp[0] || ep[0])
62 throw MDFN_Error(0, _("Property %s: Malformed integer: %s"), propname.c_str(), v.c_str());
63
64 return ret;
65 }
66
67
68 CDAccess_CCD::CDAccess_CCD(const char *path, bool image_memcache) : img_stream(NULL), sub_stream(NULL), img_numsectors(0)
69 {
70 try
71 {
72 TOC_Clear(&tocd);
73 Load(path, image_memcache);
74 }
75 catch(...)
76 {
77 Cleanup();
78 throw;
79 }
80 }
81
82 void CDAccess_CCD::Load(const char *path, bool image_memcache)
83 {
84 FileStream cf(path, MODE_READ);
85 std::map<std::string, CCD_Section> Sections;
86 std::string linebuf;
87 std::string cur_section_name;
88 std::string dir_path, file_base, file_ext;
89 char img_extsd[4] = { 'i', 'm', 'g', 0 };
90 char sub_extsd[4] = { 's', 'u', 'b', 0 };
91
92 MDFN_GetFilePathComponents(path, &dir_path, &file_base, &file_ext);
93
94 if(file_ext.length() == 4 && file_ext[0] == '.')
95 {
96 int i;
97 signed char av = -1;
98 signed char extupt[3] = { -1, -1, -1 };
99
100 for(i = 1; i < 4; i++)
101 {
102 if(file_ext[i] >= 'A' && file_ext[i] <= 'Z')
103 extupt[i - 1] = 'A' - 'a';
104 else if(file_ext[i] >= 'a' && file_ext[i] <= 'z')
105 extupt[i - 1] = 0;
106 }
107
108 for(i = 0; i < 3; i++)
109 {
110 if(extupt[i] != -1)
111 av = extupt[i];
112 else
113 extupt[i] = av;
114 }
115
116 if(av == -1)
117 av = 0;
118
119 for(i = 0; i < 3; i++)
120 {
121 if(extupt[i] == -1)
122 extupt[i] = av;
123 }
124
125 for(i = 0; i < 3; i++)
126 {
127 img_extsd[i] += extupt[i];
128 sub_extsd[i] += extupt[i];
129 }
130 }
131
132 //printf("%s %d %d %d\n", file_ext.c_str(), extupt[0], extupt[1], extupt[2]);
133
134 linebuf.reserve(256);
135
136 while(cf.get_line(linebuf) >= 0)
137 {
138 MDFN_trim(linebuf);
139
140 if(linebuf.length() == 0) // Skip blank lines.
141 continue;
142
143 if(linebuf[0] == '[')
144 {
145 if(linebuf.length() < 3 || linebuf[linebuf.length() - 1] != ']')
146 throw MDFN_Error(0, _("Malformed section specifier: %s"), linebuf.c_str());
147
148 cur_section_name = linebuf.substr(1, linebuf.length() - 2);
149 MDFN_strtoupper(cur_section_name);
150 }
151 else
152 {
153 std::string k, v;
154 const size_t feqpos = linebuf.find('=');
155 const size_t leqpos = linebuf.rfind('=');
156
157 if(feqpos == std::string::npos || feqpos != leqpos)
158 throw MDFN_Error(0, _("Malformed value pair specifier: %s"), linebuf.c_str());
159
160 k = linebuf.substr(0, feqpos);
161 v = linebuf.substr(feqpos + 1);
162
163 MDFN_trim(k);
164 MDFN_trim(v);
165
166 MDFN_strtoupper(k);
167
168 Sections[cur_section_name][k] = v;
169 }
170 }
171
172 {
173 unsigned te;
174 CCD_Section &ds = Sections["DISC"];
175 unsigned toc_entries = CCD_ReadInt<unsigned>(ds, "TOCENTRIES");
176 unsigned num_sessions = CCD_ReadInt<unsigned>(ds, "SESSIONS");
177 bool data_tracks_scrambled = CCD_ReadInt<unsigned>(ds, "DATATRACKSSCRAMBLED");
178
179 if(num_sessions != 1)
180 throw MDFN_Error(0, _("Unsupported number of sessions: %u"), num_sessions);
181
182 if(data_tracks_scrambled)
183 throw MDFN_Error(0, _("Scrambled CCD data tracks currently not supported."));
184
185 //printf("MOO: %d\n", toc_entries);
186
187 for(te = 0; te < toc_entries; te++)
188 {
189 char tmpbuf[64];
190 snprintf(tmpbuf, sizeof(tmpbuf), "ENTRY %u", te);
191 CCD_Section & ts = Sections[std::string(tmpbuf)];
192 unsigned session = CCD_ReadInt<unsigned>(ts, "SESSION");
193 uint8_t point = CCD_ReadInt<uint8>(ts, "POINT");
194 uint8_t adr = CCD_ReadInt<uint8>(ts, "ADR");
195 uint8_t control = CCD_ReadInt<uint8>(ts, "CONTROL");
196 uint8_t pmin = CCD_ReadInt<uint8>(ts, "PMIN");
197 uint8_t psec = CCD_ReadInt<uint8>(ts, "PSEC");
198 uint8_t pframe = CCD_ReadInt<uint8>(ts, "PFRAME");
199 signed plba = CCD_ReadInt<signed>(ts, "PLBA");
200
201 if(session != 1)
202 throw MDFN_Error(0, "Unsupported TOC entry Session value: %u", session);
203
204 // Reference: ECMA-394, page 5-14
205 if (point >= 1 && point <= 99)
206 {
207 tocd.tracks[point].adr = adr;
208 tocd.tracks[point].control = control;
209 tocd.tracks[point].lba = plba;
210 }
211 else
212 switch(point)
213 {
214 default:
215 throw MDFN_Error(0, "Unsupported TOC entry Point value: %u", point);
216
217 case 0xA0:
218 tocd.first_track = pmin;
219 tocd.disc_type = psec;
220 break;
221
222 case 0xA1:
223 tocd.last_track = pmin;
224 break;
225
226 case 0xA2:
227 tocd.tracks[100].adr = adr;
228 tocd.tracks[100].control = control;
229 tocd.tracks[100].lba = plba;
230 break;
231 }
232 }
233 }
234
235 /* Convenience leadout track duplication. */
236 if(tocd.last_track < 99)
237 tocd.tracks[tocd.last_track + 1] = tocd.tracks[100];
238
239 /* Open image stream. */
240 {
241 std::string image_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(img_extsd), true);
242 FileStream *str = new FileStream(image_path.c_str(), MODE_READ);
243
244 if(image_memcache)
245 img_stream = new MemoryStream(str);
246 else
247 img_stream = str;
248
249 int64 ss = img_stream->size();
250
251 if(ss % 2352)
252 throw MDFN_Error(0, _("CCD image size is not evenly divisible by 2352."));
253
254 img_numsectors = ss / 2352;
255 }
256
257 {
258 /* Open subchannel stream */
259 std::string sub_path = MDFN_EvalFIP(dir_path, file_base + std::string(".") + std::string(sub_extsd), true);
260 FileStream *str = new FileStream(sub_path.c_str(), MODE_READ);
261
262 if(image_memcache)
263 sub_stream = new MemoryStream(str);
264 else
265 sub_stream = str;
266
267 if(sub_stream->size() != (int64)img_numsectors * 96)
268 throw MDFN_Error(0, _("CCD SUB file size mismatch."));
269 }
270
271 CheckSubQSanity();
272 }
273
274 //
275 // Checks for Q subchannel mode 1(current time) data that has a correct checksum, but the data is nonsensical or corrupted nonetheless; this is the
276 // case for some bad rips floating around on the Internet. Allowing these bad rips to be used will cause all sorts of problems during emulation, so we
277 // error out here if a bad rip is detected.
278 //
279 // This check is not as aggressive or exhaustive as it could be, and will not detect all potential Q subchannel rip errors; as such, it should definitely NOT be
280 // used in an effort to "repair" a broken rip.
281 //
282 void CDAccess_CCD::CheckSubQSanity(void)
283 {
284 size_t s;
285 size_t checksum_pass_counter = 0;
286 int prev_lba = INT_MAX;
287 uint8_t prev_track = 0;
288
289 for(s = 0; s < img_numsectors; s++)
290 {
291 uint8_t adr;
292 union
293 {
294 uint8 full[96];
295 struct
296 {
297 uint8 pbuf[12];
298 uint8 qbuf[12];
299 };
300 } buf;
301
302 sub_stream->seek(s * 96, SEEK_SET);
303 sub_stream->read(buf.full, 96);
304
305 if(!subq_check_checksum(buf.qbuf))
306 continue;
307
308 adr = buf.qbuf[0] & 0xF;
309
310 if(adr == 0x01)
311 {
312 int lba;
313 uint8_t track;
314 uint8_t track_bcd = buf.qbuf[1];
315 uint8_t index_bcd = buf.qbuf[2];
316 uint8_t rm_bcd = buf.qbuf[3];
317 uint8_t rs_bcd = buf.qbuf[4];
318 uint8_t rf_bcd = buf.qbuf[5];
319 uint8_t am_bcd = buf.qbuf[7];
320 uint8_t as_bcd = buf.qbuf[8];
321 uint8_t af_bcd = buf.qbuf[9];
322
323 //printf("%2x %2x %2x\n", am_bcd, as_bcd, af_bcd);
324
325 if(!BCD_is_valid(track_bcd) || !BCD_is_valid(index_bcd) || !BCD_is_valid(rm_bcd) || !BCD_is_valid(rs_bcd) || !BCD_is_valid(rf_bcd) ||
326 !BCD_is_valid(am_bcd) || !BCD_is_valid(as_bcd) || !BCD_is_valid(af_bcd) ||
327 rs_bcd > 0x59 || rf_bcd > 0x74 || as_bcd > 0x59 || af_bcd > 0x74)
328 throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad BCD/out of range): %02x:%02x:%02x %02x:%02x:%02x"), rm_bcd, rs_bcd, rf_bcd, am_bcd, as_bcd, af_bcd);
329
330 lba = ((BCD_to_U8(am_bcd) * 60 + BCD_to_U8(as_bcd)) * 75 + BCD_to_U8(af_bcd)) - 150;
331 track = BCD_to_U8(track_bcd);
332
333 prev_lba = lba;
334
335 if(track < prev_track)
336 throw MDFN_Error(0, _("Garbage subchannel Q data detected(bad track number)"));
337
338 prev_track = track;
339 checksum_pass_counter++;
340 }
341 }
342
343 //printf("%u/%u\n", checksum_pass_counter, img_numsectors);
344 }
345
346 void CDAccess_CCD::Cleanup(void)
347 {
348 if(img_stream)
349 {
350 delete img_stream;
351 img_stream = NULL;
352 }
353
354 if(sub_stream)
355 {
356 delete sub_stream;
357 sub_stream = NULL;
358 }
359 }
360
361 CDAccess_CCD::~CDAccess_CCD()
362 {
363 Cleanup();
364 }
365
366 void CDAccess_CCD::Read_Raw_Sector(uint8 *buf, int32 lba)
367 {
368 uint8_t sub_buf[96];
369
370 if(lba < 0 || (size_t)lba >= img_numsectors)
371 throw(MDFN_Error(0, _("LBA out of range.")));
372
373 img_stream->seek(lba * 2352, SEEK_SET);
374 img_stream->read(buf, 2352);
375
376 sub_stream->seek(lba * 96, SEEK_SET);
377 sub_stream->read(sub_buf, 96);
378
379 subpw_interleave(sub_buf, buf + 2352);
380 }
381
382
383 void CDAccess_CCD::Read_TOC(TOC *toc)
384 {
385 *toc = tocd;
386 }
387
388 void CDAccess_CCD::Eject(bool eject_status)
389 {
390
391 }
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #ifndef _CDROM_CDACCESS_CCD_H_
18 #define _CDROM_CDACCESS_CCD_H_
19
20 #include "../FileStream.h"
21 #include "../MemoryStream.h"
22 #include "CDAccess.h"
23
24 #include <vector>
25
26 class CDAccess_CCD : public CDAccess
27 {
28 public:
29
30 CDAccess_CCD(const char *path, bool image_memcache);
31 virtual ~CDAccess_CCD();
32
33 virtual void Read_Raw_Sector(uint8_t *buf, int32_t lba);
34
35 virtual void Read_TOC(TOC *toc);
36
37 virtual void Eject(bool eject_status);
38
39 private:
40
41 void Load(const char *path, bool image_memcache);
42 void Cleanup(void);
43
44 void CheckSubQSanity(void);
45
46 Stream* img_stream;
47 Stream* sub_stream;
48 size_t img_numsectors;
49 TOC tocd;
50 };
51
52 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 /*
18 Notes and TODO:
19
20 POSTGAP in CUE sheets may not be handled properly, should the directive automatically increment the index number?
21
22 INDEX nn where 02 <= nn <= 99 is not supported in CUE sheets.
23
24 TOC reading code is extremely barebones, leaving out support for more esoteric features.
25
26 A PREGAP statement in the first track definition in a CUE sheet may not work properly(depends on what is proper);
27 it will be added onto the implicit default 00:02:00 of pregap.
28
29 Trying to read sectors at an LBA of less than 0 is not supported. TODO: support it(at least up to -150).
30 */
31
32 #include <retro_stat.h>
33
34 #include "../mednafen.h"
35
36 #include <sys/types.h>
37
38 #include <string.h>
39 #include <errno.h>
40 #include <time.h>
41
42 #include "../general.h"
43 #include "../FileStream.h"
44 #include "../MemoryStream.h"
45
46 #include "CDAccess.h"
47 #include "CDAccess_Image.h"
48 #include "CDUtility.h"
49
50 #include "audioreader.h"
51
52 #include "../../libretro.h"
53
54 extern retro_log_printf_t log_cb;
55
56 #include <map>
57
58 enum
59 {
60 CDRF_SUBM_NONE = 0,
61 CDRF_SUBM_RW = 1,
62 CDRF_SUBM_RW_RAW = 2
63 };
64
65 // Disk-image(rip) track/sector formats
66 enum
67 {
68 DI_FORMAT_AUDIO = 0x00,
69 DI_FORMAT_MODE1 = 0x01,
70 DI_FORMAT_MODE1_RAW = 0x02,
71 DI_FORMAT_MODE2 = 0x03,
72 DI_FORMAT_MODE2_FORM1 = 0x04,
73 DI_FORMAT_MODE2_FORM2 = 0x05,
74 DI_FORMAT_MODE2_RAW = 0x06,
75 _DI_FORMAT_COUNT
76 };
77
78 static const int32 DI_Size_Table[7] =
79 {
80 2352, // Audio
81 2048, // MODE1
82 2352, // MODE1 RAW
83 2336, // MODE2
84 2048, // MODE2 Form 1
85 2324, // Mode 2 Form 2
86 2352
87 };
88
89 static const char *DI_CDRDAO_Strings[7] =
90 {
91 "AUDIO",
92 "MODE1",
93 "MODE1_RAW",
94 "MODE2",
95 "MODE2_FORM1",
96 "MODE2_FORM2",
97 "MODE2_RAW"
98 };
99
100 static const char *DI_CUE_Strings[7] =
101 {
102 "AUDIO",
103 "MODE1/2048",
104 "MODE1/2352",
105
106 // FIXME: These are just guesses:
107 "MODE2/2336",
108 "MODE2/2048",
109 "MODE2/2324",
110 "MODE2/2352"
111 };
112
113 // Should return an offset to the start of the next argument(past any whitespace), or if there isn't a next argument,
114 // it'll return the length of the src string.
115 static size_t UnQuotify(const std::string &src, size_t source_offset, std::string &dest, bool parse_quotes = true)
116 {
117 const size_t source_len = src.length();
118 bool in_quote = 0;
119 bool already_normal = 0;
120
121 dest.clear();
122
123 while(source_offset < source_len)
124 {
125 if(src[source_offset] == ' ' || src[source_offset] == '\t')
126 {
127 if(!in_quote)
128 {
129 if(already_normal) // Trailing whitespace(IE we're done with this argument)
130 break;
131 else // Leading whitespace, ignore it.
132 {
133 source_offset++;
134 continue;
135 }
136 }
137 }
138
139 if(src[source_offset] == '"' && parse_quotes)
140 {
141 if(in_quote)
142 {
143 source_offset++;
144 // Not sure which behavior is most useful(or correct :b).
145 #if 0
146 in_quote = false;
147 already_normal = true;
148 #else
149 break;
150 #endif
151 }
152 else
153 in_quote = 1;
154 }
155 else
156 {
157 dest.push_back(src[source_offset]);
158 already_normal = 1;
159 }
160 source_offset++;
161 }
162
163 while(source_offset < source_len)
164 {
165 if(src[source_offset] != ' ' && src[source_offset] != '\t')
166 break;
167
168 source_offset++;
169 }
170
171 return source_offset;
172 }
173
174 uint32 CDAccess_Image::GetSectorCount(CDRFILE_TRACK_INFO *track)
175 {
176 int64 size;
177
178 if(track->DIFormat == DI_FORMAT_AUDIO)
179 {
180 if(track->AReader)
181 return(((track->AReader->FrameCount() * 4) - track->FileOffset) / 2352);
182
183 size = track->fp->size();
184
185 //printf("%d %d %d\n", (int)stat_buf.st_size, (int)track->FileOffset, (int)stat_buf.st_size - (int)track->FileOffset);
186 if(track->SubchannelMode)
187 return((size - track->FileOffset) / (2352 + 96));
188 return((size - track->FileOffset) / 2352);
189 }
190
191 size = track->fp->size();
192
193 return((size - track->FileOffset) / DI_Size_Table[track->DIFormat]);
194 }
195
196 void CDAccess_Image::ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const std::string &filename, const char *binoffset, const char *msfoffset, const char *length, bool image_memcache, std::map<std::string, Stream*> &toc_streamcache)
197 {
198 long offset = 0; // In bytes!
199 long tmp_long;
200 int m, s, f;
201 uint32 sector_mult;
202 long sectors;
203 std::map<std::string, Stream*>::iterator ribbit;
204
205 ribbit = toc_streamcache.find(filename);
206
207 if(ribbit != toc_streamcache.end())
208 {
209 track->FirstFileInstance = 0;
210
211 track->fp = ribbit->second;
212 }
213 else
214 {
215 std::string efn;
216
217 track->FirstFileInstance = 1;
218
219 efn = MDFN_EvalFIP(base_dir, filename);
220
221 if(image_memcache)
222 track->fp = new MemoryStream(new FileStream(efn.c_str(), MODE_READ));
223 else
224 track->fp = new FileStream(efn.c_str(), MODE_READ);
225
226 toc_streamcache[filename] = track->fp;
227 }
228
229 if(filename.length() >= 4 && !strcasecmp(filename.c_str() + filename.length() - 4, ".wav"))
230 {
231 track->AReader = AR_Open(track->fp);
232
233 if(!track->AReader)
234 throw MDFN_Error(0, "TODO ERROR");
235 }
236
237 sector_mult = DI_Size_Table[track->DIFormat];
238
239 if(track->SubchannelMode)
240 sector_mult += 96;
241
242 if(binoffset && sscanf(binoffset, "%ld", &tmp_long) == 1)
243 {
244 offset += tmp_long;
245 }
246
247 if(msfoffset && sscanf(msfoffset, "%d:%d:%d", &m, &s, &f) == 3)
248 {
249 offset += ((m * 60 + s) * 75 + f) * sector_mult;
250 }
251
252 track->FileOffset = offset; // Make sure this is set before calling GetSectorCount()!
253 sectors = GetSectorCount(track);
254 //printf("Track: %d, offset: %ld, %ld\n", tracknum, offset, sectors);
255
256 if(length)
257 {
258 tmp_long = sectors;
259
260 if(sscanf(length, "%d:%d:%d", &m, &s, &f) == 3)
261 tmp_long = (m * 60 + s) * 75 + f;
262 else if(track->DIFormat == DI_FORMAT_AUDIO)
263 {
264 char *endptr = NULL;
265
266 tmp_long = strtol(length, &endptr, 10);
267
268 // Error?
269 if(endptr == length)
270 {
271 tmp_long = sectors;
272 }
273 else
274 tmp_long /= 588;
275
276 }
277
278 if(tmp_long > sectors)
279 {
280 throw MDFN_Error(0, _("Length specified in TOC file for track %d is too large by %ld sectors!\n"), tracknum, (long)(tmp_long - sectors));
281 }
282 sectors = tmp_long;
283 }
284
285 track->sectors = sectors;
286 }
287
288 int CDAccess_Image::LoadSBI(const char* sbi_path)
289 {
290 /* Loading SBI file */
291 uint8 header[4];
292 uint8 ed[4 + 10];
293 uint8 tmpq[12];
294 FileStream sbis(sbi_path, MODE_READ);
295
296 sbis.read(header, 4);
297
298 if(memcmp(header, "SBI\0", 4))
299 return -1;
300
301 while(sbis.read(ed, sizeof(ed), false) == sizeof(ed))
302 {
303 /* Bad BCD MSF offset in SBI file. */
304 if(!BCD_is_valid(ed[0]) || !BCD_is_valid(ed[1]) || !BCD_is_valid(ed[2]))
305 return -1;
306
307 /* Unrecognized boogly oogly in SBI file */
308 if(ed[3] != 0x01)
309 return -1;
310
311 memcpy(tmpq, &ed[4], 10);
312
313 subq_generate_checksum(tmpq);
314 tmpq[10] ^= 0xFF;
315 tmpq[11] ^= 0xFF;
316
317 uint32 aba = AMSF_to_ABA(BCD_to_U8(ed[0]), BCD_to_U8(ed[1]), BCD_to_U8(ed[2]));
318
319 memcpy(SubQReplaceMap[aba].data, tmpq, 12);
320 }
321
322 //MDFN_printf(_("Loaded Q subchannel replacements for %zu sectors.\n"), SubQReplaceMap.size());
323
324 return 0;
325 }
326
327 void CDAccess_Image::ImageOpen(const char *path, bool image_memcache)
328 {
329 MemoryStream fp(new FileStream(path, MODE_READ));
330 static const unsigned max_args = 4;
331 std::string linebuf;
332 std::string cmdbuf, args[max_args];
333 bool IsTOC = FALSE;
334 int32 active_track = -1;
335 int32 AutoTrackInc = 1; // For TOC
336 CDRFILE_TRACK_INFO TmpTrack;
337 std::string file_base, file_ext;
338 std::map<std::string, Stream*> toc_streamcache;
339
340 disc_type = DISC_TYPE_CDDA_OR_M1;
341 memset(&TmpTrack, 0, sizeof(TmpTrack));
342
343 MDFN_GetFilePathComponents(path, &base_dir, &file_base, &file_ext);
344
345 if(!strcasecmp(file_ext.c_str(), ".toc"))
346 {
347 log_cb(RETRO_LOG_INFO, "TOC file detected.\n");
348 IsTOC = true;
349 }
350
351 // Check for annoying UTF-8 BOM.
352 if(!IsTOC)
353 {
354 uint8 bom_tmp[3];
355
356 if(fp.read(bom_tmp, 3, false) == 3 && bom_tmp[0] == 0xEF && bom_tmp[1] == 0xBB && bom_tmp[2] == 0xBF)
357 {
358 log_cb(RETRO_LOG_ERROR, "UTF-8 BOM detected at start of CUE sheet.\n");
359 }
360 else
361 fp.seek(0, SEEK_SET);
362 }
363
364
365 // Assign opposite maximum values so our tests will work!
366 FirstTrack = 99;
367 LastTrack = 0;
368
369 linebuf.reserve(1024);
370 while(fp.get_line(linebuf) >= 0)
371 {
372 unsigned argcount = 0;
373
374 if(IsTOC)
375 {
376 // Handle TOC format comments
377 size_t ss_loc = linebuf.find("//");
378
379 if(ss_loc != std::string::npos)
380 linebuf.resize(ss_loc);
381 }
382
383 // Call trim AFTER we handle TOC-style comments, so we'll be sure to remove trailing whitespace in lines like: MONKEY // BABIES
384 MDFN_trim(linebuf);
385
386 if(linebuf.length() == 0) // Skip blank lines.
387 continue;
388
389 // Grab command and arguments.
390 {
391 size_t offs = 0;
392
393 offs = UnQuotify(linebuf, offs, cmdbuf, false);
394 for(argcount = 0; argcount < max_args && offs < linebuf.length(); argcount++)
395 offs = UnQuotify(linebuf, offs, args[argcount]);
396
397 // Make sure unused arguments are cleared out so we don't have inter-line leaks!
398 for(unsigned x = argcount; x < max_args; x++)
399 args[x].clear();
400
401 MDFN_strtoupper(cmdbuf);
402 }
403
404 //printf("%s\n", cmdbuf.c_str()); //: %s %s %s %s\n", cmdbuf.c_str(), args[0].c_str(), args[1].c_str(), args[2].c_str(), args[3].c_str());
405
406 if(IsTOC)
407 {
408 if(cmdbuf == "TRACK")
409 {
410 if(active_track >= 0)
411 {
412 memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
413 memset(&TmpTrack, 0, sizeof(TmpTrack));
414 active_track = -1;
415 }
416
417 if(AutoTrackInc > 99)
418 {
419 throw(MDFN_Error(0, _("Invalid track number: %d"), AutoTrackInc));
420 }
421
422 active_track = AutoTrackInc++;
423 if(active_track < FirstTrack)
424 FirstTrack = active_track;
425 if(active_track > LastTrack)
426 LastTrack = active_track;
427
428 int format_lookup;
429 for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
430 {
431 if(!strcasecmp(args[0].c_str(), DI_CDRDAO_Strings[format_lookup]))
432 {
433 TmpTrack.DIFormat = format_lookup;
434 break;
435 }
436 }
437
438 if(format_lookup == _DI_FORMAT_COUNT)
439 {
440 throw(MDFN_Error(0, _("Invalid track format: %s"), args[0].c_str()));
441 }
442
443 if(TmpTrack.DIFormat == DI_FORMAT_AUDIO)
444 TmpTrack.RawAudioMSBFirst = TRUE; // Silly cdrdao...
445
446 if(!strcasecmp(args[1].c_str(), "RW"))
447 {
448 TmpTrack.SubchannelMode = CDRF_SUBM_RW;
449 throw(MDFN_Error(0, _("\"RW\" format subchannel data not supported, only \"RW_RAW\" is!")));
450 }
451 else if(!strcasecmp(args[1].c_str(), "RW_RAW"))
452 TmpTrack.SubchannelMode = CDRF_SUBM_RW_RAW;
453
454 } // end to TRACK
455 else if(cmdbuf == "SILENCE")
456 {
457 //throw MDFN_Error(0, _("Unsupported directive: %s"), cmdbuf.c_str());
458 }
459 else if(cmdbuf == "ZERO")
460 {
461 //throw MDFN_Error(0, _("Unsupported directive: %s"), cmdbuf.c_str());
462 }
463 else if(cmdbuf == "FIFO")
464 {
465 throw MDFN_Error(0, _("Unsupported directive: %s"), cmdbuf.c_str());
466 }
467 else if(cmdbuf == "FILE" || cmdbuf == "AUDIOFILE")
468 {
469 const char *binoffset = NULL;
470 const char *msfoffset = NULL;
471 const char *length = NULL;
472
473 if(args[1].c_str()[0] == '#')
474 {
475 binoffset = args[1].c_str() + 1;
476 msfoffset = args[2].c_str();
477 length = args[3].c_str();
478 }
479 else
480 {
481 msfoffset = args[1].c_str();
482 length = args[2].c_str();
483 }
484 //printf("%s, %s, %s, %s\n", args[0].c_str(), binoffset, msfoffset, length);
485 ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, msfoffset, length, image_memcache, toc_streamcache);
486 }
487 else if(cmdbuf == "DATAFILE")
488 {
489 const char *binoffset = NULL;
490 const char *length = NULL;
491
492 if(args[1].c_str()[0] == '#')
493 {
494 binoffset = args[1].c_str() + 1;
495 length = args[2].c_str();
496 }
497 else
498 length = args[1].c_str();
499
500 ParseTOCFileLineInfo(&TmpTrack, active_track, args[0], binoffset, NULL, length, image_memcache, toc_streamcache);
501 }
502 else if(cmdbuf == "INDEX")
503 {
504
505 }
506 else if(cmdbuf == "PREGAP")
507 {
508 if(active_track < 0)
509 {
510 throw(MDFN_Error(0, _("Command %s is outside of a TRACK definition!\n"), cmdbuf.c_str()));
511 }
512 int m,s,f;
513 sscanf(args[0].c_str(), "%d:%d:%d", &m, &s, &f);
514 TmpTrack.pregap = (m * 60 + s) * 75 + f;
515 } // end to PREGAP
516 else if(cmdbuf == "START")
517 {
518 if(active_track < 0)
519 {
520 throw(MDFN_Error(0, _("Command %s is outside of a TRACK definition!\n"), cmdbuf.c_str()));
521 }
522 int m,s,f;
523 sscanf(args[0].c_str(), "%d:%d:%d", &m, &s, &f);
524 TmpTrack.pregap = (m * 60 + s) * 75 + f;
525 }
526 else if(cmdbuf == "TWO_CHANNEL_AUDIO")
527 {
528 TmpTrack.subq_control &= ~SUBQ_CTRLF_4CH;
529 }
530 else if(cmdbuf == "FOUR_CHANNEL_AUDIO")
531 {
532 TmpTrack.subq_control |= SUBQ_CTRLF_4CH;
533 }
534 else if(cmdbuf == "NO")
535 {
536 MDFN_strtoupper(args[0]);
537
538 if(args[0] == "COPY")
539 {
540 TmpTrack.subq_control &= ~SUBQ_CTRLF_DCP;
541 }
542 else if(args[0] == "PRE_EMPHASIS")
543 {
544 TmpTrack.subq_control &= ~SUBQ_CTRLF_PRE;
545 }
546 else
547 {
548 throw MDFN_Error(0, _("Unsupported argument to \"NO\" directive: %s"), args[0].c_str());
549 }
550 }
551 else if(cmdbuf == "COPY")
552 {
553 TmpTrack.subq_control |= SUBQ_CTRLF_DCP;
554 }
555 else if(cmdbuf == "PRE_EMPHASIS")
556 {
557 TmpTrack.subq_control |= SUBQ_CTRLF_PRE;
558 }
559 // TODO: Confirm that these are taken from the TOC of the disc, and not synthesized by cdrdao.
560 else if(cmdbuf == "CD_DA")
561 disc_type = DISC_TYPE_CDDA_OR_M1;
562 else if(cmdbuf == "CD_ROM")
563 disc_type = DISC_TYPE_CDDA_OR_M1;
564 else if(cmdbuf == "CD_ROM_XA")
565 disc_type = DISC_TYPE_CD_XA;
566 else
567 {
568 //throw MDFN_Error(0, _("Unsupported directive: %s"), cmdbuf.c_str());
569 }
570 // TODO: CATALOG
571
572 } /*********** END TOC HANDLING ************/
573 else // now for CUE sheet handling
574 {
575 if(cmdbuf == "FILE")
576 {
577 if(active_track >= 0)
578 {
579 memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
580 memset(&TmpTrack, 0, sizeof(TmpTrack));
581 active_track = -1;
582 }
583
584 if(!MDFN_IsFIROPSafe(args[0]))
585 {
586 throw(MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting.\n"), args[0].c_str()));
587 }
588
589 std::string efn = MDFN_EvalFIP(base_dir, args[0]);
590 TmpTrack.fp = new FileStream(efn.c_str(), MODE_READ);
591 TmpTrack.FirstFileInstance = 1;
592
593 if(image_memcache)
594 TmpTrack.fp = new MemoryStream(TmpTrack.fp);
595
596 if(!strcasecmp(args[1].c_str(), "BINARY"))
597 {
598 //TmpTrack.Format = TRACK_FORMAT_DATA;
599 //struct stat stat_buf;
600 //fstat(fileno(TmpTrack.fp), &stat_buf);
601 //TmpTrack.sectors = stat_buf.st_size; // / 2048;
602 }
603 else if(!strcasecmp(args[1].c_str(), "OGG") || !strcasecmp(args[1].c_str(), "VORBIS") || !strcasecmp(args[1].c_str(), "WAVE") || !strcasecmp(args[1].c_str(), "WAV") || !strcasecmp(args[1].c_str(), "PCM")
604 || !strcasecmp(args[1].c_str(), "MPC") || !strcasecmp(args[1].c_str(), "MP+"))
605 {
606 TmpTrack.AReader = AR_Open(TmpTrack.fp);
607
608 if(!TmpTrack.AReader)
609 {
610 throw(MDFN_Error(0, _("Unsupported audio track file format: %s\n"), args[0].c_str()));
611 }
612 }
613 else
614 {
615 throw(MDFN_Error(0, _("Unsupported track format: %s\n"), args[1].c_str()));
616 }
617 }
618 else if(cmdbuf == "TRACK")
619 {
620 if(active_track >= 0)
621 {
622 memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
623 TmpTrack.FirstFileInstance = 0;
624 TmpTrack.pregap = 0;
625 TmpTrack.pregap_dv = 0;
626 TmpTrack.postgap = 0;
627 TmpTrack.index[0] = -1;
628 TmpTrack.index[1] = 0;
629 }
630 active_track = atoi(args[0].c_str());
631
632 if(active_track < FirstTrack)
633 FirstTrack = active_track;
634 if(active_track > LastTrack)
635 LastTrack = active_track;
636
637 int format_lookup;
638 for(format_lookup = 0; format_lookup < _DI_FORMAT_COUNT; format_lookup++)
639 {
640 if(!strcasecmp(args[1].c_str(), DI_CUE_Strings[format_lookup]))
641 {
642 TmpTrack.DIFormat = format_lookup;
643 break;
644 }
645 }
646
647 if(format_lookup == _DI_FORMAT_COUNT)
648 {
649 throw(MDFN_Error(0, _("Invalid track format: %s\n"), args[1].c_str()));
650 }
651
652 if(active_track < 0 || active_track > 99)
653 {
654 throw(MDFN_Error(0, _("Invalid track number: %d\n"), active_track));
655 }
656 }
657 else if(cmdbuf == "INDEX")
658 {
659 if(active_track >= 0)
660 {
661 unsigned int m,s,f;
662
663 if(sscanf(args[1].c_str(), "%u:%u:%u", &m, &s, &f) != 3)
664 {
665 throw MDFN_Error(0, _("Malformed m:s:f time in \"%s\" directive: %s"), cmdbuf.c_str(), args[0].c_str());
666 }
667
668 if(!strcasecmp(args[0].c_str(), "01") || !strcasecmp(args[0].c_str(), "1"))
669 TmpTrack.index[1] = (m * 60 + s) * 75 + f;
670 else if(!strcasecmp(args[0].c_str(), "00") || !strcasecmp(args[0].c_str(), "0"))
671 TmpTrack.index[0] = (m * 60 + s) * 75 + f;
672 }
673 }
674 else if(cmdbuf == "PREGAP")
675 {
676 if(active_track >= 0)
677 {
678 unsigned int m,s,f;
679
680 if(sscanf(args[0].c_str(), "%u:%u:%u", &m, &s, &f) != 3)
681 {
682 throw MDFN_Error(0, _("Malformed m:s:f time in \"%s\" directive: %s"), cmdbuf.c_str(), args[0].c_str());
683 }
684
685 TmpTrack.pregap = (m * 60 + s) * 75 + f;
686 }
687 }
688 else if(cmdbuf == "POSTGAP")
689 {
690 if(active_track >= 0)
691 {
692 unsigned int m,s,f;
693
694 if(sscanf(args[0].c_str(), "%u:%u:%u", &m, &s, &f) != 3)
695 {
696 throw MDFN_Error(0, _("Malformed m:s:f time in \"%s\" directive: %s"), cmdbuf.c_str(), args[0].c_str());
697 }
698
699 TmpTrack.postgap = (m * 60 + s) * 75 + f;
700 }
701 }
702 else if(cmdbuf == "REM")
703 {
704
705 }
706 else if(cmdbuf == "FLAGS")
707 {
708 TmpTrack.subq_control &= ~(SUBQ_CTRLF_PRE | SUBQ_CTRLF_DCP | SUBQ_CTRLF_4CH);
709 for(unsigned i = 0; i < argcount; i++)
710 {
711 if(args[i] == "DCP")
712 {
713 TmpTrack.subq_control |= SUBQ_CTRLF_DCP;
714 }
715 else if(args[i] == "4CH")
716 {
717 TmpTrack.subq_control |= SUBQ_CTRLF_4CH;
718 }
719 else if(args[i] == "PRE")
720 {
721 TmpTrack.subq_control |= SUBQ_CTRLF_PRE;
722 }
723 else if(args[i] == "SCMS")
724 {
725 // Not implemented, likely pointless. PROBABLY indicates that the copy bit of the subchannel Q control field is supposed to
726 // alternate between 1 and 0 at 9.375 Hz(four 1, four 0, four 1, four 0, etc.).
727 }
728 else
729 {
730 throw MDFN_Error(0, _("Unknown CUE sheet \"FLAGS\" directive flag \"%s\".\n"), args[i].c_str());
731 }
732 }
733 }
734 else if(cmdbuf == "CDTEXTFILE" || cmdbuf == "CATALOG" || cmdbuf == "ISRC" ||
735 cmdbuf == "TITLE" || cmdbuf == "PERFORMER" || cmdbuf == "SONGWRITER")
736 log_cb(RETRO_LOG_ERROR, "Unsupported CUE sheet directive: \"%s\".\n", cmdbuf.c_str());
737 else
738 {
739 throw MDFN_Error(0, _("Unknown CUE sheet directive \"%s\".\n"), cmdbuf.c_str());
740 }
741 } // end of CUE sheet handling
742 } // end of fgets() loop
743
744 if(active_track >= 0)
745 memcpy(&Tracks[active_track], &TmpTrack, sizeof(TmpTrack));
746
747 if(FirstTrack > LastTrack)
748 throw(MDFN_Error(0, _("No tracks found!\n")));
749
750 NumTracks = 1 + LastTrack - FirstTrack;
751
752 int32 RunningLBA = 0;
753 int32 LastIndex = 0;
754 long FileOffset = 0;
755
756 for(int x = FirstTrack; x < (FirstTrack + NumTracks); x++)
757 {
758 if(Tracks[x].DIFormat == DI_FORMAT_AUDIO)
759 Tracks[x].subq_control &= ~SUBQ_CTRLF_DATA;
760 else
761 Tracks[x].subq_control |= SUBQ_CTRLF_DATA;
762
763 if(!IsTOC) // TOC-format disc_type calculation is handled differently.
764 {
765 switch(Tracks[x].DIFormat)
766 {
767 default: break;
768
769 case DI_FORMAT_MODE2:
770 case DI_FORMAT_MODE2_FORM1:
771 case DI_FORMAT_MODE2_FORM2:
772 case DI_FORMAT_MODE2_RAW:
773 disc_type = DISC_TYPE_CD_XA;
774 break;
775 }
776 }
777
778 if(IsTOC)
779 {
780 RunningLBA += Tracks[x].pregap;
781 Tracks[x].LBA = RunningLBA;
782 RunningLBA += Tracks[x].sectors;
783 RunningLBA += Tracks[x].postgap;
784 }
785 else // else handle CUE sheet...
786 {
787 if(Tracks[x].FirstFileInstance)
788 {
789 LastIndex = 0;
790 FileOffset = 0;
791 }
792
793 RunningLBA += Tracks[x].pregap;
794
795 Tracks[x].pregap_dv = 0;
796
797 if(Tracks[x].index[0] != -1)
798 Tracks[x].pregap_dv = Tracks[x].index[1] - Tracks[x].index[0];
799
800 FileOffset += Tracks[x].pregap_dv * DI_Size_Table[Tracks[x].DIFormat];
801
802 RunningLBA += Tracks[x].pregap_dv;
803
804 Tracks[x].LBA = RunningLBA;
805
806 // Make sure FileOffset this is set before the call to GetSectorCount()
807 Tracks[x].FileOffset = FileOffset;
808 Tracks[x].sectors = GetSectorCount(&Tracks[x]);
809
810 if((x + 1) >= (FirstTrack + NumTracks) || Tracks[x+1].FirstFileInstance)
811 {
812
813 }
814 else
815 {
816 // Fix the sector count if we have multiple tracks per one binary image file.
817 if(Tracks[x + 1].index[0] == -1)
818 Tracks[x].sectors = Tracks[x + 1].index[1] - Tracks[x].index[1];
819 else
820 Tracks[x].sectors = Tracks[x + 1].index[0] - Tracks[x].index[1]; //Tracks[x + 1].index - Tracks[x].index;
821 }
822
823 //printf("Poo: %d %d\n", x, Tracks[x].sectors);
824 RunningLBA += Tracks[x].sectors;
825 RunningLBA += Tracks[x].postgap;
826
827 //printf("%d, %ld %d %d %d %d\n", x, FileOffset, Tracks[x].index, Tracks[x].pregap, Tracks[x].sectors, Tracks[x].LBA);
828
829 FileOffset += Tracks[x].sectors * DI_Size_Table[Tracks[x].DIFormat];
830 } // end to cue sheet handling
831 } // end to track loop
832
833 total_sectors = RunningLBA;
834
835 //
836 // Load SBI file, if present
837 //
838 if(!IsTOC)
839 {
840 const char *sbi_path = NULL;
841 char sbi_ext[4] = { 's', 'b', 'i', 0 };
842
843 if(file_ext.length() == 4 && file_ext[0] == '.')
844 {
845 unsigned i;
846 for(i = 0; i < 3; i++)
847 {
848 if(file_ext[1 + i] >= 'A' && file_ext[1 + i] <= 'Z')
849 sbi_ext[i] += 'A' - 'a';
850 }
851 }
852
853 sbi_path = MDFN_EvalFIP(base_dir, file_base + std::string(".") + std::string(sbi_ext), true).c_str();
854
855 if (path_is_valid(sbi_path))
856 LoadSBI(sbi_path);
857 }
858 }
859
860 void CDAccess_Image::Cleanup(void)
861 {
862 int32_t track;
863
864 for(track = 0; track < 100; track++)
865 {
866 CDRFILE_TRACK_INFO *this_track = &Tracks[track];
867
868 if(this_track->FirstFileInstance)
869 {
870 if(Tracks[track].AReader)
871 {
872 delete Tracks[track].AReader;
873 Tracks[track].AReader = NULL;
874 }
875
876 if(this_track->fp)
877 {
878 delete this_track->fp;
879 this_track->fp = NULL;
880 }
881 }
882 }
883 }
884
885 CDAccess_Image::CDAccess_Image(const char *path, bool image_memcache) : NumTracks(0), FirstTrack(0), LastTrack(0), total_sectors(0)
886 {
887 memset(Tracks, 0, sizeof(Tracks));
888
889 ImageOpen(path, image_memcache);
890 }
891
892 CDAccess_Image::~CDAccess_Image()
893 {
894 Cleanup();
895 }
896
897 void CDAccess_Image::Read_Raw_Sector(uint8 *buf, int32 lba)
898 {
899 int32_t track;
900 uint8_t SimuQ[0xC];
901 bool TrackFound = FALSE;
902
903 memset(buf + 2352, 0, 96);
904
905 MakeSubPQ(lba, buf + 2352);
906
907 subq_deinterleave(buf + 2352, SimuQ);
908
909 for(track = FirstTrack; track < (FirstTrack + NumTracks); track++)
910 {
911 CDRFILE_TRACK_INFO *ct = &Tracks[track];
912
913 if(lba >= (ct->LBA - ct->pregap_dv - ct->pregap) && lba < (ct->LBA + ct->sectors + ct->postgap))
914 {
915 TrackFound = TRUE;
916
917 // Handle pregap and postgap reading
918 if(lba < (ct->LBA - ct->pregap_dv) || lba >= (ct->LBA + ct->sectors))
919 {
920 //printf("Pre/post-gap read, LBA=%d(LBA-track_start_LBA=%d)\n", lba, lba - ct->LBA);
921 memset(buf, 0, 2352); // Null sector data, per spec
922 }
923 else
924 {
925 if(ct->AReader)
926 {
927 int16 AudioBuf[588 * 2];
928 int frames_read = ct->AReader->Read((ct->FileOffset / 4) + (lba - ct->LBA) * 588, AudioBuf, 588);
929
930 ct->LastSamplePos += frames_read;
931
932 if(frames_read < 0 || frames_read > 588) // This shouldn't happen.
933 {
934 printf("Error: frames_read out of range: %d\n", frames_read);
935 frames_read = 0;
936 }
937
938 if(frames_read < 588)
939 memset((uint8 *)AudioBuf + frames_read * 2 * sizeof(int16), 0, (588 - frames_read) * 2 * sizeof(int16));
940
941 for(int i = 0; i < 588 * 2; i++)
942 MDFN_en16lsb(buf + i * 2, AudioBuf[i]);
943 }
944 else // Binary, woo.
945 {
946 long SeekPos = ct->FileOffset;
947 long LBARelPos = lba - ct->LBA;
948
949 SeekPos += LBARelPos * DI_Size_Table[ct->DIFormat];
950
951 if(ct->SubchannelMode)
952 SeekPos += 96 * (lba - ct->LBA);
953
954 ct->fp->seek(SeekPos, SEEK_SET);
955
956 switch(ct->DIFormat)
957 {
958 case DI_FORMAT_AUDIO:
959 ct->fp->read(buf, 2352);
960
961 if(ct->RawAudioMSBFirst)
962 Endian_A16_Swap(buf, 588 * 2);
963 break;
964
965 case DI_FORMAT_MODE1:
966 ct->fp->read(buf + 12 + 3 + 1, 2048);
967 encode_mode1_sector(lba + 150, buf);
968 break;
969
970 case DI_FORMAT_MODE1_RAW:
971 case DI_FORMAT_MODE2_RAW:
972 ct->fp->read(buf, 2352);
973 break;
974
975 case DI_FORMAT_MODE2:
976 ct->fp->read(buf + 16, 2336);
977 encode_mode2_sector(lba + 150, buf);
978 break;
979
980
981 // FIXME: M2F1, M2F2, does sub-header come before or after user data(standards say before, but I wonder
982 // about cdrdao...).
983 case DI_FORMAT_MODE2_FORM1:
984 ct->fp->read(buf + 24, 2048);
985 //encode_mode2_form1_sector(lba + 150, buf);
986 break;
987
988 case DI_FORMAT_MODE2_FORM2:
989 ct->fp->read(buf + 24, 2324);
990 //encode_mode2_form2_sector(lba + 150, buf);
991 break;
992
993 }
994
995 if(ct->SubchannelMode)
996 ct->fp->read(buf + 2352, 96);
997 }
998 } // end if audible part of audio track read.
999 break;
1000 } // End if LBA is in range
1001 } // end track search loop
1002
1003 if(!TrackFound)
1004 throw(MDFN_Error(0, _("Could not find track for sector %u!"), lba));
1005
1006 #if 0
1007 if(qbuf[0] & 0x40)
1008 {
1009 uint8 dummy_buf[2352 + 96];
1010 bool any_mismatch = FALSE;
1011
1012 memcpy(dummy_buf + 16, buf + 16, 2048);
1013 memset(dummy_buf + 2352, 0, 96);
1014
1015 MakeSubPQ(lba, dummy_buf + 2352);
1016 encode_mode1_sector(lba + 150, dummy_buf);
1017
1018 for(int i = 0; i < 2352 + 96; i++)
1019 {
1020 if(dummy_buf[i] != buf[i])
1021 {
1022 printf("Mismatch at %d, %d: %02x:%02x; ", lba, i, dummy_buf[i], buf[i]);
1023 any_mismatch = TRUE;
1024 }
1025 }
1026 if(any_mismatch)
1027 puts("\n");
1028 }
1029 #endif
1030
1031 //subq_deinterleave(buf + 2352, qbuf);
1032 //printf("%02x\n", qbuf[0]);
1033 //printf("%02x\n", buf[12 + 3]);
1034 }
1035
1036 // Note: this function makes use of the current contents(as in |=) in SubPWBuf.
1037 void CDAccess_Image::MakeSubPQ(int32 lba, uint8 *SubPWBuf)
1038 {
1039 unsigned i;
1040 uint8_t buf[0xC], adr, control;
1041 int32_t track;
1042 uint32_t lba_relative;
1043 uint32_t ma, sa, fa;
1044 uint32_t m, s, f;
1045 uint8_t pause_or = 0x00;
1046 bool track_found = FALSE;
1047
1048 for(track = FirstTrack; track < (FirstTrack + NumTracks); track++)
1049 {
1050 if(lba >= (Tracks[track].LBA - Tracks[track].pregap_dv - Tracks[track].pregap) && lba < (Tracks[track].LBA + Tracks[track].sectors + Tracks[track].postgap))
1051 {
1052 track_found = TRUE;
1053 break;
1054 }
1055 }
1056
1057 //printf("%d %d\n", Tracks[1].LBA, Tracks[1].sectors);
1058
1059 if(!track_found)
1060 {
1061 printf("MakeSubPQ error for sector %u!", lba);
1062 track = FirstTrack;
1063 }
1064
1065 lba_relative = abs((int32)lba - Tracks[track].LBA);
1066
1067 f = (lba_relative % 75);
1068 s = ((lba_relative / 75) % 60);
1069 m = (lba_relative / 75 / 60);
1070
1071 fa = (lba + 150) % 75;
1072 sa = ((lba + 150) / 75) % 60;
1073 ma = ((lba + 150) / 75 / 60);
1074
1075 adr = 0x1; // Q channel data encodes position
1076 control = Tracks[track].subq_control;
1077
1078 // Handle pause(D7 of interleaved subchannel byte) bit, should be set to 1 when in pregap or postgap.
1079 if((lba < Tracks[track].LBA) || (lba >= Tracks[track].LBA + Tracks[track].sectors))
1080 {
1081 //printf("pause_or = 0x80 --- %d\n", lba);
1082 pause_or = 0x80;
1083 }
1084
1085 // Handle pregap between audio->data track
1086 {
1087 int32_t pg_offset = (int32)lba - Tracks[track].LBA;
1088
1089 // If we're more than 2 seconds(150 sectors) from the real "start" of the track/INDEX 01, and the track is a data track,
1090 // and the preceding track is an audio track, encode it as audio(by taking the SubQ control field from the preceding track).
1091 //
1092 // TODO: Look into how we're supposed to handle subq control field in the four combinations of track types(data/audio).
1093 //
1094 if(pg_offset < -150)
1095 {
1096 if((Tracks[track].subq_control & SUBQ_CTRLF_DATA) && (FirstTrack < track) && !(Tracks[track - 1].subq_control & SUBQ_CTRLF_DATA))
1097 {
1098 //printf("Pregap part 1 audio->data: lba=%d track_lba=%d\n", lba, Tracks[track].LBA);
1099 control = Tracks[track - 1].subq_control;
1100 }
1101 }
1102 }
1103
1104 memset(buf, 0, 0xC);
1105 buf[0] = (adr << 0) | (control << 4);
1106 buf[1] = U8_to_BCD(track);
1107
1108 if(lba < Tracks[track].LBA) // Index is 00 in pregap
1109 buf[2] = U8_to_BCD(0x00);
1110 else
1111 buf[2] = U8_to_BCD(0x01);
1112
1113 /* Track relative MSF address */
1114 buf[3] = U8_to_BCD(m);
1115 buf[4] = U8_to_BCD(s);
1116 buf[5] = U8_to_BCD(f);
1117 buf[6] = 0;
1118 /* Absolute MSF address */
1119 buf[7] = U8_to_BCD(ma);
1120 buf[8] = U8_to_BCD(sa);
1121 buf[9] = U8_to_BCD(fa);
1122
1123 subq_generate_checksum(buf);
1124
1125 if(!SubQReplaceMap.empty())
1126 {
1127 //printf("%d\n", lba);
1128 std::map<uint32, cpp11_array_doodad>::const_iterator it = SubQReplaceMap.find(LBA_to_ABA(lba));
1129
1130 if(it != SubQReplaceMap.end())
1131 {
1132 //printf("Replace: %d\n", lba);
1133 memcpy(buf, it->second.data, 12);
1134 }
1135 }
1136
1137 for (i = 0; i < 96; i++)
1138 SubPWBuf[i] |= (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | pause_or;
1139 }
1140
1141 void CDAccess_Image::Read_TOC(TOC *toc)
1142 {
1143 unsigned i;
1144
1145 TOC_Clear(toc);
1146
1147 toc->first_track = FirstTrack;
1148 toc->last_track = FirstTrack + NumTracks - 1;
1149 toc->disc_type = disc_type;
1150
1151 for(i = toc->first_track; i <= toc->last_track; i++)
1152 {
1153 toc->tracks[i].lba = Tracks[i].LBA;
1154 toc->tracks[i].adr = ADR_CURPOS;
1155 toc->tracks[i].control = Tracks[i].subq_control;
1156 }
1157
1158 toc->tracks[100].lba = total_sectors;
1159 toc->tracks[100].adr = ADR_CURPOS;
1160 toc->tracks[100].control = toc->tracks[toc->last_track].control & 0x4;
1161
1162 // Convenience leadout track duplication.
1163 if(toc->last_track < 99)
1164 toc->tracks[toc->last_track + 1] = toc->tracks[100];
1165 }
1166
1167 void CDAccess_Image::Eject(bool eject_status)
1168 {
1169
1170 }
0 #ifndef __MDFN_CDACCESS_IMAGE_H
1 #define __MDFN_CDACCESS_IMAGE_H
2
3 #include <map>
4
5 class Stream;
6 class AudioReader;
7
8 struct CDRFILE_TRACK_INFO
9 {
10 int32_t LBA;
11
12 uint32_t DIFormat;
13 uint8_t subq_control;
14
15 int32_t pregap;
16 int32_t pregap_dv;
17
18 int32_t postgap;
19
20 int32_t index[2];
21
22 int32_t sectors; // Not including pregap sectors!
23 Stream *fp;
24 bool FirstFileInstance;
25 bool RawAudioMSBFirst;
26 long FileOffset;
27 unsigned int SubchannelMode;
28
29 uint32_t LastSamplePos;
30
31 AudioReader *AReader;
32 };
33
34 class CDAccess_Image : public CDAccess
35 {
36 public:
37
38 CDAccess_Image(const char *path, bool image_memcache);
39 virtual ~CDAccess_Image();
40
41 virtual void Read_Raw_Sector(uint8_t *buf, int32_t lba);
42
43 virtual void Read_TOC(TOC *toc);
44
45 virtual void Eject(bool eject_status);
46 private:
47
48 int32_t NumTracks;
49 int32_t FirstTrack;
50 int32_t LastTrack;
51 int32_t total_sectors;
52 uint8_t disc_type;
53 CDRFILE_TRACK_INFO Tracks[100]; // Track #0(HMM?) through 99
54
55 struct cpp11_array_doodad
56 {
57 uint8 data[12];
58 };
59
60 std::map<uint32, cpp11_array_doodad> SubQReplaceMap;
61
62 std::string base_dir;
63
64 void ImageOpen(const char *path, bool image_memcache);
65 int LoadSBI(const char* sbi_path);
66 void Cleanup(void);
67
68 // MakeSubPQ will OR the simulated P and Q subchannel data into SubPWBuf.
69 void MakeSubPQ(int32_t lba, uint8_t *SubPWBuf);
70
71 void ParseTOCFileLineInfo(CDRFILE_TRACK_INFO *track, const int tracknum, const std::string &filename, const char *binoffset, const char *msfoffset, const char *length, bool image_memcache, std::map<std::string, Stream*> &toc_streamcache);
72 uint32_t GetSectorCount(CDRFILE_TRACK_INFO *track);
73 };
74
75
76 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * Subchannel Q CRC Code: Copyright (C) 1998 Andreas Mueller <mueller@daneb.ping.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19 #include "CDUtility.h"
20 #include "edc_crc32.h"
21 #include "galois.h"
22 #include "l-ec.h"
23 #include "recover-raw.h"
24 #include "lec.h"
25
26 #include <assert.h>
27
28 // lookup table for crc calculation
29 static uint16_t subq_crctab[256] =
30 {
31 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108,
32 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, 0x1231, 0x0210,
33 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, 0x9339, 0x8318, 0xB37B,
34 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, 0x2462, 0x3443, 0x0420, 0x1401,
35 0x64E6, 0x74C7, 0x44A4, 0x5485, 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE,
36 0xF5CF, 0xC5AC, 0xD58D, 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6,
37 0x5695, 0x46B4, 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D,
38 0xC7BC, 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
39 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, 0x5AF5,
40 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, 0xDBFD, 0xCBDC,
41 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, 0x6CA6, 0x7C87, 0x4CE4,
42 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD,
43 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13,
44 0x2E32, 0x1E51, 0x0E70, 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A,
45 0x9F59, 0x8F78, 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E,
46 0xE16F, 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
47 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, 0x02B1,
48 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, 0xB5EA, 0xA5CB,
49 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, 0x34E2, 0x24C3, 0x14A0,
50 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xA7DB, 0xB7FA, 0x8799, 0x97B8,
51 0xE75F, 0xF77E, 0xC71D, 0xD73C, 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657,
52 0x7676, 0x4615, 0x5634, 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9,
53 0xB98A, 0xA9AB, 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882,
54 0x28A3, 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
55 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, 0xFD2E,
56 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, 0x7C26, 0x6C07,
57 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, 0xEF1F, 0xFF3E, 0xCF5D,
58 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, 0x6E17, 0x7E36, 0x4E55, 0x5E74,
59 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
60 };
61
62
63 static uint8_t scramble_table[2352 - 12];
64
65 static bool CDUtility_Inited = false;
66
67 static void InitScrambleTable(void)
68 {
69 unsigned i, b;
70 unsigned cv = 1;
71
72 for(i = 12; i < 2352; i++)
73 {
74 unsigned char z = 0;
75
76 for(b = 0; b < 8; b++)
77 {
78 z |= (cv & 1) << b;
79
80 int feedback = ((cv >> 1) & 1) ^ (cv & 1);
81 cv = (cv >> 1) | (feedback << 14);
82 }
83
84 scramble_table[i - 12] = z;
85 }
86 }
87
88 void CDUtility_Init(void)
89 {
90 if(!CDUtility_Inited)
91 {
92 Init_LEC_Correct();
93
94 InitScrambleTable();
95 lec_tables_init();
96
97 CDUtility_Inited = true;
98 }
99 }
100
101 void encode_mode0_sector(uint32_t aba, uint8_t *sector_data)
102 {
103 CDUtility_Init();
104
105 lec_encode_mode0_sector(aba, sector_data);
106 }
107
108 void encode_mode1_sector(uint32_t aba, uint8_t *sector_data)
109 {
110 CDUtility_Init();
111
112 lec_encode_mode1_sector(aba, sector_data);
113 }
114
115 void encode_mode2_sector(uint32_t aba, uint8_t *sector_data)
116 {
117 CDUtility_Init();
118
119 lec_encode_mode2_sector(aba, sector_data);
120 }
121
122 void encode_mode2_form1_sector(uint32_t aba, uint8_t *sector_data)
123 {
124 CDUtility_Init();
125
126 lec_encode_mode2_form1_sector(aba, sector_data);
127 }
128
129 void encode_mode2_form2_sector(uint32_t aba, uint8_t *sector_data)
130 {
131 CDUtility_Init();
132
133 lec_encode_mode2_form2_sector(aba, sector_data);
134 }
135
136 bool edc_check(const uint8_t *sector_data, bool xa)
137 {
138 CDUtility_Init();
139
140 return(CheckEDC(sector_data, xa));
141 }
142
143 bool edc_lec_check_and_correct(uint8_t *sector_data, bool xa)
144 {
145 CDUtility_Init();
146
147 return(ValidateRawSector(sector_data, xa));
148 }
149
150
151 bool subq_check_checksum(const uint8_t *SubQBuf)
152 {
153 unsigned i;
154 uint16_t crc = 0;
155 uint16_t stored_crc = 0;
156
157 stored_crc = SubQBuf[0xA] << 8;
158 stored_crc |= SubQBuf[0xB];
159
160 for(i = 0; i < 0xA; i++)
161 crc = subq_crctab[(crc >> 8) ^ SubQBuf[i]] ^ (crc << 8);
162
163 crc = ~crc;
164
165 return(crc == stored_crc);
166 }
167
168 void subq_generate_checksum(uint8_t *buf)
169 {
170 unsigned i;
171 uint16_t crc = 0;
172
173 for(i = 0; i < 0xA; i++)
174 crc = subq_crctab[(crc >> 8) ^ buf[i]] ^ (crc << 8);
175
176 // Checksum
177 buf[0xa] = ~(crc >> 8);
178 buf[0xb] = ~(crc);
179 }
180
181 void subq_deinterleave(const uint8_t *SubPWBuf, uint8_t *qbuf)
182 {
183 unsigned i;
184
185 memset(qbuf, 0, 0xC);
186
187 for(i = 0; i < 96; i++)
188 qbuf[i >> 3] |= ((SubPWBuf[i] >> 6) & 0x1) << (7 - (i & 0x7));
189 }
190
191
192 // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
193 void subpw_deinterleave(const uint8_t *in_buf, uint8_t *out_buf)
194 {
195 unsigned ch, i;
196 assert(in_buf != out_buf);
197
198 memset(out_buf, 0, 96);
199
200 for(ch = 0; ch < 8; ch++)
201 {
202 for(i = 0; i < 96; i++)
203 out_buf[(ch * 12) + (i >> 3)] |= ((in_buf[i] >> (7 - ch)) & 0x1) << (7 - (i & 0x7));
204 }
205
206 }
207
208 // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
209 void subpw_interleave(const uint8_t *in_buf, uint8_t *out_buf)
210 {
211 unsigned d, bitpoodle, ch;
212
213 assert(in_buf != out_buf);
214
215 for(d = 0; d < 12; d++)
216 {
217 for(bitpoodle = 0; bitpoodle < 8; bitpoodle++)
218 {
219 uint8_t rawb = 0;
220
221 for(ch = 0; ch < 8; ch++)
222 rawb |= ((in_buf[ch * 12 + d] >> (7 - bitpoodle)) & 1) << (7 - ch);
223 out_buf[(d << 3) + bitpoodle] = rawb;
224 }
225 }
226 }
227
228 // NOTES ON LEADOUT AREA SYNTHESIS
229 //
230 // I'm not trusting that the "control" field for the TOC leadout entry will always be set properly, so | the control fields for the last track entry
231 // and the leadout entry together before extracting the D2 bit. Audio track->data leadout is fairly benign though maybe noisy(especially if we ever implement
232 // data scrambling properly), but data track->audio leadout could break things in an insidious manner for the more accurate drive emulation code).
233 //
234 void subpw_synth_leadout_lba(const struct TOC *toc, const int32_t lba, uint8_t* SubPWBuf)
235 {
236 unsigned i;
237 uint8_t buf[0xC];
238 uint32_t lba_relative;
239 uint32_t ma, sa, fa;
240 uint32_t m, s, f;
241
242 lba_relative = lba - toc->tracks[100].lba;
243
244 f = (lba_relative % 75);
245 s = ((lba_relative / 75) % 60);
246 m = (lba_relative / 75 / 60);
247
248 fa = (lba + 150) % 75;
249 sa = ((lba + 150) / 75) % 60;
250 ma = ((lba + 150) / 75 / 60);
251
252 uint8_t adr = 0x1; // Q channel data encodes position
253 uint8_t control = (toc->tracks[toc->last_track].control & 0x4) | toc->tracks[100].control;
254
255 memset(buf, 0, 0xC);
256 buf[0] = (adr << 0) | (control << 4);
257 buf[1] = 0xAA;
258 buf[2] = 0x01;
259
260 // Track relative MSF address
261 buf[3] = U8_to_BCD(m);
262 buf[4] = U8_to_BCD(s);
263 buf[5] = U8_to_BCD(f);
264
265 buf[6] = 0; // Zerroooo
266
267 // Absolute MSF address
268 buf[7] = U8_to_BCD(ma);
269 buf[8] = U8_to_BCD(sa);
270 buf[9] = U8_to_BCD(fa);
271
272 subq_generate_checksum(buf);
273
274 for(i = 0; i < 96; i++)
275 SubPWBuf[i] = (((buf[i >> 3] >> (7 - (i & 0x7))) & 1) ? 0x40 : 0x00) | 0x80;
276 }
277
278 void synth_leadout_sector_lba(const uint8_t mode, const struct TOC *toc, const int32_t lba, uint8_t* out_buf)
279 {
280 memset(out_buf, 0, 2352 + 96);
281 subpw_synth_leadout_lba(toc, lba, out_buf + 2352);
282
283 if((toc->tracks[toc->last_track].control | toc->tracks[100].control) & 0x4)
284 {
285 switch(mode)
286 {
287 default:
288 encode_mode0_sector(LBA_to_ABA(lba), out_buf);
289 break;
290
291 case 0x01:
292 encode_mode1_sector(LBA_to_ABA(lba), out_buf);
293 break;
294
295 case 0x02:
296 out_buf[18] = 0x20;
297 encode_mode2_form2_sector(LBA_to_ABA(lba), out_buf);
298 break;
299 }
300 }
301 }
302
303 void scrambleize_data_sector(uint8_t *sector_data)
304 {
305 unsigned i;
306 for(i = 12; i < 2352; i++)
307 sector_data[i] ^= scramble_table[i - 12];
308 }
0 #ifndef __MDFN_CDROM_CDUTILITY_H
1 #define __MDFN_CDROM_CDUTILITY_H
2
3 #include <stdint.h>
4 #include <string.h>
5
6 #include <boolean.h>
7 #include <retro_inline.h>
8
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12
13 enum
14 {
15 ADR_NOQINFO = 0x00,
16 ADR_CURPOS = 0x01,
17 ADR_MCN = 0x02,
18 ADR_ISRC = 0x03
19 };
20
21 struct TOC_Track
22 {
23 uint8_t adr;
24 uint8_t control;
25 uint32_t lba;
26 };
27
28 // SubQ control field flags.
29 enum
30 {
31 SUBQ_CTRLF_PRE = 0x01, // With 50/15us pre-emphasis.
32 SUBQ_CTRLF_DCP = 0x02, // Digital copy permitted.
33 SUBQ_CTRLF_DATA = 0x04, // Data track.
34 SUBQ_CTRLF_4CH = 0x08, // 4-channel CD-DA.
35 };
36
37 enum
38 {
39 DISC_TYPE_CDDA_OR_M1 = 0x00,
40 DISC_TYPE_CD_I = 0x10,
41 DISC_TYPE_CD_XA = 0x20
42 };
43
44 struct TOC
45 {
46 uint8_t first_track;
47 uint8_t last_track;
48 uint8_t disc_type;
49 struct TOC_Track tracks[100 + 1];
50 };
51
52 // Call once at app startup before creating any threads that could potentially cause re-entrancy to these functions.
53 // It will also be called automatically if needed for the first time a function in this namespace that requires
54 // the initialization function to be called is called, for potential
55 // usage in constructors of statically-declared objects.
56 void CDUtility_Init(void);
57
58 // Quick definitions here:
59 //
60 // ABA - Absolute block address, synonymous to absolute MSF
61 // aba = (m_a * 60 * 75) + (s_a * 75) + f_a
62 //
63 // LBA - Logical block address(related: data CDs are required to have a pregap of 2 seconds, IE 150 frames/sectors)
64 // lba = aba - 150
65
66 static INLINE void TOC_Clear(struct TOC *toc)
67 {
68 if (!toc)
69 return;
70
71 toc->first_track = 0;
72 toc->last_track = 0;
73 toc->disc_type = 0;
74
75 memset(toc->tracks, 0, sizeof(toc->tracks));
76 }
77
78 static INLINE int TOC_FindTrackByLBA(struct TOC *toc, uint32_t LBA)
79 {
80 int32_t track;
81
82 for(track = toc->first_track; track <= (toc->last_track + 1); track++)
83 {
84 if(track == (toc->last_track + 1))
85 {
86 if(LBA < toc->tracks[100].lba)
87 return(track - 1);
88 }
89 else
90 {
91 if(LBA < toc->tracks[track].lba)
92 return(track - 1);
93 }
94 }
95
96 return 0;
97 }
98
99 // Address conversion functions.
100 static INLINE uint32_t AMSF_to_ABA(int32_t m_a, int32_t s_a, int32_t f_a)
101 {
102 return(f_a + 75 * s_a + 75 * 60 * m_a);
103 }
104
105 static INLINE void ABA_to_AMSF(uint32_t aba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a)
106 {
107 *m_a = aba / 75 / 60;
108 *s_a = (aba - *m_a * 75 * 60) / 75;
109 *f_a = aba - (*m_a * 75 * 60) - (*s_a * 75);
110 }
111
112 static INLINE int32_t ABA_to_LBA(uint32_t aba)
113 {
114 return(aba - 150);
115 }
116
117 static INLINE uint32_t LBA_to_ABA(int32_t lba)
118 {
119 return(lba + 150);
120 }
121
122 static INLINE int32_t AMSF_to_LBA(uint8_t m_a, uint8_t s_a, uint8_t f_a)
123 {
124 return(ABA_to_LBA(AMSF_to_ABA(m_a, s_a, f_a)));
125 }
126
127 static INLINE void LBA_to_AMSF(int32_t lba, uint8_t *m_a, uint8_t *s_a, uint8_t *f_a)
128 {
129 ABA_to_AMSF(LBA_to_ABA(lba), m_a, s_a, f_a);
130 }
131
132 //
133 // BCD conversion functions
134 //
135 static INLINE bool BCD_is_valid(uint8_t bcd_number)
136 {
137 if((bcd_number & 0xF0) >= 0xA0)
138 return(false);
139
140 if((bcd_number & 0x0F) >= 0x0A)
141 return(false);
142
143 return(true);
144 }
145
146 static INLINE uint8_t BCD_to_U8(uint8_t bcd_number)
147 {
148 return( ((bcd_number >> 4) * 10) + (bcd_number & 0x0F) );
149 }
150
151 static INLINE uint8_t U8_to_BCD(uint8_t num)
152 {
153 return( ((num / 10) << 4) + (num % 10) );
154 }
155
156 // should always perform the conversion, even if the bcd number is invalid.
157 static INLINE bool BCD_to_U8_check(uint8_t bcd_number, uint8_t *out_number)
158 {
159 *out_number = BCD_to_U8(bcd_number);
160
161 if(!BCD_is_valid(bcd_number))
162 return(false);
163
164 return(true);
165 }
166
167 //
168 // Sector data encoding functions(to full 2352 bytes raw sector).
169 //
170 // sector_data must be able to contain at least 2352 bytes.
171 void encode_mode0_sector(uint32_t aba, uint8_t *sector_data);
172 void encode_mode1_sector(uint32_t aba, uint8_t *sector_data); // 2048 bytes of user data at offset 16
173 void encode_mode2_sector(uint32_t aba, uint8_t *sector_data); // 2336 bytes of user data at offset 16
174 void encode_mode2_form1_sector(uint32_t aba, uint8_t *sector_data); // 2048+8 bytes of user data at offset 16
175 void encode_mode2_form2_sector(uint32_t aba, uint8_t *sector_data); // 2324+8 bytes of user data at offset 16
176
177
178 // out_buf must be able to contain 2352+96 bytes.
179 // "mode" is only used if(toc.tracks[100].control & 0x4)
180 void synth_leadout_sector_lba(const uint8_t mode, const struct TOC *toc, const int32_t lba, uint8_t* out_buf);
181
182 //
183 // User data error detection and correction
184 //
185
186 // Check EDC of a mode 1 or mode 2 form 1 sector.
187 // Returns "true" if checksum is ok(matches).
188 // Returns "false" if checksum mismatch.
189 // sector_data should contain 2352 bytes of raw sector data.
190 bool edc_check(const uint8_t *sector_data, bool xa);
191
192 // Check EDC and L-EC data of a mode 1 or mode 2 form 1 sector, and correct bit errors if any exist.
193 // Returns "true" if errors weren't detected, or they were corrected succesfully.
194 // Returns "false" if errors couldn't be corrected.
195 // sector_data should contain 2352 bytes of raw sector data.
196 bool edc_lec_check_and_correct(uint8_t *sector_data, bool xa);
197
198 //
199 // Subchannel(Q in particular) functions
200 //
201
202 // Returns false on checksum mismatch, true on match.
203 bool subq_check_checksum(const uint8_t *subq_buf);
204
205 // Calculates the checksum of Q subchannel data(not including the checksum bytes of course ;)) from subq_buf, and stores it into the appropriate position
206 // in subq_buf.
207 void subq_generate_checksum(uint8_t *subq_buf);
208
209 // Deinterleaves 12 bytes of subchannel Q data from 96 bytes of interleaved subchannel PW data.
210 void subq_deinterleave(const uint8_t *subpw_buf, uint8_t *subq_buf);
211
212 // Deinterleaves 96 bytes of subchannel P-W data from 96 bytes of interleaved subchannel PW data.
213 void subpw_deinterleave(const uint8_t *in_buf, uint8_t *out_buf);
214
215 // Interleaves 96 bytes of subchannel P-W data from 96 bytes of uninterleaved subchannel PW data.
216 void subpw_interleave(const uint8_t *in_buf, uint8_t *out_buf);
217
218 // Extrapolates Q subchannel current position data from subq_input, with frame/sector delta position_delta, and writes to subq_output.
219 // Only valid for ADR_CURPOS.
220 // subq_input must pass subq_check_checksum().
221 // TODO
222 //void subq_extrapolate(const uint8_t *subq_input, int32_t position_delta, uint8_t *subq_output);
223
224 // (De)Scrambles data sector.
225 void scrambleize_data_sector(uint8_t *sector_data);
226
227 #ifdef __cplusplus
228 }
229 #endif
230
231 #endif
0 #include "../mednafen.h"
1 #include "SimpleFIFO.h"
2
3
4
5
0 #ifndef __MDFN_SIMPLEFIFO_H
1 #define __MDFN_SIMPLEFIFO_H
2
3 #include <vector>
4 #include <assert.h>
5
6 #include "../math_ops.h"
7
8 template<typename T>
9 class SimpleFIFO
10 {
11 public:
12
13 // Constructor
14 SimpleFIFO(uint32_t the_size) // Size should be a power of 2!
15 {
16 data.resize(round_up_pow2(the_size));
17 size = the_size;
18 read_pos = 0;
19 write_pos = 0;
20 in_count = 0;
21 }
22
23 // Destructor
24 INLINE ~SimpleFIFO()
25 {
26
27 }
28
29 INLINE void SaveStatePostLoad(void)
30 {
31 read_pos %= data.size();
32 write_pos %= data.size();
33 in_count %= (data.size() + 1);
34 }
35
36 #if 0
37 INLINE int StateAction(StateMem *sm, int load, int data_only, const char* sname)
38 {
39 SFORMAT StateRegs[] =
40 {
41 std::vector<T> data;
42 uint32_t size;
43
44 SFVAR(read_pos),
45 SFVAR(write_pos),
46 SFVAR(in_count),
47 SFEND;
48 }
49 int ret = MDFNSS_StateAction(sm, load, data_only, sname);
50
51 if(load)
52 {
53 read_pos %= data.size();
54 write_pos %= data.size();
55 in_count %= (data.size() + 1);
56 }
57
58 return(ret);
59 }
60 #endif
61
62 INLINE uint32_t CanRead(void)
63 {
64 return(in_count);
65 }
66
67 INLINE uint32_t CanWrite(void)
68 {
69 return(size - in_count);
70 }
71
72 INLINE T ReadUnit(bool peek = false)
73 {
74 T ret;
75
76 assert(in_count > 0);
77
78 ret = data[read_pos];
79
80 if(!peek)
81 {
82 read_pos = (read_pos + 1) & (data.size() - 1);
83 in_count--;
84 }
85
86 return(ret);
87 }
88
89 INLINE uint8_t ReadByte(bool peek = false)
90 {
91 assert(sizeof(T) == 1);
92
93 return(ReadUnit(peek));
94 }
95
96 INLINE void Write(const T *happy_data, uint32_t happy_count)
97 {
98 assert(CanWrite() >= happy_count);
99
100 while(happy_count)
101 {
102 data[write_pos] = *happy_data;
103
104 write_pos = (write_pos + 1) & (data.size() - 1);
105 in_count++;
106 happy_data++;
107 happy_count--;
108 }
109 }
110
111 INLINE void WriteUnit(const T& wr_data)
112 {
113 Write(&wr_data, 1);
114 }
115
116 INLINE void WriteByte(const T& wr_data)
117 {
118 assert(sizeof(T) == 1);
119 Write(&wr_data, 1);
120 }
121
122
123 INLINE void Flush(void)
124 {
125 read_pos = 0;
126 write_pos = 0;
127 in_count = 0;
128 }
129
130 //private:
131 std::vector<T> data;
132 uint32_t size;
133 uint32_t read_pos; // Read position
134 uint32_t write_pos; // Write position
135 uint32_t in_count; // Number of units in the FIFO
136 };
137
138
139 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 // AR_Open(), and AudioReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
18 // to it for as long as the AudioReader object exists.
19
20 // Don't allow exceptions to propagate into the vorbis/musepack/etc. libraries, as it could easily leave the state of the library's decoder "object" in an
21 // inconsistent state, which would cause all sorts of unfun when we try to destroy it while handling the exception farther up.
22
23 #include "../mednafen.h"
24 #include "audioreader.h"
25
26 #include "../tremor/ivorbisfile.h"
27
28 #include <string.h>
29 #include <errno.h>
30 #include <time.h>
31
32 #include "../general.h"
33 #include "../mednafen-endian.h"
34
35 AudioReader::AudioReader() : LastReadPos(0)
36 {
37
38 }
39
40 AudioReader::~AudioReader()
41 {
42
43 }
44
45 int64_t AudioReader::Read_(int16_t *buffer, int64_t frames)
46 {
47 abort();
48 return(false);
49 }
50
51 bool AudioReader::Seek_(int64_t frame_offset)
52 {
53 abort();
54 return(false);
55 }
56
57 int64_t AudioReader::FrameCount(void)
58 {
59 abort();
60 return(0);
61 }
62
63 class OggVorbisReader : public AudioReader
64 {
65 public:
66 OggVorbisReader(Stream *fp);
67 ~OggVorbisReader();
68
69 int64_t Read_(int16_t *buffer, int64_t frames);
70 bool Seek_(int64_t frame_offset);
71 int64_t FrameCount(void);
72
73 private:
74 OggVorbis_File ovfile;
75 };
76
77
78 static size_t iov_read_func(void *ptr, size_t size, size_t nmemb, void *user_data)
79 {
80 Stream *fw = (Stream*)user_data;
81
82 if(!size || !fw)
83 return(0);
84
85 return fw->read(ptr, size * nmemb, false) / size;
86 }
87
88 static int iov_seek_func(void *user_data, ogg_int64_t offset, int whence)
89 {
90 Stream *fw = (Stream*)user_data;
91
92 if (fw)
93 fw->seek(offset, whence);
94 return(0);
95 }
96
97 static int iov_close_func(void *user_data)
98 {
99 Stream *fw = (Stream*)user_data;
100
101 if (fw)
102 fw->close();
103 return(0);
104 }
105
106 static long iov_tell_func(void *user_data)
107 {
108 Stream *fw = (Stream*)user_data;
109
110 if (!fw)
111 return -1;
112
113 return fw->tell();
114 }
115
116 OggVorbisReader::OggVorbisReader(Stream *fp)
117 {
118 ov_callbacks cb;
119
120 memset(&cb, 0, sizeof(cb));
121 cb.read_func = iov_read_func;
122 cb.seek_func = iov_seek_func;
123 cb.close_func = iov_close_func;
124 cb.tell_func = iov_tell_func;
125
126 fp->seek(0, SEEK_SET);
127 if(ov_open_callbacks(fp, &ovfile, NULL, 0, cb))
128 throw(0);
129 }
130
131 OggVorbisReader::~OggVorbisReader()
132 {
133 ov_clear(&ovfile);
134 }
135
136 int64_t OggVorbisReader::Read_(int16_t *buffer, int64_t frames)
137 {
138 uint8 *tw_buf = (uint8 *)buffer;
139 int cursection = 0;
140 long toread = frames * sizeof(int16_t) * 2;
141
142 while(toread > 0)
143 {
144 long didread = ov_read(&ovfile, (char*)tw_buf, toread, &cursection);
145
146 if(didread == 0)
147 break;
148
149 tw_buf = (uint8 *)tw_buf + didread;
150 toread -= didread;
151 }
152
153 return(frames - toread / sizeof(int16_t) / 2);
154 }
155
156 bool OggVorbisReader::Seek_(int64_t frame_offset)
157 {
158 ov_pcm_seek(&ovfile, frame_offset);
159 return(true);
160 }
161
162 int64_t OggVorbisReader::FrameCount(void)
163 {
164 return(ov_pcm_total(&ovfile, -1));
165 }
166
167 AudioReader *AR_Open(Stream *fp)
168 {
169 return new OggVorbisReader(fp);
170 }
0 #ifndef __MDFN_AUDIOREADER_H
1 #define __MDFN_AUDIOREADER_H
2
3 #include "../Stream.h"
4
5 class AudioReader
6 {
7 public:
8 AudioReader();
9 virtual ~AudioReader();
10
11 virtual int64_t FrameCount(void);
12 INLINE int64_t Read(int64_t frame_offset, int16_t *buffer, int64_t frames)
13 {
14 int64_t ret;
15
16 if(LastReadPos != frame_offset)
17 {
18 //puts("SEEK");
19 if(!Seek_(frame_offset))
20 return(0);
21 LastReadPos = frame_offset;
22 }
23
24 ret = Read_(buffer, frames);
25 LastReadPos += ret;
26 return(ret);
27 }
28
29 private:
30 virtual int64_t Read_(int16_t *buffer, int64_t frames);
31 virtual bool Seek_(int64_t frame_offset);
32
33 int64_t LastReadPos;
34 };
35
36 // AR_Open(), and AudioReader, will NOT take "ownership" of the Stream object(IE it won't ever delete it). Though it does assume it has exclusive access
37 // to it for as long as the AudioReader object exists.
38 AudioReader *AR_Open(Stream *fp);
39
40 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../mednafen.h"
18 #include <string.h>
19 #include <sys/types.h>
20 #include "cdromif.h"
21 #include "CDAccess.h"
22 #include "../general.h"
23
24 #include <algorithm>
25 #include <rthreads/rthreads.h>
26 #include "../../libretro.h"
27
28 extern retro_log_printf_t log_cb;
29
30 enum
31 {
32 // Status/Error messages
33 CDIF_MSG_DONE = 0,
34 CDIF_MSG_INFO,
35 CDIF_MSG_FATAL_ERROR,
36
37 // Command messages.
38 CDIF_MSG_DIEDIEDIE,
39 CDIF_MSG_READ_SECTOR,
40 CDIF_MSG_EJECT
41 };
42
43 class CDIF_Message
44 {
45 public:
46
47 CDIF_Message();
48 CDIF_Message(unsigned int message_, uint32 arg0 = 0, uint32 arg1 = 0, uint32 arg2 = 0, uint32 arg3 = 0);
49 CDIF_Message(unsigned int message_, const std::string &str);
50 ~CDIF_Message();
51
52 unsigned int message;
53 uint32 args[4];
54 void *parg;
55 std::string str_message;
56 };
57
58 class CDIF_Queue
59 {
60 public:
61
62 CDIF_Queue();
63 ~CDIF_Queue();
64
65 bool Read(CDIF_Message *message, bool blocking = TRUE);
66
67 void Write(const CDIF_Message &message);
68
69 private:
70 std::queue<CDIF_Message> ze_queue;
71 slock_t *ze_mutex;
72 scond_t *ze_cond;
73 };
74
75
76 typedef struct
77 {
78 bool valid;
79 bool error;
80 uint32 lba;
81 uint8 data[2352 + 96];
82 } CDIF_Sector_Buffer;
83
84 /* TODO: prohibit copy constructor */
85 class CDIF_MT : public CDIF
86 {
87 public:
88
89 CDIF_MT(CDAccess *cda);
90 virtual ~CDIF_MT();
91
92 virtual void HintReadSector(uint32 lba);
93 virtual bool ReadRawSector(uint8 *buf, uint32 lba);
94 virtual bool ReadRawSectorPWOnly(uint8 *buf, uint32 lba, bool hint_fullread);
95
96 // Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
97 // Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
98 virtual bool Eject(bool eject_status);
99
100 // FIXME: Semi-private:
101 int ReadThreadStart(void);
102
103 private:
104
105 CDAccess *disc_cdaccess;
106 sthread_t *CDReadThread;
107
108 // Queue for messages to the read thread.
109 CDIF_Queue ReadThreadQueue;
110
111 // Queue for messages to the emu thread.
112 CDIF_Queue EmuThreadQueue;
113
114
115 enum { SBSize = 256 };
116 CDIF_Sector_Buffer SectorBuffers[SBSize];
117
118 uint32 SBWritePos;
119
120 slock_t *SBMutex;
121 scond_t *SBCond;
122
123 //
124 // Read-thread-only:
125 //
126 void RT_EjectDisc(bool eject_status, bool skip_actual_eject = false);
127
128 uint32 ra_lba;
129 int ra_count;
130 uint32 last_read_lba;
131 };
132
133 /* TODO: prohibit copy constructor */
134 class CDIF_ST : public CDIF
135 {
136 public:
137
138 CDIF_ST(CDAccess *cda);
139 virtual ~CDIF_ST();
140
141 virtual void HintReadSector(uint32 lba);
142 virtual bool ReadRawSector(uint8 *buf, uint32 lba);
143 virtual bool ReadRawSectorPWOnly(uint8 *buf, uint32 lba, bool hint_fullread);
144 virtual bool Eject(bool eject_status);
145
146 private:
147 CDAccess *disc_cdaccess;
148 };
149
150 CDIF::CDIF() : UnrecoverableError(false), DiscEjected(false)
151 {
152 TOC_Clear(&disc_toc);
153 }
154
155 CDIF::~CDIF()
156 {
157
158 }
159
160
161 CDIF_Message::CDIF_Message()
162 {
163 message = 0;
164
165 memset(args, 0, sizeof(args));
166 }
167
168 CDIF_Message::CDIF_Message(unsigned int message_, uint32 arg0, uint32 arg1, uint32 arg2, uint32 arg3)
169 {
170 message = message_;
171 args[0] = arg0;
172 args[1] = arg1;
173 args[2] = arg2;
174 args[3] = arg3;
175 }
176
177 CDIF_Message::CDIF_Message(unsigned int message_, const std::string &str)
178 {
179 message = message_;
180 str_message = str;
181 }
182
183 CDIF_Message::~CDIF_Message()
184 {
185
186 }
187
188 CDIF_Queue::CDIF_Queue()
189 {
190 ze_mutex = slock_new();
191 ze_cond = scond_new();
192 }
193
194 CDIF_Queue::~CDIF_Queue()
195 {
196 slock_free(ze_mutex);
197 scond_free(ze_cond);
198 }
199
200 // Returns FALSE if message not read, TRUE if it was read. Will always return TRUE if "blocking" is set.
201 // Will throw MDFN_Error if the read message code is CDIF_MSG_FATAL_ERROR
202 bool CDIF_Queue::Read(CDIF_Message *message, bool blocking)
203 {
204 bool ret = true;
205
206 slock_lock((slock_t*)ze_mutex);
207
208 if(blocking)
209 {
210 while(ze_queue.size() == 0) // while, not just if.
211 scond_wait((scond_t*)ze_cond, (slock_t*)ze_mutex);
212 }
213
214 if(ze_queue.size() == 0)
215 ret = false;
216 else
217 {
218 *message = ze_queue.front();
219 ze_queue.pop();
220 }
221
222 slock_unlock((slock_t*)ze_mutex);
223
224 if(ret && message->message == CDIF_MSG_FATAL_ERROR)
225 throw MDFN_Error(0, "%s", message->str_message.c_str());
226
227 return(ret);
228 }
229
230 void CDIF_Queue::Write(const CDIF_Message &message)
231 {
232 slock_lock((slock_t*)ze_mutex);
233
234 ze_queue.push(message);
235
236 scond_signal((scond_t*)ze_cond); // Signal while the mutex is held to prevent icky race conditions
237
238 slock_unlock((slock_t*)ze_mutex);
239 }
240
241
242 void CDIF_MT::RT_EjectDisc(bool eject_status, bool skip_actual_eject)
243 {
244 int32_t old_de = DiscEjected;
245
246 DiscEjected = eject_status;
247
248 if(old_de != DiscEjected)
249 {
250 if(!skip_actual_eject)
251 disc_cdaccess->Eject(eject_status);
252
253 if(!eject_status) // Re-read the TOC
254 {
255 disc_cdaccess->Read_TOC(&disc_toc);
256
257 if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
258 throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
259 }
260
261 SBWritePos = 0;
262 ra_lba = 0;
263 ra_count = 0;
264 last_read_lba = ~0U;
265 memset(SectorBuffers, 0, SBSize * sizeof(CDIF_Sector_Buffer));
266 }
267 }
268
269 struct RTS_Args
270 {
271 CDIF_MT *cdif_ptr;
272 };
273
274 static int ReadThreadStart_C(void *v_arg)
275 {
276 RTS_Args *args = (RTS_Args *)v_arg;
277
278 return args->cdif_ptr->ReadThreadStart();
279 }
280
281 int CDIF_MT::ReadThreadStart()
282 {
283 bool Running = TRUE;
284
285 DiscEjected = true;
286 SBWritePos = 0;
287 ra_lba = 0;
288 ra_count = 0;
289 last_read_lba = ~0U;
290
291 try
292 {
293 RT_EjectDisc(false, true);
294 }
295 catch(std::exception &e)
296 {
297 EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what())));
298 return(0);
299 }
300
301 EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE));
302
303 while(Running)
304 {
305 CDIF_Message msg;
306
307 // Only do a blocking-wait for a message if we don't have any sectors to read-ahead.
308 // MDFN_DispMessage("%d %d %d\n", last_read_lba, ra_lba, ra_count);
309 if(ReadThreadQueue.Read(&msg, ra_count ? FALSE : TRUE))
310 {
311 switch(msg.message)
312 {
313 case CDIF_MSG_DIEDIEDIE:
314 Running = FALSE;
315 break;
316
317 case CDIF_MSG_EJECT:
318 try
319 {
320 RT_EjectDisc(msg.args[0]);
321 EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_DONE));
322 }
323 catch(std::exception &e)
324 {
325 EmuThreadQueue.Write(CDIF_Message(CDIF_MSG_FATAL_ERROR, std::string(e.what())));
326 }
327 break;
328
329 case CDIF_MSG_READ_SECTOR:
330 {
331 static const int max_ra = 16;
332 static const int initial_ra = 1;
333 static const int speedmult_ra = 2;
334 uint32_t new_lba = msg.args[0];
335
336 assert((unsigned int)max_ra < (SBSize / 4));
337
338 if(last_read_lba != ~0U && new_lba == (last_read_lba + 1))
339 {
340 int how_far_ahead = ra_lba - new_lba;
341
342 if(how_far_ahead <= max_ra)
343 ra_count = std::min(speedmult_ra, 1 + max_ra - how_far_ahead);
344 else
345 ra_count++;
346 }
347 else if(new_lba != last_read_lba)
348 {
349 ra_lba = new_lba;
350 ra_count = initial_ra;
351 }
352
353 last_read_lba = new_lba;
354 }
355 break;
356 }
357 }
358
359 // Don't read >= the "end" of the disc, silly snake. Slither.
360 if(ra_count && ra_lba == disc_toc.tracks[100].lba)
361 {
362 ra_count = 0;
363 //printf("Ephemeral scarabs: %d!\n", ra_lba);
364 }
365
366 if(ra_count)
367 {
368 uint8_t tmpbuf[2352 + 96];
369 bool error_condition = false;
370
371 try
372 {
373 disc_cdaccess->Read_Raw_Sector(tmpbuf, ra_lba);
374 }
375 catch(std::exception &e)
376 {
377 log_cb(RETRO_LOG_ERROR, "Sector %u read error: %s\n", ra_lba, e.what());
378 memset(tmpbuf, 0, sizeof(tmpbuf));
379 error_condition = true;
380 }
381
382 slock_lock((slock_t*)SBMutex);
383
384 SectorBuffers[SBWritePos].lba = ra_lba;
385 memcpy(SectorBuffers[SBWritePos].data, tmpbuf, 2352 + 96);
386 SectorBuffers[SBWritePos].valid = TRUE;
387 SectorBuffers[SBWritePos].error = error_condition;
388 SBWritePos = (SBWritePos + 1) % SBSize;
389
390 scond_signal((scond_t*)SBCond);
391 slock_unlock((slock_t*)SBMutex);
392
393 ra_lba++;
394 ra_count--;
395 }
396 }
397
398 return(1);
399 }
400
401 CDIF_MT::CDIF_MT(CDAccess *cda) : disc_cdaccess(cda), CDReadThread(NULL), SBMutex(NULL), SBCond(NULL)
402 {
403 try
404 {
405 CDIF_Message msg;
406 RTS_Args s;
407
408 SBMutex = slock_new();
409 SBCond = scond_new();
410 UnrecoverableError = false;
411
412 s.cdif_ptr = this;
413
414 CDReadThread = sthread_create((void (*)(void*))ReadThreadStart_C, &s);
415 EmuThreadQueue.Read(&msg);
416 }
417 catch(...)
418 {
419 if(CDReadThread)
420 {
421 sthread_join((sthread_t*)CDReadThread);
422 CDReadThread = NULL;
423 }
424
425 if(SBMutex)
426 {
427 slock_free((slock_t*)SBMutex);
428 SBMutex = NULL;
429 }
430
431 if(SBCond)
432 {
433 scond_free((scond_t*)SBCond);
434 SBCond = NULL;
435 }
436
437 if(disc_cdaccess)
438 {
439 delete disc_cdaccess;
440 disc_cdaccess = NULL;
441 }
442
443 throw;
444 }
445 }
446
447
448 CDIF_MT::~CDIF_MT()
449 {
450 bool thread_deaded_failed = false;
451
452 try
453 {
454 ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_DIEDIEDIE));
455 }
456 catch(std::exception &e)
457 {
458 log_cb(RETRO_LOG_ERROR, "%s.\n", e.what());
459 thread_deaded_failed = true;
460 }
461
462 if(!thread_deaded_failed)
463 sthread_join((sthread_t*)CDReadThread);
464
465 if(SBMutex)
466 {
467 slock_free((slock_t*)SBMutex);
468 SBMutex = NULL;
469 }
470
471 if(disc_cdaccess)
472 {
473 delete disc_cdaccess;
474 disc_cdaccess = NULL;
475 }
476 }
477
478 bool CDIF::ValidateRawSector(uint8 *buf)
479 {
480 int mode = buf[12 + 3];
481
482 if(mode != 0x1 && mode != 0x2)
483 return(false);
484
485 if(!edc_lec_check_and_correct(buf, mode == 2))
486 return(false);
487
488 return(true);
489 }
490
491 bool CDIF_MT::ReadRawSector(uint8 *buf, uint32 lba)
492 {
493 bool found = FALSE;
494 bool error_condition = false;
495
496 if(UnrecoverableError)
497 {
498 memset(buf, 0, 2352 + 96);
499 return(false);
500 }
501
502 // This shouldn't happen, the emulated-system-specific CDROM emulation code should make sure the emulated program doesn't try
503 // to read past the last "real" sector of the disc.
504 if(lba >= disc_toc.tracks[100].lba)
505 {
506 printf("Attempt to read LBA %d, >= LBA %d\n", lba, disc_toc.tracks[100].lba);
507 return(FALSE);
508 }
509
510 ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
511
512 slock_lock((slock_t*)SBMutex);
513
514 do
515 {
516 int i;
517 for(i = 0; i < SBSize; i++)
518 {
519 if(SectorBuffers[i].valid && SectorBuffers[i].lba == lba)
520 {
521 error_condition = SectorBuffers[i].error;
522 memcpy(buf, SectorBuffers[i].data, 2352 + 96);
523 found = TRUE;
524 }
525 }
526
527 if(!found)
528 scond_wait((scond_t*)SBCond, (slock_t*)SBMutex);
529 } while(!found);
530
531 slock_unlock((slock_t*)SBMutex);
532
533 return(!error_condition);
534 }
535
536 bool CDIF_MT::ReadRawSectorPWOnly(uint8 *buf, uint32 lba, bool hint_fullread)
537 {
538 uint8 tmpbuf[2352 + 96];
539 bool ret;
540
541 if(UnrecoverableError)
542 {
543 memset(buf, 0, 96);
544 return(false);
545 }
546
547 // This shouldn't happen, the emulated-system-specific CDROM emulation code should make sure the emulated program doesn't try
548 // to read past the last "real" sector of the disc.
549 if(lba >= disc_toc.tracks[100].lba)
550 {
551 printf("Attempt to read LBA %d, >= LBA %d\n", lba, disc_toc.tracks[100].lba);
552 memset(buf, 0, 96);
553 return(FALSE);
554 }
555
556 ret = ReadRawSector(tmpbuf, lba);
557 memcpy(buf, tmpbuf + 2352, 96);
558
559 return ret;
560 }
561
562 void CDIF_MT::HintReadSector(uint32 lba)
563 {
564 if(UnrecoverableError)
565 return;
566
567 ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_READ_SECTOR, lba));
568 }
569
570 int CDIF::ReadSector(uint8* pBuf, uint32 lba, uint32 nSectors)
571 {
572 int ret = 0;
573
574 if(UnrecoverableError)
575 return(false);
576
577 while(nSectors--)
578 {
579 int mode;
580 uint8_t tmpbuf[2352 + 96];
581
582 if(!ReadRawSector(tmpbuf, lba))
583 {
584 puts("CDIF Raw Read error");
585 return(FALSE);
586 }
587
588 if(!ValidateRawSector(tmpbuf))
589 return(false);
590
591 mode = tmpbuf[12 + 3];
592
593 if(!ret)
594 ret = mode;
595
596 switch (mode)
597 {
598 case 1:
599 memcpy(pBuf, &tmpbuf[12 + 4], 2048);
600 break;
601 case 2:
602 memcpy(pBuf, &tmpbuf[12 + 4 + 8], 2048);
603 break;
604 default:
605 printf("CDIF_ReadSector() invalid sector type at LBA=%u\n", (unsigned int)lba);
606 return(false);
607 }
608
609 pBuf += 2048;
610 lba++;
611 }
612
613 return(ret);
614 }
615
616 bool CDIF_MT::Eject(bool eject_status)
617 {
618 if(UnrecoverableError)
619 return(false);
620
621 try
622 {
623 CDIF_Message msg;
624
625 ReadThreadQueue.Write(CDIF_Message(CDIF_MSG_EJECT, eject_status));
626 EmuThreadQueue.Read(&msg);
627 }
628 catch(std::exception &e)
629 {
630 log_cb(RETRO_LOG_ERROR, "Error on eject/insert attempt: %s\n", e.what());
631 return(false);
632 }
633
634 return(true);
635 }
636
637 // Single-threaded implementation follows.
638
639 CDIF_ST::CDIF_ST(CDAccess *cda) : disc_cdaccess(cda)
640 {
641 //puts("***WARNING USING SINGLE-THREADED CD READER***");
642
643 UnrecoverableError = false;
644 DiscEjected = false;
645
646 disc_cdaccess->Read_TOC(&disc_toc);
647
648 if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
649 throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
650 }
651
652 CDIF_ST::~CDIF_ST()
653 {
654 if(disc_cdaccess)
655 {
656 delete disc_cdaccess;
657 disc_cdaccess = NULL;
658 }
659 }
660
661 void CDIF_ST::HintReadSector(uint32 lba)
662 {
663 /* TODO: disc_cdaccess seek hint? (probably not, would require asynchronousitycamel) */
664 }
665
666 bool CDIF_ST::ReadRawSector(uint8 *buf, uint32 lba)
667 {
668 if(UnrecoverableError)
669 {
670 memset(buf, 0, 2352 + 96);
671 return(false);
672 }
673
674 try
675 {
676 disc_cdaccess->Read_Raw_Sector(buf, lba);
677 }
678 catch(std::exception &e)
679 {
680 log_cb(RETRO_LOG_ERROR, "Sector %u read error: %s\n", lba, e.what());
681 memset(buf, 0, 2352 + 96);
682 return(false);
683 }
684
685 return(true);
686 }
687
688 bool CDIF_ST::ReadRawSectorPWOnly(uint8 *buf, uint32 lba, bool hint_fullread)
689 {
690 uint8 tmpbuf[2352 + 96];
691 bool ret;
692
693 if(UnrecoverableError)
694 {
695 memset(buf, 0, 96);
696 return(false);
697 }
698
699 // This shouldn't happen, the emulated-system-specific CDROM emulation code should make sure the emulated program doesn't try
700 // to read past the last "real" sector of the disc.
701 if(lba >= disc_toc.tracks[100].lba)
702 {
703 printf("Attempt to read LBA %d, >= LBA %d\n", lba, disc_toc.tracks[100].lba);
704 memset(buf, 0, 96);
705 return(FALSE);
706 }
707
708 ret = ReadRawSector(tmpbuf, lba);
709 memcpy(buf, tmpbuf + 2352, 96);
710
711 return ret;
712 }
713
714 bool CDIF_ST::Eject(bool eject_status)
715 {
716 if(UnrecoverableError)
717 return(false);
718
719 try
720 {
721 int32_t old_de = DiscEjected;
722
723 DiscEjected = eject_status;
724
725 if(old_de != DiscEjected)
726 {
727 disc_cdaccess->Eject(eject_status);
728
729 if(!eject_status) // Re-read the TOC
730 {
731 disc_cdaccess->Read_TOC(&disc_toc);
732
733 if(disc_toc.first_track < 1 || disc_toc.last_track > 99 || disc_toc.first_track > disc_toc.last_track)
734 throw(MDFN_Error(0, _("TOC first(%d)/last(%d) track numbers bad."), disc_toc.first_track, disc_toc.last_track));
735 }
736 }
737 }
738 catch(std::exception &e)
739 {
740 log_cb(RETRO_LOG_ERROR, "%s\n", e.what());
741 return(false);
742 }
743
744 return(true);
745 }
746
747
748 class CDIF_Stream_Thing : public Stream
749 {
750 public:
751
752 CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 lba_arg, uint32 sector_count_arg);
753 ~CDIF_Stream_Thing();
754
755 virtual uint64 attributes(void);
756 virtual uint8 *map(void);
757 virtual void unmap(void);
758
759 virtual uint64 read(void *data, uint64 count, bool error_on_eos = true);
760 virtual void write(const void *data, uint64 count);
761
762 virtual void seek(int64 offset, int whence);
763 virtual int64 tell(void);
764 virtual int64 size(void);
765 virtual void close(void);
766
767 private:
768 CDIF *cdintf;
769 const uint32 start_lba;
770 const uint32 sector_count;
771 int64 position;
772 };
773
774 CDIF_Stream_Thing::CDIF_Stream_Thing(CDIF *cdintf_arg, uint32 start_lba_arg,
775 uint32 sector_count_arg) : cdintf(cdintf_arg), start_lba(start_lba_arg), sector_count(sector_count_arg)
776 {
777
778 }
779
780 CDIF_Stream_Thing::~CDIF_Stream_Thing()
781 {
782
783 }
784
785 uint64 CDIF_Stream_Thing::attributes(void)
786 {
787 return(ATTRIBUTE_READABLE | ATTRIBUTE_SEEKABLE);
788 }
789
790 uint8 *CDIF_Stream_Thing::map(void)
791 {
792 return NULL;
793 }
794
795 void CDIF_Stream_Thing::unmap(void)
796 {
797
798 }
799
800 uint64 CDIF_Stream_Thing::read(void *data, uint64 count, bool error_on_eos)
801 {
802 uint64_t rp;
803
804 if(count > (((uint64)sector_count * 2048) - position))
805 {
806 if(error_on_eos)
807 throw MDFN_Error(0, "EOF");
808
809 count = ((uint64)sector_count * 2048) - position;
810 }
811
812 if(!count)
813 return(0);
814
815 for(rp = position; rp < (position + count); rp = (rp &~ 2047) + 2048)
816 {
817 uint8_t buf[2048];
818
819 if(!cdintf->ReadSector(buf, start_lba + (rp / 2048), 1))
820 throw MDFN_Error(ErrnoHolder(EIO));
821
822 memcpy((uint8_t*)data + (rp - position),
823 buf + (rp & 2047),
824 std::min<uint64>(2048 - (rp & 2047),count - (rp - position))
825 );
826 }
827
828 position += count;
829
830 return count;
831 }
832
833 void CDIF_Stream_Thing::write(const void *data, uint64 count)
834 {
835 throw MDFN_Error(ErrnoHolder(EBADF));
836 }
837
838 void CDIF_Stream_Thing::seek(int64 offset, int whence)
839 {
840 int64 new_position;
841
842 switch(whence)
843 {
844 case SEEK_SET:
845 new_position = offset;
846 break;
847
848 case SEEK_CUR:
849 new_position = position + offset;
850 break;
851
852 case SEEK_END:
853 new_position = ((int64)sector_count * 2048) + offset;
854 break;
855 }
856
857 if(new_position < 0 || new_position > ((int64)sector_count * 2048))
858 throw MDFN_Error(ErrnoHolder(EINVAL));
859
860 position = new_position;
861 }
862
863 int64 CDIF_Stream_Thing::tell(void)
864 {
865 return position;
866 }
867
868 int64 CDIF_Stream_Thing::size(void)
869 {
870 return(sector_count * 2048);
871 }
872
873 void CDIF_Stream_Thing::close(void)
874 {
875
876 }
877
878
879 Stream *CDIF::MakeStream(uint32 lba, uint32 sector_count)
880 {
881 return new CDIF_Stream_Thing(this, lba, sector_count);
882 }
883
884
885 CDIF *CDIF_Open(const char *path, const bool is_device, bool image_memcache)
886 {
887 CDAccess *cda = cdaccess_open_image(path, image_memcache);
888
889 if(!image_memcache)
890 return new CDIF_MT(cda);
891 return new CDIF_ST(cda);
892 }
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #ifndef __MDFN_CDROM_CDROMIF_H
18 #define __MDFN_CDROM_CDROMIF_H
19
20 #include "CDUtility.h"
21 #include "../Stream.h"
22
23 #include <queue>
24
25 typedef TOC CD_TOC;
26
27 class CDIF
28 {
29 public:
30
31 CDIF();
32 virtual ~CDIF();
33
34 inline void ReadTOC(TOC *read_target)
35 {
36 *read_target = disc_toc;
37 }
38
39 virtual void HintReadSector(uint32_t lba) = 0;
40 virtual bool ReadRawSector(uint8_t *buf, uint32_t lba) = 0;
41 virtual bool ReadRawSectorPWOnly(uint8_t *buf, uint32_t lba, bool hint_fullread) = 0;
42
43 // Call for mode 1 or mode 2 form 1 only.
44 bool ValidateRawSector(uint8_t *buf);
45
46 // Utility/Wrapped functions
47 // Reads mode 1 and mode2 form 1 sectors(2048 bytes per sector returned)
48 // Will return the type(1, 2) of the first sector read to the buffer supplied, 0 on error
49 int ReadSector(uint8_t *pBuf, uint32_t lba, uint32_t nSectors);
50
51 // Return true if operation succeeded or it was a NOP(either due to not being implemented, or the current status matches eject_status).
52 // Returns false on failure(usually drive error of some kind; not completely fatal, can try again).
53 virtual bool Eject(bool eject_status) = 0;
54
55 // For Mode 1, or Mode 2 Form 1.
56 // No reference counting or whatever is done, so if you destroy the CDIF object before you destroy the returned Stream, things will go BOOM.
57 Stream *MakeStream(uint32_t lba, uint32_t sector_count);
58
59 protected:
60 bool UnrecoverableError;
61 TOC disc_toc;
62 bool DiscEjected;
63 };
64
65 CDIF *CDIF_Open(const char *path, const bool is_device, bool image_memcache);
66
67 #endif
0 /* dvdisaster: Additional error correction for optical media.
1 * Copyright (C) 2004-2007 Carsten Gnoerlich.
2 * Project home page: http://www.dvdisaster.com
3 * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
4 *
5 * CRC32 code based upon public domain code by Ross Williams (see notes below)
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
20 * or direct your browser at http://www.gnu.org.
21 */
22
23 #include <stdint.h>
24
25 /***
26 *** EDC checksum used in CDROM sectors
27 ***/
28
29 /*****************************************************************/
30 /* */
31 /* CRC LOOKUP TABLE */
32 /* ================ */
33 /* The following CRC lookup table was generated automagically */
34 /* by the Rocksoft^tm Model CRC Algorithm Table Generation */
35 /* Program V1.0 using the following model parameters: */
36 /* */
37 /* Width : 4 bytes. */
38 /* Poly : 0x8001801BL */
39 /* Reverse : TRUE. */
40 /* */
41 /* For more information on the Rocksoft^tm Model CRC Algorithm, */
42 /* see the document titled "A Painless Guide to CRC Error */
43 /* Detection Algorithms" by Ross Williams */
44 /* (ross@guest.adelaide.edu.au.). This document is likely to be */
45 /* in the FTP archive "ftp.adelaide.edu.au/pub/rocksoft". */
46 /* */
47 /*****************************************************************/
48
49 unsigned long edctable[256] =
50 {
51 0x00000000L, 0x90910101L, 0x91210201L, 0x01B00300L,
52 0x92410401L, 0x02D00500L, 0x03600600L, 0x93F10701L,
53 0x94810801L, 0x04100900L, 0x05A00A00L, 0x95310B01L,
54 0x06C00C00L, 0x96510D01L, 0x97E10E01L, 0x07700F00L,
55 0x99011001L, 0x09901100L, 0x08201200L, 0x98B11301L,
56 0x0B401400L, 0x9BD11501L, 0x9A611601L, 0x0AF01700L,
57 0x0D801800L, 0x9D111901L, 0x9CA11A01L, 0x0C301B00L,
58 0x9FC11C01L, 0x0F501D00L, 0x0EE01E00L, 0x9E711F01L,
59 0x82012001L, 0x12902100L, 0x13202200L, 0x83B12301L,
60 0x10402400L, 0x80D12501L, 0x81612601L, 0x11F02700L,
61 0x16802800L, 0x86112901L, 0x87A12A01L, 0x17302B00L,
62 0x84C12C01L, 0x14502D00L, 0x15E02E00L, 0x85712F01L,
63 0x1B003000L, 0x8B913101L, 0x8A213201L, 0x1AB03300L,
64 0x89413401L, 0x19D03500L, 0x18603600L, 0x88F13701L,
65 0x8F813801L, 0x1F103900L, 0x1EA03A00L, 0x8E313B01L,
66 0x1DC03C00L, 0x8D513D01L, 0x8CE13E01L, 0x1C703F00L,
67 0xB4014001L, 0x24904100L, 0x25204200L, 0xB5B14301L,
68 0x26404400L, 0xB6D14501L, 0xB7614601L, 0x27F04700L,
69 0x20804800L, 0xB0114901L, 0xB1A14A01L, 0x21304B00L,
70 0xB2C14C01L, 0x22504D00L, 0x23E04E00L, 0xB3714F01L,
71 0x2D005000L, 0xBD915101L, 0xBC215201L, 0x2CB05300L,
72 0xBF415401L, 0x2FD05500L, 0x2E605600L, 0xBEF15701L,
73 0xB9815801L, 0x29105900L, 0x28A05A00L, 0xB8315B01L,
74 0x2BC05C00L, 0xBB515D01L, 0xBAE15E01L, 0x2A705F00L,
75 0x36006000L, 0xA6916101L, 0xA7216201L, 0x37B06300L,
76 0xA4416401L, 0x34D06500L, 0x35606600L, 0xA5F16701L,
77 0xA2816801L, 0x32106900L, 0x33A06A00L, 0xA3316B01L,
78 0x30C06C00L, 0xA0516D01L, 0xA1E16E01L, 0x31706F00L,
79 0xAF017001L, 0x3F907100L, 0x3E207200L, 0xAEB17301L,
80 0x3D407400L, 0xADD17501L, 0xAC617601L, 0x3CF07700L,
81 0x3B807800L, 0xAB117901L, 0xAAA17A01L, 0x3A307B00L,
82 0xA9C17C01L, 0x39507D00L, 0x38E07E00L, 0xA8717F01L,
83 0xD8018001L, 0x48908100L, 0x49208200L, 0xD9B18301L,
84 0x4A408400L, 0xDAD18501L, 0xDB618601L, 0x4BF08700L,
85 0x4C808800L, 0xDC118901L, 0xDDA18A01L, 0x4D308B00L,
86 0xDEC18C01L, 0x4E508D00L, 0x4FE08E00L, 0xDF718F01L,
87 0x41009000L, 0xD1919101L, 0xD0219201L, 0x40B09300L,
88 0xD3419401L, 0x43D09500L, 0x42609600L, 0xD2F19701L,
89 0xD5819801L, 0x45109900L, 0x44A09A00L, 0xD4319B01L,
90 0x47C09C00L, 0xD7519D01L, 0xD6E19E01L, 0x46709F00L,
91 0x5A00A000L, 0xCA91A101L, 0xCB21A201L, 0x5BB0A300L,
92 0xC841A401L, 0x58D0A500L, 0x5960A600L, 0xC9F1A701L,
93 0xCE81A801L, 0x5E10A900L, 0x5FA0AA00L, 0xCF31AB01L,
94 0x5CC0AC00L, 0xCC51AD01L, 0xCDE1AE01L, 0x5D70AF00L,
95 0xC301B001L, 0x5390B100L, 0x5220B200L, 0xC2B1B301L,
96 0x5140B400L, 0xC1D1B501L, 0xC061B601L, 0x50F0B700L,
97 0x5780B800L, 0xC711B901L, 0xC6A1BA01L, 0x5630BB00L,
98 0xC5C1BC01L, 0x5550BD00L, 0x54E0BE00L, 0xC471BF01L,
99 0x6C00C000L, 0xFC91C101L, 0xFD21C201L, 0x6DB0C300L,
100 0xFE41C401L, 0x6ED0C500L, 0x6F60C600L, 0xFFF1C701L,
101 0xF881C801L, 0x6810C900L, 0x69A0CA00L, 0xF931CB01L,
102 0x6AC0CC00L, 0xFA51CD01L, 0xFBE1CE01L, 0x6B70CF00L,
103 0xF501D001L, 0x6590D100L, 0x6420D200L, 0xF4B1D301L,
104 0x6740D400L, 0xF7D1D501L, 0xF661D601L, 0x66F0D700L,
105 0x6180D800L, 0xF111D901L, 0xF0A1DA01L, 0x6030DB00L,
106 0xF3C1DC01L, 0x6350DD00L, 0x62E0DE00L, 0xF271DF01L,
107 0xEE01E001L, 0x7E90E100L, 0x7F20E200L, 0xEFB1E301L,
108 0x7C40E400L, 0xECD1E501L, 0xED61E601L, 0x7DF0E700L,
109 0x7A80E800L, 0xEA11E901L, 0xEBA1EA01L, 0x7B30EB00L,
110 0xE8C1EC01L, 0x7850ED00L, 0x79E0EE00L, 0xE971EF01L,
111 0x7700F000L, 0xE791F101L, 0xE621F201L, 0x76B0F300L,
112 0xE541F401L, 0x75D0F500L, 0x7460F600L, 0xE4F1F701L,
113 0xE381F801L, 0x7310F900L, 0x72A0FA00L, 0xE231FB01L,
114 0x71C0FC00L, 0xE151FD01L, 0xE0E1FE01L, 0x7070FF00L
115 };
116
117 /*
118 * CDROM EDC calculation
119 */
120
121 uint32_t EDCCrc32(const unsigned char *data, int len)
122 {
123 uint32_t crc = 0;
124
125 while(len--)
126 crc = edctable[(crc ^ *data++) & 0xFF] ^ (crc >> 8);
127
128 return crc;
129 }
0 #ifndef _EDC_CRC32_H
1 #define _EDC_CRC32_H
2
3 #include <stdint.h>
4
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8
9 uint32_t EDCCrc32(const unsigned char*, int);
10
11 #ifdef __cplusplus
12 }
13 #endif
14
15 #endif
0 /* dvdisaster: Additional error correction for optical media.
1 * Copyright (C) 2004-2007 Carsten Gnoerlich.
2 * Project home page: http://www.dvdisaster.com
3 * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
4 *
5 * The Reed-Solomon error correction draws a lot of inspiration - and even code -
6 * from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
21 * or direct your browser at http://www.gnu.org.
22 */
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include "galois.h"
27
28 /***
29 *** Galois field arithmetic.
30 ***
31 * Calculations are done over the extension field GF(2**n).
32 * Be careful not to overgeneralize these arithmetics;
33 * they only work for the case of GF(p**n) with p being prime.
34 */
35
36 /* Initialize the Galois field tables */
37
38 GaloisTables* CreateGaloisTables(int32_t gf_generator)
39 {
40 int32_t b,log;
41 GaloisTables *gt = (GaloisTables *)calloc(1, sizeof(GaloisTables));
42
43 /* Allocate the tables.
44 The encoder uses a special version of alpha_to which has the mod_fieldmax()
45 folded into the table. */
46
47 gt->gfGenerator = gf_generator;
48
49 gt->indexOf = (int32_t *)calloc(GF_FIELDSIZE, sizeof(int32_t));
50 gt->alphaTo = (int32_t *)calloc(GF_FIELDSIZE, sizeof(int32_t));
51 gt->encAlphaTo = (int32_t *)calloc(2*GF_FIELDSIZE, sizeof(int32_t));
52
53 /* create the log/ilog values */
54
55 for(b=1, log=0; log<GF_FIELDMAX; log++)
56 { gt->indexOf[b] = log;
57 gt->alphaTo[log] = b;
58 b = b << 1;
59 if(b & GF_FIELDSIZE)
60 b = b ^ gf_generator;
61 }
62
63 if(b!=1)
64 {
65 printf("Failed to create the Galois field log tables!\n");
66 exit(1);
67 }
68
69 /* we're even closed using infinity (makes things easier) */
70
71 gt->indexOf[0] = GF_ALPHA0; /* log(0) = inf */
72 gt->alphaTo[GF_ALPHA0] = 0; /* and the other way around */
73
74 for(b=0; b<2*GF_FIELDSIZE; b++)
75 gt->encAlphaTo[b] = gt->alphaTo[mod_fieldmax(b)];
76
77 return gt;
78 }
79
80 void FreeGaloisTables(GaloisTables *gt)
81 {
82 if(gt->indexOf)
83 free(gt->indexOf);
84 if(gt->alphaTo)
85 free(gt->alphaTo);
86 if(gt->encAlphaTo)
87 free(gt->encAlphaTo);
88
89 free(gt);
90 }
91
92 /***
93 *** Create the the Reed-Solomon generator polynomial
94 *** and some auxiliary data structures.
95 */
96
97 ReedSolomonTables *CreateReedSolomonTables(GaloisTables *gt,
98 int32_t first_consecutive_root,
99 int32_t prim_elem,
100 int nroots_in)
101 {
102 int32_t i,j,root;
103 ReedSolomonTables *rt = (ReedSolomonTables *)
104 calloc(1, sizeof(ReedSolomonTables));
105
106 rt->gfTables = gt;
107 rt->fcr = first_consecutive_root;
108 rt->primElem = prim_elem;
109 rt->nroots = nroots_in;
110 rt->ndata = GF_FIELDMAX - rt->nroots;
111
112 rt->gpoly = (int32_t *)calloc((rt->nroots+1), sizeof(int32_t));
113
114 /* Create the RS code generator polynomial */
115
116 rt->gpoly[0] = 1;
117
118 for(i=0, root=first_consecutive_root*prim_elem; i<rt->nroots; i++, root+=prim_elem)
119 { rt->gpoly[i+1] = 1;
120
121 /* Multiply gpoly by alpha**(root+x) */
122
123 for(j=i; j>0; j--)
124 {
125 if(rt->gpoly[j] != 0)
126 rt->gpoly[j] = rt->gpoly[j-1] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[j]] + root)];
127 else
128 rt->gpoly[j] = rt->gpoly[j-1];
129 }
130
131 rt->gpoly[0] = gt->alphaTo[mod_fieldmax(gt->indexOf[rt->gpoly[0]] + root)];
132 }
133
134 /* Store the polynomials index for faster encoding */
135
136 for(i=0; i<=rt->nroots; i++)
137 rt->gpoly[i] = gt->indexOf[rt->gpoly[i]];
138
139 return rt;
140 }
141
142 void FreeReedSolomonTables(ReedSolomonTables *rt)
143 {
144 if(rt->gpoly)
145 free(rt->gpoly);
146
147 free(rt);
148 }
0 #ifndef _GALOIS_H
1 #define _GALOIS_H
2
3 #include <stdint.h>
4 #include <retro_inline.h>
5
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9
10 /***
11 *** galois.c
12 ***
13 * This is currently the hardcoded GF(2**8).
14 * int32_t gives abundant space for the GF.
15 * Squeezing it down to uint8 won't probably gain much,
16 * so we implement this defensively here.
17 *
18 * Note that some performance critical stuff needs to
19 * be #included from galois-inlines.h
20 */
21
22 /* Galois field parameters for 8bit symbol Reed-Solomon code */
23
24 #define GF_SYMBOLSIZE 8
25 #define GF_FIELDSIZE (1<<GF_SYMBOLSIZE)
26 #define GF_FIELDMAX (GF_FIELDSIZE-1)
27 #define GF_ALPHA0 GF_FIELDMAX
28
29 /* Lookup tables for Galois field arithmetic */
30
31 typedef struct _GaloisTables
32 { int32_t gfGenerator; /* GF generator polynomial */
33 int32_t *indexOf; /* log */
34 int32_t *alphaTo; /* inverse log */
35 int32_t *encAlphaTo; /* inverse log optimized for encoder */
36 } GaloisTables;
37
38 /* Lookup and working tables for the ReedSolomon codecs */
39
40 typedef struct _ReedSolomonTables
41 {
42 GaloisTables *gfTables;/* from above */
43 int32_t *gpoly; /* RS code generator polynomial */
44 int32_t fcr; /* first consecutive root of RS generator polynomial */
45 int32_t primElem; /* primitive field element */
46 int32_t nroots; /* degree of RS generator polynomial */
47 int32_t ndata; /* data bytes per ecc block */
48 } ReedSolomonTables;
49
50 /*
51 * The following routine is performance critical.
52 */
53
54 static INLINE int mod_fieldmax(int x)
55 {
56 while (x >= GF_FIELDMAX)
57 {
58 x -= GF_FIELDMAX;
59 x = (x >> GF_SYMBOLSIZE) + (x & GF_FIELDMAX);
60 }
61
62 return x;
63 }
64
65 GaloisTables* CreateGaloisTables(int32_t a);
66 void FreeGaloisTables(GaloisTables *a);
67
68 ReedSolomonTables *CreateReedSolomonTables(GaloisTables *a, int32_t b, int32_t c, int d);
69 void FreeReedSolomonTables(ReedSolomonTables *a);
70
71 #ifdef __cplusplus
72 }
73 #endif
74
75 #endif
0 /* dvdisaster: Additional error correction for optical media.
1 * Copyright (C) 2004-2007 Carsten Gnoerlich.
2 * Project home page: http://www.dvdisaster.com
3 * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
4 *
5 * The Reed-Solomon error correction draws a lot of inspiration - and even code -
6 * from Phil Karn's excellent Reed-Solomon library: http://www.ka9q.net/code/fec/
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
21 * or direct your browser at http://www.gnu.org.
22 */
23
24 #include "l-ec.h"
25 #include <stdlib.h>
26 #include <string.h>
27
28 #define MIN(a, b) (((a) < (b)) ? (a) : (b))
29
30 /***
31 *** Mapping between cd frame and parity vectors
32 ***/
33
34 /*
35 * Mapping of frame bytes to P/Q Vectors
36 */
37
38 int PToByteIndex(int p, int i)
39 { return 12 + p + i*86;
40 }
41
42 void ByteIndexToP(int b, int *p, int *i)
43 { *p = (b-12)%86;
44 *i = (b-12)/86;
45 }
46
47 int QToByteIndex(int q, int i)
48 { int offset = 12 + (q & 1);
49
50 if(i == 43) return 2248+q;
51 if(i == 44) return 2300+q;
52
53 q&=~1;
54 return offset + (q*43 + i*88) % 2236;
55 }
56
57 void ByteIndexToQ(int b, int *q, int *i)
58 { int x,y,offset;
59
60 if(b >= 2300)
61 { *i = 44;
62 *q = (b-2300);
63 return;
64 }
65
66 if(b >= 2248)
67 { *i = 43;
68 *q = (b-2248);
69 return;
70 }
71
72 offset = b&1;
73 b = (b-12)/2;
74 x = b/43;
75 y = (b-(x*43))%26;
76 *i = b-(x*43);
77 *q = 2*((x+26-y)%26)+offset;
78 }
79
80 /*
81 * There are 86 vectors of P-parity, yielding a RS(26,24) code.
82 */
83
84 void GetPVector(unsigned char *frame, unsigned char *data, int n)
85 { int i;
86 int w_idx = n+12;
87
88 for(i=0; i<26; i++, w_idx+=86)
89 data[i] = frame[w_idx];
90 }
91
92 void SetPVector(unsigned char *frame, unsigned char *data, int n)
93 { int i;
94 int w_idx = n+12;
95
96 for(i=0; i<26; i++, w_idx+=86)
97 frame[w_idx] = data[i];
98 }
99
100 void FillPVector(unsigned char *frame, unsigned char data, int n)
101 { int i;
102 int w_idx = n+12;
103
104 for(i=0; i<26; i++, w_idx+=86)
105 frame[w_idx] = data;
106 }
107
108 void OrPVector(unsigned char *frame, unsigned char value, int n)
109 { int i;
110 int w_idx = n+12;
111
112 for(i=0; i<26; i++, w_idx+=86)
113 frame[w_idx] |= value;
114 }
115
116 void AndPVector(unsigned char *frame, unsigned char value, int n)
117 { int i;
118 int w_idx = n+12;
119
120 for(i=0; i<26; i++, w_idx+=86)
121 frame[w_idx] &= value;
122 }
123
124 /*
125 * There are 52 vectors of Q-parity, yielding a RS(45,43) code.
126 */
127
128 void GetQVector(unsigned char *frame, unsigned char *data, int n)
129 { int offset = 12 + (n & 1);
130 int w_idx = (n&~1) * 43;
131 int i;
132
133 for(i=0; i<43; i++, w_idx+=88)
134 data[i] = frame[(w_idx % 2236) + offset];
135
136 data[43] = frame[2248 + n];
137 data[44] = frame[2300 + n];
138 }
139
140 void SetQVector(unsigned char *frame, unsigned char *data, int n)
141 { int offset = 12 + (n & 1);
142 int w_idx = (n&~1) * 43;
143 int i;
144
145 for(i=0; i<43; i++, w_idx+=88)
146 frame[(w_idx % 2236) + offset] = data[i];
147
148 frame[2248 + n] = data[43];
149 frame[2300 + n] = data[44];
150 }
151
152 void FillQVector(unsigned char *frame, unsigned char data, int n)
153 { int offset = 12 + (n & 1);
154 int w_idx = (n&~1) * 43;
155 int i;
156
157 for(i=0; i<43; i++, w_idx+=88)
158 frame[(w_idx % 2236) + offset] = data;
159
160 frame[2248 + n] = data;
161 frame[2300 + n] = data;
162 }
163
164 void OrQVector(unsigned char *frame, unsigned char data, int n)
165 { int offset = 12 + (n & 1);
166 int w_idx = (n&~1) * 43;
167 int i;
168
169 for(i=0; i<43; i++, w_idx+=88)
170 frame[(w_idx % 2236) + offset] |= data;
171
172 frame[2248 + n] |= data;
173 frame[2300 + n] |= data;
174 }
175
176 void AndQVector(unsigned char *frame, unsigned char data, int n)
177 { int offset = 12 + (n & 1);
178 int w_idx = (n&~1) * 43;
179 int i;
180
181 for(i=0; i<43; i++, w_idx+=88)
182 frame[(w_idx % 2236) + offset] &= data;
183
184 frame[2248 + n] &= data;
185 frame[2300 + n] &= data;
186 }
187
188 /***
189 *** C2 error counting
190 ***/
191
192 int CountC2Errors(unsigned char *frame)
193 { int i,count = 0;
194 frame += 2352;
195
196 for(i=0; i<294; i++, frame++)
197 { if(*frame & 0x01) count++;
198 if(*frame & 0x02) count++;
199 if(*frame & 0x04) count++;
200 if(*frame & 0x08) count++;
201 if(*frame & 0x10) count++;
202 if(*frame & 0x20) count++;
203 if(*frame & 0x40) count++;
204 if(*frame & 0x80) count++;
205 }
206
207 return count;
208 }
209
210 /***
211 *** L-EC error correction for CD raw data sectors
212 ***/
213
214 /*
215 * These could be used from ReedSolomonTables,
216 * but hardcoding them is faster.
217 */
218
219 #define NROOTS 2
220 #define LEC_FIRST_ROOT 0 //GF_ALPHA0
221 #define LEC_PRIM_ELEM 1
222 #define LEC_PRIMTH_ROOT 1
223
224 /*
225 * Calculate the error syndrome
226 */
227
228 int DecodePQ(ReedSolomonTables *rt, unsigned char *data, int padding,
229 int *erasure_list, int erasure_count)
230 {
231 GaloisTables *gt = rt->gfTables;
232 int syndrome[NROOTS];
233 int lambda[NROOTS+1];
234 int omega[NROOTS+1];
235 int b[NROOTS+1];
236 int reg[NROOTS+1];
237 int root[NROOTS];
238 int loc[NROOTS];
239 int syn_error;
240 int deg_lambda,lambda_roots;
241 int deg_omega;
242 int shortened_size = GF_FIELDMAX - padding;
243 int corrected = 0;
244 int i,j,k;
245 int r,el;
246
247 /*** Form the syndromes: Evaluate data(x) at roots of g(x) */
248
249 for(i=0; i<NROOTS; i++)
250 syndrome[i] = data[0];
251
252 for(j=1; j<shortened_size; j++)
253 for(i=0; i<NROOTS; i++)
254 if(syndrome[i] == 0)
255 syndrome[i] = data[j];
256 else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
257 + (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
258
259 /*** Convert syndrome to index form, check for nonzero condition. */
260
261 syn_error = 0;
262 for(i=0; i<NROOTS; i++)
263 { syn_error |= syndrome[i];
264 syndrome[i] = gt->indexOf[syndrome[i]];
265 }
266
267 /*** If the syndrome is zero, everything is fine. */
268
269 if(!syn_error)
270 return 0;
271
272 /*** Initialize lambda to be the erasure locator polynomial */
273
274 lambda[0] = 1;
275 lambda[1] = lambda[2] = 0;
276
277 erasure_list[0] += padding;
278 erasure_list[1] += padding;
279
280 if(erasure_count > 2) /* sanity check */
281 erasure_count = 0;
282
283 if(erasure_count > 0)
284 { lambda[1] = gt->alphaTo[mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[0]))];
285
286 for(i=1; i<erasure_count; i++)
287 { int u = mod_fieldmax(LEC_PRIM_ELEM*(GF_FIELDMAX-1-erasure_list[i]));
288
289 for(j=i+1; j>0; j--)
290 { int tmp = gt->indexOf[lambda[j-1]];
291
292 if(tmp != GF_ALPHA0)
293 lambda[j] ^= gt->alphaTo[mod_fieldmax(u + tmp)];
294 }
295 }
296 }
297
298 for(i=0; i<NROOTS+1; i++)
299 b[i] = gt->indexOf[lambda[i]];
300
301 /*** Berlekamp-Massey algorithm to determine error+erasure locator polynomial */
302
303 r = erasure_count; /* r is the step number */
304 el = erasure_count;
305
306 /* Compute discrepancy at the r-th step in poly-form */
307
308 while(++r <= NROOTS)
309 { int discr_r = 0;
310
311 for(i=0; i<r; i++)
312 if((lambda[i] != 0) && (syndrome[r-i-1] != GF_ALPHA0))
313 discr_r ^= gt->alphaTo[mod_fieldmax(gt->indexOf[lambda[i]] + syndrome[r-i-1])];
314
315 discr_r = gt->indexOf[discr_r];
316
317 if(discr_r == GF_ALPHA0)
318 { /* B(x) = x*B(x) */
319 memmove(b+1, b, NROOTS*sizeof(b[0]));
320 b[0] = GF_ALPHA0;
321 }
322 else
323 { int t[NROOTS+1];
324
325 /* T(x) = lambda(x) - discr_r*x*b(x) */
326 t[0] = lambda[0];
327 for(i=0; i<NROOTS; i++)
328 { if(b[i] != GF_ALPHA0)
329 t[i+1] = lambda[i+1] ^ gt->alphaTo[mod_fieldmax(discr_r + b[i])];
330 else t[i+1] = lambda[i+1];
331 }
332
333 if(2*el <= r+erasure_count-1)
334 { el = r + erasure_count - el;
335
336 /* B(x) <-- inv(discr_r) * lambda(x) */
337 for(i=0; i<=NROOTS; i++)
338 b[i] = (lambda[i] == 0) ? GF_ALPHA0
339 : mod_fieldmax(gt->indexOf[lambda[i]] - discr_r + GF_FIELDMAX);
340 }
341 else
342 { /* 2 lines below: B(x) <-- x*B(x) */
343 memmove(b+1, b, NROOTS*sizeof(b[0]));
344 b[0] = GF_ALPHA0;
345 }
346
347 memcpy(lambda, t, (NROOTS+1)*sizeof(t[0]));
348 }
349 }
350
351 /*** Convert lambda to index form and compute deg(lambda(x)) */
352
353 deg_lambda = 0;
354 for(i=0; i<NROOTS+1; i++)
355 { lambda[i] = gt->indexOf[lambda[i]];
356 if(lambda[i] != GF_ALPHA0)
357 deg_lambda = i;
358 }
359
360 /*** Find roots of the error+erasure locator polynomial by Chien search */
361
362 memcpy(reg+1, lambda+1, NROOTS*sizeof(reg[0]));
363 lambda_roots = 0; /* Number of roots of lambda(x) */
364
365 for(i=1, k=LEC_PRIMTH_ROOT-1; i<=GF_FIELDMAX; i++, k=mod_fieldmax(k+LEC_PRIMTH_ROOT))
366 { int q=1; /* lambda[0] is always 0 */
367
368 for(j=deg_lambda; j>0; j--)
369 { if(reg[j] != GF_ALPHA0)
370 { reg[j] = mod_fieldmax(reg[j] + j);
371 q ^= gt->alphaTo[reg[j]];
372 }
373 }
374
375 if(q != 0) continue; /* Not a root */
376
377 /* store root in index-form and the error location number */
378
379 root[lambda_roots] = i;
380 loc[lambda_roots] = k;
381
382 /* If we've already found max possible roots, abort the search to save time */
383
384 if(++lambda_roots == deg_lambda) break;
385 }
386
387 /* deg(lambda) unequal to number of roots => uncorrectable error detected
388 This is not reliable for very small numbers of roots, e.g. nroots = 2 */
389
390 if(deg_lambda != lambda_roots)
391 { return -1;
392 }
393
394 /* Compute err+eras evaluator poly omega(x) = syn(x)*lambda(x)
395 (modulo x**nroots). in index form. Also find deg(omega). */
396
397 deg_omega = deg_lambda-1;
398
399 for(i=0; i<=deg_omega; i++)
400 { int tmp = 0;
401
402 for(j=i; j>=0; j--)
403 { if((syndrome[i - j] != GF_ALPHA0) && (lambda[j] != GF_ALPHA0))
404 tmp ^= gt->alphaTo[mod_fieldmax(syndrome[i - j] + lambda[j])];
405 }
406
407 omega[i] = gt->indexOf[tmp];
408 }
409
410 /* Compute error values in poly-form.
411 num1 = omega(inv(X(l))),
412 num2 = inv(X(l))**(FIRST_ROOT-1) and
413 den = lambda_pr(inv(X(l))) all in poly-form. */
414
415 for(j=lambda_roots-1; j>=0; j--)
416 { int num1 = 0;
417 int num2;
418 int den;
419 int location = loc[j];
420
421 for(i=deg_omega; i>=0; i--)
422 { if(omega[i] != GF_ALPHA0)
423 num1 ^= gt->alphaTo[mod_fieldmax(omega[i] + i * root[j])];
424 }
425
426 num2 = gt->alphaTo[mod_fieldmax(root[j] * (LEC_FIRST_ROOT - 1) + GF_FIELDMAX)];
427 den = 0;
428
429 /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */
430
431 for(i=MIN(deg_lambda, NROOTS-1) & ~1; i>=0; i-=2)
432 { if(lambda[i+1] != GF_ALPHA0)
433 den ^= gt->alphaTo[mod_fieldmax(lambda[i+1] + i * root[j])];
434 }
435
436 /* Apply error to data */
437
438 if(num1 != 0 && location >= padding)
439 {
440 corrected++;
441 data[location-padding] ^= gt->alphaTo[mod_fieldmax(gt->indexOf[num1] + gt->indexOf[num2]
442 + GF_FIELDMAX - gt->indexOf[den])];
443
444 /* If no erasures were given, at most one error was corrected.
445 Return its position in erasure_list[0]. */
446
447 if(!erasure_count)
448 erasure_list[0] = location-padding;
449 }
450 else
451 return -3;
452 }
453
454 /*** Form the syndromes: Evaluate data(x) at roots of g(x) */
455
456 for(i=0; i<NROOTS; i++)
457 syndrome[i] = data[0];
458
459 for(j=1; j<shortened_size; j++)
460 for(i=0; i<NROOTS; i++)
461 { if(syndrome[i] == 0)
462 syndrome[i] = data[j];
463 else syndrome[i] = data[j] ^ gt->alphaTo[mod_fieldmax(gt->indexOf[syndrome[i]]
464 + (LEC_FIRST_ROOT+i)*LEC_PRIM_ELEM)];
465 }
466
467 /*** Convert syndrome to index form, check for nonzero condition. */
468 for(i=0; i<NROOTS; i++)
469 if(syndrome[i])
470 return -2;
471
472 return corrected;
473 }
0 #ifndef _L_EC_H
1 #define _L_EC_H
2
3 #include <stdint.h>
4 #include "galois.h"
5
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9
10 #define N_P_VECTORS 86 /* 43 16bit p vectors */
11 #define P_VECTOR_SIZE 26 /* using RS(26,24) ECC */
12
13 #define N_Q_VECTORS 52 /* 26 16bit q vectors */
14 #define Q_VECTOR_SIZE 45 /* using RS(45,43) ECC */
15
16 #define P_PADDING 229 /* padding values for */
17 #define Q_PADDING 210 /* shortened RS code */
18
19 int PToByteIndex(int, int);
20 int QToByteIndex(int, int);
21 void ByteIndexToP(int, int*, int*);
22 void ByteIndexToQ(int, int*, int*);
23
24 void GetPVector(unsigned char*, unsigned char*, int);
25 void SetPVector(unsigned char*, unsigned char*, int);
26 void FillPVector(unsigned char*, unsigned char, int);
27 void AndPVector(unsigned char*, unsigned char, int);
28 void OrPVector(unsigned char*, unsigned char, int);
29
30 void GetQVector(unsigned char*, unsigned char*, int);
31 void SetQVector(unsigned char*, unsigned char*, int);
32 void FillQVector(unsigned char*, unsigned char, int);
33 void AndQVector(unsigned char*, unsigned char, int);
34 void OrQVector(unsigned char*, unsigned char, int);
35
36 int DecodePQ(ReedSolomonTables*, unsigned char*, int, int*, int);
37
38 int CountC2Errors(unsigned char*);
39
40 #ifdef __cplusplus
41 }
42 #endif
43
44 #endif
0 /* cdrdao - write audio CD-Rs in disc-at-once mode
1 *
2 * Copyright (C) 1998-2002 Andreas Mueller <andreas@daneb.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #include <assert.h>
20 #include <sys/types.h>
21 #include <stdint.h>
22
23 #include "lec.h"
24
25 #define GF8_PRIM_POLY 0x11d /* x^8 + x^4 + x^3 + x^2 + 1 */
26
27 #define EDC_POLY 0x8001801b /* (x^16 + x^15 + x^2 + 1) (x^16 + x^2 + x + 1) */
28
29 #define LEC_HEADER_OFFSET 12
30 #define LEC_DATA_OFFSET 16
31 #define LEC_MODE1_DATA_LEN 2048
32 #define LEC_MODE1_EDC_OFFSET 2064
33 #define LEC_MODE1_INTERMEDIATE_OFFSET 2068
34 #define LEC_MODE1_P_PARITY_OFFSET 2076
35 #define LEC_MODE1_Q_PARITY_OFFSET 2248
36 #define LEC_MODE2_FORM1_DATA_LEN (2048+8)
37 #define LEC_MODE2_FORM1_EDC_OFFSET 2072
38 #define LEC_MODE2_FORM2_DATA_LEN (2324+8)
39 #define LEC_MODE2_FORM2_EDC_OFFSET 2348
40
41 static uint8_t GF8_LOG[256];
42 static uint8_t GF8_ILOG[256];
43
44 uint16_t cf8_table[43][256];
45 uint32_t crc_table[256];
46 uint8_t scramble_table[2340];
47
48 /* Addition in the GF(8) domain: just the XOR of the values.
49 */
50 #define gf8_add(a, b) (a) ^ (b)
51
52 /* Division in the GF(8) domain: Like multiplication but logarithms a
53 * subtracted.
54 */
55 static uint8_t gf8_div(uint8_t a, uint8_t b)
56 {
57 int16_t sum;
58
59 assert(b != 0);
60
61 if (a == 0)
62 return 0;
63
64 sum = GF8_LOG[a] - GF8_LOG[b];
65
66 if (sum < 0)
67 sum += 255;
68
69 return GF8_ILOG[sum];
70 }
71
72
73 /* Reverses the bits in 'd'. 'bits' defines the bit width of 'd'.
74 */
75 static uint32_t mirror_bits(uint32_t d, int bits)
76 {
77 int i;
78 uint32_t r = 0;
79
80 for (i = 0; i < bits; i++)
81 {
82 r <<= 1;
83
84 if ((d & 0x1) != 0)
85 r |= 0x1;
86
87 d >>= 1;
88 }
89
90 return r;
91 }
92
93
94 /* Calculates the CRC of given data with given lengths based on the
95 * table lookup algorithm.
96 */
97 static uint32_t calc_edc(uint8_t *data, int len)
98 {
99 uint32_t crc = 0;
100
101 while (len--)
102 crc = crc_table[(int)(crc ^ *data++) & 0xff] ^ (crc >> 8);
103
104 return crc;
105 }
106
107 /* Build the scramble table as defined in the yellow book. The bytes
108 12 to 2351 of a sector will be XORed with the data of this table.
109 */
110 static void scramble_table_init(void)
111 {
112 uint8_t d;
113 uint16_t i, j;
114 uint16_t reg = 1;
115
116 for (i = 0; i < 2340; i++)
117 {
118 d = 0;
119
120 for (j = 0; j < 8; j++)
121 {
122 d >>= 1;
123
124 if ((reg & 0x1) != 0)
125 d |= 0x80;
126
127 reg >>= 1;
128 if ((reg & 0x1) != ((reg >> 1) & 0x1))
129 reg |= 0x4000; /* 15-bit register */
130 }
131
132 scramble_table[i] = d;
133 }
134 }
135
136 /* Build the CRC lookup table for EDC_POLY poly. The CRC is 32 bit wide
137 * and reversed (i.e. the bit stream is divided by the EDC_POLY with the
138 * LSB first order).
139 */
140 static void crc_table_init(void)
141 {
142 uint32_t i, j;
143 uint32_t r;
144
145 for (i = 0; i < 256; i++)
146 {
147 r = mirror_bits(i, 8);
148
149 r <<= 24;
150
151 for (j = 0; j < 8; j++)
152 {
153 r <<= 1;
154 if ((r & 0x80000000) != 0)
155 r ^= EDC_POLY;
156 }
157
158 r = mirror_bits(r, 32);
159
160 crc_table[i] = r;
161 }
162 }
163
164 /* Creates the logarithm and inverse logarithm table that is required
165 * for performing multiplication in the GF(8) domain.
166 */
167 static void gf8_create_log_tables(void)
168 {
169 uint8_t log;
170 uint16_t b;
171
172 for (b = 0; b <= 255; b++)
173 {
174 GF8_LOG[b] = 0;
175 GF8_ILOG[b] = 0;
176 }
177
178 b = 1;
179
180 for (log = 0; log < 255; log++)
181 {
182 GF8_LOG[(uint8_t)b] = log;
183 GF8_ILOG[log] = (uint8_t)b;
184
185 b <<= 1;
186
187 if ((b & 0x100) != 0)
188 b ^= GF8_PRIM_POLY;
189 }
190 }
191
192 static void cf8_table_init(void)
193 {
194 int i, j;
195 uint16_t c;
196 uint8_t GF8_COEFFS_HELP[2][45];
197 uint8_t GF8_Q_COEFFS[2][45];
198
199 gf8_create_log_tables();
200
201 /* build matrix H:
202 * 1 1 ... 1 1
203 * a^44 a^43 ... a^1 a^0
204 *
205 *
206 */
207
208 for (j = 0; j < 45; j++)
209 {
210 GF8_COEFFS_HELP[0][j] = 1; /* e0 */
211 GF8_COEFFS_HELP[1][j] = GF8_ILOG[44-j]; /* e1 */
212 }
213
214
215 /* resolve equation system for parity byte 0 and 1 */
216
217 /* e1' = e1 + e0 */
218 for (j = 0; j < 45; j++)
219 GF8_Q_COEFFS[1][j] = gf8_add(GF8_COEFFS_HELP[1][j],
220 GF8_COEFFS_HELP[0][j]);
221
222 /* e1'' = e1' / (a^1 + 1) */
223 for (j = 0; j < 45; j++)
224 GF8_Q_COEFFS[1][j] = gf8_div(GF8_Q_COEFFS[1][j], GF8_Q_COEFFS[1][43]);
225
226 /* e0' = e0 + e1 / a^1 */
227 for (j = 0; j < 45; j++)
228 GF8_Q_COEFFS[0][j] = gf8_add(GF8_COEFFS_HELP[0][j],
229 gf8_div(GF8_COEFFS_HELP[1][j],
230 GF8_ILOG[1]));
231
232 /* e0'' = e0' / (1 + 1 / a^1) */
233 for (j = 0; j < 45; j++)
234 GF8_Q_COEFFS[0][j] = gf8_div(GF8_Q_COEFFS[0][j], GF8_Q_COEFFS[0][44]);
235
236 /*
237 * Compute the products of 0..255 with all of the Q coefficients in
238 * advance. When building the scalar product between the data vectors
239 * and the P/Q vectors the individual products can be looked up in
240 * this table
241 *
242 * The P parity coefficients are just a subset of the Q coefficients so
243 * that we do not need to create a separate table for them.
244 */
245
246 for (j = 0; j < 43; j++)
247 {
248
249 cf8_table[j][0] = 0;
250
251 for (i = 1; i < 256; i++)
252 {
253 c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[0][j]];
254 if (c >= 255) c -= 255;
255 cf8_table[j][i] = GF8_ILOG[c];
256
257 c = GF8_LOG[i] + GF8_LOG[GF8_Q_COEFFS[1][j]];
258 if (c >= 255) c -= 255;
259 cf8_table[j][i] |= GF8_ILOG[c]<<8;
260 }
261 }
262 }
263
264 void lec_tables_init(void)
265 {
266 scramble_table_init();
267 crc_table_init();
268 cf8_table_init();
269 }
270
271 /* Calc EDC for a MODE 1 sector
272 */
273 static void calc_mode1_edc(uint8_t *sector)
274 {
275 uint32_t crc = calc_edc(sector, LEC_MODE1_DATA_LEN + 16);
276
277 sector[LEC_MODE1_EDC_OFFSET] = crc & 0xffL;
278 sector[LEC_MODE1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
279 sector[LEC_MODE1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
280 sector[LEC_MODE1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
281 }
282
283 /* Calc EDC for a XA form 1 sector
284 */
285 static void calc_mode2_form1_edc(uint8_t *sector)
286 {
287 uint32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
288 LEC_MODE2_FORM1_DATA_LEN);
289
290 sector[LEC_MODE2_FORM1_EDC_OFFSET] = crc & 0xffL;
291 sector[LEC_MODE2_FORM1_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
292 sector[LEC_MODE2_FORM1_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
293 sector[LEC_MODE2_FORM1_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
294 }
295
296 /* Calc EDC for a XA form 2 sector
297 */
298 static void calc_mode2_form2_edc(uint8_t *sector)
299 {
300 uint32_t crc = calc_edc(sector + LEC_DATA_OFFSET,
301 LEC_MODE2_FORM2_DATA_LEN);
302
303 sector[LEC_MODE2_FORM2_EDC_OFFSET] = crc & 0xffL;
304 sector[LEC_MODE2_FORM2_EDC_OFFSET + 1] = (crc >> 8) & 0xffL;
305 sector[LEC_MODE2_FORM2_EDC_OFFSET + 2] = (crc >> 16) & 0xffL;
306 sector[LEC_MODE2_FORM2_EDC_OFFSET + 3] = (crc >> 24) & 0xffL;
307 }
308
309 /* Writes the sync pattern to the given sector.
310 */
311 static void set_sync_pattern(uint8_t *sector)
312 {
313 sector[0] = 0;
314
315 sector[1] = sector[2] = sector[3] = sector[4] = sector[5] =
316 sector[6] = sector[7] = sector[8] = sector[9] = sector[10] = 0xff;
317
318 sector[11] = 0;
319 }
320
321
322 static uint8_t bin2bcd(uint8_t b)
323 {
324 return (((b/10) << 4) & 0xf0) | ((b%10) & 0x0f);
325 }
326
327 /* Builds the sector header.
328 */
329 static void set_sector_header(uint8_t mode, uint32_t adr, uint8_t *sector)
330 {
331 sector[LEC_HEADER_OFFSET] = bin2bcd(adr / (60*75));
332 sector[LEC_HEADER_OFFSET + 1] = bin2bcd((adr / 75) % 60);
333 sector[LEC_HEADER_OFFSET + 2] = bin2bcd(adr % 75);
334 sector[LEC_HEADER_OFFSET + 3] = mode;
335 }
336
337 /* Calculate the P parities for the sector.
338 * The 43 P vectors of length 24 are combined with the GF8_P_COEFFS.
339 */
340 static void calc_P_parity(uint8_t *sector)
341 {
342 int i, j;
343 uint16_t p01_msb, p01_lsb;
344 uint8_t *p_lsb_start;
345 uint8_t *p_lsb;
346 uint8_t *p0, *p1;
347 uint8_t d0,d1;
348
349 p_lsb_start = sector + LEC_HEADER_OFFSET;
350
351 p1 = sector + LEC_MODE1_P_PARITY_OFFSET;
352 p0 = sector + LEC_MODE1_P_PARITY_OFFSET + 2 * 43;
353
354 for (i = 0; i <= 42; i++)
355 {
356 p_lsb = p_lsb_start;
357
358 p01_lsb = p01_msb = 0;
359
360 for (j = 19; j <= 42; j++)
361 {
362 d0 = *p_lsb;
363 d1 = *(p_lsb+1);
364
365 p01_lsb ^= cf8_table[j][d0];
366 p01_msb ^= cf8_table[j][d1];
367
368 p_lsb += 2 * 43;
369 }
370
371 *p0 = p01_lsb;
372 *(p0 + 1) = p01_msb;
373
374 *p1 = p01_lsb>>8;
375 *(p1 + 1) = p01_msb>>8;
376
377 p0 += 2;
378 p1 += 2;
379
380 p_lsb_start += 2;
381 }
382 }
383
384 /* Calculate the Q parities for the sector.
385 * The 26 Q vectors of length 43 are combined with the GF8_Q_COEFFS.
386 */
387 static void calc_Q_parity(uint8_t *sector)
388 {
389 int i, j;
390 uint16_t q01_lsb, q01_msb;
391 uint8_t *q_lsb_start;
392 uint8_t *q_lsb;
393 uint8_t *q0, *q1, *q_start;
394 uint8_t d0,d1;
395
396 q_lsb_start = sector + LEC_HEADER_OFFSET;
397
398 q_start = sector + LEC_MODE1_Q_PARITY_OFFSET;
399 q1 = sector + LEC_MODE1_Q_PARITY_OFFSET;
400 q0 = sector + LEC_MODE1_Q_PARITY_OFFSET + 2 * 26;
401
402 for (i = 0; i <= 25; i++)
403 {
404 q_lsb = q_lsb_start;
405
406 q01_lsb = q01_msb = 0;
407
408 for (j = 0; j <= 42; j++)
409 {
410 d0 = *q_lsb;
411 d1 = *(q_lsb+1);
412
413 q01_lsb ^= cf8_table[j][d0];
414 q01_msb ^= cf8_table[j][d1];
415
416 q_lsb += 2 * 44;
417
418 if (q_lsb >= q_start)
419 q_lsb -= 2 * 1118;
420 }
421
422 *q0 = q01_lsb;
423 *(q0 + 1) = q01_msb;
424
425 *q1 = q01_lsb>>8;
426 *(q1 + 1) = q01_msb>>8;
427
428 q0 += 2;
429 q1 += 2;
430
431 q_lsb_start += 2 * 43;
432 }
433 }
434
435 /* Encodes a MODE 0 sector.
436 * 'adr' is the current physical sector address
437 * 'sector' must be 2352 byte wide
438 */
439 void lec_encode_mode0_sector(uint32_t adr, uint8_t *sector)
440 {
441 uint16_t i;
442
443 set_sync_pattern(sector);
444 set_sector_header(0, adr, sector);
445
446 sector += 16;
447
448 for (i = 0; i < 2336; i++)
449 *sector++ = 0;
450 }
451
452 /* Encodes a MODE 1 sector.
453 * 'adr' is the current physical sector address
454 * 'sector' must be 2352 byte wide containing 2048 bytes user data at
455 * offset 16
456 */
457 void lec_encode_mode1_sector(uint32_t adr, uint8_t *sector)
458 {
459 set_sync_pattern(sector);
460 set_sector_header(1, adr, sector);
461
462 calc_mode1_edc(sector);
463
464 /* clear the intermediate field */
465 sector[LEC_MODE1_INTERMEDIATE_OFFSET] =
466 sector[LEC_MODE1_INTERMEDIATE_OFFSET + 1] =
467 sector[LEC_MODE1_INTERMEDIATE_OFFSET + 2] =
468 sector[LEC_MODE1_INTERMEDIATE_OFFSET + 3] =
469 sector[LEC_MODE1_INTERMEDIATE_OFFSET + 4] =
470 sector[LEC_MODE1_INTERMEDIATE_OFFSET + 5] =
471 sector[LEC_MODE1_INTERMEDIATE_OFFSET + 6] =
472 sector[LEC_MODE1_INTERMEDIATE_OFFSET + 7] = 0;
473
474 calc_P_parity(sector);
475 calc_Q_parity(sector);
476 }
477
478 /* Encodes a MODE 2 sector.
479 * 'adr' is the current physical sector address
480 * 'sector' must be 2352 byte wide containing 2336 bytes user data at
481 * offset 16
482 */
483 void lec_encode_mode2_sector(uint32_t adr, uint8_t *sector)
484 {
485 set_sync_pattern(sector);
486 set_sector_header(2, adr, sector);
487 }
488
489 /* Encodes a XA form 1 sector.
490 * 'adr' is the current physical sector address
491 * 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
492 * offset 16
493 */
494 void lec_encode_mode2_form1_sector(uint32_t adr, uint8_t *sector)
495 {
496 set_sync_pattern(sector);
497
498 calc_mode2_form1_edc(sector);
499
500 /* P/Q partiy must not contain the sector header so clear it */
501 sector[LEC_HEADER_OFFSET] =
502 sector[LEC_HEADER_OFFSET + 1] =
503 sector[LEC_HEADER_OFFSET + 2] =
504 sector[LEC_HEADER_OFFSET + 3] = 0;
505
506 calc_P_parity(sector);
507 calc_Q_parity(sector);
508
509 /* finally add the sector header */
510 set_sector_header(2, adr, sector);
511 }
512
513 /* Encodes a XA form 2 sector.
514 * 'adr' is the current physical sector address
515 * 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
516 * offset 16
517 */
518 void lec_encode_mode2_form2_sector(uint32_t adr, uint8_t *sector)
519 {
520 set_sync_pattern(sector);
521
522 calc_mode2_form2_edc(sector);
523
524 set_sector_header(2, adr, sector);
525 }
526
527 /* Scrambles and byte swaps an encoded sector.
528 * 'sector' must be 2352 byte wide.
529 */
530 void lec_scramble(uint8_t *sector)
531 {
532 uint16_t i;
533 uint8_t *p = sector;
534 uint8_t tmp;
535 const uint8_t *stable = scramble_table;
536
537 for (i = 0; i < 6; i++)
538 {
539 /* just swap bytes of sector sync */
540 tmp = *p;
541 *p = *(p + 1);
542 p++;
543 *p++ = tmp;
544 }
545
546 for (;i < (2352 / 2); i++)
547 {
548 /* scramble and swap bytes */
549 tmp = *p ^ *stable++;
550 *p = *(p + 1) ^ *stable++;
551 p++;
552 *p++ = tmp;
553 }
554 }
0 /* cdrdao - write audio CD-Rs in disc-at-once mode
1 *
2 * Copyright (C) 1998-2002 Andreas Mueller <mueller@daneb.ping.de>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifndef __LEC_H__
20 #define __LEC_H__
21
22 #include <stdint.h>
23 #include <boolean.h>
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 #ifndef TRUE
30 #define TRUE 1
31 #endif
32
33 /* Encodes a MODE 0 sector.
34 * 'adr' is the current physical sector address
35 * 'sector' must be 2352 byte wide
36 */
37 void lec_encode_mode0_sector(uint32_t adr, uint8_t *sector);
38
39 /* Encodes a MODE 1 sector.
40 * 'adr' is the current physical sector address
41 * 'sector' must be 2352 byte wide containing 2048 bytes user data at
42 * offset 16
43 */
44 void lec_encode_mode1_sector(uint32_t adr, uint8_t *sector);
45
46 /* Encodes a MODE 2 sector.
47 * 'adr' is the current physical sector address
48 * 'sector' must be 2352 byte wide containing 2336 bytes user data at
49 * offset 16
50 */
51 void lec_encode_mode2_sector(uint32_t adr, uint8_t *sector);
52
53 /* Encodes a XA form 1 sector.
54 * 'adr' is the current physical sector address
55 * 'sector' must be 2352 byte wide containing 2048+8 bytes user data at
56 * offset 16
57 */
58 void lec_encode_mode2_form1_sector(uint32_t adr, uint8_t *sector);
59
60 /* Encodes a XA form 2 sector.
61 * 'adr' is the current physical sector address
62 * 'sector' must be 2352 byte wide containing 2324+8 bytes user data at
63 * offset 16
64 */
65 void lec_encode_mode2_form2_sector(uint32_t adr, uint8_t *sector);
66
67 /* Scrambles and byte swaps an encoded sector.
68 * 'sector' must be 2352 byte wide.
69 */
70 void lec_scramble(uint8_t *sector);
71
72 void lec_tables_init(void);
73
74 #ifdef __cplusplus
75 }
76 #endif
77
78 #endif
0 #include <stdint.h>
1 #include <string.h>
2
3 #include <string>
4
5 #include "misc.h"
6
7 void MDFN_strtoupper(char *str)
8 {
9 size_t x;
10 for(x = 0; str[x]; x++)
11 {
12 if(str[x] >= 'a' && str[x] <= 'z')
13 str[x] = str[x] - 'a' + 'A';
14 }
15 }
16
17 void MDFN_strtoupper(std::string &str)
18 {
19 size_t x;
20 const size_t len = str.length();
21
22 for(x = 0; x < len; x++)
23 {
24 if(str[x] >= 'a' && str[x] <= 'z')
25 str[x] = str[x] - 'a' + 'A';
26 }
27 }
0 #ifndef __MDFN_CDROM_MISC_H
1 #define __MDFN_CDROM_MISC_H
2
3 void MDFN_strtoupper(std::string &str);
4 void MDFN_strtoupper(char *str);
5
6 #endif
0 /* dvdisaster: Additional error correction for optical media.
1 * Copyright (C) 2004-2007 Carsten Gnoerlich.
2 * Project home page: http://www.dvdisaster.com
3 * Email: carsten@dvdisaster.com -or- cgnoerlich@fsfe.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
18 * or direct your browser at http://www.gnu.org.
19 */
20
21 #include <stdint.h>
22 #include <string.h>
23 #include "recover-raw.h"
24 #include "l-ec.h"
25 #include "edc_crc32.h"
26 #include "galois.h"
27
28 static GaloisTables *gt = NULL; /* for L-EC Reed-Solomon */
29 static ReedSolomonTables *rt = NULL;
30
31 bool Init_LEC_Correct(void)
32 {
33 gt = CreateGaloisTables(0x11d);
34 rt = CreateReedSolomonTables(gt, 0, 1, 10);
35
36 return(1);
37 }
38
39 void Kill_LEC_Correct(void)
40 {
41 FreeGaloisTables(gt);
42 FreeReedSolomonTables(rt);
43 }
44
45 /***
46 *** CD level CRC calculation
47 ***/
48
49 /*
50 * Test raw sector against its 32bit CRC.
51 * Returns TRUE if frame is good.
52 */
53
54 int CheckEDC(const unsigned char *cd_frame, bool xa_mode)
55 {
56 unsigned int expected_crc, real_crc;
57 unsigned int crc_base = xa_mode ? 2072 : 2064;
58
59 expected_crc = cd_frame[crc_base + 0] << 0;
60 expected_crc |= cd_frame[crc_base + 1] << 8;
61 expected_crc |= cd_frame[crc_base + 2] << 16;
62 expected_crc |= cd_frame[crc_base + 3] << 24;
63
64 if(xa_mode)
65 real_crc = EDCCrc32(cd_frame+16, 2056);
66 else
67 real_crc = EDCCrc32(cd_frame, 2064);
68
69 if(expected_crc == real_crc)
70 return(1);
71
72 //printf("Bad EDC CRC: Calculated: %08x, Recorded: %08x\n", real_crc, expected_crc);
73 return(0);
74 }
75
76 /***
77 *** A very simple L-EC error correction.
78 ***
79 * Perform just one pass over the Q and P vectors to see if everything
80 * is okay respectively correct minor errors. This is pretty much the
81 * same stuff the drive is supposed to do in the final L-EC stage.
82 */
83
84 static int simple_lec(unsigned char *frame)
85 {
86 unsigned char byte_state[2352];
87 unsigned char p_vector[P_VECTOR_SIZE];
88 unsigned char q_vector[Q_VECTOR_SIZE];
89 unsigned char p_state[P_VECTOR_SIZE];
90 int erasures[Q_VECTOR_SIZE], erasure_count;
91 int ignore[2];
92 int p_failures, q_failures;
93 int p_corrected, q_corrected;
94 int p,q;
95
96 /* Setup */
97
98 memset(byte_state, 0, 2352);
99
100 p_failures = q_failures = 0;
101 p_corrected = q_corrected = 0;
102
103 /* Perform Q-Parity error correction */
104
105 for(q=0; q<N_Q_VECTORS; q++)
106 {
107 int err;
108
109 /* We have no erasure information for Q vectors */
110
111 GetQVector(frame, q_vector, q);
112 err = DecodePQ(rt, q_vector, Q_PADDING, ignore, 0);
113
114 /* See what we've got */
115
116 if(err < 0) /* Uncorrectable. Mark bytes are erasure. */
117 { q_failures++;
118 FillQVector(byte_state, 1, q);
119 }
120 else /* Correctable */
121 {
122 if(err == 1 || err == 2) /* Store back corrected vector */
123 {
124 SetQVector(frame, q_vector, q);
125 q_corrected++;
126 }
127 }
128 }
129
130 /* Perform P-Parity error correction */
131 for(p=0; p<N_P_VECTORS; p++)
132 {
133 int err,i;
134
135 /* Try error correction without erasure information */
136
137 GetPVector(frame, p_vector, p);
138 err = DecodePQ(rt, p_vector, P_PADDING, ignore, 0);
139
140 /* If unsuccessful, try again using erasures.
141 Erasure information is uncertain, so try this last. */
142
143 if(err < 0 || err > 2)
144 {
145 GetPVector(byte_state, p_state, p);
146 erasure_count = 0;
147
148 for(i=0; i<P_VECTOR_SIZE; i++)
149 if(p_state[i])
150 erasures[erasure_count++] = i;
151
152 if(erasure_count > 0 && erasure_count <= 2)
153 {
154 GetPVector(frame, p_vector, p);
155 err = DecodePQ(rt, p_vector, P_PADDING, erasures, erasure_count);
156 }
157 }
158
159 /* See what we've got */
160
161 if(err < 0) /* Uncorrectable. */
162 p_failures++;
163 else /* Correctable. */
164 {
165 if(err == 1 || err == 2) /* Store back corrected vector */
166 { SetPVector(frame, p_vector, p);
167 p_corrected++;
168 }
169 }
170 }
171
172 /* Sum up */
173
174 if(q_failures || p_failures || q_corrected || p_corrected)
175 return 1;
176
177 return 0;
178 }
179
180 /***
181 *** Validate CD raw sector
182 ***/
183
184 int ValidateRawSector(unsigned char *frame, bool xaMode)
185 {
186 int lec_did_sth = false;
187
188 /* Do simple L-EC.
189 It seems that drives stop their internal L-EC as soon as the
190 EDC is okay, so we may see uncorrected errors in the parity bytes.
191 Since we are also interested in the user data only and doing the
192 L-EC is expensive, we skip our L-EC as well when the EDC is fine. */
193
194 if(!CheckEDC(frame, xaMode))
195 lec_did_sth = simple_lec(frame);
196 /* Test internal sector checksum again */
197
198 /* EDC failure in RAW sector */
199 if(!CheckEDC(frame, xaMode))
200 return false;
201
202 return true;
203 }
0 #ifndef _RECOVER_RAW_H
1 #define _RECOVER_RAW_H
2
3 #include <stdint.h>
4 #include <boolean.h>
5
6 #ifdef __cplusplus
7 extern "C" {
8 #endif
9
10 #define CD_RAW_SECTOR_SIZE 2352
11 #define CD_RAW_C2_SECTOR_SIZE (2352+294) /* main channel plus C2 vector */
12
13 int CheckEDC(const unsigned char *a, bool b);
14 int CheckMSF(unsigned char *a, int b);
15
16
17 int ValidateRawSector(unsigned char *frame, bool xaMode);
18 bool Init_LEC_Correct(void);
19 void Kill_LEC_Correct(void);
20
21 #ifdef __cplusplus
22 }
23 #endif
24
25 #endif
0 #ifndef __MDFN_CLAMP_H
1 #define __MDFN_CLAMP_H
2
3 #ifdef __cplusplus
4 extern "C" {
5 #endif
6
7 #include <stddef.h>
8 #ifndef _WIN32
9 #include <unistd.h>
10 #endif
11
12 static INLINE int32 clamp_to_u8(int32 i)
13 {
14 if(i & 0xFFFFFF00)
15 i = (((~i) >> 30) & 0xFF);
16
17 return(i);
18 }
19
20
21 static INLINE int32 clamp_to_u16(int32 i)
22 {
23 if(i & 0xFFFF0000)
24 i = (((~i) >> 31) & 0xFFFF);
25
26 return(i);
27 }
28
29 static INLINE void clamp(int32_t *val, ssize_t min, ssize_t max)
30 {
31 if(*val < min)
32 *val = min;
33 if(*val > max)
34 *val = max;
35 }
36
37 #define clamp_simple(val) \
38 if ( (int16_t)val != val ) \
39 val = (val >> 31) ^ 0x7FFF;
40
41 #ifdef __cplusplus
42 }
43 #endif
44
45 #endif
0 #ifndef _MDFN_DRIVERH
1 #define _MDFN_DRIVERH
2
3 #include "mednafen-types.h"
4 #include "git.h"
5 #include "settings-driver.h"
6 #include "mednafen-driver.h"
7 #include "mempatcher-driver.h"
8
9 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "mednafen.h"
18 #include "error.h"
19 #include <string.h>
20 #include <stdarg.h>
21 #include "include/trio/trio.h"
22 #include "../libretro.h"
23
24 extern retro_log_printf_t log_cb;
25
26 MDFN_Error::MDFN_Error() throw()
27 {
28 abort();
29 }
30
31 MDFN_Error::MDFN_Error(int errno_code_new, const char *format, ...) throw()
32 {
33 errno_code = errno_code_new;
34
35 va_list ap;
36 va_start(ap, format);
37 error_message = trio_vaprintf(format, ap);
38 va_end(ap);
39
40 log_cb(RETRO_LOG_ERROR, "%s\n", error_message);
41 }
42
43
44 MDFN_Error::MDFN_Error(const ErrnoHolder &enh)
45 {
46 errno_code = enh.Errno();
47
48 error_message = trio_aprintf("%s", enh.StrError());
49 }
50
51
52 MDFN_Error::~MDFN_Error() throw()
53 {
54 if(error_message)
55 {
56 free(error_message);
57 error_message = NULL;
58 }
59 }
60
61 MDFN_Error::MDFN_Error(const MDFN_Error &ze_error) throw()
62 {
63 if(ze_error.error_message)
64 error_message = strdup(ze_error.error_message);
65 else
66 error_message = NULL;
67
68 errno_code = ze_error.errno_code;
69 }
70
71 MDFN_Error& MDFN_Error::operator=(const MDFN_Error &ze_error) throw()
72 {
73 char *new_error_message = ze_error.error_message ? strdup(ze_error.error_message) : NULL;
74 int new_errno_code = ze_error.errno_code;
75
76 if(error_message)
77 free(error_message);
78
79 error_message = new_error_message;
80 errno_code = new_errno_code;
81
82 return(*this);
83 }
84
85
86 const char * MDFN_Error::what(void) const throw()
87 {
88 if(!error_message)
89 return("Error allocating memory for the error message!");
90
91 return(error_message);
92 }
93
94 int MDFN_Error::GetErrno(void) const throw()
95 {
96 return(errno_code);
97 }
98
99 static const char *srr_wrap(int ret, const char *local_strerror)
100 {
101 if(ret == -1)
102 return("ERROR IN strerror_r()!!!");
103
104 return(local_strerror);
105 }
106
107 static const char *srr_wrap(const char *ret, const char *local_strerror)
108 {
109 if(ret == NULL)
110 return("ERROR IN strerror_r()!!!");
111
112 return(ret);
113 }
114
115 void ErrnoHolder::SetErrno(int the_errno)
116 {
117 local_errno = the_errno;
118
119 if(the_errno == 0)
120 local_strerror[0] = 0;
121 else
122 {
123 strncpy(local_strerror, strerror(the_errno), 255);
124
125 local_strerror[255] = 0;
126 }
127 }
128
0 #ifndef __MDFN_ERROR_H
1 #define __MDFN_ERROR_H
2
3 #include <errno.h>
4 #include <string.h>
5
6 #ifdef __cplusplus
7 #include <stdexcept>
8
9 class ErrnoHolder;
10 class MDFN_Error : public std::exception
11 {
12 public:
13
14 MDFN_Error() throw();
15
16 MDFN_Error(int errno_code_new, const char *format, ...) throw();
17 MDFN_Error(const ErrnoHolder &enh);
18
19 ~MDFN_Error() throw();
20
21 MDFN_Error(const MDFN_Error &ze_error) throw();
22 MDFN_Error & operator=(const MDFN_Error &ze_error) throw();
23
24 virtual const char *what(void) const throw();
25 int GetErrno(void) const throw();
26
27 private:
28
29 int errno_code;
30 char *error_message;
31 };
32
33 class ErrnoHolder
34 {
35 public:
36
37 ErrnoHolder()
38 {
39 local_errno = 0;
40 local_strerror[0] = 0;
41 }
42
43 ErrnoHolder(int the_errno)
44 {
45 SetErrno(the_errno);
46 }
47
48 inline int Errno(void) const
49 {
50 return(local_errno);
51 }
52
53 const char *StrError(void) const
54 {
55 return(local_strerror);
56 }
57
58 void operator=(int the_errno)
59 {
60 SetErrno(the_errno);
61 }
62
63 private:
64
65 void SetErrno(int the_errno);
66
67 int local_errno;
68 char local_strerror[256];
69 };
70
71 #endif
72
73 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <string.h>
22
23 #include "file.h"
24 #include "mednafen-endian.h"
25
26 struct MDFNFILE *file_open(const char *path)
27 {
28 const char *ld;
29 FILE *fp;
30 struct MDFNFILE *file = (struct MDFNFILE*)calloc(1, sizeof(*file));
31
32 if (!file)
33 return NULL;
34
35 fp = fopen(path, "rb");
36
37 if (!fp)
38 goto error;
39
40 fseek(fp, 0, SEEK_SET);
41 fseek((FILE *)fp, 0, SEEK_END);
42 file->size = ftell((FILE *)fp);
43 fseek((FILE *)fp, 0, SEEK_SET);
44
45 if (!(file->data = (uint8_t*)malloc(file->size)))
46 goto error;
47 fread(file->data, 1, file->size, (FILE *)fp);
48
49 ld = (const char*)strrchr(path, '.');
50 file->ext = strdup(ld ? ld + 1 : "");
51
52 return file;
53
54 error:
55 if (fp)
56 fclose((FILE*)fp);
57 if (file)
58 free(file);
59 return NULL;
60 }
61
62 int file_close(struct MDFNFILE *file)
63 {
64 if (!file)
65 return 0;
66
67 if (file->ext)
68 free(file->ext);
69 file->ext = NULL;
70
71 if (file->data)
72 free(file->data);
73 file->data = NULL;
74
75 free(file);
76
77 return 1;
78 }
79
80 uint64_t file_read(struct MDFNFILE *file, void *ptr,
81 size_t element_size, size_t nmemb)
82 {
83 uint32_t total = element_size * nmemb;
84
85 if (file->location >= file->size)
86 return 0;
87
88 if ((file->location + total) > file->size)
89 {
90 int64_t ak = file->size - file->location;
91
92 memcpy((uint8_t*)ptr, file->data + file->location, ak);
93
94 file->location = file->size;
95
96 return(ak / element_size);
97 }
98
99 memcpy((uint8_t*)ptr, file->data + file->location, total);
100
101 file->location += total;
102
103 return nmemb;
104 }
105
106 int file_seek(struct MDFNFILE *file, int64_t offset, int whence)
107 {
108 switch(whence)
109 {
110 case SEEK_SET:
111 if (offset >= file->size)
112 return -1;
113
114 file->location = offset;
115 break;
116 case SEEK_CUR:
117 if ((offset + file->location) > file->size)
118 return -1;
119
120 file->location += offset;
121 break;
122 }
123
124 return 0;
125 }
126
127 char *file_fgets(struct MDFNFILE *file, char *s, int len)
128 {
129 int pos = 0;
130
131 if (!len)
132 return(NULL);
133
134 if (file->location >= len)
135 return(NULL);
136
137 while(pos < (len - 1) && file->location < len)
138 {
139 int v = file->data[file->location];
140 s[pos] = v;
141 file->location++;
142 pos++;
143 if (v == '\n')
144 break;
145 }
146
147 if (len)
148 s[pos] = 0;
149
150 return s;
151 }
0 #ifndef MDFN_FILE_H
1 #define MDFN_FILE_H
2
3 #include <stdint.h>
4
5 #define MDFNFILE_EC_NOTFOUND 1
6 #define MDFNFILE_EC_OTHER 2
7
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11
12 struct MDFNFILE
13 {
14 uint8_t *data;
15 int64_t size;
16 char *ext;
17 int64_t location;
18 };
19
20 struct MDFNFILE *file_open(const char *path);
21
22 int file_close(struct MDFNFILE *file);
23
24 uint64_t file_read(struct MDFNFILE *file, void *ptr,
25 size_t element_size, size_t nmemb);
26
27 int file_seek(struct MDFNFILE *file, int64_t offset, int whence);
28
29 char *file_fgets(struct MDFNFILE *file, char *s, int buffer_size);
30
31 #ifdef __cplusplus
32 }
33 #endif
34
35 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "mednafen.h"
18
19 #include <string.h>
20 #include <stdarg.h>
21
22 #include <sys/types.h>
23
24 #include <string>
25
26 #include "general.h"
27 #include "state.h"
28
29 #include "md5.h"
30
31 using namespace std;
32
33 static bool IsAbsolutePath(const char *path)
34 {
35 if (
36 #ifdef _WIN32
37 path[0] == '\\' ||
38 #endif
39 path[0] == '/'
40 )
41 return(TRUE);
42
43 #if defined(WIN32) || defined(DOS)
44 if((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'))
45 {
46 if(path[1] == ':')
47 return(TRUE);
48 }
49 #endif
50
51 return(FALSE);
52 }
53
54 bool MDFN_IsFIROPSafe(const std::string &path)
55 {
56 // We could make this more OS-specific, but it shouldn't hurt to try to weed out usage of characters that are path
57 // separators in one OS but not in another, and we'd also run more of a risk of missing a special path separator case
58 // in some OS.
59
60 if(!MDFN_GetSettingB("filesys.untrusted_fip_check"))
61 return(true);
62
63 if(path.find('\0') != string::npos)
64 return(false);
65
66 if(path.find(':') != string::npos)
67 return(false);
68
69 if(path.find('\\') != string::npos)
70 return(false);
71
72 if(path.find('/') != string::npos)
73 return(false);
74
75 return(true);
76 }
77
78 void MDFN_GetFilePathComponents(const std::string &file_path,
79 std::string *dir_path_out, std::string *file_base_out,
80 std::string *file_ext_out)
81 {
82 size_t final_ds; // in file_path
83 string file_name;
84 size_t fn_final_dot; // in local var file_name
85 string dir_path, file_base, file_ext; // Temporary output
86
87 #ifdef _WIN32
88 final_ds = file_path.find_last_of('\\');
89
90 size_t alt_final_ds = file_path.find_last_of('/');
91
92 if(final_ds == string::npos || (alt_final_ds != string::npos && alt_final_ds > final_ds))
93 final_ds = alt_final_ds;
94 #else
95 final_ds = file_path.find_last_of('/');
96 #endif
97
98 if(final_ds == string::npos)
99 {
100 dir_path = string(".");
101 file_name = file_path;
102 }
103 else
104 {
105 dir_path = file_path.substr(0, final_ds);
106 file_name = file_path.substr(final_ds + 1);
107 }
108
109 fn_final_dot = file_name.find_last_of('.');
110
111 if(fn_final_dot != string::npos)
112 {
113 file_base = file_name.substr(0, fn_final_dot);
114 file_ext = file_name.substr(fn_final_dot);
115 }
116 else
117 {
118 file_base = file_name;
119 file_ext = string("");
120 }
121
122 if(dir_path_out)
123 *dir_path_out = dir_path;
124
125 if(file_base_out)
126 *file_base_out = file_base;
127
128 if(file_ext_out)
129 *file_ext_out = file_ext;
130 }
131
132 std::string MDFN_EvalFIP(const std::string &dir_path, const std::string &rel_path, bool skip_safety_check)
133 {
134 char slash;
135 #ifdef _WIN32
136 slash = '\\';
137 #else
138 slash = '/';
139 #endif
140
141 if(!skip_safety_check && !MDFN_IsFIROPSafe(rel_path))
142 throw MDFN_Error(0, _("Referenced path \"%s\" is potentially unsafe. See \"filesys.untrusted_fip_check\" setting.\n"), rel_path.c_str());
143
144 if(IsAbsolutePath(rel_path.c_str()))
145 return(rel_path);
146 else
147 return(dir_path + slash + rel_path);
148 }
149
150 const char * GetFNComponent(const char *str)
151 {
152 const char *tp1;
153
154 #ifdef _WIN32
155 tp1 = ((char *)strrchr(str,'\\'));
156
157 const char *tp3;
158
159 tp3 = ((char *)strrchr(str,'/'));
160
161 if (tp1<tp3)
162 tp1 = tp3;
163 #else
164 tp1 = ((char *)strrchr(str,'/'));
165 #endif
166
167 if (tp1)
168 return (tp1+1);
169 else
170 return (str);
171 }
172
173 // Remove whitespace from beginning of string
174 void MDFN_ltrim(char *string)
175 {
176 int32 di, si;
177 bool InWhitespace = TRUE;
178
179 di = si = 0;
180
181 while(string[si])
182 {
183 if(InWhitespace && (string[si] == ' ' || string[si] == '\r' || string[si] == '\n' || string[si] == '\t' || string[si] == 0x0b))
184 {
185
186 }
187 else
188 {
189 InWhitespace = FALSE;
190 string[di] = string[si];
191 di++;
192 }
193 si++;
194 }
195 string[di] = 0;
196 }
197
198 // Remove whitespace from end of string
199 void MDFN_rtrim(char *string)
200 {
201 int32 len = strlen(string);
202
203 if(len)
204 {
205 for(int32 x = len - 1; x >= 0; x--)
206 {
207 if(string[x] == ' ' || string[x] == '\r' || string[x] == '\n' || string[x] == '\t' || string[x] == 0x0b)
208 string[x] = 0;
209 else
210 break;
211 }
212 }
213 }
214
215 void MDFN_trim(char *string)
216 {
217 MDFN_rtrim(string);
218 MDFN_ltrim(string);
219 }
220
221 // Remove whitespace from beginning of string
222 void MDFN_ltrim(std::string &string)
223 {
224 size_t len = string.length();
225 size_t di, si;
226 bool InWhitespace = TRUE;
227
228 di = si = 0;
229
230 while(si < len)
231 {
232 if(InWhitespace && (string[si] == ' ' || string[si] == '\r' || string[si] == '\n' || string[si] == '\t' || string[si] == 0x0b))
233 {
234
235 }
236 else
237 {
238 InWhitespace = FALSE;
239 string[di] = string[si];
240 di++;
241 }
242 si++;
243 }
244
245 string.resize(di);
246 }
247
248 // Remove whitespace from end of string
249 void MDFN_rtrim(std::string &string)
250 {
251 size_t len = string.length();
252
253 if(len)
254 {
255 size_t x = len;
256 size_t new_len = len;
257
258 do
259 {
260 x--;
261
262 if(!(string[x] == ' ' || string[x] == '\r' || string[x] == '\n' || string[x] == '\t' || string[x] == 0x0b))
263 break;
264
265 new_len--;
266 } while(x);
267
268 string.resize(new_len);
269 }
270 }
271
272
273 void MDFN_trim(std::string &string)
274 {
275 MDFN_rtrim(string);
276 MDFN_ltrim(string);
277 }
278
0 #ifndef _GENERAL_H
1 #define _GENERAL_H
2
3 #include <string>
4
5 extern uint32 MDFN_RoundUpPow2(uint32);
6
7 void GetFileBase(const char *f);
8
9 // File-inclusion for-read-only path, for PSF and CUE/TOC sheet usage.
10 bool MDFN_IsFIROPSafe(const std::string &path);
11
12 std::string MDFN_MakeFName(int type, int id1, const char *cd1);
13
14 void MDFN_ltrim(char *string);
15 void MDFN_rtrim(char *string);
16 void MDFN_trim(char *string);
17
18 void MDFN_ltrim(std::string &string);
19 void MDFN_rtrim(std::string &string);
20 void MDFN_trim(std::string &string);
21
22 typedef enum
23 {
24 MDFNMKF_STATE = 0,
25 MDFNMKF_SNAP,
26 MDFNMKF_SAV,
27 MDFNMKF_CHEAT,
28 MDFNMKF_PALETTE,
29 MDFNMKF_IPS,
30 MDFNMKF_MOVIE,
31 MDFNMKF_AUX,
32 MDFNMKF_SNAP_DAT,
33 MDFNMKF_CHEAT_TMP,
34 MDFNMKF_FIRMWARE
35 } MakeFName_Type;
36
37 const char *MDFN_MakeFName(MakeFName_Type type, int id1, const char *cd1);
38
39 const char * GetFNComponent(const char *str);
40
41 void MDFN_GetFilePathComponents(const std::string &file_path, std::string *dir_path_out, std::string *file_base_out = NULL, std::string *file_ext_out = NULL);
42 std::string MDFN_EvalFIP(const std::string &dir_path, const std::string &rel_path, bool skip_safety_check = false);
43 #endif
0 #ifndef _GIT_H
1 #define _GIT_H
2
3 #include <string>
4
5 #include "video.h"
6 #include "state.h"
7 #include "settings-common.h"
8
9 typedef struct
10 {
11 const char *extension;
12 const char *description;
13 } FileExtensionSpecStruct;
14
15 #include "file.h"
16
17 enum
18 {
19 MDFN_ROTATE0 = 0,
20 MDFN_ROTATE90,
21 MDFN_ROTATE180,
22 MDFN_ROTATE270
23 };
24
25 typedef enum
26 {
27 VIDSYS_NONE,
28 VIDSYS_PAL,
29 VIDSYS_PAL_M,
30 VIDSYS_NTSC,
31 VIDSYS_SECAM
32 } VideoSystems;
33
34 typedef enum
35 {
36 GMT_CART,
37 GMT_ARCADE,
38 GMT_DISK,
39 GMT_CDROM,
40 GMT_PLAYER
41 } GameMediumTypes;
42
43 typedef enum
44 {
45 IDIT_BUTTON,
46 IDIT_BUTTON_CAN_RAPID,
47
48 IDIT_X_AXIS,
49 IDIT_Y_AXIS,
50 IDIT_X_AXIS_REL,
51 IDIT_Y_AXIS_REL,
52
53 IDIT_BYTE_SPECIAL,
54
55 IDIT_BUTTON_ANALOG,
56 IDIT_RUMBLE
57 } InputDeviceInputType;
58
59 #define IDIT_BUTTON_ANALOG_FLAG_SQLR 0x00000001
60
61 typedef struct
62 {
63 const char *SettingName;
64 const char *Name;
65 const int ConfigOrder;
66 const InputDeviceInputType Type;
67 const char *ExcludeName;
68 const char *RotateName[3];
69 unsigned Flags;
70 } InputDeviceInputInfoStruct;
71
72 typedef struct
73 {
74 const char *ShortName;
75 const char *FullName;
76 const char *Description;
77
78 const void *PortExpanderDeviceInfo;
79 int NumInputs;
80 const InputDeviceInputInfoStruct *IDII;
81 } InputDeviceInfoStruct;
82
83 typedef struct
84 {
85 const char *ShortName;
86 const char *FullName;
87 int NumTypes;
88 InputDeviceInfoStruct *DeviceInfo;
89 const char *DefaultDevice;
90 } InputPortInfoStruct;
91
92 typedef struct
93 {
94 int InputPorts;
95 const InputPortInfoStruct *Types;
96 } InputInfoStruct;
97
98 struct MemoryPatch;
99
100 struct CheatFormatStruct
101 {
102 const char *FullName;
103 const char *Description;
104
105 bool (*DecodeCheat)(const std::string& cheat_string, MemoryPatch* patch);
106 };
107
108 struct CheatFormatInfoStruct
109 {
110 unsigned NumFormats;
111
112 CheatFormatStruct *Formats;
113 };
114
115 enum
116 {
117 MDFN_MSC_RESET = 0x01,
118 MDFN_MSC_POWER = 0x02,
119
120 MDFN_MSC_INSERT_COIN = 0x07,
121
122 MDFN_MSC_TOGGLE_DIP0 = 0x10,
123 MDFN_MSC_TOGGLE_DIP1,
124 MDFN_MSC_TOGGLE_DIP2,
125 MDFN_MSC_TOGGLE_DIP3,
126 MDFN_MSC_TOGGLE_DIP4,
127 MDFN_MSC_TOGGLE_DIP5,
128 MDFN_MSC_TOGGLE_DIP6,
129 MDFN_MSC_TOGGLE_DIP7,
130 MDFN_MSC_TOGGLE_DIP8,
131 MDFN_MSC_TOGGLE_DIP9,
132 MDFN_MSC_TOGGLE_DIP10,
133 MDFN_MSC_TOGGLE_DIP11,
134 MDFN_MSC_TOGGLE_DIP12,
135 MDFN_MSC_TOGGLE_DIP13,
136 MDFN_MSC_TOGGLE_DIP14,
137 MDFN_MSC_TOGGLE_DIP15,
138
139
140 // n of DISKn translates to is emulation module specific.
141 MDFN_MSC_INSERT_DISK0 = 0x20,
142 MDFN_MSC_INSERT_DISK1,
143 MDFN_MSC_INSERT_DISK2,
144 MDFN_MSC_INSERT_DISK3,
145 MDFN_MSC_INSERT_DISK4,
146 MDFN_MSC_INSERT_DISK5,
147 MDFN_MSC_INSERT_DISK6,
148 MDFN_MSC_INSERT_DISK7,
149 MDFN_MSC_INSERT_DISK8,
150 MDFN_MSC_INSERT_DISK9,
151 MDFN_MSC_INSERT_DISK10,
152 MDFN_MSC_INSERT_DISK11,
153 MDFN_MSC_INSERT_DISK12,
154 MDFN_MSC_INSERT_DISK13,
155 MDFN_MSC_INSERT_DISK14,
156 MDFN_MSC_INSERT_DISK15,
157
158 MDFN_MSC_INSERT_DISK = 0x30,
159 MDFN_MSC_EJECT_DISK = 0x31,
160
161 MDFN_MSC_SELECT_DISK = 0x32,
162
163 MDFN_MSC__LAST = 0x3F
164 };
165
166 typedef struct
167 {
168 // Pitch(32-bit) must be equal to width and >= the "fb_width" specified in the MDFNGI struct for the emulated system.
169 // Height must be >= to the "fb_height" specified in the MDFNGI struct for the emulated system.
170 // The framebuffer pointed to by surface->pixels is written to by the system emulation code.
171 MDFN_Surface *surface;
172
173 // Will be set to TRUE if the video pixel format has changed since the last call to Emulate(), FALSE otherwise.
174 // Will be set to TRUE on the first call to the Emulate() function/method
175 bool VideoFormatChanged;
176
177 // Set by the system emulation code every frame, to denote the horizontal and vertical offsets of the image, and the size
178 // of the image. If the emulated system sets the elements of LineWidths, then the horizontal offset(x) and width(w) of this structure
179 // are ignored while drawing the image.
180 MDFN_Rect DisplayRect;
181
182 // Pointer to an array of MDFN_Rect, number of elements = fb_height, set by the driver code. Individual MDFN_Rect structs written
183 // to by system emulation code. If the emulated system doesn't support multiple screen widths per frame, or if you handle
184 // such a situation by outputting at a constant width-per-frame that is the least-common-multiple of the screen widths, then
185 // you can ignore this. If you do wish to use this, you must set all elements every frame.
186 int32_t *LineWidths;
187
188 // TODO
189 bool *IsFMV;
190
191 // Set(optionally) by emulation code. If InterlaceOn is true, then assume field height is 1/2 DisplayRect.h, and
192 // only every other line in surface (with the start line defined by InterlacedField) has valid data
193 // (it's up to internal Mednafen code to deinterlace it).
194 bool InterlaceOn;
195 bool InterlaceField;
196
197 // Skip rendering this frame if true. Set by the driver code.
198 int skip;
199
200 //
201 // If sound is disabled, the driver code must set SoundRate to false, SoundBuf to NULL, SoundBufMaxSize to 0.
202
203 // Will be set to TRUE if the sound format(only rate for now, at least) has changed since the last call to Emulate(), FALSE otherwise.
204 // Will be set to TRUE on the first call to the Emulate() function/method
205 bool SoundFormatChanged;
206
207 // Sound rate. Set by driver side.
208 double SoundRate;
209
210 // Pointer to sound buffer, set by the driver code, that the emulation code should render sound to.
211 // Guaranteed to be at least 500ms in length, but emulation code really shouldn't exceed 40ms or so. Additionally, if emulation code
212 // generates >= 100ms,
213 // DEPRECATED: Emulation code may set this pointer to a sound buffer internal to the emulation module.
214 int16_t *SoundBuf;
215
216 // Maximum size of the sound buffer, in frames. Set by the driver code.
217 int32_t SoundBufMaxSize;
218
219 // Number of frames currently in internal sound buffer. Set by the system emulation code, to be read by the driver code.
220 int32_t SoundBufSize;
221 int32_t SoundBufSizeALMS; // SoundBufSize value at last MidSync(), 0
222 // if mid sync isn't implemented for the emulation module in use.
223
224 // Number of cycles that this frame consumed, using MDFNGI::MasterClock as a time base.
225 // Set by emulation code.
226 int64_t MasterCycles;
227 int64_t MasterCyclesALMS; // MasterCycles value at last MidSync(), 0
228 // if mid sync isn't implemented for the emulation module in use.
229
230 // Current sound volume(0.000...<=volume<=1.000...). If, after calling Emulate(), it is still != 1, Mednafen will handle it internally.
231 // Emulation modules can handle volume themselves if they like, for speed reasons. If they do, afterwards, they should set its value to 1.
232 double SoundVolume;
233
234 // Current sound speed multiplier. Set by the driver code. If, after calling Emulate(), it is still != 1, Mednafen will handle it internally
235 // by resampling the audio. This means that emulation modules can handle(and set the value to 1 after handling it) it if they want to get the most
236 // performance possible. HOWEVER, emulation modules must make sure the value is in a range(with minimum and maximum) that their code can handle
237 // before they try to handle it.
238 double soundmultiplier;
239
240 // True if we want to rewind one frame. Set by the driver code.
241 bool NeedRewind;
242
243 // Sound reversal during state rewinding is normally done in mednafen.cpp, but
244 // individual system emulation code can also do it if this is set, and clear it after it's done.
245 // (Also, the driver code shouldn't touch this variable)
246 bool NeedSoundReverse;
247
248 } EmulateSpecStruct;
249
250 typedef enum
251 {
252 MODPRIO_INTERNAL_EXTRA_LOW = 0, // For "cdplay" module, mostly.
253
254 MODPRIO_INTERNAL_LOW = 10,
255 MODPRIO_EXTERNAL_LOW = 20,
256 MODPRIO_INTERNAL_HIGH = 30,
257 MODPRIO_EXTERNAL_HIGH = 40
258 } ModPrio;
259
260 class CDIF;
261
262 typedef struct
263 {
264 /* Private functions to Mednafen. Do not call directly
265 from the driver code, or else bad things shall happen. Maybe. Probably not, but don't
266 do it(yet)!
267 */
268 // Short system name, lowercase a-z, 0-9, and _ are the only allowable characters!
269 const char *shortname;
270
271 // Full system name. Preferably English letters, but can be UTF8
272 const char *fullname;
273
274 // Pointer to an array of FileExtensionSpecStruct, with the last entry being { NULL, NULL } to terminate the list.
275 // This list is used to make best-guess choices, when calling the TestMagic*() functions would be unreasonable, such
276 // as when scanning a ZIP archive for a file to load. The list may also be used in the future for GUI file open windows.
277 const FileExtensionSpecStruct *FileExtensions;
278
279 ModPrio ModulePriority;
280
281 void *Debugger;
282 InputInfoStruct *InputInfo;
283
284 // Returns 1 on successful load, 0 on fatal error(deprecated: -1 on unrecognized format)
285 int (*Load)(const char *name, MDFNFILE *fp);
286
287 // Return TRUE if the file is a recognized type, FALSE if not.
288 bool (*TestMagic)(const char *name, MDFNFILE *fp);
289
290 //
291 // (*CDInterfaces).size() is guaranteed to be >= 1.
292 int (*LoadCD)(std::vector<CDIF *> *CDInterfaces);
293 bool (*TestMagicCD)(std::vector<CDIF *> *CDInterfaces);
294
295 void (*CloseGame)(void);
296
297 void (*SetLayerEnableMask)(uint64_t mask); // Video
298 const char *LayerNames;
299
300 void (*SetChanEnableMask)(uint64_t mask); // Audio(TODO, placeholder)
301 const char *ChanNames;
302
303 void (*InstallReadPatch)(uint32_t address);
304 void (*RemoveReadPatches)(void);
305 uint8_t (*MemRead)(uint32_t addr);
306
307 #ifdef WANT_NEW_API
308 CheatFormatInfoStruct *CheatFormatInfo;
309 #endif
310
311 bool SaveStateAltersState; // true for bsnes and some libco-style emulators, false otherwise.
312 // Main save state routine, called by the save state code in state.cpp.
313 // When saving, load is set to 0. When loading, load is set to the version field of the save state being loaded.
314 // data_only is true when the save state data is temporary, such as being saved into memory for state rewinding.
315 int (*StateAction)(StateMem *sm, int load, int data_only);
316
317 void (*Emulate)(EmulateSpecStruct *espec);
318 void (*SetInput)(int port, const char *type, void *ptr);
319
320 void (*DoSimpleCommand)(int cmd);
321
322 const MDFNSetting *Settings;
323
324 // Time base for EmulateSpecStruct::MasterCycles
325 #define MDFN_MASTERCLOCK_FIXED(n) ((int64_t)((double)(n) * (INT64_C(1) << 32)))
326 int64_t MasterClock;
327
328 uint32_t fps; // frames per second * 65536 * 256, truncated
329
330 // multires is a hint that, if set, indicates that the system has fairly programmable video modes(particularly, the ability
331 // to display multiple horizontal resolutions, such as the PCE, PC-FX, or Genesis). In practice, it will cause the driver
332 // code to set the linear interpolation on by default.
333 //
334 // lcm_width and lcm_height are the least common multiples of all possible
335 // resolutions in the frame buffer as specified by DisplayRect/LineWidths(Ex for PCE: widths of 256, 341.333333, 512,
336 // lcm = 1024)
337 //
338 // nominal_width and nominal_height specify the resolution that Mednafen should display
339 // the framebuffer image in at 1x scaling, scaled from the dimensions of DisplayRect, and optionally the LineWidths array
340 // passed through espec to the Emulate() function.
341 //
342 bool multires;
343
344 int lcm_width;
345 int lcm_height;
346
347 void *dummy_separator; //
348
349 int nominal_width;
350 int nominal_height;
351
352 int fb_width; // Width of the framebuffer(not necessarily width of the image). MDFN_Surface width should be >= this.
353 int fb_height; // Height of the framebuffer passed to the Emulate() function(not necessarily height of the image)
354
355 int soundchan; // Number of output sound channels.
356
357
358 int rotated;
359
360 uint8_t *name; /* Game name, UTF8 encoding */
361 uint8_t MD5[16];
362 uint8_t GameSetMD5[16]; /* A unique ID for the game set this CD belongs to, only used in PC-FX emulation. */
363 bool GameSetMD5Valid; /* True if GameSetMD5 is valid. */
364
365 uint8_t StateMD5[16]; // ID to use in save state naming and netplay session IDs, if
366 bool StateMD5Valid; // StateMD5Valid is true(useful for systems with multiple BIOS revisions, e.g. PS1).
367
368 int soundrate; /* For Ogg Vorbis expansion sound wacky support. 0 for default. */
369
370 VideoSystems VideoSystem;
371 GameMediumTypes GameType;
372
373 //int DiskLogicalCount; // A single double-sided disk would be 2 here.
374 //const char *DiskNames; // Null-terminated.
375
376 const char *cspecial; /* Special cart expansion: DIP switches, barcode reader, etc. */
377
378 std::vector<const char *>DesiredInput; // Desired input device for the input ports, NULL for don't care
379
380 // For mouse relative motion.
381 double mouse_sensitivity;
382
383
384 // For absolute coordinates(IDIT_X_AXIS and IDIT_Y_AXIS), usually mapped to a mouse(hence the naming).
385 float mouse_scale_x, mouse_scale_y;
386 float mouse_offs_x, mouse_offs_y;
387 } MDFNGI;
388
389 #endif
0 /* RetroArch - A frontend for libretro.
1 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
2 *
3 * RetroArch is free software: you can redistribute it and/or modify it under the terms
4 * of the GNU General Public License as published by the Free Software Found-
5 * ation, either version 3 of the License, or (at your option) any later version.
6 *
7 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9 * PURPOSE. See the GNU General Public License for more details.
10 *
11 * You should have received a copy of the GNU General Public License along with RetroArch.
12 * If not, see <http://www.gnu.org/licenses/>.
13 */
14
15 #ifndef __RARCH_BOOLEAN_H
16 #define __RARCH_BOOLEAN_H
17
18 #ifndef __cplusplus
19
20 #if defined(_MSC_VER) && !defined(SN_TARGET_PS3)
21 /* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
22 #define bool unsigned char
23 #define true 1
24 #define false 0
25 #else
26 #include <stdbool.h>
27 #endif
28
29 #endif
30
31 #endif
32
0 /* include/config.h.in. Generated from configure.ac by autoheader. */
1
2 /* Define if building universal (internal helper macro) */
3 #undef AC_APPLE_UNIVERSAL_BUILD
4
5 /* Define if we are compiling for PPC architectures. */
6 #undef ARCH_POWERPC
7
8 /* Define if we are compiling with AltiVec usage. */
9 #undef ARCH_POWERPC_ALTIVEC
10
11 /* Define if we are compiling for 32-bit or 64-bit x86 architectures. */
12 #undef ARCH_X86
13
14 /* Define if we are compiling for 32-bit x86 architectures. */
15 #undef ARCH_X86_32
16
17 /* Define if we are compiling for 64-bit x86 architectures. */
18 #undef ARCH_X86_64
19
20 /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP
21 systems. This function is required for `alloca.c' support on those systems.
22 */
23 #undef CRAY_STACKSEG_END
24
25 /* Define to 1 if using `alloca.c'. */
26 #undef C_ALLOCA
27
28 /* Define to 1 if translation of program messages to the user's native
29 language is requested. */
30 #undef ENABLE_NLS
31
32 /* Define to 1 if you have the `accept' function. */
33 #undef HAVE_ACCEPT
34
35 /* Define to 1 if you have `alloca', as a function or macro. */
36 #undef HAVE_ALLOCA
37
38 /* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix).
39 */
40 #undef HAVE_ALLOCA_H
41
42 /* Define if we are compiling with ALSA support. */
43 #undef HAVE_ALSA
44
45 /* Define if altivec.h is present and usable. */
46 #undef HAVE_ALTIVEC_H
47
48 /* Define if we should include from OpenGL instead of GL */
49 #undef HAVE_APPLE_OPENGL_FRAMEWORK
50
51 /* Define to 1 if you have the `argz_count' function. */
52 #undef HAVE_ARGZ_COUNT
53
54 /* Define to 1 if you have the <argz.h> header file. */
55 #undef HAVE_ARGZ_H
56
57 /* Define to 1 if you have the `argz_next' function. */
58 #undef HAVE_ARGZ_NEXT
59
60 /* Define to 1 if you have the `argz_stringify' function. */
61 #undef HAVE_ARGZ_STRINGIFY
62
63 /* Define to 1 if you have the `asprintf' function. */
64 #undef HAVE_ASPRINTF
65
66 /* Define to 1 if you have the `bind' function. */
67 #undef HAVE_BIND
68
69 /* Define to 1 if the compiler understands __builtin_expect. */
70 #undef HAVE_BUILTIN_EXPECT
71
72 /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
73 CoreFoundation framework. */
74 #undef HAVE_CFLOCALECOPYCURRENT
75
76 /* Define to 1 if you have the MacOS X function CFPreferencesCopyAppValue in
77 the CoreFoundation framework. */
78 #undef HAVE_CFPREFERENCESCOPYAPPVALUE
79
80 /* Define to 1 if you have the `clock_gettime' function. */
81 #undef HAVE_CLOCK_GETTIME
82
83 /* Define to 1 if you have the `close' function. */
84 #undef HAVE_CLOSE
85
86 /* Define to 1 if you have the `connect' function. */
87 #undef HAVE_CONNECT
88
89 /* Define if the GNU dcgettext() function is already present or preinstalled.
90 */
91 #undef HAVE_DCGETTEXT
92
93 /* Define to 1 if you have the declaration of `feof_unlocked', and to 0 if you
94 don't. */
95 #undef HAVE_DECL_FEOF_UNLOCKED
96
97 /* Define to 1 if you have the declaration of `fgets_unlocked', and to 0 if
98 you don't. */
99 #undef HAVE_DECL_FGETS_UNLOCKED
100
101 /* Define to 1 if you have the declaration of `getc_unlocked', and to 0 if you
102 don't. */
103 #undef HAVE_DECL_GETC_UNLOCKED
104
105 /* Define to 1 if you have the declaration of `_snprintf', and to 0 if you
106 don't. */
107 #undef HAVE_DECL__SNPRINTF
108
109 /* Define to 1 if you have the declaration of `_snwprintf', and to 0 if you
110 don't. */
111 #undef HAVE_DECL__SNWPRINTF
112
113 /* Define if we are compiling with DirectSound support. */
114 #undef HAVE_DIRECTSOUND
115
116 /* Define to 1 if you have the <dlfcn.h> header file. */
117 #undef HAVE_DLFCN_H
118
119 /* Define to 1 if you have the `fcntl' function. */
120 #undef HAVE_FCNTL
121
122 /* Define to 1 if you have the <fcntl.h> header file. */
123 #undef HAVE_FCNTL_H
124
125 /* Define to 1 if you have the `fopen64' function. */
126 #undef HAVE_FOPEN64
127
128 /* Define to 1 if you have the `freeaddrinfo' function. */
129 #undef HAVE_FREEADDRINFO
130
131 /* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
132 #undef HAVE_FSEEKO
133
134 /* Define to 1 if you have the `fseeko64' function. */
135 #undef HAVE_FSEEKO64
136
137 /* Define to 1 if you have the `fstat64' function. */
138 #undef HAVE_FSTAT64
139
140 /* Define to 1 if you have the `ftello' function. */
141 #undef HAVE_FTELLO
142
143 /* Define to 1 if you have the `ftello64' function. */
144 #undef HAVE_FTELLO64
145
146 /* Define to 1 if you have the `fwprintf' function. */
147 #undef HAVE_FWPRINTF
148
149 /* Define to 1 if you have the `gai_strerror' function. */
150 #undef HAVE_GAI_STRERROR
151
152 /* Define to 1 if you have the `getaddrinfo' function. */
153 #undef HAVE_GETADDRINFO
154
155 /* Define to 1 if you have the `getcwd' function. */
156 #undef HAVE_GETCWD
157
158 /* Define to 1 if you have the `getegid' function. */
159 #undef HAVE_GETEGID
160
161 /* Define to 1 if you have the `getenv' function. */
162 #undef HAVE_GETENV
163
164 /* Define to 1 if you have the `geteuid' function. */
165 #undef HAVE_GETEUID
166
167 /* Define to 1 if you have the `getgid' function. */
168 #undef HAVE_GETGID
169
170 /* Define to 1 if you have the `gethostbyaddr' function. */
171 #undef HAVE_GETHOSTBYADDR
172
173 /* Define to 1 if you have the `gethostbyname' function. */
174 #undef HAVE_GETHOSTBYNAME
175
176 /* Define to 1 if you have the `getpagesize' function. */
177 #undef HAVE_GETPAGESIZE
178
179 /* Define to 1 if you have the `getpwuid' function. */
180 #undef HAVE_GETPWUID
181
182 /* Define to 1 if you have the `getsockopt' function. */
183 #undef HAVE_GETSOCKOPT
184
185 /* Define if the GNU gettext() function is already present or preinstalled. */
186 #undef HAVE_GETTEXT
187
188 /* Define to 1 if you have the `gettimeofday' function. */
189 #undef HAVE_GETTIMEOFDAY
190
191 /* Define to 1 if you have the `getuid' function. */
192 #undef HAVE_GETUID
193
194 /* Define if you have the iconv() function and it works. */
195 #undef HAVE_ICONV
196
197 /* Define if you have the 'intmax_t' type in <stdint.h> or <inttypes.h>. */
198 #undef HAVE_INTMAX_T
199
200 /* Define to 1 if you have the <inttypes.h> header file. */
201 #undef HAVE_INTTYPES_H
202
203 /* Define if <inttypes.h> exists, doesn't clash with <sys/types.h>, and
204 declares uintmax_t. */
205 #undef HAVE_INTTYPES_H_WITH_UINTMAX
206
207 /* Define if we are compiling with JACK support. */
208 #undef HAVE_JACK
209
210 /* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
211 #undef HAVE_LANGINFO_CODESET
212
213 /* Define if your <locale.h> file defines LC_MESSAGES. */
214 #undef HAVE_LC_MESSAGES
215
216 /* Define to 1 if you have the `asound' library (-lasound). */
217 #undef HAVE_LIBASOUND
218
219 /* Define if we are compiling with libsndfile support. */
220 #undef HAVE_LIBSNDFILE
221
222 /* Define to 1 if you have the `z' library (-lz). */
223 #undef HAVE_LIBZ
224
225 /* Define to 1 if you have the <limits.h> header file. */
226 #undef HAVE_LIMITS_H
227
228 /* Define if we are compiling with Linux joystick support. */
229 #undef HAVE_LINUX_JOYSTICK
230
231 /* Define to 1 if you have the `listen' function. */
232 #undef HAVE_LISTEN
233
234 /* Define to 1 if the system has the type `long long int'. */
235 #undef HAVE_LONG_LONG_INT
236
237 /* Define to 1 if you have the `madvise' function. */
238 #undef HAVE_MADVISE
239
240 /* Define to 1 if you have the `mbrtowc' function. */
241 #undef HAVE_MBRTOWC
242
243 /* Define to 1 if you have the `memcmp' function. */
244 #undef HAVE_MEMCMP
245
246 /* Define to 1 if you have the `memcpy' function. */
247 #undef HAVE_MEMCPY
248
249 /* Define to 1 if you have the `memmove' function. */
250 #undef HAVE_MEMMOVE
251
252 /* Define to 1 if you have the <memory.h> header file. */
253 #undef HAVE_MEMORY_H
254
255 /* Define to 1 if you have the `mempcpy' function. */
256 #undef HAVE_MEMPCPY
257
258 /* Define to 1 if you have the `memset' function. */
259 #undef HAVE_MEMSET
260
261 /* Define to 1 if you have the `mkdir' function. */
262 #undef HAVE_MKDIR
263
264 /* Define to 1 if you have a working `mmap' system call. */
265 #undef HAVE_MMAP
266
267 /* Define to 1 if you have the `munmap' function. */
268 #undef HAVE_MUNMAP
269
270 /* Define to 1 if you have the `nanosleep' function. */
271 #undef HAVE_NANOSLEEP
272
273 /* Define to 1 if you have the `newlocale' function. */
274 #undef HAVE_NEWLOCALE
275
276 /* Define if we are compiling with OSS support. */
277 #undef HAVE_OSSDSP
278
279 /* Define if your printf() function supports format strings with positions. */
280 #undef HAVE_POSIX_PRINTF
281
282 /* Define if we are compiling with POSIX sockets support. */
283 #undef HAVE_POSIX_SOCKETS
284
285 /* Define if the <pthread.h> defines PTHREAD_MUTEX_RECURSIVE. */
286 #undef HAVE_PTHREAD_MUTEX_RECURSIVE
287
288 /* Define if the POSIX multithreading library has read/write locks. */
289 #undef HAVE_PTHREAD_RWLOCK
290
291 /* Define to 1 if you have the `putenv' function. */
292 #undef HAVE_PUTENV
293
294 /* Define to 1 if you have the `recv' function. */
295 #undef HAVE_RECV
296
297 /* Define if we are compiling with SDL sound support. */
298 #undef HAVE_SDL
299
300 /* Define to 1 if you have the `select' function. */
301 #undef HAVE_SELECT
302
303 /* Define to 1 if you have the `send' function. */
304 #undef HAVE_SEND
305
306 /* Define to 1 if you have the `setenv' function. */
307 #undef HAVE_SETENV
308
309 /* Define to 1 if you have the `setlocale' function. */
310 #undef HAVE_SETLOCALE
311
312 /* Define to 1 if you have the `setsockopt' function. */
313 #undef HAVE_SETSOCKOPT
314
315 /* Define to 1 if you have the `sigaction' function. */
316 #undef HAVE_SIGACTION
317
318 /* Define to 1 if you have the `signal' function. */
319 #undef HAVE_SIGNAL
320
321 /* Define to 1 if you have the `snprintf' function. */
322 #undef HAVE_SNPRINTF
323
324 /* Define to 1 if you have the `socket' function. */
325 #undef HAVE_SOCKET
326
327 /* Define to 1 if you have the <stddef.h> header file. */
328 #undef HAVE_STDDEF_H
329
330 /* Define to 1 if you have the <stdint.h> header file. */
331 #undef HAVE_STDINT_H
332
333 /* Define if <stdint.h> exists, doesn't clash with <sys/types.h>, and declares
334 uintmax_t. */
335 #undef HAVE_STDINT_H_WITH_UINTMAX
336
337 /* Define to 1 if you have the <stdlib.h> header file. */
338 #undef HAVE_STDLIB_H
339
340 /* Define to 1 if you have the `stpcpy' function. */
341 #undef HAVE_STPCPY
342
343 /* Define to 1 if you have the `strcasecmp' function. */
344 #undef HAVE_STRCASECMP
345
346 /* Define to 1 if you have the `strdup' function. */
347 #undef HAVE_STRDUP
348
349 /* Define to 1 if you have the `strerror' function. */
350 #undef HAVE_STRERROR
351
352 /* Define to 1 if you have the `strerror_r' function. */
353 #undef HAVE_STRERROR_R
354
355 /* Define to 1 if you have the <strings.h> header file. */
356 #undef HAVE_STRINGS_H
357
358 /* Define to 1 if you have the <string.h> header file. */
359 #undef HAVE_STRING_H
360
361 /* Define to 1 if you have the `strnlen' function. */
362 #undef HAVE_STRNLEN
363
364 /* Define to 1 if you have the `strtoul' function. */
365 #undef HAVE_STRTOUL
366
367 /* Define to 1 if you have the <sys/param.h> header file. */
368 #undef HAVE_SYS_PARAM_H
369
370 /* Define to 1 if you have the <sys/stat.h> header file. */
371 #undef HAVE_SYS_STAT_H
372
373 /* Define to 1 if you have the <sys/types.h> header file. */
374 #undef HAVE_SYS_TYPES_H
375
376 /* Define to 1 if you have the `tsearch' function. */
377 #undef HAVE_TSEARCH
378
379 /* Define if you have the 'uintmax_t' type in <stdint.h> or <inttypes.h>. */
380 #undef HAVE_UINTMAX_T
381
382 /* Define to 1 if you have the <unistd.h> header file. */
383 #undef HAVE_UNISTD_H
384
385 /* Define to 1 if the system has the type `unsigned long long int'. */
386 #undef HAVE_UNSIGNED_LONG_LONG_INT
387
388 /* Define to 1 if you have the `uselocale' function. */
389 #undef HAVE_USELOCALE
390
391 /* Define to 1 if you have the `usleep' function. */
392 #undef HAVE_USLEEP
393
394 /* Define to 1 or 0, depending whether the compiler supports simple visibility
395 declarations. */
396 #undef HAVE_VISIBILITY
397
398 /* Define if you have the 'wchar_t' type. */
399 #undef HAVE_WCHAR_T
400
401 /* Define to 1 if you have the `wcrtomb' function. */
402 #undef HAVE_WCRTOMB
403
404 /* Define to 1 if you have the `wcslen' function. */
405 #undef HAVE_WCSLEN
406
407 /* Define to 1 if you have the `wcsnlen' function. */
408 #undef HAVE_WCSNLEN
409
410 /* Define if you have the 'wint_t' type. */
411 #undef HAVE_WINT_T
412
413 /* Define to 1 if O_NOATIME works. */
414 #undef HAVE_WORKING_O_NOATIME
415
416 /* Define to 1 if O_NOFOLLOW works. */
417 #undef HAVE_WORKING_O_NOFOLLOW
418
419 /* Define to 1 if you have the `_mkdir' function. */
420 #undef HAVE__MKDIR
421
422 /* Define to 1 if you have the `__fsetlocking' function. */
423 #undef HAVE___FSETLOCKING
424
425 /* Define as const if the declaration of iconv() needs const. */
426 #undef ICONV_CONST
427
428 /* Define if integer division by zero raises signal SIGFPE. */
429 #undef INTDIV0_RAISES_SIGFPE
430
431 /* Define on little-endian platforms. */
432 #undef LSB_FIRST
433
434 /* Define to the sub-directory in which libtool stores uninstalled libraries.
435 */
436 #undef LT_OBJDIR
437
438 /* Mednafen version definition. */
439 #undef MEDNAFEN_VERSION
440
441 /* Mednafen version numeric. */
442 #undef MEDNAFEN_VERSION_NUMERIC
443
444 /* Define if config.h is present */
445 #undef MINILZO_HAVE_CONFIG_H
446
447 /* Define if mkdir takes only one argument. */
448 #undef MKDIR_TAKES_ONE_ARG
449
450 /* Define to use fixed-point MPC decoder. */
451 #undef MPC_FIXED_POINT
452
453 /* Define on big-endian platforms. */
454 #undef MSB_FIRST
455
456 /* Define to 1 if your C compiler doesn't accept -c and -o together. */
457 #undef NO_MINUS_C_MINUS_O
458
459 /* Name of package */
460 #undef PACKAGE
461
462 /* Define to the address where bug reports for this package should be sent. */
463 #undef PACKAGE_BUGREPORT
464
465 /* Define to the full name of this package. */
466 #undef PACKAGE_NAME
467
468 /* Define to the full name and version of this package. */
469 #undef PACKAGE_STRING
470
471 /* Define to the one symbol short name of this package. */
472 #undef PACKAGE_TARNAME
473
474 /* Define to the home page for this package. */
475 #undef PACKAGE_URL
476
477 /* Define to the version of this package. */
478 #undef PACKAGE_VERSION
479
480 /* Define if <inttypes.h> exists and defines unusable PRI* macros. */
481 #undef PRI_MACROS_BROKEN
482
483 /* Defines the filesystem path-separator type. */
484 #undef PSS_STYLE
485
486 /* Define if the pthread_in_use() detection is hard. */
487 #undef PTHREAD_IN_USE_DETECTION_HARD
488
489 /* The size of `double', as computed by sizeof. */
490 #undef SIZEOF_DOUBLE
491
492 /* The size of `int', as computed by sizeof. */
493 #undef SIZEOF_INT
494
495 /* The size of `long', as computed by sizeof. */
496 #undef SIZEOF_LONG
497
498 /* The size of `long long', as computed by sizeof. */
499 #undef SIZEOF_LONG_LONG
500
501 /* The size of `off_t', as computed by sizeof. */
502 #undef SIZEOF_OFF_T
503
504 /* The size of `ptrdiff_t', as computed by sizeof. */
505 #undef SIZEOF_PTRDIFF_T
506
507 /* The size of `short', as computed by sizeof. */
508 #undef SIZEOF_SHORT
509
510 /* The size of `size_t', as computed by sizeof. */
511 #undef SIZEOF_SIZE_T
512
513 /* The size of `void *', as computed by sizeof. */
514 #undef SIZEOF_VOID_P
515
516 /* The size of `__int64', as computed by sizeof. */
517 #undef SIZEOF___INT64
518
519 /* Define as the maximum value of type 'size_t', if the system doesn't define
520 it. */
521 #ifndef SIZE_MAX
522 # undef SIZE_MAX
523 #endif
524
525 /* If using the C implementation of alloca, define if you know the
526 direction of stack growth for your system; otherwise it will be
527 automatically deduced at runtime.
528 STACK_DIRECTION > 0 => grows toward higher addresses
529 STACK_DIRECTION < 0 => grows toward lower addresses
530 STACK_DIRECTION = 0 => direction of growth unknown */
531 #undef STACK_DIRECTION
532
533 /* Define to 1 if you have the ANSI C header files. */
534 #undef STDC_HEADERS
535
536 /* Define if the POSIX multithreading library can be used. */
537 #undef USE_POSIX_THREADS
538
539 /* Define if references to the POSIX multithreading library should be made
540 weak. */
541 #undef USE_POSIX_THREADS_WEAK
542
543 /* Define if the GNU Pth multithreading library can be used. */
544 #undef USE_PTH_THREADS
545
546 /* Define if references to the GNU Pth multithreading library should be made
547 weak. */
548 #undef USE_PTH_THREADS_WEAK
549
550 /* Define if the old Solaris multithreading library can be used. */
551 #undef USE_SOLARIS_THREADS
552
553 /* Define if references to the old Solaris multithreading library should be
554 made weak. */
555 #undef USE_SOLARIS_THREADS_WEAK
556
557 /* Enable extensions on AIX 3, Interix. */
558 #ifndef _ALL_SOURCE
559 # undef _ALL_SOURCE
560 #endif
561 /* Enable GNU extensions on systems that have them. */
562 #ifndef _GNU_SOURCE
563 # undef _GNU_SOURCE
564 #endif
565 /* Enable threading extensions on Solaris. */
566 #ifndef _POSIX_PTHREAD_SEMANTICS
567 # undef _POSIX_PTHREAD_SEMANTICS
568 #endif
569 /* Enable extensions on HP NonStop. */
570 #ifndef _TANDEM_SOURCE
571 # undef _TANDEM_SOURCE
572 #endif
573 /* Enable general extensions on Solaris. */
574 #ifndef __EXTENSIONS__
575 # undef __EXTENSIONS__
576 #endif
577
578
579 /* Define if the Win32 multithreading API can be used. */
580 #undef USE_WIN32_THREADS
581
582 /* Version number of package */
583 #undef VERSION
584
585 /* Define if we are compiling with debugger. */
586 #undef WANT_DEBUGGER
587
588 /* Define if we are compiling with GBA emulation. */
589 #undef WANT_GBA_EMU
590
591 /* Define if we are compiling with GB emulation. */
592 #undef WANT_GB_EMU
593
594 /* Define if we are compiling with internal CJK fonts. */
595 #undef WANT_INTERNAL_CJK
596
597 /* Define if we are compiling with Lynx emulation. */
598 #undef WANT_LYNX_EMU
599
600 /* Define if we are compiling with Sega Genesis/MegaDrive emulation. */
601 #undef WANT_MD_EMU
602
603 /* Define if we are compiling with NES emulation. */
604 #undef WANT_NES_EMU
605
606 /* Define if we are compiling with NGP emulation. */
607 #undef WANT_NGP_EMU
608
609 /* Define if we are compiling with PCE emulation. */
610 #undef WANT_PCE_EMU
611
612 /* Define if we are compiling with separate fast PCE emulation. */
613 #undef WANT_PCE_FAST_EMU
614
615 /* Define if we are compiling with PC-FX emulation. */
616 #undef WANT_PCFX_EMU
617
618 /* Define if we are compiling with PlayStation emulation. */
619 #undef WANT_PSX_EMU
620
621 /* Define if we are compiling with SMS+GG emulation. */
622 #undef WANT_SMS_EMU
623
624 /* Define if we are compiling with SNES emulation. */
625 #undef WANT_SNES_EMU
626
627 /* Define if we are compiling with Virtual Boy emulation. */
628 #undef WANT_VB_EMU
629
630 /* Define if we are compiling with WonderSwan emulation. */
631 #undef WANT_WSWAN_EMU
632
633 /* Define if we are compiling for Win32. */
634 #undef WIN32
635
636 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
637 significant byte first (like Motorola and SPARC, unlike Intel). */
638 #if defined AC_APPLE_UNIVERSAL_BUILD
639 # if defined __BIG_ENDIAN__
640 # define WORDS_BIGENDIAN 1
641 # endif
642 #else
643 # ifndef WORDS_BIGENDIAN
644 # undef WORDS_BIGENDIAN
645 # endif
646 #endif
647
648 /* Number of bits in a file offset, on hosts where this is settable. */
649 #undef _FILE_OFFSET_BITS
650
651 /* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
652 #undef _LARGEFILE_SOURCE
653
654 /* Define for large files, on AIX-style hosts. */
655 #undef _LARGE_FILES
656
657 /* Define to 1 if on MINIX. */
658 #undef _MINIX
659
660 /* Define to 2 if the system does not provide POSIX.1 features except with
661 this defined. */
662 #undef _POSIX_1_SOURCE
663
664 /* Define to 1 if you need to in order for `stat' and other things to work. */
665 #undef _POSIX_SOURCE
666
667 /* Define to empty if `const' does not conform to ANSI C. */
668 #undef const
669
670 /* Define to `__inline__' or `__inline' if that's what the C compiler
671 calls it, or to nothing if 'inline' is not supported under any name. */
672 #ifndef __cplusplus
673 #undef inline
674 #endif
675
676 /* Define as the type of the result of subtracting two pointers, if the system
677 doesn't define it. */
678 #undef ptrdiff_t
679
680 /* Define to `unsigned int' if <sys/types.h> does not define. */
681 #undef size_t
682
683 /* Define to unsigned long or unsigned long long if <stdint.h> and
684 <inttypes.h> don't define. */
685 #undef uintmax_t
686
687
688 #define __libc_lock_t gl_lock_t
689 #define __libc_lock_define gl_lock_define
690 #define __libc_lock_define_initialized gl_lock_define_initialized
691 #define __libc_lock_init gl_lock_init
692 #define __libc_lock_lock gl_lock_lock
693 #define __libc_lock_unlock gl_lock_unlock
694 #define __libc_lock_recursive_t gl_recursive_lock_t
695 #define __libc_lock_define_recursive gl_recursive_lock_define
696 #define __libc_lock_define_initialized_recursive gl_recursive_lock_define_initialized
697 #define __libc_lock_init_recursive gl_recursive_lock_init
698 #define __libc_lock_lock_recursive gl_recursive_lock_lock
699 #define __libc_lock_unlock_recursive gl_recursive_lock_unlock
700 #define glthread_in_use libintl_thread_in_use
701 #define glthread_lock_init_func libintl_lock_init_func
702 #define glthread_lock_lock_func libintl_lock_lock_func
703 #define glthread_lock_unlock_func libintl_lock_unlock_func
704 #define glthread_lock_destroy_func libintl_lock_destroy_func
705 #define glthread_rwlock_init_multithreaded libintl_rwlock_init_multithreaded
706 #define glthread_rwlock_init_func libintl_rwlock_init_func
707 #define glthread_rwlock_rdlock_multithreaded libintl_rwlock_rdlock_multithreaded
708 #define glthread_rwlock_rdlock_func libintl_rwlock_rdlock_func
709 #define glthread_rwlock_wrlock_multithreaded libintl_rwlock_wrlock_multithreaded
710 #define glthread_rwlock_wrlock_func libintl_rwlock_wrlock_func
711 #define glthread_rwlock_unlock_multithreaded libintl_rwlock_unlock_multithreaded
712 #define glthread_rwlock_unlock_func libintl_rwlock_unlock_func
713 #define glthread_rwlock_destroy_multithreaded libintl_rwlock_destroy_multithreaded
714 #define glthread_rwlock_destroy_func libintl_rwlock_destroy_func
715 #define glthread_recursive_lock_init_multithreaded libintl_recursive_lock_init_multithreaded
716 #define glthread_recursive_lock_init_func libintl_recursive_lock_init_func
717 #define glthread_recursive_lock_lock_multithreaded libintl_recursive_lock_lock_multithreaded
718 #define glthread_recursive_lock_lock_func libintl_recursive_lock_lock_func
719 #define glthread_recursive_lock_unlock_multithreaded libintl_recursive_lock_unlock_multithreaded
720 #define glthread_recursive_lock_unlock_func libintl_recursive_lock_unlock_func
721 #define glthread_recursive_lock_destroy_multithreaded libintl_recursive_lock_destroy_multithreaded
722 #define glthread_recursive_lock_destroy_func libintl_recursive_lock_destroy_func
723 #define glthread_once_func libintl_once_func
724 #define glthread_once_singlethreaded libintl_once_singlethreaded
725 #define glthread_once_multithreaded libintl_once_multithreaded
726
0 ../src/desa68/
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (retro_inline.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef __LIBRETRO_SDK_INLINE_H
23 #define __LIBRETRO_SDK_INLINE_H
24
25 #ifndef INLINE
26
27 #if !defined(__cplusplus) && defined(_WIN32)
28 #define INLINE _inline
29 #elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
30 #define INLINE inline
31 #elif defined(__GNUC__)
32 #define INLINE __inline__
33 #else
34 #define INLINE
35 #endif
36
37 #endif
38 #endif
0 /* Copyright (C) 2010-2015 The RetroArch team
1 *
2 * ---------------------------------------------------------------------------------------
3 * The following license statement only applies to this file (rthreads.h).
4 * ---------------------------------------------------------------------------------------
5 *
6 * Permission is hereby granted, free of charge,
7 * to any person obtaining a copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation the rights to
9 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
10 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
15 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 #ifndef __LIBRETRO_SDK_RTHREADS_H__
23 #define __LIBRETRO_SDK_RTHREADS_H__
24
25 #include <boolean.h>
26 #include <stdint.h>
27 #include <retro_inline.h>
28
29 #if defined(__cplusplus) && !defined(_MSC_VER)
30 extern "C" {
31 #endif
32
33 typedef struct sthread sthread_t;
34 typedef struct slock slock_t;
35 typedef struct scond scond_t;
36
37 /**
38 * sthread_create:
39 * @start_routine : thread entry callback function
40 * @userdata : pointer to userdata that will be made
41 * available in thread entry callback function
42 *
43 * Create a new thread.
44 *
45 * Returns: pointer to new thread if successful, otherwise NULL.
46 */
47 sthread_t *sthread_create(void (*thread_func)(void*), void *userdata);
48
49 /**
50 * sthread_detach:
51 * @thread : pointer to thread object
52 *
53 * Detach a thread. When a detached thread terminates, its
54 * resource sare automatically released back to the system
55 * without the need for another thread to join with the
56 * terminated thread.
57 *
58 * Returns: 0 on success, otherwise it returns a non-zero error number.
59 */
60 int sthread_detach(sthread_t *thread);
61
62 /**
63 * sthread_join:
64 * @thread : pointer to thread object
65 *
66 * Join with a terminated thread. Waits for the thread specified by
67 * @thread to terminate. If that thread has already terminated, then
68 * it will return immediately. The thread specified by @thread must
69 * be joinable.
70 *
71 * Returns: 0 on success, otherwise it returns a non-zero error number.
72 */
73 void sthread_join(sthread_t *thread);
74
75 /**
76 * slock_new:
77 *
78 * Create and initialize a new mutex. Must be manually
79 * freed.
80 *
81 * Returns: pointer to a new mutex if successful, otherwise NULL.
82 **/
83 slock_t *slock_new(void);
84
85 /**
86 * slock_free:
87 * @lock : pointer to mutex object
88 *
89 * Frees a mutex.
90 **/
91 void slock_free(slock_t *lock);
92
93 /**
94 * slock_lock:
95 * @lock : pointer to mutex object
96 *
97 * Locks a mutex. If a mutex is already locked by
98 * another thread, the calling thread shall block until
99 * the mutex becomes available.
100 **/
101 void slock_lock(slock_t *lock);
102
103 /**
104 * slock_unlock:
105 * @lock : pointer to mutex object
106 *
107 * Unlocks a mutex.
108 **/
109 void slock_unlock(slock_t *lock);
110
111 /**
112 * scond_new:
113 *
114 * Creates and initializes a condition variable. Must
115 * be manually freed.
116 *
117 * Returns: pointer to new condition variable on success,
118 * otherwise NULL.
119 **/
120 scond_t *scond_new(void);
121
122 /**
123 * scond_free:
124 * @cond : pointer to condition variable object
125 *
126 * Frees a condition variable.
127 **/
128 void scond_free(scond_t *cond);
129
130 /**
131 * scond_wait:
132 * @cond : pointer to condition variable object
133 * @lock : pointer to mutex object
134 *
135 * Block on a condition variable (i.e. wait on a condition).
136 **/
137 void scond_wait(scond_t *cond, slock_t *lock);
138
139 /**
140 * scond_wait_timeout:
141 * @cond : pointer to condition variable object
142 * @lock : pointer to mutex object
143 * @timeout_us : timeout (in microseconds)
144 *
145 * Try to block on a condition variable (i.e. wait on a condition) until
146 * @timeout_us elapses.
147 *
148 * Returns: false (0) if timeout elapses before condition variable is
149 * signaled or broadcast, otherwise true (1).
150 **/
151 bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us);
152
153 /**
154 * scond_broadcast:
155 * @cond : pointer to condition variable object
156 *
157 * Broadcast a condition. Unblocks all threads currently blocked
158 * on the specified condition variable @cond.
159 **/
160 int scond_broadcast(scond_t *cond);
161
162 /**
163 * scond_signal:
164 * @cond : pointer to condition variable object
165 *
166 * Signal a condition. Unblocks at least one of the threads currently blocked
167 * on the specified condition variable @cond.
168 **/
169 void scond_signal(scond_t *cond);
170
171 #ifndef RARCH_INTERNAL
172 #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
173 #include <sys/timer.h>
174 #elif defined(XENON)
175 #include <time/time.h>
176 #elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
177 #include <unistd.h>
178 #elif defined(PSP)
179 #include <pspthreadman.h>
180 #include <psputils.h>
181 #elif defined(_3DS)
182 #include <3ds.h>
183 #elif defined(_WIN32) && !defined(_XBOX)
184 #include <windows.h>
185 #elif defined(_XBOX)
186 #include <xtl.h>
187 #else
188 #include <time.h>
189 #endif
190
191 /**
192 * retro_sleep:
193 * @msec : amount in milliseconds to sleep
194 *
195 * Sleeps for a specified amount of milliseconds (@msec).
196 **/
197 static INLINE void retro_sleep(unsigned msec)
198 {
199 #if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
200 sys_timer_usleep(1000 * msec);
201 #elif defined(PSP)
202 sceKernelDelayThread(1000 * msec);
203 #elif defined(_3DS)
204 svcSleepThread(1000000 * (s64)msec);
205 #elif defined(_WIN32)
206 Sleep(msec);
207 #elif defined(XENON)
208 udelay(1000 * msec);
209 #elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
210 usleep(1000 * msec);
211 #else
212 struct timespec tv = {0};
213 tv.tv_sec = msec / 1000;
214 tv.tv_nsec = (msec % 1000) * 1000000;
215 nanosleep(&tv, NULL);
216 #endif
217 }
218 #endif
219
220 #if defined(__cplusplus) && !defined(_MSC_VER)
221 }
222 #endif
223
224 #endif
0 ../../src/trio/CHANGES
0 /*************************************************************************
1 *
2 * $Id: trio.h,v 1.19 2009/09/13 10:12:22 breese Exp $
3 *
4 * Copyright (C) 1998 Bjorn Reese and Daniel Stenberg.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
14 *
15 *************************************************************************
16 *
17 * http://ctrio.sourceforge.net/
18 *
19 ************************************************************************/
20
21 #ifndef TRIO_TRIO_H
22 #define TRIO_TRIO_H
23
24 #if !defined(WITHOUT_TRIO)
25
26 /*
27 * Use autoconf defines if present. Packages using trio must define
28 * HAVE_CONFIG_H as a compiler option themselves.
29 */
30 #if defined(HAVE_CONFIG_H)
31 # include <config.h>
32 #endif
33
34 #include "triop.h"
35
36 #include <stdio.h>
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41
42 /*
43 * Error codes.
44 *
45 * Remember to add a textual description to trio_strerror.
46 */
47 enum {
48 TRIO_EOF = 1,
49 TRIO_EINVAL = 2,
50 TRIO_ETOOMANY = 3,
51 TRIO_EDBLREF = 4,
52 TRIO_EGAP = 5,
53 TRIO_ENOMEM = 6,
54 TRIO_ERANGE = 7,
55 TRIO_ERRNO = 8,
56 TRIO_ECUSTOM = 9
57 };
58
59 /* Error macros */
60 #define TRIO_ERROR_CODE(x) ((-(x)) & 0x00FF)
61 #define TRIO_ERROR_POSITION(x) ((-(x)) >> 8)
62 #define TRIO_ERROR_NAME(x) trio_strerror(x)
63
64 typedef int (*trio_outstream_t) TRIO_PROTO((trio_pointer_t, int));
65 typedef int (*trio_instream_t) TRIO_PROTO((trio_pointer_t));
66
67 TRIO_CONST char *trio_strerror TRIO_PROTO((int));
68
69 /*************************************************************************
70 * Print Functions
71 */
72
73 int trio_printf TRIO_PROTO((TRIO_CONST char *format, ...));
74 int trio_vprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
75 int trio_printfv TRIO_PROTO((TRIO_CONST char *format, void **args));
76
77 int trio_fprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
78 int trio_vfprintf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
79 int trio_fprintfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));
80
81 int trio_dprintf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
82 int trio_vdprintf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
83 int trio_dprintfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));
84
85 int trio_cprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
86 TRIO_CONST char *format, ...));
87 int trio_vcprintf TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
88 TRIO_CONST char *format, va_list args));
89 int trio_cprintfv TRIO_PROTO((trio_outstream_t stream, trio_pointer_t closure,
90 TRIO_CONST char *format, void **args));
91
92 int trio_sprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, ...));
93 int trio_vsprintf TRIO_PROTO((char *buffer, TRIO_CONST char *format, va_list args));
94 int trio_sprintfv TRIO_PROTO((char *buffer, TRIO_CONST char *format, void **args));
95
96 int trio_snprintf TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
97 int trio_vsnprintf TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
98 va_list args));
99 int trio_snprintfv TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
100 void **args));
101
102 int trio_snprintfcat TRIO_PROTO((char *buffer, size_t max, TRIO_CONST char *format, ...));
103 int trio_vsnprintfcat TRIO_PROTO((char *buffer, size_t bufferSize, TRIO_CONST char *format,
104 va_list args));
105
106 #if defined(TRIO_DEPRECATED)
107 char *trio_aprintf TRIO_PROTO((TRIO_CONST char *format, ...));
108 char *trio_vaprintf TRIO_PROTO((TRIO_CONST char *format, va_list args));
109 #endif
110
111 int trio_asprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, ...));
112 int trio_vasprintf TRIO_PROTO((char **ret, TRIO_CONST char *format, va_list args));
113 int trio_asprintfv TRIO_PROTO((char **result, TRIO_CONST char *format, trio_pointer_t * args));
114
115 /*************************************************************************
116 * Scan Functions
117 */
118 int trio_scanf TRIO_PROTO((TRIO_CONST char *format, ...));
119 int trio_vscanf TRIO_PROTO((TRIO_CONST char *format, va_list args));
120 int trio_scanfv TRIO_PROTO((TRIO_CONST char *format, void **args));
121
122 int trio_fscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, ...));
123 int trio_vfscanf TRIO_PROTO((FILE *file, TRIO_CONST char *format, va_list args));
124 int trio_fscanfv TRIO_PROTO((FILE *file, TRIO_CONST char *format, void **args));
125
126 int trio_dscanf TRIO_PROTO((int fd, TRIO_CONST char *format, ...));
127 int trio_vdscanf TRIO_PROTO((int fd, TRIO_CONST char *format, va_list args));
128 int trio_dscanfv TRIO_PROTO((int fd, TRIO_CONST char *format, void **args));
129
130 int trio_cscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
131 TRIO_CONST char *format, ...));
132 int trio_vcscanf TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
133 TRIO_CONST char *format, va_list args));
134 int trio_cscanfv TRIO_PROTO((trio_instream_t stream, trio_pointer_t closure,
135 TRIO_CONST char *format, void **args));
136
137 int trio_sscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, ...));
138 int trio_vsscanf TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, va_list args));
139 int trio_sscanfv TRIO_PROTO((TRIO_CONST char *buffer, TRIO_CONST char *format, void **args));
140
141 /*************************************************************************
142 * Locale Functions
143 */
144 void trio_locale_set_decimal_point TRIO_PROTO((char *decimalPoint));
145 void trio_locale_set_thousand_separator TRIO_PROTO((char *thousandSeparator));
146 void trio_locale_set_grouping TRIO_PROTO((char *grouping));
147
148 /*************************************************************************
149 * Renaming
150 */
151 #ifdef TRIO_REPLACE_STDIO
152 /* Replace the <stdio.h> functions */
153 #ifndef HAVE_PRINTF
154 # undef printf
155 # define printf trio_printf
156 #endif
157 #ifndef HAVE_VPRINTF
158 # undef vprintf
159 # define vprintf trio_vprintf
160 #endif
161 #ifndef HAVE_FPRINTF
162 # undef fprintf
163 # define fprintf trio_fprintf
164 #endif
165 #ifndef HAVE_VFPRINTF
166 # undef vfprintf
167 # define vfprintf trio_vfprintf
168 #endif
169 #ifndef HAVE_SPRINTF
170 # undef sprintf
171 # define sprintf trio_sprintf
172 #endif
173 #ifndef HAVE_VSPRINTF
174 # undef vsprintf
175 # define vsprintf trio_vsprintf
176 #endif
177 #ifndef HAVE_SNPRINTF
178 # undef snprintf
179 # define snprintf trio_snprintf
180 #endif
181 #ifndef HAVE_VSNPRINTF
182 # undef vsnprintf
183 # define vsnprintf trio_vsnprintf
184 #endif
185 #ifndef HAVE_SCANF
186 # undef scanf
187 # define scanf trio_scanf
188 #endif
189 #ifndef HAVE_VSCANF
190 # undef vscanf
191 # define vscanf trio_vscanf
192 #endif
193 #ifndef HAVE_FSCANF
194 # undef fscanf
195 # define fscanf trio_fscanf
196 #endif
197 #ifndef HAVE_VFSCANF
198 # undef vfscanf
199 # define vfscanf trio_vfscanf
200 #endif
201 #ifndef HAVE_SSCANF
202 # undef sscanf
203 # define sscanf trio_sscanf
204 #endif
205 #ifndef HAVE_VSSCANF
206 # undef vsscanf
207 # define vsscanf trio_vsscanf
208 #endif
209 /* These aren't stdio functions, but we make them look similar */
210 #undef dprintf
211 #define dprintf trio_dprintf
212 #undef vdprintf
213 #define vdprintf trio_vdprintf
214 #undef aprintf
215 #define aprintf trio_aprintf
216 #undef vaprintf
217 #define vaprintf trio_vaprintf
218 #undef asprintf
219 #define asprintf trio_asprintf
220 #undef vasprintf
221 #define vasprintf trio_vasprintf
222 #undef dscanf
223 #define dscanf trio_dscanf
224 #undef vdscanf
225 #define vdscanf trio_vdscanf
226 #endif
227
228 #ifdef __cplusplus
229 } /* extern "C" */
230 #endif
231
232 #endif /* WITHOUT_TRIO */
233
234 #endif /* TRIO_TRIO_H */
0 /*************************************************************************
1 *
2 * $Id: triodef.h,v 1.35 2009/09/20 11:37:14 breese Exp $
3 *
4 * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
14 *
15 ************************************************************************/
16
17 #ifndef TRIO_TRIODEF_H
18 #define TRIO_TRIODEF_H
19
20 /*************************************************************************
21 * Compiler support detection
22 */
23
24 #if defined(__GNUC__)
25 # define TRIO_COMPILER_GCC
26 #endif
27
28 #if defined(__SUNPRO_CC)
29 # define TRIO_COMPILER_SUNPRO __SUNPRO_CC
30 #else
31 # if defined(__SUNPRO_C)
32 # define TRIO_COMPILER_SUNPRO __SUNPRO_C
33 # endif
34 #endif
35
36 #if defined(__xlC__) || defined(__IBMC__) || defined(__IBMCPP__)
37 # define TRIO_COMPILER_XLC
38 #else
39 # if defined(_AIX) && !defined(__GNUC__)
40 # define TRIO_COMPILER_XLC /* Workaround for old xlc */
41 # endif
42 #endif
43
44 #if defined(__DECC) || defined(__DECCXX)
45 # define TRIO_COMPILER_DECC
46 #else
47 # if defined(__osf__) && defined(__LANGUAGE_C__) && !defined(__GNUC__)
48 # define TRIO_COMPILER_DECC /* Workaround for old DEC C compilers */
49 # endif
50 #endif
51
52 #if defined(__HP_aCC) || defined(__HP_cc)
53 # define TRIO_COMPILER_HP
54 #endif
55
56 #if defined(sgi) || defined(__sgi)
57 # define TRIO_COMPILER_MIPSPRO
58 #endif
59
60 #if defined(_MSC_VER)
61 # define TRIO_COMPILER_MSVC
62 #endif
63
64 #if defined(__BORLANDC__)
65 # define TRIO_COMPILER_BCB
66 #endif
67
68 /*************************************************************************
69 * Platform support detection
70 */
71
72 #if defined(VMS) || defined(__VMS)
73 # define TRIO_PLATFORM_VMS
74 #endif
75
76 #if defined(unix) || defined(__unix) || defined(__unix__)
77 # define TRIO_PLATFORM_UNIX
78 #endif
79
80 #if defined(TRIO_COMPILER_XLC) || defined(_AIX)
81 # define TRIO_PLATFORM_UNIX
82 #endif
83
84 #if defined(TRIO_COMPILER_DECC) || defined(__osf___)
85 # if !defined(TRIO_PLATFORM_VMS)
86 # define TRIO_PLATFORM_UNIX
87 # endif
88 #endif
89
90 #if defined(__NetBSD__)
91 # define TRIO_PLATFORM_UNIX
92 #endif
93
94 #if defined(__Lynx__)
95 # define TRIO_PLATFORM_UNIX
96 # define TRIO_PLATFORM_LYNX
97 #endif
98
99 #if defined(__APPLE__) && defined(__MACH__)
100 # define TRIO_PLATFORM_UNIX
101 #endif
102
103 #if defined(__QNX__)
104 # define TRIO_PLATFORM_UNIX
105 # define TRIO_PLATFORM_QNX
106 #endif
107
108 #if defined(__CYGWIN__)
109 # define TRIO_PLATFORM_UNIX
110 #endif
111
112 #if defined(AMIGA) && defined(TRIO_COMPILER_GCC)
113 # define TRIO_PLATFORM_UNIX
114 #endif
115
116 #if defined(TRIO_COMPILER_MSVC) || defined(WIN32) || defined(_WIN32)
117 # define TRIO_PLATFORM_WIN32
118 #endif
119
120 #if defined(_WIN32_WCE)
121 # define TRIO_PLATFORM_WINCE
122 #endif
123
124 #if defined(mpeix) || defined(__mpexl)
125 # define TRIO_PLATFORM_MPEIX
126 #endif
127
128 #if defined(_AIX)
129 # define TRIO_PLATFORM_AIX
130 #endif
131
132 #if defined(__hpux)
133 # define TRIO_PLATFORM_HPUX
134 #endif
135
136 #if defined(sun) || defined(__sun__)
137 # if defined(__SVR4) || defined(__svr4__)
138 # define TRIO_PLATFORM_SOLARIS
139 # else
140 # define TRIO_PLATFORM_SUNOS
141 # endif
142 #endif
143
144 /*************************************************************************
145 * Standards support detection
146 */
147
148 #if defined(__STDC__) \
149 || defined(_MSC_EXTENSIONS) \
150 || defined(TRIO_COMPILER_BCB)
151 # define PREDEF_STANDARD_C89
152 #endif
153 #if defined(__STDC_VERSION__)
154 # define PREDEF_STANDARD_C90
155 #endif
156 #if (__STDC_VERSION__ - 0 >= 199409L)
157 # define PREDEF_STANDARD_C94
158 #endif
159 #if (__STDC_VERSION__ - 0 >= 199901L)
160 # define PREDEF_STANDARD_C99
161 #endif
162 #if defined(TRIO_COMPILER_SUNPRO) && (TRIO_COMPILER_SUNPRO >= 0x420)
163 # if !defined(PREDEF_STANDARD_C94)
164 # define PREDEF_STANDARD_C94
165 # endif
166 #endif
167
168 #if defined(__cplusplus)
169 # define PREDEF_STANDARD_CXX
170 #endif
171 #if __cplusplus - 0 >= 199711L
172 # define PREDEF_STANDARD_CXX89
173 #endif
174
175 #if defined(_POSIX_VERSION)
176 # define PREDEF_STANDARD_POSIX _POSIX_VERSION
177 # if (_POSIX_VERSION >= 199506L)
178 # define PREDEF_STANDARD_POSIX_1996
179 # endif
180 #endif
181
182 #if (_XOPEN_VERSION - 0 >= 3) || defined(_XOPEN_XPG3)
183 # define PREDEF_STANDARD_XPG3
184 #endif
185 #if (_XOPEN_VERSION - 0 >= 4) || defined(_XOPEN_XPG4)
186 # define PREDEF_STANDARD_XPG4
187 #endif
188 #if (_XOPEN_VERSION - 0 > 4) \
189 || (defined(_XOPEN_UNIX) && (_XOPEN_VERSION - 0 == 4))
190 # define PREDEF_STANDARD_UNIX95
191 #endif
192 #if (_XOPEN_VERSION - 0 >= 500)
193 # define PREDEF_STANDARD_UNIX98
194 #endif
195 #if (_XOPEN_VERSION - 0 >= 600)
196 # define PREDEF_STANDARD_UNIX03
197 #endif
198
199 /*************************************************************************
200 * Generic defines
201 */
202
203 #if !defined(TRIO_PUBLIC)
204 # define TRIO_PUBLIC
205 #endif
206 #if !defined(TRIO_PRIVATE)
207 # define TRIO_PRIVATE static
208 #endif
209
210 #if !(defined(PREDEF_STANDARD_C89) || defined(PREDEF_STANDARD_CXX))
211 # define TRIO_COMPILER_ANCIENT
212 #endif
213
214 #if defined(TRIO_COMPILER_ANCIENT)
215 # define TRIO_CONST
216 # define TRIO_VOLATILE
217 # define TRIO_SIGNED
218 typedef double trio_long_double_t;
219 typedef char * trio_pointer_t;
220 # define TRIO_SUFFIX_LONG(x) x
221 # define TRIO_PROTO(x) ()
222 # define TRIO_NOARGS
223 # define TRIO_ARGS1(list,a1) list a1;
224 # define TRIO_ARGS2(list,a1,a2) list a1; a2;
225 # define TRIO_ARGS3(list,a1,a2,a3) list a1; a2; a3;
226 # define TRIO_ARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4;
227 # define TRIO_ARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5;
228 # define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) list a1; a2; a3; a4; a5; a6;
229 # define TRIO_ARGS7(list,a1,a2,a3,a4,a5,a6,a7) list a1; a2; a3; a4; a5; a6; a7;
230 # define TRIO_VARGS2(list,a1,a2) list a1; a2
231 # define TRIO_VARGS3(list,a1,a2,a3) list a1; a2; a3
232 # define TRIO_VARGS4(list,a1,a2,a3,a4) list a1; a2; a3; a4
233 # define TRIO_VARGS5(list,a1,a2,a3,a4,a5) list a1; a2; a3; a4; a5
234 # define TRIO_VA_DECL va_dcl
235 # define TRIO_VA_START(x,y) va_start(x)
236 # define TRIO_VA_END(x) va_end(x)
237 #else /* ANSI C */
238 # define TRIO_CONST const
239 # define TRIO_VOLATILE volatile
240 # define TRIO_SIGNED signed
241 typedef long double trio_long_double_t;
242 typedef void * trio_pointer_t;
243 # define TRIO_SUFFIX_LONG(x) x ## L
244 # define TRIO_PROTO(x) x
245 # define TRIO_NOARGS void
246 # define TRIO_ARGS1(list,a1) (a1)
247 # define TRIO_ARGS2(list,a1,a2) (a1,a2)
248 # define TRIO_ARGS3(list,a1,a2,a3) (a1,a2,a3)
249 # define TRIO_ARGS4(list,a1,a2,a3,a4) (a1,a2,a3,a4)
250 # define TRIO_ARGS5(list,a1,a2,a3,a4,a5) (a1,a2,a3,a4,a5)
251 # define TRIO_ARGS6(list,a1,a2,a3,a4,a5,a6) (a1,a2,a3,a4,a5,a6)
252 # define TRIO_ARGS7(list,a1,a2,a3,a4,a5,a6,a7) (a1,a2,a3,a4,a5,a6,a7)
253 # define TRIO_VARGS2 TRIO_ARGS2
254 # define TRIO_VARGS3 TRIO_ARGS3
255 # define TRIO_VARGS4 TRIO_ARGS4
256 # define TRIO_VARGS5 TRIO_ARGS5
257 # define TRIO_VA_DECL ...
258 # define TRIO_VA_START(x,y) va_start(x,y)
259 # define TRIO_VA_END(x) va_end(x)
260 #endif
261
262 #if defined(PREDEF_STANDARD_C99) || defined(PREDEF_STANDARD_CXX)
263 # define TRIO_INLINE inline
264 #else
265 # if defined(TRIO_COMPILER_GCC)
266 # define TRIO_INLINE __inline__
267 # endif
268 # if defined(TRIO_COMPILER_MSVC)
269 # define TRIO_INLINE _inline
270 # endif
271 # if defined(TRIO_COMPILER_BCB)
272 # define TRIO_INLINE __inline
273 # endif
274 #endif
275 #if !defined(TRIO_INLINE)
276 # define TRIO_INLINE
277 #endif
278
279 /*************************************************************************
280 * Workarounds
281 */
282
283 #if defined(TRIO_PLATFORM_VMS)
284 /*
285 * Computations done with constants at compile time can trigger these
286 * even when compiling with IEEE enabled.
287 */
288 # pragma message disable (UNDERFLOW, FLOATOVERFL)
289
290 # if (__CRTL_VER < 80210001)
291 /*
292 * Although the compiler supports C99 language constructs, the C
293 * run-time library does not contain all C99 functions.
294 */
295 # if defined(PREDEF_STANDARD_C99)
296 # undef PREDEF_STANDARD_C99
297 # endif
298 # endif
299 #endif
300
301 /*
302 * Not all preprocessors supports the LL token.
303 */
304 #if defined(TRIO_COMPILER_MSVC) || defined(TRIO_COMPILER_BCB)
305 #else
306 # define TRIO_COMPILER_SUPPORTS_LL
307 #endif
308
309 #if defined(__CYGWIN__)
310 /*
311 * Cygwin defines the macros for hosted C99, but does not support certain
312 * long double math functions.
313 */
314 # include <cygwin/version.h>
315 # define TRIO_CYGWIN_VERSION_API CYGWIN_VERSION_API_MAJOR * 1000 + \
316 CYGWIN_VERSION_API_MINOR
317 /*
318 * Please change the version number below when the Cygwin API supports
319 * long double math functions (powl, fmodl, etc.)
320 */
321 # if TRIO_CYGWIN_VERSION_API < 99999999
322 # define TRIO_NO_FLOORL 1
323 # define TRIO_NO_CEILL 1
324 # define TRIO_NO_POWL 1
325 # define TRIO_NO_FMODL 1
326 # define TRIO_NO_LOG10L 1
327 # endif
328 #endif
329
330 #endif /* TRIO_TRIODEF_H */
0 /*************************************************************************
1 *
2 * $Id: trionan.h,v 1.9 2005/03/27 18:52:45 breese Exp $
3 *
4 * Copyright (C) 2001 Bjorn Reese <breese@users.sourceforge.net>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
14 *
15 ************************************************************************/
16
17 #ifndef TRIO_TRIONAN_H
18 #define TRIO_TRIONAN_H
19
20 #include "triodef.h"
21
22 #ifdef __cplusplus
23 extern "C" {
24 #endif
25
26 #if !defined(TRIO_PUBLIC_NAN)
27 # if !defined(TRIO_PUBLIC)
28 # define TRIO_PUBLIC
29 # endif
30 # define TRIO_PUBLIC_NAN TRIO_PUBLIC
31 #endif
32
33 enum {
34 TRIO_FP_INFINITE,
35 TRIO_FP_NAN,
36 TRIO_FP_NORMAL,
37 TRIO_FP_SUBNORMAL,
38 TRIO_FP_ZERO
39 };
40
41 /*************************************************************************
42 * Dependencies
43 */
44
45 #if defined(TRIO_EMBED_NAN)
46
47 /*
48 * The application that trionan is embedded in must define which functions
49 * it uses.
50 *
51 * The following resolves internal dependencies.
52 */
53
54 # if defined(TRIO_FUNC_ISNAN) \
55 || defined(TRIO_FUNC_ISINF)
56 # if !defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT)
57 # define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT
58 # endif
59 # endif
60
61 # if defined(TRIO_FUNC_NAN)
62 # if !defined(TRIO_FUNC_PINF)
63 # define TRIO_FUNC_PINF
64 # endif
65 # endif
66
67 # if defined(TRIO_FUNC_NINF)
68 # if !defined(TRIO_FUNC_PINF)
69 # define TRIO_FUNC_PINF
70 # endif
71 # endif
72
73 #else
74
75 /*
76 * When trionan is not embedded all all functions are defined.
77 */
78
79 # define TRIO_FUNC_NAN
80 # define TRIO_FUNC_PINF
81 # define TRIO_FUNC_NINF
82 # define TRIO_FUNC_NZERO
83 # define TRIO_FUNC_ISNAN
84 # define TRIO_FUNC_ISINF
85 # define TRIO_FUNC_ISFINITE
86 # define TRIO_FUNC_SIGNBIT
87 # define TRIO_FUNC_FPCLASSIFY
88 # define TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT
89
90 #endif
91
92 /*************************************************************************
93 * Functions
94 */
95
96 /*
97 * Return NaN (Not-a-Number).
98 */
99 #if defined(TRIO_FUNC_NAN)
100 TRIO_PUBLIC_NAN double
101 trio_nan
102 TRIO_PROTO((void));
103 #endif
104
105 /*
106 * Return positive infinity.
107 */
108 #if defined(TRIO_FUNC_PINF)
109 TRIO_PUBLIC_NAN double
110 trio_pinf
111 TRIO_PROTO((void));
112 #endif
113
114 /*
115 * Return negative infinity.
116 */
117 #if defined(TRIO_FUNC_NINF)
118 TRIO_PUBLIC_NAN double
119 trio_ninf
120 TRIO_PROTO((void));
121 #endif
122
123 /*
124 * Return negative zero.
125 */
126 #if defined(TRIO_FUNC_NZERO)
127 TRIO_PUBLIC_NAN double
128 trio_nzero
129 TRIO_PROTO((TRIO_NOARGS));
130 #endif
131
132 /*
133 * If number is a NaN return non-zero, otherwise return zero.
134 */
135 #if defined(TRIO_FUNC_ISNAN)
136 TRIO_PUBLIC_NAN int
137 trio_isnan
138 TRIO_PROTO((double number));
139 #endif
140
141 /*
142 * If number is positive infinity return 1, if number is negative
143 * infinity return -1, otherwise return 0.
144 */
145 #if defined(TRIO_FUNC_ISINF)
146 TRIO_PUBLIC_NAN int
147 trio_isinf
148 TRIO_PROTO((double number));
149 #endif
150
151 /*
152 * If number is finite return non-zero, otherwise return zero.
153 */
154 #if defined(TRIO_FUNC_ISFINITE)
155 TRIO_PUBLIC_NAN int
156 trio_isfinite
157 TRIO_PROTO((double number));
158 #endif
159
160 #if defined(TRIO_FUNC_SIGNBIT)
161 TRIO_PUBLIC_NAN int
162 trio_signbit
163 TRIO_PROTO((double number));
164 #endif
165
166 #if defined(TRIO_FUNC_FPCLASSIFY)
167 TRIO_PUBLIC_NAN int
168 trio_fpclassify
169 TRIO_PROTO((double number));
170 #endif
171
172 #if defined(TRIO_FUNC_FPCLASSIFY_AND_SIGNBIT)
173 TRIO_PUBLIC_NAN int
174 trio_fpclassify_and_signbit
175 TRIO_PROTO((double number, int *is_negative));
176 #endif
177
178 #ifdef __cplusplus
179 }
180 #endif
181
182 #endif /* TRIO_TRIONAN_H */
0 /*************************************************************************
1 *
2 * $Id: triop.h,v 1.18 2009/07/05 10:14:07 breese Exp $
3 *
4 * Copyright (C) 2000 Bjorn Reese and Daniel Stenberg.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
14 *
15 ************************************************************************
16 *
17 * Private functions, types, etc. used for callback functions.
18 *
19 * The ref pointer is an opaque type and should remain as such.
20 * Private data must only be accessible through the getter and
21 * setter functions.
22 *
23 ************************************************************************/
24
25 #ifndef TRIO_TRIOP_H
26 #define TRIO_TRIOP_H
27
28 #include "triodef.h"
29
30 #include <stdlib.h>
31 #if defined(TRIO_COMPILER_ANCIENT)
32 # include <varargs.h>
33 #else
34 # include <stdarg.h>
35 #endif
36
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40
41 /*************************************************************************
42 * Supported standards
43 */
44
45 /*
46 * TRIO_C99 (=0 or =1)
47 *
48 * Define this to 0 to disable C99 format specifier extensions, or
49 * define to 1 to enable them. The format specifiers that are
50 * disabled by this switch are labelled with [C99] in the format
51 * specifier documentation.
52 */
53 #if !defined(TRIO_C99)
54 # define TRIO_C99 1
55 #endif
56
57 /*
58 * TRIO_BSD (=0 or =1)
59 *
60 * Define this to 0 to disable BSD format specifier extensions, or
61 * define to 1 to enable them. The format specifiers that are
62 * disabled by this switch are labelled with [BSD] in the format
63 * specifier documentation.
64 */
65 #if !defined(TRIO_BSD)
66 # define TRIO_BSD 1
67 #endif
68
69 /*
70 * TRIO_GNU (=0 or =1)
71 *
72 * Define this to 0 to disable GNU format specifier extensions, or
73 * define to 1 to enable them. The format specifiers that are
74 * disabled by this switch are labelled with [GNU] in the format
75 * specifier documentation.
76 */
77 #if !defined(TRIO_GNU)
78 # define TRIO_GNU 1
79 #endif
80
81 /*
82 * TRIO_MISC (=0 or =1)
83 *
84 * Define this to 0 to disable miscellaneous format specifier
85 * extensions, or define to 1 to enable them. The format specifiers
86 * that are disabled by this switch are labelled with [MISC] in the
87 * format specifier documentation.
88 */
89 #if !defined(TRIO_MISC)
90 # define TRIO_MISC 1
91 #endif
92
93 /*
94 * TRIO_UNIX98 (=0 or =1)
95 *
96 * Define this to 0 to disable UNIX98 format specifier extensions,
97 * or define to 1 to enable them. The format specifiers that are
98 * disabled by this switch are labelled with [UNIX98] in the format
99 * specifier documentation.
100 */
101 #if !defined(TRIO_UNIX98)
102 # define TRIO_UNIX98 1
103 #endif
104
105 /*
106 * TRIO_MICROSOFT (=0 or =1)
107 *
108 * Define this to 0 to disable Microsoft Visual C format specifier
109 * extensions, or define to 1 to enable them. The format specifiers
110 * that are disabled by this switch are labelled with [MSVC] in the
111 * format specifier documentation.
112 */
113 #if !defined(TRIO_MICROSOFT)
114 # define TRIO_MICROSOFT 1
115 #endif
116
117 /*
118 * TRIO_EXTENSION (=0 or =1)
119 *
120 * Define this to 0 to disable Trio-specific extensions, or define
121 * to 1 to enable them. This has two effects: it controls whether
122 * or not the Trio user-defined formating mechanism
123 * (trio_register() etc) is supported, and it enables or disables
124 * Trio's own format specifier extensions. The format specifiers
125 * that are disabled by this switch are labelled with [TRIO] in
126 * the format specifier documentation.
127 */
128 #if !defined(TRIO_EXTENSION)
129 # define TRIO_EXTENSION 1
130 #endif
131
132 /*
133 * TRIO_DEPRECATED (=0 or =1)
134 *
135 * Define this to 0 to disable deprecated functionality, or define
136 * to 1 to enable them.
137 */
138 #if !defined(TRIO_DEPRECATED)
139 # define TRIO_DEPRECATED 1
140 #endif
141
142 /*************************************************************************
143 * Features
144 */
145
146 #if defined(TRIO_SNPRINTF_ONLY)
147 # define TRIO_FEATURE_SCANF 0
148 # define TRIO_FEATURE_FILE 0
149 # define TRIO_FEATURE_STDIO 0
150 # define TRIO_FEATURE_FD 0
151 # define TRIO_FEATURE_DYNAMICSTRING 0
152 # define TRIO_FEATURE_CLOSURE 0
153 # define TRIO_FEATURE_STRERR 0
154 # define TRIO_FEATURE_LOCALE 0
155 # define TRIO_EMBED_NAN 1
156 # define TRIO_EMBED_STRING 1
157 #endif
158
159 /*
160 * TRIO_FEATURE_SCANF (=0 or =1)
161 *
162 * Define this to 0 to disable all the scanf() variants, or define to 1
163 * to enable them.
164 */
165 #if !defined(TRIO_FEATURE_SCANF)
166 # define TRIO_FEATURE_SCANF 1
167 #endif
168
169 /*
170 * TRIO_FEATURE_FILE (=0 or =1)
171 *
172 * Define this to 0 to disable compilation of the trio_fprintf() and
173 * trio_fscanf() family of functions, or define to 1 to enable them.
174 *
175 * This may be useful on an embedded platform with no filesystem.
176 * Note that trio_printf() uses fwrite to write to stdout, so if you
177 * do not have an implementation of fwrite() at all then you must also
178 * define TRIO_FEATURE_STDIO to 0.
179 */
180 #if !defined(TRIO_FEATURE_FILE)
181 # define TRIO_FEATURE_FILE 1
182 #endif
183
184 /*
185 * TRIO_FEATURE_STDIO (=0 or =1)
186 *
187 * Define this to 0 to disable compilation of the trio_printf() and
188 * trio_scanf() family of functions, or define to 1 to enable them.
189 *
190 * This may be useful on an embedded platform with no standard I/O.
191 */
192 #if !defined(TRIO_FEATURE_STDIO)
193 # define TRIO_FEATURE_STDIO 1
194 #endif
195
196 /*
197 * TRIO_FEATURE_FD (=0 or =1)
198 *
199 * Define this to 0 to disable compilation of the trio_dprintf() and
200 * trio_dscanf() family of functions, or define to 1 to enable them.
201 *
202 * This may be useful on an embedded platform with no filesystem, or on
203 * a platform that supports file I/O using FILE* but not using raw file
204 * descriptors.
205 */
206 #if !defined(TRIO_FEATURE_FD)
207 # define TRIO_FEATURE_FD 1
208 #endif
209
210 /*
211 * TRIO_FEATURE_DYNAMICSTRING (=0 or =1)
212 *
213 * Define this to 0 to disable compilation of the trio_aprintf()
214 * family of functions, or define to 1 to enable them.
215 *
216 * If you define both this and TRIO_MINIMAL to 0, then Trio will never
217 * call malloc or free.
218 */
219 #if !defined(TRIO_FEATURE_DYNAMICSTRING)
220 # define TRIO_FEATURE_DYNAMICSTRING 1
221 #endif
222
223 /*
224 * TRIO_FEATURE_CLOSURE (=0 or =1)
225 *
226 * Define this to 0 to disable compilation of the trio_cprintf() and
227 * trio_cscanf() family of functions, or define to 1 to enable them.
228 *
229 * These functions are rarely needed. This saves a (small) amount of code.
230 */
231 #if !defined(TRIO_FEATURE_CLOSURE)
232 # define TRIO_FEATURE_CLOSURE 1
233 #endif
234
235 /*
236 * TRIO_FEATURE_ERRORCODE (=0 or =1)
237 *
238 * Define this to 0 to return -1 from the print and scan function on
239 * error, or define to 1 to return a negative number with debugging
240 * information as part of the return code.
241 *
242 * If enabled, the return code will be a negative number, which encodes
243 * an error code and an error location. These can be decoded with the
244 * TRIO_ERROR_CODE and TRIO_ERROR_POSITION macros.
245 */
246 #if defined(TRIO_ERRORS)
247 # define TRIO_FEATURE_ERRORCODE TRIO_ERRORS
248 #endif
249 #if !defined(TRIO_FEATURE_ERRORCODE)
250 # define TRIO_FEATURE_ERRORCODE 1
251 #endif
252
253 /*
254 * TRIO_FEATURE_STRERR (=0 or =1)
255 *
256 * Define this to 0 if you do not use trio_strerror(), or define to 1 if
257 * you do use it.
258 *
259 * This saves a (small) amount of code.
260 */
261 #if !defined(TRIO_FEATURE_STRERR)
262 # define TRIO_FEATURE_STRERR 1
263 #endif
264
265 /*
266 * TRIO_FEATURE_FLOAT (=0 or =1)
267 *
268 * Define this to 0 to disable all floating-point support, or define
269 * to 1 to enable it.
270 *
271 * This is useful in restricted embedded platforms that do not support
272 * floating-point. Obviously you cannot use floating-point format
273 * specifiers if you define this.
274 *
275 * Do not compile trionan.c if you disable this.
276 */
277 #if !defined(TRIO_FEATURE_FLOAT)
278 # define TRIO_FEATURE_FLOAT 1
279 #endif
280
281 /*
282 * TRIO_FEATURE_LOCALE (=0 or =1)
283 *
284 * Define this to 0 to disable customized locale support, or define
285 * to 1 to enable it.
286 *
287 * This saves a (small) amount of code.
288 */
289 #if !defined(TRIO_FEATURE_LOCALE)
290 # define TRIO_FEATURE_LOCALE 1
291 #endif
292
293 /*
294 * TRIO_MINIMAL
295 *
296 * Define this to disable building the public trionan.h and triostr.h.
297 * If you define this, then you must not compile trionan.c and triostr.c
298 * separately.
299 */
300 #if defined(TRIO_MINIMAL)
301 # if !defined(TRIO_EMBED_NAN)
302 # define TRIO_EMBED_NAN
303 # endif
304 # if !defined(TRIO_EMBED_STRING)
305 # define TRIO_EMBED_STRING
306 # endif
307 #endif
308
309 /* Does not work yet. Do not enable */
310 #ifndef TRIO_FEATURE_WIDECHAR
311 # define TRIO_FEATURE_WIDECHAR 0
312 #endif
313
314 /*************************************************************************
315 * Mapping standards to internal features
316 */
317
318 #if !defined(TRIO_FEATURE_HEXFLOAT)
319 # define TRIO_FEATURE_HEXFLOAT (TRIO_C99 && TRIO_FEATURE_FLOAT)
320 #endif
321
322 #if !defined(TRIO_FEATURE_LONGDOUBLE)
323 # define TRIO_FEATURE_LONGDOUBLE TRIO_FEATURE_FLOAT
324 #endif
325
326 #if !defined(TRIO_FEATURE_ERRNO)
327 # define TRIO_FEATURE_ERRNO TRIO_GNU
328 #endif
329
330 #if !defined(TRIO_FEATURE_QUAD)
331 # define TRIO_FEATURE_QUAD (TRIO_BSD || TRIO_GNU)
332 #endif
333
334 #if !defined(TRIO_FEATURE_SIZE_T)
335 # define TRIO_FEATURE_SIZE_T TRIO_C99
336 #endif
337
338 #if !defined(TRIO_FEATURE_SIZE_T_UPPER)
339 # define TRIO_FEATURE_SIZE_T_UPPER TRIO_GNU
340 #endif
341
342 #if !defined(TRIO_FEATURE_PTRDIFF_T)
343 # define TRIO_FEATURE_PTRDIFF_T TRIO_C99
344 #endif
345
346 #if !defined(TRIO_FEATURE_INTMAX_T)
347 # define TRIO_FEATURE_INTMAX_T TRIO_C99
348 #endif
349
350 #if !defined(TRIO_FEATURE_FIXED_SIZE)
351 # define TRIO_FEATURE_FIXED_SIZE TRIO_MICROSOFT
352 #endif
353
354 #if !defined(TRIO_FEATURE_POSITIONAL)
355 # define TRIO_FEATURE_POSITIONAL TRIO_UNIX98
356 #endif
357
358 #if !defined(TRIO_FEATURE_USER_DEFINED)
359 # define TRIO_FEATURE_USER_DEFINED TRIO_EXTENSION
360 #endif
361
362 #if !defined(TRIO_FEATURE_BINARY)
363 # define TRIO_FEATURE_BINARY TRIO_EXTENSION
364 #endif
365
366 #if !defined(TRIO_FEATURE_QUOTE)
367 # define TRIO_FEATURE_QUOTE TRIO_EXTENSION
368 #endif
369
370 #if !defined(TRIO_FEATURE_STICKY)
371 # define TRIO_FEATURE_STICKY TRIO_EXTENSION
372 #endif
373
374 #if !defined(TRIO_FEATURE_VARSIZE)
375 # define TRIO_FEATURE_VARSIZE TRIO_EXTENSION
376 #endif
377
378 #if !defined(TRIO_FEATURE_ROUNDING)
379 # define TRIO_FEATURE_ROUNDING TRIO_EXTENSION
380 #endif
381
382 /*************************************************************************
383 * Memory handling
384 */
385 #ifndef TRIO_MALLOC
386 # define TRIO_MALLOC(n) malloc(n)
387 #endif
388 #ifndef TRIO_REALLOC
389 # define TRIO_REALLOC(x,n) realloc((x),(n))
390 #endif
391 #ifndef TRIO_FREE
392 # define TRIO_FREE(x) free(x)
393 #endif
394
395
396 /*************************************************************************
397 * User-defined specifiers
398 */
399
400 typedef int (*trio_callback_t) TRIO_PROTO((trio_pointer_t));
401
402 trio_pointer_t trio_register TRIO_PROTO((trio_callback_t callback, const char *name));
403 void trio_unregister TRIO_PROTO((trio_pointer_t handle));
404
405 TRIO_CONST char *trio_get_format TRIO_PROTO((trio_pointer_t ref));
406 /* Mednafen modification to fix a gcc warning */
407 /*TRIO_CONST*/ trio_pointer_t trio_get_argument TRIO_PROTO((trio_pointer_t ref));
408
409 /* Modifiers */
410 int trio_get_width TRIO_PROTO((trio_pointer_t ref));
411 void trio_set_width TRIO_PROTO((trio_pointer_t ref, int width));
412 int trio_get_precision TRIO_PROTO((trio_pointer_t ref));
413 void trio_set_precision TRIO_PROTO((trio_pointer_t ref, int precision));
414 int trio_get_base TRIO_PROTO((trio_pointer_t ref));
415 void trio_set_base TRIO_PROTO((trio_pointer_t ref, int base));
416 int trio_get_padding TRIO_PROTO((trio_pointer_t ref));
417 void trio_set_padding TRIO_PROTO((trio_pointer_t ref, int is_padding));
418 int trio_get_short TRIO_PROTO((trio_pointer_t ref)); /* h */
419 void trio_set_shortshort TRIO_PROTO((trio_pointer_t ref, int is_shortshort));
420 int trio_get_shortshort TRIO_PROTO((trio_pointer_t ref)); /* hh */
421 void trio_set_short TRIO_PROTO((trio_pointer_t ref, int is_short));
422 int trio_get_long TRIO_PROTO((trio_pointer_t ref)); /* l */
423 void trio_set_long TRIO_PROTO((trio_pointer_t ref, int is_long));
424 int trio_get_longlong TRIO_PROTO((trio_pointer_t ref)); /* ll */
425 void trio_set_longlong TRIO_PROTO((trio_pointer_t ref, int is_longlong));
426 int trio_get_longdouble TRIO_PROTO((trio_pointer_t ref)); /* L */
427 void trio_set_longdouble TRIO_PROTO((trio_pointer_t ref, int is_longdouble));
428 int trio_get_alternative TRIO_PROTO((trio_pointer_t ref)); /* # */
429 void trio_set_alternative TRIO_PROTO((trio_pointer_t ref, int is_alternative));
430 int trio_get_alignment TRIO_PROTO((trio_pointer_t ref)); /* - */
431 void trio_set_alignment TRIO_PROTO((trio_pointer_t ref, int is_leftaligned));
432 int trio_get_spacing TRIO_PROTO((trio_pointer_t ref)); /* (space) */
433 void trio_set_spacing TRIO_PROTO((trio_pointer_t ref, int is_space));
434 int trio_get_sign TRIO_PROTO((trio_pointer_t ref)); /* + */
435 void trio_set_sign TRIO_PROTO((trio_pointer_t ref, int is_showsign));
436 #if TRIO_FEATURE_QUOTE
437 int trio_get_quote TRIO_PROTO((trio_pointer_t ref)); /* ' */
438 void trio_set_quote TRIO_PROTO((trio_pointer_t ref, int is_quote));
439 #endif
440 int trio_get_upper TRIO_PROTO((trio_pointer_t ref));
441 void trio_set_upper TRIO_PROTO((trio_pointer_t ref, int is_upper));
442 #if TRIO_FEATURE_INTMAX_T
443 int trio_get_largest TRIO_PROTO((trio_pointer_t ref)); /* j */
444 void trio_set_largest TRIO_PROTO((trio_pointer_t ref, int is_largest));
445 #endif
446 #if TRIO_FEATURE_PTRDIFF_T
447 int trio_get_ptrdiff TRIO_PROTO((trio_pointer_t ref)); /* t */
448 void trio_set_ptrdiff TRIO_PROTO((trio_pointer_t ref, int is_ptrdiff));
449 #endif
450 #if TRIO_FEATURE_SIZE_T
451 int trio_get_size TRIO_PROTO((trio_pointer_t ref)); /* z / Z */
452 void trio_set_size TRIO_PROTO((trio_pointer_t ref, int is_size));
453 #endif
454
455 /* Printing */
456 int trio_print_ref TRIO_PROTO((trio_pointer_t ref, const char *format, ...));
457 int trio_vprint_ref TRIO_PROTO((trio_pointer_t ref, const char *format, va_list args));
458 int trio_printv_ref TRIO_PROTO((trio_pointer_t ref, const char *format, trio_pointer_t *args));
459
460 void trio_print_int TRIO_PROTO((trio_pointer_t ref, int number));
461 void trio_print_uint TRIO_PROTO((trio_pointer_t ref, unsigned int number));
462 /* void trio_print_long TRIO_PROTO((trio_pointer_t ref, long number)); */
463 /* void trio_print_ulong TRIO_PROTO((trio_pointer_t ref, unsigned long number)); */
464 void trio_print_double TRIO_PROTO((trio_pointer_t ref, double number));
465 void trio_print_string TRIO_PROTO((trio_pointer_t ref, TRIO_CONST char *string));
466 void trio_print_pointer TRIO_PROTO((trio_pointer_t ref, trio_pointer_t pointer));
467
468 #ifdef __cplusplus
469 } /* extern "C" */
470 #endif
471
472 #endif /* TRIO_TRIOP_H */
0 /*************************************************************************
1 *
2 * $Id: triostr.h,v 1.18 2010/01/26 13:02:02 breese Exp $
3 *
4 * Copyright (C) 2001 Bjorn Reese and Daniel Stenberg.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
14 *
15 ************************************************************************/
16
17 #ifndef TRIO_TRIOSTR_H
18 #define TRIO_TRIOSTR_H
19
20 /*
21 * Documentation is located in triostr.c
22 */
23
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include "triodef.h"
29 #include "triop.h"
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 enum {
36 TRIO_HASH_NONE = 0,
37 TRIO_HASH_PLAIN,
38 TRIO_HASH_TWOSIGNED
39 };
40
41 #if !defined(TRIO_PUBLIC_STRING)
42 # if !defined(TRIO_PUBLIC)
43 # define TRIO_PUBLIC
44 # endif
45 # define TRIO_PUBLIC_STRING TRIO_PUBLIC
46 #endif
47
48 /*************************************************************************
49 * Dependencies
50 */
51
52 #if defined(TRIO_EMBED_STRING)
53
54 /*
55 * The application that triostr is embedded in must define which functions
56 * it uses.
57 *
58 * The following resolves internal dependencies.
59 */
60
61 # if defined(TRIO_FUNC_XSTRING_SET)
62 # if !defined(TRIO_FUNC_DUPLICATE)
63 # define TRIO_FUNC_DUPLICATE
64 # endif
65 # endif
66
67 # if defined(TRIO_FUNC_DUPLICATE) \
68 || defined(TRIO_FUNC_DUPLICATE_MAX) \
69 || defined(TRIO_FUNC_STRING_DUPLICATE) \
70 || defined(TRIO_FUNC_XSTRING_DUPLICATE)
71 # if !defined(TRIO_FUNC_CREATE)
72 # define TRIO_FUNC_CREATE
73 # endif
74 # if !defined(TRIO_FUNC_COPY_MAX)
75 # define TRIO_FUNC_COPY_MAX
76 # endif
77 # endif
78
79 # if defined(TRIO_FUNC_STRING_CREATE)
80 # if !defined(TRIO_FUNC_STRING_DESTROY)
81 # define TRIO_FUNC_STRING_DESTROY
82 # endif
83 # endif
84
85 # if defined(TRIO_FUNC_STRING_DESTROY) \
86 || defined(TRIO_FUNC_XSTRING_SET)
87 # if !defined(TRIO_FUNC_DESTROY)
88 # define TRIO_FUNC_DESTROY
89 # endif
90 # endif
91
92 # if defined(TRIO_FUNC_EQUAL_LOCALE) \
93 || defined(TRIO_FUNC_STRING_EQUAL) \
94 || defined(TRIO_FUNC_XSTRING_EQUAL)
95 # if !defined(TRIO_FUNC_EQUAL)
96 # define TRIO_FUNC_EQUAL
97 # endif
98 # endif
99
100 # if defined(TRIO_FUNC_EQUAL_CASE) \
101 || defined(TRIO_FUNC_STRING_EQUAL_CASE) \
102 || defined(TRIO_FUNC_XSTRING_EQUAL_CASE)
103 # if !defined(TRIO_FUNC_EQUAL_CASE)
104 # define TRIO_FUNC_EQUAL_CASE
105 # endif
106 # endif
107
108 # if defined(TRIO_FUNC_SUBSTRING_MAX) \
109 || defined(TRIO_FUNC_STRING_EQUAL_MAX) \
110 || defined(TRIO_FUNC_XSTRING_EQUAL_MAX)
111 # if !defined(TRIO_FUNC_EQUAL_MAX)
112 # define TRIO_FUNC_EQUAL_MAX
113 # endif
114 # endif
115
116 # if defined(TRIO_FUNC_TO_DOUBLE) \
117 || defined(TRIO_FUNC_TO_FLOAT)
118 # if !defined(TRIO_FUNC_TO_LONG_DOUBLE)
119 # define TRIO_FUNC_TO_LONG_DOUBLE
120 # endif
121 # endif
122
123 # if defined(TRIO_FUNC_STRING_TERMINATE)
124 # if !defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
125 # define TRIO_FUNC_XSTRING_APPEND_CHAR
126 # endif
127 # endif
128
129 # if defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
130 # if !defined(TRIO_FUNC_STRING_SIZE)
131 # define TRIO_FUNC_STRING_SIZE
132 # endif
133 # endif
134
135 #else
136
137 /*
138 * When triostr is not embedded all functions are defined.
139 */
140
141 # define TRIO_FUNC_APPEND
142 # define TRIO_FUNC_APPEND_MAX
143 # define TRIO_FUNC_CONTAINS
144 # define TRIO_FUNC_COPY
145 # define TRIO_FUNC_COPY_MAX
146 # define TRIO_FUNC_CREATE
147 # define TRIO_FUNC_DESTROY
148 # define TRIO_FUNC_DUPLICATE
149 # define TRIO_FUNC_DUPLICATE_MAX
150 # define TRIO_FUNC_EQUAL
151 # define TRIO_FUNC_EQUAL_CASE
152 # define TRIO_FUNC_EQUAL_CASE_MAX
153 # define TRIO_FUNC_EQUAL_LOCALE
154 # define TRIO_FUNC_EQUAL_MAX
155 # define TRIO_FUNC_ERROR
156 # if !defined(TRIO_PLATFORM_WINCE)
157 # define TRIO_FUNC_FORMAT_DATE_MAX
158 # endif
159 # define TRIO_FUNC_HASH
160 # define TRIO_FUNC_INDEX
161 # define TRIO_FUNC_INDEX_LAST
162 # define TRIO_FUNC_LENGTH
163 # define TRIO_FUNC_LENGTH_MAX
164 # define TRIO_FUNC_LOWER
165 # define TRIO_FUNC_MATCH
166 # define TRIO_FUNC_MATCH_CASE
167 # define TRIO_FUNC_SPAN_FUNCTION
168 # define TRIO_FUNC_SUBSTRING
169 # define TRIO_FUNC_SUBSTRING_MAX
170 # define TRIO_FUNC_TO_DOUBLE
171 # define TRIO_FUNC_TO_FLOAT
172 # define TRIO_FUNC_TO_LONG
173 # define TRIO_FUNC_TO_LONG_DOUBLE
174 # define TRIO_FUNC_TO_LOWER
175 # define TRIO_FUNC_TO_UNSIGNED_LONG
176 # define TRIO_FUNC_TO_UPPER
177 # define TRIO_FUNC_TOKENIZE
178 # define TRIO_FUNC_UPPER
179
180 # define TRIO_FUNC_STRING_APPEND
181 # define TRIO_FUNC_STRING_CONTAINS
182 # define TRIO_FUNC_STRING_COPY
183 # define TRIO_FUNC_STRING_CREATE
184 # define TRIO_FUNC_STRING_DESTROY
185 # define TRIO_FUNC_STRING_DUPLICATE
186 # define TRIO_FUNC_STRING_EQUAL
187 # define TRIO_FUNC_STRING_EQUAL_CASE
188 # define TRIO_FUNC_STRING_EQUAL_CASE_MAX
189 # define TRIO_FUNC_STRING_EQUAL_MAX
190 # define TRIO_FUNC_STRING_EXTRACT
191 # if !defined(TRIO_PLATFORM_WINCE)
192 # define TRIO_FUNC_STRING_FORMAT_DATE_MAX
193 # endif
194 # define TRIO_FUNC_STRING_GET
195 # define TRIO_FUNC_STRING_INDEX
196 # define TRIO_FUNC_STRING_INDEX_LAST
197 # define TRIO_FUNC_STRING_LENGTH
198 # define TRIO_FUNC_STRING_LOWER
199 # define TRIO_FUNC_STRING_MATCH
200 # define TRIO_FUNC_STRING_MATCH_CASE
201 # define TRIO_FUNC_STRING_SIZE
202 # define TRIO_FUNC_STRING_SUBSTRING
203 # define TRIO_FUNC_STRING_TERMINATE
204 # define TRIO_FUNC_STRING_UPPER
205
206 # define TRIO_FUNC_XSTRING_APPEND
207 # define TRIO_FUNC_XSTRING_APPEND_CHAR
208 # define TRIO_FUNC_XSTRING_APPEND_MAX
209 # define TRIO_FUNC_XSTRING_CONTAINS
210 # define TRIO_FUNC_XSTRING_COPY
211 # define TRIO_FUNC_XSTRING_DUPLICATE
212 # define TRIO_FUNC_XSTRING_EQUAL
213 # define TRIO_FUNC_XSTRING_EQUAL_CASE
214 # define TRIO_FUNC_XSTRING_EQUAL_CASE_MAX
215 # define TRIO_FUNC_XSTRING_EQUAL_MAX
216 # define TRIO_FUNC_XSTRING_MATCH
217 # define TRIO_FUNC_XSTRING_MATCH_CASE
218 # define TRIO_FUNC_XSTRING_SET
219 # define TRIO_FUNC_XSTRING_SUBSTRING
220
221 #endif
222
223
224 /*************************************************************************
225 * String functions
226 */
227
228 #if defined(TRIO_FUNC_APPEND)
229 TRIO_PUBLIC_STRING int
230 trio_append
231 TRIO_PROTO((char *target, TRIO_CONST char *source));
232 #endif
233
234 #if defined(TRIO_FUNC_APPEND_MAX)
235 TRIO_PUBLIC_STRING int
236 trio_append_max
237 TRIO_PROTO((char *target, size_t max, TRIO_CONST char *source));
238 #endif
239
240 #if defined(TRIO_FUNC_CONTAINS)
241 TRIO_PUBLIC_STRING int
242 trio_contains
243 TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *substring));
244 #endif
245
246 #if defined(TRIO_FUNC_COPY)
247 TRIO_PUBLIC_STRING int
248 trio_copy
249 TRIO_PROTO((char *target, TRIO_CONST char *source));
250 #endif
251
252 #if defined(TRIO_FUNC_COPY_MAX)
253 TRIO_PUBLIC_STRING int
254 trio_copy_max
255 TRIO_PROTO((char *target, size_t max, TRIO_CONST char *source));
256 #endif
257
258 #if defined(TRIO_FUNC_CREATE)
259 TRIO_PUBLIC_STRING char *
260 trio_create
261 TRIO_PROTO((size_t size));
262 #endif
263
264 #if defined(TRIO_FUNC_DESTROY)
265 TRIO_PUBLIC_STRING void
266 trio_destroy
267 TRIO_PROTO((char *string));
268 #endif
269
270 #if defined(TRIO_FUNC_DUPLICATE)
271 TRIO_PUBLIC_STRING char *
272 trio_duplicate
273 TRIO_PROTO((TRIO_CONST char *source));
274 #endif
275
276 #if defined(TRIO_FUNC_DUPLICATE_MAX)
277 TRIO_PUBLIC_STRING char *
278 trio_duplicate_max
279 TRIO_PROTO((TRIO_CONST char *source, size_t max));
280 #endif
281
282 #if defined(TRIO_FUNC_EQUAL)
283 TRIO_PUBLIC_STRING int
284 trio_equal
285 TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second));
286 #endif
287
288 #if defined(TRIO_FUNC_EQUAL_CASE)
289 TRIO_PUBLIC_STRING int
290 trio_equal_case
291 TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second));
292 #endif
293
294 #if defined(TRIO_FUNC_EQUAL_CASE_MAX)
295 TRIO_PUBLIC_STRING int
296 trio_equal_case_max
297 TRIO_PROTO((TRIO_CONST char *first, size_t max, TRIO_CONST char *second));
298 #endif
299
300 #if defined(TRIO_FUNC_EQUAL_LOCALE)
301 TRIO_PUBLIC_STRING int
302 trio_equal_locale
303 TRIO_PROTO((TRIO_CONST char *first, TRIO_CONST char *second));
304 #endif
305
306 #if defined(TRIO_FUNC_EQUAL_MAX)
307 TRIO_PUBLIC_STRING int
308 trio_equal_max
309 TRIO_PROTO((TRIO_CONST char *first, size_t max, TRIO_CONST char *second));
310 #endif
311
312 #if defined(TRIO_FUNC_ERROR)
313 TRIO_PUBLIC_STRING TRIO_CONST char *
314 trio_error
315 TRIO_PROTO((int));
316 #endif
317
318 #if defined(TRIO_FUNC_FORMAT_DATE_MAX)
319 TRIO_PUBLIC_STRING size_t
320 trio_format_date_max
321 TRIO_PROTO((char *target, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime));
322 #endif
323
324 #if defined(TRIO_FUNC_HASH)
325 TRIO_PUBLIC_STRING unsigned long
326 trio_hash
327 TRIO_PROTO((TRIO_CONST char *string, int type));
328 #endif
329
330 #if defined(TRIO_FUNC_INDEX)
331 TRIO_PUBLIC_STRING char *
332 trio_index
333 TRIO_PROTO((TRIO_CONST char *string, int character));
334 #endif
335
336 #if defined(TRIO_FUNC_INDEX_LAST)
337 TRIO_PUBLIC_STRING char *
338 trio_index_last
339 TRIO_PROTO((TRIO_CONST char *string, int character));
340 #endif
341
342 #if defined(TRIO_FUNC_LENGTH)
343 TRIO_PUBLIC_STRING size_t
344 trio_length
345 TRIO_PROTO((TRIO_CONST char *string));
346 #endif
347
348 #if defined(TRIO_FUNC_LENGTH_MAX)
349 TRIO_PUBLIC_STRING size_t
350 trio_length_max
351 TRIO_PROTO((TRIO_CONST char *string, size_t max));
352 #endif
353
354 #if defined(TRIO_FUNC_LOWER)
355 TRIO_PUBLIC_STRING int
356 trio_lower
357 TRIO_PROTO((char *target));
358 #endif
359
360 #if defined(TRIO_FUNC_MATCH)
361 TRIO_PUBLIC_STRING int
362 trio_match
363 TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *pattern));
364 #endif
365
366 #if defined(TRIO_FUNC_MATCH_CASE)
367 TRIO_PUBLIC_STRING int
368 trio_match_case
369 TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *pattern));
370 #endif
371
372 #if defined(TRIO_FUNC_SPAN_FUNCTION)
373 TRIO_PUBLIC_STRING size_t
374 trio_span_function
375 TRIO_PROTO((char *target, TRIO_CONST char *source, int (*Function) TRIO_PROTO((int))));
376 #endif
377
378 #if defined(TRIO_FUNC_SUBSTRING)
379 TRIO_PUBLIC_STRING char *
380 trio_substring
381 TRIO_PROTO((TRIO_CONST char *string, TRIO_CONST char *substring));
382 #endif
383
384 #if defined(TRIO_FUNC_SUBSTRING_MAX)
385 TRIO_PUBLIC_STRING char *
386 trio_substring_max
387 TRIO_PROTO((TRIO_CONST char *string, size_t max, TRIO_CONST char *substring));
388 #endif
389
390 #if defined(TRIO_FUNC_TO_DOUBLE)
391 TRIO_PUBLIC_STRING double
392 trio_to_double
393 TRIO_PROTO((TRIO_CONST char *source, char **endp));
394 #endif
395
396 #if defined(TRIO_FUNC_TO_FLOAT)
397 TRIO_PUBLIC_STRING float
398 trio_to_float
399 TRIO_PROTO((TRIO_CONST char *source, char **endp));
400 #endif
401
402 #if defined(TRIO_FUNC_TO_LONG)
403 TRIO_PUBLIC_STRING long
404 trio_to_long
405 TRIO_PROTO((TRIO_CONST char *source, char **endp, int base));
406 #endif
407
408 #if defined(TRIO_FUNC_TO_LOWER)
409 TRIO_PUBLIC_STRING int
410 trio_to_lower
411 TRIO_PROTO((int source));
412 #endif
413
414 #if defined(TRIO_FUNC_TO_LONG_DOUBLE)
415 TRIO_PUBLIC_STRING trio_long_double_t
416 trio_to_long_double
417 TRIO_PROTO((TRIO_CONST char *source, char **endp));
418 #endif
419
420 #if defined(TRIO_FUNC_TO_UNSIGNED_LONG)
421 TRIO_PUBLIC_STRING unsigned long
422 trio_to_unsigned_long
423 TRIO_PROTO((TRIO_CONST char *source, char **endp, int base));
424 #endif
425
426 #if defined(TRIO_FUNC_TO_UPPER)
427 TRIO_PUBLIC_STRING int
428 trio_to_upper
429 TRIO_PROTO((int source));
430 #endif
431
432 #if defined(TRIO_FUNC_TOKENIZE)
433 TRIO_PUBLIC_STRING char *
434 trio_tokenize
435 TRIO_PROTO((char *string, TRIO_CONST char *delimiters));
436 #endif
437
438 #if defined(TRIO_FUNC_UPPER)
439 TRIO_PUBLIC_STRING int
440 trio_upper
441 TRIO_PROTO((char *target));
442 #endif
443
444 /*************************************************************************
445 * Dynamic string functions
446 */
447
448 /*
449 * Opaque type for dynamic strings
450 */
451
452 typedef struct _trio_string_t trio_string_t;
453
454 #if defined(TRIO_FUNC_STRING_APPEND)
455 TRIO_PUBLIC_STRING int
456 trio_string_append
457 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
458 #endif
459
460 #if defined(TRIO_FUNC_STRING_CONTAINS)
461 TRIO_PUBLIC_STRING int
462 trio_string_contains
463 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
464 #endif
465
466 #if defined(TRIO_FUNC_STRING_COPY)
467 TRIO_PUBLIC_STRING int
468 trio_string_copy
469 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
470 #endif
471
472 #if defined(TRIO_FUNC_STRING_CREATE)
473 TRIO_PUBLIC_STRING trio_string_t *
474 trio_string_create
475 TRIO_PROTO((int initial_size));
476 #endif
477
478 #if defined(TRIO_FUNC_STRING_DESTROY)
479 TRIO_PUBLIC_STRING void
480 trio_string_destroy
481 TRIO_PROTO((trio_string_t *self));
482 #endif
483
484 #if defined(TRIO_FUNC_STRING_DUPLICATE)
485 TRIO_PUBLIC_STRING trio_string_t *
486 trio_string_duplicate
487 TRIO_PROTO((trio_string_t *other));
488 #endif
489
490 #if defined(TRIO_FUNC_STRING_EQUAL)
491 TRIO_PUBLIC_STRING int
492 trio_string_equal
493 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
494 #endif
495
496 #if defined(TRIO_FUNC_STRING_EQUAL_MAX)
497 TRIO_PUBLIC_STRING int
498 trio_string_equal_max
499 TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *second));
500 #endif
501
502 #if defined(TRIO_FUNC_STRING_EQUAL_CASE)
503 TRIO_PUBLIC_STRING int
504 trio_string_equal_case
505 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
506 #endif
507
508 #if defined(TRIO_FUNC_STRING_EQUAL_CASE_MAX)
509 TRIO_PUBLIC_STRING int
510 trio_string_equal_case_max
511 TRIO_PROTO((trio_string_t *self, size_t max, trio_string_t *other));
512 #endif
513
514 #if defined(TRIO_FUNC_STRING_EXTRACT)
515 TRIO_PUBLIC_STRING char *
516 trio_string_extract
517 TRIO_PROTO((trio_string_t *self));
518 #endif
519
520 #if defined(TRIO_FUNC_STRING_FORMAT_DATE_MAX)
521 TRIO_PUBLIC_STRING size_t
522 trio_string_format_date_max
523 TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *format, TRIO_CONST struct tm *datetime));
524 #endif
525
526 #if defined(TRIO_FUNC_STRING_GET)
527 TRIO_PUBLIC_STRING char *
528 trio_string_get
529 TRIO_PROTO((trio_string_t *self, int offset));
530 #endif
531
532 #if defined(TRIO_FUNC_STRING_INDEX)
533 TRIO_PUBLIC_STRING char *
534 trio_string_index
535 TRIO_PROTO((trio_string_t *self, int character));
536 #endif
537
538 #if defined(TRIO_FUNC_STRING_INDEX_LAST)
539 TRIO_PUBLIC_STRING char *
540 trio_string_index_last
541 TRIO_PROTO((trio_string_t *self, int character));
542 #endif
543
544 #if defined(TRIO_FUNC_STRING_LENGTH)
545 TRIO_PUBLIC_STRING int
546 trio_string_length
547 TRIO_PROTO((trio_string_t *self));
548 #endif
549
550 #if defined(TRIO_FUNC_STRING_LOWER)
551 TRIO_PUBLIC_STRING int
552 trio_string_lower
553 TRIO_PROTO((trio_string_t *self));
554 #endif
555
556 #if defined(TRIO_FUNC_STRING_MATCH)
557 TRIO_PUBLIC_STRING int
558 trio_string_match
559 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
560 #endif
561
562 #if defined(TRIO_FUNC_STRING_MATCH_CASE)
563 TRIO_PUBLIC_STRING int
564 trio_string_match_case
565 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
566 #endif
567
568 #if defined(TRIO_FUNC_STRING_SIZE)
569 TRIO_PUBLIC_STRING int
570 trio_string_size
571 TRIO_PROTO((trio_string_t *self));
572 #endif
573
574 #if defined(TRIO_FUNC_STRING_SUBSTRING)
575 TRIO_PUBLIC_STRING char *
576 trio_string_substring
577 TRIO_PROTO((trio_string_t *self, trio_string_t *other));
578 #endif
579
580 #if defined(TRIO_FUNC_STRING_TERMINATE)
581 TRIO_PUBLIC_STRING void
582 trio_string_terminate
583 TRIO_PROTO((trio_string_t *self));
584 #endif
585
586 #if defined(TRIO_FUNC_STRING_UPPER)
587 TRIO_PUBLIC_STRING int
588 trio_string_upper
589 TRIO_PROTO((trio_string_t *self));
590 #endif
591
592 #if defined(TRIO_FUNC_XSTRING_APPEND)
593 TRIO_PUBLIC_STRING int
594 trio_xstring_append
595 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
596 #endif
597
598 #if defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
599 TRIO_PUBLIC_STRING int
600 trio_xstring_append_char
601 TRIO_PROTO((trio_string_t *self, char character));
602 #endif
603
604 #if defined(TRIO_FUNC_XSTRING_APPEND_MAX)
605 TRIO_PUBLIC_STRING int
606 trio_xstring_append_max
607 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other, size_t max));
608 #endif
609
610 #if defined(TRIO_FUNC_XSTRING_CONTAINS)
611 TRIO_PUBLIC_STRING int
612 trio_xstring_contains
613 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
614 #endif
615
616 #if defined(TRIO_FUNC_XSTRING_COPY)
617 TRIO_PUBLIC_STRING int
618 trio_xstring_copy
619 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
620 #endif
621
622 #if defined(TRIO_FUNC_XSTRING_DUPLICATE)
623 TRIO_PUBLIC_STRING trio_string_t *
624 trio_xstring_duplicate
625 TRIO_PROTO((TRIO_CONST char *other));
626 #endif
627
628 #if defined(TRIO_FUNC_XSTRING_EQUAL)
629 TRIO_PUBLIC_STRING int
630 trio_xstring_equal
631 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
632 #endif
633
634 #if defined(TRIO_FUNC_XSTRING_EQUAL_MAX)
635 TRIO_PUBLIC_STRING int
636 trio_xstring_equal_max
637 TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *other));
638 #endif
639
640 #if defined(TRIO_FUNC_XSTRING_EQUAL_CASE)
641 TRIO_PUBLIC_STRING int
642 trio_xstring_equal_case
643 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
644 #endif
645
646 #if defined(TRIO_FUNC_XSTRING_EQUAL_CASE_MAX)
647 TRIO_PUBLIC_STRING int
648 trio_xstring_equal_case_max
649 TRIO_PROTO((trio_string_t *self, size_t max, TRIO_CONST char *other));
650 #endif
651
652 #if defined(TRIO_FUNC_XSTRING_MATCH)
653 TRIO_PUBLIC_STRING int
654 trio_xstring_match
655 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
656 #endif
657
658 #if defined(TRIO_FUNC_XSTRING_MATCH_CASE)
659 TRIO_PUBLIC_STRING int
660 trio_xstring_match_case
661 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
662 #endif
663
664 #if defined(TRIO_FUNC_XSTRING_SET)
665 TRIO_PUBLIC_STRING void
666 trio_xstring_set
667 TRIO_PROTO((trio_string_t *self, char *buffer));
668 #endif
669
670 #if defined(TRIO_FUNC_XSTRING_SUBSTRING)
671 TRIO_PUBLIC_STRING char *
672 trio_xstring_substring
673 TRIO_PROTO((trio_string_t *self, TRIO_CONST char *other));
674 #endif
675
676 #ifdef __cplusplus
677 }
678 #endif
679
680 #endif /* TRIO_TRIOSTR_H */
0 #ifndef __MDFN_PSX_MASMEM_H
1 #define __MDFN_PSX_MASMEM_H
2
3 // TODO, WIP (big-endian stores and loads not fully supported yet)
4
5 #ifdef MSB_FIRST
6 #define MAS_NATIVE_IS_BIGENDIAN 1
7 #else
8 #define MAS_NATIVE_IS_BIGENDIAN 0
9 #endif
10
11 static INLINE uint16 LoadU16_RBO(const uint16 *a)
12 {
13 #ifdef ARCH_POWERPC
14 uint16 tmp;
15
16 __asm__ ("lhbrx %0, %y1" : "=r"(tmp) : "Z"(*a));
17
18 return(tmp);
19
20 #else
21 uint16 tmp = *a;
22 return((tmp << 8) | (tmp >> 8));
23 #endif
24 }
25
26 static INLINE uint32 LoadU32_RBO(const uint32 *a)
27 {
28 #ifdef ARCH_POWERPC
29 uint32 tmp;
30
31 __asm__ ("lwbrx %0, %y1" : "=r"(tmp) : "Z"(*a));
32
33 return(tmp);
34 #else
35 uint32 tmp = *a;
36 return((tmp << 24) | ((tmp & 0xFF00) << 8) | ((tmp >> 8) & 0xFF00) | (tmp >> 24));
37 #endif
38 }
39
40 static INLINE void StoreU16_RBO(uint16 *a, const uint16 v)
41 {
42 #ifdef ARCH_POWERPC
43 __asm__ ("sthbrx %0, %y1" : : "r"(v), "Z"(*a));
44 #else
45 uint16 tmp = (v << 8) | (v >> 8);
46 *a = tmp;
47 #endif
48 }
49
50 static INLINE void StoreU32_RBO(uint32 *a, const uint32 v)
51 {
52 #ifdef ARCH_POWERPC
53 __asm__ ("stwbrx %0, %y1" : : "r"(v), "Z"(*a));
54 #else
55 uint32 tmp = (v << 24) | ((v & 0xFF00) << 8) | ((v >> 8) & 0xFF00) | (v >> 24);
56 *a = tmp;
57 #endif
58 }
59
60 static INLINE uint16 LoadU16_LE(const uint16 *a)
61 {
62 #ifdef MSB_FIRST
63 return LoadU16_RBO(a);
64 #else
65 return *a;
66 #endif
67 }
68
69 static INLINE uint32 LoadU32_LE(const uint32 *a)
70 {
71 #ifdef MSB_FIRST
72 return LoadU32_RBO(a);
73 #else
74 return *a;
75 #endif
76 }
77
78 static INLINE void StoreU16_LE(uint16 *a, const uint16 v)
79 {
80 #ifdef MSB_FIRST
81 StoreU16_RBO(a, v);
82 #else
83 *a = v;
84 #endif
85 }
86
87 static INLINE void StoreU32_LE(uint32 *a, const uint32 v)
88 {
89 #ifdef MSB_FIRST
90 StoreU32_RBO(a, v);
91 #else
92 *a = v;
93 #endif
94 }
95
96
97 // address must not be >= size specified by template parameter, and address must be a multiple of the byte-size of the
98 // unit(1,2,4) being read(except for Read/WriteU24, which only needs to be byte-aligned).
99 //
100 // max_unit_type should be uint16 or uint32
101 //
102 // pre_padding and post_padding are specified in units of sizeof(max_unit_type).
103 //
104 template<unsigned size, typename max_unit_type, bool big_endian> //, unsigned pre_padding_count, unsigned post_padding_count>
105 struct MultiAccessSizeMem
106 {
107 //max_unit_type pre_padding[pre_padding_count ? pre_padding_count : 1];
108
109 union
110 {
111 uint8 data8[size];
112 uint16 data16[size / sizeof(uint16)];
113 uint32 data32[size / sizeof(uint32)];
114 };
115
116 //max_unit_type post_padding[post_padding_count ? post_padding_count : 1];
117
118 INLINE uint8 ReadU8(uint32 address)
119 {
120 return data8[address];
121 }
122
123 INLINE uint16 ReadU16(uint32 address)
124 {
125 if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
126 return *(uint16*)(((uint8*)data16) + address);
127 else
128 return LoadU16_RBO((uint16*)(((uint8*)data16) + address));
129 }
130
131 INLINE uint32 ReadU32(uint32 address)
132 {
133 if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
134 return *(uint32*)(((uint8*)data32) + address);
135 else
136 return LoadU32_RBO((uint32*)(((uint8*)data32) + address));
137 }
138
139 INLINE uint32 ReadU24(uint32 address)
140 {
141 uint32 ret;
142
143 if(!big_endian)
144 {
145 ret = ReadU8(address) | (ReadU8(address + 1) << 8) | (ReadU8(address + 2) << 16);
146 }
147
148 return(ret);
149 }
150
151
152 INLINE void WriteU8(uint32 address, uint8 value)
153 {
154 data8[address] = value;
155 }
156
157 INLINE void WriteU16(uint32 address, uint16 value)
158 {
159 if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
160 *(uint16*)(((uint8*)data16) + address) = value;
161 else
162 StoreU16_RBO((uint16*)(((uint8*)data16) + address), value);
163 }
164
165 INLINE void WriteU32(uint32 address, uint32 value)
166 {
167 if(MAS_NATIVE_IS_BIGENDIAN == big_endian)
168 *(uint32*)(((uint8*)data32) + address) = value;
169 else
170 StoreU32_RBO((uint32*)(((uint8*)data32) + address), value);
171 }
172
173 INLINE void WriteU24(uint32 address, uint32 value)
174 {
175 if(!big_endian)
176 {
177 WriteU8(address + 0, value >> 0);
178 WriteU8(address + 1, value >> 8);
179 WriteU8(address + 2, value >> 16);
180 }
181 }
182
183 template<typename T>
184 INLINE T Read(uint32 address)
185 {
186 if(sizeof(T) == 4)
187 return(ReadU32(address));
188 else if(sizeof(T) == 2)
189 return(ReadU16(address));
190 else
191 return(ReadU8(address));
192 }
193
194 template<typename T>
195 INLINE void Write(uint32 address, T value)
196 {
197 if(sizeof(T) == 4)
198 WriteU32(address, value);
199 else if(sizeof(T) == 2)
200 WriteU16(address, value);
201 else
202 WriteU8(address, value);
203 }
204 };
205
206 #undef MAS_NATIVE_IS_BIGENDIAN
207
208 #endif
0 #ifndef __MDFN_MATH_OPS_H
1 #define __MDFN_MATH_OPS_H
2
3 // Source: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
4 // Rounds up to the nearest power of 2.
5 static INLINE uint32 round_up_pow2(uint32 v)
6 {
7 v--;
8 v |= v >> 1;
9 v |= v >> 2;
10 v |= v >> 4;
11 v |= v >> 8;
12 v |= v >> 16;
13 v++;
14
15 v += (v == 0);
16
17 return(v);
18 }
19
20 // Some compilers' optimizers and some platforms might fubar the generated code from these macros,
21 // so some tests are run in...tests.cpp
22 #define sign_8_to_s16(_value) ((int16)(int8)(_value))
23 #define sign_9_to_s16(_value) (((int16)((unsigned int)(_value) << 7)) >> 7)
24 #define sign_10_to_s16(_value) (((int16)((uint32)(_value) << 6)) >> 6)
25 #define sign_11_to_s16(_value) (((int16)((uint32)(_value) << 5)) >> 5)
26 #define sign_12_to_s16(_value) (((int16)((uint32)(_value) << 4)) >> 4)
27 #define sign_13_to_s16(_value) (((int16)((uint32)(_value) << 3)) >> 3)
28 #define sign_14_to_s16(_value) (((int16)((uint32)(_value) << 2)) >> 2)
29 #define sign_15_to_s16(_value) (((int16)((uint32)(_value) << 1)) >> 1)
30
31 // This obviously won't convert higher-than-32 bit numbers to signed 32-bit ;)
32 // Also, this shouldn't be used for 8-bit and 16-bit signed numbers, since you can
33 // convert those faster with typecasts...
34 #define sign_x_to_s32(_bits, _value) (((int32)((uint32)(_value) << (32 - _bits))) >> (32 - _bits))
35
36 #endif
0 /*
1 * RFC 1321 compliant MD5 implementation,
2 * by Christophe Devine <devine@cr0.net>;
3 * this program is licensed under the GPL.
4 */
5
6 /* Modified October 3, 2003, to remove testing code, and add
7 include of "fceu-types.h".
8
9 Added simple MD5 to ASCII string conversion function.
10 -Xodnizel
11 */
12
13 #include <string.h>
14 #include "md5.h"
15
16 #define GET_UINT32(n, b, i) \
17 { \
18 (n) = ((uint32_t)(b)[(i) + 3] << 24) | \
19 ((uint32_t)(b)[(i) + 2] << 16) | \
20 ((uint32_t)(b)[(i) + 1] << 8) | \
21 ((uint32_t)(b)[(i) ]); \
22 }
23
24 #define PUT_UINT32(n, b, i) \
25 { \
26 (b)[(i) ] = (uint8_t)((n)); \
27 (b)[(i) + 1] = (uint8_t)((n) >> 8); \
28 (b)[(i) + 2] = (uint8_t)((n) >> 16); \
29 (b)[(i) + 3] = (uint8_t)((n) >> 24); \
30 }
31
32 void md5_starts(struct md5_context *ctx)
33 {
34 ctx->total[0] = 0;
35 ctx->total[1] = 0;
36 ctx->state[0] = 0x67452301;
37 ctx->state[1] = 0xEFCDAB89;
38 ctx->state[2] = 0x98BADCFE;
39 ctx->state[3] = 0x10325476;
40 }
41
42 void md5_process(struct md5_context *ctx, uint8_t data[64])
43 {
44 uint32_t A, B, C, D, X[16];
45
46 GET_UINT32(X[0], data, 0);
47 GET_UINT32(X[1], data, 4);
48 GET_UINT32(X[2], data, 8);
49 GET_UINT32(X[3], data, 12);
50 GET_UINT32(X[4], data, 16);
51 GET_UINT32(X[5], data, 20);
52 GET_UINT32(X[6], data, 24);
53 GET_UINT32(X[7], data, 28);
54 GET_UINT32(X[8], data, 32);
55 GET_UINT32(X[9], data, 36);
56 GET_UINT32(X[10], data, 40);
57 GET_UINT32(X[11], data, 44);
58 GET_UINT32(X[12], data, 48);
59 GET_UINT32(X[13], data, 52);
60 GET_UINT32(X[14], data, 56);
61 GET_UINT32(X[15], data, 60);
62
63 #define S(x, n) ((x << n) | ((x & 0xFFFFFFFF) >> (32 - n)))
64
65 #define P(a, b, c, d, k, s, t) \
66 { \
67 a += F(b, c, d) + X[k] + t; a = S(a, s) + b; \
68 }
69
70 A = ctx->state[0];
71 B = ctx->state[1];
72 C = ctx->state[2];
73 D = ctx->state[3];
74
75 #define F(x, y, z) (z ^ (x & (y ^ z)))
76
77 P(A, B, C, D, 0, 7, 0xD76AA478);
78 P(D, A, B, C, 1, 12, 0xE8C7B756);
79 P(C, D, A, B, 2, 17, 0x242070DB);
80 P(B, C, D, A, 3, 22, 0xC1BDCEEE);
81 P(A, B, C, D, 4, 7, 0xF57C0FAF);
82 P(D, A, B, C, 5, 12, 0x4787C62A);
83 P(C, D, A, B, 6, 17, 0xA8304613);
84 P(B, C, D, A, 7, 22, 0xFD469501);
85 P(A, B, C, D, 8, 7, 0x698098D8);
86 P(D, A, B, C, 9, 12, 0x8B44F7AF);
87 P(C, D, A, B, 10, 17, 0xFFFF5BB1);
88 P(B, C, D, A, 11, 22, 0x895CD7BE);
89 P(A, B, C, D, 12, 7, 0x6B901122);
90 P(D, A, B, C, 13, 12, 0xFD987193);
91 P(C, D, A, B, 14, 17, 0xA679438E);
92 P(B, C, D, A, 15, 22, 0x49B40821);
93
94 #undef F
95
96 #define F(x, y, z) (y ^ (z & (x ^ y)))
97
98 P(A, B, C, D, 1, 5, 0xF61E2562);
99 P(D, A, B, C, 6, 9, 0xC040B340);
100 P(C, D, A, B, 11, 14, 0x265E5A51);
101 P(B, C, D, A, 0, 20, 0xE9B6C7AA);
102 P(A, B, C, D, 5, 5, 0xD62F105D);
103 P(D, A, B, C, 10, 9, 0x02441453);
104 P(C, D, A, B, 15, 14, 0xD8A1E681);
105 P(B, C, D, A, 4, 20, 0xE7D3FBC8);
106 P(A, B, C, D, 9, 5, 0x21E1CDE6);
107 P(D, A, B, C, 14, 9, 0xC33707D6);
108 P(C, D, A, B, 3, 14, 0xF4D50D87);
109 P(B, C, D, A, 8, 20, 0x455A14ED);
110 P(A, B, C, D, 13, 5, 0xA9E3E905);
111 P(D, A, B, C, 2, 9, 0xFCEFA3F8);
112 P(C, D, A, B, 7, 14, 0x676F02D9);
113 P(B, C, D, A, 12, 20, 0x8D2A4C8A);
114
115 #undef F
116
117 #define F(x, y, z) (x ^ y ^ z)
118
119 P(A, B, C, D, 5, 4, 0xFFFA3942);
120 P(D, A, B, C, 8, 11, 0x8771F681);
121 P(C, D, A, B, 11, 16, 0x6D9D6122);
122 P(B, C, D, A, 14, 23, 0xFDE5380C);
123 P(A, B, C, D, 1, 4, 0xA4BEEA44);
124 P(D, A, B, C, 4, 11, 0x4BDECFA9);
125 P(C, D, A, B, 7, 16, 0xF6BB4B60);
126 P(B, C, D, A, 10, 23, 0xBEBFBC70);
127 P(A, B, C, D, 13, 4, 0x289B7EC6);
128 P(D, A, B, C, 0, 11, 0xEAA127FA);
129 P(C, D, A, B, 3, 16, 0xD4EF3085);
130 P(B, C, D, A, 6, 23, 0x04881D05);
131 P(A, B, C, D, 9, 4, 0xD9D4D039);
132 P(D, A, B, C, 12, 11, 0xE6DB99E5);
133 P(C, D, A, B, 15, 16, 0x1FA27CF8);
134 P(B, C, D, A, 2, 23, 0xC4AC5665);
135
136 #undef F
137
138 #define F(x, y, z) (y ^ (x | ~z))
139
140 P(A, B, C, D, 0, 6, 0xF4292244);
141 P(D, A, B, C, 7, 10, 0x432AFF97);
142 P(C, D, A, B, 14, 15, 0xAB9423A7);
143 P(B, C, D, A, 5, 21, 0xFC93A039);
144 P(A, B, C, D, 12, 6, 0x655B59C3);
145 P(D, A, B, C, 3, 10, 0x8F0CCC92);
146 P(C, D, A, B, 10, 15, 0xFFEFF47D);
147 P(B, C, D, A, 1, 21, 0x85845DD1);
148 P(A, B, C, D, 8, 6, 0x6FA87E4F);
149 P(D, A, B, C, 15, 10, 0xFE2CE6E0);
150 P(C, D, A, B, 6, 15, 0xA3014314);
151 P(B, C, D, A, 13, 21, 0x4E0811A1);
152 P(A, B, C, D, 4, 6, 0xF7537E82);
153 P(D, A, B, C, 11, 10, 0xBD3AF235);
154 P(C, D, A, B, 2, 15, 0x2AD7D2BB);
155 P(B, C, D, A, 9, 21, 0xEB86D391);
156
157 #undef F
158
159 ctx->state[0] += A;
160 ctx->state[1] += B;
161 ctx->state[2] += C;
162 ctx->state[3] += D;
163 }
164
165 void md5_update(struct md5_context *ctx, uint8_t *input, uint32_t length)
166 {
167 uint32_t left, fill;
168
169 if (!length)
170 return;
171
172 left = (ctx->total[0] >> 3) & 0x3F;
173 fill = 64 - left;
174
175 ctx->total[0] += length << 3;
176 ctx->total[1] += length >> 29;
177
178 ctx->total[0] &= 0xFFFFFFFF;
179 ctx->total[1] += ctx->total[0] < (length << 3);
180
181 if (left && length >= fill)
182 {
183 memcpy((void*)(ctx->buffer + left), (void*)input, fill);
184 md5_process(ctx, ctx->buffer);
185 length -= fill;
186 input += fill;
187 left = 0;
188 }
189
190 while (length >= 64)
191 {
192 md5_process(ctx, input);
193 length -= 64;
194 input += 64;
195 }
196
197 if (length)
198 memcpy((void*)(ctx->buffer + left), (void*)input, length);
199 }
200
201 void md5_update_u32_as_lsb(struct md5_context *ctx, uint32_t input)
202 {
203 uint8_t buf[4];
204
205 buf[0] = input >> 0;
206 buf[1] = input >> 8;
207 buf[2] = input >> 16;
208 buf[3] = input >> 24;
209
210 md5_update(ctx, buf, 4);
211 }
212
213 static uint8_t md5_padding[64] =
214 {
215 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
216 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
217 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
218 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
219 };
220
221 void md5_finish(struct md5_context *ctx, uint8_t digest[16])
222 {
223 uint32_t last, padn;
224 uint8_t msglen[8];
225
226 PUT_UINT32(ctx->total[0], msglen, 0);
227 PUT_UINT32(ctx->total[1], msglen, 4);
228
229 last = (ctx->total[0] >> 3) & 0x3F;
230 padn = (last < 56) ? (56 - last) : (120 - last);
231
232 md5_update(ctx, md5_padding, padn);
233 md5_update(ctx, msglen, 8);
234
235 PUT_UINT32(ctx->state[0], digest, 0);
236 PUT_UINT32(ctx->state[1], digest, 4);
237 PUT_UINT32(ctx->state[2], digest, 8);
238 PUT_UINT32(ctx->state[3], digest, 12);
239 }
240
241
242 /* Uses a static buffer, so beware of how it's used. */
243 char *md5_asciistr(uint8_t digest[16])
244 {
245 static char str[33];
246 static char trans[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
247 int x;
248
249 for (x = 0; x < 16; x++)
250 {
251 str[x * 2] = trans[digest[x] >> 4];
252 str[x * 2 + 1] = trans[digest[x] & 0x0F];
253 }
254 return(str);
255 }
0 #ifndef _MD5_H
1 #define _MD5_H
2
3 #include <stdint.h>
4
5 #ifdef __cplusplus
6 extern "C" {
7 #endif
8
9 struct md5_context
10 {
11 uint32_t total[2];
12 uint32_t state[4];
13 uint8_t buffer[64];
14 };
15
16 void md5_starts(struct md5_context *ctx);
17 void md5_update_u32_as_lsb(struct md5_context *ctx, uint32_t input);
18 void md5_update(struct md5_context *ctx, uint8_t *input, uint32_t length);
19 void md5_finish(struct md5_context *ctx, uint8_t digest[16]);
20
21 /* Uses a static buffer, so beware of how it's used. */
22 char *md5_asciistr(uint8_t digest[16]);
23
24 #ifdef __cplusplus
25 }
26 #endif
27
28 #endif /* md5.h */
0 #ifndef __MDFN_MEDNAFEN_DRIVER_H
1 #define __MDFN_MEDNAFEN_DRIVER_H
2
3 #include <stdio.h>
4 #include <vector>
5 #include <string>
6
7 #include "settings-common.h"
8
9 extern std::vector<MDFNGI *>MDFNSystems;
10
11 MDFNGI *MDFNI_LoadCD(const char *sysname, const char *devicename);
12
13 // Call this function as early as possible, even before MDFNI_Initialize()
14 bool MDFNI_InitializeModule(void);
15
16 /* Sets the base directory(save states, snapshots, etc. are saved in directories
17 below this directory. */
18 void MDFNI_SetBaseDirectory(const char *dir);
19
20 /* Closes currently loaded game */
21 void MDFNI_CloseGame(void);
22
23 void MDFN_DispMessage(const char *format, ...);
24 #define MDFNI_DispMessage MDFN_DispMessage
25
26 uint32 MDFNI_CRC32(uint32 crc, uint8 *buf, uint32 len);
27
28 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "mednafen-endian.h"
18
19 void Endian_A16_Swap(void *src, uint32_t nelements)
20 {
21 uint32_t i;
22 uint8_t *nsrc = (uint8_t *)src;
23
24 for(i = 0; i < nelements; i++)
25 {
26 uint8_t tmp = nsrc[i * 2];
27
28 nsrc[i * 2] = nsrc[i * 2 + 1];
29 nsrc[i * 2 + 1] = tmp;
30 }
31 }
32
33 void Endian_A32_Swap(void *src, uint32_t nelements)
34 {
35 uint32_t i;
36 uint8_t *nsrc = (uint8_t *)src;
37
38 for(i = 0; i < nelements; i++)
39 {
40 uint8_t tmp1 = nsrc[i * 4];
41 uint8_t tmp2 = nsrc[i * 4 + 1];
42
43 nsrc[i * 4] = nsrc[i * 4 + 3];
44 nsrc[i * 4 + 1] = nsrc[i * 4 + 2];
45
46 nsrc[i * 4 + 2] = tmp2;
47 nsrc[i * 4 + 3] = tmp1;
48 }
49 }
50
51 void Endian_A64_Swap(void *src, uint32_t nelements)
52 {
53 uint32_t i;
54 uint8_t *nsrc = (uint8_t *)src;
55
56 for(i = 0; i < nelements; i++)
57 {
58 unsigned z;
59 uint8_t *base = &nsrc[i * 8];
60
61 for(z = 0; z < 4; z++)
62 {
63 uint8_t tmp = base[z];
64
65 base[z] = base[7 - z];
66 base[7 - z] = tmp;
67 }
68 }
69 }
70
71 void Endian_A16_NE_to_LE(void *src, uint32_t nelements)
72 {
73 #ifdef MSB_FIRST
74 Endian_A16_Swap(src, nelements);
75 #endif
76 }
77
78 void Endian_A32_NE_to_LE(void *src, uint32_t nelements)
79 {
80 #ifdef MSB_FIRST
81 Endian_A32_Swap(src, nelements);
82 #endif
83 }
84
85 void Endian_A64_NE_to_LE(void *src, uint32_t nelements)
86 {
87 #ifdef MSB_FIRST
88 Endian_A64_Swap(src, nelements);
89 #endif
90 }
91
92
93 void Endian_A16_LE_to_NE(void *src, uint32_t nelements)
94 {
95 #ifdef MSB_FIRST
96 uint32_t i;
97 uint8_t *nsrc = (uint8_t *)src;
98
99 for(i = 0; i < nelements; i++)
100 {
101 uint8_t tmp = nsrc[i * 2];
102
103 nsrc[i * 2] = nsrc[i * 2 + 1];
104 nsrc[i * 2 + 1] = tmp;
105 }
106 #endif
107 }
108
109 void Endian_A16_BE_to_NE(void *src, uint32_t nelements)
110 {
111 #ifndef MSB_FIRST
112 uint32_t i;
113 uint8_t *nsrc = (uint8_t *)src;
114
115 for(i = 0; i < nelements; i++)
116 {
117 uint8_t tmp = nsrc[i * 2];
118
119 nsrc[i * 2] = nsrc[i * 2 + 1];
120 nsrc[i * 2 + 1] = tmp;
121 }
122 #endif
123 }
124
125
126 void Endian_A32_LE_to_NE(void *src, uint32_t nelements)
127 {
128 #ifdef MSB_FIRST
129 uint32_t i;
130 uint8_t *nsrc = (uint8_t *)src;
131
132 for(i = 0; i < nelements; i++)
133 {
134 uint8_t tmp1 = nsrc[i * 4];
135 uint8_t tmp2 = nsrc[i * 4 + 1];
136
137 nsrc[i * 4] = nsrc[i * 4 + 3];
138 nsrc[i * 4 + 1] = nsrc[i * 4 + 2];
139
140 nsrc[i * 4 + 2] = tmp2;
141 nsrc[i * 4 + 3] = tmp1;
142 }
143 #endif
144 }
145
146 void Endian_A64_LE_to_NE(void *src, uint32_t nelements)
147 {
148 #ifdef MSB_FIRST
149 uint32_t i;
150 uint8_t *nsrc = (uint8_t *)src;
151
152 for(i = 0; i < nelements; i++)
153 {
154 unsigned z;
155 uint8_t *base = &nsrc[i * 8];
156
157 for(z = 0; z < 4; z++)
158 {
159 uint8_t tmp = base[z];
160
161 base[z] = base[7 - z];
162 base[7 - z] = tmp;
163 }
164 }
165 #endif
166 }
167
168 void FlipByteOrder(uint8_t *src, uint32_t count)
169 {
170 uint8_t *start=src;
171 uint8_t *end=src+count-1;
172
173 if((count&1) || !count)
174 return; /* This shouldn't happen. */
175
176 count >>= 1;
177
178 while(count--)
179 {
180 uint8_t tmp;
181
182 tmp=*end;
183 *end=*start;
184 *start=tmp;
185 end--;
186 start++;
187 }
188 }
189
190 void Endian_V_LE_to_NE(void *src, uint32_t bytesize)
191 {
192 #ifdef MSB_FIRST
193 FlipByteOrder((uint8_t *)src, bytesize);
194 #endif
195 }
196
197 void Endian_V_NE_to_LE(void *src, uint32_t bytesize)
198 {
199 #ifdef MSB_FIRST
200 FlipByteOrder((uint8_t *)src, bytesize);
201 #endif
202 }
203
204 int read32le(uint32_t *Bufo, FILE *fp)
205 {
206 uint32_t buf;
207 if(fread(&buf,1,4,fp)<4)
208 return 0;
209 #ifdef MSB_FIRST
210 *(uint32_t*)Bufo=((buf&0xFF)<<24)|((buf&0xFF00)<<8)|((buf&0xFF0000)>>8)|((buf&0xFF000000)>>24);
211 #else
212 *(uint32_t*)Bufo=buf;
213 #endif
214 return 1;
215 }
216
217 int read16le(char *d, FILE *fp)
218 {
219 #ifdef MSB_FIRST
220 int ret=fread(d+1,1,1,fp);
221 ret+=fread(d,1,1,fp);
222 return ret<2?0:2;
223 #else
224 return((fread(d,1,2,fp)<2)?0:2);
225 #endif
226 }
227
0 #ifndef __MDFN_ENDIAN_H
1 #define __MDFN_ENDIAN_H
2
3 #include <stdio.h>
4 #include <stdint.h>
5
6 #ifdef MSB_FIRST
7 #ifndef le32toh
8 #define le32toh(l) ((((l)>>24) & 0xff) | (((l)>>8) & 0xff00) \
9 | (((l)<<8) & 0xff0000) | (((l)<<24) & 0xff000000))
10 #endif
11 #ifndef le16toh
12 #define le16toh(l) ((((l)>>8) & 0xff) | (((l)<<8) & 0xff00))
13 #endif
14 #else
15 #ifndef le32toh
16 #define le32toh(l) (l)
17 #endif
18 #ifndef le16toh
19 #define le16toh(l) (l)
20 #endif
21 #endif
22
23 #ifndef htole32
24 #define htole32 le32toh
25 #endif
26
27 #ifndef htole16
28 #define htole16 le16toh
29 #endif
30
31 #ifdef __cplusplus
32 extern "C" {
33 #endif
34
35 int read32le(uint32_t *Bufo, FILE *fp);
36
37 void Endian_A16_Swap(void *src, uint32_t nelements);
38 void Endian_A32_Swap(void *src, uint32_t nelements);
39 void Endian_A64_Swap(void *src, uint32_t nelements);
40
41 void Endian_A16_NE_to_LE(void *src, uint32_t nelements);
42 void Endian_A32_NE_to_LE(void *src, uint32_t nelements);
43 void Endian_A64_NE_to_LE(void *src, uint32_t nelements);
44
45 void Endian_A16_LE_to_NE(void *src, uint32_t nelements);
46 void Endian_A16_BE_to_NE(void *src, uint32_t nelements);
47 void Endian_A32_LE_to_NE(void *src, uint32_t nelements);
48 void Endian_A64_LE_to_NE(void *src, uint32_t nelements);
49
50 void Endian_V_LE_to_NE(void *src, uint32_t bytesize);
51 void Endian_V_NE_to_LE(void *src, uint32_t bytesize);
52
53 void FlipByteOrder(uint8_t *src, uint32_t count);
54
55 // The following functions can encode/decode to unaligned addresses.
56
57 static inline void MDFN_en16lsb(uint8_t *buf, uint16_t morp)
58 {
59 buf[0]=morp;
60 buf[1]=morp>>8;
61 }
62
63 static inline void MDFN_en24lsb(uint8_t *buf, uint32_t morp)
64 {
65 buf[0]=morp;
66 buf[1]=morp>>8;
67 buf[2]=morp>>16;
68 }
69
70
71 static inline void MDFN_en32lsb(uint8_t *buf, uint32_t morp)
72 {
73 buf[0]=morp;
74 buf[1]=morp>>8;
75 buf[2]=morp>>16;
76 buf[3]=morp>>24;
77 }
78
79 static inline void MDFN_en64lsb(uint8_t *buf, uint64_t morp)
80 {
81 buf[0]=morp >> 0;
82 buf[1]=morp >> 8;
83 buf[2]=morp >> 16;
84 buf[3]=morp >> 24;
85 buf[4]=morp >> 32;
86 buf[5]=morp >> 40;
87 buf[6]=morp >> 48;
88 buf[7]=morp >> 56;
89 }
90
91
92 static inline void MDFN_en16msb(uint8_t *buf, uint16_t morp)
93 {
94 buf[0] = morp >> 8;
95 buf[1] = morp;
96 }
97
98 static inline void MDFN_en24msb(uint8_t *buf, uint32_t morp)
99 {
100 buf[0] = morp >> 16;
101 buf[1] = morp >> 8;
102 buf[2] = morp;
103 }
104
105 static inline void MDFN_en32msb(uint8_t *buf, uint32_t morp)
106 {
107 buf[0] = morp >> 24;
108 buf[1] = morp >> 16;
109 buf[2] = morp >> 8;
110 buf[3] = morp;
111 }
112
113 static inline void MDFN_en64msb(uint8_t *buf, uint64_t morp)
114 {
115 buf[0] = morp >> 56;
116 buf[1] = morp >> 48;
117 buf[2] = morp >> 40;
118 buf[3] = morp >> 32;
119 buf[4] = morp >> 24;
120 buf[5] = morp >> 16;
121 buf[6] = morp >> 8;
122 buf[7] = morp >> 0;
123 }
124
125 static inline uint16_t MDFN_de16lsb(const uint8_t *morp)
126 {
127 return(morp[0] | (morp[1] << 8));
128 }
129
130 static inline uint32_t MDFN_de24lsb(const uint8_t *morp)
131 {
132 return(morp[0]|(morp[1]<<8)|(morp[2]<<16));
133 }
134
135 static inline uint32_t MDFN_de32lsb(const uint8_t *morp)
136 {
137 return(morp[0]|(morp[1]<<8)|(morp[2]<<16)|(morp[3]<<24));
138 }
139
140 static inline uint64_t MDFN_de64lsb(const uint8_t *morp)
141 {
142 uint64_t ret = 0;
143
144 ret |= (uint64_t)morp[0];
145 ret |= (uint64_t)morp[1] << 8;
146 ret |= (uint64_t)morp[2] << 16;
147 ret |= (uint64_t)morp[3] << 24;
148 ret |= (uint64_t)morp[4] << 32;
149 ret |= (uint64_t)morp[5] << 40;
150 ret |= (uint64_t)morp[6] << 48;
151 ret |= (uint64_t)morp[7] << 56;
152
153 return(ret);
154 }
155
156 static inline uint16_t MDFN_de16msb(const uint8_t *morp)
157 {
158 return(morp[1] | (morp[0] << 8));
159 }
160
161 static inline uint32_t MDFN_de24msb(const uint8_t *morp)
162 {
163 return((morp[2]<<0)|(morp[1]<<8)|(morp[0]<<16));
164 }
165
166
167 static inline uint32_t MDFN_de32msb(const uint8_t *morp)
168 {
169 return(morp[3]|(morp[2]<<8)|(morp[1]<<16)|(morp[0]<<24));
170 }
171
172 #ifdef __cplusplus
173 }
174 #endif
175
176 #endif
0 #ifndef __MDFN_TYPES
1 #define __MDFN_TYPES
2
3 #include <assert.h>
4 #include <stdint.h>
5
6 typedef int8_t int8;
7 typedef int16_t int16;
8 typedef int32_t int32;
9 typedef int64_t int64;
10
11 typedef uint8_t uint8;
12 typedef uint16_t uint16;
13 typedef uint32_t uint32;
14 typedef uint64_t uint64;
15
16 #ifdef __GNUC__
17 #define MDFN_UNLIKELY(n) __builtin_expect((n) != 0, 0)
18 #define MDFN_LIKELY(n) __builtin_expect((n) != 0, 1)
19
20 #define INLINE inline __attribute__((always_inline))
21 #define NO_INLINE __attribute__((noinline))
22
23 #if defined(__386__) || defined(__i386__) || defined(__i386) || defined(_M_IX86) || defined(_M_I386)
24 #define MDFN_FASTCALL __attribute__((fastcall))
25 #else
26 #define MDFN_FASTCALL
27 #endif
28
29 #define MDFN_ALIGN(n) __attribute__ ((aligned (n)))
30 #define MDFN_FORMATSTR(a,b,c) __attribute__ ((format (a, b, c)));
31 #define MDFN_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
32 #define MDFN_NOWARN_UNUSED __attribute__((unused))
33
34 #elif defined(_MSC_VER)
35 #define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
36 #define INLINE inline
37 #define NO_INLINE
38 #define MDFN_LIKELY(n) ((n) != 0)
39 #define MDFN_UNLIKELY(n) ((n) != 0)
40
41 #define MDFN_FASTCALL
42
43 //#define MDFN_ALIGN(n) __declspec(align(n))
44 #define MDFN_ALIGN(n)
45
46 #define MDFN_FORMATSTR(a,b,c)
47
48 #define MDFN_WARN_UNUSED_RESULT
49 #define MDFN_NOWARN_UNUSED
50
51 #else
52 #error "Not compiling with GCC nor MSVC"
53 #define INLINE inline
54 #define NO_INLINE
55
56 #define MDFN_FASTCALL
57
58 #define MDFN_ALIGN(n)
59
60 #define MDFN_FORMATSTR(a,b,c)
61
62 #define MDFN_WARN_UNUSED_RESULT
63
64 #endif
65
66
67 typedef struct
68 {
69 union
70 {
71 struct
72 {
73 #ifdef MSB_FIRST
74 uint8 High;
75 uint8 Low;
76 #else
77 uint8 Low;
78 uint8 High;
79 #endif
80 } Union8;
81 uint16 Val16;
82 };
83 } Uuint16;
84
85 typedef struct
86 {
87 union
88 {
89 struct
90 {
91 #ifdef MSB_FIRST
92 Uuint16 High;
93 Uuint16 Low;
94 #else
95 Uuint16 Low;
96 Uuint16 High;
97 #endif
98 } Union16;
99 uint32 Val32;
100 };
101 } Uuint32;
102
103 typedef uint32 UTF32; /* at least 32 bits */
104 typedef uint16 UTF16; /* at least 16 bits */
105 typedef uint8 UTF8; /* typically 8 bits */
106 typedef unsigned char Boolean; /* 0 or 1 */
107
108 #ifndef FALSE
109 #define FALSE 0
110 #endif
111
112 #ifndef TRUE
113 #define TRUE 1
114 #endif
115
116 #define MDFN_COLD
117
118 #undef require
119 #define require( expr ) assert( expr )
120
121 #include "error.h"
122
123
124 #endif
0 #ifndef _MEDNAFEN_H
1 #define _MEDNAFEN_H
2
3 #include "mednafen-types.h"
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #define _(String) (String)
9
10 #include "math_ops.h"
11 #include "git.h"
12
13 #ifdef _WIN32
14 #define strcasecmp _stricmp
15 #endif
16
17 #define GET_FDATA_PTR(fp) (fp->data)
18 #define GET_FSIZE_PTR(fp) (fp->size)
19 #define GET_FEXTS_PTR(fp) (fp->ext)
20
21 extern MDFNGI *MDFNGameInfo;
22
23 #include "settings.h"
24
25 void MDFN_DispMessage(const char *format, ...);
26
27 void MDFN_LoadGameCheats(void *override);
28 void MDFN_FlushGameCheats(int nosave);
29
30 #include "mednafen-driver.h"
31
32 #include "mednafen-endian.h"
33
34 #endif
0 #ifndef __MDFN_MEMPATCHER_DRIVER_H
1 #define __MDFN_MEMPATCHER_DRIVER_H
2
3 struct MemoryPatch
4 {
5 MemoryPatch();
6 ~MemoryPatch();
7 std::string name;
8 std::string conditions;
9 uint32 addr;
10 uint64 val;
11 uint64 compare;
12 uint32 mltpl_count;
13 uint32 mltpl_addr_inc;
14 uint64 mltpl_val_inc;
15 uint32 copy_src_addr;
16 uint32 copy_src_addr_inc;
17 unsigned length;
18 bool bigendian;
19 bool status; // (in)active
20 unsigned icount;
21 char type; /* 'R' for replace, 'S' for substitute(GG), 'C' for substitute with compare */
22 /* 'T' for copy/transfer data, 'A' for add(variant of type R) */
23 //enum { TypeReplace, TypeSubst, TypeCompSubst };
24 //int type;
25 };
26
27 int MDFNI_DecodePAR(const char *code, uint32 *a, uint8 *v, uint8 *c, char *type);
28 int MDFNI_DecodeGG(const char *str, uint32 *a, uint8 *v, uint8 *c, char *type);
29 int MDFNI_AddCheat(const char *name, uint32 addr, uint64 val, uint64 compare, char type, unsigned int length, bool bigendian);
30 int MDFNI_DelCheat(uint32 which);
31 int MDFNI_ToggleCheat(uint32 which);
32
33 int32 MDFNI_CheatSearchGetCount(void);
34 void MDFNI_CheatSearchGetRange(uint32 first, uint32 last, int (*callb)(uint32 a, uint8 last, uint8 current));
35 void MDFNI_CheatSearchGet(int (*callb)(uint32 a, uint64 last, uint64 current, void *data), void *data);
36 void MDFNI_CheatSearchBegin(void);
37 void MDFNI_CheatSearchEnd(int type, uint64 v1, uint64 v2, unsigned int bytelen, bool bigendian);
38 void MDFNI_ListCheats(int (*callb)(char *name, uint32 a, uint64 v, uint64 compare, int s, char type, unsigned int length, bool bigendian, void *data), void *data);
39
40 int MDFNI_GetCheat(uint32 which, char **name, uint32 *a, uint64 *v, uint64 *compare, int *s, char *type, unsigned int *length, bool *bigendian);
41 int MDFNI_SetCheat(uint32 which, const char *name, uint32 a, uint64 v, uint64 compare, int s, char type, unsigned int length, bool bigendian);
42
43 void MDFNI_CheatSearchShowExcluded(void);
44 void MDFNI_CheatSearchSetCurrentAsOriginal(void);
45
46 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "mednafen.h"
18
19 #include <string.h>
20 #include <ctype.h>
21 #include "include/trio/trio.h"
22 #include <errno.h>
23 #include <vector>
24
25 #include "general.h"
26 #include "md5.h"
27 #include "mempatcher.h"
28
29 #ifdef _WIN32
30 #include "msvc_compat.h"
31 #endif
32
33 #include "../libretro.h"
34
35 extern retro_log_printf_t log_cb;
36
37 static uint8 **RAMPtrs = NULL;
38 static uint32 PageSize;
39 static uint32 NumPages;
40
41 typedef struct __CHEATF
42 {
43 char *name;
44 char *conditions;
45
46 uint32 addr;
47 uint64 val;
48 uint64 compare;
49
50 unsigned int length;
51 bool bigendian;
52 unsigned int icount; // Instance count
53 char type; /* 'R' for replace, 'S' for substitute(GG), 'C' for substitute with compare */
54 int status;
55 } CHEATF;
56
57 static std::vector<CHEATF> cheats;
58 static int savecheats;
59 static uint32 resultsbytelen = 1;
60 static bool resultsbigendian = 0;
61 static bool CheatsActive = TRUE;
62
63 bool SubCheatsOn = 0;
64 std::vector<SUBCHEAT> SubCheats[8];
65
66 static void RebuildSubCheats(void)
67 {
68 std::vector<CHEATF>::iterator chit;
69
70 SubCheatsOn = 0;
71 for(int x = 0; x < 8; x++)
72 SubCheats[x].clear();
73
74 if(!CheatsActive) return;
75
76 for(chit = cheats.begin(); chit != cheats.end(); chit++)
77 {
78 if(chit->status && chit->type != 'R')
79 {
80 for(unsigned int x = 0; x < chit->length; x++)
81 {
82 SUBCHEAT tmpsub;
83 unsigned int shiftie;
84
85 if(chit->bigendian)
86 shiftie = (chit->length - 1 - x) * 8;
87 else
88 shiftie = x * 8;
89
90 tmpsub.addr = chit->addr + x;
91 tmpsub.value = (chit->val >> shiftie) & 0xFF;
92 if(chit->type == 'C')
93 tmpsub.compare = (chit->compare >> shiftie) & 0xFF;
94 else
95 tmpsub.compare = -1;
96 SubCheats[(chit->addr + x) & 0x7].push_back(tmpsub);
97 SubCheatsOn = 1;
98 }
99 }
100 }
101 }
102
103 bool MDFNMP_Init(uint32 ps, uint32 numpages)
104 {
105 PageSize = ps;
106 NumPages = numpages;
107
108 RAMPtrs = (uint8 **)calloc(numpages, sizeof(uint8 *));
109
110 CheatsActive = MDFN_GetSettingB("cheats");
111 return(1);
112 }
113
114 void MDFNMP_Kill(void)
115 {
116 if(RAMPtrs)
117 {
118 free(RAMPtrs);
119 RAMPtrs = NULL;
120 }
121 }
122
123
124 void MDFNMP_AddRAM(uint32 size, uint32 A, uint8 *RAM)
125 {
126 uint32 AB = A / PageSize;
127
128 size /= PageSize;
129
130 for(unsigned int x = 0; x < size; x++)
131 {
132 RAMPtrs[AB + x] = RAM;
133 if(RAM) // Don't increment the RAM pointer if we're passed a NULL pointer
134 RAM += PageSize;
135 }
136 }
137
138 void MDFNMP_InstallReadPatches(void)
139 {
140 if(!CheatsActive) return;
141
142 std::vector<SUBCHEAT>::iterator chit;
143
144 for(unsigned int x = 0; x < 8; x++)
145 for(chit = SubCheats[x].begin(); chit != SubCheats[x].end(); chit++)
146 {
147 if(MDFNGameInfo->InstallReadPatch)
148 MDFNGameInfo->InstallReadPatch(chit->addr);
149 }
150 }
151
152 void MDFNMP_RemoveReadPatches(void)
153 {
154 if(MDFNGameInfo->RemoveReadPatches)
155 MDFNGameInfo->RemoveReadPatches();
156 }
157
158 /* This function doesn't allocate any memory for "name" */
159 static int AddCheatEntry(char *name, char *conditions, uint32 addr, uint64 val, uint64 compare, int status, char type, unsigned int length, bool bigendian)
160 {
161 CHEATF temp;
162
163 memset(&temp, 0, sizeof(CHEATF));
164
165 temp.name=name;
166 temp.conditions = conditions;
167 temp.addr=addr;
168 temp.val=val;
169 temp.status=status;
170 temp.compare=compare;
171 temp.length = length;
172 temp.bigendian = bigendian;
173 temp.type=type;
174
175 cheats.push_back(temp);
176 return(1);
177 }
178
179 void MDFN_LoadGameCheats(void *override_ptr)
180 {
181 RebuildSubCheats();
182 }
183
184 void MDFN_FlushGameCheats(int nosave)
185 {
186 std::vector<CHEATF>::iterator chit;
187
188 for(chit = cheats.begin(); chit != cheats.end(); chit++)
189 {
190 free(chit->name);
191 if(chit->conditions)
192 free(chit->conditions);
193 }
194 cheats.clear();
195
196 RebuildSubCheats();
197 }
198
199 int MDFNI_AddCheat(const char *name, uint32 addr, uint64 val, uint64 compare, char type, unsigned int length, bool bigendian)
200 {
201 char *t;
202
203 if(!(t = strdup(name)))
204 return(0);
205
206 if(!AddCheatEntry(t, NULL, addr,val,compare,1,type, length, bigendian))
207 {
208 free(t);
209 return(0);
210 }
211
212 savecheats = 1;
213
214 MDFNMP_RemoveReadPatches();
215 RebuildSubCheats();
216 MDFNMP_InstallReadPatches();
217
218 return(1);
219 }
220
221 int MDFNI_DelCheat(uint32 which)
222 {
223 free(cheats[which].name);
224 cheats.erase(cheats.begin() + which);
225
226 savecheats=1;
227
228 MDFNMP_RemoveReadPatches();
229 RebuildSubCheats();
230 MDFNMP_InstallReadPatches();
231
232 return(1);
233 }
234
235 /*
236 Condition format(ws = white space):
237
238 <variable size><ws><endian><ws><address><ws><operation><ws><value>
239 [,second condition...etc.]
240
241 Value should be unsigned integer, hex(with a 0x prefix) or
242 base-10.
243
244 Operations:
245 >=
246 <=
247 >
248 <
249 ==
250 !=
251 & // Result of AND between two values is nonzero
252 !& // Result of AND between two values is zero
253 ^ // same, XOR
254 !^
255 | // same, OR
256 !|
257
258 Full example:
259
260 2 L 0xADDE == 0xDEAD, 1 L 0xC000 == 0xA0
261
262 */
263
264 static bool TestConditions(const char *string)
265 {
266 char address[64];
267 char operation[64];
268 char value[64];
269 char endian;
270 unsigned int bytelen;
271 bool passed = 1;
272
273 //printf("TR: %s\n", string);
274 while(trio_sscanf(string, "%u %c %.63s %.63s %.63s", &bytelen, &endian, address, operation, value) == 5 && passed)
275 {
276 uint32 v_address;
277 uint64 v_value;
278 uint64 value_at_address;
279
280 if(address[0] == '0' && address[1] == 'x')
281 v_address = strtoul(address + 2, NULL, 16);
282 else
283 v_address = strtoul(address, NULL, 10);
284
285 if(value[0] == '0' && value[1] == 'x')
286 v_value = strtoull(value + 2, NULL, 16);
287 else
288 v_value = strtoull(value, NULL, 0);
289
290 value_at_address = 0;
291 for(unsigned int x = 0; x < bytelen; x++)
292 {
293 unsigned int shiftie;
294
295 if(endian == 'B')
296 shiftie = (bytelen - 1 - x) * 8;
297 else
298 shiftie = x * 8;
299 value_at_address |= MDFNGameInfo->MemRead(v_address + x) << shiftie;
300 }
301
302 //printf("A: %08x, V: %08llx, VA: %08llx, OP: %s\n", v_address, v_value, value_at_address, operation);
303 if(!strcmp(operation, ">="))
304 {
305 if(!(value_at_address >= v_value))
306 passed = 0;
307 }
308 else if(!strcmp(operation, "<="))
309 {
310 if(!(value_at_address <= v_value))
311 passed = 0;
312 }
313 else if(!strcmp(operation, ">"))
314 {
315 if(!(value_at_address > v_value))
316 passed = 0;
317 }
318 else if(!strcmp(operation, "<"))
319 {
320 if(!(value_at_address < v_value))
321 passed = 0;
322 }
323 else if(!strcmp(operation, "=="))
324 {
325 if(!(value_at_address == v_value))
326 passed = 0;
327 }
328 else if(!strcmp(operation, "!="))
329 {
330 if(!(value_at_address != v_value))
331 passed = 0;
332 }
333 else if(!strcmp(operation, "&"))
334 {
335 if(!(value_at_address & v_value))
336 passed = 0;
337 }
338 else if(!strcmp(operation, "!&"))
339 {
340 if(value_at_address & v_value)
341 passed = 0;
342 }
343 else if(!strcmp(operation, "^"))
344 {
345 if(!(value_at_address ^ v_value))
346 passed = 0;
347 }
348 else if(!strcmp(operation, "!^"))
349 {
350 if(value_at_address ^ v_value)
351 passed = 0;
352 }
353 else if(!strcmp(operation, "|"))
354 {
355 if(!(value_at_address | v_value))
356 passed = 0;
357 }
358 else if(!strcmp(operation, "!|"))
359 {
360 if(value_at_address | v_value)
361 passed = 0;
362 }
363 else
364 puts("Invalid operation");
365 string = strchr(string, ',');
366 if(string == NULL)
367 break;
368 else
369 string++;
370 //printf("Foo: %s\n", string);
371 }
372
373 return(passed);
374 }
375
376 void MDFNMP_ApplyPeriodicCheats(void)
377 {
378 std::vector<CHEATF>::iterator chit;
379
380 if(!CheatsActive)
381 return;
382
383 for(chit = cheats.begin(); chit != cheats.end(); chit++)
384 {
385 if(chit->status && chit->type == 'R')
386 {
387 if(!chit->conditions || TestConditions(chit->conditions))
388 for(unsigned int x = 0; x < chit->length; x++)
389 {
390 uint32 page = ((chit->addr + x) / PageSize) % NumPages;
391 if(RAMPtrs[page])
392 {
393 uint64 tmpval = chit->val;
394
395 if(chit->bigendian)
396 tmpval >>= (chit->length - 1 - x) * 8;
397 else
398 tmpval >>= x * 8;
399
400 RAMPtrs[page][(chit->addr + x) % PageSize] = tmpval;
401 }
402 }
403 }
404 }
405 }
406
407
408 void MDFNI_ListCheats(int (*callb)(char *name, uint32 a, uint64 v, uint64 compare, int s, char type, unsigned int length, bool bigendian, void *data), void *data)
409 {
410 std::vector<CHEATF>::iterator chit;
411
412 for(chit = cheats.begin(); chit != cheats.end(); chit++)
413 {
414 if(!callb(chit->name, chit->addr, chit->val, chit->compare, chit->status, chit->type, chit->length, chit->bigendian, data)) break;
415 }
416 }
417
418 int MDFNI_GetCheat(uint32 which, char **name, uint32 *a, uint64 *v, uint64 *compare, int *s, char *type, unsigned int *length, bool *bigendian)
419 {
420 CHEATF *next = &cheats[which];
421
422 if(name)
423 *name=next->name;
424 if(a)
425 *a=next->addr;
426 if(v)
427 *v=next->val;
428 if(s)
429 *s=next->status;
430 if(compare)
431 *compare=next->compare;
432 if(type)
433 *type=next->type;
434 if(length)
435 *length = next->length;
436 if(bigendian)
437 *bigendian = next->bigendian;
438 return(1);
439 }
440
441 static uint8 CharToNibble(char thechar)
442 {
443 const char lut[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
444
445 thechar = toupper(thechar);
446
447 for(int x = 0; x < 16; x++)
448 if(lut[x] == thechar)
449 return(x);
450
451 return(0xFF);
452 }
453
454 bool MDFNI_DecodeGBGG(const char *instr, uint32 *a, uint8 *v, uint8 *c, char *type)
455 {
456 char str[10];
457 int len;
458
459 for(int x = 0; x < 9; x++)
460 {
461 while(*instr && CharToNibble(*instr) == 255)
462 instr++;
463 if(!(str[x] = *instr)) break;
464 instr++;
465 }
466 str[9] = 0;
467
468 len = strlen(str);
469
470 if(len != 9 && len != 6)
471 return(0);
472
473 uint32 tmp_address;
474 uint8 tmp_value;
475 uint8 tmp_compare = 0;
476
477 tmp_address = (CharToNibble(str[5]) << 12) | (CharToNibble(str[2]) << 8) | (CharToNibble(str[3]) << 4) | (CharToNibble(str[4]) << 0);
478 tmp_address ^= 0xF000;
479 tmp_value = (CharToNibble(str[0]) << 4) | (CharToNibble(str[1]) << 0);
480
481 if(len == 9)
482 {
483 tmp_compare = (CharToNibble(str[6]) << 4) | (CharToNibble(str[8]) << 0);
484 tmp_compare = (tmp_compare >> 2) | ((tmp_compare << 6) & 0xC0);
485 tmp_compare ^= 0xBA;
486 }
487
488 *a = tmp_address;
489 *v = tmp_value;
490
491 if(len == 9)
492 {
493 *c = tmp_compare;
494 *type = 'C';
495 }
496 else
497 {
498 *c = 0;
499 *type = 'S';
500 }
501
502 return(1);
503 }
504
505 static int GGtobin(char c)
506 {
507 static char lets[16]={'A','P','Z','L','G','I','T','Y','E','O','X','U','K','S','V','N'};
508 int x;
509
510 for(x=0;x<16;x++)
511 if(lets[x] == toupper(c)) return(x);
512 return(0);
513 }
514
515 /* Returns 1 on success, 0 on failure. Sets *a,*v,*c. */
516 int MDFNI_DecodeGG(const char *str, uint32 *a, uint8 *v, uint8 *c, char *type)
517 {
518 uint16 A;
519 uint8 V,C;
520 uint8 t;
521 int s;
522
523 A=0x8000;
524 V=0;
525 C=0;
526
527 s=strlen(str);
528 if(s!=6 && s!=8) return(0);
529
530 t=GGtobin(*str++);
531 V|=(t&0x07);
532 V|=(t&0x08)<<4;
533
534 t=GGtobin(*str++);
535 V|=(t&0x07)<<4;
536 A|=(t&0x08)<<4;
537
538 t=GGtobin(*str++);
539 A|=(t&0x07)<<4;
540 //if(t&0x08) return(0); /* 8-character code?! */
541
542 t=GGtobin(*str++);
543 A|=(t&0x07)<<12;
544 A|=(t&0x08);
545
546 t=GGtobin(*str++);
547 A|=(t&0x07);
548 A|=(t&0x08)<<8;
549
550 if(s==6)
551 {
552 t=GGtobin(*str++);
553 A|=(t&0x07)<<8;
554 V|=(t&0x08);
555
556 *a=A;
557 *v=V;
558 *type = 'S';
559 *c = 0;
560 }
561 else
562 {
563 t=GGtobin(*str++);
564 A|=(t&0x07)<<8;
565 C|=(t&0x08);
566
567 t=GGtobin(*str++);
568 C|=(t&0x07);
569 C|=(t&0x08)<<4;
570
571 t=GGtobin(*str++);
572 C|=(t&0x07)<<4;
573 V|=(t&0x08);
574 *a=A;
575 *v=V;
576 *c=C;
577 *type = 'C';
578 }
579
580 return(1);
581 }
582
583 int MDFNI_DecodePAR(const char *str, uint32 *a, uint8 *v, uint8 *c, char *type)
584 {
585 int boo[4];
586 if(strlen(str)!=8) return(0);
587
588 trio_sscanf(str,"%02x%02x%02x%02x",boo,boo+1,boo+2,boo+3);
589
590 *c = 0;
591
592 if(1)
593 {
594 *a=(boo[3]<<8)|(boo[2]+0x7F);
595 *v=0;
596 }
597 else
598 {
599 *v=boo[3];
600 *a=boo[2]|(boo[1]<<8);
601 }
602
603 *type = 'S';
604 return(1);
605 }
606
607 /* name can be NULL if the name isn't going to be changed. */
608 int MDFNI_SetCheat(uint32 which, const char *name, uint32 a, uint64 v, uint64 compare, int s, char type, unsigned int length, bool bigendian)
609 {
610 CHEATF *next = &cheats[which];
611
612 if(name)
613 {
614 char *t;
615
616 if((t=(char *)realloc(next->name,strlen(name+1))))
617 {
618 next->name=t;
619 strcpy(next->name,name);
620 }
621 else
622 return(0);
623 }
624 next->addr=a;
625 next->val=v;
626 next->status=s;
627 next->compare=compare;
628 next->type=type;
629 next->length = length;
630 next->bigendian = bigendian;
631
632 RebuildSubCheats();
633 savecheats=1;
634
635 return(1);
636 }
637
638 /* Convenience function. */
639 int MDFNI_ToggleCheat(uint32 which)
640 {
641 cheats[which].status = !cheats[which].status;
642 savecheats = 1;
643 RebuildSubCheats();
644
645 return(cheats[which].status);
646 }
647
648 static void SettingChanged(const char *name)
649 {
650 MDFNMP_RemoveReadPatches();
651
652 CheatsActive = MDFN_GetSettingB("cheats");
653
654 RebuildSubCheats();
655
656 MDFNMP_InstallReadPatches();
657 }
658
659
660 MDFNSetting MDFNMP_Settings[] =
661 {
662 { "cheats", MDFNSF_NOFLAGS, "Enable cheats.", NULL, MDFNST_BOOL, "1", NULL, NULL, NULL, SettingChanged },
663 { NULL}
664 };
0 #ifndef __MDFN_MEMPATCHER_H
1 #define __MDFN_MEMPATCHER_H
2
3 #include "mempatcher-driver.h"
4 #include <vector>
5
6 typedef struct __SUBCHEAT
7 {
8 uint32 addr;
9 uint8 value;
10 int compare; // < 0 on no compare
11 } SUBCHEAT;
12
13 extern std::vector<SUBCHEAT> SubCheats[8];
14 extern bool SubCheatsOn;
15
16 bool MDFNMP_Init(uint32 ps, uint32 numpages);
17 void MDFNMP_AddRAM(uint32 size, uint32 address, uint8 *RAM);
18 void MDFNMP_Kill(void);
19
20
21 void MDFNMP_InstallReadPatches(void);
22 void MDFNMP_RemoveReadPatches(void);
23
24 void MDFNMP_ApplyPeriodicCheats(void);
25
26 extern MDFNSetting MDFNMP_Settings[];
27
28 #endif
0 /* RetroArch - A frontend for libretro.
1 * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
2 * Copyright (C) 2011-2014 - Daniel De Matteis
3 *
4 * RetroArch is free software: you can redistribute it and/or modify it under the terms
5 * of the GNU General Public License as published by the Free Software Found-
6 * ation, either version 3 of the License, or (at your option) any later version.
7 *
8 * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10 * PURPOSE. See the GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License along with RetroArch.
13 * If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 #ifndef __RARCH_MSVC_COMPAT_H
17 #define __RARCH_MSVC_COMPAT_H
18
19 #ifdef _MSC_VER
20
21 #undef UNICODE // Do not bother with UNICODE at this time.
22 #include <direct.h>
23 #include <stddef.h>
24 #include <math.h>
25
26 // Python headers defines ssize_t and sets HAVE_SSIZE_T. Cannot duplicate these efforts.
27 #ifndef HAVE_SSIZE_T
28 #if defined(_WIN64)
29 typedef __int64 ssize_t;
30 #elif defined(_WIN32)
31 typedef int ssize_t;
32 #endif
33 #endif
34
35 #define mkdir(dirname, unused) _mkdir(dirname)
36 #define snprintf _snprintf
37 #define strtoull _strtoui64
38 #undef strcasecmp
39 #define strcasecmp _stricmp
40 #undef strncasecmp
41 #define strncasecmp _strnicmp
42
43 // Disable some of the annoying warnings.
44 #pragma warning(disable : 4800)
45 #pragma warning(disable : 4805)
46 #pragma warning(disable : 4244)
47 #pragma warning(disable : 4305)
48 #pragma warning(disable : 4146)
49 #pragma warning(disable : 4267)
50 #pragma warning(disable : 4723)
51 #pragma warning(disable : 4996)
52
53 #define roundf(in) (in >= 0.0f ? floorf(in + 0.5f) : ceilf(in - 0.5f))
54
55 #ifndef PATH_MAX
56 #define PATH_MAX _MAX_PATH
57 #endif
58
59 #ifndef SIZE_MAX
60 #define SIZE_MAX _UI32_MAX
61 #endif
62
63 #endif
64 #endif
65
0 #ifndef __MDFN_FASTFIFO_H
1 #define __MDFN_FASTFIFO_H
2
3 // size should be a power of 2.
4 template<typename T, size_t size>
5 class FastFIFO
6 {
7 public:
8
9 FastFIFO()
10 {
11 memset(data, 0, sizeof(data));
12 read_pos = 0;
13 write_pos = 0;
14 in_count = 0;
15 }
16
17 INLINE ~FastFIFO()
18 {
19
20 }
21
22 INLINE void SaveStatePostLoad(void)
23 {
24 read_pos %= size;
25 write_pos %= size;
26 in_count %= (size + 1);
27 }
28
29 INLINE uint32 CanRead(void)
30 {
31 return(in_count);
32 }
33
34 INLINE uint32 CanWrite(void)
35 {
36 return(size - in_count);
37 }
38
39 INLINE T Peek(void)
40 {
41 return data[read_pos];
42 }
43
44 INLINE T Read(void)
45 {
46 T ret = data[read_pos];
47
48 read_pos = (read_pos + 1) & (size - 1);
49 in_count--;
50
51 return(ret);
52 }
53
54 INLINE void Write(const T& wr_data)
55 {
56 data[write_pos] = wr_data;
57 write_pos = (write_pos + 1) & (size - 1);
58 in_count++;
59 }
60
61 INLINE void Flush(void)
62 {
63 read_pos = 0;
64 write_pos = 0;
65 in_count = 0;
66 }
67
68 T data[size];
69 uint32 read_pos; // Read position
70 uint32 write_pos; // Write position
71 uint32 in_count; // Number of units in the FIFO
72 };
73
74
75 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 /*
18 Games to test after changing code affecting CD reading and buffering:
19 Bedlam
20 Rise 2
21
22 */
23
24 // TODO: async command counter and async command phase?
25 /*
26
27 TODO:
28 Implement missing commands.
29
30 SPU CD-DA and CD-XA streaming semantics.
31 */
32
33 /*
34 After eject(doesn't appear to occur when drive is in STOP state):
35 * Does not appear to occur in STOP state.
36 * Does not appear to occur in PAUSE state.
37 * DOES appear to occur in STANDBY state. (TODO: retest)
38
39 % Result 0: 16
40 % Result 1: 08
41 % IRQ Result: e5
42 % 19 e0
43
44 Command abortion tests(NOP tested):
45 Does not appear to occur when in STOP or PAUSE states(STOP or PAUSE command just executed).
46
47 DOES occur after a ReadTOC completes, if ReadTOC is not followed by a STOP or PAUSE. Odd.
48 */
49
50 #include "psx.h"
51 #include "cdc.h"
52 #include "spu.h"
53
54 PS_CDC::PS_CDC() : DMABuffer(4096)
55 {
56 IsPSXDisc = false;
57 Cur_CDIF = NULL;
58
59 DriveStatus = DS_STOPPED;
60 PendingCommandPhase = 0;
61
62 TOC_Clear(&toc);
63 }
64
65 PS_CDC::~PS_CDC()
66 {
67
68 }
69
70 void PS_CDC::DMForceStop(void)
71 {
72 PSRCounter = 0;
73
74 if((DriveStatus != DS_PAUSED && DriveStatus != DS_STOPPED) || PendingCommandPhase >= 2)
75 {
76 PendingCommand = 0x00;
77 PendingCommandCounter = 0;
78 PendingCommandPhase = 0;
79 }
80
81 HeaderBufValid = false;
82 DriveStatus = DS_STOPPED;
83 ClearAIP();
84 SectorPipe_Pos = SectorPipe_In = 0;
85 SectorsRead = 0;
86 }
87
88 void PS_CDC::SetDisc(bool tray_open, CDIF *cdif, const char *disc_id)
89 {
90 if(tray_open)
91 cdif = NULL;
92
93 Cur_CDIF = cdif;
94 IsPSXDisc = false;
95 memset(DiscID, 0, sizeof(DiscID));
96
97 if(!Cur_CDIF)
98 {
99 DMForceStop();
100 }
101 else
102 {
103 HeaderBufValid = false;
104 DiscStartupDelay = (int64)1000 * 33868800 / 1000;
105 DiscChanged = true;
106
107 Cur_CDIF->ReadTOC(&toc);
108
109 if(disc_id)
110 {
111 strncpy((char *)DiscID, disc_id, 4);
112 IsPSXDisc = true;
113 }
114 }
115 }
116
117 int32 PS_CDC::CalcNextEvent(void)
118 {
119 int32 next_event = SPUCounter;
120
121 if(PSRCounter > 0 && next_event > PSRCounter)
122 next_event = PSRCounter;
123
124 if(PendingCommandCounter > 0 && next_event > PendingCommandCounter)
125 next_event = PendingCommandCounter;
126
127 if(!(IRQBuffer & 0xF))
128 {
129 if(CDCReadyReceiveCounter > 0 && next_event > CDCReadyReceiveCounter)
130 next_event = CDCReadyReceiveCounter;
131 }
132
133 if(DiscStartupDelay > 0 && next_event > DiscStartupDelay)
134 next_event = DiscStartupDelay;
135
136 //fprintf(stderr, "%d %d %d %d --- %d\n", PSRCounter, PendingCommandCounter, CDCReadyReceiveCounter, DiscStartupDelay, next_event);
137
138 return(next_event);
139 }
140
141 void PS_CDC::SoftReset(void)
142 {
143 ClearAudioBuffers();
144
145 // Not sure about initial volume state
146 Pending_DecodeVolume[0][0] = 0x80;
147 Pending_DecodeVolume[0][1] = 0x00;
148 Pending_DecodeVolume[1][0] = 0x00;
149 Pending_DecodeVolume[1][1] = 0x80;
150 memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));
151
152 RegSelector = 0;
153 memset(ArgsBuf, 0, sizeof(ArgsBuf));
154 ArgsWP = ArgsRP = 0;
155
156 memset(ResultsBuffer, 0, sizeof(ResultsBuffer));
157 ResultsWP = 0;
158 ResultsRP = 0;
159 ResultsIn = 0;
160
161 CDCReadyReceiveCounter = 0;
162
163 IRQBuffer = 0;
164 IRQOutTestMask = 0;
165 RecalcIRQ();
166
167 DMABuffer.Flush();
168 SB_In = 0;
169 SectorPipe_Pos = SectorPipe_In = 0;
170 SectorsRead = 0;
171
172 memset(SubQBuf, 0, sizeof(SubQBuf));
173 memset(SubQBuf_Safe, 0, sizeof(SubQBuf_Safe));
174 SubQChecksumOK = false;
175
176 memset(HeaderBuf, 0, sizeof(HeaderBuf));
177
178
179 FilterFile = 0;
180 FilterChan = 0;
181
182 PendingCommand = 0;
183 PendingCommandPhase = 0;
184 PendingCommandCounter = 0;
185
186 Mode = 0x20;
187
188 HeaderBufValid = false;
189 DriveStatus = DS_STOPPED;
190 ClearAIP();
191 StatusAfterSeek = DS_STOPPED;
192 SeekRetryCounter = 0;
193
194 Forward = false;
195 Backward = false;
196 Muted = false;
197
198 PlayTrackMatch = 0;
199
200 PSRCounter = 0;
201
202 CurSector = 0;
203
204 ClearAIP();
205
206 SeekTarget = 0;
207
208 CommandLoc = 0;
209 CommandLoc_Dirty = true;
210
211 DiscChanged = true;
212 }
213
214 void PS_CDC::Power(void)
215 {
216 SPU->Power();
217
218 SoftReset();
219
220 DiscStartupDelay = 0;
221
222 SPUCounter = SPU->UpdateFromCDC(0);
223 lastts = 0;
224 }
225
226 int PS_CDC::StateAction(StateMem *sm, int load, int data_only)
227 {
228 SFORMAT StateRegs[] =
229 {
230 SFVAR(DiscChanged),
231 SFVAR(DiscStartupDelay),
232
233 SFARRAY16(&AudioBuffer.Samples[0][0], sizeof(AudioBuffer.Samples) / sizeof(AudioBuffer.Samples[0][0])),
234 SFVAR(AudioBuffer.Size),
235 SFVAR(AudioBuffer.Freq),
236 SFVAR(AudioBuffer.ReadPos),
237
238 SFARRAY(&Pending_DecodeVolume[0][0], 2 * 2),
239 SFARRAY(&DecodeVolume[0][0], 2 * 2),
240
241 SFARRAY16(&ADPCM_ResampBuf[0][0], sizeof(ADPCM_ResampBuf) / sizeof(ADPCM_ResampBuf[0][0])),
242 SFVAR(ADPCM_ResampCurPhase),
243 SFVAR(ADPCM_ResampCurPos),
244
245
246
247 SFVAR(RegSelector),
248 SFARRAY(ArgsBuf, 16),
249 SFVAR(ArgsWP),
250 SFVAR(ArgsRP),
251
252 SFVAR(ArgsReceiveLatch),
253 SFARRAY(ArgsReceiveBuf, 32),
254 SFVAR(ArgsReceiveIn),
255
256 SFARRAY(ResultsBuffer, 16),
257 SFVAR(ResultsIn),
258 SFVAR(ResultsWP),
259 SFVAR(ResultsRP),
260
261 //
262 //
263 //
264 SFARRAY(&DMABuffer.data[0], DMABuffer.data.size()),
265 SFVAR(DMABuffer.read_pos),
266 SFVAR(DMABuffer.write_pos),
267 SFVAR(DMABuffer.in_count),
268 //
269 //
270 //
271
272 SFARRAY(SB, sizeof(SB) / sizeof(SB[0])),
273 SFVAR(SB_In),
274
275 SFARRAY(&SectorPipe[0][0], sizeof(SectorPipe) / sizeof(SectorPipe[0][0])),
276 SFVAR(SectorPipe_Pos),
277 SFVAR(SectorPipe_In),
278
279 SFARRAY(SubQBuf, sizeof(SubQBuf) / sizeof(SubQBuf[0])),
280 SFARRAY(SubQBuf_Safe, sizeof(SubQBuf_Safe) / sizeof(SubQBuf_Safe[0])),
281
282 SFVAR(SubQChecksumOK),
283
284 SFVAR(HeaderBufValid),
285 SFARRAY(HeaderBuf, sizeof(HeaderBuf) / sizeof(HeaderBuf[0])),
286
287 SFVAR(IRQBuffer),
288 SFVAR(IRQOutTestMask),
289 SFVAR(CDCReadyReceiveCounter),
290
291 SFVAR(FilterFile),
292 SFVAR(FilterChan),
293
294 SFVAR(PendingCommand),
295 SFVAR(PendingCommandPhase),
296 SFVAR(PendingCommandCounter),
297
298 SFVAR(SPUCounter),
299
300 SFVAR(Mode),
301 SFVAR(DriveStatus),
302 SFVAR(StatusAfterSeek),
303 SFVAR(Forward),
304 SFVAR(Backward),
305 SFVAR(Muted),
306
307 SFVAR(PlayTrackMatch),
308
309 SFVAR(PSRCounter),
310
311 SFVAR(CurSector),
312 SFVAR(SectorsRead),
313
314
315 SFVAR(AsyncIRQPending),
316 SFARRAY(AsyncResultsPending, sizeof(AsyncResultsPending) / sizeof(AsyncResultsPending[0])),
317 SFVAR(AsyncResultsPendingCount),
318
319 SFVAR(SeekTarget),
320 SFVAR(SeekRetryCounter),
321
322 // FIXME: Save TOC stuff?
323 #if 0
324 CDUtility::TOC toc;
325 bool IsPSXDisc;
326 uint8 DiscID[4];
327 #endif
328 SFVAR(CommandLoc),
329 SFVAR(CommandLoc_Dirty),
330 SFARRAY16(&xa_previous[0][0], sizeof(xa_previous) / sizeof(xa_previous[0][0])),
331
332 SFVAR(xa_cur_set),
333 SFVAR(xa_cur_file),
334 SFVAR(xa_cur_chan),
335
336 SFVAR(ReportLastF),
337
338 SFEND
339 };
340
341 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "CDC");
342
343 if(load)
344 {
345 DMABuffer.SaveStatePostLoad();
346 SectorPipe_Pos %= SectorPipe_Count;
347
348 //
349 // Handle pre-0.9.37 state loading, and maliciously-constructed/corrupted save states.
350 if(!Cur_CDIF)
351 DMForceStop();
352 }
353 return(ret);
354 }
355
356 void PS_CDC::ResetTS(void)
357 {
358 lastts = 0;
359 }
360
361 void PS_CDC::RecalcIRQ(void)
362 {
363 ::IRQ_Assert(IRQ_CD, (bool)(IRQBuffer & (IRQOutTestMask & 0x1F)));
364 }
365 //static int32 doom_ts;
366 void PS_CDC::WriteIRQ(uint8 V)
367 {
368 assert(CDCReadyReceiveCounter <= 0);
369 assert(!(IRQBuffer & 0xF));
370
371 //PSX_WARNING("[CDC] ***IRQTHINGY: 0x%02x -- %u", V, doom_ts);
372
373 CDCReadyReceiveCounter = 2000; //1024;
374
375 IRQBuffer = (IRQBuffer & 0x10) | V;
376 RecalcIRQ();
377 }
378
379 void PS_CDC::BeginResults(void)
380 {
381 //if(ResultsIn)
382 // {
383 // printf("Cleared %d results. IRQBuffer=0x%02x\n", ResultsIn, IRQBuffer);
384 //}
385
386 ResultsIn = 0;
387 ResultsWP = 0;
388 ResultsRP = 0;
389
390 memset(ResultsBuffer, 0x00, sizeof(ResultsBuffer));
391 }
392
393 void PS_CDC::WriteResult(uint8 V)
394 {
395 ResultsBuffer[ResultsWP] = V;
396 ResultsWP = (ResultsWP + 1) & 0xF;
397 ResultsIn = (ResultsIn + 1) & 0x1F;
398
399 if(!ResultsIn)
400 PSX_WARNING("[CDC] Results buffer overflow!");
401 }
402
403 uint8 PS_CDC::ReadResult(void)
404 {
405 uint8 ret = ResultsBuffer[ResultsRP];
406
407 if(!ResultsIn)
408 PSX_WARNING("[CDC] Results buffer underflow!");
409
410 ResultsRP = (ResultsRP + 1) & 0xF;
411 ResultsIn = (ResultsIn - 1) & 0x1F;
412
413 return ret;
414 }
415
416 uint8 PS_CDC::MakeStatus(bool cmd_error)
417 {
418 uint8 ret = 0;
419
420 /* Are these bit positions right? */
421
422 switch (DriveStatus)
423 {
424 case DS_PLAYING:
425 ret |= 0x80;
426 break;
427 case DS_READING:
428 /* Probably will want to be careful with this HeaderBufValid
429 * versus seek/read bit business in the future as it is a bit fragile;
430 * "Gran Turismo 1"'s music is a good test case. */
431 if(HeaderBufValid)
432 {
433 ret |= 0x20;
434 break;
435 }
436 /* fall-through */
437 case DS_SEEKING:
438 case DS_SEEKING_LOGICAL:
439 ret |= 0x40;
440 break;
441 }
442
443 if(!Cur_CDIF || DiscChanged)
444 ret |= 0x10;
445
446 if(DriveStatus != DS_STOPPED)
447 ret |= 0x02;
448
449 if(cmd_error)
450 ret |= 0x01;
451
452 DiscChanged = false; // FIXME: Only do it on NOP command execution?
453
454 return(ret);
455 }
456
457 bool PS_CDC::DecodeSubQ(uint8 *subpw)
458 {
459 uint8 tmp_q[0xC];
460
461 memset(tmp_q, 0, 0xC);
462
463 for(int i = 0; i < 96; i++)
464 tmp_q[i >> 3] |= ((subpw[i] & 0x40) >> 6) << (7 - (i & 7));
465
466 if((tmp_q[0] & 0xF) == 1)
467 {
468 memcpy(SubQBuf, tmp_q, 0xC);
469 SubQChecksumOK = subq_check_checksum(tmp_q);
470
471 if(SubQChecksumOK)
472 {
473 memcpy(SubQBuf_Safe, tmp_q, 0xC);
474 return(true);
475 }
476 }
477
478 return(false);
479 }
480
481 static const int16 CDADPCMImpulse[7][25] =
482 {
483 { 0, -5, 17, -35, 70, -23, -68, 347, -839, 2062, -4681, 15367, 21472, -5882, 2810, -1352, 635, -235, 26, 43, -35, 16, -8, 2, 0, }, /* 0 */
484 { 0, -2, 10, -34, 65, -84, 52, 9, -266, 1024, -2680, 9036, 26516, -6016, 3021, -1571, 848, -365, 107, 10, -16, 17, -8, 3, -1, }, /* 1 */
485 { -2, 0, 3, -19, 60, -75, 162, -227, 306, -67, -615, 3229, 29883, -4532, 2488, -1471, 882, -424, 166, -27, 5, 6, -8, 3, -1, }, /* 2 */
486 { -1, 3, -2, -5, 31, -74, 179, -402, 689, -926, 1272, -1446, 31033, -1446, 1272, -926, 689, -402, 179, -74, 31, -5, -2, 3, -1, }, /* 3 */
487 { -1, 3, -8, 6, 5, -27, 166, -424, 882, -1471, 2488, -4532, 29883, 3229, -615, -67, 306, -227, 162, -75, 60, -19, 3, 0, -2, }, /* 4 */
488 { -1, 3, -8, 17, -16, 10, 107, -365, 848, -1571, 3021, -6016, 26516, 9036, -2680, 1024, -266, 9, 52, -84, 65, -34, 10, -2, 0, }, /* 5 */
489 { 0, 2, -8, 16, -35, 43, 26, -235, 635, -1352, 2810, -5882, 21472, 15367, -4681, 2062, -839, 347, -68, -23, 70, -35, 17, -5, 0, }, /* 6 */
490 };
491
492 void PS_CDC::ReadAudioBuffer(int32 samples[2])
493 {
494 samples[0] = AudioBuffer.Samples[0][AudioBuffer.ReadPos];
495 samples[1] = AudioBuffer.Samples[1][AudioBuffer.ReadPos];
496
497 AudioBuffer.ReadPos++;
498 }
499
500 INLINE void PS_CDC::ApplyVolume(int32 samples[2])
501 {
502 // Take care not to alter samples[] before we're done calculating the new output samples!
503 int32 left_out = ((samples[0] * DecodeVolume[0][0]) >> 7) + ((samples[1] * DecodeVolume[1][0]) >> 7);
504 int32 right_out = ((samples[0] * DecodeVolume[0][1]) >> 7) + ((samples[1] * DecodeVolume[1][1]) >> 7);
505
506 clamp(&left_out, -32768, 32767);
507 clamp(&right_out, -32768, 32767);
508
509 if(Muted)
510 {
511 left_out = 0;
512 right_out = 0;
513 }
514
515 samples[0] = left_out;
516 samples[1] = right_out;
517 }
518
519 // This function must always set samples[0] and samples[1], even if just to 0;
520 // range of samples[n] shall be restricted to -32768 through 32767.
521 void PS_CDC::GetCDAudio(int32 samples[2])
522 {
523 const unsigned freq = (AudioBuffer.ReadPos < AudioBuffer.Size) ? AudioBuffer.Freq : 0;
524
525 samples[0] = 0;
526 samples[1] = 0;
527
528 if(!freq)
529 return;
530
531 if(freq == 7 || freq == 14)
532 {
533 ReadAudioBuffer(samples);
534 if(freq == 14)
535 ReadAudioBuffer(samples);
536 }
537 else
538 {
539 int32 out_tmp[2] = { 0, 0 };
540
541 for(unsigned i = 0; i < 2; i++)
542 {
543 const int16* imp = CDADPCMImpulse[ADPCM_ResampCurPhase];
544 int16* wf = &ADPCM_ResampBuf[i][(ADPCM_ResampCurPos + 32 - 25) & 0x1F];
545
546 for(unsigned s = 0; s < 25; s++)
547 {
548 out_tmp[i] += imp[s] * wf[s];
549 }
550
551 out_tmp[i] >>= 15;
552 clamp(&out_tmp[i], -32768, 32767);
553 samples[i] = out_tmp[i];
554 }
555
556 ADPCM_ResampCurPhase += freq;
557
558 if(ADPCM_ResampCurPhase >= 7)
559 {
560 int32 raw[2] = { 0, 0 };
561
562 ADPCM_ResampCurPhase -= 7;
563 ReadAudioBuffer(raw);
564
565 for(unsigned i = 0; i < 2; i++)
566 {
567 ADPCM_ResampBuf[i][ADPCM_ResampCurPos + 0] =
568 ADPCM_ResampBuf[i][ADPCM_ResampCurPos + 32] = raw[i];
569 }
570 ADPCM_ResampCurPos = (ADPCM_ResampCurPos + 1) & 0x1F;
571 }
572 }
573
574 // Algorithmically, volume is applied after resampling for CD-XA ADPCM playback,
575 // per PS1 tests(though when "mute" is applied wasn't tested).
576 ApplyVolume(samples);
577 }
578
579
580 struct XA_Subheader
581 {
582 uint8 file;
583 uint8 channel;
584 uint8 submode;
585 uint8 coding;
586
587 uint8 file_dup;
588 uint8 channel_dup;
589 uint8 submode_dup;
590 uint8 coding_dup;
591 };
592
593 struct XA_SoundGroup
594 {
595 uint8 params[16];
596 uint8 samples[112];
597 };
598
599 #define XA_SUBMODE_EOF 0x80
600 #define XA_SUBMODE_REALTIME 0x40
601 #define XA_SUBMODE_FORM 0x20
602 #define XA_SUBMODE_TRIGGER 0x10
603 #define XA_SUBMODE_DATA 0x08
604 #define XA_SUBMODE_AUDIO 0x04
605 #define XA_SUBMODE_VIDEO 0x02
606 #define XA_SUBMODE_EOR 0x01
607
608 #define XA_CODING_EMPHASIS 0x40
609
610 //#define XA_CODING_BPS_MASK 0x30
611 //#define XA_CODING_BPS_4BIT 0x00
612 //#define XA_CODING_BPS_8BIT 0x10
613 //#define XA_CODING_SR_MASK 0x0C
614 //#define XA_CODING_SR_378 0x00
615 //#define XA_CODING_SR_
616
617 #define XA_CODING_8BIT 0x10
618 #define XA_CODING_189 0x04
619 #define XA_CODING_STEREO 0x01
620
621 // Special regression prevention test cases:
622 // Um Jammer Lammy (start doing poorly)
623 // Yarudora Series Vol.1 - Double Cast (non-FMV speech)
624
625 bool PS_CDC::XA_Test(const uint8 *sdata)
626 {
627 const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];
628
629 if(!(Mode & MODE_STRSND))
630 return false;
631
632 if(!(sh->submode & XA_SUBMODE_AUDIO))
633 return false;
634
635 if((Mode & MODE_SF) && (sh->file != FilterFile || sh->channel != FilterChan))
636 return false;
637
638 if(!xa_cur_set || (Mode & MODE_SF))
639 {
640 xa_cur_set = true;
641 xa_cur_file = sh->file;
642 xa_cur_chan = sh->channel;
643 }
644 else if(sh->file != xa_cur_file || sh->channel != xa_cur_chan)
645 return false;
646
647 if(sh->submode & XA_SUBMODE_EOF)
648 {
649 //puts("YAY");
650 xa_cur_set = false;
651 xa_cur_file = 0;
652 xa_cur_chan = 0;
653 }
654
655 return true;
656 }
657
658 void PS_CDC::ClearAudioBuffers(void)
659 {
660 memset(&AudioBuffer, 0, sizeof(AudioBuffer));
661 memset(xa_previous, 0, sizeof(xa_previous));
662
663 xa_cur_set = false;
664 xa_cur_file = 0;
665 xa_cur_chan = 0;
666
667 memset(ADPCM_ResampBuf, 0, sizeof(ADPCM_ResampBuf));
668 ADPCM_ResampCurPhase = 0;
669 ADPCM_ResampCurPos = 0;
670 }
671
672 //
673 // output should be readable at -2 and -1
674 static void DecodeXAADPCM(const uint8 *input, int16 *output, const unsigned shift, const unsigned weight)
675 {
676 // Weights copied over from SPU channel ADPCM playback code,
677 // may not be entirely the same for CD-XA ADPCM, we need to run tests.
678 static const int32 Weights[16][2] =
679 {
680 // s-1 s-2
681 { 0, 0 },
682 { 60, 0 },
683 { 115, -52 },
684 { 98, -55 },
685 { 122, -60 },
686 };
687
688 for(int i = 0; i < 28; i++)
689 {
690 int32 sample = (int16)(input[i] << 8);
691 sample >>= shift;
692
693 sample += ((output[i - 1] * Weights[weight][0]) >> 6) + ((output[i - 2] * Weights[weight][1]) >> 6);
694
695 clamp(&sample, -32768, 32767);
696 output[i] = sample;
697 }
698 }
699
700 void PS_CDC::XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab)
701 {
702 const XA_Subheader *sh = (const XA_Subheader *)&sdata[12 + 4];
703 const unsigned unit_index_shift = (sh->coding & XA_CODING_8BIT) ? 0 : 1;
704
705 ab->ReadPos = 0;
706 ab->Size = 18 * (4 << unit_index_shift) * 28;
707
708 if(sh->coding & XA_CODING_STEREO)
709 ab->Size >>= 1;
710
711 ab->Freq = (sh->coding & XA_CODING_189) ? 3 : 6;
712
713 //fprintf(stderr, "Coding: %02x %02x\n", sh->coding, sh->coding_dup);
714
715 for(unsigned group = 0; group < 18; group++)
716 {
717 const XA_SoundGroup *sg = (const XA_SoundGroup *)&sdata[12 + 4 + 8 + group * 128];
718
719 for(unsigned unit = 0; unit < (4U << unit_index_shift); unit++)
720 {
721 const uint8 param = sg->params[(unit & 3) | ((unit & 4) << 1)];
722 const uint8 param_copy = sg->params[4 | (unit & 3) | ((unit & 4) << 1)];
723 uint8 ibuffer[28];
724 int16 obuffer[2 + 28];
725
726 if(param != param_copy)
727 {
728 PSX_WARNING("[CDC] CD-XA param != param_copy --- %d %02x %02x\n", unit, param, param_copy);
729 }
730
731 for(unsigned i = 0; i < 28; i++)
732 {
733 uint8 tmp = sg->samples[i * 4 + (unit >> unit_index_shift)];
734
735 if(unit_index_shift)
736 {
737 tmp <<= (unit & 1) ? 0 : 4;
738 tmp &= 0xf0;
739 }
740
741 ibuffer[i] = tmp;
742 }
743
744 const bool ocn = (bool)(unit & 1) && (sh->coding & XA_CODING_STEREO);
745
746 obuffer[0] = xa_previous[ocn][0];
747 obuffer[1] = xa_previous[ocn][1];
748
749 DecodeXAADPCM(ibuffer, &obuffer[2], param & 0x0F, param >> 4);
750
751 xa_previous[ocn][0] = obuffer[28];
752 xa_previous[ocn][1] = obuffer[29];
753
754 if(param != param_copy)
755 memset(obuffer, 0, sizeof(obuffer));
756
757 if(sh->coding & XA_CODING_STEREO)
758 {
759 for(unsigned s = 0; s < 28; s++)
760 {
761 ab->Samples[ocn][group * (2 << unit_index_shift) * 28 + (unit >> 1) * 28 + s] = obuffer[2 + s];
762 }
763 }
764 else
765 {
766 for(unsigned s = 0; s < 28; s++)
767 {
768 ab->Samples[0][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s];
769 ab->Samples[1][group * (4 << unit_index_shift) * 28 + unit * 28 + s] = obuffer[2 + s];
770 }
771 }
772 }
773 }
774
775 #if 0
776 // Test
777 for(unsigned i = 0; i < ab->Size; i++)
778 {
779 static unsigned counter = 0;
780
781 ab->Samples[0][i] = (counter & 2) ? -0x6000 : 0x6000;
782 ab->Samples[1][i] = rand();
783 counter++;
784 }
785 #endif
786 }
787
788 void PS_CDC::ClearAIP(void)
789 {
790 AsyncResultsPendingCount = 0;
791 AsyncIRQPending = 0;
792 }
793
794 void PS_CDC::CheckAIP(void)
795 {
796 if(AsyncIRQPending && CDCReadyReceiveCounter <= 0)
797 {
798 BeginResults();
799
800 for(unsigned i = 0; i < AsyncResultsPendingCount; i++)
801 WriteResult(AsyncResultsPending[i]);
802
803 WriteIRQ(AsyncIRQPending);
804
805 ClearAIP();
806 }
807 }
808
809 void PS_CDC::SetAIP(unsigned irq, unsigned result_count, uint8 *r)
810 {
811 if(AsyncIRQPending)
812 {
813 PSX_WARNING("***WARNING*** Previous notification skipped: CurSector=%d, old_notification=0x%02x", CurSector, AsyncIRQPending);
814 }
815 ClearAIP();
816
817 AsyncResultsPendingCount = result_count;
818
819 for(unsigned i = 0; i < result_count; i++)
820 AsyncResultsPending[i] = r[i];
821
822 AsyncIRQPending = irq;
823
824 CheckAIP();
825 }
826
827 void PS_CDC::SetAIP(unsigned irq, uint8 result0)
828 {
829 uint8 tr[1] = { result0 };
830 SetAIP(irq, 1, tr);
831 }
832
833 void PS_CDC::SetAIP(unsigned irq, uint8 result0, uint8 result1)
834 {
835 uint8 tr[2] = { result0, result1 };
836 SetAIP(irq, 2, tr);
837 }
838
839
840 void PS_CDC::EnbufferizeCDDASector(const uint8 *buf)
841 {
842 CD_Audio_Buffer *ab = &AudioBuffer;
843
844 ab->Freq = 7 * ((Mode & MODE_SPEED) ? 2 : 1);
845 ab->Size = 588;
846
847 if(SubQBuf_Safe[0] & 0x40)
848 {
849 for(int i = 0; i < 588; i++)
850 {
851 ab->Samples[0][i] = 0;
852 ab->Samples[1][i] = 0;
853 }
854 }
855 else
856 {
857 for(int i = 0; i < 588; i++)
858 {
859 ab->Samples[0][i] = (int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 0]);
860 ab->Samples[1][i] = (int16)MDFN_de16lsb(&buf[i * sizeof(int16) * 2 + 2]);
861 }
862 }
863
864 ab->ReadPos = 0;
865 }
866
867 void PS_CDC::HandlePlayRead(void)
868 {
869 uint8 read_buf[2352 + 96];
870
871 //PSX_WARNING("Read sector: %d", CurSector);
872
873 if(CurSector >= ((int32)toc.tracks[100].lba + 300) && CurSector >= (75 * 60 * 75 - 150))
874 {
875 PSX_WARNING("[CDC] Read/Play position waaay too far out(%u), forcing STOP", CurSector);
876 DriveStatus = DS_STOPPED;
877 SectorPipe_Pos = SectorPipe_In = 0;
878 SectorsRead = 0;
879 return;
880 }
881
882 if(CurSector >= (int32)toc.tracks[100].lba)
883 {
884 PSX_WARNING("[CDC] In leadout area: %u", CurSector);
885 }
886
887 Cur_CDIF->ReadRawSector(read_buf, CurSector); // FIXME: error out on error.
888 DecodeSubQ(read_buf + 2352);
889
890
891 if(SubQBuf_Safe[1] == 0xAA && (DriveStatus == DS_PLAYING || (!(SubQBuf_Safe[0] & 0x40) && (Mode & MODE_CDDA))))
892 {
893 HeaderBufValid = false;
894
895 PSX_WARNING("[CDC] CD-DA leadout reached: %u", CurSector);
896
897 // Status in this end-of-disc context here should be generated after we're in the pause state.
898 DriveStatus = DS_PAUSED;
899 SectorPipe_Pos = SectorPipe_In = 0;
900 SectorsRead = 0;
901 SetAIP(CDCIRQ_DATA_END, MakeStatus());
902
903 return;
904 }
905
906 if(DriveStatus == DS_PLAYING)
907 {
908 // Note: Some game(s) start playing in the pregap of a track(so don't replace this with a simple subq index == 0 check for autopause).
909 if(PlayTrackMatch == -1 && SubQChecksumOK)
910 PlayTrackMatch = SubQBuf_Safe[0x1];
911
912 if((Mode & MODE_AUTOPAUSE) && PlayTrackMatch != -1 && SubQBuf_Safe[0x1] != PlayTrackMatch)
913 {
914 // Status needs to be taken before we're paused(IE it should still report playing).
915 SetAIP(CDCIRQ_DATA_END, MakeStatus());
916
917 DriveStatus = DS_PAUSED;
918 SectorPipe_Pos = SectorPipe_In = 0;
919 SectorsRead = 0;
920 PSRCounter = 0;
921 return;
922 }
923
924 if((Mode & MODE_REPORT) && (((SubQBuf_Safe[0x9] >> 4) != ReportLastF) || Forward || Backward) && SubQChecksumOK)
925 {
926 uint8 tr[8];
927 #if 0
928 uint16 abs_lev_max = 0;
929 bool abs_lev_chselect = SubQBuf_Safe[0x8] & 0x01;
930
931 for(int i = 0; i < 588; i++)
932 abs_lev_max = std::max<uint16>(abs_lev_max, std::min<int>(abs((int16)MDFN_de16lsb(&read_buf[i * 4 + (abs_lev_chselect * 2)])), 32767));
933 abs_lev_max |= abs_lev_chselect << 15;
934 #endif
935
936 ReportLastF = SubQBuf_Safe[0x9] >> 4;
937
938 tr[0] = MakeStatus();
939 tr[1] = SubQBuf_Safe[0x1]; // Track
940 tr[2] = SubQBuf_Safe[0x2]; // Index
941
942 if(SubQBuf_Safe[0x9] & 0x10)
943 {
944 tr[3] = SubQBuf_Safe[0x3]; // R M
945 tr[4] = SubQBuf_Safe[0x4] | 0x80; // R S
946 tr[5] = SubQBuf_Safe[0x5]; // R F
947 }
948 else
949 {
950 tr[3] = SubQBuf_Safe[0x7]; // A M
951 tr[4] = SubQBuf_Safe[0x8]; // A S
952 tr[5] = SubQBuf_Safe[0x9]; // A F
953 }
954
955 tr[6] = 0; //abs_lev_max >> 0;
956 tr[7] = 0; //abs_lev_max >> 8;
957
958 SetAIP(CDCIRQ_DATA_READY, 8, tr);
959 }
960 }
961
962 if(SectorPipe_In >= SectorPipe_Count)
963 {
964 uint8* buf = SectorPipe[SectorPipe_Pos];
965 SectorPipe_In--;
966
967 if(DriveStatus == DS_READING)
968 {
969 if(SubQBuf_Safe[0] & 0x40) //) || !(Mode & MODE_CDDA))
970 {
971 memcpy(HeaderBuf, buf + 12, 12);
972 HeaderBufValid = true;
973
974 if((Mode & MODE_STRSND) && (buf[12 + 3] == 0x2) && ((buf[12 + 6] & 0x64) == 0x64))
975 {
976 if(XA_Test(buf))
977 {
978 if(AudioBuffer.ReadPos < AudioBuffer.Size)
979 {
980 PSX_WARNING("[CDC] CD-XA ADPCM sector skipped - readpos=0x%04x, size=0x%04x", AudioBuffer.ReadPos, AudioBuffer.Size);
981 }
982 else
983 {
984 XA_ProcessSector(buf, &AudioBuffer);
985 }
986 }
987 }
988 else
989 {
990 // maybe if(!(Mode & 0x30)) too?
991 if(!(buf[12 + 6] & 0x20))
992 {
993 if(!edc_lec_check_and_correct(buf, true))
994 {
995 MDFN_DispMessage("Bad sector? - %d", CurSector);
996 }
997 }
998
999 if(!(Mode & 0x30) && (buf[12 + 6] & 0x20))
1000 PSX_WARNING("[CDC] BORK: %d", CurSector);
1001
1002 int32 offs = (Mode & 0x20) ? 0 : 12;
1003 int32 size = (Mode & 0x20) ? 2340 : 2048;
1004
1005 if(Mode & 0x10)
1006 {
1007 offs = 12;
1008 size = 2328;
1009 }
1010
1011 memcpy(SB, buf + 12 + offs, size);
1012 SB_In = size;
1013 SetAIP(CDCIRQ_DATA_READY, MakeStatus());
1014 }
1015 }
1016 }
1017
1018 if(!(SubQBuf_Safe[0] & 0x40) && ((Mode & MODE_CDDA) || DriveStatus == DS_PLAYING))
1019 {
1020 if(AudioBuffer.ReadPos < AudioBuffer.Size)
1021 {
1022 PSX_WARNING("[CDC] BUG CDDA buffer full");
1023 }
1024 else
1025 {
1026 EnbufferizeCDDASector(buf);
1027 }
1028 }
1029 }
1030
1031 memcpy(SectorPipe[SectorPipe_Pos], read_buf, 2352);
1032 SectorPipe_Pos = (SectorPipe_Pos + 1) % SectorPipe_Count;
1033 SectorPipe_In++;
1034
1035 PSRCounter += 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
1036
1037 if(DriveStatus == DS_PLAYING)
1038 {
1039 // FIXME: What's the real fast-forward and backward speed?
1040 if(Forward)
1041 CurSector += 12;
1042 else if(Backward)
1043 {
1044 CurSector -= 12;
1045
1046 if(CurSector < 0) // FIXME: How does a real PS handle this condition?
1047 CurSector = 0;
1048 }
1049 else
1050 CurSector++;
1051 }
1052 else
1053 CurSector++;
1054
1055 SectorsRead++;
1056 }
1057
1058 int32_t PS_CDC::Update(const int32_t timestamp)
1059 {
1060 int32 clocks = timestamp - lastts;
1061
1062 //doom_ts = timestamp;
1063
1064 while(clocks > 0)
1065 {
1066 int32 chunk_clocks = clocks;
1067
1068 if(PSRCounter > 0 && chunk_clocks > PSRCounter)
1069 chunk_clocks = PSRCounter;
1070
1071 if(PendingCommandCounter > 0 && chunk_clocks > PendingCommandCounter)
1072 chunk_clocks = PendingCommandCounter;
1073
1074 if(chunk_clocks > SPUCounter)
1075 chunk_clocks = SPUCounter;
1076
1077 if(DiscStartupDelay > 0)
1078 {
1079 if(chunk_clocks > DiscStartupDelay)
1080 chunk_clocks = DiscStartupDelay;
1081
1082 DiscStartupDelay -= chunk_clocks;
1083
1084 if(DiscStartupDelay <= 0)
1085 DriveStatus = DS_PAUSED; // or is it supposed to be DS_STANDBY?
1086 }
1087
1088 //MDFN_DispMessage("%02x %d -- %d %d -- %02x", IRQBuffer, CDCReadyReceiveCounter, PSRCounter, PendingCommandCounter, PendingCommand);
1089
1090 if(!(IRQBuffer & 0xF))
1091 {
1092 if(CDCReadyReceiveCounter > 0 && chunk_clocks > CDCReadyReceiveCounter)
1093 chunk_clocks = CDCReadyReceiveCounter;
1094
1095 if(CDCReadyReceiveCounter > 0)
1096 CDCReadyReceiveCounter -= chunk_clocks;
1097 }
1098
1099 CheckAIP();
1100
1101 if(PSRCounter > 0)
1102 {
1103
1104 PSRCounter -= chunk_clocks;
1105
1106 if(PSRCounter <= 0)
1107 {
1108 switch (DriveStatus)
1109 {
1110 case DS_RESETTING:
1111 SetAIP(CDCIRQ_COMPLETE, MakeStatus());
1112
1113 Muted = false; // Does it get reset here?
1114 ClearAudioBuffers();
1115
1116 SB_In = 0;
1117 SectorPipe_Pos = 0;
1118 SectorPipe_In = 0;
1119 SectorsRead = 0;
1120 Mode = 0x20; /* Confirmed (and see "This Is Football 2"). */
1121 CurSector = 0;
1122 CommandLoc = 0;
1123
1124 DriveStatus = DS_PAUSED; // or DS_STANDBY?
1125 ClearAIP();
1126 break;
1127 case DS_SEEKING:
1128 {
1129 int x;
1130 CurSector = SeekTarget;
1131
1132 // CurSector + x for "Tomb Raider"'s sake, as it relies on behavior that we can't emulate very well without a more accurate CD drive
1133 // emulation model.
1134 for(x = -1; x >= -16; x--)
1135 {
1136 uint8 pwbuf[96];
1137 Cur_CDIF->ReadRawSectorPWOnly(pwbuf, CurSector + x, false);
1138 if(DecodeSubQ(pwbuf))
1139 break;
1140 }
1141
1142 DriveStatus = StatusAfterSeek;
1143
1144 if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
1145 PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
1146 }
1147 break;
1148 case DS_SEEKING_LOGICAL:
1149 {
1150 uint8 pwbuf[96];
1151 CurSector = SeekTarget;
1152 Cur_CDIF->ReadRawSectorPWOnly(pwbuf, CurSector, false);
1153 DecodeSubQ(pwbuf);
1154
1155 if(!(Mode & MODE_CDDA) && !(SubQBuf_Safe[0] & 0x40))
1156 {
1157 if(!SeekRetryCounter)
1158 {
1159 DriveStatus = DS_STANDBY;
1160 SetAIP(CDCIRQ_DISC_ERROR, MakeStatus() | 0x04, 0x04);
1161 }
1162 else
1163 {
1164 SeekRetryCounter--;
1165 PSRCounter = 33868800 / 75;
1166 }
1167 }
1168 else
1169 {
1170 DriveStatus = StatusAfterSeek;
1171
1172 if(DriveStatus != DS_PAUSED && DriveStatus != DS_STANDBY)
1173 PSRCounter = 33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1));
1174 }
1175 }
1176 break;
1177 case DS_READING:
1178 case DS_PLAYING:
1179 HandlePlayRead();
1180 break;
1181 }
1182 }
1183 }
1184
1185 if(PendingCommandCounter > 0)
1186 {
1187 PendingCommandCounter -= chunk_clocks;
1188
1189 if(PendingCommandCounter <= 0 && CDCReadyReceiveCounter > 0)
1190 {
1191 PendingCommandCounter = CDCReadyReceiveCounter; //256;
1192 }
1193 //else if(PendingCommandCounter <= 0 && PSRCounter > 0 && PSRCounter < 2000)
1194 //{
1195 // PendingCommandCounter = PSRCounter + 1;
1196 //}
1197 else if(PendingCommandCounter <= 0)
1198 {
1199 int32 next_time = 0;
1200
1201 if(PendingCommandPhase >= 2) // Command phase 2+
1202 {
1203 BeginResults();
1204
1205 const CDC_CTEntry *command = &Commands[PendingCommand];
1206
1207 next_time = (this->*(command->func2))();
1208 }
1209 else switch (PendingCommandPhase)
1210 {
1211 case -1:
1212 if(ArgsRP != ArgsWP)
1213 {
1214 ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F];
1215 ArgsRP = (ArgsRP + 1) & 0x1F;
1216 PendingCommandPhase += 1;
1217 next_time = 1815;
1218 }
1219 else
1220 {
1221 PendingCommandPhase += 2;
1222 next_time = 8500;
1223 }
1224 break;
1225 case 0: /* Command phase 0 */
1226 if(ArgsReceiveIn < 32)
1227 ArgsReceiveBuf[ArgsReceiveIn++] = ArgsReceiveLatch;
1228
1229 if(ArgsRP != ArgsWP)
1230 {
1231 ArgsReceiveLatch = ArgsBuf[ArgsRP & 0x0F];
1232 ArgsRP = (ArgsRP + 1) & 0x1F;
1233 next_time = 1815;
1234 }
1235 else
1236 {
1237 PendingCommandPhase++;
1238 next_time = 8500;
1239 }
1240 break;
1241 default: /* Command phase 1 */
1242 {
1243 BeginResults();
1244
1245 if(PendingCommand >= 0x20 || !Commands[PendingCommand].func)
1246 {
1247 PSX_WARNING("[CDC] Unknown command: 0x%02x", PendingCommand);
1248
1249 WriteResult(MakeStatus(true));
1250 WriteResult(ERRCODE_BAD_COMMAND);
1251 WriteIRQ(CDCIRQ_DISC_ERROR);
1252 }
1253 else if(ArgsReceiveIn < Commands[PendingCommand].args_min ||
1254 ArgsReceiveIn > Commands[PendingCommand].args_max)
1255 {
1256 PSX_DBG(PSX_DBG_WARNING, "[CDC] Bad number(%d) of args(first check) for command 0x%02x", ArgsReceiveIn, PendingCommand);
1257 for(unsigned int i = 0; i < ArgsReceiveIn; i++)
1258 PSX_DBG(PSX_DBG_WARNING, " 0x%02x", ArgsReceiveBuf[i]);
1259 PSX_DBG(PSX_DBG_WARNING, "\n");
1260
1261 WriteResult(MakeStatus(true));
1262 WriteResult(ERRCODE_BAD_NUMARGS);
1263 WriteIRQ(CDCIRQ_DISC_ERROR);
1264 }
1265 else
1266 {
1267 const CDC_CTEntry *command = &Commands[PendingCommand];
1268
1269 PSX_DBG(PSX_DBG_SPARSE, "[CDC] Command: %s --- ", command->name);
1270 for(unsigned int i = 0; i < ArgsReceiveIn; i++)
1271 PSX_DBG(PSX_DBG_SPARSE, " 0x%02x", ArgsReceiveBuf[i]);
1272 PSX_DBG(PSX_DBG_SPARSE, "\n");
1273
1274 next_time = (this->*(command->func))(ArgsReceiveIn, ArgsReceiveBuf);
1275 PendingCommandPhase = 2;
1276 }
1277 ArgsReceiveIn = 0;
1278 }
1279 break;
1280 }
1281
1282 if(!next_time)
1283 PendingCommandCounter = 0;
1284 else
1285 PendingCommandCounter += next_time;
1286 }
1287 }
1288
1289 SPUCounter = SPU->UpdateFromCDC(chunk_clocks);
1290
1291 clocks -= chunk_clocks;
1292 } // end while(clocks > 0)
1293
1294 lastts = timestamp;
1295
1296 return(timestamp + CalcNextEvent());
1297 }
1298
1299 void PS_CDC::Write(const int32_t timestamp, uint32 A, uint8 V)
1300 {
1301 A &= 0x3;
1302
1303 //printf("Write: %08x %02x\n", A, V);
1304
1305 if(A == 0x00)
1306 {
1307 RegSelector = V & 0x3;
1308 }
1309 else
1310 {
1311 const unsigned reg_index = ((RegSelector & 0x3) * 3) + (A - 1);
1312
1313 Update(timestamp);
1314 //PSX_WARNING("[CDC] Write to register 0x%02x: 0x%02x @ %d --- 0x%02x 0x%02x\n", reg_index, V, timestamp, DMABuffer.CanRead(), IRQBuffer);
1315
1316 switch(reg_index)
1317 {
1318 default:
1319 PSX_WARNING("[CDC] Unknown write to register 0x%02x: 0x%02x\n", reg_index, V);
1320 break;
1321
1322 case 0x00:
1323 if(PendingCommandCounter > 0)
1324 {
1325 PSX_WARNING("[CDC] WARNING: Interrupting command 0x%02x, phase=%d, timeleft=%d with command=0x%02x", PendingCommand, PendingCommandPhase,
1326 PendingCommandCounter, V);
1327 }
1328
1329 if(IRQBuffer & 0xF)
1330 {
1331 PSX_WARNING("[CDC] Attempting to start command(0x%02x) while IRQBuffer(0x%02x) is not clear.", V, IRQBuffer);
1332 }
1333
1334 if(ResultsIn > 0)
1335 {
1336 PSX_WARNING("[CDC] Attempting to start command(0x%02x) while command results(count=%d) still in buffer.", V, ResultsIn);
1337 }
1338
1339 PendingCommandCounter = 10500 + PSX_GetRandU32(0, 3000) + 1815;
1340 PendingCommand = V;
1341 PendingCommandPhase = -1;
1342 ArgsReceiveIn = 0;
1343 break;
1344
1345 case 0x01:
1346 ArgsBuf[ArgsWP & 0xF] = V;
1347 ArgsWP = (ArgsWP + 1) & 0x1F;
1348
1349 if(!((ArgsWP - ArgsRP) & 0x0F))
1350 {
1351 PSX_WARNING("[CDC] Argument buffer overflow");
1352 }
1353 break;
1354
1355 case 0x02:
1356 if(V & 0x80)
1357 {
1358 if(!DMABuffer.CanRead())
1359 {
1360 if(!SB_In)
1361 {
1362 PSX_WARNING("[CDC] Data read begin when no data to read!");
1363
1364 DMABuffer.Write(SB, 2340);
1365
1366 while(DMABuffer.CanWrite())
1367 DMABuffer.WriteByte(0x00);
1368 }
1369 else
1370 {
1371 DMABuffer.Write(SB, SB_In);
1372 SB_In = 0;
1373 }
1374 }
1375 else
1376 {
1377 //PSX_WARNING("[CDC] Attempt to start data transfer via 0x80->1803 when %d bytes still in buffer", DMABuffer.CanRead());
1378 }
1379 }
1380 else if(V & 0x40) // Something CD-DA related(along with & 0x20 ???)?
1381 {
1382 for(unsigned i = 0; i < 4 && DMABuffer.CanRead(); i++)
1383 DMABuffer.ReadByte();
1384 }
1385 else
1386 {
1387 DMABuffer.Flush();
1388 }
1389
1390 if(V & 0x20)
1391 {
1392 PSX_WARNING("[CDC] Mystery IRQ trigger bit set.");
1393 IRQBuffer |= 0x10;
1394 RecalcIRQ();
1395 }
1396 break;
1397
1398 case 0x04:
1399 IRQOutTestMask = V;
1400 RecalcIRQ();
1401 break;
1402
1403 case 0x05:
1404 if((IRQBuffer &~ V) != IRQBuffer && ResultsIn)
1405 {
1406 // To debug icky race-condition related problems in "Psychic Detective", and to see if any games suffer from the same potential issue
1407 // (to know what to test when we emulate CPU more accurately in regards to pipeline stalls and timing, which could throw off our kludge
1408 // for this issue)
1409 PSX_WARNING("[CDC] Acknowledged IRQ(wrote 0x%02x, before_IRQBuffer=0x%02x) while %u bytes in results buffer.", V, IRQBuffer, ResultsIn);
1410 }
1411
1412 IRQBuffer &= ~V;
1413 RecalcIRQ();
1414
1415 if(V & 0x80) // Forced CD hardware reset of some kind(interface, controller, and drive?) Seems to take a while(relatively speaking) to complete.
1416 {
1417 PSX_WARNING("[CDC] Soft Reset");
1418 SoftReset();
1419 }
1420
1421 if(V & 0x40) // Does it clear more than arguments buffer? Doesn't appear to clear results buffer.
1422 ArgsWP = ArgsRP = 0;
1423 break;
1424
1425 case 0x07:
1426 Pending_DecodeVolume[0][0] = V;
1427 break;
1428
1429 case 0x08:
1430 Pending_DecodeVolume[0][1] = V;
1431 break;
1432
1433 case 0x09:
1434 Pending_DecodeVolume[1][1] = V;
1435 break;
1436
1437 case 0x0A:
1438 Pending_DecodeVolume[1][0] = V;
1439 break;
1440
1441 case 0x0B:
1442 if(V & 0x20)
1443 memcpy(DecodeVolume, Pending_DecodeVolume, sizeof(DecodeVolume));
1444 break;
1445 }
1446 PSX_SetEventNT(PSX_EVENT_CDC, timestamp + CalcNextEvent());
1447 }
1448 }
1449
1450 uint8 PS_CDC::Read(const int32_t timestamp, uint32 A)
1451 {
1452 A &= 0x03;
1453
1454 //printf("Read %08x\n", A);
1455
1456 if(A == 0x00)
1457 {
1458 uint8 ret = RegSelector & 0x3;
1459
1460 if(ArgsWP == ArgsRP)
1461 ret |= 0x08; // Args FIFO empty.
1462
1463 if(!((ArgsWP - ArgsRP) & 0x10))
1464 ret |= 0x10; // Args FIFO has room.
1465
1466 if(ResultsIn)
1467 ret |= 0x20;
1468
1469 if(DMABuffer.CanRead())
1470 ret |= 0x40;
1471
1472 if(PendingCommandCounter > 0 && PendingCommandPhase <= 1)
1473 ret |= 0x80;
1474
1475 return ret;
1476 }
1477
1478 switch(A & 0x3)
1479 {
1480 case 0x01:
1481 return ReadResult();
1482 case 0x02:
1483 //PSX_WARNING("[CDC] DMA Buffer manual read");
1484 if(DMABuffer.CanRead())
1485 return DMABuffer.ReadByte();
1486 PSX_WARNING("[CDC] CD data transfer port read, but no data present!");
1487 break;
1488 case 0x03:
1489 if(RegSelector & 0x1)
1490 return 0xE0 | IRQBuffer;
1491 return 0xFF;
1492 }
1493
1494 return 0;
1495 }
1496
1497
1498 bool PS_CDC::DMACanRead(void)
1499 {
1500 return(DMABuffer.CanRead());
1501 }
1502
1503 uint32 PS_CDC::DMARead(void)
1504 {
1505 unsigned i;
1506 uint32_t data = 0;
1507
1508 for(i = 0; i < 4; i++)
1509 {
1510 if(DMABuffer.CanRead())
1511 data |= DMABuffer.ReadByte() << (i * 8);
1512 else
1513 {
1514 PSX_WARNING("[CDC] DMA read buffer underflow!");
1515 }
1516 }
1517
1518 return data;
1519 }
1520
1521 bool PS_CDC::CommandCheckDiscPresent(void)
1522 {
1523 if(!Cur_CDIF || DiscStartupDelay > 0)
1524 {
1525 WriteResult(MakeStatus(true));
1526 WriteResult(ERRCODE_NOT_READY);
1527
1528 WriteIRQ(CDCIRQ_DISC_ERROR);
1529
1530 return(false);
1531 }
1532
1533 return(true);
1534 }
1535
1536 int32 PS_CDC::Command_Nop(const int arg_count, const uint8 *args)
1537 {
1538 WriteResult(MakeStatus());
1539 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1540
1541 return(0);
1542 }
1543
1544 int32 PS_CDC::Command_Setloc(const int arg_count, const uint8 *args)
1545 {
1546 uint8 m, s, f;
1547
1548 if((args[0] & 0x0F) > 0x09 || args[0] > 0x99 ||
1549 (args[1] & 0x0F) > 0x09 || args[1] > 0x59 ||
1550 (args[2] & 0x0F) > 0x09 || args[2] > 0x74)
1551 {
1552 WriteResult(MakeStatus(true));
1553 WriteResult(ERRCODE_BAD_ARGVAL);
1554 WriteIRQ(CDCIRQ_DISC_ERROR);
1555 return(0);
1556 }
1557
1558 m = BCD_to_U8(args[0]);
1559 s = BCD_to_U8(args[1]);
1560 f = BCD_to_U8(args[2]);
1561
1562 CommandLoc = f + 75 * s + 75 * 60 * m - 150;
1563 CommandLoc_Dirty = true;
1564
1565 WriteResult(MakeStatus());
1566 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1567
1568 return(0);
1569 }
1570
1571 int32 PS_CDC::CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused)
1572 {
1573 int32 ret = 0;
1574
1575 if(!motor_on)
1576 {
1577 initial = 0;
1578 ret += 33868800;
1579 }
1580
1581 ret += std::max<int64>((int64)abs(initial - target) * 33868800 * 1000 / (72 * 60 * 75) / 1000, 20000);
1582
1583 if(abs(initial - target) >= 2250)
1584 ret += (int64)33868800 * 300 / 1000;
1585 else if(paused)
1586 {
1587 // The delay to restart from a Pause state is...very....WEIRD. The time it takes is related to the amount of time that has passed since the pause, and
1588 // where on the disc the laser head is, with generally more time passed = longer to resume, except that there's a window of time where it takes a
1589 // ridiculous amount of time when not much time has passed.
1590 //
1591 // What we have here will be EXTREMELY simplified.
1592
1593 //
1594 //
1595
1596 //if(time_passed >= 67737)
1597 //{
1598 //}
1599 //else
1600 {
1601 // Take twice as long for 1x mode.
1602 ret += 1237952 * ((Mode & MODE_SPEED) ? 1 : 2);
1603 }
1604 }
1605 //else if(target < initial)
1606 // ret += 1000000;
1607
1608 ret += PSX_GetRandU32(0, 25000);
1609
1610 PSX_DBG(PSX_DBG_SPARSE, "[CDC] CalcSeekTime() %d->%d = %d\n", initial, target, ret);
1611
1612 return(ret);
1613 }
1614
1615 // Remove this function when we have better seek emulation; it's here because the Rockman complete works games(at least 2 and 4) apparently have finicky fubared CD
1616 // access code.
1617 void PS_CDC::PreSeekHack(uint32 target)
1618 {
1619 uint8 pwbuf[96];
1620 int max_try = 32;
1621
1622 CurSector = target; // If removing/changing this, take into account how it will affect ReadN/ReadS/Play/etc command calls that interrupt a seek.
1623 SeekRetryCounter = 128;
1624
1625 // If removing this SubQ reading bit, think about how it will interact with a Read command of data(or audio :b) sectors when Mode bit0 is 1.
1626 do
1627 {
1628 Cur_CDIF->ReadRawSectorPWOnly(pwbuf, target++, true);
1629 } while (!DecodeSubQ(pwbuf) && --max_try > 0);
1630 }
1631
1632 /*
1633 Play command with a track argument that's not a valid BCD quantity causes interesting half-buggy behavior on an actual PS1(unlike some of the other commands,
1634 an error doesn't seem to be generated for a bad BCD argument).
1635 */
1636 int32 PS_CDC::Command_Play(const int arg_count, const uint8 *args)
1637 {
1638 if(!CommandCheckDiscPresent())
1639 return(0);
1640
1641 ClearAIP();
1642
1643 WriteResult(MakeStatus());
1644 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1645
1646 Forward = Backward = false;
1647
1648 if(arg_count && args[0])
1649 {
1650 int track = BCD_to_U8(args[0]);
1651
1652 if(track < toc.first_track)
1653 {
1654 PSX_WARNING("[CDC] Attempt to play track before first track.");
1655 track = toc.first_track;
1656 }
1657 else if(track > toc.last_track)
1658 {
1659 PSX_WARNING("[CDC] Attempt to play track after last track.");
1660 track = toc.last_track;
1661 }
1662
1663 ClearAudioBuffers();
1664 SectorPipe_Pos = SectorPipe_In = 0;
1665 SectorsRead = 0;
1666
1667 PlayTrackMatch = track;
1668
1669 PSX_WARNING("[CDC] Play track: %d", track);
1670
1671 SeekTarget = toc.tracks[track].lba;
1672 PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
1673 HeaderBufValid = false;
1674 PreSeekHack(SeekTarget);
1675
1676 ReportLastF = 0xFF;
1677
1678 DriveStatus = DS_SEEKING;
1679 StatusAfterSeek = DS_PLAYING;
1680 }
1681 else if(CommandLoc_Dirty || DriveStatus != DS_PLAYING)
1682 {
1683 ClearAudioBuffers();
1684 SectorPipe_Pos = SectorPipe_In = 0;
1685 SectorsRead = 0;
1686
1687 if(CommandLoc_Dirty)
1688 SeekTarget = CommandLoc;
1689 else
1690 SeekTarget = CurSector;
1691
1692 PlayTrackMatch = -1;
1693
1694 PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
1695 HeaderBufValid = false;
1696 PreSeekHack(SeekTarget);
1697
1698 ReportLastF = 0xFF;
1699
1700 DriveStatus = DS_SEEKING;
1701 StatusAfterSeek = DS_PLAYING;
1702 }
1703
1704 CommandLoc_Dirty = false;
1705 return(0);
1706 }
1707
1708 int32 PS_CDC::Command_Forward(const int arg_count, const uint8 *args)
1709 {
1710 if(!CommandCheckDiscPresent())
1711 return(0);
1712
1713 WriteResult(MakeStatus());
1714 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1715
1716 Backward = false;
1717 Forward = true;
1718
1719 return(0);
1720 }
1721
1722 int32 PS_CDC::Command_Backward(const int arg_count, const uint8 *args)
1723 {
1724 if(!CommandCheckDiscPresent())
1725 return(0);
1726
1727 WriteResult(MakeStatus());
1728 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1729
1730 Backward = true;
1731 Forward = false;
1732
1733 return(0);
1734 }
1735
1736
1737 void PS_CDC::ReadBase(void)
1738 {
1739 if(!CommandCheckDiscPresent())
1740 return;
1741
1742 if(!IsPSXDisc)
1743 {
1744 WriteResult(MakeStatus(true));
1745 WriteResult(ERRCODE_BAD_COMMAND);
1746
1747 WriteIRQ(CDCIRQ_DISC_ERROR);
1748 return;
1749 }
1750
1751 WriteResult(MakeStatus());
1752 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1753
1754 if(DriveStatus == DS_SEEKING_LOGICAL && SeekTarget == CommandLoc && StatusAfterSeek == DS_READING)
1755 {
1756 CommandLoc_Dirty = false;
1757 return;
1758 }
1759
1760 if(CommandLoc_Dirty || DriveStatus != DS_READING)
1761 {
1762 // Don't flush the DMABuffer here; see CTR course selection screen.
1763 ClearAIP();
1764 ClearAudioBuffers();
1765 SB_In = 0;
1766 SectorPipe_Pos = SectorPipe_In = 0;
1767 SectorsRead = 0;
1768
1769 // TODO: separate motor start from seek phase?
1770
1771 if(CommandLoc_Dirty)
1772 SeekTarget = CommandLoc;
1773 else
1774 SeekTarget = CurSector;
1775
1776 PSRCounter = /*903168 * 1.5 +*/ CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
1777 HeaderBufValid = false;
1778 PreSeekHack(SeekTarget);
1779
1780 DriveStatus = DS_SEEKING_LOGICAL;
1781 StatusAfterSeek = DS_READING;
1782 }
1783
1784 CommandLoc_Dirty = false;
1785 }
1786
1787 int32 PS_CDC::Command_ReadN(const int arg_count, const uint8 *args)
1788 {
1789 ReadBase();
1790 return 0;
1791 }
1792
1793 int32 PS_CDC::Command_ReadS(const int arg_count, const uint8 *args)
1794 {
1795 ReadBase();
1796 return 0;
1797 }
1798
1799 int32 PS_CDC::Command_Stop(const int arg_count, const uint8 *args)
1800 {
1801 if(!CommandCheckDiscPresent())
1802 return(0);
1803
1804 WriteResult(MakeStatus());
1805 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1806
1807 if(DriveStatus == DS_STOPPED)
1808 return(5000);
1809
1810 ClearAudioBuffers();
1811 ClearAIP();
1812 SectorPipe_Pos = SectorPipe_In = 0;
1813 SectorsRead = 0;
1814
1815 DriveStatus = DS_STOPPED;
1816 HeaderBufValid = false;
1817
1818 return(33868); // FIXME, should be much higher.
1819 }
1820
1821 int32 PS_CDC::Command_Stop_Part2(void)
1822 {
1823 PSRCounter = 0;
1824
1825 WriteResult(MakeStatus());
1826 WriteIRQ(CDCIRQ_COMPLETE);
1827
1828 return(0);
1829 }
1830
1831 int32 PS_CDC::Command_Standby(const int arg_count, const uint8 *args)
1832 {
1833 if(!CommandCheckDiscPresent())
1834 return(0);
1835
1836 if(DriveStatus != DS_STOPPED)
1837 {
1838 WriteResult(MakeStatus(true));
1839 WriteResult(0x20);
1840 WriteIRQ(CDCIRQ_DISC_ERROR);
1841 return(0);
1842 }
1843
1844 WriteResult(MakeStatus());
1845 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1846
1847 ClearAudioBuffers();
1848 ClearAIP();
1849 SectorPipe_Pos = SectorPipe_In = 0;
1850 SectorsRead = 0;
1851
1852 DriveStatus = DS_STANDBY;
1853
1854 return((int64)33868800 * 100 / 1000); // No idea, FIXME.
1855 }
1856
1857 int32 PS_CDC::Command_Standby_Part2(void)
1858 {
1859 PSRCounter = 0;
1860
1861 WriteResult(MakeStatus());
1862 WriteIRQ(CDCIRQ_COMPLETE);
1863
1864 return(0);
1865 }
1866
1867 int32 PS_CDC::Command_Pause(const int arg_count, const uint8 *args)
1868 {
1869 if(!CommandCheckDiscPresent())
1870 return(0);
1871
1872 WriteResult(MakeStatus());
1873 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1874
1875 if(DriveStatus == DS_PAUSED || DriveStatus == DS_STOPPED)
1876 return(5000);
1877
1878 CurSector -= std::min<uint32>(4, SectorsRead); // See: Bedlam, Rise 2
1879 SectorsRead = 0;
1880
1881 // "Viewpoint" flips out and crashes if reading isn't stopped (almost?) immediately.
1882 //ClearAudioBuffers();
1883 SectorPipe_Pos = SectorPipe_In = 0;
1884 ClearAIP();
1885 DriveStatus = DS_PAUSED;
1886
1887 // An approximation.
1888 return((1124584 + ((int64)CurSector * 42596 / (75 * 60))) * ((Mode & MODE_SPEED) ? 1 : 2));
1889 }
1890
1891 int32 PS_CDC::Command_Pause_Part2(void)
1892 {
1893 PSRCounter = 0;
1894
1895 WriteResult(MakeStatus());
1896 WriteIRQ(CDCIRQ_COMPLETE);
1897
1898 return(0);
1899 }
1900
1901 int32 PS_CDC::Command_Reset(const int arg_count, const uint8 *args)
1902 {
1903 WriteResult(MakeStatus());
1904 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1905
1906 if(DriveStatus != DS_RESETTING)
1907 {
1908 HeaderBufValid = false;
1909 DriveStatus = DS_RESETTING;
1910 PSRCounter = 1136000;
1911 }
1912
1913 return(0);
1914 }
1915
1916 int32 PS_CDC::Command_Mute(const int arg_count, const uint8 *args)
1917 {
1918 Muted = true;
1919
1920 WriteResult(MakeStatus());
1921 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1922
1923 return(0);
1924 }
1925
1926 int32 PS_CDC::Command_Demute(const int arg_count, const uint8 *args)
1927 {
1928 Muted = false;
1929
1930 WriteResult(MakeStatus());
1931 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1932
1933 return(0);
1934 }
1935
1936 int32 PS_CDC::Command_Setfilter(const int arg_count, const uint8 *args)
1937 {
1938 FilterFile = args[0];
1939 FilterChan = args[1];
1940
1941 //PSX_WARNING("[CDC] Setfilter: %02x %02x", args[0], args[1]);
1942
1943 WriteResult(MakeStatus());
1944 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1945
1946 return(0);
1947 }
1948
1949 int32 PS_CDC::Command_Setmode(const int arg_count, const uint8 *args)
1950 {
1951 Mode = args[0];
1952
1953 WriteResult(MakeStatus());
1954 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1955
1956 return(0);
1957 }
1958
1959 int32 PS_CDC::Command_Getparam(const int arg_count, const uint8 *args)
1960 {
1961 WriteResult(MakeStatus());
1962 WriteResult(Mode);
1963 WriteResult(0x00);
1964 WriteResult(FilterFile);
1965 WriteResult(FilterChan);
1966
1967 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1968
1969
1970 return(0);
1971 }
1972
1973 int32 PS_CDC::Command_GetlocL(const int arg_count, const uint8 *args)
1974 {
1975 if(!CommandCheckDiscPresent())
1976 return(0);
1977
1978 if(!HeaderBufValid)
1979 {
1980 WriteResult(MakeStatus(true));
1981 WriteResult(0x80);
1982 WriteIRQ(CDCIRQ_DISC_ERROR);
1983 return(0);
1984 }
1985
1986 for(unsigned i = 0; i < 8; i++)
1987 {
1988 //printf("%d %d: %02x\n", DriveStatus, i, HeaderBuf[i]);
1989 WriteResult(HeaderBuf[i]);
1990 }
1991
1992 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
1993
1994 return(0);
1995 }
1996
1997 int32 PS_CDC::Command_GetlocP(const int arg_count, const uint8 *args)
1998 {
1999 if(!CommandCheckDiscPresent())
2000 return(0);
2001
2002 //printf("%2x:%2x %2x:%2x:%2x %2x:%2x:%2x\n", SubQBuf_Safe[0x1], SubQBuf_Safe[0x2], SubQBuf_Safe[0x3], SubQBuf_Safe[0x4], SubQBuf_Safe[0x5], SubQBuf_Safe[0x7], SubQBuf_Safe[0x8], SubQBuf_Safe[0x9]);
2003
2004 WriteResult(SubQBuf_Safe[0x1]); // Track
2005 WriteResult(SubQBuf_Safe[0x2]); // Index
2006 WriteResult(SubQBuf_Safe[0x3]); // R M
2007 WriteResult(SubQBuf_Safe[0x4]); // R S
2008 WriteResult(SubQBuf_Safe[0x5]); // R F
2009 WriteResult(SubQBuf_Safe[0x7]); // A M
2010 WriteResult(SubQBuf_Safe[0x8]); // A S
2011 WriteResult(SubQBuf_Safe[0x9]); // A F
2012
2013 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2014
2015 return(0);
2016 }
2017
2018 int32 PS_CDC::Command_ReadT(const int arg_count, const uint8 *args)
2019 {
2020 WriteResult(MakeStatus());
2021 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2022
2023 return(44100 * 768 / 1000);
2024 }
2025
2026 int32 PS_CDC::Command_ReadT_Part2(void)
2027 {
2028 WriteResult(MakeStatus());
2029 WriteIRQ(CDCIRQ_COMPLETE);
2030
2031 return(0);
2032 }
2033
2034 int32 PS_CDC::Command_GetTN(const int arg_count, const uint8 *args)
2035 {
2036 if(!CommandCheckDiscPresent())
2037 return(0);
2038
2039 WriteResult(MakeStatus());
2040 WriteResult(U8_to_BCD(toc.first_track));
2041 WriteResult(U8_to_BCD(toc.last_track));
2042
2043 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2044
2045 return(0);
2046 }
2047
2048 int32 PS_CDC::Command_GetTD(const int arg_count, const uint8 *args)
2049 {
2050 if(!CommandCheckDiscPresent())
2051 return(0);
2052
2053 int track;
2054 uint8 m, s, f;
2055
2056 if(!args[0])
2057 track = 100;
2058 else
2059 {
2060 track= BCD_to_U8(args[0]);
2061
2062 if(!BCD_is_valid(args[0]) || track < toc.first_track || track > toc.last_track) // Error
2063 {
2064 WriteResult(MakeStatus(true));
2065 WriteResult(ERRCODE_BAD_ARGVAL);
2066 WriteIRQ(CDCIRQ_DISC_ERROR);
2067 return(0);
2068 }
2069 }
2070
2071 LBA_to_AMSF(toc.tracks[track].lba, &m, &s, &f);
2072
2073 WriteResult(MakeStatus());
2074 WriteResult(U8_to_BCD(m));
2075 WriteResult(U8_to_BCD(s));
2076 //WriteResult(U8_to_BCD(f));
2077
2078 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2079
2080 return(0);
2081 }
2082
2083 int32 PS_CDC::Command_SeekL(const int arg_count, const uint8 *args)
2084 {
2085 if(!CommandCheckDiscPresent())
2086 return(0);
2087
2088 WriteResult(MakeStatus());
2089 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2090
2091 SeekTarget = CommandLoc;
2092
2093 PSRCounter = (33868800 / (75 * ((Mode & MODE_SPEED) ? 2 : 1))) + CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
2094 HeaderBufValid = false;
2095 PreSeekHack(SeekTarget);
2096 DriveStatus = DS_SEEKING_LOGICAL;
2097 StatusAfterSeek = DS_STANDBY;
2098 ClearAIP();
2099
2100 return(PSRCounter);
2101 }
2102
2103 int32 PS_CDC::Command_SeekP(const int arg_count, const uint8 *args)
2104 {
2105 if(!CommandCheckDiscPresent())
2106 return(0);
2107
2108 WriteResult(MakeStatus());
2109 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2110
2111 SeekTarget = CommandLoc;
2112
2113 PSRCounter = CalcSeekTime(CurSector, SeekTarget, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
2114 HeaderBufValid = false;
2115 PreSeekHack(SeekTarget);
2116 DriveStatus = DS_SEEKING;
2117 StatusAfterSeek = DS_STANDBY;
2118 ClearAIP();
2119
2120 return(PSRCounter);
2121 }
2122
2123 int32 PS_CDC::Command_Seek_PartN(void)
2124 {
2125 if(DriveStatus == DS_STANDBY)
2126 {
2127 BeginResults();
2128 WriteResult(MakeStatus());
2129 WriteIRQ(CDCIRQ_COMPLETE);
2130
2131 return(0);
2132 }
2133
2134 return(std::max<int32>(PSRCounter, 256));
2135 }
2136
2137 int32 PS_CDC::Command_Test(const int arg_count, const uint8 *args)
2138 {
2139 //PSX_WARNING("[CDC] Test command sub-operation: 0x%02x", args[0]);
2140
2141 if ((args[0] >= 0x00 && args[0] <= 0x03) || (args[0] >= 0x10 && args[0] <= 0x1A))
2142 {
2143 PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2144 WriteResult(MakeStatus());
2145 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2146 }
2147 else switch(args[0])
2148 {
2149 default:
2150 PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2151 WriteResult(MakeStatus(true));
2152 WriteResult(0x10);
2153 WriteIRQ(CDCIRQ_DISC_ERROR);
2154 break;
2155 #if 0
2156 case 0x50: // *Need to retest this test command, it takes additional arguments??? Or in any case, it generates a different error code(0x20) than most other Test
2157 // sub-commands that generate an error code(0x10).
2158 break;
2159
2160 // Same with 0x60, 0x71-0x76
2161
2162 #endif
2163
2164 case 0x51: // *Need to retest this test command
2165 PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2166 WriteResult(0x01);
2167 WriteResult(0x00);
2168 WriteResult(0x00);
2169 break;
2170
2171 case 0x75: // *Need to retest this test command
2172 PSX_WARNING("[CDC] Unknown Test command sub-operation: 0x%02x", args[0]);
2173 WriteResult(0x00);
2174 WriteResult(0xC0);
2175 WriteResult(0x00);
2176 WriteResult(0x00);
2177 break;
2178
2179 //
2180 // SCEx counters not reset by command 0x0A.
2181 //
2182
2183 case 0x04: // Reset SCEx counters
2184 WriteResult(MakeStatus());
2185 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2186 break;
2187
2188 case 0x05: // Read SCEx counters
2189 WriteResult(0x00); // Number of TOC/leadin reads? (apparently increases by 1 or 2 per ReadTOC, even on non-PSX music CD)
2190 WriteResult(0x00); // Number of SCEx strings received? (Stays at zero on music CD)
2191 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2192 break;
2193
2194 case 0x20:
2195 WriteResult(0x97);
2196 WriteResult(0x01);
2197 WriteResult(0x10);
2198 WriteResult(0xC2);
2199
2200 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2201 break;
2202
2203 case 0x21: // *Need to retest this test command.
2204 WriteResult(0x01);
2205 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2206 break;
2207
2208 case 0x22:
2209 {
2210 static const uint8 td[7] = { 0x66, 0x6f, 0x72, 0x20, 0x55, 0x2f, 0x43 };
2211
2212 for(unsigned i = 0; i < 7; i++)
2213 WriteResult(td[i]);
2214
2215 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2216 }
2217 break;
2218
2219 case 0x23:
2220 case 0x24:
2221 {
2222 static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x32, 0x35, 0x34, 0x35, 0x51 };
2223
2224 for(unsigned i = 0; i < 8; i++)
2225 WriteResult(td[i]);
2226
2227 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2228 }
2229 break;
2230
2231 case 0x25:
2232 {
2233 static const uint8 td[8] = { 0x43, 0x58, 0x44, 0x31, 0x38, 0x31, 0x35, 0x51 };
2234
2235 for(unsigned i = 0; i < 8; i++)
2236 WriteResult(td[i]);
2237
2238 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2239 }
2240 break;
2241 }
2242 return(0);
2243 }
2244
2245 int32 PS_CDC::Command_ID(const int arg_count, const uint8 *args)
2246 {
2247 if(!CommandCheckDiscPresent())
2248 return(0);
2249
2250 WriteResult(MakeStatus());
2251 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2252
2253 return(33868);
2254 }
2255
2256 int32 PS_CDC::Command_ID_Part2(void)
2257 {
2258 if(IsPSXDisc)
2259 {
2260 WriteResult(MakeStatus());
2261 WriteResult(0x00);
2262 WriteResult(0x20);
2263 WriteResult(0x00);
2264 }
2265 else
2266 {
2267 WriteResult(MakeStatus() | 0x08);
2268 WriteResult(0x90);
2269 WriteResult(toc.disc_type);
2270 WriteResult(0x00);
2271 }
2272
2273 if(IsPSXDisc)
2274 {
2275 WriteResult(DiscID[0]);
2276 WriteResult(DiscID[1]);
2277 WriteResult(DiscID[2]);
2278 WriteResult(DiscID[3]);
2279 }
2280 else
2281 {
2282 WriteResult(0xff);
2283 WriteResult(0);
2284 WriteResult(0);
2285 WriteResult(0);
2286 }
2287
2288 if(IsPSXDisc)
2289 WriteIRQ(CDCIRQ_COMPLETE);
2290 else
2291 WriteIRQ(CDCIRQ_DISC_ERROR);
2292
2293 return(0);
2294 }
2295
2296 int32 PS_CDC::Command_Init(const int arg_count, const uint8 *args)
2297 {
2298 return(0);
2299 }
2300
2301 int32 PS_CDC::Command_ReadTOC(const int arg_count, const uint8 *args)
2302 {
2303 int32 ret_time;
2304
2305 HeaderBufValid = false;
2306 WriteResult(MakeStatus());
2307 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2308
2309 // ReadTOC doesn't error out if the tray is open, and it completes rather quickly in that case.
2310 //
2311 if(!CommandCheckDiscPresent())
2312 return(26000);
2313
2314
2315
2316 // A gross approximation.
2317 // The penalty for the drive being stopped seems to be rather high(higher than what CalcSeekTime() currently introduces), although
2318 // that should be investigated further.
2319 //
2320 // ...and not to mention the time taken varies from disc to disc even!
2321 ret_time = 30000000 + CalcSeekTime(CurSector, 0, DriveStatus != DS_STOPPED, DriveStatus == DS_PAUSED);
2322
2323 DriveStatus = DS_PAUSED; // Ends up in a pause state when the command is finished. Maybe we should add DS_READTOC or something...
2324 ClearAIP();
2325
2326 return ret_time;
2327 }
2328
2329 int32 PS_CDC::Command_ReadTOC_Part2(void)
2330 {
2331 //if(!CommandCheckDiscPresent())
2332 // DriveStatus = DS_PAUSED;
2333
2334 WriteResult(MakeStatus());
2335 WriteIRQ(CDCIRQ_COMPLETE);
2336
2337 return(0);
2338 }
2339
2340 int32 PS_CDC::Command_0x1d(const int arg_count, const uint8 *args)
2341 {
2342 WriteResult(MakeStatus());
2343 WriteIRQ(CDCIRQ_ACKNOWLEDGE);
2344 return(0);
2345 }
2346
2347 PS_CDC::CDC_CTEntry PS_CDC::Commands[0x20] =
2348 {
2349 { /* 0x00, */ 0, 0, NULL, NULL, NULL },
2350 { /* 0x01, */ 0, 0, "Nop", &PS_CDC::Command_Nop, NULL },
2351 { /* 0x02, */ 3, 3, "Setloc", &PS_CDC::Command_Setloc, NULL },
2352 { /* 0x03, */ 0, 1, "Play", &PS_CDC::Command_Play, NULL },
2353 { /* 0x04, */ 0, 0, "Forward", &PS_CDC::Command_Forward, NULL },
2354 { /* 0x05, */ 0, 0, "Backward", &PS_CDC::Command_Backward, NULL },
2355 { /* 0x06, */ 0, 0, "ReadN", &PS_CDC::Command_ReadN, NULL },
2356 { /* 0x07, */ 0, 0, "Standby", &PS_CDC::Command_Standby, &PS_CDC::Command_Standby_Part2 },
2357 { /* 0x08, */ 0, 0, "Stop", &PS_CDC::Command_Stop, &PS_CDC::Command_Stop_Part2 },
2358 { /* 0x09, */ 0, 0, "Pause", &PS_CDC::Command_Pause, &PS_CDC::Command_Pause_Part2 },
2359 { /* 0x0A, */ 0, 0, "Reset", &PS_CDC::Command_Reset, NULL },
2360 { /* 0x0B, */ 0, 0, "Mute", &PS_CDC::Command_Mute, NULL },
2361 { /* 0x0C, */ 0, 0, "Demute", &PS_CDC::Command_Demute, NULL },
2362 { /* 0x0D, */ 2, 2, "Setfilter", &PS_CDC::Command_Setfilter, NULL },
2363 { /* 0x0E, */ 1, 1, "Setmode", &PS_CDC::Command_Setmode, NULL },
2364 { /* 0x0F, */ 0, 0, "Getparam", &PS_CDC::Command_Getparam, NULL },
2365 { /* 0x10, */ 0, 0, "GetlocL", &PS_CDC::Command_GetlocL, NULL },
2366 { /* 0x11, */ 0, 0, "GetlocP", &PS_CDC::Command_GetlocP, NULL },
2367 { /* 0x12, */ 1, 1, "ReadT", &PS_CDC::Command_ReadT, &PS_CDC::Command_ReadT_Part2 },
2368 { /* 0x13, */ 0, 0, "GetTN", &PS_CDC::Command_GetTN, NULL },
2369 { /* 0x14, */ 1, 1, "GetTD", &PS_CDC::Command_GetTD, NULL },
2370 { /* 0x15, */ 0, 0, "SeekL", &PS_CDC::Command_SeekL, &PS_CDC::Command_Seek_PartN },
2371 { /* 0x16, */ 0, 0, "SeekP", &PS_CDC::Command_SeekP, &PS_CDC::Command_Seek_PartN },
2372
2373 { /* 0x17, */ 0, 0, NULL, NULL, NULL },
2374 { /* 0x18, */ 0, 0, NULL, NULL, NULL },
2375
2376 { /* 0x19, */ 1, 1/* ??? */, "Test", &PS_CDC::Command_Test, NULL },
2377 { /* 0x1A, */ 0, 0, "ID", &PS_CDC::Command_ID, &PS_CDC::Command_ID_Part2 },
2378 { /* 0x1B, */ 0, 0, "ReadS", &PS_CDC::Command_ReadS, NULL },
2379 { /* 0x1C, */ 0, 0, "Init", &PS_CDC::Command_Init, NULL },
2380 { /* 0x1D, */ 2, 2, "Unknown 0x1D", &PS_CDC::Command_0x1d, NULL },
2381 { /* 0x1E, */ 0, 0, "ReadTOC", &PS_CDC::Command_ReadTOC, &PS_CDC::Command_ReadTOC_Part2 },
2382 { /* 0x1F, */ 0, 0, NULL, NULL, NULL },
2383 };
0 #ifndef __MDFN_PSX_CDC_H
1 #define __MDFN_PSX_CDC_H
2
3 #include "../cdrom/cdromif.h"
4 #include "../cdrom/SimpleFIFO.h"
5 #include "../clamp.h"
6
7 struct CD_Audio_Buffer
8 {
9 int16 Samples[2][0x1000]; // [0][...] = l, [1][...] = r
10 int32 Size;
11 uint32 Freq;
12 int32 ReadPos;
13 };
14
15 class PS_CDC
16 {
17 public:
18
19 PS_CDC();
20 ~PS_CDC();
21
22 void SetDisc(bool tray_open, CDIF *cdif, const char disc_id[4]);
23
24 void Power(void);
25 int StateAction(StateMem *sm, int load, int data_only);
26 void ResetTS(void);
27
28 int32 CalcNextEvent(void); // Returns in master cycles to next event.
29
30 int32_t Update(const int32_t timestamp);
31
32 void Write(const int32_t timestamp, uint32 A, uint8 V);
33 uint8 Read(const int32_t timestamp, uint32 A);
34
35 bool DMACanRead(void);
36 uint32 DMARead(void);
37 void SoftReset(void);
38
39 void GetCDAudio(int32 samples[2]);
40
41 private:
42 CDIF *Cur_CDIF;
43 bool DiscChanged;
44 int32 DiscStartupDelay;
45
46 CD_Audio_Buffer AudioBuffer;
47
48 uint8 Pending_DecodeVolume[2][2], DecodeVolume[2][2]; // [data_source][output_port]
49
50 int16 ADPCM_ResampBuf[2][32 * 2];
51 uint8 ADPCM_ResampCurPos;
52 uint8 ADPCM_ResampCurPhase;
53
54 void ApplyVolume(int32 samples[2]);
55 void ReadAudioBuffer(int32 samples[2]);
56
57 void ClearAudioBuffers(void);
58
59 uint8 RegSelector;
60 uint8 ArgsBuf[16];
61 uint8 ArgsWP; // 5-bit(0 ... 31)
62 uint8 ArgsRP; // 5-bit(0 ... 31)
63
64 uint8 ArgsReceiveLatch;
65 uint8 ArgsReceiveBuf[32];
66 uint8 ArgsReceiveIn;
67
68 uint8 ResultsBuffer[16];
69 uint8 ResultsIn; // 5-bit(0 ... 31)
70 uint8 ResultsWP; // Write position, 4 bit(0 ... 15).
71 uint8 ResultsRP; // Read position, 4 bit(0 ... 15).
72
73 SimpleFIFO<uint8> DMABuffer;
74 uint8 SB[2340];
75 uint32 SB_In;
76
77 enum { SectorPipe_Count = 2 };
78 uint8 SectorPipe[SectorPipe_Count][2352];
79 uint8 SectorPipe_Pos;
80 uint8 SectorPipe_In;
81
82 uint8 SubQBuf[0xC];
83 uint8 SubQBuf_Safe[0xC];
84 bool SubQChecksumOK;
85
86 bool HeaderBufValid;
87 uint8 HeaderBuf[12];
88
89 void RecalcIRQ(void);
90 enum
91 {
92 CDCIRQ_NONE = 0,
93 CDCIRQ_DATA_READY = 1,
94 CDCIRQ_COMPLETE = 2,
95 CDCIRQ_ACKNOWLEDGE = 3,
96 CDCIRQ_DATA_END = 4,
97 CDCIRQ_DISC_ERROR = 5
98 };
99
100 // Names are just guessed for these based on what conditions cause them:
101 enum
102 {
103 ERRCODE_BAD_ARGVAL = 0x10,
104 ERRCODE_BAD_NUMARGS = 0x20,
105 ERRCODE_BAD_COMMAND = 0x40,
106 ERRCODE_NOT_READY = 0x80 // 0x80 (happens with getlocl when drive isn't reading, pause when tray is open, and MAYBE when trying to run an async
107 // command while another async command is currently in its asynch phase being executed[pause when in readtoc, todo test more])
108 };
109
110 uint8 IRQBuffer;
111 uint8 IRQOutTestMask;
112 int32 CDCReadyReceiveCounter; // IRQBuffer being non-zero prevents new results and new IRQ from coming in and erasing the current results,
113 // but apparently at least one CONFOUNDED game is clearing the IRQ state BEFORE reading the results, so we need to have a delay
114 // between IRQBuffer being cleared to when we allow new results to come in. (The real thing should be like this too,
115 // but the mechanism is probably more nuanced and complex and ugly and I like anchovy pizza)
116
117 void BeginResults(void);
118 void WriteIRQ(uint8);
119 void WriteResult(uint8);
120 uint8 ReadResult(void);
121
122 uint8 FilterFile;
123 uint8 FilterChan;
124
125
126 uint8 PendingCommand;
127 int PendingCommandPhase;
128 int32 PendingCommandCounter;
129
130 int32 SPUCounter;
131
132 enum { MODE_SPEED = 0x80 };
133 enum { MODE_STRSND = 0x40 };
134 enum { MODE_SIZE = 0x20 };
135 enum { MODE_SIZE2 = 0x10 };
136 enum { MODE_SF = 0x08 };
137 enum { MODE_REPORT = 0x04 };
138 enum { MODE_AUTOPAUSE = 0x02 };
139 enum { MODE_CDDA = 0x01 };
140 uint8 Mode;
141
142 enum
143 {
144 DS_STANDBY = -2,
145 DS_PAUSED = -1,
146 DS_STOPPED = 0,
147 DS_SEEKING,
148 DS_SEEKING_LOGICAL,
149 DS_PLAY_SEEKING,
150 DS_PLAYING,
151 DS_READING,
152 DS_RESETTING
153 };
154 int DriveStatus;
155 int StatusAfterSeek;
156 bool Forward;
157 bool Backward;
158 bool Muted;
159
160 int32 PlayTrackMatch;
161
162 int32 PSRCounter;
163
164 int32 CurSector;
165 uint32 SectorsRead; // Reset to 0 on Read*/Play command start; used in the rough simulation of PS1 SetLoc->Read->Pause->Read behavior.
166
167 unsigned AsyncIRQPending;
168 uint8 AsyncResultsPending[16];
169 uint8 AsyncResultsPendingCount;
170
171 int32 CalcSeekTime(int32 initial, int32 target, bool motor_on, bool paused);
172
173 void ClearAIP(void);
174 void CheckAIP(void);
175 void SetAIP(unsigned irq, unsigned result_count, uint8 *r);
176 void SetAIP(unsigned irq, uint8 result0);
177 void SetAIP(unsigned irq, uint8 result0, uint8 result1);
178
179 int32 SeekTarget;
180 uint32 SeekRetryCounter;
181
182 int32_t lastts;
183
184 TOC toc;
185 bool IsPSXDisc;
186 uint8 DiscID[4];
187
188 int32 CommandLoc;
189 bool CommandLoc_Dirty;
190
191 uint8 MakeStatus(bool cmd_error = false);
192 bool DecodeSubQ(uint8 *subpw);
193 bool CommandCheckDiscPresent(void);
194 void DMForceStop();
195
196 void EnbufferizeCDDASector(const uint8 *buf);
197 bool XA_Test(const uint8 *sdata);
198 void XA_ProcessSector(const uint8 *sdata, CD_Audio_Buffer *ab);
199 int16 xa_previous[2][2];
200 bool xa_cur_set;
201 uint8 xa_cur_file;
202 uint8 xa_cur_chan;
203
204 uint8 ReportLastF;
205
206 void HandlePlayRead(void);
207
208 struct CDC_CTEntry
209 {
210 uint8 args_min;
211 uint8 args_max;
212 const char *name;
213 int32 (PS_CDC::*func)(const int arg_count, const uint8 *args);
214 int32 (PS_CDC::*func2)(void);
215 };
216
217 void PreSeekHack(uint32_t target);
218 void ReadBase(void);
219
220 static CDC_CTEntry Commands[0x20];
221
222 int32 Command_Nop(const int arg_count, const uint8 *args);
223 int32 Command_Setloc(const int arg_count, const uint8 *args);
224 int32 Command_Play(const int arg_count, const uint8 *args);
225 int32 Command_Forward(const int arg_count, const uint8 *args);
226 int32 Command_Backward(const int arg_count, const uint8 *args);
227 int32 Command_ReadN(const int arg_count, const uint8 *args);
228 int32 Command_Standby(const int arg_count, const uint8 *args);
229 int32 Command_Standby_Part2(void);
230 int32 Command_Stop(const int arg_count, const uint8 *args);
231 int32 Command_Stop_Part2(void);
232 int32 Command_Pause(const int arg_count, const uint8 *args);
233 int32 Command_Pause_Part2(void);
234 int32 Command_Reset(const int arg_count, const uint8 *args);
235 int32 Command_Mute(const int arg_count, const uint8 *args);
236 int32 Command_Demute(const int arg_count, const uint8 *args);
237 int32 Command_Setfilter(const int arg_count, const uint8 *args);
238 int32 Command_Setmode(const int arg_count, const uint8 *args);
239 int32 Command_Getparam(const int arg_count, const uint8 *args);
240 int32 Command_GetlocL(const int arg_count, const uint8 *args);
241 int32 Command_GetlocP(const int arg_count, const uint8 *args);
242
243 int32 Command_ReadT(const int arg_count, const uint8 *args);
244 int32 Command_ReadT_Part2(void);
245
246 int32 Command_GetTN(const int arg_count, const uint8 *args);
247 int32 Command_GetTD(const int arg_count, const uint8 *args);
248 int32 Command_SeekL(const int arg_count, const uint8 *args);
249 int32 Command_SeekP(const int arg_count, const uint8 *args);
250 int32 Command_Seek_PartN(void);
251
252 int32 Command_Test(const int arg_count, const uint8 *args);
253
254 int32 Command_ID(const int arg_count, const uint8 *args);
255 int32 Command_ID_Part2(void);
256
257 int32 Command_ReadS(const int arg_count, const uint8 *args);
258 int32 Command_Init(const int arg_count, const uint8 *args);
259
260 int32 Command_ReadTOC(const int arg_count, const uint8 *args);
261 int32 Command_ReadTOC_Part2(void);
262
263 int32 Command_0x1d(const int arg_count, const uint8 *args);
264 };
265
266 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "cpu.h"
19
20 /* TODO
21 Make sure load delays are correct.
22
23 Consider preventing IRQs being taken while in a branch delay slot, to prevent potential problems with games that like to be too clever and perform
24 un-restartable sequences of instructions.
25 */
26
27 #define BIU_ENABLE_ICACHE_S1 0x00000800 // Enable I-cache, set 1
28 #define BIU_ENABLE_DCACHE 0x00000080 // Enable D-cache
29 #define BIU_TAG_TEST_MODE 0x00000004 // Enable TAG test mode(IsC must be set to 1 as well presumably?)
30 #define BIU_INVALIDATE_MODE 0x00000002 // Enable Invalidate mode(IsC must be set to 1 as well presumably?)
31 #define BIU_LOCK 0x00000001 // Enable Lock mode(IsC must be set to 1 as well presumably?)
32 // Does lock mode prevent the actual data payload from being modified, while allowing tags to be modified/updated???
33
34 PS_CPU::PS_CPU()
35 {
36 uint64_t a;
37 unsigned i;
38 Halted = false;
39
40 memset(FastMap, 0, sizeof(FastMap));
41 memset(DummyPage, 0xFF, sizeof(DummyPage)); // 0xFF to trigger an illegal instruction exception, so we'll know what's up when debugging.
42
43 for(a = 0x00000000; a < (UINT64_C(1) << 32); a += FAST_MAP_PSIZE)
44 SetFastMap(DummyPage, a, FAST_MAP_PSIZE);
45
46 CPUHook = NULL;
47 ADDBT = NULL;
48
49 GTE_Init();
50
51 for(i = 0; i < 24; i++)
52 {
53 uint8 v = 7;
54
55 if(i < 12)
56 v += 4;
57
58 if(i < 21)
59 v += 3;
60
61 MULT_Tab24[i] = v;
62 }
63 }
64
65 PS_CPU::~PS_CPU()
66 {
67
68
69 }
70
71 void PS_CPU::SetFastMap(void *region_mem, uint32_t region_address, uint32_t region_size)
72 {
73 uint64_t A;
74 // FAST_MAP_SHIFT
75 // FAST_MAP_PSIZE
76
77 for(A = region_address; A < (uint64)region_address + region_size; A += FAST_MAP_PSIZE)
78 FastMap[A >> FAST_MAP_SHIFT] = ((uint8_t *)region_mem - region_address);
79 }
80
81 INLINE void PS_CPU::RecalcIPCache(void)
82 {
83 IPCache = 0;
84
85 if(((CP0.SR & CP0.CAUSE & 0xFF00) && (CP0.SR & 1)) || Halted)
86 IPCache = 0x80;
87
88 if(Halted)
89 IPCache = 0x80;
90 }
91
92 void PS_CPU::SetHalt(bool status)
93 {
94 Halted = status;
95 RecalcIPCache();
96 }
97
98 void PS_CPU::Power(void)
99 {
100 unsigned i;
101
102 assert(sizeof(ICache) == sizeof(ICache_Bulk));
103
104 memset(GPR, 0, sizeof(GPR));
105 memset(&CP0, 0, sizeof(CP0));
106 LO = 0;
107 HI = 0;
108
109 gte_ts_done = 0;
110 muldiv_ts_done = 0;
111
112 BACKED_PC = 0xBFC00000;
113 BACKED_new_PC = 4;
114 BACKED_new_PC_mask = ~0U;
115
116 BACKED_LDWhich = 0x20;
117 BACKED_LDValue = 0;
118 LDAbsorb = 0;
119 memset(ReadAbsorb, 0, sizeof(ReadAbsorb));
120 ReadAbsorbWhich = 0;
121 ReadFudge = 0;
122
123 //WriteAbsorb = 0;
124 //WriteAbsorbCount = 0;
125 //WriteAbsorbMonkey = 0;
126
127 CP0.SR |= (1 << 22); // BEV
128 CP0.SR |= (1 << 21); // TS
129
130 CP0.PRID = 0x2;
131
132 RecalcIPCache();
133
134
135 BIU = 0;
136
137 memset(ScratchRAM.data8, 0, 1024);
138
139 // Not quite sure about these poweron/reset values:
140 for(i = 0; i < 1024; i++)
141 {
142 ICache[i].TV = 0x2 | ((BIU & 0x800) ? 0x0 : 0x1);
143 ICache[i].Data = 0;
144 }
145
146 GTE_Power();
147 }
148
149 int PS_CPU::StateAction(StateMem *sm, int load, int data_only)
150 {
151 SFORMAT StateRegs[] =
152 {
153 SFARRAY32(GPR, 32),
154 SFVAR(LO),
155 SFVAR(HI),
156 SFVAR(BACKED_PC),
157 SFVAR(BACKED_new_PC),
158 SFVAR(BACKED_new_PC_mask),
159
160 SFVAR(IPCache),
161 SFVAR(Halted),
162
163 SFVAR(BACKED_LDWhich),
164 SFVAR(BACKED_LDValue),
165 SFVAR(LDAbsorb),
166
167 SFVAR(next_event_ts),
168 SFVAR(gte_ts_done),
169 SFVAR(muldiv_ts_done),
170
171 SFVAR(BIU),
172 SFARRAY32(ICache_Bulk, 2048),
173
174 SFARRAY32(CP0.Regs, 32),
175
176 SFARRAY(ReadAbsorb, 0x20),
177 SFVARN(ReadAbsorb[0x2], "ReadAbsorbDummy"),
178 SFVAR(ReadAbsorbWhich),
179 SFVAR(ReadFudge),
180
181 SFARRAY(ScratchRAM.data8, 1024),
182
183 SFEND
184 };
185 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "CPU");
186
187 ret &= GTE_StateAction(sm, load, data_only);
188
189 if(load)
190 {
191
192 }
193
194 return(ret);
195 }
196
197 void PS_CPU::AssertIRQ(unsigned which, bool asserted)
198 {
199 assert(which <= 5);
200
201 CP0.CAUSE &= ~(1 << (10 + which));
202
203 if(asserted)
204 CP0.CAUSE |= 1 << (10 + which);
205
206 RecalcIPCache();
207 }
208
209 void PS_CPU::SetBIU(uint32_t val)
210 {
211 const uint32_t old_BIU = BIU;
212
213 BIU = val & ~(0x440);
214
215 if((BIU ^ old_BIU) & 0x800)
216 {
217 unsigned i;
218
219 if(BIU & 0x800) // ICache enabled
220 {
221 for(i = 0; i < 1024; i++)
222 ICache[i].TV &= ~0x1;
223 }
224 else // ICache disabled
225 {
226 for(i = 0; i < 1024; i++)
227 ICache[i].TV |= 0x1;
228 }
229 }
230
231 PSX_DBG(PSX_DBG_SPARSE, "[CPU] Set BIU=0x%08x\n", BIU);
232 }
233
234 uint32_t PS_CPU::GetBIU(void)
235 {
236 return BIU;
237 }
238
239 static const uint32_t addr_mask[8] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
240 0x7FFFFFFF, 0x1FFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
241
242 template<typename T>
243 INLINE T PS_CPU::PeekMemory(uint32_t address)
244 {
245 address &= addr_mask[address >> 29];
246
247 if(address >= 0x1F800000 && address <= 0x1F8003FF)
248 return ScratchRAM.Read<T>(address & 0x3FF);
249
250 //assert(!(CP0.SR & 0x10000));
251
252 if(sizeof(T) == 1)
253 return PSX_MemPeek8(address);
254 else if(sizeof(T) == 2)
255 return PSX_MemPeek16(address);
256 return PSX_MemPeek32(address);
257 }
258
259 template<typename T>
260 INLINE T PS_CPU::ReadMemory(int32_t &timestamp, uint32_t address, bool DS24, bool LWC_timing)
261 {
262 T ret;
263
264 //WriteAbsorb >>= WriteAbsorbMonkey * 8;
265 //WriteAbsorbCount -= WriteAbsorbMonkey;
266 //WriteAbsorbMonkey = WriteAbsorbCount;
267
268 ReadAbsorb[ReadAbsorbWhich] = 0;
269 ReadAbsorbWhich = 0;
270
271 address &= addr_mask[address >> 29];
272
273 if(address >= 0x1F800000 && address <= 0x1F8003FF)
274 {
275 LDAbsorb = 0;
276
277 if(DS24)
278 return ScratchRAM.ReadU24(address & 0x3FF);
279 return ScratchRAM.Read<T>(address & 0x3FF);
280 }
281
282 timestamp += (ReadFudge >> 4) & 2;
283
284 //assert(!(CP0.SR & 0x10000));
285
286 int32_t lts = timestamp;
287
288 if(sizeof(T) == 1)
289 ret = PSX_MemRead8(lts, address);
290 else if(sizeof(T) == 2)
291 ret = PSX_MemRead16(lts, address);
292 else
293 {
294 if(DS24)
295 ret = PSX_MemRead24(lts, address) & 0xFFFFFF;
296 else
297 ret = PSX_MemRead32(lts, address);
298 }
299
300 if(LWC_timing)
301 lts += 1;
302 else
303 lts += 2;
304
305 LDAbsorb = (lts - timestamp);
306 timestamp = lts;
307
308 return(ret);
309 }
310
311 template<typename T>
312 INLINE void PS_CPU::WriteMemory(int32_t &timestamp, uint32_t address, uint32_t value, bool DS24)
313 {
314 if(MDFN_LIKELY(!(CP0.SR & 0x10000)))
315 {
316 address &= addr_mask[address >> 29];
317
318 if(address >= 0x1F800000 && address <= 0x1F8003FF)
319 {
320 if(DS24)
321 ScratchRAM.WriteU24(address & 0x3FF, value);
322 else
323 ScratchRAM.Write<T>(address & 0x3FF, value);
324
325 return;
326 }
327
328 //if(WriteAbsorbCount == 4)
329 //{
330 // WriteAbsorb >>= 8;
331 // WriteAbsorbCount--;
332 //
333 // if(WriteAbsorbMonkey)
334 // WriteAbsorbMonkey--;
335 //}
336 //timestamp += 3;
337 //WriteAbsorb |= (3U << (WriteAbsorbCount * 8));
338 //WriteAbsorbCount++;
339
340 if(sizeof(T) == 1)
341 PSX_MemWrite8(timestamp, address, value);
342 else if(sizeof(T) == 2)
343 PSX_MemWrite16(timestamp, address, value);
344 else
345 {
346 if(DS24)
347 PSX_MemWrite24(timestamp, address, value);
348 else
349 PSX_MemWrite32(timestamp, address, value);
350 }
351 }
352 else
353 {
354 if(BIU & 0x800) // Instruction cache is enabled/active
355 {
356 if(BIU & 0x4) // TAG test mode.
357 {
358 // TODO: Respect written value.
359 __ICache *ICI = &ICache[((address & 0xFF0) >> 2)];
360 const uint8_t valid_bits = 0x00;
361
362 ICI[0].TV = ((valid_bits & 0x01) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
363 ICI[1].TV = ((valid_bits & 0x02) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
364 ICI[2].TV = ((valid_bits & 0x04) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
365 ICI[3].TV = ((valid_bits & 0x08) ? 0x00 : 0x02) | ((BIU & 0x800) ? 0x0 : 0x1);
366 }
367 else if(!(BIU & 0x1))
368 {
369 ICache[(address & 0xFFC) >> 2].Data = value << ((address & 0x3) * 8);
370 }
371 }
372
373 if((BIU & 0x081) == 0x080) // Writes to the scratchpad(TODO test)
374 {
375 if(DS24)
376 ScratchRAM.WriteU24(address & 0x3FF, value);
377 else
378 ScratchRAM.Write<T>(address & 0x3FF, value);
379 }
380 //printf("IsC WRITE%d 0x%08x 0x%08x -- CP0.SR=0x%08x\n", (int)sizeof(T), address, value, CP0.SR);
381 }
382 }
383
384 uint32_t PS_CPU::Exception(uint32_t code, uint32_t PC, const uint32_t NPM)
385 {
386 const bool InBDSlot = !(NPM & 0x3);
387 uint32_t handler = 0x80000080;
388
389 assert(code < 16);
390
391 if(code != EXCEPTION_INT && code != EXCEPTION_BP && code != EXCEPTION_SYSCALL)
392 {
393 PSX_DBG(PSX_DBG_WARNING, "Exception: %08x @ PC=0x%08x(IBDS=%d) -- IPCache=0x%02x -- IPEND=0x%02x -- SR=0x%08x ; IRQC_Status=0x%04x -- IRQC_Mask=0x%04x\n", code, PC, InBDSlot, IPCache, (CP0.CAUSE >> 8) & 0xFF, CP0.SR,
394 ::IRQ_GetRegister(IRQ_GSREG_STATUS, NULL, 0), ::IRQ_GetRegister(IRQ_GSREG_MASK, NULL, 0));
395 }
396
397 if(CP0.SR & (1 << 22)) // BEV
398 handler = 0xBFC00180;
399
400 CP0.EPC = PC;
401 if(InBDSlot)
402 CP0.EPC -= 4;
403
404 #ifdef HAVE_DEBUG
405 if(ADDBT)
406 ADDBT(PC, handler, true);
407 #endif
408
409 // "Push" IEc and KUc(so that the new IEc and KUc are 0)
410 CP0.SR = (CP0.SR & ~0x3F) | ((CP0.SR << 2) & 0x3F);
411
412 // Setup cause register
413 CP0.CAUSE &= 0x0000FF00;
414 CP0.CAUSE |= code << 2;
415
416 // If EPC was adjusted -= 4 because we were in a branch delay slot, set the bit.
417 if(InBDSlot)
418 CP0.CAUSE |= 0x80000000;
419
420 RecalcIPCache();
421
422 return(handler);
423 }
424
425 #define BACKING_TO_ACTIVE \
426 PC = BACKED_PC; \
427 new_PC = BACKED_new_PC; \
428 new_PC_mask = BACKED_new_PC_mask; \
429 LDWhich = BACKED_LDWhich; \
430 LDValue = BACKED_LDValue;
431
432 #define ACTIVE_TO_BACKING \
433 BACKED_PC = PC; \
434 BACKED_new_PC = new_PC; \
435 BACKED_new_PC_mask = new_PC_mask; \
436 BACKED_LDWhich = LDWhich; \
437 BACKED_LDValue = LDValue;
438
439 #define GPR_DEPRES_BEGIN { uint8_t back = ReadAbsorb[0];
440 #define GPR_DEP(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
441 #define GPR_RES(n) { unsigned tn = (n); ReadAbsorb[tn] = 0; }
442 #define GPR_DEPRES_END ReadAbsorb[0] = back; }
443
444 template<bool DebugMode>
445 int32_t PS_CPU::RunReal(int32_t timestamp_in)
446 {
447 register int32_t timestamp = timestamp_in;
448
449 register uint32_t PC;
450 register uint32_t new_PC;
451 register uint32_t new_PC_mask;
452 register uint32_t LDWhich;
453 register uint32_t LDValue;
454
455 //printf("%d %d\n", gte_ts_done, muldiv_ts_done);
456
457 gte_ts_done += timestamp;
458 muldiv_ts_done += timestamp;
459
460 BACKING_TO_ACTIVE;
461
462 do
463 {
464 //printf("Running: %d %d\n", timestamp, next_event_ts);
465 while(MDFN_LIKELY(timestamp < next_event_ts))
466 {
467 uint32_t instr;
468 uint32_t opf;
469
470 // Zero must be zero...until the Master Plan is enacted.
471 GPR[0] = 0;
472
473 #ifdef HAVE_DEBUG
474 if(DebugMode && CPUHook)
475 {
476 ACTIVE_TO_BACKING;
477
478 // For save states in step mode.
479 gte_ts_done -= timestamp;
480 muldiv_ts_done -= timestamp;
481
482 CPUHook(timestamp, PC);
483
484 // For save states in step mode.
485 gte_ts_done += timestamp;
486 muldiv_ts_done += timestamp;
487
488 BACKING_TO_ACTIVE;
489 }
490 #endif
491
492 // We can't fold this into the ICache[] != PC handling, since the lower 2 bits of TV
493 // are already used for cache management purposes and it assumes that the lower 2 bits of PC will be 0.
494 if(MDFN_UNLIKELY(PC & 0x3))
495 {
496 // This will block interrupt processing, but since we're going more for keeping broken homebrew/hacks from working
497 // than super-duper-accurate pipeline emulation, it shouldn't be a problem.
498 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
499 new_PC_mask = 0;
500 goto OpDone;
501 }
502
503 instr = ICache[(PC & 0xFFC) >> 2].Data;
504
505 if(ICache[(PC & 0xFFC) >> 2].TV != PC)
506 {
507 //WriteAbsorb = 0;
508 //WriteAbsorbCount = 0;
509 //WriteAbsorbMonkey = 0;
510 ReadAbsorb[ReadAbsorbWhich] = 0;
511 ReadAbsorbWhich = 0;
512
513 // FIXME: Handle executing out of scratchpad.
514 if(PC >= 0xA0000000 || !(BIU & 0x800))
515 {
516 instr = LoadU32_LE((uint32_t *)&FastMap[PC >> FAST_MAP_SHIFT][PC]);
517 timestamp += 4; // Approximate best-case cache-disabled time, per PS1 tests(executing out of 0xA0000000+); it can be 5 in *some* sequences of code(like a lot of sequential "nop"s, probably other simple instructions too).
518 }
519 else
520 {
521 __ICache *ICI = &ICache[((PC & 0xFF0) >> 2)];
522 const uint32_t *FMP = (uint32_t *)&FastMap[(PC &~ 0xF) >> FAST_MAP_SHIFT][PC &~ 0xF];
523
524 // | 0x2 to simulate (in)validity bits.
525 ICI[0x00].TV = (PC &~ 0xF) | 0x00 | 0x2;
526 ICI[0x01].TV = (PC &~ 0xF) | 0x04 | 0x2;
527 ICI[0x02].TV = (PC &~ 0xF) | 0x08 | 0x2;
528 ICI[0x03].TV = (PC &~ 0xF) | 0x0C | 0x2;
529
530 timestamp += 3;
531
532 switch(PC & 0xC)
533 {
534 case 0x0:
535 timestamp++;
536 ICI[0x00].TV &= ~0x2;
537 ICI[0x00].Data = LoadU32_LE(&FMP[0]);
538 case 0x4:
539 timestamp++;
540 ICI[0x01].TV &= ~0x2;
541 ICI[0x01].Data = LoadU32_LE(&FMP[1]);
542 case 0x8:
543 timestamp++;
544 ICI[0x02].TV &= ~0x2;
545 ICI[0x02].Data = LoadU32_LE(&FMP[2]);
546 case 0xC:
547 timestamp++;
548 ICI[0x03].TV &= ~0x2;
549 ICI[0x03].Data = LoadU32_LE(&FMP[3]);
550 break;
551 }
552 instr = ICache[(PC & 0xFFC) >> 2].Data;
553 }
554 }
555
556 //printf("PC=%08x, SP=%08x - op=0x%02x - funct=0x%02x - instr=0x%08x\n", PC, GPR[29], instr >> 26, instr & 0x3F, instr);
557 //for(int i = 0; i < 32; i++)
558 // printf("%02x : %08x\n", i, GPR[i]);
559 //printf("\n");
560
561 opf = instr & 0x3F;
562
563 if(instr & (0x3F << 26))
564 opf = 0x40 | (instr >> 26);
565
566 opf |= IPCache;
567
568 #if 0
569 {
570 uint32_t tmp = (ReadAbsorb[ReadAbsorbWhich] + 0x7FFFFFFF) >> 31;
571 ReadAbsorb[ReadAbsorbWhich] -= tmp;
572 timestamp = timestamp + 1 - tmp;
573 }
574 #else
575 if(ReadAbsorb[ReadAbsorbWhich])
576 ReadAbsorb[ReadAbsorbWhich]--;
577 //else if((uint8)WriteAbsorb)
578 //{
579 // WriteAbsorb--;
580 // if(!WriteAbsorb)
581 // {
582 // WriteAbsorbCount--;
583 // if(WriteAbsorbMonkey)
584 // WriteAbsorbMonkey--;
585 // WriteAbsorb >>= 8;
586 // }
587 //}
588 else
589 timestamp++;
590 #endif
591
592 #define DO_LDS() { GPR[LDWhich] = LDValue; ReadAbsorb[LDWhich] = LDAbsorb; ReadFudge = LDWhich; ReadAbsorbWhich |= LDWhich & 0x1F; LDWhich = 0x20; }
593 #define BEGIN_OPF(name, arg_op, arg_funct) { op_##name: /*assert( ((arg_op) ? (0x40 | (arg_op)) : (arg_funct)) == opf); */
594 #define END_OPF goto OpDone; }
595
596 #define DO_BRANCH(offset, mask) \
597 { \
598 PC = (PC & new_PC_mask) + new_PC; \
599 new_PC = (offset); \
600 new_PC_mask = (mask) & ~3; \
601 /* Lower bits of new_PC_mask being clear signifies being in a branch delay slot. (overloaded behavior for performance) */ \
602 goto SkipNPCStuff; \
603 }
604
605
606 #define ITYPE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 immediate = (int32)(int16)(instr & 0xFFFF); /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/
607 #define ITYPE_ZE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 immediate = instr & 0xFFFF; /*printf(" rs=%02x(%08x), rt=%02x(%08x), immediate=(%08x) ", rs, GPR[rs], rt, GPR[rt], immediate);*/
608 #define JTYPE uint32 target = instr & ((1 << 26) - 1); /*printf(" target=(%08x) ", target);*/
609 #define RTYPE uint32 rs MDFN_NOWARN_UNUSED = (instr >> 21) & 0x1F; uint32 rt MDFN_NOWARN_UNUSED = (instr >> 16) & 0x1F; uint32 rd MDFN_NOWARN_UNUSED = (instr >> 11) & 0x1F; uint32 shamt MDFN_NOWARN_UNUSED = (instr >> 6) & 0x1F; /*printf(" rs=%02x(%08x), rt=%02x(%08x), rd=%02x(%08x) ", rs, GPR[rs], rt, GPR[rt], rd, GPR[rd]);*/
610
611 #if !defined(__GNUC__) || defined(NO_COMPUTED_GOTO)
612 /* (uint8) cast for cheaper alternative to generated branch+compare bounds check instructions, but still more
613 expensive than computed goto which needs no masking nor bounds checking.
614 */
615 #define CGBEGIN { enum { CGESB = 1 + __COUNTER__ }; switch((uint8)opf) {
616 #define CGE(l) case __COUNTER__ - CGESB: goto l;
617 #define CGEND } }
618 #else
619 #define CGBEGIN static const void *const op_goto_table[256] = {
620 #define CGE(l) &&l,
621 #define CGEND }; goto *op_goto_table[opf];
622 #endif
623
624 CGBEGIN
625 CGE(op_SLL) CGE(op_ILL) CGE(op_SRL) CGE(op_SRA) CGE(op_SLLV) CGE(op_ILL) CGE(op_SRLV) CGE(op_SRAV)
626 CGE(op_JR) CGE(op_JALR) CGE(op_ILL) CGE(op_ILL) CGE(op_SYSCALL) CGE(op_BREAK) CGE(op_ILL) CGE(op_ILL)
627 CGE(op_MFHI) CGE(op_MTHI) CGE(op_MFLO) CGE(op_MTLO) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
628 CGE(op_MULT) CGE(op_MULTU) CGE(op_DIV) CGE(op_DIVU) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
629 CGE(op_ADD) CGE(op_ADDU) CGE(op_SUB) CGE(op_SUBU) CGE(op_AND) CGE(op_OR) CGE(op_XOR) CGE(op_NOR)
630 CGE(op_ILL) CGE(op_ILL) CGE(op_SLT) CGE(op_SLTU) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
631 CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
632 CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
633
634 CGE(op_ILL) CGE(op_BCOND) CGE(op_J) CGE(op_JAL) CGE(op_BEQ) CGE(op_BNE) CGE(op_BLEZ) CGE(op_BGTZ)
635 CGE(op_ADDI) CGE(op_ADDIU) CGE(op_SLTI) CGE(op_SLTIU) CGE(op_ANDI) CGE(op_ORI) CGE(op_XORI) CGE(op_LUI)
636 CGE(op_COP0) CGE(op_COP1) CGE(op_COP2) CGE(op_COP3) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
637 CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
638 CGE(op_LB) CGE(op_LH) CGE(op_LWL) CGE(op_LW) CGE(op_LBU) CGE(op_LHU) CGE(op_LWR) CGE(op_ILL)
639 CGE(op_SB) CGE(op_SH) CGE(op_SWL) CGE(op_SW) CGE(op_ILL) CGE(op_ILL) CGE(op_SWR) CGE(op_ILL)
640 CGE(op_LWC0) CGE(op_LWC1) CGE(op_LWC2) CGE(op_LWC3) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
641 CGE(op_SWC0) CGE(op_SWC1) CGE(op_SWC2) CGE(op_SWC3) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL) CGE(op_ILL)
642
643 // Interrupt portion of this table is constructed so that an interrupt won't be taken when the PC is pointing to a GTE instruction,
644 // to avoid problems caused by pipeline vs coprocessor nuances that aren't emulated.
645 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
646 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
647 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
648 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
649 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
650 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
651 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
652 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
653
654 CGE(op_ILL) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
655 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
656 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_COP2) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
657 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
658 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
659 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
660 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
661 CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT) CGE(op_INTERRUPT)
662 CGEND
663
664 {
665 BEGIN_OPF(ILL, 0, 0);
666 PSX_WARNING("[CPU] Unknown instruction @%08x = %08x, op=%02x, funct=%02x", PC, instr, instr >> 26, (instr & 0x3F));
667 DO_LDS();
668 new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask);
669 new_PC_mask = 0;
670 END_OPF;
671
672 //
673 // ADD - Add Word
674 //
675 BEGIN_OPF(ADD, 0, 0x20);
676 RTYPE;
677
678 GPR_DEPRES_BEGIN
679 GPR_DEP(rs);
680 GPR_DEP(rt);
681 GPR_RES(rd);
682 GPR_DEPRES_END
683
684 uint32 result = GPR[rs] + GPR[rt];
685 bool ep = ((~(GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
686
687 DO_LDS();
688
689 if(MDFN_UNLIKELY(ep))
690 {
691 new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask);
692 new_PC_mask = 0;
693 }
694 else
695 GPR[rd] = result;
696
697 END_OPF;
698
699 //
700 // ADDI - Add Immediate Word
701 //
702 BEGIN_OPF(ADDI, 0x08, 0);
703 ITYPE;
704
705 GPR_DEPRES_BEGIN
706 GPR_DEP(rs);
707 GPR_RES(rt);
708 GPR_DEPRES_END
709
710 uint32 result = GPR[rs] + immediate;
711 bool ep = ((~(GPR[rs] ^ immediate)) & (GPR[rs] ^ result)) & 0x80000000;
712
713 DO_LDS();
714
715 if(MDFN_UNLIKELY(ep))
716 {
717 new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask);
718 new_PC_mask = 0;
719 }
720 else
721 GPR[rt] = result;
722
723 END_OPF;
724
725 //
726 // ADDIU - Add Immediate Unsigned Word
727 //
728 BEGIN_OPF(ADDIU, 0x09, 0);
729 ITYPE;
730
731 GPR_DEPRES_BEGIN
732 GPR_DEP(rs);
733 GPR_RES(rt);
734 GPR_DEPRES_END
735
736 uint32 result = GPR[rs] + immediate;
737
738 DO_LDS();
739
740 GPR[rt] = result;
741
742 END_OPF;
743
744 //
745 // ADDU - Add Unsigned Word
746 //
747 BEGIN_OPF(ADDU, 0, 0x21);
748 RTYPE;
749
750 GPR_DEPRES_BEGIN
751 GPR_DEP(rs);
752 GPR_DEP(rt);
753 GPR_RES(rd);
754 GPR_DEPRES_END
755
756 uint32 result = GPR[rs] + GPR[rt];
757
758 DO_LDS();
759
760 GPR[rd] = result;
761
762 END_OPF;
763
764 //
765 // AND - And
766 //
767 BEGIN_OPF(AND, 0, 0x24);
768 RTYPE;
769
770 GPR_DEPRES_BEGIN
771 GPR_DEP(rs);
772 GPR_DEP(rt);
773 GPR_RES(rd);
774 GPR_DEPRES_END
775
776 uint32 result = GPR[rs] & GPR[rt];
777
778 DO_LDS();
779
780 GPR[rd] = result;
781
782 END_OPF;
783
784 //
785 // ANDI - And Immediate
786 //
787 BEGIN_OPF(ANDI, 0x0C, 0);
788 ITYPE_ZE;
789
790 GPR_DEPRES_BEGIN
791 GPR_DEP(rs);
792 GPR_RES(rt);
793 GPR_DEPRES_END
794
795 uint32 result = GPR[rs] & immediate;
796
797 DO_LDS();
798
799 GPR[rt] = result;
800
801 END_OPF;
802
803 //
804 // BEQ - Branch on Equal
805 //
806 BEGIN_OPF(BEQ, 0x04, 0);
807 ITYPE;
808
809 GPR_DEPRES_BEGIN
810 GPR_DEP(rs);
811 GPR_DEP(rt);
812 GPR_DEPRES_END
813
814 bool result = (GPR[rs] == GPR[rt]);
815
816 DO_LDS();
817
818 if(result)
819 {
820 DO_BRANCH((immediate << 2), ~0U);
821 }
822 END_OPF;
823
824 // Bah, why does MIPS encoding have to be funky like this. :(
825 // Handles BGEZ, BGEZAL, BLTZ, BLTZAL
826 BEGIN_OPF(BCOND, 0x01, 0);
827 const uint32 tv = GPR[(instr >> 21) & 0x1F];
828 uint32 riv = (instr >> 16) & 0x1F;
829 uint32 immediate = (int32)(int16)(instr & 0xFFFF);
830 bool result = (int32)(tv ^ (riv << 31)) < 0;
831
832 GPR_DEPRES_BEGIN
833 GPR_DEP((instr >> 21) & 0x1F);
834
835 if(riv & 0x10)
836 GPR_RES(31);
837
838 GPR_DEPRES_END
839
840
841 DO_LDS();
842
843 if(riv & 0x10) // Unconditional link reg setting.
844 GPR[31] = PC + 8;
845
846 if(result)
847 {
848 DO_BRANCH((immediate << 2), ~0U);
849 }
850
851 END_OPF;
852
853
854 //
855 // BGTZ - Branch on Greater than Zero
856 //
857 BEGIN_OPF(BGTZ, 0x07, 0);
858 ITYPE;
859
860 GPR_DEPRES_BEGIN
861 GPR_DEP(rs);
862 GPR_DEPRES_END
863
864 bool result = (int32)GPR[rs] > 0;
865
866 DO_LDS();
867
868 if(result)
869 {
870 DO_BRANCH((immediate << 2), ~0U);
871 }
872 END_OPF;
873
874 //
875 // BLEZ - Branch on Less Than or Equal to Zero
876 //
877 BEGIN_OPF(BLEZ, 0x06, 0);
878 ITYPE;
879
880 GPR_DEPRES_BEGIN
881 GPR_DEP(rs);
882 GPR_DEPRES_END
883
884 bool result = (int32)GPR[rs] <= 0;
885
886 DO_LDS();
887
888 if(result)
889 {
890 DO_BRANCH((immediate << 2), ~0U);
891 }
892
893 END_OPF;
894
895 //
896 // BNE - Branch on Not Equal
897 //
898 BEGIN_OPF(BNE, 0x05, 0);
899 ITYPE;
900
901 GPR_DEPRES_BEGIN
902 GPR_DEP(rs);
903 GPR_DEP(rt);
904 GPR_DEPRES_END
905
906 bool result = GPR[rs] != GPR[rt];
907
908 DO_LDS();
909
910 if(result)
911 {
912 DO_BRANCH((immediate << 2), ~0U);
913 }
914
915 END_OPF;
916
917 //
918 // BREAK - Breakpoint
919 //
920 BEGIN_OPF(BREAK, 0, 0x0D);
921 PSX_WARNING("[CPU] BREAK BREAK BREAK BREAK DAAANCE -- PC=0x%08x", PC);
922
923 DO_LDS();
924 new_PC = Exception(EXCEPTION_BP, PC, new_PC_mask);
925 new_PC_mask = 0;
926 END_OPF;
927
928 // Cop "instructions": CFCz(no CP0), COPz, CTCz(no CP0), LWCz(no CP0), MFCz, MTCz, SWCz(no CP0)
929 //
930 // COP0 instructions
931 BEGIN_OPF(COP0, 0x10, 0);
932 uint32 sub_op = (instr >> 21) & 0x1F;
933
934 if(sub_op & 0x10)
935 sub_op = 0x10 + (instr & 0x3F);
936
937 //printf("COP0 thing: %02x\n", sub_op);
938 switch(sub_op)
939 {
940 default:
941 DO_LDS();
942 break;
943
944 case 0x00: // MFC0 - Move from Coprocessor
945 {
946 uint32 rt = (instr >> 16) & 0x1F;
947 uint32 rd = (instr >> 11) & 0x1F;
948
949 //printf("MFC0: rt=%d <- rd=%d(%08x)\n", rt, rd, CP0.Regs[rd]);
950 DO_LDS();
951
952 LDAbsorb = 0;
953 LDWhich = rt;
954 LDValue = CP0.Regs[rd];
955 }
956 break;
957
958 case 0x04: // MTC0 - Move to Coprocessor
959 {
960 uint32 rt = (instr >> 16) & 0x1F;
961 uint32 rd = (instr >> 11) & 0x1F;
962 uint32 val = GPR[rt];
963
964 if(rd != CP0REG_PRID && rd != CP0REG_CAUSE && rd != CP0REG_SR && val)
965 {
966 PSX_WARNING("[CPU] Unimplemented MTC0: rt=%d(%08x) -> rd=%d", rt, GPR[rt], rd);
967 }
968
969 switch(rd)
970 {
971 case CP0REG_BPC:
972 CP0.BPC = val;
973 break;
974
975 case CP0REG_BDA:
976 CP0.BDA = val;
977 break;
978
979 case CP0REG_TAR:
980 CP0.TAR = val;
981 break;
982
983 case CP0REG_DCIC:
984 CP0.DCIC = val & 0xFF80003F;
985 break;
986
987 case CP0REG_BDAM:
988 CP0.BDAM = val;
989 break;
990
991 case CP0REG_BPCM:
992 CP0.BPCM = val;
993 break;
994
995 case CP0REG_CAUSE:
996 CP0.CAUSE &= ~(0x3 << 8);
997 CP0.CAUSE |= val & (0x3 << 8);
998 RecalcIPCache();
999 break;
1000
1001 case CP0REG_SR:
1002 if((CP0.SR ^ val) & 0x10000)
1003 PSX_DBG(PSX_DBG_SPARSE, "[CPU] IsC %u->%u\n", (bool)(CP0.SR & (1U << 16)), (bool)(val & (1U << 16)));
1004
1005 CP0.SR = val & ~( (0x3 << 26) | (0x3 << 23) | (0x3 << 6));
1006 RecalcIPCache();
1007 break;
1008 }
1009 }
1010 DO_LDS();
1011 break;
1012
1013 case (0x10 + 0x10): // RFE
1014 // "Pop"
1015 DO_LDS();
1016 CP0.SR = (CP0.SR & ~0x0F) | ((CP0.SR >> 2) & 0x0F);
1017 RecalcIPCache();
1018 break;
1019 }
1020 END_OPF;
1021
1022 //
1023 // COP1
1024 //
1025 BEGIN_OPF(COP1, 0x11, 0);
1026 DO_LDS();
1027 new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
1028 new_PC_mask = 0;
1029 END_OPF;
1030
1031 //
1032 // COP2
1033 //
1034 BEGIN_OPF(COP2, 0x12, 0);
1035 uint32 sub_op = (instr >> 21) & 0x1F;
1036
1037 if (sub_op >= 0x10 && sub_op <= 0x1F)
1038 {
1039 //printf("%08x\n", PC);
1040 if(timestamp < gte_ts_done)
1041 timestamp = gte_ts_done;
1042 gte_ts_done = timestamp + GTE_Instruction(instr);
1043 DO_LDS();
1044 }
1045 else switch(sub_op)
1046 {
1047 default:
1048 DO_LDS();
1049 break;
1050
1051 case 0x00: // MFC2 - Move from Coprocessor
1052 {
1053 uint32 rt = (instr >> 16) & 0x1F;
1054 uint32 rd = (instr >> 11) & 0x1F;
1055
1056 DO_LDS();
1057
1058 if(timestamp < gte_ts_done)
1059 {
1060 LDAbsorb = gte_ts_done - timestamp;
1061 timestamp = gte_ts_done;
1062 }
1063 else
1064 LDAbsorb = 0;
1065
1066 LDWhich = rt;
1067 LDValue = GTE_ReadDR(rd);
1068 }
1069 break;
1070
1071 case 0x04: // MTC2 - Move to Coprocessor
1072 {
1073 uint32 rt = (instr >> 16) & 0x1F;
1074 uint32 rd = (instr >> 11) & 0x1F;
1075 uint32 val = GPR[rt];
1076
1077 if(timestamp < gte_ts_done)
1078 timestamp = gte_ts_done;
1079
1080 //printf("GTE WriteDR: %d %d\n", rd, val);
1081 GTE_WriteDR(rd, val);
1082 DO_LDS();
1083 }
1084 break;
1085
1086 case 0x02: // CFC2
1087 {
1088 uint32 rt = (instr >> 16) & 0x1F;
1089 uint32 rd = (instr >> 11) & 0x1F;
1090
1091 DO_LDS();
1092
1093 if(timestamp < gte_ts_done)
1094 {
1095 LDAbsorb = gte_ts_done - timestamp;
1096 timestamp = gte_ts_done;
1097 }
1098 else
1099 LDAbsorb = 0;
1100
1101 LDWhich = rt;
1102 LDValue = GTE_ReadCR(rd);
1103
1104 //printf("GTE ReadCR: %d %d\n", rd, GPR[rt]);
1105 }
1106 break;
1107
1108 case 0x06: // CTC2
1109 {
1110 uint32 rt = (instr >> 16) & 0x1F;
1111 uint32 rd = (instr >> 11) & 0x1F;
1112 uint32 val = GPR[rt];
1113
1114 //printf("GTE WriteCR: %d %d\n", rd, val);
1115
1116 if(timestamp < gte_ts_done)
1117 timestamp = gte_ts_done;
1118
1119 GTE_WriteCR(rd, val);
1120 DO_LDS();
1121 }
1122 break;
1123 }
1124 END_OPF;
1125
1126 //
1127 // COP3
1128 //
1129 BEGIN_OPF(COP3, 0x13, 0);
1130 DO_LDS();
1131 new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
1132 new_PC_mask = 0;
1133 END_OPF;
1134
1135 //
1136 // LWC0
1137 //
1138 BEGIN_OPF(LWC0, 0x30, 0);
1139 DO_LDS();
1140 new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
1141 new_PC_mask = 0;
1142 END_OPF;
1143
1144 //
1145 // LWC1
1146 //
1147 BEGIN_OPF(LWC1, 0x31, 0);
1148 DO_LDS();
1149 new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
1150 new_PC_mask = 0;
1151 END_OPF;
1152
1153 //
1154 // LWC2
1155 //
1156 BEGIN_OPF(LWC2, 0x32, 0);
1157 ITYPE;
1158 uint32 address = GPR[rs] + immediate;
1159
1160 DO_LDS();
1161
1162 if(MDFN_UNLIKELY(address & 3))
1163 {
1164 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
1165 new_PC_mask = 0;
1166 }
1167 else
1168 {
1169 if(timestamp < gte_ts_done)
1170 timestamp = gte_ts_done;
1171
1172 GTE_WriteDR(rt, ReadMemory<uint32>(timestamp, address, false, true));
1173 }
1174 // GTE stuff here
1175 END_OPF;
1176
1177 //
1178 // LWC3
1179 //
1180 BEGIN_OPF(LWC3, 0x33, 0);
1181 DO_LDS();
1182 new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
1183 new_PC_mask = 0;
1184 END_OPF;
1185
1186
1187 //
1188 // SWC0
1189 //
1190 BEGIN_OPF(SWC0, 0x38, 0);
1191 DO_LDS();
1192 new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
1193 new_PC_mask = 0;
1194 END_OPF;
1195
1196 //
1197 // SWC1
1198 //
1199 BEGIN_OPF(SWC1, 0x39, 0);
1200 DO_LDS();
1201 new_PC = Exception(EXCEPTION_COPU, PC, new_PC_mask);
1202 new_PC_mask = 0;
1203 END_OPF;
1204
1205 //
1206 // SWC2
1207 //
1208 BEGIN_OPF(SWC2, 0x3A, 0);
1209 ITYPE;
1210 uint32 address = GPR[rs] + immediate;
1211
1212 if(MDFN_UNLIKELY(address & 0x3))
1213 {
1214 new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask);
1215 new_PC_mask = 0;
1216 }
1217 else
1218 {
1219 if(timestamp < gte_ts_done)
1220 timestamp = gte_ts_done;
1221
1222 WriteMemory<uint32>(timestamp, address, GTE_ReadDR(rt));
1223 }
1224 DO_LDS();
1225 END_OPF;
1226
1227 //
1228 // SWC3
1229 ///
1230 BEGIN_OPF(SWC3, 0x3B, 0);
1231 DO_LDS();
1232 new_PC = Exception(EXCEPTION_RI, PC, new_PC_mask);
1233 new_PC_mask = 0;
1234 END_OPF;
1235
1236
1237 //
1238 // DIV - Divide Word
1239 //
1240 BEGIN_OPF(DIV, 0, 0x1A);
1241 RTYPE;
1242
1243 GPR_DEPRES_BEGIN
1244 GPR_DEP(rs);
1245 GPR_DEP(rt);
1246 GPR_DEPRES_END
1247
1248 if(!GPR[rt])
1249 {
1250 if(GPR[rs] & 0x80000000)
1251 LO = 1;
1252 else
1253 LO = 0xFFFFFFFF;
1254
1255 HI = GPR[rs];
1256 }
1257 else if(GPR[rs] == 0x80000000 && GPR[rt] == 0xFFFFFFFF)
1258 {
1259 LO = 0x80000000;
1260 HI = 0;
1261 }
1262 else
1263 {
1264 LO = (int32)GPR[rs] / (int32)GPR[rt];
1265 HI = (int32)GPR[rs] % (int32)GPR[rt];
1266 }
1267 muldiv_ts_done = timestamp + 37;
1268
1269 DO_LDS();
1270
1271 END_OPF;
1272
1273 // DIVU - Divide Unsigned Word
1274 BEGIN_OPF(DIVU, 0, 0x1B);
1275 RTYPE;
1276
1277 GPR_DEPRES_BEGIN
1278 GPR_DEP(rs);
1279 GPR_DEP(rt);
1280 GPR_DEPRES_END
1281
1282 if(!GPR[rt])
1283 {
1284 LO = 0xFFFFFFFF;
1285 HI = GPR[rs];
1286 }
1287 else
1288 {
1289 LO = GPR[rs] / GPR[rt];
1290 HI = GPR[rs] % GPR[rt];
1291 }
1292 muldiv_ts_done = timestamp + 37;
1293
1294 DO_LDS();
1295 END_OPF;
1296
1297 //
1298 // J - Jump
1299 //
1300 BEGIN_OPF(J, 0x02, 0);
1301 JTYPE;
1302
1303 DO_LDS();
1304
1305 DO_BRANCH(target << 2, 0xF0000000);
1306 END_OPF;
1307
1308 //
1309 // JAL - Jump and Link
1310 //
1311 BEGIN_OPF(JAL, 0x03, 0);
1312 JTYPE;
1313
1314 //GPR_DEPRES_BEGIN
1315 GPR_RES(31);
1316 //GPR_DEPRES_END
1317
1318 DO_LDS();
1319
1320 GPR[31] = PC + 8;
1321
1322 DO_BRANCH(target << 2, 0xF0000000);
1323 END_OPF;
1324
1325 //
1326 // JALR - Jump and Link Register
1327 //
1328 BEGIN_OPF(JALR, 0, 0x09);
1329 RTYPE;
1330
1331 GPR_DEPRES_BEGIN
1332 GPR_DEP(rs);
1333 GPR_RES(rd);
1334 GPR_DEPRES_END
1335
1336 uint32 tmp = GPR[rs];
1337
1338 DO_LDS();
1339
1340 GPR[rd] = PC + 8;
1341
1342 DO_BRANCH(tmp, 0);
1343
1344 END_OPF;
1345
1346 //
1347 // JR - Jump Register
1348 //
1349 BEGIN_OPF(JR, 0, 0x08);
1350 RTYPE;
1351
1352 GPR_DEPRES_BEGIN
1353 GPR_DEP(rs);
1354 GPR_RES(rd);
1355 GPR_DEPRES_END
1356
1357 uint32 bt = GPR[rs];
1358
1359 DO_LDS();
1360
1361 DO_BRANCH(bt, 0);
1362
1363 END_OPF;
1364
1365 //
1366 // LUI - Load Upper Immediate
1367 //
1368 BEGIN_OPF(LUI, 0x0F, 0);
1369 ITYPE_ZE; // Actually, probably would be sign-extending...if we were emulating a 64-bit MIPS chip :b
1370
1371 GPR_DEPRES_BEGIN
1372 GPR_RES(rt);
1373 GPR_DEPRES_END
1374
1375 DO_LDS();
1376
1377 GPR[rt] = immediate << 16;
1378
1379 END_OPF;
1380
1381 //
1382 // MFHI - Move from HI
1383 //
1384 BEGIN_OPF(MFHI, 0, 0x10);
1385 RTYPE;
1386
1387 GPR_DEPRES_BEGIN
1388 GPR_RES(rd);
1389 GPR_DEPRES_END
1390
1391 DO_LDS();
1392
1393 if(timestamp < muldiv_ts_done)
1394 {
1395 if(timestamp == muldiv_ts_done - 1)
1396 muldiv_ts_done--;
1397 else
1398 {
1399 do
1400 {
1401 if(ReadAbsorb[ReadAbsorbWhich])
1402 ReadAbsorb[ReadAbsorbWhich]--;
1403 timestamp++;
1404 } while(timestamp < muldiv_ts_done);
1405 }
1406 }
1407
1408 GPR[rd] = HI;
1409
1410 END_OPF;
1411
1412
1413 //
1414 // MFLO - Move from LO
1415 //
1416 BEGIN_OPF(MFLO, 0, 0x12);
1417 RTYPE;
1418
1419 GPR_DEPRES_BEGIN
1420 GPR_RES(rd);
1421 GPR_DEPRES_END
1422
1423 DO_LDS();
1424
1425 if(timestamp < muldiv_ts_done)
1426 {
1427 if(timestamp == muldiv_ts_done - 1)
1428 muldiv_ts_done--;
1429 else
1430 {
1431 do
1432 {
1433 if(ReadAbsorb[ReadAbsorbWhich])
1434 ReadAbsorb[ReadAbsorbWhich]--;
1435 timestamp++;
1436 } while(timestamp < muldiv_ts_done);
1437 }
1438 }
1439
1440 GPR[rd] = LO;
1441
1442 END_OPF;
1443
1444
1445 //
1446 // MTHI - Move to HI
1447 //
1448 BEGIN_OPF(MTHI, 0, 0x11);
1449 RTYPE;
1450
1451 GPR_DEPRES_BEGIN
1452 GPR_DEP(rs);
1453 GPR_DEPRES_END
1454
1455 HI = GPR[rs];
1456
1457 DO_LDS();
1458
1459 END_OPF;
1460
1461 //
1462 // MTLO - Move to LO
1463 //
1464 BEGIN_OPF(MTLO, 0, 0x13);
1465 RTYPE;
1466
1467 GPR_DEPRES_BEGIN
1468 GPR_DEP(rs);
1469 GPR_DEPRES_END
1470
1471 LO = GPR[rs];
1472
1473 DO_LDS();
1474
1475 END_OPF;
1476
1477
1478 //
1479 // MULT - Multiply Word
1480 //
1481 BEGIN_OPF(MULT, 0, 0x18);
1482 RTYPE;
1483
1484 GPR_DEPRES_BEGIN
1485 GPR_DEP(rs);
1486 GPR_DEP(rt);
1487 GPR_DEPRES_END
1488
1489 uint64 result;
1490
1491 result = (int64)(int32)GPR[rs] * (int32)GPR[rt];
1492 muldiv_ts_done = timestamp + MULT_Tab24[__builtin_clz((GPR[rs] ^ ((int32)GPR[rs] >> 31)) | 0x400)];
1493 DO_LDS();
1494
1495 LO = result;
1496 HI = result >> 32;
1497
1498 END_OPF;
1499
1500 //
1501 // MULTU - Multiply Unsigned Word
1502 //
1503 BEGIN_OPF(MULTU, 0, 0x19);
1504 RTYPE;
1505
1506 GPR_DEPRES_BEGIN
1507 GPR_DEP(rs);
1508 GPR_DEP(rt);
1509 GPR_DEPRES_END
1510
1511 uint64 result;
1512
1513 result = (uint64)GPR[rs] * GPR[rt];
1514 muldiv_ts_done = timestamp + MULT_Tab24[__builtin_clz(GPR[rs] | 0x400)];
1515 DO_LDS();
1516
1517 LO = result;
1518 HI = result >> 32;
1519
1520 END_OPF;
1521
1522
1523 //
1524 // NOR - NOR
1525 //
1526 BEGIN_OPF(NOR, 0, 0x27);
1527 RTYPE;
1528
1529 GPR_DEPRES_BEGIN
1530 GPR_DEP(rs);
1531 GPR_DEP(rt);
1532 GPR_RES(rd);
1533 GPR_DEPRES_END
1534
1535 uint32 result = ~(GPR[rs] | GPR[rt]);
1536
1537 DO_LDS();
1538
1539 GPR[rd] = result;
1540
1541 END_OPF;
1542
1543 //
1544 // OR - OR
1545 //
1546 BEGIN_OPF(OR, 0, 0x25);
1547 RTYPE;
1548
1549 GPR_DEPRES_BEGIN
1550 GPR_DEP(rs);
1551 GPR_DEP(rt);
1552 GPR_RES(rd);
1553 GPR_DEPRES_END
1554
1555 uint32 result = GPR[rs] | GPR[rt];
1556
1557 DO_LDS();
1558
1559 GPR[rd] = result;
1560
1561 END_OPF;
1562
1563
1564 //
1565 // ORI - OR Immediate
1566 //
1567 BEGIN_OPF(ORI, 0x0D, 0);
1568 ITYPE_ZE;
1569
1570 GPR_DEPRES_BEGIN
1571 GPR_DEP(rs);
1572 GPR_RES(rt);
1573 GPR_DEPRES_END
1574
1575 uint32 result = GPR[rs] | immediate;
1576
1577 DO_LDS();
1578
1579 GPR[rt] = result;
1580
1581 END_OPF;
1582
1583
1584 //
1585 // SLL - Shift Word Left Logical
1586 //
1587 BEGIN_OPF(SLL, 0, 0x00); // SLL
1588 RTYPE;
1589
1590 GPR_DEPRES_BEGIN
1591 GPR_DEP(rt);
1592 GPR_RES(rd);
1593 GPR_DEPRES_END
1594
1595 uint32 result = GPR[rt] << shamt;
1596
1597 DO_LDS();
1598
1599 GPR[rd] = result;
1600
1601 END_OPF;
1602
1603
1604 //
1605 // SLLV - Shift Word Left Logical Variable
1606 //
1607 BEGIN_OPF(SLLV, 0, 0x04);
1608 RTYPE;
1609
1610 GPR_DEPRES_BEGIN
1611 GPR_DEP(rs);
1612 GPR_DEP(rt);
1613 GPR_RES(rd);
1614 GPR_DEPRES_END
1615
1616 uint32 result = GPR[rt] << (GPR[rs] & 0x1F);
1617
1618 DO_LDS();
1619
1620 GPR[rd] = result;
1621
1622 END_OPF;
1623
1624 //
1625 // SLT - Set on Less Than
1626 //
1627 BEGIN_OPF(SLT, 0, 0x2A);
1628 RTYPE;
1629
1630 GPR_DEPRES_BEGIN
1631 GPR_DEP(rs);
1632 GPR_DEP(rt);
1633 GPR_RES(rd);
1634 GPR_DEPRES_END
1635
1636 uint32 result = (bool)((int32)GPR[rs] < (int32)GPR[rt]);
1637
1638 DO_LDS();
1639
1640 GPR[rd] = result;
1641
1642 END_OPF;
1643
1644
1645 //
1646 // SLTI - Set on Less Than Immediate
1647 //
1648 BEGIN_OPF(SLTI, 0x0A, 0);
1649 ITYPE;
1650
1651 GPR_DEPRES_BEGIN
1652 GPR_DEP(rs);
1653 GPR_RES(rt);
1654 GPR_DEPRES_END
1655
1656 uint32 result = (bool)((int32)GPR[rs] < (int32)immediate);
1657
1658 DO_LDS();
1659
1660 GPR[rt] = result;
1661
1662 END_OPF;
1663
1664
1665 //
1666 // SLTIU - Set on Less Than Immediate, Unsigned
1667 //
1668 BEGIN_OPF(SLTIU, 0x0B, 0);
1669 ITYPE;
1670
1671 GPR_DEPRES_BEGIN
1672 GPR_DEP(rs);
1673 GPR_RES(rt);
1674 GPR_DEPRES_END
1675
1676 uint32 result = (bool)(GPR[rs] < (uint32)immediate);
1677
1678 DO_LDS();
1679
1680 GPR[rt] = result;
1681
1682 END_OPF;
1683
1684
1685 //
1686 // SLTU - Set on Less Than, Unsigned
1687 //
1688 BEGIN_OPF(SLTU, 0, 0x2B);
1689 RTYPE;
1690
1691 GPR_DEPRES_BEGIN
1692 GPR_DEP(rs);
1693 GPR_DEP(rt);
1694 GPR_RES(rd);
1695 GPR_DEPRES_END
1696
1697 uint32 result = (bool)(GPR[rs] < GPR[rt]);
1698
1699 DO_LDS();
1700
1701 GPR[rd] = result;
1702
1703 END_OPF;
1704
1705
1706 //
1707 // SRA - Shift Word Right Arithmetic
1708 //
1709 BEGIN_OPF(SRA, 0, 0x03);
1710 RTYPE;
1711
1712 GPR_DEPRES_BEGIN
1713 GPR_DEP(rt);
1714 GPR_RES(rd);
1715 GPR_DEPRES_END
1716
1717 uint32 result = ((int32)GPR[rt]) >> shamt;
1718
1719 DO_LDS();
1720
1721 GPR[rd] = result;
1722
1723 END_OPF;
1724
1725
1726 //
1727 // SRAV - Shift Word Right Arithmetic Variable
1728 //
1729 BEGIN_OPF(SRAV, 0, 0x07);
1730 RTYPE;
1731
1732 GPR_DEPRES_BEGIN
1733 GPR_DEP(rs);
1734 GPR_DEP(rt);
1735 GPR_RES(rd);
1736 GPR_DEPRES_END
1737
1738 uint32 result = ((int32)GPR[rt]) >> (GPR[rs] & 0x1F);
1739
1740 DO_LDS();
1741
1742 GPR[rd] = result;
1743
1744 END_OPF;
1745
1746
1747 //
1748 // SRL - Shift Word Right Logical
1749 //
1750 BEGIN_OPF(SRL, 0, 0x02);
1751 RTYPE;
1752
1753 GPR_DEPRES_BEGIN
1754 GPR_DEP(rt);
1755 GPR_RES(rd);
1756 GPR_DEPRES_END
1757
1758 uint32 result = GPR[rt] >> shamt;
1759
1760 DO_LDS();
1761
1762 GPR[rd] = result;
1763
1764 END_OPF;
1765
1766 //
1767 // SRLV - Shift Word Right Logical Variable
1768 //
1769 BEGIN_OPF(SRLV, 0, 0x06);
1770 RTYPE;
1771
1772 GPR_DEPRES_BEGIN
1773 GPR_DEP(rs);
1774 GPR_DEP(rt);
1775 GPR_RES(rd);
1776 GPR_DEPRES_END
1777
1778 uint32 result = GPR[rt] >> (GPR[rs] & 0x1F);
1779
1780 DO_LDS();
1781
1782 GPR[rd] = result;
1783
1784 END_OPF;
1785
1786
1787 //
1788 // SUB - Subtract Word
1789 //
1790 BEGIN_OPF(SUB, 0, 0x22);
1791 RTYPE;
1792
1793 GPR_DEPRES_BEGIN
1794 GPR_DEP(rs);
1795 GPR_DEP(rt);
1796 GPR_RES(rd);
1797 GPR_DEPRES_END
1798
1799 uint32 result = GPR[rs] - GPR[rt];
1800 bool ep = (((GPR[rs] ^ GPR[rt])) & (GPR[rs] ^ result)) & 0x80000000;
1801
1802 DO_LDS();
1803
1804 if(MDFN_UNLIKELY(ep))
1805 {
1806 new_PC = Exception(EXCEPTION_OV, PC, new_PC_mask);
1807 new_PC_mask = 0;
1808 }
1809 else
1810 GPR[rd] = result;
1811
1812 END_OPF;
1813
1814
1815 //
1816 // SUBU - Subtract Unsigned Word
1817 //
1818 BEGIN_OPF(SUBU, 0, 0x23); // SUBU
1819 RTYPE;
1820
1821 GPR_DEPRES_BEGIN
1822 GPR_DEP(rs);
1823 GPR_DEP(rt);
1824 GPR_RES(rd);
1825 GPR_DEPRES_END
1826
1827 uint32 result = GPR[rs] - GPR[rt];
1828
1829 DO_LDS();
1830
1831 GPR[rd] = result;
1832
1833 END_OPF;
1834
1835
1836 //
1837 // SYSCALL
1838 //
1839 BEGIN_OPF(SYSCALL, 0, 0x0C);
1840 DO_LDS();
1841
1842 new_PC = Exception(EXCEPTION_SYSCALL, PC, new_PC_mask);
1843 new_PC_mask = 0;
1844 END_OPF;
1845
1846
1847 //
1848 // XOR
1849 //
1850 BEGIN_OPF(XOR, 0, 0x26);
1851 RTYPE;
1852
1853 GPR_DEPRES_BEGIN
1854 GPR_DEP(rs);
1855 GPR_DEP(rt);
1856 GPR_RES(rd);
1857 GPR_DEPRES_END
1858
1859 uint32 result = GPR[rs] ^ GPR[rt];
1860
1861 DO_LDS();
1862
1863 GPR[rd] = result;
1864
1865 END_OPF;
1866
1867 //
1868 // XORI - Exclusive OR Immediate
1869 //
1870 BEGIN_OPF(XORI, 0x0E, 0);
1871 ITYPE_ZE;
1872
1873 GPR_DEPRES_BEGIN
1874 GPR_DEP(rs);
1875 GPR_RES(rt);
1876 GPR_DEPRES_END
1877
1878 uint32 result = GPR[rs] ^ immediate;
1879
1880 DO_LDS();
1881
1882 GPR[rt] = result;
1883 END_OPF;
1884
1885 //
1886 // Memory access instructions(besides the coprocessor ones) follow:
1887 //
1888
1889 //
1890 // LB - Load Byte
1891 //
1892 BEGIN_OPF(LB, 0x20, 0);
1893 ITYPE;
1894
1895 GPR_DEPRES_BEGIN
1896 GPR_DEP(rs);
1897 GPR_DEPRES_END
1898
1899 uint32 address = GPR[rs] + immediate;
1900
1901 DO_LDS();
1902
1903 LDWhich = rt;
1904 LDValue = (int32)ReadMemory<int8>(timestamp, address);
1905 END_OPF;
1906
1907 //
1908 // LBU - Load Byte Unsigned
1909 //
1910 BEGIN_OPF(LBU, 0x24, 0);
1911 ITYPE;
1912
1913 GPR_DEPRES_BEGIN
1914 GPR_DEP(rs);
1915 GPR_DEPRES_END
1916
1917 uint32 address = GPR[rs] + immediate;
1918
1919 DO_LDS();
1920
1921 LDWhich = rt;
1922 LDValue = ReadMemory<uint8>(timestamp, address);
1923 END_OPF;
1924
1925 //
1926 // LH - Load Halfword
1927 //
1928 BEGIN_OPF(LH, 0x21, 0);
1929 ITYPE;
1930
1931 GPR_DEPRES_BEGIN
1932 GPR_DEP(rs);
1933 GPR_DEPRES_END
1934
1935 uint32 address = GPR[rs] + immediate;
1936
1937 DO_LDS();
1938
1939 if(MDFN_UNLIKELY(address & 1))
1940 {
1941 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
1942 new_PC_mask = 0;
1943 }
1944 else
1945 {
1946 LDWhich = rt;
1947 LDValue = (int32)ReadMemory<int16>(timestamp, address);
1948 }
1949 END_OPF;
1950
1951 //
1952 // LHU - Load Halfword Unsigned
1953 //
1954 BEGIN_OPF(LHU, 0x25, 0);
1955 ITYPE;
1956
1957 GPR_DEPRES_BEGIN
1958 GPR_DEP(rs);
1959 GPR_DEPRES_END
1960
1961 uint32 address = GPR[rs] + immediate;
1962
1963 DO_LDS();
1964
1965 if(MDFN_UNLIKELY(address & 1))
1966 {
1967 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
1968 new_PC_mask = 0;
1969 }
1970 else
1971 {
1972 LDWhich = rt;
1973 LDValue = ReadMemory<uint16>(timestamp, address);
1974 }
1975 END_OPF;
1976
1977
1978 //
1979 // LW - Load Word
1980 //
1981 BEGIN_OPF(LW, 0x23, 0);
1982 ITYPE;
1983
1984 GPR_DEPRES_BEGIN
1985 GPR_DEP(rs);
1986 GPR_DEPRES_END
1987
1988 uint32 address = GPR[rs] + immediate;
1989
1990 DO_LDS();
1991
1992 if(MDFN_UNLIKELY(address & 3))
1993 {
1994 new_PC = Exception(EXCEPTION_ADEL, PC, new_PC_mask);
1995 new_PC_mask = 0;
1996 }
1997 else
1998 {
1999 LDWhich = rt;
2000 LDValue = ReadMemory<uint32>(timestamp, address);
2001 }
2002 END_OPF;
2003
2004 //
2005 // SB - Store Byte
2006 //
2007 BEGIN_OPF(SB, 0x28, 0);
2008 ITYPE;
2009
2010 GPR_DEPRES_BEGIN
2011 GPR_DEP(rs);
2012 GPR_DEP(rt);
2013 GPR_DEPRES_END
2014
2015 uint32 address = GPR[rs] + immediate;
2016
2017 WriteMemory<uint8>(timestamp, address, GPR[rt]);
2018
2019 DO_LDS();
2020 END_OPF;
2021
2022 //
2023 // SH - Store Halfword
2024 //
2025 BEGIN_OPF(SH, 0x29, 0);
2026 ITYPE;
2027
2028 GPR_DEPRES_BEGIN
2029 GPR_DEP(rs);
2030 GPR_DEP(rt);
2031 GPR_DEPRES_END
2032
2033 uint32 address = GPR[rs] + immediate;
2034
2035 if(MDFN_UNLIKELY(address & 0x1))
2036 {
2037 new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask);
2038 new_PC_mask = 0;
2039 }
2040 else
2041 WriteMemory<uint16>(timestamp, address, GPR[rt]);
2042
2043 DO_LDS();
2044 END_OPF;
2045
2046 //
2047 // SW - Store Word
2048 //
2049 BEGIN_OPF(SW, 0x2B, 0);
2050 ITYPE;
2051
2052 GPR_DEPRES_BEGIN
2053 GPR_DEP(rs);
2054 GPR_DEP(rt);
2055 GPR_DEPRES_END
2056
2057 uint32 address = GPR[rs] + immediate;
2058
2059 if(MDFN_UNLIKELY(address & 0x3))
2060 {
2061 new_PC = Exception(EXCEPTION_ADES, PC, new_PC_mask);
2062 new_PC_mask = 0;
2063 }
2064 else
2065 WriteMemory<uint32>(timestamp, address, GPR[rt]);
2066
2067 DO_LDS();
2068 END_OPF;
2069
2070 // LWL and LWR load delay slot tomfoolery appears to apply even to MFC0! (and probably MFCn and CFCn as well, though they weren't explicitly tested)
2071
2072 //
2073 // LWL - Load Word Left
2074 //
2075 BEGIN_OPF(LWL, 0x22, 0);
2076 ITYPE;
2077
2078 GPR_DEPRES_BEGIN
2079 GPR_DEP(rs);
2080 //GPR_DEP(rt);
2081 GPR_DEPRES_END
2082
2083 uint32 address = GPR[rs] + immediate;
2084 uint32 v = GPR[rt];
2085
2086 if(LDWhich == rt)
2087 {
2088 v = LDValue;
2089 ReadFudge = 0;
2090 }
2091 else
2092 {
2093 DO_LDS();
2094 }
2095
2096 LDWhich = rt;
2097 switch(address & 0x3)
2098 {
2099 case 0:
2100 LDValue = (v & ~(0xFF << 24)) | (ReadMemory<uint8>(timestamp, address & ~3) << 24);
2101 break;
2102 case 1:
2103 LDValue = (v & ~(0xFFFF << 16)) | (ReadMemory<uint16>(timestamp, address & ~3) << 16);
2104 break;
2105 case 2:
2106 LDValue = (v & ~(0xFFFFFF << 8)) | (ReadMemory<uint32>(timestamp, address & ~3, true) << 8);
2107 break;
2108 case 3:
2109 LDValue = (v & ~(0xFFFFFFFF << 0)) | (ReadMemory<uint32>(timestamp, address & ~3) << 0);
2110 break;
2111 }
2112 END_OPF;
2113
2114 //
2115 // SWL - Store Word Left
2116 //
2117 BEGIN_OPF(SWL, 0x2A, 0);
2118 ITYPE;
2119
2120 GPR_DEPRES_BEGIN
2121 GPR_DEP(rs);
2122 GPR_DEP(rt);
2123 GPR_DEPRES_END
2124
2125 uint32 address = GPR[rs] + immediate;
2126
2127 switch(address & 0x3)
2128 {
2129 case 0:
2130 WriteMemory<uint8>(timestamp, address & ~3, GPR[rt] >> 24);
2131 break;
2132 case 1:
2133 WriteMemory<uint16>(timestamp, address & ~3, GPR[rt] >> 16);
2134 break;
2135 case 2:
2136 WriteMemory<uint32>(timestamp, address & ~3, GPR[rt] >> 8, true);
2137 break;
2138 case 3:
2139 WriteMemory<uint32>(timestamp, address & ~3, GPR[rt] >> 0);
2140 break;
2141 }
2142 DO_LDS();
2143
2144 END_OPF;
2145
2146 //
2147 // LWR - Load Word Right
2148 //
2149 BEGIN_OPF(LWR, 0x26, 0);
2150 ITYPE;
2151
2152 GPR_DEPRES_BEGIN
2153 GPR_DEP(rs);
2154 //GPR_DEP(rt);
2155 GPR_DEPRES_END
2156
2157 uint32 address = GPR[rs] + immediate;
2158 uint32 v = GPR[rt];
2159
2160 if(LDWhich == rt)
2161 {
2162 v = LDValue;
2163 ReadFudge = 0;
2164 }
2165 else
2166 {
2167 DO_LDS();
2168 }
2169
2170 LDWhich = rt;
2171 switch(address & 0x3)
2172 {
2173 case 0:
2174 LDValue = (v & ~(0xFFFFFFFF)) | ReadMemory<uint32>(timestamp, address);
2175 break;
2176 case 1:
2177 LDValue = (v & ~(0xFFFFFF)) | ReadMemory<uint32>(timestamp, address, true);
2178 break;
2179 case 2:
2180 LDValue = (v & ~(0xFFFF)) | ReadMemory<uint16>(timestamp, address);
2181 break;
2182 case 3:
2183 LDValue = (v & ~(0xFF)) | ReadMemory<uint8>(timestamp, address);
2184 break;
2185 }
2186 END_OPF;
2187
2188 //
2189 // SWR - Store Word Right
2190 //
2191 BEGIN_OPF(SWR, 0x2E, 0);
2192 ITYPE;
2193
2194 GPR_DEPRES_BEGIN
2195 GPR_DEP(rs);
2196 GPR_DEP(rt);
2197 GPR_DEPRES_END
2198
2199 uint32 address = GPR[rs] + immediate;
2200
2201 switch(address & 0x3)
2202 {
2203 case 0:
2204 WriteMemory<uint32>(timestamp, address, GPR[rt]);
2205 break;
2206 case 1:
2207 WriteMemory<uint32>(timestamp, address, GPR[rt], true);
2208 break;
2209 case 2:
2210 WriteMemory<uint16>(timestamp, address, GPR[rt]);
2211 break;
2212 case 3:
2213 WriteMemory<uint8>(timestamp, address, GPR[rt]);
2214 break;
2215 }
2216
2217 DO_LDS();
2218
2219 END_OPF;
2220
2221 //
2222 // Mednafen special instruction
2223 //
2224 BEGIN_OPF(INTERRUPT, 0x3F, 0);
2225 if(Halted)
2226 {
2227 goto SkipNPCStuff;
2228 }
2229 else
2230 {
2231 DO_LDS();
2232
2233 new_PC = Exception(EXCEPTION_INT, PC, new_PC_mask);
2234 new_PC_mask = 0;
2235 }
2236 END_OPF;
2237 }
2238
2239 OpDone: ;
2240
2241 PC = (PC & new_PC_mask) + new_PC;
2242 new_PC_mask = ~0U;
2243 new_PC = 4;
2244
2245 SkipNPCStuff: ;
2246
2247 //printf("\n");
2248 }
2249 } while(MDFN_LIKELY(PSX_EventHandler(timestamp)));
2250
2251 if(gte_ts_done > 0)
2252 gte_ts_done -= timestamp;
2253
2254 if(muldiv_ts_done > 0)
2255 muldiv_ts_done -= timestamp;
2256
2257 ACTIVE_TO_BACKING;
2258
2259 return(timestamp);
2260 }
2261
2262 int32_t PS_CPU::Run(int32_t timestamp_in)
2263 {
2264 #ifdef HAVE_DEBUG
2265 if(CPUHook || ADDBT)
2266 return(RunReal<true>(timestamp_in));
2267 #endif
2268 return(RunReal<false>(timestamp_in));
2269 }
2270
2271 void PS_CPU::SetCPUHook(void (*cpuh)(const int32_t timestamp, uint32_t pc), void (*addbt)(uint32_t from, uint32_t to, bool exception))
2272 {
2273 ADDBT = addbt;
2274 CPUHook = cpuh;
2275 }
2276
2277 uint32_t PS_CPU::GetRegister(unsigned int which, char *special, const uint32_t special_len)
2278 {
2279 if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
2280 return GPR[which];
2281 switch(which)
2282 {
2283 case GSREG_PC:
2284 return BACKED_PC;
2285 case GSREG_PC_NEXT:
2286 return BACKED_new_PC;
2287 case GSREG_IN_BD_SLOT:
2288 return !(BACKED_new_PC_mask & 3);
2289 case GSREG_LO:
2290 return LO;
2291 case GSREG_HI:
2292 return HI;
2293 case GSREG_SR:
2294 return CP0.SR;
2295 case GSREG_CAUSE:
2296 return CP0.CAUSE;
2297 case GSREG_EPC:
2298 return CP0.EPC;
2299 }
2300
2301 return 0;
2302 }
2303
2304 void PS_CPU::SetRegister(unsigned int which, uint32_t value)
2305 {
2306 if(which >= GSREG_GPR && which < (GSREG_GPR + 32))
2307 {
2308 if(which != (GSREG_GPR + 0))
2309 GPR[which] = value;
2310 }
2311 else switch(which)
2312 {
2313 case GSREG_PC:
2314 BACKED_PC = value & ~0x3; // Remove masking if we ever add proper misaligned PC exception
2315 break;
2316
2317 case GSREG_LO:
2318 LO = value;
2319 break;
2320
2321 case GSREG_HI:
2322 HI = value;
2323 break;
2324
2325 case GSREG_SR:
2326 CP0.SR = value; // TODO: mask
2327 break;
2328
2329 case GSREG_CAUSE:
2330 CP0.CAUSE = value;
2331 break;
2332
2333 case GSREG_EPC:
2334 CP0.EPC = value & ~0x3U;
2335 break;
2336 }
2337 }
2338
2339 bool PS_CPU::PeekCheckICache(uint32_t PC, uint32_t *iw)
2340 {
2341 if(ICache[(PC & 0xFFC) >> 2].TV == PC)
2342 {
2343 *iw = ICache[(PC & 0xFFC) >> 2].Data;
2344 return(true);
2345 }
2346
2347 return(false);
2348 }
2349
2350
2351 uint8_t PS_CPU::PeekMem8(uint32_t A)
2352 {
2353 return PeekMemory<uint8>(A);
2354 }
2355
2356 uint16_t PS_CPU::PeekMem16(uint32_t A)
2357 {
2358 return PeekMemory<uint16>(A);
2359 }
2360
2361 uint32_t PS_CPU::PeekMem32(uint32_t A)
2362 {
2363 return PeekMemory<uint32>(A);
2364 }
2365
2366
2367 #undef BEGIN_OPF
2368 #undef END_OPF
2369 #undef MK_OPF
2370
2371 #define MK_OPF(op, funct) ((op) ? (0x40 | (op)) : (funct))
2372 #define BEGIN_OPF(op, funct) case MK_OPF(op, funct): {
2373 #define END_OPF } break;
2374
2375 // FIXME: should we breakpoint on an illegal address? And with LWC2/SWC2 if CP2 isn't enabled?
2376 void PS_CPU::CheckBreakpoints(void (*callback)(bool write, uint32_t address, unsigned int len), uint32_t instr)
2377 {
2378 uint32 opf;
2379
2380 opf = instr & 0x3F;
2381
2382 if(instr & (0x3F << 26))
2383 opf = 0x40 | (instr >> 26);
2384
2385
2386 switch(opf)
2387 {
2388 default:
2389 break;
2390
2391 //
2392 // LB - Load Byte
2393 //
2394 BEGIN_OPF(0x20, 0);
2395 ITYPE;
2396 uint32 address = GPR[rs] + immediate;
2397
2398 callback(false, address, 1);
2399 END_OPF;
2400
2401 //
2402 // LBU - Load Byte Unsigned
2403 //
2404 BEGIN_OPF(0x24, 0);
2405 ITYPE;
2406 uint32 address = GPR[rs] + immediate;
2407
2408 callback(false, address, 1);
2409 END_OPF;
2410
2411 //
2412 // LH - Load Halfword
2413 //
2414 BEGIN_OPF(0x21, 0);
2415 ITYPE;
2416 uint32 address = GPR[rs] + immediate;
2417
2418 callback(false, address, 2);
2419 END_OPF;
2420
2421 //
2422 // LHU - Load Halfword Unsigned
2423 //
2424 BEGIN_OPF(0x25, 0);
2425 ITYPE;
2426 uint32 address = GPR[rs] + immediate;
2427
2428 callback(false, address, 2);
2429 END_OPF;
2430
2431
2432 //
2433 // LW - Load Word
2434 //
2435 BEGIN_OPF(0x23, 0);
2436 ITYPE;
2437 uint32 address = GPR[rs] + immediate;
2438
2439 callback(false, address, 4);
2440 END_OPF;
2441
2442 //
2443 // SB - Store Byte
2444 //
2445 BEGIN_OPF(0x28, 0);
2446 ITYPE;
2447 uint32 address = GPR[rs] + immediate;
2448
2449 callback(true, address, 1);
2450 END_OPF;
2451
2452 //
2453 // SH - Store Halfword
2454 //
2455 BEGIN_OPF(0x29, 0);
2456 ITYPE;
2457 uint32 address = GPR[rs] + immediate;
2458
2459 callback(true, address, 2);
2460 END_OPF;
2461
2462 //
2463 // SW - Store Word
2464 //
2465 BEGIN_OPF(0x2B, 0);
2466 ITYPE;
2467 uint32 address = GPR[rs] + immediate;
2468
2469 callback(true, address, 4);
2470 END_OPF;
2471
2472 //
2473 // LWL - Load Word Left
2474 //
2475 BEGIN_OPF(0x22, 0);
2476 ITYPE;
2477 uint32 address = GPR[rs] + immediate;
2478
2479 do
2480 {
2481 callback(false, address, 1);
2482 } while((address--) & 0x3);
2483
2484 END_OPF;
2485
2486 //
2487 // SWL - Store Word Left
2488 //
2489 BEGIN_OPF(0x2A, 0);
2490 ITYPE;
2491 uint32 address = GPR[rs] + immediate;
2492
2493 do
2494 {
2495 callback(true, address, 1);
2496 } while((address--) & 0x3);
2497
2498 END_OPF;
2499
2500 //
2501 // LWR - Load Word Right
2502 //
2503 BEGIN_OPF(0x26, 0);
2504 ITYPE;
2505 uint32 address = GPR[rs] + immediate;
2506
2507 do
2508 {
2509 callback(false, address, 1);
2510 } while((++address) & 0x3);
2511
2512 END_OPF;
2513
2514 //
2515 // SWR - Store Word Right
2516 //
2517 BEGIN_OPF(0x2E, 0);
2518 ITYPE;
2519 uint32 address = GPR[rs] + immediate;
2520
2521 do
2522 {
2523 callback(true, address, 1);
2524 } while((++address) & 0x3);
2525
2526 END_OPF;
2527
2528 //
2529 // LWC2
2530 //
2531 BEGIN_OPF(0x32, 0);
2532 ITYPE;
2533 uint32 address = GPR[rs] + immediate;
2534
2535 callback(false, address, 4);
2536 END_OPF;
2537
2538 //
2539 // SWC2
2540 //
2541 BEGIN_OPF(0x3A, 0);
2542 ITYPE;
2543 uint32 address = GPR[rs] + immediate;
2544
2545 callback(true, address, 4);
2546 END_OPF;
2547
2548 }
2549 }
0 #ifndef __MDFN_PSX_CPU_H
1 #define __MDFN_PSX_CPU_H
2
3 #include "gte.h"
4
5 #define PS_CPU_EMULATE_ICACHE 1
6
7 #define FAST_MAP_SHIFT 16
8 #define FAST_MAP_PSIZE (1 << FAST_MAP_SHIFT)
9
10 #define CP0REG_BPC 3 /* PC breakpoint address */
11 #define CP0REG_BDA 5 /* Data load/store breakpoint address */
12 #define CP0REG_TAR 6 /* Target address */
13 #define CP0REG_DCIC 7 /* Cache control */
14 #define CP0REG_BDAM 9 /* Data load/store address mask */
15 #define CP0REG_BPCM 11 /* PC breakpoint address mask */
16 #define CP0REG_SR 12
17 #define CP0REG_CAUSE 13
18 #define CP0REG_EPC 14
19 #define CP0REG_PRID 15 /* Product ID */
20 #define CP0REG_ERREG 16
21
22 #define EXCEPTION_INT 0
23 #define EXCEPTION_MOD 1
24 #define EXCEPTION_TLBL 2
25 #define EXCEPTION_TLBS 3
26 #define EXCEPTION_ADEL 4 /* Address error on load */
27 #define EXCEPTION_ADES 5 /* Address error on store */
28 #define EXCEPTION_IBE 6 /* Instruction bus error */
29 #define EXCEPTION_DBE 7 /* Data bus error */
30 #define EXCEPTION_SYSCALL 8 /* System call */
31 #define EXCEPTION_BP 9 /* Breakpoint */
32 #define EXCEPTION_RI 10 /* Reserved instruction */
33 #define EXCEPTION_COPU 11 /* Coprocessor unusable */
34 #define EXCEPTION_OV 12 /* Arithmetic overflow */
35
36 #define GSREG_GPR 0
37 #define GSREG_PC 32
38 #define GSREG_PC_NEXT 33
39 #define GSREG_IN_BD_SLOT 34
40 #define GSREG_LO 35
41 #define GSREG_HI 36
42 #define GSREG_SR 37
43 #define GSREG_CAUSE 38
44 #define GSREG_EPC 39
45
46 class PS_CPU
47 {
48 public:
49
50 PS_CPU();
51 ~PS_CPU();
52
53 void SetFastMap(void *region_mem, uint32_t region_address, uint32_t region_size);
54
55 INLINE void SetEventNT(const int32_t next_event_ts_arg)
56 {
57 next_event_ts = next_event_ts_arg;
58 }
59
60 int32_t Run(int32_t timestamp_in);
61
62 void Power(void);
63
64 // which ranges 0-5, inclusive
65 void AssertIRQ(unsigned which, bool asserted);
66
67 void SetHalt(bool status);
68
69 // TODO eventually: factor BIU address decoding directly in the CPU core somehow without hurting speed.
70 void SetBIU(uint32_t val);
71 uint32_t GetBIU(void);
72
73 int StateAction(StateMem *sm, int load, int data_only);
74
75 private:
76
77 uint32_t GPR[32 + 1]; // GPR[32] Used as dummy in load delay simulation(indexing past the end of real GPR)
78 uint32_t LO;
79 uint32_t HI;
80
81
82 uint32_t BACKED_PC;
83 uint32_t BACKED_new_PC;
84 uint32_t BACKED_new_PC_mask;
85
86 uint32_t IPCache;
87 void RecalcIPCache(void);
88 bool Halted;
89
90 uint32_t BACKED_LDWhich;
91 uint32_t BACKED_LDValue;
92 uint32_t LDAbsorb;
93
94 int32_t next_event_ts;
95 int32_t gte_ts_done;
96 int32_t muldiv_ts_done;
97
98 uint32_t BIU;
99
100 struct __ICache
101 {
102 uint32_t TV;
103 uint32_t Data;
104 };
105
106 union
107 {
108 __ICache ICache[1024];
109 uint32_t ICache_Bulk[2048];
110 };
111
112
113 struct
114 {
115 union
116 {
117 uint32_t Regs[32];
118 struct
119 {
120 uint32_t Unused00;
121 uint32_t Unused01;
122 uint32_t Unused02;
123 uint32_t BPC; // RW
124 uint32_t Unused04;
125 uint32_t BDA; // RW
126 uint32_t TAR;
127 uint32_t DCIC; // RW
128 uint32_t Unused08;
129 uint32_t BDAM; // R/W
130 uint32_t Unused0A;
131 uint32_t BPCM; // R/W
132 uint32_t SR; // R/W
133 uint32_t CAUSE; // R/W(partial)
134 uint32_t EPC; // R
135 uint32_t PRID; // R
136 uint32_t ERREG; // ?(may not exist, test)
137 };
138 };
139 } CP0;
140
141 uint8_t ReadAbsorb[0x20 + 1];
142 uint8_t ReadAbsorbWhich;
143 uint8_t ReadFudge;
144
145 uint8 MULT_Tab24[24];
146
147 MultiAccessSizeMem<1024, uint32, false> ScratchRAM;
148
149 uint8_t *FastMap[1 << (32 - FAST_MAP_SHIFT)];
150 uint8_t DummyPage[FAST_MAP_PSIZE];
151
152
153 uint32_t Exception(uint32_t code, uint32_t PC, const uint32_t NPM) MDFN_WARN_UNUSED_RESULT;
154
155 template<bool DebugMode> int32_t RunReal(int32_t timestamp_in);
156
157 template<typename T> T PeekMemory(uint32_t address) MDFN_COLD;
158 template<typename T> T ReadMemory(int32_t &timestamp, uint32_t address, bool DS24 = false, bool LWC_timing = false);
159 template<typename T> void WriteMemory(int32_t &timestamp, uint32_t address, uint32_t value, bool DS24 = false);
160
161 // Mednafen debugger stuff follows:
162 public:
163 void SetCPUHook(void (*cpuh)(const int32_t timestamp, uint32_t pc), void (*addbt)(uint32_t from, uint32_t to, bool exception));
164 void CheckBreakpoints(void (*callback)(bool write, uint32_t address, unsigned int len), uint32_t instr);
165
166
167 uint32_t GetRegister(unsigned int which, char *special, const uint32_t special_len);
168 void SetRegister(unsigned int which, uint32_t value);
169 bool PeekCheckICache(uint32_t PC, uint32_t *iw);
170 uint8_t PeekMem8(uint32_t A);
171 uint16_t PeekMem16(uint32_t A);
172 uint32_t PeekMem32(uint32_t A);
173 private:
174 void (*CPUHook)(const int32_t timestamp, uint32_t pc);
175 void (*ADDBT)(uint32_t from, uint32_t to, bool exception);
176 };
177
178 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "timer.h"
19 #include "cdc.h"
20 #include "spu.h"
21
22 extern PS_GPU *GPU;
23 extern PS_SPU *SPU;
24
25 static void RedoCPUHook(void);
26
27 static void (*CPUHook)(uint32, bool) = NULL;
28 static bool CPUHookContinuous = false;
29
30 struct PSX_BPOINT
31 {
32 uint32 A[2];
33 int type;
34 };
35
36 static std::vector<PSX_BPOINT> BreakPointsPC, BreakPointsRead, BreakPointsWrite;
37 static bool FoundBPoint;
38
39 static bool BTEnabled;
40 static int BTIndex;
41
42 struct BTEntry
43 {
44 uint32 from;
45 uint32 to;
46 uint32 branch_count;
47 bool exception;
48 bool valid;
49 };
50
51 #define NUMBT 24
52 static BTEntry BTEntries[NUMBT];
53
54 void DBG_Break(void)
55 {
56 FoundBPoint = true;
57 }
58
59 static void AddBranchTrace(uint32 from, uint32 to, bool exception)
60 {
61 BTEntry *prevbt = &BTEntries[(BTIndex + NUMBT - 1) % NUMBT];
62
63 //if(BTEntries[(BTIndex - 1) & 0xF] == PC) return;
64
65 if(prevbt->from == from && prevbt->to == to && prevbt->exception == exception && prevbt->branch_count < 0xFFFFFFFF && prevbt->valid)
66 prevbt->branch_count++;
67 else
68 {
69 BTEntries[BTIndex].from = from;
70 BTEntries[BTIndex].to = to;
71 BTEntries[BTIndex].exception = exception;
72 BTEntries[BTIndex].branch_count = 1;
73 BTEntries[BTIndex].valid = true;
74
75 BTIndex = (BTIndex + 1) % NUMBT;
76 }
77 }
78
79 static void EnableBranchTrace(bool enable)
80 {
81 BTEnabled = enable;
82 if(!enable)
83 {
84 BTIndex = 0;
85 memset(BTEntries, 0, sizeof(BTEntries));
86 }
87 RedoCPUHook();
88 }
89
90 static std::vector<BranchTraceResult> GetBranchTrace(void)
91 {
92 BranchTraceResult tmp;
93 std::vector<BranchTraceResult> ret;
94
95 for(int x = 0; x < NUMBT; x++)
96 {
97 const BTEntry *bt = &BTEntries[(x + BTIndex) % NUMBT];
98
99 tmp.count = bt->branch_count;
100 snprintf(tmp.from, sizeof(tmp.from), "%08x", bt->from);
101 snprintf(tmp.to, sizeof(tmp.to), "%08x", bt->to);
102 snprintf(tmp.code, sizeof(tmp.code), "%s", bt->exception ? "e" : "");
103
104 ret.push_back(tmp);
105 }
106 return(ret);
107 }
108
109 void CheckCPUBPCallB(bool write, uint32 address, unsigned int len)
110 {
111 std::vector<PSX_BPOINT>::iterator bpit;
112 std::vector<PSX_BPOINT>::iterator bpit_end;
113
114 if(write)
115 {
116 bpit = BreakPointsWrite.begin();
117 bpit_end = BreakPointsWrite.end();
118 }
119 else
120 {
121 bpit = BreakPointsRead.begin();
122 bpit_end = BreakPointsRead.end();
123 }
124
125 while(bpit != bpit_end)
126 {
127 if(address >= bpit->A[0] && address <= bpit->A[1])
128 {
129 FoundBPoint = true;
130 break;
131 }
132 bpit++;
133 }
134 }
135
136 static void CPUHandler(const int32_t timestamp, uint32 PC)
137 {
138 std::vector<PSX_BPOINT>::iterator bpit;
139
140 for(bpit = BreakPointsPC.begin(); bpit != BreakPointsPC.end(); bpit++)
141 {
142 if(PC >= bpit->A[0] && PC <= bpit->A[1])
143 {
144 FoundBPoint = true;
145 break;
146 }
147 }
148
149 CPU->CheckBreakpoints(CheckCPUBPCallB, CPU->PeekMem32(PC));
150
151 CPUHookContinuous |= FoundBPoint;
152
153 if(CPUHookContinuous && CPUHook)
154 {
155 ForceEventUpdates(timestamp);
156 CPUHook(PC, FoundBPoint);
157 }
158
159 FoundBPoint = false;
160 }
161
162
163 static void RedoCPUHook(void)
164 {
165 const bool HappyTest = CPUHook || BreakPointsPC.size() || BreakPointsRead.size() || BreakPointsWrite.size();
166
167 CPU->SetCPUHook(HappyTest ? CPUHandler : NULL, BTEnabled ? AddBranchTrace : NULL);
168 }
169
170 static void FlushBreakPoints(int type)
171 {
172 if(type == BPOINT_READ)
173 BreakPointsRead.clear();
174 else if(type == BPOINT_WRITE)
175 BreakPointsWrite.clear();
176 else if(type == BPOINT_PC)
177 BreakPointsPC.clear();
178
179 RedoCPUHook();
180 }
181
182 static void AddBreakPoint(int type, unsigned int A1, unsigned int A2, bool logical)
183 {
184 PSX_BPOINT tmp;
185
186 tmp.A[0] = A1;
187 tmp.A[1] = A2;
188 tmp.type = type;
189
190 if(type == BPOINT_READ)
191 BreakPointsRead.push_back(tmp);
192 else if(type == BPOINT_WRITE)
193 BreakPointsWrite.push_back(tmp);
194 else if(type == BPOINT_PC)
195 BreakPointsPC.push_back(tmp);
196
197 RedoCPUHook();
198 }
199
200 static void SetCPUCallback(void (*callb)(uint32 PC, bool bpoint), bool continuous)
201 {
202 CPUHook = callb;
203 CPUHookContinuous = continuous;
204 RedoCPUHook();
205 }
206
207 static void GetAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint8 *Buffer)
208 {
209 if(!strcmp(name, "cpu"))
210 {
211 while(Length--)
212 {
213 Address &= 0xFFFFFFFF;
214 *Buffer = CPU->PeekMem8(Address);
215 Address++;
216 Buffer++;
217 }
218 }
219 else if(!strcmp(name, "ram"))
220 {
221 while(Length--)
222 {
223 Address &= 0x1FFFFF;
224 *Buffer = CPU->PeekMem8(Address);
225 Address++;
226 Buffer++;
227 }
228 }
229 else if(!strcmp(name, "spu"))
230 {
231 while(Length--)
232 {
233 Address &= 0x7FFFF;
234 *Buffer = SPU->PeekSPURAM(Address >> 1) >> ((Address & 1) * 8);
235 Address++;
236 Buffer++;
237 }
238 }
239 else if(!strcmp(name, "gpu"))
240 {
241 while(Length--)
242 {
243 Address &= 0xFFFFF;
244 *Buffer = GPU->PeekRAM(Address >> 1) >> ((Address & 1) * 8);
245 Address++;
246 Buffer++;
247 }
248 }
249 }
250
251
252 static void PutAddressSpaceBytes(const char *name, uint32 Address, uint32 Length, uint32 Granularity, bool hl, const uint8 *Buffer)
253 {
254 if(!strcmp(name, "cpu"))
255 {
256 while(Length--)
257 {
258 int32_t dummy = 0;
259 Address &= 0xFFFFFFFF;
260
261 // TODO
262 PSX_MemWrite8(dummy, Address, *Buffer);
263
264 Address++;
265 Buffer++;
266 }
267 }
268 else if(!strcmp(name, "gpu"))
269 {
270 while(Length--)
271 {
272 Address &= 0xFFFFF;
273
274 uint16 peeko = GPU->PeekRAM(Address >> 1);
275
276 GPU->PokeRAM(Address >> 1, (*Buffer << ((Address & 1) * 8)) | (peeko & (0xFF00 >> ((Address & 1) * 8))) );
277 Address++;
278 Buffer++;
279 }
280 }
281 else if(!strcmp(name, "spu"))
282 {
283 while(Length--)
284 {
285 Address &= 0x7FFFF;
286
287 uint16 peeko = SPU->PeekSPURAM(Address >> 1);
288
289 SPU->PokeSPURAM(Address >> 1, (*Buffer << ((Address & 1) * 8)) | (peeko & (0xFF00 >> ((Address & 1) * 8))) );
290 Address++;
291 Buffer++;
292 }
293 }
294
295 }
296
297 static uint32 MemPeek(uint32 A, unsigned int bsize, bool hl, bool logical)
298 {
299 uint32 ret = 0;
300
301 for(unsigned int i = 0; i < bsize; i++)
302 ret |= CPU->PeekMem8(A + i) << (i * 8);
303
304 return(ret);
305 }
306
307 static void Disassemble(uint32 &A, uint32 SpecialA, char *TextBuf)
308 {
309 assert(!(A & 0x3));
310
311 uint32 instr = CPU->PeekMem32(A);
312
313 CPU->PeekCheckICache(A, &instr);
314
315 strncpy(TextBuf, DisassembleMIPS(A, instr).c_str(), 256);
316 TextBuf[255] = 0;
317
318 // snprintf(TextBuf, 256, "0x%08x", instr);
319
320 A += 4;
321 }
322
323 static MDFN_Surface *GfxDecode_Buf = NULL;
324 static int GfxDecode_Line = -1;
325 static int GfxDecode_Layer = 0;
326 static int GfxDecode_Scroll = 0;
327 static int GfxDecode_PBN = 0;
328
329 static void DoGfxDecode(void)
330 {
331 unsigned tp_w, tp_h;
332
333 tp_w = 256;
334 tp_h = 256;
335
336 if(GfxDecode_Buf)
337 {
338 for(int sy = 0; sy < GfxDecode_Buf->h; sy++)
339 {
340 for(int sx = 0; sx < GfxDecode_Buf->w; sx++)
341 {
342 unsigned fb_x = ((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) & 1023;
343 unsigned fb_y = (((sy + GfxDecode_Scroll) % GfxDecode_Buf->w) + ((((sx % GfxDecode_Buf->w) + ((sy + GfxDecode_Scroll) / GfxDecode_Buf->w * GfxDecode_Buf->w)) / 1024) * 256)) & 511;
344
345 uint16 pixel = GPU->PeekRAM(fb_y * 1024 + fb_x);
346
347 GfxDecode_Buf->pixels[(sy * GfxDecode_Buf->w * 3) + sx] = GfxDecode_Buf->MakeColor(((pixel >> 0) & 0x1F) * 255 / 31,
348 ((pixel >> 5) & 0x1F) * 255 / 31,
349 ((pixel >> 10) & 0x1F) * 255 / 31, 0xFF);
350 }
351 }
352 }
353 }
354
355
356 void DBG_GPUScanlineHook(unsigned scanline)
357 {
358 if((int)scanline == GfxDecode_Line)
359 {
360 DoGfxDecode();
361 }
362 }
363
364
365 static void SetGraphicsDecode(MDFN_Surface *surface, int line, int which, int xscroll, int yscroll, int pbn)
366 {
367 GfxDecode_Buf = surface;
368 GfxDecode_Line = line;
369 GfxDecode_Layer = which;
370 GfxDecode_Scroll = yscroll;
371 GfxDecode_PBN = pbn;
372
373 if(GfxDecode_Buf && GfxDecode_Line == -1)
374 DoGfxDecode();
375 }
376
377 DebuggerInfoStruct PSX_DBGInfo =
378 {
379 "shift_jis",
380 4, // Max instruction byte size
381 4, // Instruction alignment(bytes)
382 32, // Logical address bits
383 32, // Physical address bits
384 0x00000000, // Default watch addr
385 ~0U, // ZP addr
386
387 MemPeek,
388 Disassemble,
389 NULL,
390 NULL, //ForceIRQ,
391 NULL, //NESDBG_GetVector,
392 FlushBreakPoints,
393 AddBreakPoint,
394 SetCPUCallback,
395 EnableBranchTrace,
396 GetBranchTrace,
397 SetGraphicsDecode,
398 NULL, //PCFXDBG_SetLogFunc,
399 };
400
401 static RegType Regs_Misc[] =
402 {
403 { TIMER_GSREG_COUNTER0, "COUNT0", "Counter 0", 2 },
404 { TIMER_GSREG_MODE0, "MODE0", "Mode 0", 2 },
405 { TIMER_GSREG_TARGET0, "TARGET0", "Target 0", 2 },
406
407 { 0, "------", "", 0xFFFF },
408
409
410 { TIMER_GSREG_COUNTER1, "COUNT1", "Counter 1", 2 },
411 { TIMER_GSREG_MODE1, "MODE1", "Mode 1", 2 },
412 { TIMER_GSREG_TARGET1, "TARGET1", "Target 1", 2 },
413
414 { 0, "------", "", 0xFFFF },
415
416 { TIMER_GSREG_COUNTER2, "COUNT2", "Counter 2", 2 },
417 { TIMER_GSREG_MODE2, "MODE2", "Mode 2", 2 },
418 { TIMER_GSREG_TARGET2, "TARGET2", "Target 2", 2 },
419
420 { 0, "------", "", 0xFFFF },
421 { 0, "------", "", 0xFFFF },
422
423 { 0x10000 | IRQ_GSREG_ASSERTED, "ASSERTD", "IRQ Asserted", 2 },
424 { 0x10000 | IRQ_GSREG_STATUS, "STATUS", "IRQ Status", 2 },
425 { 0x10000 | IRQ_GSREG_MASK, "MASK", "IRQ Mask", 2 },
426
427 { 0, "", "", 0 }
428 };
429
430
431 static uint32 GetRegister_Misc(const unsigned int id, char *special, const uint32 special_len)
432 {
433 if(id & 0x10000)
434 return(IRQ_GetRegister(id & 0xFFFF, special, special_len));
435 else
436 return(TIMER_GetRegister(id & 0xFFFF, special, special_len));
437 }
438
439 static void SetRegister_Misc(const unsigned int id, uint32 value)
440 {
441 if(id & 0x10000)
442 IRQ_SetRegister(id & 0xFFFF, value);
443 else
444 TIMER_SetRegister(id & 0xFFFF, value);
445 }
446
447 static RegGroupType MiscRegsGroup =
448 {
449 NULL,
450 Regs_Misc,
451 GetRegister_Misc,
452 SetRegister_Misc
453 };
454
455 static RegType Regs_SPU[] =
456 {
457 { PS_SPU::GSREG_SPUCONTROL, "SPUCTRL", "SPU Control", 2 },
458
459 { PS_SPU::GSREG_FM_ON, "FMOn", "FM Enable", 3 },
460 { PS_SPU::GSREG_NOISE_ON, "NoiseOn", "Noise Enable", 3 },
461 { PS_SPU::GSREG_REVERB_ON, "ReverbOn", "Reverb Enable", 3 },
462
463 { PS_SPU::GSREG_CDVOL_L, "CDVolL", "CD Volume Left", 2 },
464 { PS_SPU::GSREG_CDVOL_R, "CDVolR", "CD Volume Right", 2 },
465
466 { PS_SPU::GSREG_DRYVOL_CTRL_L, "DryVolCL", "Dry Volume Control Left", 2 },
467 { PS_SPU::GSREG_DRYVOL_CTRL_R, "DryVolCR", "Dry Volume Control Right", 2 },
468
469 { PS_SPU::GSREG_DRYVOL_L, "DryVolL", "Dry Volume Left", 2 },
470 { PS_SPU::GSREG_DRYVOL_R, "DryVolR", "Dry Volume Right", 2 },
471
472 { PS_SPU::GSREG_WETVOL_L, "WetVolL", "Wet Volume Left", 2 },
473 { PS_SPU::GSREG_WETVOL_R, "WetVolR", "Wet Volume Right", 2 },
474
475 { PS_SPU::GSREG_RWADDR, "RWAddr", "SPURAM Read/Write Address", 3 },
476
477 { PS_SPU::GSREG_IRQADDR, "IRQAddr", "IRQ Compare Address", 3 },
478
479 { PS_SPU::GSREG_REVERBWA, "ReverbWA", "Reverb Work Area(Raw)", 2 },
480
481 { PS_SPU::GSREG_VOICEON, "VoiceOn", "Voice On", 3 },
482 { PS_SPU::GSREG_VOICEOFF, "VoiceOff", "Voice Off", 3 },
483 { PS_SPU::GSREG_BLOCKEND, "BlockEnd", "Block End", 3 },
484
485
486 { 0, "------", "", 0xFFFF },
487
488 { PS_SPU::GSREG_FB_SRC_A, "FB_SRC_A", "", 2 },
489 { PS_SPU::GSREG_FB_SRC_B, "FB_SRC_B", "", 2 },
490 { PS_SPU::GSREG_IIR_ALPHA, "IIR_ALPHA", "", 2 },
491 { PS_SPU::GSREG_ACC_COEF_A, "ACC_COEF_A", "", 2 },
492 { PS_SPU::GSREG_ACC_COEF_B, "ACC_COEF_B", "", 2 },
493 { PS_SPU::GSREG_ACC_COEF_C, "ACC_COEF_C", "", 2 },
494 { PS_SPU::GSREG_ACC_COEF_D, "ACC_COEF_D", "", 2 },
495 { PS_SPU::GSREG_IIR_COEF, "IIR_COEF", "", 2 },
496 { PS_SPU::GSREG_FB_ALPHA, "FB_ALPHA", "", 2 },
497 { PS_SPU::GSREG_FB_X, "FB_X", "", 2 },
498 { PS_SPU::GSREG_IIR_DEST_A0, "IIR_DST_A0", "", 2 },
499 { PS_SPU::GSREG_IIR_DEST_A1, "IIR_DST_A1", "", 2 },
500 { PS_SPU::GSREG_ACC_SRC_A0, "ACC_SRC_A0", "", 2 },
501 { PS_SPU::GSREG_ACC_SRC_A1, "ACC_SRC_A1", "", 2 },
502 { PS_SPU::GSREG_ACC_SRC_B0, "ACC_SRC_B0", "", 2 },
503 { PS_SPU::GSREG_ACC_SRC_B1, "ACC_SRC_B1", "", 2 },
504 { PS_SPU::GSREG_IIR_SRC_A0, "IIR_SRC_A0", "", 2 },
505 { PS_SPU::GSREG_IIR_SRC_A1, "IIR_SRC_A1", "", 2 },
506 { PS_SPU::GSREG_IIR_DEST_B0, "IIR_DST_B0", "", 2 },
507 { PS_SPU::GSREG_IIR_DEST_B1, "IIR_DST_B1", "", 2 },
508 { PS_SPU::GSREG_ACC_SRC_C0, "ACC_SRC_C0", "", 2 },
509 { PS_SPU::GSREG_ACC_SRC_C1, "ACC_SRC_C1", "", 2 },
510 { PS_SPU::GSREG_ACC_SRC_D0, "ACC_SRC_D0", "", 2 },
511 { PS_SPU::GSREG_ACC_SRC_D1, "ACC_SRC_D1", "", 2 },
512 { PS_SPU::GSREG_IIR_SRC_B1, "IIR_SRC_B1", "", 2 },
513 { PS_SPU::GSREG_IIR_SRC_B0, "IIR_SRC_B0", "", 2 },
514 { PS_SPU::GSREG_MIX_DEST_A0, "MIX_DST_A0", "", 2 },
515 { PS_SPU::GSREG_MIX_DEST_A1, "MIX_DST_A1", "", 2 },
516 { PS_SPU::GSREG_MIX_DEST_B0, "MIX_DST_B0", "", 2 },
517 { PS_SPU::GSREG_MIX_DEST_B1, "MIX_DST_B1", "", 2 },
518 { PS_SPU::GSREG_IN_COEF_L, "IN_COEF_L", "", 2 },
519 { PS_SPU::GSREG_IN_COEF_R, "IN_COEF_R", "", 2 },
520
521 { 0, "", "", 0 },
522 };
523
524 #define VOICE_HELPER(v) \
525 { 0, "--V"#v"--", "", 0xFFFF }, \
526 { PS_SPU:: GSREG_V0_VOL_CTRL_L + v * 256, "VolCL", "Volume Control Left", 2 }, \
527 { PS_SPU:: GSREG_V0_VOL_CTRL_R + v * 256, "VolCR", "Volume Control Right", 2 }, \
528 { PS_SPU:: GSREG_V0_VOL_L + v * 256, "VolL", "Volume Left", 2 }, \
529 { PS_SPU:: GSREG_V0_VOL_R + v * 256, "VolR", "Volume Right", 2 }, \
530 { PS_SPU:: GSREG_V0_PITCH + v * 256, "Pitch", "Pitch", 2 }, \
531 { PS_SPU:: GSREG_V0_STARTADDR + v * 256, "SAddr", "Start Address", 3 }, \
532 { PS_SPU:: GSREG_V0_ADSR_CTRL + v * 256, "ADSRCTRL", "ADSR Control", 4 }, \
533 { PS_SPU:: GSREG_V0_ADSR_LEVEL + v * 256, "ADSRLev", "ADSR Level", 2 }, \
534 { PS_SPU:: GSREG_V0_LOOP_ADDR + v * 256, "LAddr", "Loop Address", 3 }, \
535 { PS_SPU:: GSREG_V0_READ_ADDR + v * 256, "RAddr", "Read Address", 3 }
536
537
538 static RegType Regs_SPU_Voices[] =
539 {
540 #if 1
541 VOICE_HELPER(0),
542 VOICE_HELPER(1),
543 VOICE_HELPER(2),
544 VOICE_HELPER(3),
545 #else
546 VOICE_HELPER(9),
547 VOICE_HELPER(12),
548 VOICE_HELPER(17),
549 VOICE_HELPER(22),
550
551 //VOICE_HELPER(20),
552 //VOICE_HELPER(21),
553 //VOICE_HELPER(22),
554 //VOICE_HELPER(23),
555 #endif
556 { 0, "", "", 0 },
557 };
558
559
560 static uint32 GetRegister_SPU(const unsigned int id, char *special, const uint32 special_len)
561 {
562 return(SPU->GetRegister(id, special, special_len));
563 }
564
565 static void SetRegister_SPU(const unsigned int id, uint32 value)
566 {
567 SPU->SetRegister(id, value);
568 }
569
570 static RegGroupType SPURegsGroup =
571 {
572 NULL,
573 Regs_SPU,
574 GetRegister_SPU,
575 SetRegister_SPU
576 };
577
578
579 static RegGroupType SPUVoicesRegsGroup =
580 {
581 NULL,
582 Regs_SPU_Voices,
583 GetRegister_SPU,
584 SetRegister_SPU
585 };
586
587 static RegType Regs_CPU[] =
588 {
589 { PS_CPU::GSREG_PC, "PC", "PC", 4 },
590 { PS_CPU::GSREG_PC_NEXT, "NPC", "Next PC", 4 },
591 { PS_CPU::GSREG_IN_BD_SLOT, "INBD", "In Branch Delay Slot", 1 },
592 { 0, "------", "", 0xFFFF },
593 { PS_CPU::GSREG_GPR + 1, "at", "Assembler Temporary", 4 },
594 { PS_CPU::GSREG_GPR + 2, "v0", "Return Value 0", 4 },
595 { PS_CPU::GSREG_GPR + 3, "v1", "Return Value 1", 4 },
596 { PS_CPU::GSREG_GPR + 4, "a0", "Argument 0", 4 },
597 { PS_CPU::GSREG_GPR + 5, "a1", "Argument 1", 4 },
598 { PS_CPU::GSREG_GPR + 6, "a2", "Argument 2", 4 },
599 { PS_CPU::GSREG_GPR + 7, "a3", "Argument 3", 4 },
600 { PS_CPU::GSREG_GPR + 8, "t0", "Temporary 0", 4 },
601 { PS_CPU::GSREG_GPR + 9, "t1", "Temporary 1", 4 },
602 { PS_CPU::GSREG_GPR + 10, "t2", "Temporary 2", 4 },
603 { PS_CPU::GSREG_GPR + 11, "t3", "Temporary 3", 4 },
604 { PS_CPU::GSREG_GPR + 12, "t4", "Temporary 4", 4 },
605 { PS_CPU::GSREG_GPR + 13, "t5", "Temporary 5", 4 },
606 { PS_CPU::GSREG_GPR + 14, "t6", "Temporary 6", 4 },
607 { PS_CPU::GSREG_GPR + 15, "t7", "Temporary 7", 4 },
608 { PS_CPU::GSREG_GPR + 16, "s0", "Subroutine Reg Var 0", 4 },
609 { PS_CPU::GSREG_GPR + 17, "s1", "Subroutine Reg Var 1", 4 },
610 { PS_CPU::GSREG_GPR + 18, "s2", "Subroutine Reg Var 2", 4 },
611 { PS_CPU::GSREG_GPR + 19, "s3", "Subroutine Reg Var 3", 4 },
612 { PS_CPU::GSREG_GPR + 20, "s4", "Subroutine Reg Var 4", 4 },
613 { PS_CPU::GSREG_GPR + 21, "s5", "Subroutine Reg Var 5", 4 },
614 { PS_CPU::GSREG_GPR + 22, "s6", "Subroutine Reg Var 6", 4 },
615 { PS_CPU::GSREG_GPR + 23, "s7", "Subroutine Reg Var 7", 4 },
616 { PS_CPU::GSREG_GPR + 24, "t8", "Temporary 8", 4 },
617 { PS_CPU::GSREG_GPR + 25, "t9", "Temporary 9", 4 },
618 { PS_CPU::GSREG_GPR + 26, "k0", "Interrupt/Trap Handler Reg 0", 4 },
619 { PS_CPU::GSREG_GPR + 27, "k1", "Interrupt/Trap Handler Reg 1", 4 },
620 { PS_CPU::GSREG_GPR + 28, "gp", "Global Pointer", 4 },
621 { PS_CPU::GSREG_GPR + 29, "sp", "Stack Pointer", 4 },
622 { PS_CPU::GSREG_GPR + 30, "s8", "Subroutine Reg Var 8/Frame Pointer", 4 },
623 { PS_CPU::GSREG_GPR + 31, "ra", "Return Address", 4 },
624 { 0, "------", "", 0xFFFF },
625
626 { PS_CPU::GSREG_SR, "SR", "Status Register", 4 },
627 { PS_CPU::GSREG_CAUSE, "CAU","Cause Register", 4 },
628 { PS_CPU::GSREG_EPC, "EPC", "EPC Register", 4 },
629 { 0, "", "", 0 }
630 };
631
632 static uint32 GetRegister_CPU(const unsigned int id, char *special, const uint32 special_len)
633 {
634 return(CPU->GetRegister(id, special, special_len));
635 }
636
637 static void SetRegister_CPU(const unsigned int id, uint32 value)
638 {
639 CPU->SetRegister(id, value);
640 }
641
642 static RegGroupType CPURegsGroup =
643 {
644 NULL,
645 Regs_CPU,
646 GetRegister_CPU,
647 SetRegister_CPU
648 };
649
650 bool DBG_Init(void)
651 {
652 CPUHook = NULL;
653 CPUHookContinuous = false;
654 FoundBPoint = false;
655
656 BTEnabled = false;
657 BTIndex = false;
658 memset(BTEntries, 0, sizeof(BTEntries));
659
660 MDFNDBG_AddRegGroup(&CPURegsGroup);
661 MDFNDBG_AddRegGroup(&MiscRegsGroup);
662 MDFNDBG_AddRegGroup(&SPURegsGroup);
663 MDFNDBG_AddRegGroup(&SPUVoicesRegsGroup);
664 ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "cpu", "CPU Physical", 32);
665 ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "ram", "CPU Main Ram", 21);
666 ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "spu", "SPU RAM", 19);
667 ASpace_Add(GetAddressSpaceBytes, PutAddressSpaceBytes, "gpu", "GPU RAM", 20);
668 return(true);
669 }
0 #ifndef __MDFN_PSX_DEBUG_H
1 #define __MDFN_PSX_DEBUG_H
2
3 #ifdef WANT_DEBUGGER
4
5 extern DebuggerInfoStruct PSX_DBGInfo;
6
7 bool DBG_Init(void);
8
9 void DBG_Break(void);
10
11 void DBG_GPUScanlineHook(unsigned scanline);
12
13 #endif
14
15 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18
19 struct OpEntry
20 {
21 uint32 mask;
22 uint32 value;
23 const char *mnemonic;
24 const char *format;
25 };
26
27 #define MASK_OP (0x3FU << 26)
28 #define MASK_FUNC (0x3FU)
29 #define MASK_RS (0x1FU << 21)
30 #define MASK_RT (0x1FU << 16)
31 #define MASK_RD (0x1FU << 11)
32 #define MASK_SA (0x1FU << 6)
33
34 #define MK_OP(mnemonic, format, op, func, extra_mask) { MASK_OP | (op ? 0 : MASK_FUNC) | extra_mask, ((unsigned)op << 26) | func, mnemonic, format }
35
36 #define MK_OP_REGIMM(mnemonic, regop_mask, regop) { MASK_OP | (regop_mask << 16), (0x01U << 26) | (regop << 16), mnemonic, "s, p" }
37
38
39 #define MK_COPZ(z) { MASK_OP | (0x1U << 25), (0x1U << 25) | ((0x10U | z) << 26), "cop" #z, "F" }
40 #define MK_COP0_FUNC(mnemonic, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x10U << 26) | (0x1U << 25) | func, mnemonic, "" }
41
42 #define MK_COPZ_XFER(z, mnemonic, format, xf) { MASK_OP | (0x1FU << 21), ((0x10U | z) << 26) | (xf << 21), mnemonic, format }
43 #define MK_COPZ_BCzx(z, x) { MASK_OP | (0x1BU << 21) | (0x01 << 16), ((0x10U | z) << 26) | (0x08 << 21) | (x << 16), (x ? "bc" #z "t" : "bc" #z "f"), "p" }
44 #define MK_COPZ_BC(z) MK_COPZ_BCzx(z, 0), MK_COPZ_BCzx(z, 1)
45
46 #define MK_GTE(mnemonic, format, func) { MASK_OP | (0x1U << 25) | MASK_FUNC, (0x1U << 25) | (0x12U << 26) | func, mnemonic, format }
47
48 static OpEntry ops[] =
49 {
50 MK_OP("nop", "", 0, 0, MASK_RT | MASK_RD | MASK_SA),
51
52 //
53 //
54 //
55 MK_OP("sll", "d, t, a", 0, 0, 0),
56 MK_OP("srl", "d, t, a", 0, 2, 0),
57 MK_OP("sra", "d, t, a", 0, 3, 0),
58
59 MK_OP("sllv", "d, t, s", 0, 4, 0),
60 MK_OP("srlv", "d, t, s", 0, 6, 0),
61 MK_OP("srav", "d, t, s", 0, 7, 0),
62
63 MK_OP("jr", "s", 0, 8, 0),
64 MK_OP("jalr", "d, s", 0, 9, 0),
65
66 MK_OP("syscall", "", 0, 12, 0), // TODO
67 MK_OP("break", "", 0, 13, 0), // TODO
68
69 MK_OP("mfhi", "d", 0, 16, 0),
70 MK_OP("mthi", "s", 0, 17, 0),
71 MK_OP("mflo", "d", 0, 18, 0),
72 MK_OP("mtlo", "s", 0, 19, 0),
73
74 MK_OP("mult", "s, t", 0, 24, 0),
75 MK_OP("multu", "s, t", 0, 25, 0),
76 MK_OP("div", "s, t", 0, 26, 0),
77 MK_OP("divu", "s, t", 0, 27, 0),
78
79 MK_OP("add", "d, s, t", 0, 32, 0),
80 MK_OP("addu", "d, s, t", 0, 33, 0),
81 MK_OP("sub", "d, s, t", 0, 34, 0),
82 MK_OP("subu", "d, s, t", 0, 35, 0),
83 MK_OP("and", "d, s, t", 0, 36, 0),
84 MK_OP("or", "d, s, t", 0, 37, 0),
85 MK_OP("xor", "d, s, t", 0, 38, 0),
86 MK_OP("nor", "d, s, t", 0, 39, 0),
87 MK_OP("slt", "d, s, t", 0, 42, 0),
88 MK_OP("sltu", "d, s, t", 0, 43, 0),
89
90 /* keep *al before the non-linking versions, due to mask setup. */
91 MK_OP_REGIMM("bgezal", 0x1F, 0x11),
92 MK_OP_REGIMM("bltzal", 0x1F, 0x10),
93
94 MK_OP_REGIMM("bgez", 0x01, 0x01),
95 MK_OP_REGIMM("bltz", 0x00, 0x00),
96
97
98 MK_OP("j", "P", 2, 0, 0),
99 MK_OP("jal", "P", 3, 0, 0),
100
101 MK_OP("beq", "s, t, p", 4, 0, 0),
102 MK_OP("bne", "s, t, p", 5, 0, 0),
103 MK_OP("blez", "s, p", 6, 0, 0),
104 MK_OP("bgtz", "s, p", 7, 0, 0),
105
106 MK_OP("addi", "t, s, i", 8, 0, 0),
107 MK_OP("addiu", "t, s, i", 9, 0, 0),
108 MK_OP("slti", "t, s, i", 10, 0, 0),
109 MK_OP("sltiu", "t, s, i", 11, 0, 0),
110
111 MK_OP("andi", "t, s, z", 12, 0, 0),
112
113 MK_OP("ori", "t, s, z", 13, 0, 0),
114 MK_OP("xori", "t, s, z", 14, 0, 0),
115 MK_OP("lui", "t, z", 15, 0, 0),
116
117 MK_COPZ_XFER(0, "mfc0", "t, 0", 0x00),
118 MK_COPZ_XFER(1, "mfc1", "t, ?", 0x00),
119 MK_COPZ_XFER(2, "mfc2", "t, g", 0x00),
120 MK_COPZ_XFER(3, "mfc3", "t, ?", 0x00),
121
122 MK_COPZ_XFER(0, "mtc0", "t, 0", 0x04),
123 MK_COPZ_XFER(1, "mtc1", "t, ?", 0x04),
124 MK_COPZ_XFER(2, "mtc2", "t, g", 0x04),
125 MK_COPZ_XFER(3, "mtc3", "t, ?", 0x04),
126
127 MK_COPZ_XFER(0, "cfc0", "t, ?", 0x02),
128 MK_COPZ_XFER(1, "cfc1", "t, ?", 0x02),
129 MK_COPZ_XFER(2, "cfc2", "t, G", 0x02),
130 MK_COPZ_XFER(3, "cfc3", "t, ?", 0x02),
131
132 MK_COPZ_XFER(0, "ctc0", "t, ?", 0x06),
133 MK_COPZ_XFER(1, "ctc1", "t, ?", 0x06),
134 MK_COPZ_XFER(2, "ctc2", "t, G", 0x06),
135 MK_COPZ_XFER(3, "ctc3", "t, ?", 0x06),
136
137 MK_COPZ_BC(0),
138 MK_COPZ_BC(1),
139 MK_COPZ_BC(2),
140 MK_COPZ_BC(3),
141
142 // COP0 stuff here
143 MK_COP0_FUNC("rfe", 0x10),
144
145 MK_OP("lwc0", "?, i(s)", 0x30, 0, 0),
146 MK_OP("lwc1", "?, i(s)", 0x31, 0, 0),
147 MK_OP("lwc2", "h, i(s)", 0x32, 0, 0),
148 MK_OP("lwc3", "?, i(s)", 0x33, 0, 0),
149
150 MK_OP("swc0", "?, i(s)", 0x38, 0, 0),
151 MK_OP("swc1", "?, i(s)", 0x39, 0, 0),
152 MK_OP("swc2", "h, i(s)", 0x3A, 0, 0),
153 MK_OP("swc3", "?, i(s)", 0x3B, 0, 0),
154
155 MK_OP("lb", "t, i(s)", 0x20, 0, 0),
156 MK_OP("lh", "t, i(s)", 0x21, 0, 0),
157 MK_OP("lwl", "t, i(s)", 0x22, 0, 0),
158 MK_OP("lw", "t, i(s)", 0x23, 0, 0),
159 MK_OP("lbu", "t, i(s)", 0x24, 0, 0),
160 MK_OP("lhu", "t, i(s)", 0x25, 0, 0),
161 MK_OP("lwr", "t, i(s)", 0x26, 0, 0),
162
163 MK_OP("sb", "t, i(s)", 0x28, 0, 0),
164 MK_OP("sh", "t, i(s)", 0x29, 0, 0),
165 MK_OP("swl", "t, i(s)", 0x2A, 0, 0),
166 MK_OP("sw", "t, i(s)", 0x2B, 0, 0),
167 MK_OP("swr", "t, i(s)", 0x2E, 0, 0),
168
169 //
170 // GTE specific instructions
171 //
172 // sf mx v cv lm
173 //
174 MK_GTE("rtps", "#sf# #lm#", 0x00),
175 MK_GTE("rtps", "#sf# #lm#", 0x01),
176 MK_GTE("nclip", "", 0x06),
177 MK_GTE("op", "#sf# #lm#", 0x0C),
178
179 MK_GTE("dpcs", "#sf# #lm#", 0x10),
180 MK_GTE("intpl", "#sf# #lm#", 0x11),
181 MK_GTE("mvmva", "#sf# #mx# #v# #cv# #lm#", 0x12),
182 MK_GTE("ncds", "#sf# #lm#", 0x13),
183 MK_GTE("cdp", "#sf# #lm#", 0x14),
184 MK_GTE("ncdt", "#sf# #lm#", 0x16),
185 MK_GTE("dcpl", "#sf# #lm#", 0x1A),
186 MK_GTE("nccs", "#sf# #lm#", 0x1B),
187 MK_GTE("cc", "#sf# #lm#", 0x1C),
188 MK_GTE("ncs", "#sf# #lm#", 0x1E),
189 MK_GTE("nct", "#sf# #lm#", 0x20),
190 MK_GTE("sqr", "#sf# #lm#", 0x28),
191 MK_GTE("dcpl", "#sf# #lm#", 0x29),
192 MK_GTE("dpct", "#sf# #lm#", 0x2A),
193 MK_GTE("avsz3", "", 0x2D),
194 MK_GTE("avsz4", "", 0x2E),
195 MK_GTE("rtpt", "#sf# #lm#", 0x30),
196 MK_GTE("gpf", "#sf# #lm#", 0x3D),
197 MK_GTE("gpl", "#sf# #lm#", 0x3E),
198 MK_GTE("ncct", "#sf# #lm#", 0x3F),
199
200
201 //
202 //
203 //
204 MK_COPZ(0),
205 MK_COPZ(1),
206 MK_COPZ(2),
207 MK_COPZ(3),
208
209 { 0, 0, NULL, NULL }
210 };
211
212 std::string DisassembleMIPS(uint32 PC, uint32 instr)
213 {
214 std::string ret = "UNKNOWN";
215 unsigned int rs = (instr >> 21) & 0x1F;
216 unsigned int rt = (instr >> 16) & 0x1F;
217 unsigned int rd = (instr >> 11) & 0x1F;
218 unsigned int shamt = (instr >> 6) & 0x1F;
219 unsigned int immediate = (int32)(int16)(instr & 0xFFFF);
220 unsigned int immediate_ze = (instr & 0xFFFF);
221 unsigned int jt = instr & ((1 << 26) - 1);
222
223 static const char *gpr_names[32] =
224 {
225 "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
226 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra"
227 };
228
229 static const char *cop0_names[32] =
230 {
231 "CPR0", "CPR1", "CPR2", "BPC", "CPR4", "BDA", "TAR", "DCIC", "BADVA", "BDAM", "CPR10", "BPCM", "SR", "CAUSE", "EPC", "PRID",
232 "CPR16", "CPR17", "CPR18", "CPR19", "CPR20", "CPR21", "CPR22", "CPR23", "CPR24", "CPR25", "CPR26", "CPR27", "CPR28", "CPR29", "CPR30", "CPR31"
233 };
234
235 static const char *gte_cr_names[32] =
236 {
237 "R11R12", "R13R21", "R22R23", "R31R32", "R33", "TRX", "TRY", "TRZ", "L11L12", "L13L21", "L22L23", "L31L32", "L33", "RBK", "GBK", "BBK",
238 "LR1LR2", "LR3LG1", "LG2LG3", "LB1LB2", "LB3", "RFC", "GFC", "BFC", "OFX", "OFY", "H", "DQA", "DQB", "ZSF3", "ZSF4", "FLAG"
239 };
240
241 static const char *gte_dr_names[32] =
242 {
243 "VXY0", "VZ0", "VXY1", "VZ1", "VXY2", "VZ2", "RGB", "OTZ", "IR0", "IR1", "IR2", "IR3", "SXY0", "SXY1", "SXY2", "SXYP",
244 "SZ0", "SZ1", "SZ2", "SZ3", "RGB0", "RGB1", "RGB2", "RES1", "MAC0", "MAC1", "MAC2", "MAC3", "IRGB", "ORGB", "LZCS", "LZCR"
245 };
246
247 OpEntry *op = ops;
248
249 while(op->mnemonic)
250 {
251 if((instr & op->mask) == op->value)
252 {
253 // a = shift amount
254 // s = rs
255 // t = rt
256 // d = rd
257 // i = immediate
258 // z = immediate, zero-extended
259 // p = PC + 4 + immediate
260 // P = ((PC + 4) & 0xF0000000) | (26bitval << 2)
261 //
262 // 0 = rd(cop0 registers)
263 // c = rd(copz data registers)
264 // C = rd(copz control registers)
265 // g = rd(GTE data registers)
266 // G = rd(GTE control registers)
267 // h = rt(GTE data registers)
268
269 char s_a[16];
270 char s_i[16];
271 char s_z[16];
272 char s_p[16];
273 char s_P[16];
274 char s_c[16];
275 char s_C[16];
276
277 snprintf(s_a, sizeof(s_a), "%d", shamt);
278
279 #if 0
280 if(immediate < 0)
281 snprintf(s_i, sizeof(s_i), "%d", immediate);
282 else
283 #endif
284 snprintf(s_i, sizeof(s_i), "0x%04x", (uint32)immediate);
285
286 snprintf(s_z, sizeof(s_z), "0x%04x", immediate_ze);
287
288 snprintf(s_p, sizeof(s_p), "0x%08x", PC + 4 + (immediate << 2));
289
290 snprintf(s_P, sizeof(s_P), "0x%08x", ((PC + 4) & 0xF0000000) | (jt << 2));
291
292 snprintf(s_c, sizeof(s_c), "CPR%d", rd);
293 snprintf(s_C, sizeof(s_C), "CCR%d", rd);
294
295 ret = std::string(op->mnemonic);
296 ret.append(10 - ret.size(), ' ');
297
298 for(unsigned int i = 0; i < strlen(op->format); i++)
299 {
300 switch(op->format[i])
301 {
302 case '#':
303 // sf mx v cv lm
304 {
305 char as[16];
306
307 as[0] = 0;
308 if(!strncmp(&op->format[i], "#sf#", 4))
309 {
310 i += 3;
311 snprintf(as, 16, "sf=%d", (int)(bool)(instr & (1 << 19)));
312 }
313 else if(!strncmp(&op->format[i], "#mx#", 4))
314 {
315 i += 3;
316 snprintf(as, 16, "mx=%d", (instr >> 17) & 0x3);
317 }
318 else if(!strncmp(&op->format[i], "#v#", 3))
319 {
320 i += 2;
321 snprintf(as, 16, "v=%d", (instr >> 15) & 0x3);
322 }
323 else if(!strncmp(&op->format[i], "#cv#", 4))
324 {
325 i += 3;
326 snprintf(as, 16, "cv=%d", (instr >> 13) & 0x3);
327 }
328 else if(!strncmp(&op->format[i], "#lm#", 4))
329 {
330 i += 3;
331 snprintf(as, 16, "lm=%d", (int)(bool)(instr & (1 << 10)));
332 }
333 ret.append(as);
334 }
335 break;
336 case 'F':
337 {
338 char s_F[16];
339
340 snprintf(s_F, 16, "0x%07x", instr & 0x1FFFFFF);
341 ret.append(s_F);
342 }
343 break;
344
345 case 'h':
346 ret.append(gte_dr_names[rt]);
347 break;
348
349 case 'g':
350 ret.append(gte_dr_names[rd]);
351 break;
352
353 case 'G':
354 ret.append(gte_cr_names[rd]);
355 break;
356
357 case '0':
358 ret.append(cop0_names[rd]);
359 break;
360
361 case 'c':
362 ret.append(s_c);
363 break;
364
365 case 'C':
366 ret.append(s_C);
367 break;
368
369 case 'a':
370 ret.append(s_a);
371 break;
372
373 case 'i':
374 ret.append(s_i);
375 break;
376
377 case 'z':
378 ret.append(s_z);
379 break;
380
381 case 'p':
382 ret.append(s_p);
383 break;
384
385 case 'P':
386 ret.append(s_P);
387 break;
388
389 case 's':
390 ret.append(gpr_names[rs]);
391 break;
392
393 case 't':
394 ret.append(gpr_names[rt]);
395 break;
396
397 case 'd':
398 ret.append(gpr_names[rd]);
399 break;
400
401 default:
402 ret.append(1, op->format[i]);
403 break;
404 }
405 }
406 break;
407 }
408 op++;
409 }
410
411 return(ret);
412 }
0 #ifndef __MDFN_PSX_DIS_H
1 #define __MDFN_PSX_DIS_H
2
3 std::string DisassembleMIPS(uint32 PC, uint32 instr);
4
5 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "mdec.h"
19 #include "cdc.h"
20 #include "spu.h"
21
22 /* Notes:
23
24 Channel 4(SPU):
25 Write:
26 Doesn't seem to work properly with CHCR=0x01000001
27 Hung when CHCR=0x11000601
28
29 Channel 6:
30 DMA hangs if D28 of CHCR is 0?
31 D1 did not have an apparent effect.
32
33 */
34
35 enum
36 {
37 CH_MDEC_IN = 0,
38 CH_MDEC_OUT = 1,
39 CH_GPU = 2,
40 CH_CDC = 3,
41 CH_SPU = 4,
42 CH_FIVE = 5,
43 CH_OT = 6
44 };
45
46 static int32_t DMACycleCounter;
47
48 static uint32_t DMAControl;
49 static uint32_t DMAIntControl;
50 static uint8_t DMAIntStatus;
51 static bool IRQOut;
52
53 struct Channel
54 {
55 uint32_t BaseAddr;
56 uint32_t BlockControl;
57 uint32_t ChanControl;
58
59 uint32_t CurAddr;
60 uint16_t WordCounter;
61
62 int32_t ClockCounter;
63 };
64
65 static Channel DMACH[7];
66 static int32_t lastts;
67
68 static const char *PrettyChannelNames[7] = { "MDEC IN", "MDEC OUT", "GPU", "CDC", "SPU", "PIO", "OTC" };
69
70 void DMA_Init(void)
71 {
72
73 }
74
75 void DMA_Kill(void)
76 {
77
78 }
79
80 static INLINE void RecalcIRQOut(void)
81 {
82 bool irqo = (bool)DMAIntStatus;
83 irqo &= (DMAIntControl >> 23) & 1;
84
85 irqo |= (DMAIntControl >> 15) & 1;
86
87 IRQOut = irqo;
88 ::IRQ_Assert(IRQ_DMA, irqo);
89 }
90
91 void DMA_ResetTS(void)
92 {
93 lastts = 0;
94 }
95
96 void DMA_Power(void)
97 {
98 lastts = 0;
99
100 memset(DMACH, 0, sizeof(DMACH));
101
102 DMACycleCounter = 128;
103
104 DMAControl = 0;
105 DMAIntControl = 0;
106 DMAIntStatus = 0;
107 RecalcIRQOut();
108 }
109
110 static INLINE bool ChCan(const unsigned ch, const uint32_t CRModeCache)
111 {
112 switch(ch)
113 {
114 case CH_MDEC_IN:
115 return(MDEC_DMACanWrite());
116 case CH_MDEC_OUT:
117 return(MDEC_DMACanRead());
118 case CH_GPU:
119 if(CRModeCache & 0x1)
120 return(GPU->DMACanWrite());
121 case CH_CDC:
122 case CH_SPU:
123 return(true);
124 case CH_FIVE:
125 return(false);
126 case CH_OT:
127 return((bool)(DMACH[ch].ChanControl & (1U << 28)));
128 }
129
130 /* should not happen */
131 return false;
132 }
133
134 static void RecalcHalt(void)
135 {
136 bool Halt = false;
137 unsigned ch, tmp;
138 ch = 0;
139 tmp = 0;
140
141 for(ch = 0; ch < 7; ch++)
142 {
143 if(DMACH[ch].ChanControl & (1U << 24))
144 {
145 if(!(DMACH[ch].ChanControl & (7U << 8)))
146 {
147 if(DMACH[ch].WordCounter > 0)
148 {
149 Halt = true;
150 break;
151 }
152 }
153 }
154 }
155
156 #if 0
157 if((DMACH[0].WordCounter || (DMACH[0].ChanControl & (1 << 24))) && (DMACH[0].ChanControl & 0x200) /*&& MDEC_DMACanWrite()*/)
158 Halt = true;
159
160 if((DMACH[1].WordCounter || (DMACH[1].ChanControl & (1 << 24))) && (DMACH[1].ChanControl & 0x200) && (DMACH[1].WordCounter || MDEC_DMACanRead()))
161 Halt = true;
162
163 if((DMACH[2].WordCounter || (DMACH[2].ChanControl & (1 << 24))) && (DMACH[2].ChanControl & 0x200) && ((DMACH[2].ChanControl & 0x1) && (DMACH[2].WordCounter || GPU->DMACanWrite())))
164 Halt = true;
165
166 if((DMACH[3].WordCounter || (DMACH[3].ChanControl & (1 << 24))) && !(DMACH[3].ChanControl & 0x100))
167 Halt = true;
168
169 if(DMACH[6].WordCounter || (DMACH[6].ChanControl & (1 << 24)))
170 Halt = true;
171 #endif
172
173 //printf("Halt: %d\n", Halt);
174
175 if(!Halt && (DMACH[2].ChanControl & (1U << 24)) && ((DMACH[2].ChanControl & 0x700) == 0x200) && ChCan(2, DMACH[2].ChanControl))
176 {
177 tmp = DMACH[2].BlockControl & 0xFFFF;
178
179 if(tmp > 0)
180 tmp--;
181
182 PSX_SetDMACycleSteal(tmp);
183 }
184 else
185 PSX_SetDMACycleSteal(0);
186
187 CPU->SetHalt(Halt);
188 }
189
190
191 static INLINE void ChRW(const unsigned ch, const uint32_t CRModeCache, uint32_t *V, uint32_t *offset)
192 {
193 unsigned extra_cyc_overhead = 0;
194
195 switch(ch)
196 {
197 case CH_MDEC_IN:
198 if(CRModeCache & 0x1)
199 MDEC_DMAWrite(*V);
200 else
201 *V = 0;
202 break;
203
204 case CH_MDEC_OUT:
205 if(CRModeCache & 0x1)
206 {
207 }
208 else
209 *V = MDEC_DMARead(offset);
210 break;
211
212 case CH_GPU:
213 if(CRModeCache & 0x1)
214 GPU->WriteDMA(*V);
215 else
216 *V = GPU->ReadDMA();
217 break;
218
219 case CH_CDC:
220 // 0x1f801018 affects CDC DMA timing.
221 #if 0
222 if(CRModeCache & 0x100) // For CDC DMA(at least): When this bit is set, DMA controller doesn't appear to hog the (RAM?) bus.
223 {
224 if(CRModeCache & 0x00400000) // For CDC DMA(at least): When this bit is set, DMA controller appears to get even less bus time(or has a lower priority?)
225 {
226 DMACH[ch].ClockCounter -= 44 * 20 / 12;
227 }
228 else
229 {
230 DMACH[ch].ClockCounter -= 29 * 20 / 12;
231 }
232 }
233 else
234 {
235 DMACH[ch].ClockCounter -= 23 * 20 / 12; // (23 + 1) = 24. (Though closer to 24.5 or 24.4 on average per tests on a PS1)
236 }
237 #endif
238 if(CRModeCache & 0x1)
239 {
240 }
241 else
242 {
243 extra_cyc_overhead = 8; // FIXME: Test.
244 *V = CDC->DMARead(); // Note: Legend of Mana's opening movie is sensitive to DMA timing, including CDC.
245 }
246 break;
247
248 case CH_SPU:
249 // 0x1f801014 affects SPU DMA timing.
250 // Wild conjecture about 0x1f801014:
251 //
252 // & 0x0000000F
253 // & 0x000001E0 --- Used if (& 0x20000000) == 0?
254 // & 0x00001000 --- Double total bus cycle time if value == 0?
255 // & 0x0f000000 --- (value << 1) 33MHz cycles, bus cycle extension(added to 4?)?
256 // & 0x20000000 ---
257 //
258 //
259 // TODO?: SPU DMA will "complete" much faster if there's a mismatch between the CHCR read/write mode bit and the SPU control register DMA mode.
260 //
261 //
262 // Investigate: SPU DMA doesn't seem to work right if the value written to 0x1F801DAA doesn't have the upper bit set to 1(0x8000) on a PS1.
263
264 extra_cyc_overhead = 47; // Should be closer to 69, average, but actual timing is...complicated.
265
266 if(CRModeCache & 0x1)
267 SPU->WriteDMA(*V);
268 else
269 *V = SPU->ReadDMA();
270 break;
271
272 case CH_FIVE:
273 if(CRModeCache & 0x1)
274 {
275 }
276 else
277 {
278 *V = 0;
279 }
280 break;
281
282 case CH_OT:
283 if(DMACH[ch].WordCounter == 1)
284 *V = 0xFFFFFF;
285 else
286 *V = (DMACH[ch].CurAddr - 4) & 0x1FFFFF;
287 break;
288 }
289
290 // GROSS APPROXIMATION, shoehorning multiple effects together, TODO separate(especially SPU and CDC)
291 DMACH[ch].ClockCounter -= std::max<int>(extra_cyc_overhead, (CRModeCache & 0x100) ? 7 : 0);
292 }
293
294 static INLINE void RunChannelI(const unsigned ch, const uint32_t CRModeCache, int32_t clocks)
295 {
296 }
297
298 static INLINE void RunChannel(int32_t timestamp, int32_t clocks, int ch)
299 {
300 // Mask out the bits that the DMA controller will modify during the course of operation.
301 uint32_t CRModeCache = DMACH[ch].ChanControl &~(0x11 << 24);
302 uint32_t crmodecache = CRModeCache;
303
304 switch(ch)
305 {
306 case 0:
307 if(MDFN_LIKELY(CRModeCache == 0x00000201))
308 crmodecache = 0x00000201;
309 break;
310 case 1:
311 if(MDFN_LIKELY(CRModeCache == 0x00000200))
312 crmodecache = 0x00000200;
313 break;
314 case 2:
315 switch (CRModeCache)
316 {
317 case 0x00000401:
318 case 0x00000201:
319 case 0x00000200:
320 crmodecache = CRModeCache;
321 break;
322 }
323 break;
324 case 3:
325 switch (CRModeCache)
326 {
327 case 0x00000000:
328 case 0x00000100:
329 crmodecache = CRModeCache;
330 break;
331 }
332 break;
333 case 4:
334 switch (CRModeCache)
335 {
336 case 0x00000201:
337 case 0x00000200:
338 crmodecache = CRModeCache;
339 break;
340 }
341 break;
342 case 6:
343 if(MDFN_LIKELY(CRModeCache == 0x00000002))
344 crmodecache = 0x00000002;
345 break;
346 }
347
348 //
349 // Remember to handle an end condition on the same iteration of the while(DMACH[ch].ClockCounter > 0) loop that caused it,
350 // otherwise RecalcHalt() might take the CPU out of a halted state before the end-of-DMA is signaled(especially a problem considering our largeish
351 // DMA update timing granularity).
352 if (ch >= 0 && ch <= 6)
353 {
354 CRModeCache = crmodecache;
355 DMACH[ch].ClockCounter += clocks;
356
357 while(MDFN_LIKELY(DMACH[ch].ClockCounter > 0))
358 {
359 if(DMACH[ch].WordCounter == 0) // Begin WordCounter reload.
360 {
361 if(!(DMACH[ch].ChanControl & (1 << 24))) // Needed for the forced-DMA-stop kludge(see DMA_Write()).
362 break;
363
364 if(!ChCan(ch, CRModeCache))
365 break;
366
367 DMACH[ch].CurAddr = DMACH[ch].BaseAddr;
368
369 if(CRModeCache & (1U << 10))
370 {
371 uint32_t header;
372
373 if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000))
374 {
375 DMACH[ch].ChanControl &= ~(0x11 << 24);
376 DMAIntControl |= 0x8000;
377 RecalcIRQOut();
378 break;
379 }
380
381 header = MainRAM.ReadU32(DMACH[ch].CurAddr & 0x1FFFFC);
382 DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0xFFFFFF;
383
384 DMACH[ch].WordCounter = header >> 24;
385 DMACH[ch].BaseAddr = header & 0xFFFFFF;
386
387 // printf to debug Soul Reaver ;)
388 //if(DMACH[ch].WordCounter > 0x10)
389 // printf("What the lala? 0x%02x @ 0x%08x\n", DMACH[ch].WordCounter, DMACH[ch].CurAddr - 4);
390
391 if(DMACH[ch].WordCounter)
392 DMACH[ch].ClockCounter -= 15;
393 else
394 DMACH[ch].ClockCounter -= 10;
395
396 goto SkipPayloadStuff; // 3 cheers for gluten-free spaghetticode(necessary because the newly-loaded WordCounter might be 0, and we actually
397 // want 0 to mean 0 and not 65536 in this context)!
398 }
399 else
400 {
401 DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF;
402
403 if(CRModeCache & (1U << 9))
404 {
405 if(ch == 2) // Technically should apply to all channels, but since we don't implement CPU read penalties for channels other than 2 yet, it's like this to avoid making DMA longer than what games can handle.
406 DMACH[ch].ClockCounter -= 7;
407
408 DMACH[ch].BlockControl = (DMACH[ch].BlockControl & 0xFFFF) | ((DMACH[ch].BlockControl - (1U << 16)) & 0xFFFF0000);
409 }
410 }
411 } // End WordCounter reload.
412 else if(CRModeCache & 0x100) // BLARGH BLARGH FISHWHALE
413 {
414 //printf("LoadWC: %u(oldWC=%u)\n", DMACH[ch].BlockControl & 0xFFFF, DMACH[ch].WordCounter);
415 //MDFN_DispMessage("SPOOOON\n");
416 DMACH[ch].CurAddr = DMACH[ch].BaseAddr;
417 DMACH[ch].WordCounter = DMACH[ch].BlockControl & 0xFFFF;
418 }
419
420 // Do the payload read/write
421 {
422 uint32_t vtmp;
423 uint32_t voffs = 0;
424
425 if(MDFN_UNLIKELY(DMACH[ch].CurAddr & 0x800000))
426 {
427 DMACH[ch].ChanControl &= ~(0x11 << 24);
428 DMAIntControl |= 0x8000;
429 RecalcIRQOut();
430 break;
431 }
432
433 if(CRModeCache & 0x1)
434 vtmp = MainRAM.ReadU32(DMACH[ch].CurAddr & 0x1FFFFC);
435
436 ChRW(ch, CRModeCache, &vtmp, &voffs);
437
438 if(!(CRModeCache & 0x1))
439 MainRAM.WriteU32((DMACH[ch].CurAddr + (voffs << 2)) & 0x1FFFFC, vtmp);
440 }
441
442 if(CRModeCache & 0x2)
443 DMACH[ch].CurAddr = (DMACH[ch].CurAddr - 4) & 0xFFFFFF;
444 else
445 DMACH[ch].CurAddr = (DMACH[ch].CurAddr + 4) & 0xFFFFFF;
446
447 DMACH[ch].WordCounter--;
448 DMACH[ch].ClockCounter--;
449
450 SkipPayloadStuff: ;
451
452 if(CRModeCache & 0x100) // BLARGH BLARGH WHALEFISH
453 {
454 DMACH[ch].BaseAddr = DMACH[ch].CurAddr;
455 DMACH[ch].BlockControl = (DMACH[ch].BlockControl & 0xFFFF0000) | DMACH[ch].WordCounter;
456 //printf("SaveWC: %u\n", DMACH[ch].WordCounter);
457 }
458
459 //
460 // Handle channel end condition:
461 //
462 if(DMACH[ch].WordCounter == 0)
463 {
464 bool ChannelEndTC = false;
465
466 if(!(DMACH[ch].ChanControl & (1 << 24))) // Needed for the forced-DMA-stop kludge(see DMA_Write()).
467 break;
468
469 switch((CRModeCache >> 9) & 0x3)
470 {
471 case 0x0:
472 ChannelEndTC = true;
473 break;
474
475 case 0x1:
476 DMACH[ch].BaseAddr = DMACH[ch].CurAddr;
477 if((DMACH[ch].BlockControl >> 16) == 0)
478 ChannelEndTC = true;
479 break;
480
481 case 0x2:
482 case 0x3: // Not sure about 0x3.
483 if(DMACH[ch].BaseAddr == 0xFFFFFF)
484 ChannelEndTC = true;
485 break;
486 }
487
488 if(ChannelEndTC)
489 {
490 DMACH[ch].ChanControl &= ~(0x11 << 24);
491 if(DMAIntControl & (1U << (16 + ch)))
492 {
493 DMAIntStatus |= 1U << ch;
494 RecalcIRQOut();
495 }
496 break;
497 }
498 }
499 }
500
501 if(DMACH[ch].ClockCounter > 0)
502 DMACH[ch].ClockCounter = 0;
503 }
504 }
505
506 static INLINE int32_t CalcNextEvent(int32_t next_event)
507 {
508 if(DMACycleCounter < next_event)
509 next_event = DMACycleCounter;
510
511 return(next_event);
512 }
513
514 int32_t DMA_Update(const int32_t timestamp)
515 {
516 int32_t clocks, i;
517 // uint32_t dc = (DMAControl >> (ch * 4)) & 0xF;
518 clocks = timestamp - lastts;
519 lastts = timestamp;
520
521 GPU->Update(timestamp);
522 MDEC_Run(clocks);
523
524 for (i = 0; i < 7; i++)
525 RunChannel(timestamp, clocks, i);
526
527 DMACycleCounter -= clocks;
528 while(DMACycleCounter <= 0)
529 DMACycleCounter += 128;
530
531 RecalcHalt();
532
533 return (timestamp + CalcNextEvent(0x10000000));
534 }
535
536 void DMA_Write(const int32_t timestamp, uint32_t A, uint32_t V)
537 {
538 bool will_set_event = false;
539 int ch = (A & 0x7F) >> 4;
540
541 //if(ch == 2 || ch == 7)
542 //PSX_WARNING("[DMA] Write: %08x %08x, DMAIntStatus=%08x", A, V, DMAIntStatus);
543
544 // FIXME if we ever have "accurate" bus emulation
545 V <<= (A & 3) * 8;
546
547 DMA_Update(timestamp);
548
549 switch(A & 0xC)
550 {
551 case 0x0:
552 if (ch == 7)
553 {
554 DMAControl = V;
555 RecalcHalt();
556 }
557 else
558 {
559 DMACH[ch].BaseAddr = V & 0xFFFFFF;
560 will_set_event = true;
561 }
562 break;
563
564 case 0x4:
565 if (ch == 7)
566 {
567 DMAIntControl = V & 0x00ff803f;
568 DMAIntStatus &= ~(V >> 24);
569
570 RecalcIRQOut();
571 }
572 else
573 {
574 DMACH[ch].BlockControl = V;
575 will_set_event = true;
576 }
577 break;
578 case 0xC:
579 case 0x8:
580 if (ch != 7)
581 {
582 uint32_t OldCC = DMACH[ch].ChanControl;
583
584 //printf("CHCR: %u, %08x --- 0x%08x\n", ch, V, DMACH[ch].BlockControl);
585 //
586 // Kludge for DMA timing granularity and other issues. Needs to occur before setting all bits of ChanControl to the new value, to accommodate the
587 // case of a game cancelling DMA and changing the type of DMA(read/write, etc.) at the same time.
588 //
589 if((DMACH[ch].ChanControl & (1 << 24)) && !(V & (1 << 24)))
590 {
591 DMACH[ch].ChanControl &= ~(1 << 24); // Clear bit before RunChannel(), so it will only finish the block it's on at most.
592 RunChannel(timestamp, 128 * 16, ch);
593 DMACH[ch].WordCounter = 0;
594
595 #if 0 // TODO(maybe, need to work out worst-case performance for abnormally/brokenly large block sizes)
596 DMACH[ch].ClockCounter = (1 << 30);
597 RunChannel(timestamp, 1, ch);
598 DMACH[ch].ClockCounter = 0;
599 #endif
600 PSX_WARNING("[DMA] Forced stop for channel %d -- scanline=%d", ch, GPU->GetScanlineNum());
601 //MDFN_DispMessage("[DMA] Forced stop for channel %d", ch);
602 }
603
604 if(ch == 6)
605 DMACH[ch].ChanControl = (V & 0x51000000) | 0x2;
606 else
607 DMACH[ch].ChanControl = V & 0x71770703;
608
609 if(!(OldCC & (1 << 24)) && (V & (1 << 24)))
610 {
611 //if(ch == 0 || ch == 1)
612 // PSX_WARNING("[DMA] Started DMA for channel=%d --- CHCR=0x%08x --- BCR=0x%08x --- scanline=%d", ch, DMACH[ch].ChanControl, DMACH[ch].BlockControl, GPU->GetScanlineNum());
613
614 DMACH[ch].WordCounter = 0;
615 DMACH[ch].ClockCounter = 0;
616
617 //
618 // Viewpoint starts a short MEM->GPU LL DMA and apparently has race conditions that can cause a crash if it doesn't finish almost immediately(
619 // or at least very quickly, which the current DMA granularity has issues with, so run the channel ahead a bit to take of this issue and potentially
620 // games with similar issues).
621 //
622 // Though, Viewpoint isn't exactly a good game, so maybe we shouldn't bother? ;)
623 //
624 // Also, it's needed for RecalcHalt() to work with some semblance of workiness.
625 //
626 RunChannel(timestamp, 64, ch); //std::max<int>(128 - DMACycleCounter, 1)); //64); //1); //128 - DMACycleCounter);
627 }
628
629 RecalcHalt();
630 will_set_event = true;
631 break;
632 }
633 default:
634 PSX_WARNING("[DMA] Unknown write: %08x %08x", A, V);
635 break;
636 }
637
638 if (will_set_event)
639 PSX_SetEventNT(PSX_EVENT_DMA, timestamp + CalcNextEvent(0x10000000));
640 }
641
642 uint32_t DMA_Read(const int32_t timestamp, uint32_t A)
643 {
644
645 int ch = (A & 0x7F) >> 4;
646 uint32_t ret = 0;
647
648 switch(A & 0xC)
649 {
650 case 0x0:
651 if (ch == 7)
652 ret = DMAControl;
653 else
654 ret = DMACH[ch].BaseAddr;
655 break;
656 case 0x4:
657 if (ch == 7)
658 ret = DMAIntControl | (DMAIntStatus << 24) | (IRQOut << 31);
659 else
660 ret = DMACH[ch].BlockControl;
661 break;
662 case 0xC:
663 case 0x8:
664 if (ch != 7)
665 {
666 ret = DMACH[ch].ChanControl;
667 break;
668 }
669 default:
670 PSX_WARNING("[DMA] Unknown read: %08x", A);
671 break;
672 }
673
674 return (ret >> ((A & 3) * 8));
675 }
676
677 #define SFDMACH(n) SFVARN(DMACH[n].BaseAddr, #n "BaseAddr"), \
678 SFVARN(DMACH[n].BlockControl, #n "BlockControl"), \
679 SFVARN(DMACH[n].ChanControl, #n "ChanControl"), \
680 SFVARN(DMACH[n].CurAddr, #n "CurAddr"), \
681 SFVARN(DMACH[n].WordCounter, #n "WordCounter"), \
682 SFVARN(DMACH[n].ClockCounter, #n "ClockCounter")
683
684 int DMA_StateAction(StateMem *sm, int load, int data_only)
685 {
686 SFORMAT StateRegs[] =
687 {
688 SFVAR(DMACycleCounter),
689 SFVAR(DMAControl),
690 SFVAR(DMAIntControl),
691 SFVAR(DMAIntStatus),
692 SFVAR(IRQOut),
693
694
695 SFDMACH(0),
696 SFDMACH(1),
697 SFDMACH(2),
698 SFDMACH(3),
699 SFDMACH(4),
700 SFDMACH(5),
701 SFDMACH(6),
702
703 SFEND
704 };
705
706 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "DMA");
707
708 if(load)
709 {
710
711 }
712
713 return(ret);
714 }
0 #ifndef __MDFN_PSX_DMA_H
1 #define __MDFN_PSX_DMA_H
2
3 int32_t DMA_Update(const int32_t timestamp);
4 void DMA_Write(const int32_t timestamp, uint32_t A, uint32_t V);
5 uint32_t DMA_Read(const int32_t timestamp, uint32_t A);
6
7 void DMA_ResetTS(void);
8
9 void DMA_Power(void);
10
11 void DMA_Init(void);
12 void DMA_Kill(void);
13
14 int DMA_StateAction(StateMem *sm, int load, int data_only);
15
16 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "frontio.h"
19 #include "../msvc_compat.h"
20
21 #include "../video/surface.h"
22 #include "input/gamepad.h"
23 #include "input/dualanalog.h"
24 #include "input/dualshock.h"
25 #include "input/mouse.h"
26 #include "input/negcon.h"
27 #include "input/guncon.h"
28 #include "input/justifier.h"
29
30 #include "input/memcard.h"
31
32 #include "input/multitap.h"
33
34 //#define PSX_FIODBGINFO(format, ...) { /* printf(format " -- timestamp=%d -- PAD temp\n", ## __VA_ARGS__, timestamp); */ }
35 static void PSX_FIODBGINFO(const char *format, ...)
36 {
37 }
38
39 InputDevice::InputDevice() : chair_r(0), chair_g(0), chair_b(0), draw_chair(0), chair_x(-1000), chair_y(-1000)
40 {
41 }
42
43 InputDevice::~InputDevice()
44 {
45 }
46
47 void InputDevice::Power(void)
48 {
49 }
50
51 int InputDevice::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
52 {
53 return(1);
54 }
55
56 void InputDevice::Update(const int32_t timestamp)
57 {
58
59 }
60
61 void InputDevice::ResetTS(void)
62 {
63
64 }
65
66 void InputDevice::SetAMCT(bool)
67 {
68
69 }
70
71 void InputDevice::SetCrosshairsColor(uint32_t color)
72 {
73 chair_r = (color >> 16) & 0xFF;
74 chair_g = (color >> 8) & 0xFF;
75 chair_b = (color >> 0) & 0xFF;
76
77 draw_chair = (color != (1 << 24));
78 }
79
80 INLINE void InputDevice::DrawCrosshairs(uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock)
81 {
82 if(draw_chair && chair_y >= -8 && chair_y <= 8)
83 {
84 int32 ic;
85 int32 x_start, x_bound;
86
87 if(chair_y == 0)
88 ic = pix_clock / 762925;
89 else
90 ic = 0;
91
92 x_start = std::max<int32>(0, chair_x - ic);
93 x_bound = std::min<int32>(width, chair_x + ic + 1);
94
95 for(int32 x = x_start; x < x_bound; x++)
96 {
97 int r, g, b, a;
98 int nr, ng, nb;
99
100 format->DecodeColor(pixels[x], r, g, b, a);
101
102 nr = (r + chair_r * 3) >> 2;
103 ng = (g + chair_g * 3) >> 2;
104 nb = (b + chair_b * 3) >> 2;
105
106 if((int)((abs(r - nr) - 0x40) & (abs(g - ng) - 0x40) & (abs(b - nb) - 0x40)) < 0)
107 {
108 if((nr | ng | nb) & 0x80)
109 {
110 nr >>= 1;
111 ng >>= 1;
112 nb >>= 1;
113 }
114 else
115 {
116 nr ^= 0x80;
117 ng ^= 0x80;
118 nb ^= 0x80;
119 }
120 }
121
122 pixels[x] = MAKECOLOR(nr, ng, nb, a);
123 }
124 }
125 }
126
127 int FrontIO::StateAction(StateMem* sm, int load, int data_only)
128 {
129 SFORMAT StateRegs[] =
130 {
131 SFVAR(ClockDivider),
132
133 SFVAR(ReceivePending),
134 SFVAR(TransmitPending),
135
136 SFVAR(ReceiveInProgress),
137 SFVAR(TransmitInProgress),
138
139 SFVAR(ReceiveBufferAvail),
140
141 SFVAR(ReceiveBuffer),
142 SFVAR(TransmitBuffer),
143
144 SFVAR(ReceiveBitCounter),
145 SFVAR(TransmitBitCounter),
146
147 SFVAR(Mode),
148 SFVAR(Control),
149 SFVAR(Baudrate),
150
151 SFVAR(istatus),
152
153 // FIXME: Step mode save states.
154 SFARRAY32(irq10_pulse_ts, sizeof(irq10_pulse_ts) / sizeof(irq10_pulse_ts[0])),
155 SFARRAY32(dsr_pulse_delay, sizeof(dsr_pulse_delay) / sizeof(dsr_pulse_delay[0])),
156 SFARRAY32(dsr_active_until_ts, sizeof(dsr_active_until_ts) / sizeof(dsr_active_until_ts[0])),
157
158 SFEND
159 };
160
161 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "FIO");
162
163 for(unsigned i = 0; i < 8; i++)
164 {
165 char tmpbuf[32];
166 snprintf(tmpbuf, sizeof(tmpbuf), "FIODEV%u", i);
167
168 ret &= Devices[i]->StateAction(sm, load, data_only, tmpbuf);
169 }
170
171 for(unsigned i = 0; i < 8; i++)
172 {
173 char tmpbuf[32];
174 snprintf(tmpbuf, sizeof(tmpbuf), "FIOMC%u", i);
175
176 ret &= DevicesMC[i]->StateAction(sm, load, data_only, tmpbuf);
177 }
178
179 for(unsigned i = 0; i < 2; i++)
180 {
181 char tmpbuf[32];
182 snprintf(tmpbuf, sizeof(tmpbuf), "FIOTAP%u", i);
183
184 ret &= DevicesTap[i]->StateAction(sm, load, data_only, tmpbuf);
185 }
186
187 if(load)
188 {
189 ::IRQ_Assert(IRQ_SIO, istatus);
190 }
191
192 return(ret);
193 }
194
195 bool InputDevice::RequireNoFrameskip(void)
196 {
197 return false;
198 }
199
200 int32_t InputDevice::GPULineHook(const int32_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider)
201 {
202 return(PSX_EVENT_MAXTS);
203 }
204
205
206 void InputDevice::UpdateInput(const void *data)
207 {
208 }
209
210
211 void InputDevice::SetDTR(bool new_dtr)
212 {
213
214 }
215
216 bool InputDevice::GetDSR(void)
217 {
218 return 0;
219 }
220
221 bool InputDevice::Clock(bool TxD, int32_t &dsr_pulse_delay)
222 {
223 dsr_pulse_delay = 0;
224
225 return 1;
226 }
227
228 uint32_t InputDevice::GetNVSize(void)
229 {
230 return 0;
231 }
232
233 void InputDevice::ReadNV(uint8_t *buffer, uint32_t offset, uint32_t count)
234 {
235
236 }
237
238 void InputDevice::WriteNV(const uint8_t *buffer, uint32_t offset, uint32_t count)
239 {
240
241 }
242
243 uint64_t InputDevice::GetNVDirtyCount(void)
244 {
245 return 0;
246 }
247
248 void InputDevice::ResetNVDirtyCount(void)
249 {
250
251 }
252
253 static unsigned EP_to_MP(bool emulate_multitap[2], unsigned ep)
254 {
255 if(!emulate_multitap[0] && emulate_multitap[1])
256 {
257 if(ep == 0 || ep >= 5)
258 return 0;
259 return 1;
260 }
261 return(ep >= 4);
262 }
263
264 static INLINE unsigned EP_to_SP(bool emulate_multitap[2], unsigned ep)
265 {
266 if(!emulate_multitap[0] && emulate_multitap[1])
267 {
268 if(ep == 0)
269 return(0);
270 else if(ep < 5)
271 return(ep - 1);
272 return(ep - 4);
273 }
274 return(ep & 0x3);
275 }
276
277 InputDevice *FrontIO::GetMemcardDevice(unsigned int which)
278 {
279 if (DevicesMC[which])
280 return DevicesMC[which];
281 return NULL;
282 }
283
284 void FrontIO::MapDevicesToPorts(void)
285 {
286 int i;
287 if(emulate_multitap[0] && emulate_multitap[1])
288 {
289 for (i = 0; i < 2; i++)
290 {
291 Ports[i] = DevicesTap[i];
292 MCPorts[i] = DummyDevice;
293 }
294 }
295 else if(!emulate_multitap[0] && emulate_multitap[1])
296 {
297 Ports[0] = Devices[0];
298 MCPorts[0] = emulate_memcards[0] ? DevicesMC[0] : DummyDevice;
299
300 Ports[1] = DevicesTap[1];
301 MCPorts[1] = DummyDevice;
302 }
303 else if(emulate_multitap[0] && !emulate_multitap[1])
304 {
305 Ports[0] = DevicesTap[0];
306 MCPorts[0] = DummyDevice;
307
308 Ports[1] = Devices[4];
309 MCPorts[1] = emulate_memcards[4] ? DevicesMC[4] : DummyDevice;
310 }
311 else
312 {
313 for(i = 0; i < 2; i++)
314 {
315 Ports[i] = Devices[i];
316 MCPorts[i] = emulate_memcards[i] ? DevicesMC[i] : DummyDevice;
317 }
318 }
319
320 //printf("\n");
321 for(i = 0; i < 8; i++)
322 {
323 unsigned mp = EP_to_MP(emulate_multitap, i);
324
325 if(emulate_multitap[mp])
326 DevicesTap[mp]->SetSubDevice(EP_to_SP(emulate_multitap, i), Devices[i], emulate_memcards[i] ? DevicesMC[i] : DummyDevice);
327 else
328 DevicesTap[mp]->SetSubDevice(EP_to_SP(emulate_multitap, i), DummyDevice, DummyDevice);
329
330 //printf("%d-> multitap: %d, sub-port: %d\n", i, mp, EP_to_SP(emulate_multitap, i));
331 }
332 }
333
334 FrontIO::FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2])
335 {
336 int i;
337 memcpy(emulate_memcards, emulate_memcards_, sizeof(emulate_memcards));
338 memcpy(emulate_multitap, emulate_multitap_, sizeof(emulate_multitap));
339
340 DummyDevice = new InputDevice();
341
342 for(i = 0; i < 8; i++)
343 {
344 DeviceData[i] = NULL;
345 Devices[i] = new InputDevice();
346 DevicesMC[i] = Device_Memcard_Create();
347 chair_colors[i] = 1 << 24;
348 Devices[i]->SetCrosshairsColor(chair_colors[i]);
349 }
350
351 for(i = 0; i < 2; i++)
352 DevicesTap[i] = new InputDevice_Multitap();
353
354 MapDevicesToPorts();
355 }
356
357 void FrontIO::SetAMCT(bool enabled)
358 {
359 int i;
360 for(i = 0; i < 8; i++)
361 Devices[i]->SetAMCT(enabled);
362 amct_enabled = enabled;
363 }
364
365 void FrontIO::SetCrosshairsColor(unsigned port, uint32_t color)
366 {
367 chair_colors[port] = color;
368 Devices[port]->SetCrosshairsColor(color);
369 }
370
371 FrontIO::~FrontIO()
372 {
373 int i;
374 for(i = 0; i < 8; i++)
375 {
376 if(Devices[i])
377 delete Devices[i];
378 Devices[i] = NULL;
379 if(DevicesMC[i])
380 delete DevicesMC[i];
381 DevicesMC[i] = NULL;
382 }
383
384 for(i = 0; i < 2; i++)
385 {
386 if(DevicesTap[i])
387 delete DevicesTap[i];
388 DevicesTap[i] = NULL;
389 }
390
391 if(DummyDevice)
392 delete DummyDevice;
393 DummyDevice = NULL;
394 }
395
396 int32_t FrontIO::CalcNextEventTS(int32_t timestamp, int32_t next_event)
397 {
398 int32_t ret;
399 int i;
400
401 if(ClockDivider > 0 && ClockDivider < next_event)
402 next_event = ClockDivider;
403
404 for(i = 0; i < 4; i++)
405 if(dsr_pulse_delay[i] > 0 && next_event > dsr_pulse_delay[i])
406 next_event = dsr_pulse_delay[i];
407
408 ret = timestamp + next_event;
409
410 if(irq10_pulse_ts[0] < ret)
411 ret = irq10_pulse_ts[0];
412
413 if(irq10_pulse_ts[1] < ret)
414 ret = irq10_pulse_ts[1];
415
416 return(ret);
417 }
418
419 static const uint8_t ScaleShift[4] = { 0, 0, 4, 6 };
420
421 void FrontIO::CheckStartStopPending(int32_t timestamp, bool skip_event_set)
422 {
423 //const bool prior_ReceiveInProgress = ReceiveInProgress;
424 //const bool prior_TransmitInProgress = TransmitInProgress;
425 bool trigger_condition = false;
426
427 trigger_condition = (ReceivePending && (Control & 0x4)) || (TransmitPending && (Control & 0x1));
428
429 if(trigger_condition)
430 {
431 if(ReceivePending)
432 {
433 ReceivePending = false;
434 ReceiveInProgress = true;
435 ReceiveBufferAvail = false;
436 ReceiveBuffer = 0;
437 ReceiveBitCounter = 0;
438 }
439
440 if(TransmitPending)
441 {
442 TransmitPending = false;
443 TransmitInProgress = true;
444 TransmitBitCounter = 0;
445 }
446
447 ClockDivider = std::max<uint32>(0x20, (Baudrate << ScaleShift[Mode & 0x3]) & ~1); // Minimum of 0x20 is an emulation sanity check to prevent severe performance degradation.
448 //printf("CD: 0x%02x\n", ClockDivider);
449 }
450
451 if(!(Control & 0x5))
452 {
453 ReceiveInProgress = false;
454 TransmitInProgress = false;
455 }
456
457 if(!ReceiveInProgress && !TransmitInProgress)
458 ClockDivider = 0;
459
460 if(!(skip_event_set))
461 PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000));
462 }
463
464 // DSR IRQ bit setting appears(from indirect tests on real PS1) to be level-sensitive, not edge-sensitive
465 INLINE void FrontIO::DoDSRIRQ(void)
466 {
467 if(Control & 0x1000)
468 {
469 PSX_FIODBGINFO("[DSR] IRQ");
470 istatus = true;
471 ::IRQ_Assert(IRQ_SIO, true);
472 }
473 }
474
475
476 void FrontIO::Write(int32_t timestamp, uint32_t A, uint32_t V)
477 {
478 assert(!(A & 0x1));
479
480 PSX_FIODBGINFO("[FIO] Write: %08x %08x", A, V);
481
482 Update(timestamp);
483
484 switch(A & 0xF)
485 {
486 case 0x0:
487 TransmitBuffer = V;
488 TransmitPending = true;
489 TransmitInProgress = false;
490 break;
491
492 case 0x8:
493 Mode = V & 0x013F;
494 break;
495
496 case 0xa:
497 if(ClockDivider > 0 && ((V & 0x2000) != (Control & 0x2000)) && ((Control & 0x2) == (V & 0x2)) )
498 PSX_DBG(PSX_DBG_WARNING, "FIO device selection changed during comm %04x->%04x\n", Control, V);
499
500 //printf("Control: %d, %04x\n", timestamp, V);
501 Control = V & 0x3F2F;
502
503 if(V & 0x10)
504 {
505 istatus = false;
506 ::IRQ_Assert(IRQ_SIO, false);
507 }
508
509 if(V & 0x40) // Reset
510 {
511 istatus = false;
512 ::IRQ_Assert(IRQ_SIO, false);
513
514 ClockDivider = 0;
515 ReceivePending = false;
516 TransmitPending = false;
517
518 ReceiveInProgress = false;
519 TransmitInProgress = false;
520
521 ReceiveBufferAvail = false;
522
523 TransmitBuffer = 0;
524 ReceiveBuffer = 0;
525
526 ReceiveBitCounter = 0;
527 TransmitBitCounter = 0;
528
529 Mode = 0;
530 Control = 0;
531 Baudrate = 0;
532 }
533
534 Ports[0]->SetDTR((Control & 0x2) && !(Control & 0x2000));
535 MCPorts[0]->SetDTR((Control & 0x2) && !(Control & 0x2000));
536 Ports[1]->SetDTR((Control & 0x2) && (Control & 0x2000));
537 MCPorts[1]->SetDTR((Control & 0x2) && (Control & 0x2000));
538
539 #if 1
540 if(!((Control & 0x2) && !(Control & 0x2000)))
541 {
542 dsr_pulse_delay[0] = 0;
543 dsr_pulse_delay[2] = 0;
544 dsr_active_until_ts[0] = -1;
545 dsr_active_until_ts[2] = -1;
546 }
547
548 if(!((Control & 0x2) && (Control & 0x2000)))
549 {
550 dsr_pulse_delay[1] = 0;
551 dsr_pulse_delay[3] = 0;
552 dsr_active_until_ts[1] = -1;
553 dsr_active_until_ts[3] = -1;
554 }
555
556 #endif
557 // TODO: Uncomment out in the future once our CPU emulation is a bit more accurate with timing, to prevent causing problems with games
558 // that may clear the IRQ in an unsafe pattern that only works because its execution was slow enough to allow DSR to go inactive. (Whether or not
559 // such games even exist though is unknown!)
560 //if(timestamp < dsr_active_until_ts[0] || timestamp < dsr_active_until_ts[1] || timestamp < dsr_active_until_ts[2] || timestamp < dsr_active_until_ts[3])
561 // DoDSRIRQ();
562
563 break;
564
565 case 0xe:
566 Baudrate = V;
567 //printf("%02x\n", V);
568 //MDFN_DispMessage("%02x\n", V);
569 break;
570 }
571
572 CheckStartStopPending(timestamp, false);
573 }
574
575
576 uint32_t FrontIO::Read(int32_t timestamp, uint32_t A)
577 {
578 uint32_t ret = 0;
579
580 assert(!(A & 0x1));
581
582 Update(timestamp);
583
584 switch(A & 0xF)
585 {
586 case 0x0:
587 //printf("FIO Read: 0x%02x\n", ReceiveBuffer);
588 ret = ReceiveBuffer | (ReceiveBuffer << 8) | (ReceiveBuffer << 16) | (ReceiveBuffer << 24);
589 ReceiveBufferAvail = false;
590 ReceivePending = true;
591 ReceiveInProgress = false;
592 CheckStartStopPending(timestamp, false);
593 break;
594
595 case 0x4:
596 ret = 0;
597
598 if(!TransmitPending && !TransmitInProgress)
599 ret |= 0x1;
600
601 if(ReceiveBufferAvail)
602 ret |= 0x2;
603
604 if(timestamp < dsr_active_until_ts[0] || timestamp < dsr_active_until_ts[1] || timestamp < dsr_active_until_ts[2] || timestamp < dsr_active_until_ts[3])
605 ret |= 0x80;
606
607 if(istatus)
608 ret |= 0x200;
609
610 break;
611
612 case 0x8:
613 ret = Mode;
614 break;
615
616 case 0xa:
617 ret = Control;
618 break;
619
620 case 0xe:
621 ret = Baudrate;
622 break;
623 }
624
625 if((A & 0xF) != 0x4)
626 PSX_FIODBGINFO("[FIO] Read: %08x %08x", A, ret);
627
628 return(ret);
629 }
630
631 int32_t FrontIO::Update(int32_t timestamp)
632 {
633 int32_t clocks, i;
634 bool need_start_stop_check = false;
635
636 clocks = timestamp - lastts;
637
638 for(i = 0; i < 4; i++)
639 if(dsr_pulse_delay[i] > 0)
640 {
641 dsr_pulse_delay[i] -= clocks;
642 if(dsr_pulse_delay[i] <= 0)
643 {
644 dsr_active_until_ts[i] = timestamp + 32 + dsr_pulse_delay[i];
645 DoDSRIRQ();
646 }
647 }
648
649 for(i = 0; i < 2; i++)
650 {
651 if(timestamp >= irq10_pulse_ts[i])
652 {
653 //printf("Yay: %d %u\n", i, timestamp);
654 irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
655 ::IRQ_Assert(IRQ_PIO, true);
656 ::IRQ_Assert(IRQ_PIO, false);
657 }
658 }
659
660 if(ClockDivider > 0)
661 {
662 ClockDivider -= clocks;
663
664 while(ClockDivider <= 0)
665 {
666 if(ReceiveInProgress || TransmitInProgress)
667 {
668 bool rxd = 0, txd = 0;
669 const uint32_t BCMask = 0x07;
670
671 if(TransmitInProgress)
672 {
673 txd = (TransmitBuffer >> TransmitBitCounter) & 1;
674 TransmitBitCounter = (TransmitBitCounter + 1) & BCMask;
675 if(!TransmitBitCounter)
676 {
677 need_start_stop_check = true;
678 PSX_FIODBGINFO("[FIO] Data transmitted: %08x", TransmitBuffer);
679 TransmitInProgress = false;
680
681 if(Control & 0x400)
682 {
683 istatus = true;
684 ::IRQ_Assert(IRQ_SIO, true);
685 }
686 }
687 }
688
689 rxd = Ports[0]->Clock(txd, dsr_pulse_delay[0]) & Ports[1]->Clock(txd, dsr_pulse_delay[1]) &
690 MCPorts[0]->Clock(txd, dsr_pulse_delay[2]) & MCPorts[1]->Clock(txd, dsr_pulse_delay[3]);
691
692 if(ReceiveInProgress)
693 {
694 ReceiveBuffer &= ~(1 << ReceiveBitCounter);
695 ReceiveBuffer |= rxd << ReceiveBitCounter;
696
697 ReceiveBitCounter = (ReceiveBitCounter + 1) & BCMask;
698
699 if(!ReceiveBitCounter)
700 {
701 need_start_stop_check = true;
702 PSX_FIODBGINFO("[FIO] Data received: %08x", ReceiveBuffer);
703
704 ReceiveInProgress = false;
705 ReceiveBufferAvail = true;
706
707 if(Control & 0x800)
708 {
709 istatus = true;
710 ::IRQ_Assert(IRQ_SIO, true);
711 }
712 }
713 }
714 ClockDivider += std::max<uint32>(0x20, (Baudrate << ScaleShift[Mode & 0x3]) & ~1); // Minimum of 0x20 is an emulation sanity check to prevent severe performance degradation.
715 }
716 else
717 break;
718 }
719 }
720
721
722 lastts = timestamp;
723
724
725 if(need_start_stop_check)
726 {
727 CheckStartStopPending(timestamp, true);
728 }
729
730 return(CalcNextEventTS(timestamp, 0x10000000));
731 }
732
733 void FrontIO::ResetTS(void)
734 {
735 int i;
736 for(i = 0; i < 8; i++)
737 {
738 Devices[i]->Update(lastts); // Maybe eventually call Update() from FrontIO::Update() and remove this(but would hurt speed)?
739 Devices[i]->ResetTS();
740
741 DevicesMC[i]->Update(lastts); // Maybe eventually call Update() from FrontIO::Update() and remove this(but would hurt speed)?
742 DevicesMC[i]->ResetTS();
743 }
744
745 for(i = 0; i < 2; i++)
746 {
747 DevicesTap[i]->Update(lastts);
748 DevicesTap[i]->ResetTS();
749 }
750
751 for(i = 0; i < 2; i++)
752 {
753 if(irq10_pulse_ts[i] != PSX_EVENT_MAXTS)
754 irq10_pulse_ts[i] -= lastts;
755 }
756
757 for(i = 0; i < 4; i++)
758 {
759 if(dsr_active_until_ts[i] >= 0)
760 {
761 dsr_active_until_ts[i] -= lastts;
762 //printf("SPOOONY: %d %d\n", i, dsr_active_until_ts[i]);
763 }
764 }
765 lastts = 0;
766 }
767
768
769 void FrontIO::Power(void)
770 {
771 int i;
772 for(i = 0; i < 4; i++)
773 {
774 dsr_pulse_delay[i] = 0;
775 dsr_active_until_ts[i] = -1;
776 }
777
778 for(i = 0; i < 2; i++)
779 irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
780
781 lastts = 0;
782
783 //
784 //
785
786 ClockDivider = 0;
787
788 ReceivePending = false;
789 TransmitPending = false;
790
791 ReceiveInProgress = false;
792 TransmitInProgress = false;
793
794 ReceiveBufferAvail = false;
795
796 TransmitBuffer = 0;
797 ReceiveBuffer = 0;
798
799 ReceiveBitCounter = 0;
800 TransmitBitCounter = 0;
801
802 Mode = 0;
803 Control = 0;
804 Baudrate = 0;
805
806 for(i = 0; i < 8; i++)
807 {
808 Devices[i]->Power();
809 DevicesMC[i]->Power();
810 }
811
812 istatus = false;
813 }
814
815 void FrontIO::UpdateInput(void)
816 {
817 int i;
818 for(i = 0; i < 8; i++)
819 Devices[i]->UpdateInput(DeviceData[i]);
820 }
821
822 void FrontIO::SetInput(unsigned int port, const char *type, void *ptr)
823 {
824 delete Devices[port];
825 Devices[port] = NULL;
826
827 if(port < 2)
828 irq10_pulse_ts[port] = PSX_EVENT_MAXTS;
829
830 if(!strcmp(type, "gamepad") || !strcmp(type, "dancepad"))
831 Devices[port] = Device_Gamepad_Create();
832 else if(!strcmp(type, "dualanalog"))
833 Devices[port] = Device_DualAnalog_Create(false);
834 else if(!strcmp(type, "analogjoy"))
835 Devices[port] = Device_DualAnalog_Create(true);
836 else if(!strcmp(type, "dualshock"))
837 {
838 char name[256];
839 snprintf(name, 256, _("DualShock on port %u"), port + 1);
840 Devices[port] = Device_DualShock_Create(std::string(name));
841 }
842 else if(!strcmp(type, "mouse"))
843 Devices[port] = Device_Mouse_Create();
844 else if(!strcmp(type, "negcon"))
845 Devices[port] = Device_neGcon_Create();
846 else if(!strcmp(type, "guncon"))
847 Devices[port] = Device_GunCon_Create();
848 else if(!strcmp(type, "justifier"))
849 Devices[port] = Device_Justifier_Create();
850 else
851 Devices[port] = new InputDevice();
852
853 Devices[port]->SetAMCT(amct_enabled);
854 Devices[port]->SetCrosshairsColor(chair_colors[port]);
855 DeviceData[port] = ptr;
856
857 MapDevicesToPorts();
858 }
859
860 uint64_t FrontIO::GetMemcardDirtyCount(unsigned int which)
861 {
862 assert(which < 8);
863
864 return(DevicesMC[which]->GetNVDirtyCount());
865 }
866
867 void FrontIO::LoadMemcard(unsigned int which)
868 {
869 assert(which < 8);
870
871 if(DevicesMC[which]->GetNVSize())
872 {
873 DevicesMC[which]->WriteNV(DevicesMC[which]->GetNVData(), 0, (1 << 17));
874 DevicesMC[which]->ResetNVDirtyCount(); // There's no need to rewrite the file if it's the same data.
875 }
876 }
877
878 void FrontIO::LoadMemcard(unsigned int which, const char *path)
879 {
880 assert(which < 8);
881
882 try
883 {
884 if(DevicesMC[which]->GetNVSize())
885 {
886 FileStream mf(path, MODE_READ);
887
888 mf.read(DevicesMC[which]->GetNVData(), (1 << 17));
889
890 DevicesMC[which]->WriteNV(DevicesMC[which]->GetNVData(), 0, (1 << 17));
891 DevicesMC[which]->ResetNVDirtyCount(); // There's no need to rewrite the file if it's the same data.
892 }
893 }
894 catch(MDFN_Error &e)
895 {
896 if(e.GetErrno() != ENOENT)
897 throw(e);
898 }
899 }
900
901 void FrontIO::SaveMemcard(unsigned int which)
902 {
903 assert(which < 8);
904
905 if(DevicesMC[which]->GetNVSize() && DevicesMC[which]->GetNVDirtyCount())
906 {
907 DevicesMC[which]->ReadNV(DevicesMC[which]->GetNVData(), 0, (1 << 17));
908 DevicesMC[which]->ResetNVDirtyCount();
909 }
910 }
911
912 void FrontIO::SaveMemcard(unsigned int which, const char *path)
913 {
914 assert(which < 8);
915
916 if(DevicesMC[which]->GetNVSize() && DevicesMC[which]->GetNVDirtyCount())
917 {
918 FileStream mf(path, MODE_WRITE); // TODO: MODE_WRITE_ATOMIC_OVERWRITE
919
920 DevicesMC[which]->ReadNV(DevicesMC[which]->GetNVData(), 0, (1 << 17));
921 mf.write(DevicesMC[which]->GetNVData(), (1 << 17));
922
923 mf.close(); // Call before resetting the NV dirty count!
924
925 DevicesMC[which]->ResetNVDirtyCount();
926 }
927 }
928
929 bool FrontIO::RequireNoFrameskip(void)
930 {
931 unsigned i;
932
933 for(i = 0; i < 8; i++)
934 if(Devices[i]->RequireNoFrameskip())
935 return(true);
936
937 return(false);
938 }
939
940 void FrontIO::GPULineHook(const int32_t timestamp, const int32_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider)
941 {
942 Update(timestamp);
943
944 for(unsigned i = 0; i < 8; i++)
945 {
946 int32_t plts = Devices[i]->GPULineHook(line_timestamp, vsync, pixels, format, width, pix_clock_offset, pix_clock, pix_clock_divider);
947
948 if(i < 2)
949 {
950 irq10_pulse_ts[i] = plts;
951
952 if(irq10_pulse_ts[i] <= timestamp)
953 {
954 irq10_pulse_ts[i] = PSX_EVENT_MAXTS;
955 ::IRQ_Assert(IRQ_PIO, true);
956 ::IRQ_Assert(IRQ_PIO, false);
957 }
958 }
959 }
960
961 //
962 // Draw crosshairs in a separate pass so the crosshairs won't mess up the color evaluation of later lightun GPULineHook()s.
963 //
964 if(pixels && pix_clock)
965 {
966 for(unsigned i = 0; i < 8; i++)
967 {
968 Devices[i]->DrawCrosshairs(pixels, format, width, pix_clock);
969 }
970 }
971
972 PSX_SetEventNT(PSX_EVENT_FIO, CalcNextEventTS(timestamp, 0x10000000));
973 }
974
975 static InputDeviceInfoStruct InputDeviceInfoPSXPort[] =
976 {
977 // None
978 {
979 "none",
980 "none",
981 NULL,
982 NULL,
983 0,
984 NULL
985 },
986
987 // Gamepad(SCPH-1080)
988 {
989 "gamepad",
990 "Digital Gamepad",
991 "PlayStation digital gamepad; SCPH-1080.",
992 NULL,
993 sizeof(Device_Gamepad_IDII) / sizeof(InputDeviceInputInfoStruct),
994 Device_Gamepad_IDII,
995 },
996
997 // Dual Shock Gamepad(SCPH-1200)
998 {
999 "dualshock",
1000 "DualShock",
1001 "DualShock gamepad; SCPH-1200. Emulation in Mednafen includes the analog mode toggle button. Rumble is emulated, but currently only supported on Linux, and MS Windows via the XInput API and XInput-compatible gamepads/joysticks. If you're having trouble getting rumble to work on Linux, see if Mednafen is printing out error messages during startup regarding /dev/input/event*, and resolve the issue(s) as necessary.",
1002 NULL,
1003 sizeof(Device_DualShock_IDII) / sizeof(InputDeviceInputInfoStruct),
1004 Device_DualShock_IDII,
1005 },
1006
1007 // Dual Analog Gamepad(SCPH-1180), forced to analog mode.
1008 {
1009 "dualanalog",
1010 "Dual Analog",
1011 "Dual Analog gamepad; SCPH-1180. It is the predecessor/prototype to the more advanced DualShock. Emulated in Mednafen as forced to analog mode, and without rumble.",
1012 NULL,
1013 sizeof(Device_DualAnalog_IDII) / sizeof(InputDeviceInputInfoStruct),
1014 Device_DualAnalog_IDII,
1015 },
1016
1017
1018 // Analog joystick(SCPH-1110), forced to analog mode - emulated through a tweak to dual analog gamepad emulation.
1019 {
1020 "analogjoy",
1021 "Analog Joystick",
1022 "Flight-game-oriented dual-joystick controller; SCPH-1110. Emulated in Mednafen as forced to analog mode.",
1023 NULL,
1024 sizeof(Device_AnalogJoy_IDII) / sizeof(InputDeviceInputInfoStruct),
1025 Device_AnalogJoy_IDII,
1026 },
1027
1028 {
1029 "mouse",
1030 "Mouse",
1031 NULL,
1032 NULL,
1033 sizeof(Device_Mouse_IDII) / sizeof(InputDeviceInputInfoStruct),
1034 Device_Mouse_IDII,
1035 },
1036
1037 {
1038 "negcon",
1039 "neGcon",
1040 "Namco's unconventional twisty racing-game-oriented gamepad; NPC-101.",
1041 NULL,
1042 sizeof(Device_neGcon_IDII) / sizeof(InputDeviceInputInfoStruct),
1043 Device_neGcon_IDII,
1044 },
1045
1046 {
1047 "guncon",
1048 "GunCon",
1049 "Namco's light gun; NPC-103.",
1050 NULL,
1051 sizeof(Device_GunCon_IDII) / sizeof(InputDeviceInputInfoStruct),
1052 Device_GunCon_IDII,
1053 },
1054
1055 {
1056 "justifier",
1057 "Konami Justifier",
1058 "Konami's light gun; SLUH-00017. Rumored to be wrought of the coagulated rage of all who tried to shoot The Dog. If the game you want to play supports the \"GunCon\", you should use that instead. NOTE: Currently does not work properly when on any of ports 1B-1D and 2B-2D.",
1059 NULL,
1060 sizeof(Device_Justifier_IDII) / sizeof(InputDeviceInputInfoStruct),
1061 Device_Justifier_IDII,
1062 },
1063
1064 {
1065 "dancepad",
1066 "Dance Pad",
1067 "Dingo Dingo Rodeo!",
1068 NULL,
1069 sizeof(Device_Dancepad_IDII) / sizeof(InputDeviceInputInfoStruct),
1070 Device_Dancepad_IDII,
1071 },
1072
1073 };
1074
1075 static const InputPortInfoStruct PortInfo[] =
1076 {
1077 { "port1", "Virtual Port 1", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1078 { "port2", "Virtual Port 2", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1079 { "port3", "Virtual Port 3", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1080 { "port4", "Virtual Port 4", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1081 { "port5", "Virtual Port 5", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1082 { "port6", "Virtual Port 6", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1083 { "port7", "Virtual Port 7", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1084 { "port8", "Virtual Port 8", sizeof(InputDeviceInfoPSXPort) / sizeof(InputDeviceInfoStruct), InputDeviceInfoPSXPort, "gamepad" },
1085 };
1086
1087 InputInfoStruct FIO_InputInfo =
1088 {
1089 sizeof(PortInfo) / sizeof(InputPortInfoStruct),
1090 PortInfo
1091 };
0 #ifndef __MDFN_PSX_FRONTIO_H
1 #define __MDFN_PSX_FRONTIO_H
2
3 class InputDevice_Multitap;
4
5 class InputDevice
6 {
7 public:
8
9 InputDevice();
10 virtual ~InputDevice();
11
12 virtual void Power(void);
13 virtual void UpdateInput(const void *data);
14 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
15
16 virtual bool RequireNoFrameskip(void);
17 // Divide mouse X coordinate by pix_clock_divider in the lightgun code to get the coordinate in pixel(clocks).
18 virtual int32_t GPULineHook(const int32_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider);
19
20 virtual void Update(const int32_t timestamp); // Partially-implemented, don't rely on for timing any more fine-grained than a video frame for now.
21 virtual void ResetTS(void);
22
23 void DrawCrosshairs(uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock);
24
25 virtual void SetAMCT(bool enabled);
26 virtual void SetCrosshairsColor(uint32_t color);
27
28 virtual void SetDTR(bool new_dtr);
29 virtual bool GetDSR(void); // Currently unused.
30
31 virtual bool Clock(bool TxD, int32_t &dsr_pulse_delay);
32
33 virtual uint8 *GetNVData() { return NULL; }
34 virtual uint32_t GetNVSize(void);
35 virtual void ReadNV(uint8_t *buffer, uint32_t offset, uint32_t count);
36 virtual void WriteNV(const uint8_t *buffer, uint32_t offset, uint32_t count);
37
38 // Dirty count should be incremented on each call to a method this class that causes at least 1 write to occur to the
39 // nonvolatile memory(IE Clock() in the correct command phase, and WriteNV()).
40 virtual uint64_t GetNVDirtyCount(void);
41 virtual void ResetNVDirtyCount(void);
42
43 private:
44 unsigned chair_r, chair_g, chair_b;
45 bool draw_chair;
46 protected:
47 int32 chair_x, chair_y;
48 };
49
50 class FrontIO
51 {
52 public:
53
54 FrontIO(bool emulate_memcards_[8], bool emulate_multitap_[2]);
55 ~FrontIO();
56
57 void Power(void);
58 void Write(int32_t timestamp, uint32_t A, uint32_t V);
59 uint32_t Read(int32_t timestamp, uint32_t A);
60 int32_t CalcNextEventTS(int32_t timestamp, int32_t next_event);
61 int32_t Update(int32_t timestamp);
62 void ResetTS(void);
63
64 bool RequireNoFrameskip(void);
65 void GPULineHook(const int32_t timestamp, const int32_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider);
66
67 void UpdateInput(void);
68 void SetInput(unsigned int port, const char *type, void *ptr);
69 void SetAMCT(bool enabled);
70 void SetCrosshairsColor(unsigned port, uint32_t color);
71
72 InputDevice *GetMemcardDevice(unsigned int which);
73 uint64_t GetMemcardDirtyCount(unsigned int which);
74 void LoadMemcard(unsigned int which, const char *path);
75 void LoadMemcard(unsigned int which);
76 void SaveMemcard(unsigned int which, const char *path); //, bool force_save = false);
77 void SaveMemcard(unsigned int which);
78
79 int StateAction(StateMem* sm, int load, int data_only);
80
81 private:
82
83 void DoDSRIRQ(void);
84 void CheckStartStopPending(int32_t timestamp, bool skip_event_set = false);
85
86 void MapDevicesToPorts(void);
87
88 bool emulate_memcards[8];
89 bool emulate_multitap[2];
90
91 InputDevice *Ports[2];
92 InputDevice *MCPorts[2];
93
94 InputDevice *DummyDevice;
95 InputDevice_Multitap *DevicesTap[2];
96
97 InputDevice *Devices[8];
98 void *DeviceData[8];
99
100 InputDevice *DevicesMC[8];
101
102 int32_t ClockDivider;
103
104 bool ReceivePending;
105 bool TransmitPending;
106
107 bool ReceiveInProgress;
108 bool TransmitInProgress;
109
110 bool ReceiveBufferAvail;
111
112 uint8_t ReceiveBuffer;
113 uint8_t TransmitBuffer;
114
115 int32_t ReceiveBitCounter;
116 int32_t TransmitBitCounter;
117
118 uint16_t Mode;
119 uint16_t Control;
120 uint16_t Baudrate;
121
122
123 bool istatus;
124 int32_t irq10_pulse_ts[2];
125
126 int32_t dsr_pulse_delay[4];
127 int32_t dsr_active_until_ts[4];
128 int32_t lastts;
129 bool amct_enabled;
130 uint32_t chair_colors[8];
131 };
132
133 extern InputInfoStruct FIO_InputInfo;
134
135 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "timer.h"
19
20 /*
21 GPU display timing master clock is nominally 53.693182 MHz for NTSC PlayStations, and 53.203425 MHz for PAL PlayStations.
22
23 Non-interlaced NTSC mode line timing notes(real-world times calculated via PS1 timer and math with nominal CPU clock value):
24
25 263 lines per frame
26
27 ~16714.85 us per frame, average.
28 ~63.55456 us per line, average.
29
30 Multiplying the results of counter 0 in pixel clock mode by the clock divider of the current dot clock mode/width gives a result that's slightly less
31 than expected; the dot clock divider is probably being reset each scanline.
32
33 Non-interlaced PAL mode(but with an NTSC source clock in an NTSC PS1; calculated same way as NTSC values):
34
35 314 lines per frame
36
37 ~19912.27 us per frame, average.
38 ~63.41486 us per line, average.
39
40 FB X and Y display positions can be changed during active display; and Y display position appears to be treated as an offset to the current Y readout
41 position that gets reset around vblank time.
42
43 */
44
45 /*
46 November 29, 2012 notes:
47
48 PAL mode can be turned on, and then off again, mid-frame(creates a neat effect).
49
50 Pixel clock can be changed mid-frame with effect(the effect is either instantaneous, or cached at some point in the scanline, not tested to see which);
51 interestingly, alignment is off on a PS1 when going 5MHz->10MHz>5MHz with a grid image.
52
53 Vertical start and end can be changed during active display, with effect(though it needs to be vs0->ve0->vs1->ve1->..., vs0->vs1->ve0 doesn't apparently do anything
54 different from vs0->ve0.
55 */
56 static const int8 dither_table[4][4] =
57 {
58 { -4, 0, -3, 1 },
59 { 2, -2, 3, -1 },
60 { -3, 1, -4, 0 },
61 { 3, -1, 2, -2 },
62 };
63
64
65 PS_GPU::PS_GPU(bool pal_clock_and_tv, int sls, int sle)
66 {
67 int x, y, v;
68 HardwarePALType = pal_clock_and_tv;
69
70 for(y = 0; y < 4; y++)
71 for(x = 0; x < 4; x++)
72 for(v = 0; v < 512; v++)
73 {
74 int value = v + dither_table[y][x];
75
76 value >>= 3;
77
78 if(value < 0)
79 value = 0;
80
81 if(value > 0x1F)
82 value = 0x1F;
83
84 DitherLUT[y][x][v] = value;
85 }
86
87 if(HardwarePALType == false) // NTSC clock
88 GPUClockRatio = 103896; // 65536 * 53693181.818 / (44100 * 768)
89 else // PAL clock
90 GPUClockRatio = 102948; // 65536 * 53203425 / (44100 * 768)
91
92 memset(RGB8SAT_Under, 0, sizeof(RGB8SAT_Under));
93
94 for(int i = 0; i < 256; i++)
95 RGB8SAT[i] = i;
96
97 memset(RGB8SAT_Over, 0xFF, sizeof(RGB8SAT_Over));
98
99 LineVisFirst = sls;
100 LineVisLast = sle;
101 }
102
103 PS_GPU::~PS_GPU()
104 {
105
106 }
107
108 void PS_GPU::FillVideoParams(MDFNGI* gi)
109 {
110 if(HardwarePALType)
111 {
112 gi->lcm_width = 2800;
113 gi->lcm_height = (LineVisLast + 1 - LineVisFirst) * 2; //576;
114
115 gi->nominal_width = 384; // Dunno. :(
116 gi->nominal_height = LineVisLast + 1 - LineVisFirst; //288;
117
118 gi->fb_width = 768;
119 gi->fb_height = 576;
120
121 gi->fps = 836203078; // 49.842
122
123 gi->VideoSystem = VIDSYS_PAL;
124 }
125 else
126 {
127 gi->lcm_width = 2800;
128 gi->lcm_height = (LineVisLast + 1 - LineVisFirst) * 2; //480;
129
130 gi->nominal_width = 320;
131 gi->nominal_height = LineVisLast + 1 - LineVisFirst; //240;
132
133 gi->fb_width = 768;
134 gi->fb_height = 480;
135
136 gi->fps = 1005643085; // 59.941
137
138 gi->VideoSystem = VIDSYS_NTSC;
139 }
140
141 //
142 // For Justifier and Guncon.
143 //
144 gi->mouse_scale_x = (float)gi->lcm_width / gi->nominal_width;
145 gi->mouse_offs_x = (float)(2800 - gi->lcm_width) / 2;
146
147 gi->mouse_scale_y = 1.0;
148 gi->mouse_offs_y = LineVisFirst;
149 }
150
151 void PS_GPU::SoftReset(void) // Control command 0x00
152 {
153 IRQPending = false;
154 IRQ_Assert(IRQ_GPU, IRQPending);
155
156 InvalidateCache();
157 DMAControl = 0;
158
159 if(DrawTimeAvail < 0)
160 DrawTimeAvail = 0;
161
162 BlitterFIFO.Flush();
163 DataReadBufferEx = 0;
164 InCmd = INCMD_NONE;
165
166 DisplayOff = 1;
167 DisplayFB_XStart = 0;
168 DisplayFB_YStart = 0;
169
170 DisplayMode = 0;
171
172 HorizStart = 0x200;
173 HorizEnd = 0xC00;
174
175 VertStart = 0x10;
176 VertEnd = 0x100;
177
178
179 //
180 TexPageX = 0;
181 TexPageY = 0;
182
183 SpriteFlip = 0;
184
185 abr = 0;
186 TexMode = 0;
187
188 dtd = 0;
189 dfe = 0;
190
191 //
192 tww = 0;
193 twh = 0;
194 twx = 0;
195 twy = 0;
196
197 RecalcTexWindowStuff();
198
199 //
200 ClipX0 = 0;
201 ClipY0 = 0;
202
203 //
204 ClipX1 = 0;
205 ClipY1 = 0;
206
207 //
208 OffsX = 0;
209 OffsY = 0;
210
211 //
212 MaskSetOR = 0;
213 MaskEvalAND = 0;
214
215 TexDisable = false;
216 TexDisableAllowChange = false;
217 }
218
219 void PS_GPU::Power(void)
220 {
221 memset(GPURAM, 0, sizeof(GPURAM));
222
223 memset(CLUT_Cache, 0, sizeof(CLUT_Cache));
224 CLUT_Cache_VB = ~0U;
225
226 memset(TexCache, 0xFF, sizeof(TexCache));
227
228 DMAControl = 0;
229
230 ClipX0 = 0;
231 ClipY0 = 0;
232 ClipX1 = 0;
233 ClipY1 = 0;
234
235 OffsX = 0;
236 OffsY = 0;
237
238 dtd = false;
239 dfe = false;
240
241 MaskSetOR = 0;
242 MaskEvalAND = 0;
243
244 TexDisable = false;
245 TexDisableAllowChange = false;
246
247 tww = 0;
248 twh = 0;
249 twx = 0;
250 twy = 0;
251
252 RecalcTexWindowStuff();
253
254 TexPageX = 0;
255 TexPageY = 0;
256 SpriteFlip = 0;
257
258 abr = 0;
259 TexMode = 0;
260
261 BlitterFIFO.Flush();
262
263 DataReadBuffer = 0; // Don't reset in SoftReset()
264 DataReadBufferEx = 0;
265 InCmd = INCMD_NONE;
266 FBRW_X = 0;
267 FBRW_Y = 0;
268 FBRW_W = 0;
269 FBRW_H = 0;
270 FBRW_CurY = 0;
271 FBRW_CurX = 0;
272
273 DisplayMode = 0;
274 DisplayOff = 1;
275 DisplayFB_XStart = 0;
276 DisplayFB_YStart = 0;
277
278 HorizStart = 0;
279 HorizEnd = 0;
280
281 VertStart = 0;
282 VertEnd = 0;
283
284 //
285 //
286 //
287 DisplayFB_CurYOffset = 0;
288 DisplayFB_CurLineYReadout = 0;
289 InVBlank = true;
290
291 // TODO: factor out in a separate function.
292 LinesPerField = 263;
293
294 //
295 //
296 //
297 scanline = 0;
298 field = 0;
299 field_ram_readout = 0;
300 PhaseChange = 0;
301
302 //
303 //
304 //
305 DotClockCounter = 0;
306 GPUClockCounter = 0;
307 LineClockCounter = 3412 - 200;
308 LinePhase = 0;
309
310 DrawTimeAvail = 0;
311
312 lastts = 0;
313
314 SoftReset();
315
316 IRQ_Assert(IRQ_VBLANK, InVBlank);
317 TIMER_SetVBlank(InVBlank);
318 }
319
320 void PS_GPU::ResetTS(void)
321 {
322 lastts = 0;
323 }
324
325 #include "gpu_common.cpp"
326 #include "gpu_polygon.cpp"
327 #include "gpu_sprite.cpp"
328 #include "gpu_line.cpp"
329
330 //
331 // C-style function wrappers so our command table isn't so ginormous(in memory usage).
332 //
333 template<int numvertices, bool shaded, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
334 static void G_Command_DrawPolygon(PS_GPU* g, const uint32 *cb)
335 {
336 g->Command_DrawPolygon<numvertices, shaded, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(cb);
337 }
338
339 template<uint8 raw_size, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
340 static void G_Command_DrawSprite(PS_GPU* g, const uint32 *cb)
341 {
342 g->Command_DrawSprite<raw_size, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(cb);
343 }
344
345 template<bool polyline, bool goraud, int BlendMode, bool MaskEval_TA>
346 static void G_Command_DrawLine(PS_GPU* g, const uint32 *cb)
347 {
348 g->Command_DrawLine<polyline, goraud, BlendMode, MaskEval_TA>(cb);
349 }
350
351 void PS_GPU::InvalidateTexCache()
352 {
353 unsigned i;
354 for (i = 0; i < 256; i++)
355 TexCache[i].Tag = ~0U;
356 }
357
358 void PS_GPU::InvalidateCache()
359 {
360 CLUT_Cache_VB = ~0U;
361 InvalidateTexCache();
362 }
363
364 static void G_Command_ClearCache(PS_GPU* g, const uint32 *cb)
365 {
366 g->InvalidateCache();
367 }
368
369 static void G_Command_IRQ(PS_GPU* g, const uint32 *cb)
370 {
371 g->IRQPending = true;
372 IRQ_Assert(IRQ_GPU, g->IRQPending);
373 }
374
375 // Special RAM write mode(16 pixels at a time), does *not* appear to use mask drawing environment settings.
376 //
377 static void G_Command_FBFill(PS_GPU* gpu, const uint32 *cb)
378 {
379 int32_t x, y, r, g, b, destX, destY, width, height;
380 r = cb[0] & 0xFF;
381 g = (cb[0] >> 8) & 0xFF;
382 b = (cb[0] >> 16) & 0xFF;
383 const uint16_t fill_value = ((r >> 3) << 0) | ((g >> 3) << 5) | ((b >> 3) << 10);
384
385 destX = (cb[1] >> 0) & 0x3F0;
386 destY = (cb[1] >> 16) & 0x3FF;
387
388 width = (((cb[2] >> 0) & 0x3FF) + 0xF) & ~0xF;
389 height = (cb[2] >> 16) & 0x1FF;
390
391 //printf("[GPU] FB Fill %d:%d w=%d, h=%d\n", destX, destY, width, height);
392 gpu->DrawTimeAvail -= 46; // Approximate
393
394 for(y = 0; y < height; y++)
395 {
396 const int32 d_y = (y + destY) & 511;
397
398 if(LineSkipTest(gpu, d_y))
399 continue;
400
401 gpu->DrawTimeAvail -= (width >> 3) + 9;
402
403 for(x = 0; x < width; x++)
404 {
405 const int32 d_x = (x + destX) & 1023;
406
407 gpu->GPURAM[d_y][d_x] = fill_value;
408 }
409 }
410 }
411
412 static void G_Command_FBCopy(PS_GPU* g, const uint32 *cb)
413 {
414 int32 sourceX = (cb[1] >> 0) & 0x3FF;
415 int32 sourceY = (cb[1] >> 16) & 0x3FF;
416 int32 destX = (cb[2] >> 0) & 0x3FF;
417 int32 destY = (cb[2] >> 16) & 0x3FF;
418
419 int32 width = (cb[3] >> 0) & 0x3FF;
420 int32 height = (cb[3] >> 16) & 0x1FF;
421
422 if(!width)
423 width = 0x400;
424
425 if(!height)
426 height = 0x200;
427
428 g->InvalidateTexCache();
429 //printf("FB Copy: %d %d %d %d %d %d\n", sourceX, sourceY, destX, destY, width, height);
430
431 g->DrawTimeAvail -= (width * height) * 2;
432
433 for(int32 y = 0; y < height; y++)
434 {
435 for(int32 x = 0; x < width; x += 128)
436 {
437 const int32 chunk_x_max = std::min<int32>(width - x, 128);
438 uint16 tmpbuf[128]; // TODO: Check and see if the GPU is actually (ab)using the CLUT or texture cache.
439
440 for(int32 chunk_x = 0; chunk_x < chunk_x_max; chunk_x++)
441 {
442 int32 s_y = (y + sourceY) & 511;
443 int32 s_x = (x + chunk_x + sourceX) & 1023;
444
445 tmpbuf[chunk_x] = g->GPURAM[s_y][s_x];
446 }
447
448 for(int32 chunk_x = 0; chunk_x < chunk_x_max; chunk_x++)
449 {
450 int32 d_y = (y + destY) & 511;
451 int32 d_x = (x + chunk_x + destX) & 1023;
452
453 if(!(g->GPURAM[d_y][d_x] & g->MaskEvalAND))
454 g->GPURAM[d_y][d_x] = tmpbuf[chunk_x] | g->MaskSetOR;
455 }
456 }
457 }
458 }
459
460 static void G_Command_FBWrite(PS_GPU* g, const uint32 *cb)
461 {
462 //assert(InCmd == INCMD_NONE);
463
464 g->FBRW_X = (cb[1] >> 0) & 0x3FF;
465 g->FBRW_Y = (cb[1] >> 16) & 0x3FF;
466
467 g->FBRW_W = (cb[2] >> 0) & 0x3FF;
468 g->FBRW_H = (cb[2] >> 16) & 0x1FF;
469
470 if(!g->FBRW_W)
471 g->FBRW_W = 0x400;
472
473 if(!g->FBRW_H)
474 g->FBRW_H = 0x200;
475
476 g->FBRW_CurX = g->FBRW_X;
477 g->FBRW_CurY = g->FBRW_Y;
478
479 g->InvalidateTexCache();
480
481 if(g->FBRW_W != 0 && g->FBRW_H != 0)
482 g->InCmd = INCMD_FBWRITE;
483 }
484
485 /* FBRead: PS1 GPU in SCPH-5501 gives odd, inconsistent results when
486 * raw_height == 0, or raw_height != 0x200 && (raw_height & 0x1FF) == 0
487 */
488
489 static void G_Command_FBRead(PS_GPU* g, const uint32 *cb)
490 {
491 //assert(g->InCmd == INCMD_NONE);
492
493 g->FBRW_X = (cb[1] >> 0) & 0x3FF;
494 g->FBRW_Y = (cb[1] >> 16) & 0x3FF;
495
496 g->FBRW_W = (cb[2] >> 0) & 0x3FF;
497 g->FBRW_H = (cb[2] >> 16) & 0x3FF;
498
499 if(!g->FBRW_W)
500 g->FBRW_W = 0x400;
501
502 if(g->FBRW_H > 0x200)
503 g->FBRW_H &= 0x1FF;
504
505 g->FBRW_CurX = g->FBRW_X;
506 g->FBRW_CurY = g->FBRW_Y;
507
508 g->InvalidateTexCache();
509
510 if(g->FBRW_W != 0 && g->FBRW_H != 0)
511 g->InCmd = INCMD_FBREAD;
512 }
513
514 static void G_Command_DrawMode(PS_GPU* g, const uint32 *cb)
515 {
516 const uint32 cmdw = *cb;
517
518 g->SetTPage(cmdw);
519
520 g->SpriteFlip = (cmdw & 0x3000);
521 g->dtd = (cmdw >> 9) & 1;
522 g->dfe = (cmdw >> 10) & 1;
523
524 //printf("*******************DFE: %d -- scanline=%d\n", dfe, scanline);
525 }
526
527 static void G_Command_TexWindow(PS_GPU* g, const uint32 *cb)
528 {
529 g->tww = (*cb & 0x1F);
530 g->twh = ((*cb >> 5) & 0x1F);
531 g->twx = ((*cb >> 10) & 0x1F);
532 g->twy = ((*cb >> 15) & 0x1F);
533
534 g->RecalcTexWindowStuff();
535 }
536
537 static void G_Command_Clip0(PS_GPU* g, const uint32 *cb)
538 {
539 g->ClipX0 = *cb & 1023;
540 g->ClipY0 = (*cb >> 10) & 1023;
541 }
542
543 static void G_Command_Clip1(PS_GPU* g, const uint32 *cb)
544 {
545 g->ClipX1 = *cb & 1023;
546 g->ClipY1 = (*cb >> 10) & 1023;
547 }
548
549 static void G_Command_DrawingOffset(PS_GPU* g, const uint32 *cb)
550 {
551 g->OffsX = sign_x_to_s32(11, (*cb & 2047));
552 g->OffsY = sign_x_to_s32(11, ((*cb >> 11) & 2047));
553
554 //fprintf(stderr, "[GPU] Drawing offset: %d(raw=%d) %d(raw=%d) -- %d\n", OffsX, *cb, OffsY, *cb >> 11, scanline);
555 }
556
557 static void G_Command_MaskSetting(PS_GPU* g, const uint32 *cb)
558 {
559 //printf("Mask setting: %08x\n", *cb);
560 g->MaskSetOR = (*cb & 1) ? 0x8000 : 0x0000;
561 g->MaskEvalAND = (*cb & 2) ? 0x8000 : 0x0000;
562 }
563
564
565 CTEntry PS_GPU::Commands[256] =
566 {
567 /* 0x00 */
568 NULLCMD(),
569 OTHER_HELPER(1, 2, false, G_Command_ClearCache),
570 OTHER_HELPER(3, 3, false, G_Command_FBFill),
571
572 NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
573 NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
574
575 /* 0x10 */
576 NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
577 NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
578
579 OTHER_HELPER(1, 1, false, G_Command_IRQ),
580
581 /* 0x20 */
582 POLY_HELPER(0x20),
583 POLY_HELPER(0x21),
584 POLY_HELPER(0x22),
585 POLY_HELPER(0x23),
586 POLY_HELPER(0x24),
587 POLY_HELPER(0x25),
588 POLY_HELPER(0x26),
589 POLY_HELPER(0x27),
590 POLY_HELPER(0x28),
591 POLY_HELPER(0x29),
592 POLY_HELPER(0x2a),
593 POLY_HELPER(0x2b),
594 POLY_HELPER(0x2c),
595 POLY_HELPER(0x2d),
596 POLY_HELPER(0x2e),
597 POLY_HELPER(0x2f),
598 POLY_HELPER(0x30),
599 POLY_HELPER(0x31),
600 POLY_HELPER(0x32),
601 POLY_HELPER(0x33),
602 POLY_HELPER(0x34),
603 POLY_HELPER(0x35),
604 POLY_HELPER(0x36),
605 POLY_HELPER(0x37),
606 POLY_HELPER(0x38),
607 POLY_HELPER(0x39),
608 POLY_HELPER(0x3a),
609 POLY_HELPER(0x3b),
610 POLY_HELPER(0x3c),
611 POLY_HELPER(0x3d),
612 POLY_HELPER(0x3e),
613 POLY_HELPER(0x3f),
614
615 LINE_HELPER(0x40),
616 LINE_HELPER(0x41),
617 LINE_HELPER(0x42),
618 LINE_HELPER(0x43),
619 LINE_HELPER(0x44),
620 LINE_HELPER(0x45),
621 LINE_HELPER(0x46),
622 LINE_HELPER(0x47),
623 LINE_HELPER(0x48),
624 LINE_HELPER(0x49),
625 LINE_HELPER(0x4a),
626 LINE_HELPER(0x4b),
627 LINE_HELPER(0x4c),
628 LINE_HELPER(0x4d),
629 LINE_HELPER(0x4e),
630 LINE_HELPER(0x4f),
631 LINE_HELPER(0x50),
632 LINE_HELPER(0x51),
633 LINE_HELPER(0x52),
634 LINE_HELPER(0x53),
635 LINE_HELPER(0x54),
636 LINE_HELPER(0x55),
637 LINE_HELPER(0x56),
638 LINE_HELPER(0x57),
639 LINE_HELPER(0x58),
640 LINE_HELPER(0x59),
641 LINE_HELPER(0x5a),
642 LINE_HELPER(0x5b),
643 LINE_HELPER(0x5c),
644 LINE_HELPER(0x5d),
645 LINE_HELPER(0x5e),
646 LINE_HELPER(0x5f),
647
648 SPR_HELPER(0x60),
649 SPR_HELPER(0x61),
650 SPR_HELPER(0x62),
651 SPR_HELPER(0x63),
652 SPR_HELPER(0x64),
653 SPR_HELPER(0x65),
654 SPR_HELPER(0x66),
655 SPR_HELPER(0x67),
656 SPR_HELPER(0x68),
657 SPR_HELPER(0x69),
658 SPR_HELPER(0x6a),
659 SPR_HELPER(0x6b),
660 SPR_HELPER(0x6c),
661 SPR_HELPER(0x6d),
662 SPR_HELPER(0x6e),
663 SPR_HELPER(0x6f),
664 SPR_HELPER(0x70),
665 SPR_HELPER(0x71),
666 SPR_HELPER(0x72),
667 SPR_HELPER(0x73),
668 SPR_HELPER(0x74),
669 SPR_HELPER(0x75),
670 SPR_HELPER(0x76),
671 SPR_HELPER(0x77),
672 SPR_HELPER(0x78),
673 SPR_HELPER(0x79),
674 SPR_HELPER(0x7a),
675 SPR_HELPER(0x7b),
676 SPR_HELPER(0x7c),
677 SPR_HELPER(0x7d),
678 SPR_HELPER(0x7e),
679 SPR_HELPER(0x7f),
680
681 /* 0x80 ... 0x9F */
682 OTHER_HELPER_X32(4, 2, false, G_Command_FBCopy),
683
684 /* 0xA0 ... 0xBF */
685 OTHER_HELPER_X32(3, 2, false, G_Command_FBWrite),
686
687 /* 0xC0 ... 0xDF */
688 OTHER_HELPER_X32(3, 2, false, G_Command_FBRead),
689
690 /* 0xE0 */
691
692 NULLCMD(),
693 OTHER_HELPER(1, 2, false, G_Command_DrawMode),
694 OTHER_HELPER(1, 2, false, G_Command_TexWindow),
695 OTHER_HELPER(1, 1, true, G_Command_Clip0),
696 OTHER_HELPER(1, 1, true, G_Command_Clip1),
697 OTHER_HELPER(1, 1, true, G_Command_DrawingOffset),
698 OTHER_HELPER(1, 2, false, G_Command_MaskSetting),
699
700 NULLCMD(),
701 NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
702
703 /* 0xF0 */
704 NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
705 NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(), NULLCMD(),
706
707 };
708
709
710 void PS_GPU::ProcessFIFO(void)
711 {
712 uint32_t CB[0x10], InData;
713 unsigned i;
714 uint32_t cc = InCmd_CC;
715 unsigned command_len;
716 const CTEntry *command = &Commands[cc];
717 bool read_fifo = false;
718
719 if(!BlitterFIFO.CanRead())
720 return;
721
722 switch(InCmd)
723 {
724 default:
725 case INCMD_NONE:
726 break;
727
728 case INCMD_FBREAD:
729 return;
730
731 case INCMD_FBWRITE:
732 InData = BlitterFIFO.Read();
733
734 for(i = 0; i < 2; i++)
735 {
736 if(!(GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] & MaskEvalAND))
737 GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] = InData | MaskSetOR;
738
739 FBRW_CurX++;
740 if(FBRW_CurX == (FBRW_X + FBRW_W))
741 {
742 FBRW_CurX = FBRW_X;
743 FBRW_CurY++;
744 if(FBRW_CurY == (FBRW_Y + FBRW_H))
745 {
746 InCmd = INCMD_NONE;
747 break; // Break out of the for() loop.
748 }
749 }
750 InData >>= 16;
751 }
752 return;
753
754 case INCMD_QUAD:
755 if(DrawTimeAvail < 0)
756 return;
757
758 command_len = 1 + (bool)(cc & 0x4) + (bool)(cc & 0x10);
759 read_fifo = true;
760 break;
761 case INCMD_PLINE:
762 if(DrawTimeAvail < 0)
763 return;
764
765 command_len = 1 + (bool)(InCmd_CC & 0x10);
766
767 if((BlitterFIFO.Peek() & 0xF000F000) == 0x50005000)
768 {
769 BlitterFIFO.Read();
770 InCmd = INCMD_NONE;
771 return;
772 }
773
774 read_fifo = true;
775 break;
776 }
777
778 if (!read_fifo)
779 {
780 cc = BlitterFIFO.Peek() >> 24;
781 command = &Commands[cc];
782 command_len = command->len;
783
784 if(DrawTimeAvail < 0 && !command->ss_cmd)
785 return;
786 }
787
788 if(BlitterFIFO.CanRead() < command_len)
789 return;
790
791 for(i = 0; i < command_len; i++)
792 CB[i] = BlitterFIFO.Read();
793
794 if (!read_fifo)
795 {
796 if(!command->ss_cmd)
797 DrawTimeAvail -= 2;
798
799 // A very very ugly kludge to support texture mode specialization. fixme/cleanup/SOMETHING in the future.
800 /* Don't alter SpriteFlip here. */
801 if(cc >= 0x20 && cc <= 0x3F && (cc & 0x4))
802 SetTPage(CB[4 + ((cc >> 4) & 0x1)] >> 16);
803 }
804
805 if ((cc >= 0x80) && (cc <= 0x9F))
806 G_Command_FBCopy(this, CB);
807 else if ((cc >= 0xA0) && (cc <= 0xBF))
808 G_Command_FBWrite(this, CB);
809 else if ((cc >= 0xC0) && (cc <= 0xDF))
810 G_Command_FBRead(this, CB);
811 else switch (cc)
812 {
813 case 0x01:
814 CLUT_Cache_VB = ~0U;
815 InvalidateTexCache();
816 break;
817 case 0x02:
818 G_Command_FBFill(this, CB);
819 break;
820 case 0x1F:
821 this->IRQPending = true;
822 IRQ_Assert(IRQ_GPU, this->IRQPending);
823 break;
824 case 0xe1:
825 G_Command_DrawMode(this, CB);
826 break;
827 case 0xe2:
828 G_Command_TexWindow(this, CB);
829 break;
830 case 0xe3: /* Clip 0 */
831 this->ClipX0 = *CB & 1023;
832 this->ClipY0 = (*CB >> 10) & 1023;
833 break;
834 case 0xe4: /* Clip 1 */
835 this->ClipX1 = *CB & 1023;
836 this->ClipY1 = (*CB >> 10) & 1023;
837 break;
838 case 0xe5: /* Drawing Offset */
839 this->OffsX = sign_x_to_s32(11, (*CB & 2047));
840 this->OffsY = sign_x_to_s32(11, ((*CB >> 11) & 2047));
841 break;
842 case 0xe6: /* Mask Setting */
843 this->MaskSetOR = (*CB & 1) ? 0x8000 : 0x0000;
844 this->MaskEvalAND = (*CB & 2) ? 0x8000 : 0x0000;
845 break;
846 default:
847 if(command->func[abr][TexMode])
848 command->func[abr][TexMode | (MaskEvalAND ? 0x4 : 0x0)](this, CB);
849 break;
850 }
851 }
852
853 INLINE void PS_GPU::WriteCB(uint32_t InData)
854 {
855 if(BlitterFIFO.CanRead() >= 0x10 && (InCmd != INCMD_NONE || (BlitterFIFO.CanRead() - 0x10) >= Commands[BlitterFIFO.Peek() >> 24].fifo_fb_len))
856 {
857 PSX_DBG(PSX_DBG_WARNING, "GPU FIFO overflow!!!\n");
858 return;
859 }
860
861 BlitterFIFO.Write(InData);
862 ProcessFIFO();
863 }
864
865 void PS_GPU::SetTPage(const uint32_t cmdw)
866 {
867 const unsigned NewTexPageX = (cmdw & 0xF) * 64;
868 const unsigned NewTexPageY = (cmdw & 0x10) * 16;
869 const unsigned NewTexMode = (cmdw >> 7) & 0x3;
870
871 abr = (cmdw >> 5) & 0x3;
872
873 if(!NewTexMode != !TexMode || NewTexPageX != TexPageX || NewTexPageY != TexPageY)
874 {
875 InvalidateTexCache();
876 }
877
878 if(TexDisableAllowChange)
879 {
880 bool NewTexDisable = (cmdw >> 11) & 1;
881
882 if (NewTexDisable != TexDisable)
883 InvalidateTexCache();
884
885 TexDisable = NewTexDisable;
886 //printf("TexDisable: %02x\n", TexDisable);
887 }
888
889 TexPageX = NewTexPageX;
890 TexPageY = NewTexPageY;
891 TexMode = NewTexMode;
892 }
893
894 void PS_GPU::Write(const int32_t timestamp, uint32_t A, uint32_t V)
895 {
896 V <<= (A & 3) * 8;
897
898 if(A & 4) // GP1 ("Control")
899 {
900 uint32_t command = V >> 24;
901
902 V &= 0x00FFFFFF;
903
904 //PSX_WARNING("[GPU] Control command: %02x %06x %d", command, V, scanline);
905
906 switch(command)
907 {
908 /*
909 0x40-0xFF do NOT appear to be mirrors, at least not on my PS1's GPU.
910 */
911 default:
912 PSX_WARNING("[GPU] Unknown control command %02x - %06x", command, V);
913 break;
914 case 0x00: // Reset GPU
915 //printf("\n\n************ Soft Reset %u ********* \n\n", scanline);
916 SoftReset();
917 break;
918
919 case 0x01: // Reset command buffer
920 if(DrawTimeAvail < 0)
921 DrawTimeAvail = 0;
922 BlitterFIFO.Flush();
923 InCmd = INCMD_NONE;
924 break;
925
926 case 0x02: // Acknowledge IRQ
927 IRQPending = false;
928 IRQ_Assert(IRQ_GPU, IRQPending);
929 break;
930
931 case 0x03: // Display enable
932 DisplayOff = V & 1;
933 break;
934
935 case 0x04: // DMA Setup
936 DMAControl = V & 0x3;
937 break;
938
939 case 0x05: // Start of display area in framebuffer
940 DisplayFB_XStart = V & 0x3FE; // Lower bit is apparently ignored.
941 DisplayFB_YStart = (V >> 10) & 0x1FF;
942 break;
943
944 case 0x06: // Horizontal display range
945 HorizStart = V & 0xFFF;
946 HorizEnd = (V >> 12) & 0xFFF;
947 break;
948
949 case 0x07:
950 VertStart = V & 0x3FF;
951 VertEnd = (V >> 10) & 0x3FF;
952 break;
953
954 case 0x08:
955 //printf("\n\nDISPLAYMODE SET: 0x%02x, %u *************************\n\n\n", V & 0xFF, scanline);
956 DisplayMode = V & 0xFF;
957 break;
958
959 case 0x09:
960 TexDisableAllowChange = V & 1;
961 break;
962
963 case 0x10: // GPU info(?)
964 switch(V & 0xF)
965 {
966 // DataReadBuffer must remain unchanged for any unhandled GPU info index.
967 default: break;
968
969 case 0x2:
970 DataReadBufferEx &= 0xFFF00000;
971 DataReadBufferEx |= (tww << 0) | (twh << 5) | (twx << 10) | (twy << 15);
972 DataReadBuffer = DataReadBufferEx;
973 break;
974
975 case 0x3:
976 DataReadBufferEx &= 0xFFF00000;
977 DataReadBufferEx |= (ClipY0 << 10) | ClipX0;
978 DataReadBuffer = DataReadBufferEx;
979 break;
980
981 case 0x4:
982 DataReadBufferEx &= 0xFFF00000;
983 DataReadBufferEx |= (ClipY1 << 10) | ClipX1;
984 DataReadBuffer = DataReadBufferEx;
985 break;
986
987 case 0x5:
988 DataReadBufferEx &= 0xFFC00000;
989 DataReadBufferEx |= (OffsX & 2047) | ((OffsY & 2047) << 11);
990 DataReadBuffer = DataReadBufferEx;
991 break;
992
993 case 0x7:
994 DataReadBufferEx = 2;
995 DataReadBuffer = DataReadBufferEx;
996 break;
997
998 case 0x8:
999 DataReadBufferEx = 0;
1000 DataReadBuffer = DataReadBufferEx;
1001 break;
1002 }
1003 break;
1004
1005 }
1006 }
1007 else // GP0 ("Data")
1008 {
1009 //uint32_t command = V >> 24;
1010 //printf("Meow command: %02x\n", command);
1011 //assert(!(DMAControl & 2));
1012 WriteCB(V);
1013 }
1014 }
1015
1016
1017 void PS_GPU::WriteDMA(uint32_t V)
1018 {
1019 WriteCB(V);
1020 }
1021
1022 INLINE uint32_t PS_GPU::ReadData(void)
1023 {
1024 if(InCmd == INCMD_FBREAD)
1025 {
1026 DataReadBufferEx = 0;
1027 for(int i = 0; i < 2; i++)
1028 {
1029 DataReadBufferEx |= GPURAM[FBRW_CurY & 511][FBRW_CurX & 1023] << (i * 16);
1030
1031 FBRW_CurX++;
1032 if(FBRW_CurX == (FBRW_X + FBRW_W))
1033 {
1034 if((FBRW_CurY + 1) == (FBRW_Y + FBRW_H))
1035 {
1036 InCmd = INCMD_NONE;
1037 }
1038 else
1039 {
1040 FBRW_CurY++;
1041 FBRW_CurX = FBRW_X;
1042 }
1043 }
1044 }
1045
1046 return DataReadBufferEx;
1047 }
1048
1049 return DataReadBuffer;
1050 }
1051
1052 uint32_t PS_GPU::ReadDMA(void)
1053 {
1054 return ReadData();
1055 }
1056
1057 uint32_t PS_GPU::Read(const int32_t timestamp, uint32_t A)
1058 {
1059 uint32_t ret = 0;
1060
1061 if(A & 4) // Status
1062 {
1063 ret = (((DisplayMode << 1) & 0x7F) | ((DisplayMode >> 6) & 1)) << 16;
1064
1065 ret |= (DisplayMode & 0x80) << 7;
1066
1067 ret |= DMAControl << 29;
1068
1069 ret |= (DisplayFB_CurLineYReadout & 1) << 31;
1070
1071 ret |= (!field) << 13;
1072
1073 if(DMAControl & 0x02)
1074 ret |= 1 << 25;
1075
1076 ret |= IRQPending << 24;
1077
1078 ret |= DisplayOff << 23;
1079
1080 if(InCmd == INCMD_NONE && DrawTimeAvail >= 0 && BlitterFIFO.CanRead() == 0x00) // GPU idle bit.
1081 ret |= 1 << 26;
1082
1083 if(InCmd == INCMD_FBREAD) // Might want to more accurately emulate this in the future?
1084 ret |= (1 << 27);
1085
1086 ret |= CalcFIFOReadyBit() << 28; // FIFO has room bit? (kinda).
1087
1088 //
1089 //
1090 ret |= TexPageX >> 6;
1091 ret |= TexPageY >> 4;
1092 ret |= abr << 5;
1093 ret |= TexMode << 7;
1094
1095 ret |= dtd << 9;
1096 ret |= dfe << 10;
1097
1098 if(MaskSetOR)
1099 ret |= 1 << 11;
1100
1101 if(MaskEvalAND)
1102 ret |= 1 << 12;
1103
1104 ret |= TexDisable << 15;
1105 }
1106 else // "Data"
1107 ret = ReadData();
1108
1109 if(DMAControl & 2)
1110 {
1111 //PSX_WARNING("[GPU READ WHEN (DMACONTROL&2)] 0x%08x - ret=0x%08x, scanline=%d", A, ret, scanline);
1112 }
1113
1114 return(ret >> ((A & 3) * 8));
1115 }
1116
1117 INLINE void PS_GPU::ReorderRGB_Var(uint32_t out_Rshift, uint32_t out_Gshift, uint32_t out_Bshift, bool bpp24, const uint16_t *src, uint32_t *dest, const int32 dx_start, const int32 dx_end, int32 fb_x)
1118 {
1119 if(bpp24) // 24bpp
1120 {
1121 for(int32 x = dx_start; x < dx_end; x++)
1122 {
1123 uint32_t srcpix;
1124
1125 srcpix = src[(fb_x >> 1) + 0] | (src[((fb_x >> 1) + 1) & 0x7FF] << 16);
1126 srcpix >>= (fb_x & 1) * 8;
1127
1128 dest[x] = (((srcpix >> 0) << RED_SHIFT) & (0xFF << RED_SHIFT)) | (((srcpix >> 8) << GREEN_SHIFT) & (0xFF << GREEN_SHIFT)) |
1129 (((srcpix >> 16) << BLUE_SHIFT) & (0xFF << BLUE_SHIFT));
1130
1131 fb_x = (fb_x + 3) & 0x7FF;
1132 }
1133 } // 15bpp
1134 else
1135 {
1136 for(int32 x = dx_start; x < dx_end; x++)
1137 {
1138 uint32_t srcpix = src[fb_x >> 1];
1139 dest[x] = MAKECOLOR((((srcpix >> 0) & 0x1F) << 3), (((srcpix >> 5) & 0x1F) << 3), (((srcpix >> 10) & 0x1F) << 3), 0);
1140
1141 fb_x = (fb_x + 2) & 0x7FF;
1142 }
1143 }
1144
1145 }
1146
1147 int32_t PS_GPU::Update(const int32_t sys_timestamp)
1148 {
1149 static const uint32_t DotClockRatios[5] = { 10, 8, 5, 4, 7 };
1150 const uint32_t dmc = (DisplayMode & 0x40) ? 4 : (DisplayMode & 0x3);
1151 const uint32_t dmw = 2800 / DotClockRatios[dmc]; // Must be <= 768
1152
1153 int32 sys_clocks = sys_timestamp - lastts;
1154 int32 gpu_clocks;
1155
1156 //printf("GPUISH: %d\n", sys_timestamp - lastts);
1157
1158 if(!sys_clocks)
1159 goto TheEnd;
1160
1161 DrawTimeAvail += sys_clocks << 1;
1162
1163 if(DrawTimeAvail > 256)
1164 DrawTimeAvail = 256;
1165
1166 ProcessFIFO();
1167
1168 //puts("GPU Update Start");
1169
1170 GPUClockCounter += (uint64)sys_clocks * GPUClockRatio;
1171
1172 gpu_clocks = GPUClockCounter >> 16;
1173 GPUClockCounter -= gpu_clocks << 16;
1174
1175 while(gpu_clocks > 0)
1176 {
1177 int32 chunk_clocks = gpu_clocks;
1178 int32 dot_clocks;
1179
1180 if(chunk_clocks > LineClockCounter)
1181 {
1182 //printf("Chunk: %u, LCC: %u\n", chunk_clocks, LineClockCounter);
1183 chunk_clocks = LineClockCounter;
1184 }
1185
1186 gpu_clocks -= chunk_clocks;
1187 LineClockCounter -= chunk_clocks;
1188
1189 DotClockCounter += chunk_clocks;
1190 dot_clocks = DotClockCounter / DotClockRatios[DisplayMode & 0x3];
1191 DotClockCounter -= dot_clocks * DotClockRatios[DisplayMode & 0x3];
1192
1193 TIMER_AddDotClocks(dot_clocks);
1194
1195
1196 if(!LineClockCounter)
1197 {
1198 PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(sys_timestamp)); // We could just call this at the top of GPU_Update(), but do it here for slightly less CPU usage(presumably).
1199
1200 LinePhase = (LinePhase + 1) & 1;
1201
1202 if(LinePhase)
1203 {
1204 TIMER_SetHRetrace(true);
1205 LineClockCounter = 200;
1206 TIMER_ClockHRetrace();
1207 }
1208 else
1209 {
1210 const unsigned int FirstVisibleLine = LineVisFirst + (HardwarePALType ? 20 : 16);
1211 const unsigned int VisibleLineCount = LineVisLast + 1 - LineVisFirst; //HardwarePALType ? 288 : 240;
1212
1213 TIMER_SetHRetrace(false);
1214
1215 if(DisplayMode & 0x08)
1216 LineClockCounter = 3405 - 200;
1217 else
1218 LineClockCounter = 3412 + PhaseChange - 200;
1219
1220 scanline = (scanline + 1) % LinesPerField;
1221 PhaseChange = !PhaseChange;
1222
1223 #ifdef WANT_DEBUGGER
1224 DBG_GPUScanlineHook(scanline);
1225 #endif
1226
1227 //
1228 //
1229 //
1230 if(scanline == (HardwarePALType ? 308 : 256)) // Will need to be redone if we ever allow for visible vertical overscan with NTSC.
1231 {
1232 if(sl_zero_reached)
1233 {
1234 //printf("Req Exit(visible fallthrough case): %u\n", scanline);
1235 PSX_RequestMLExit();
1236 }
1237 }
1238
1239 if(scanline == (LinesPerField - 1))
1240 {
1241 if(sl_zero_reached)
1242 {
1243 //printf("Req Exit(final fallthrough case): %u\n", scanline);
1244 PSX_RequestMLExit();
1245 }
1246
1247 if(DisplayMode & 0x20)
1248 field = !field;
1249 else
1250 field = 0;
1251 }
1252
1253 if(scanline == 0)
1254 {
1255 assert(sl_zero_reached == false);
1256 sl_zero_reached = true;
1257
1258 if(DisplayMode & 0x20)
1259 {
1260 if(DisplayMode & 0x08) // PAL
1261 LinesPerField = 313 - field;
1262 else // NTSC
1263 LinesPerField = 263 - field;
1264 }
1265 else
1266 {
1267 field = 0; // May not be the correct place for this?
1268
1269 if(DisplayMode & 0x08) // PAL
1270 LinesPerField = 314;
1271 else // NTSC
1272 LinesPerField = 263;
1273 }
1274
1275
1276 if(espec)
1277 {
1278 if((bool)(DisplayMode & 0x08) != HardwarePALType)
1279 {
1280 DisplayRect->x = 0;
1281 DisplayRect->y = 0;
1282 DisplayRect->w = 384;
1283 DisplayRect->h = VisibleLineCount;
1284
1285 for(int32 y = 0; y < DisplayRect->h; y++)
1286 {
1287 uint32_t *dest = surface->pixels + y * surface->pitch32;
1288
1289 LineWidths[y] = 384;
1290
1291 memset(dest, 0, 384 * sizeof(int32));
1292 }
1293
1294 //char buffer[256];
1295 //snprintf(buffer, sizeof(buffer), _("VIDEO STANDARD MISMATCH"));
1296 //DrawTextTrans(surface->pixels + ((DisplayRect->h / 2) - (13 / 2)) * surface->pitch32, surface->pitch32 << 2, DisplayRect->w, (UTF8*)buffer,
1297 //MAKECOLOR(0x00, 0xFF, 0x00), true, MDFN_FONT_6x13_12x13, 0);
1298 }
1299 else
1300 {
1301 espec->InterlaceOn = (bool)(DisplayMode & 0x20);
1302 espec->InterlaceField = (bool)(DisplayMode & 0x20) && field;
1303
1304 DisplayRect->x = 0;
1305 DisplayRect->y = 0;
1306 DisplayRect->w = 0;
1307 DisplayRect->h = VisibleLineCount << (bool)(DisplayMode & 0x20);
1308
1309 // Clear ~0 state.
1310 LineWidths[0] = 0;
1311
1312 for(int i = 0; i < (DisplayRect->y + DisplayRect->h); i++)
1313 {
1314 surface->pixels[i * surface->pitch32 + 0] =
1315 surface->pixels[i * surface->pitch32 + 1] = 0;
1316 LineWidths[i] = 2;
1317 }
1318 }
1319 }
1320 }
1321
1322 //
1323 // Don't mess with the order of evaluation of these scanline == VertXXX && (InVblankwhatever) if statements and the following IRQ/timer vblank stuff
1324 // unless you know what you're doing!!! (IE you've run further tests to refine the behavior)
1325 //
1326 if(scanline == VertEnd && !InVBlank)
1327 {
1328 if(sl_zero_reached)
1329 {
1330 // Gameplay in Descent(NTSC) has vblank at scanline 236
1331 //
1332 // Mikagura Shoujo Tanteidan has vblank at scanline 192 during intro
1333 // FMV(which we don't handle here because low-latency in that case is not so important).
1334 //
1335 if(scanline >= (HardwarePALType ? 260 : 232))
1336 {
1337 //printf("Req Exit(vblank case): %u\n", scanline);
1338 PSX_RequestMLExit();
1339 }
1340 #if 0
1341 else
1342 {
1343 //printf("VBlank too early, chickening out early exit: %u!\n", scanline);
1344 }
1345 #endif
1346 }
1347
1348 //printf("VBLANK: %u\n", scanline);
1349 InVBlank = true;
1350
1351 DisplayFB_CurYOffset = 0;
1352
1353 if((DisplayMode & 0x24) == 0x24)
1354 field_ram_readout = !field;
1355 else
1356 field_ram_readout = 0;
1357 }
1358
1359 if(scanline == VertStart && InVBlank)
1360 {
1361 InVBlank = false;
1362
1363 // Note to self: X-Men Mutant Academy relies on this being set on the proper scanline in 480i mode(otherwise it locks up on startup).
1364 //if(HeightMode)
1365 // DisplayFB_CurYOffset = field;
1366 }
1367
1368 IRQ_Assert(IRQ_VBLANK, InVBlank);
1369 TIMER_SetVBlank(InVBlank);
1370 //
1371 //
1372 //
1373
1374 // Needs to occur even in vblank.
1375 // Not particularly confident about the timing of this in regards to vblank and the upper bit(ODE) of the GPU status port, though the test that
1376 // showed an oddity was pathological in that VertEnd < VertStart in it.
1377 if((DisplayMode & 0x24) == 0x24)
1378 DisplayFB_CurLineYReadout = (DisplayFB_YStart + (DisplayFB_CurYOffset << 1) + (InVBlank ? 0 : field_ram_readout)) & 0x1FF;
1379 else
1380 DisplayFB_CurLineYReadout = (DisplayFB_YStart + DisplayFB_CurYOffset) & 0x1FF;
1381
1382 unsigned dmw_width = 0;
1383 unsigned pix_clock_offset = 0;
1384 unsigned pix_clock = 0;
1385 unsigned pix_clock_div = 0;
1386 uint32_t *dest = NULL;
1387 if((bool)(DisplayMode & 0x08) == HardwarePALType && scanline >= FirstVisibleLine && scanline < (FirstVisibleLine + VisibleLineCount))
1388 {
1389 int32 dest_line;
1390 int32 fb_x = DisplayFB_XStart * 2;
1391 int32 dx_start = HorizStart, dx_end = HorizEnd;
1392
1393 dest_line = ((scanline - FirstVisibleLine) << espec->InterlaceOn) + espec->InterlaceField;
1394 dest = surface->pixels + dest_line * surface->pitch32;
1395
1396 if(dx_end < dx_start)
1397 dx_end = dx_start;
1398
1399 dx_start = dx_start / DotClockRatios[dmc];
1400 dx_end = dx_end / DotClockRatios[dmc];
1401
1402 dx_start -= 488 / DotClockRatios[dmc];
1403 dx_end -= 488 / DotClockRatios[dmc];
1404
1405 if(dx_start < 0)
1406 {
1407 fb_x -= dx_start * ((DisplayMode & 0x10) ? 3 : 2);
1408 fb_x &= 0x7FF; //0x3FF;
1409 dx_start = 0;
1410 }
1411
1412 if((uint32)dx_end > dmw)
1413 dx_end = dmw;
1414
1415 if(InVBlank || DisplayOff)
1416 dx_start = dx_end = 0;
1417
1418 LineWidths[dest_line] = dmw;
1419
1420 {
1421 uint32_t x;
1422 const uint16_t *src = GPURAM[DisplayFB_CurLineYReadout];
1423
1424 memset(dest, 0, dx_start * sizeof(int32));
1425
1426 //printf("%d %d %d - %d %d\n", scanline, dx_start, dx_end, HorizStart, HorizEnd);
1427 ReorderRGB_Var(RED_SHIFT, GREEN_SHIFT, BLUE_SHIFT, DisplayMode & 0x10, src, dest, dx_start, dx_end, fb_x);
1428
1429 for(x = dx_end; x < dmw; x++)
1430 dest[x] = 0;
1431 }
1432
1433 //if(scanline == 64)
1434 // printf("%u\n", sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio);
1435
1436 dmw_width = dmw;
1437 pix_clock_offset = (488 - 146) / DotClockRatios[dmc];
1438 pix_clock = (HardwarePALType ? 53203425 : 53693182) / DotClockRatios[dmc];
1439 pix_clock_div = DotClockRatios[dmc];
1440 }
1441 PSX_GPULineHook(sys_timestamp, sys_timestamp - ((uint64)gpu_clocks * 65536) / GPUClockRatio, scanline == 0, dest, &surface->format, dmw_width, pix_clock_offset, pix_clock, pix_clock_div);
1442
1443 if(!InVBlank)
1444 {
1445 DisplayFB_CurYOffset = (DisplayFB_CurYOffset + 1) & 0x1FF;
1446 }
1447 }
1448 PSX_SetEventNT(PSX_EVENT_TIMER, TIMER_Update(sys_timestamp)); // Mostly so the next event time gets recalculated properly in regards to our calls
1449 // to TIMER_SetVBlank() and TIMER_SetHRetrace().
1450 } // end if(!LineClockCounter)
1451 } // end while(gpu_clocks > 0)
1452
1453 //puts("GPU Update End");
1454
1455 TheEnd:
1456 lastts = sys_timestamp;
1457
1458 {
1459 int32 next_dt = LineClockCounter;
1460
1461 next_dt = (((int64)next_dt << 16) - GPUClockCounter + GPUClockRatio - 1) / GPUClockRatio;
1462
1463 next_dt = std::max<int32>(1, next_dt);
1464 next_dt = std::min<int32>(128, next_dt);
1465
1466 //printf("%d\n", next_dt);
1467
1468 return(sys_timestamp + next_dt);
1469 }
1470 }
1471
1472 void PS_GPU::StartFrame(EmulateSpecStruct *espec_arg)
1473 {
1474 sl_zero_reached = false;
1475
1476 espec = espec_arg;
1477
1478 surface = espec->surface;
1479 DisplayRect = &espec->DisplayRect;
1480 LineWidths = espec->LineWidths;
1481 }
1482
1483 int PS_GPU::StateAction(StateMem *sm, int load, int data_only)
1484 {
1485 uint32 TexCache_Tag[256];
1486 uint16 TexCache_Data[256][4];
1487
1488 for(unsigned i = 0; i < 256; i++)
1489 {
1490 TexCache_Tag[i] = TexCache[i].Tag;
1491
1492 for(unsigned j = 0; j < 4; j++)
1493 TexCache_Data[i][j] = TexCache[i].Data[j];
1494
1495 }
1496 SFORMAT StateRegs[] =
1497 {
1498 SFARRAY16(&GPURAM[0][0], sizeof(GPURAM) / sizeof(GPURAM[0][0])),
1499
1500 SFVAR(DMAControl),
1501
1502 SFVAR(ClipX0),
1503 SFVAR(ClipY0),
1504 SFVAR(ClipX1),
1505 SFVAR(ClipY1),
1506
1507 SFVAR(OffsX),
1508 SFVAR(OffsY),
1509
1510 SFVAR(dtd),
1511 SFVAR(dfe),
1512
1513 SFVAR(MaskSetOR),
1514 SFVAR(MaskEvalAND),
1515
1516 SFVAR(TexDisable),
1517 SFVAR(TexDisableAllowChange),
1518
1519 SFVAR(tww),
1520 SFVAR(twh),
1521 SFVAR(twx),
1522 SFVAR(twy),
1523
1524 SFVAR(TexPageX),
1525 SFVAR(TexPageY),
1526
1527 SFVAR(SpriteFlip),
1528
1529 SFVAR(abr),
1530 SFVAR(TexMode),
1531
1532 SFARRAY32(&BlitterFIFO.data[0], sizeof(BlitterFIFO.data) / sizeof(BlitterFIFO.data[0])),
1533 SFVAR(BlitterFIFO.read_pos),
1534 SFVAR(BlitterFIFO.write_pos),
1535 SFVAR(BlitterFIFO.in_count),
1536
1537 SFVAR(DataReadBuffer),
1538 SFVAR(DataReadBufferEx),
1539
1540 SFVAR(IRQPending),
1541
1542 SFVAR(InCmd),
1543 SFVAR(InCmd_CC),
1544
1545 #define TVHELPER(n) SFVAR(n.x), SFVAR(n.y), SFVAR(n.u), SFVAR(n.v), SFVAR(n.r), SFVAR(n.g), SFVAR(n.b)
1546 TVHELPER(InQuad_F3Vertices[0]),
1547 TVHELPER(InQuad_F3Vertices[1]),
1548 TVHELPER(InQuad_F3Vertices[2]),
1549 #undef TVHELPER
1550
1551 SFVAR(InPLine_PrevPoint.x),
1552 SFVAR(InPLine_PrevPoint.y),
1553 SFVAR(InPLine_PrevPoint.r),
1554 SFVAR(InPLine_PrevPoint.g),
1555 SFVAR(InPLine_PrevPoint.b),
1556
1557 SFVAR(FBRW_X),
1558 SFVAR(FBRW_Y),
1559 SFVAR(FBRW_W),
1560 SFVAR(FBRW_H),
1561 SFVAR(FBRW_CurY),
1562 SFVAR(FBRW_CurX),
1563
1564 SFVAR(DisplayMode),
1565 SFVAR(DisplayOff),
1566 SFVAR(DisplayFB_XStart),
1567 SFVAR(DisplayFB_YStart),
1568
1569 SFVAR(HorizStart),
1570 SFVAR(HorizEnd),
1571
1572 SFVAR(VertStart),
1573 SFVAR(VertEnd),
1574
1575 SFVAR(DisplayFB_CurYOffset),
1576 SFVAR(DisplayFB_CurLineYReadout),
1577
1578 SFVAR(InVBlank),
1579
1580 SFVAR(LinesPerField),
1581 SFVAR(scanline),
1582 SFVAR(field),
1583 SFVAR(field_ram_readout),
1584 SFVAR(PhaseChange),
1585
1586 SFVAR(DotClockCounter),
1587
1588 SFVAR(GPUClockCounter),
1589 SFVAR(LineClockCounter),
1590 SFVAR(LinePhase),
1591
1592 SFVAR(DrawTimeAvail),
1593
1594 SFEND
1595 };
1596 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GPU");
1597
1598 if(load)
1599 {
1600 for(unsigned i = 0; i < 256; i++)
1601 {
1602 TexCache[i].Tag = TexCache_Tag[i];
1603
1604 for(unsigned j = 0; j < 4; j++)
1605 TexCache[i].Data[j] = TexCache_Data[i][j];
1606 }
1607 RecalcTexWindowStuff();
1608 BlitterFIFO.SaveStatePostLoad();
1609
1610 HorizStart &= 0xFFF;
1611 HorizEnd &= 0xFFF;
1612
1613 IRQ_Assert(IRQ_GPU, IRQPending);
1614 }
1615
1616 return(ret);
1617 }
0 // WARNING WARNING WARNING: ONLY use CanRead() method of BlitterFIFO, and NOT CanWrite(), since the FIFO is larger than the actual PS1 GPU FIFO to accommodate
1 // our lack of fancy superscalarish command sequencer.
2
3 #ifndef __MDFN_PSX_GPU_H
4 #define __MDFN_PSX_GPU_H
5
6 #include "FastFIFO.h"
7
8 class PS_GPU;
9
10 #define INCMD_NONE 0
11 #define INCMD_PLINE 1
12 #define INCMD_QUAD 2
13 #define INCMD_FBWRITE 4
14 #define INCMD_FBREAD 8
15
16 struct CTEntry
17 {
18 void (*func[4][8])(PS_GPU* g, const uint32 *cb);
19 uint8 len;
20 uint8 fifo_fb_len;
21 bool ss_cmd;
22 };
23
24 struct tri_vertex
25 {
26 int32 x, y;
27 int32 u, v;
28 int32 r, g, b;
29 };
30
31 struct i_group;
32 struct i_deltas;
33
34 struct line_point
35 {
36 int32 x, y;
37 uint8 r, g, b;
38 };
39
40 class PS_GPU
41 {
42 public:
43
44 PS_GPU(bool pal_clock_and_tv, int sls, int sle) MDFN_COLD;
45 ~PS_GPU() MDFN_COLD;
46
47 void FillVideoParams(MDFNGI* gi) MDFN_COLD;
48
49 void Power(void) MDFN_COLD;
50
51 int StateAction(StateMem *sm, int load, int data_only);
52
53 void ResetTS(void);
54
55 void StartFrame(EmulateSpecStruct *espec);
56
57 int32_t Update(const int32_t timestamp);
58
59 void Write(const int32_t timestamp, uint32 A, uint32 V);
60
61 INLINE bool CalcFIFOReadyBit(void)
62 {
63 if(InCmd & (INCMD_PLINE | INCMD_QUAD))
64 return(false);
65
66 if(BlitterFIFO.CanRead() == 0)
67 return(true);
68
69 if(InCmd & (INCMD_FBREAD | INCMD_FBWRITE))
70 return(false);
71
72 if(BlitterFIFO.CanRead() >= Commands[BlitterFIFO.Peek() >> 24].fifo_fb_len)
73 return(false);
74
75 return(true);
76 }
77
78 INLINE bool DMACanWrite(void)
79 {
80 return CalcFIFOReadyBit();
81 }
82
83 void WriteDMA(uint32 V);
84 uint32 ReadDMA(void);
85
86 uint32 Read(const int32_t timestamp, uint32 A);
87
88 inline int32 GetScanlineNum(void)
89 {
90 return(scanline);
91 }
92
93 INLINE uint16 PeekRAM(uint32 A)
94 {
95 return(GPURAM[(A >> 10) & 0x1FF][A & 0x3FF]);
96 }
97
98 INLINE void PokeRAM(uint32 A, uint16 V)
99 {
100 GPURAM[(A >> 10) & 0x1FF][A & 0x3FF] = V;
101 }
102
103 // Y, X
104 uint16 GPURAM[512][1024];
105
106 uint32 DMAControl;
107
108 // Drawing stuff
109 int32 ClipX0;
110 int32 ClipY0;
111 int32 ClipX1;
112 int32 ClipY1;
113
114 int32 OffsX;
115 int32 OffsY;
116
117 bool dtd; // Dithering enable
118 bool dfe;
119
120 uint32 MaskSetOR;
121 uint32 MaskEvalAND;
122
123 bool TexDisable;
124 bool TexDisableAllowChange;
125
126 uint8 tww, twh, twx, twy;
127 struct
128 {
129 uint8 TexWindowXLUT_Pre[16];
130 uint8 TexWindowXLUT[256];
131 uint8 TexWindowXLUT_Post[16];
132 };
133
134 struct
135 {
136 uint8 TexWindowYLUT_Pre[16];
137 uint8 TexWindowYLUT[256];
138 uint8 TexWindowYLUT_Post[16];
139 };
140 void RecalcTexWindowStuff(void);
141
142 uint32_t TexPageX; // 0, 64, 128, 192, etc up to 960
143 uint32_t TexPageY; // 0 or 256
144
145 uint32 SpriteFlip;
146
147 uint32 abr; // Semi-transparency mode(0~3)
148 uint32 TexMode;
149
150 struct
151 {
152 uint8 RGB8SAT_Under[256];
153 uint8 RGB8SAT[256];
154 uint8 RGB8SAT_Over[256];
155 };
156
157 static CTEntry Commands[256];
158
159 FastFIFO<uint32, 0x20> BlitterFIFO; // 0x10 on an actual PS1 GPU, 0x20 here (see comment at top of gpu.h)
160
161 uint32 DataReadBuffer;
162 uint32 DataReadBufferEx;
163
164 bool IRQPending;
165
166 // Powers of 2 for faster multiple equality testing(just for multi-testing; InCmd itself will only contain 0, or a power of 2).
167 uint8 InCmd;
168 uint8 InCmd_CC;
169
170 tri_vertex InQuad_F3Vertices[3];
171 uint32 InQuad_clut;
172
173 line_point InPLine_PrevPoint;
174
175 uint32 FBRW_X;
176 uint32 FBRW_Y;
177 uint32 FBRW_W;
178 uint32 FBRW_H;
179 uint32 FBRW_CurY;
180 uint32 FBRW_CurX;
181
182 //
183 // Display Parameters
184 //
185 uint32 DisplayMode;
186
187 bool DisplayOff;
188 uint32 DisplayFB_XStart;
189 uint32 DisplayFB_YStart;
190
191 uint32 HorizStart;
192 uint32 HorizEnd;
193
194 uint32 VertStart;
195 uint32 VertEnd;
196
197 //
198 // Display work vars
199 //
200 uint32 DisplayFB_CurYOffset;
201 uint32 DisplayFB_CurLineYReadout;
202
203 bool InVBlank;
204
205 //
206 //
207 //
208 uint32 LinesPerField;
209 uint32 scanline;
210 bool field;
211 bool field_ram_readout;
212 bool PhaseChange;
213
214 uint32 DotClockCounter;
215
216 uint64 GPUClockCounter;
217 uint32 GPUClockRatio;
218 int32 LineClockCounter;
219 int32 LinePhase;
220
221 int32 DrawTimeAvail;
222
223 int32_t lastts;
224
225 bool sl_zero_reached;
226
227 EmulateSpecStruct *espec;
228 MDFN_Surface *surface;
229 MDFN_Rect *DisplayRect;
230 int32 *LineWidths;
231 bool HardwarePALType;
232 int LineVisFirst, LineVisLast;
233
234 uint16 CLUT_Cache[256];
235
236 uint32 CLUT_Cache_VB; // Don't try to be clever and reduce it to 16 bits... ~0U is value for invalidated state.
237
238 struct // Speedup-cache varibles, derived from other variables; shouldn't be saved in save states.
239 {
240 // TW*_* variables derived from tww, twh, twx, twy, TexPageX, TexPageY
241 uint32 TWX_AND;
242 uint32 TWX_ADD;
243
244 uint32 TWY_AND;
245 uint32 TWY_ADD;
246 } SUCV;
247
248 struct
249 {
250 uint16 Data[4];
251 uint32 Tag;
252 } TexCache[256];
253
254 void InvalidateTexCache(void);
255 void InvalidateCache(void);
256 void SetTPage(uint32_t data);
257
258 uint8_t DitherLUT[4][4][512]; // Y, X, 8-bit source value(256 extra for saturation)
259
260 private:
261
262 template<uint32 TexMode_TA>
263 void Update_CLUT_Cache(uint16 raw_clut);
264
265
266 void ProcessFIFO(void);
267 void WriteCB(uint32 data);
268 uint32 ReadData(void);
269 void SoftReset(void);
270
271 template<int BlendMode, bool MaskEval_TA, bool textured>
272 void PlotPixel(int32 x, int32 y, uint16 pix);
273
274 template<uint32 TexMode_TA>
275 uint16 GetTexel(uint32 clut_offset, int32 u, int32 v);
276
277 uint16 ModTexel(uint16 texel, int32 r, int32 g, int32 b, const int32 dither_x, const int32 dither_y);
278
279 template<bool goraud, bool textured, int BlendMode, bool TexMult, uint32 TexMode, bool MaskEval_TA>
280 void DrawSpan(int y, uint32 clut_offset, const int32 x_start, const int32 x_bound, i_group ig, const i_deltas &idl);
281
282 template<bool shaded, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
283 void DrawTriangle(tri_vertex *vertices, uint32 clut);
284
285 template<bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA, bool FlipX, bool FlipY>
286 void DrawSprite(int32 x_arg, int32 y_arg, int32 w, int32 h, uint8 u_arg, uint8 v_arg, uint32 color, uint32 clut_offset);
287
288 template<bool goraud, int BlendMode, bool MaskEval_TA>
289 void DrawLine(line_point *vertices);
290
291 public:
292 template<int numvertices, bool shaded, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
293 void Command_DrawPolygon(const uint32 *cb);
294
295 template<uint8 raw_size, bool textured, int BlendMode, bool TexMult, uint32 TexMode_TA, bool MaskEval_TA>
296 void Command_DrawSprite(const uint32 *cb);
297
298
299 template<bool polyline, bool goraud, int BlendMode, bool MaskEval_TA>
300 void Command_DrawLine(const uint32 *cb);
301
302 void Command_ClearCache(const uint32 *cb);
303 void Command_IRQ(const uint32 *cb);
304
305 void Command_FBFill(const uint32 *cb);
306 void Command_FBCopy(const uint32 *cb);
307 void Command_FBWrite(const uint32 *cb);
308 void Command_FBRead(const uint32 *cb);
309
310 void Command_DrawMode(const uint32 *cb);
311 void Command_TexWindow(const uint32 *cb);
312 void Command_Clip0(const uint32 *cb);
313 void Command_Clip1(const uint32 *cb);
314 void Command_DrawingOffset(const uint32 *cb);
315 void Command_MaskSetting(const uint32 *cb);
316
317 private:
318
319
320 void ReorderRGB_Var(uint32 out_Rshift, uint32 out_Gshift, uint32 out_Bshift, bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x);
321
322 template<uint32 out_Rshift, uint32 out_Gshift, uint32 out_Bshift>
323 void ReorderRGB(bool bpp24, const uint16 *src, uint32 *dest, const int32 dx_start, const int32 dx_end, int32 fb_x) NO_INLINE;
324 };
325
326 #endif
0 template<int BlendMode, bool MaskEval_TA, bool textured>
1 INLINE void PS_GPU::PlotPixel(int32_t x, int32_t y, uint16_t fore_pix)
2 {
3 y &= 511; // More Y precision bits than GPU RAM installed in (non-arcade, at least) Playstation hardware.
4
5 if(BlendMode >= 0 && (fore_pix & 0x8000))
6 {
7 uint16 bg_pix = GPURAM[y][x]; // Don't use bg_pix for mask evaluation, it's modified in blending code paths.
8 uint16 pix; // = fore_pix & 0x8000;
9
10 /*
11 static const int32_t tab[4][2] =
12 {
13 { 2, 2 },
14 { 4, 4 },
15 { 4, -4 },
16 { 4, 1 }
17 };
18 */
19 // Efficient 15bpp pixel math algorithms from blargg
20 switch(BlendMode)
21 {
22 case 0:
23 bg_pix |= 0x8000;
24 pix = ((fore_pix + bg_pix) - ((fore_pix ^ bg_pix) & 0x0421)) >> 1;
25 break;
26
27 case 1:
28 {
29 bg_pix &= ~0x8000;
30
31 uint32_t sum = fore_pix + bg_pix;
32 uint32_t carry = (sum - ((fore_pix ^ bg_pix) & 0x8421)) & 0x8420;
33
34 pix = (sum - carry) | (carry - (carry >> 5));
35 }
36 break;
37
38 case 2:
39 {
40 bg_pix |= 0x8000;
41 fore_pix &= ~0x8000;
42
43 uint32_t diff = bg_pix - fore_pix + 0x108420;
44 uint32_t borrow = (diff - ((bg_pix ^ fore_pix) & 0x108420)) & 0x108420;
45
46 pix = (diff - borrow) & (borrow - (borrow >> 5));
47 }
48 break;
49
50 case 3:
51 {
52 bg_pix &= ~0x8000;
53 fore_pix = ((fore_pix >> 2) & 0x1CE7) | 0x8000;
54
55 uint32_t sum = fore_pix + bg_pix;
56 uint32_t carry = (sum - ((fore_pix ^ bg_pix) & 0x8421)) & 0x8420;
57
58 pix = (sum - carry) | (carry - (carry >> 5));
59 }
60 break;
61 case -1:
62 default:
63 break;
64 }
65
66 if(!MaskEval_TA || !(GPURAM[y][x] & 0x8000))
67 GPURAM[y][x] = (textured ? pix : (pix & 0x7FFF)) | MaskSetOR;
68 }
69 else
70 {
71 if(!MaskEval_TA || !(GPURAM[y][x] & 0x8000))
72 GPURAM[y][x] = (textured ? fore_pix : (fore_pix & 0x7FFF)) | MaskSetOR;
73 }
74 }
75
76 INLINE uint16_t PS_GPU::ModTexel(uint16_t texel, int32_t r, int32_t g, int32_t b, const int32_t dither_x, const int32_t dither_y)
77 {
78 uint16_t ret = texel & 0x8000;
79
80 ret |= DitherLUT[dither_y][dither_x][(((texel & 0x1F) * r) >> (5 - 1))] << 0;
81 ret |= DitherLUT[dither_y][dither_x][(((texel & 0x3E0) * g) >> (10 - 1))] << 5;
82 ret |= DitherLUT[dither_y][dither_x][(((texel & 0x7C00) * b) >> (15 - 1))] << 10;
83
84 return(ret);
85 }
86
87 template<uint32_t TexMode_TA>
88 INLINE void PS_GPU::Update_CLUT_Cache(uint16 raw_clut)
89 {
90 if(TexMode_TA < 2)
91 {
92 const uint32_t new_ccvb = ((raw_clut & 0x7FFF) | (TexMode_TA << 16)); // Confirmed upper bit of raw_clut is ignored(at least on SCPH-5501's GPU).
93
94 if(CLUT_Cache_VB != new_ccvb)
95 {
96 uint16* const gpulp = GPURAM[(raw_clut >> 6) & 0x1FF];
97 const uint32_t cxo = (raw_clut & 0x3F) << 4;
98 const uint32_t count = (TexMode_TA ? 256 : 16);
99
100 DrawTimeAvail -= count;
101
102 for(unsigned i = 0; i < count; i++)
103 {
104 CLUT_Cache[i] = gpulp[(cxo + i) & 0x3FF];
105 }
106
107 CLUT_Cache_VB = new_ccvb;
108 }
109 }
110 }
111
112 #if 0
113 TexWindowX_AND = ~(tww << 3);
114 TexWindowX_ADD = ((twx & tww) << 3;
115
116 TexWindowY_AND = ~(twh << 3);
117 TexWindowY_OR = (twy & twh) << 3;
118
119 uint32_t u = (u_arg & TexWindowX_AND) TexWindowX_OR;
120 uint32_t v = (v_arg & TexWindowY_AND) | TexWindowY_OR;
121 uint32_t fbtex_x = TexPageX + (u >> (2 - TexMode_TA));
122 uint32_t fbtex_y = TexPageY + v;
123 uint16 fbw = GPURAM[fbtex_y][fbtex_x & 1023];
124
125 if(TexMode_TA != 2)
126 {
127 if(TexMode_TA == 0)
128 fbw = (fbw >> ((u & 3) * 4)) & 0xF;
129 else
130 fbw = (fbw >> ((u & 1) * 8)) & 0xFF;
131
132 fbw = CLUT_Cache[fbw];
133 }
134 #endif
135
136 INLINE void PS_GPU::RecalcTexWindowStuff(void)
137 {
138 unsigned x, y;
139 const unsigned TexWindowX_AND = ~(tww << 3);
140 const unsigned TexWindowX_OR = (twx & tww) << 3;
141 const unsigned TexWindowY_AND = ~(twh << 3);
142 const unsigned TexWindowY_OR = (twy & twh) << 3;
143
144 for(x = 0; x < 256; x++)
145 TexWindowXLUT[x] = (x & TexWindowX_AND) | TexWindowX_OR;
146 for(y = 0; y < 256; y++)
147 TexWindowYLUT[y] = (y & TexWindowY_AND) | TexWindowY_OR;
148 memset(TexWindowXLUT_Pre, TexWindowXLUT[0], sizeof(TexWindowXLUT_Pre));
149 memset(TexWindowXLUT_Post, TexWindowXLUT[255], sizeof(TexWindowXLUT_Post));
150 memset(TexWindowYLUT_Pre, TexWindowYLUT[0], sizeof(TexWindowYLUT_Pre));
151 memset(TexWindowYLUT_Post, TexWindowYLUT[255], sizeof(TexWindowYLUT_Post));
152
153 SUCV.TWX_AND = ~(tww << 3);
154 SUCV.TWX_ADD = ((twx & tww) << 3) + (TexPageX << (2 - std::min<uint32_t>(2, TexMode)));
155
156 SUCV.TWY_AND = ~(twh << 3);
157 SUCV.TWY_ADD = ((twy & twh) << 3) + TexPageY;
158 }
159
160 template<uint32_t TexMode_TA>
161 INLINE uint16_t PS_GPU::GetTexel(const uint32_t clut_offset, int32_t u_arg, int32_t v_arg)
162 {
163 #if 0
164 /* TODO */
165 uint32_t u_ext = ((u_arg & SUCV.TWX_AND) + SUCV.TWX_ADD);
166 uint32_t fbtex_x = ((u_ext >> (2 - TexMode_TA))) & 1023;
167 uint32_t fbtex_y = (v_arg & SUCV.TWY_AND) + SUCV.TWY_ADD;
168 uint32_t gro = fbtex_y * 1024U + fbtex_x;
169
170 decltype(&TexCache[0]) c;
171
172 switch(TexMode_TA)
173 {
174 case 0: c = &TexCache[((gro >> 2) & 0x3) | ((gro >> 8) & 0xFC)]; break; // 64x64
175 case 1: c = &TexCache[((gro >> 2) & 0x7) | ((gro >> 7) & 0xF8)]; break; // 64x32 (NOT 32x64!)
176 case 2: c = &TexCache[((gro >> 2) & 0x7) | ((gro >> 7) & 0xF8)]; break; // 32x32
177 }
178
179 if(MDFN_UNLIKELY(c->Tag != (gro &~ 0x3)))
180 {
181 // SCPH-1001 old revision GPU is like(for sprites at least): (20 + 4)
182 // SCPH-5501 new revision GPU is like(for sprites at least): (12 + 4)
183 //
184 // We'll be conservative and just go with 4 for now, until we can run some tests with triangles too.
185 //
186 DrawTimeAvail -= 4;
187 c->Data[0] = (&GPURAM[0][0])[gro &~ 0x3];
188 c->Data[1] = (&GPURAM[0][1])[gro &~ 0x3];
189 c->Data[2] = (&GPURAM[0][2])[gro &~ 0x3];
190 c->Data[3] = (&GPURAM[0][3])[gro &~ 0x3];
191 c->Tag = (gro &~ 0x3);
192 }
193
194 uint16 fbw = c->Data[gro & 0x3];
195 #else
196 uint32_t u_ext = TexWindowXLUT[u_arg];
197 uint32_t v = TexWindowYLUT[v_arg];
198 uint32_t fbtex_x = TexPageX + (u_ext >> (2 - TexMode_TA));
199 uint32_t fbtex_y = TexPageY + v;
200 uint16_t fbw = GPURAM[fbtex_y][fbtex_x & 1023];
201 #endif
202 if(TexMode_TA != 2)
203 {
204 if(TexMode_TA == 0)
205 fbw = (fbw >> ((u_ext & 3) * 4)) & 0xF;
206 else
207 fbw = (fbw >> ((u_ext & 1) * 8)) & 0xFF;
208
209 #if 0
210 fbw = CLUT_Cache[fbw];
211 #else
212 fbw = GPURAM[(clut_offset >> 10) & 511][(clut_offset + fbw) & 1023];
213 #endif
214 }
215
216 return(fbw);
217 }
218
219 static INLINE bool LineSkipTest(PS_GPU* g, unsigned y)
220 {
221 #if 0
222 DisplayFB_XStart >= OffsX && DisplayFB_YStart >= OffsY &&
223 ((y & 1) == (DisplayFB_CurLineYReadout & 1))
224 #endif
225
226 if((g->DisplayMode & 0x24) != 0x24)
227 return false;
228
229 if(!g->dfe && ((y & 1) == ((g->DisplayFB_YStart + g->field_ram_readout) & 1))/* && !DisplayOff*/) //&& (y >> 1) >= DisplayFB_YStart && (y >> 1) < (DisplayFB_YStart + (VertEnd - VertStart)))
230 return true;
231
232 return false;
233 }
234
235 // Command table generation macros follow:
236
237 //#define BM_HELPER(fg) { fg(0), fg(1), fg(2), fg(3) }
238
239 #define POLY_HELPER_SUB(bm, cv, tm, mam) \
240 G_Command_DrawPolygon<3 + ((cv & 0x8) >> 3), ((cv & 0x10) >> 4), ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? bm : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam >
241
242 #define POLY_HELPER_FG(bm, cv) \
243 { \
244 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 0), \
245 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 0), \
246 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \
247 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \
248 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 1), \
249 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 1), \
250 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \
251 POLY_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \
252 }
253
254 #define POLY_HELPER(cv) \
255 { \
256 { POLY_HELPER_FG(0, cv), POLY_HELPER_FG(1, cv), POLY_HELPER_FG(2, cv), POLY_HELPER_FG(3, cv) }, \
257 1 + (3 /*+ ((cv & 0x8) >> 3)*/) * ( 1 + ((cv & 0x4) >> 2) + ((cv & 0x10) >> 4) ) - ((cv & 0x10) >> 4), \
258 1, \
259 false \
260 }
261
262 #define SPR_HELPER_SUB(bm, cv, tm, mam) G_Command_DrawSprite<(cv >> 3) & 0x3, ((cv & 0x4) >> 2), ((cv & 0x2) >> 1) ? bm : -1, ((cv & 1) ^ 1) & ((cv & 0x4) >> 2), tm, mam>
263
264 #define SPR_HELPER_FG(bm, cv) \
265 { \
266 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 0), \
267 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 0), \
268 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \
269 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 0), \
270 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 0 : 0), 1), \
271 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 1 : 0), 1), \
272 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \
273 SPR_HELPER_SUB(bm, cv, ((cv & 0x4) ? 2 : 0), 1), \
274 }
275
276
277 #define SPR_HELPER(cv) \
278 { \
279 { SPR_HELPER_FG(0, cv), SPR_HELPER_FG(1, cv), SPR_HELPER_FG(2, cv), SPR_HELPER_FG(3, cv) }, \
280 2 + ((cv & 0x4) >> 2) + ((cv & 0x18) ? 0 : 1), \
281 2 | ((cv & 0x4) >> 2) | ((cv & 0x18) ? 0 : 1), /* |, not +, for this */ \
282 false \
283 }
284
285 #define LINE_HELPER_SUB(bm, cv, mam) G_Command_DrawLine<((cv & 0x08) >> 3), ((cv & 0x10) >> 4), ((cv & 0x2) >> 1) ? bm : -1, mam>
286
287 #define LINE_HELPER_FG(bm, cv) \
288 { \
289 LINE_HELPER_SUB(bm, cv, 0), \
290 LINE_HELPER_SUB(bm, cv, 0), \
291 LINE_HELPER_SUB(bm, cv, 0), \
292 LINE_HELPER_SUB(bm, cv, 0), \
293 LINE_HELPER_SUB(bm, cv, 1), \
294 LINE_HELPER_SUB(bm, cv, 1), \
295 LINE_HELPER_SUB(bm, cv, 1), \
296 LINE_HELPER_SUB(bm, cv, 1) \
297 }
298
299 #define LINE_HELPER(cv) \
300 { \
301 { LINE_HELPER_FG(0, cv), LINE_HELPER_FG(1, cv), LINE_HELPER_FG(2, cv), LINE_HELPER_FG(3, cv) }, \
302 3 + ((cv & 0x10) >> 4), \
303 1, \
304 false \
305 }
306
307 #define OTHER_HELPER_FG(bm, arg_ptr) { arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr, arg_ptr }
308 #define OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_ptr) { { OTHER_HELPER_FG(0, arg_ptr), OTHER_HELPER_FG(1, arg_ptr), OTHER_HELPER_FG(2, arg_ptr), OTHER_HELPER_FG(3, arg_ptr) }, arg_cs, arg_fbcs, arg_ss }
309 #define OTHER_HELPER_X2(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER(arg_cs, arg_fbcs, arg_ss, arg_ptr)
310 #define OTHER_HELPER_X4(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X2(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X2(arg_cs, arg_fbcs, arg_ss, arg_ptr)
311 #define OTHER_HELPER_X8(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X4(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X4(arg_cs, arg_fbcs, arg_ss, arg_ptr)
312 #define OTHER_HELPER_X16(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X8(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X8(arg_cs, arg_fbcs, arg_ss, arg_ptr)
313 #define OTHER_HELPER_X32(arg_cs, arg_fbcs, arg_ss, arg_ptr) OTHER_HELPER_X16(arg_cs, arg_fbcs, arg_ss, arg_ptr), OTHER_HELPER_X16(arg_cs, arg_fbcs, arg_ss, arg_ptr)
314
315 #define NULLCMD_FG(bm) { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }
316 #define NULLCMD() { { NULLCMD_FG(0), NULLCMD_FG(1), NULLCMD_FG(2), NULLCMD_FG(3) }, 1, 1, true }
0 #ifdef __cplusplus
1
2 #ifndef __STDC_CONSTANT_MACROS
3 #define __STDC_CONSTANT_MACROS
4 #endif
5
6 #ifdef _STDINT_H
7 #undef _STDINT_H
8 #endif
9
10 # include <stdint.h>
11 #endif
12
13 struct line_fxp_coord
14 {
15 uint64_t x, y;
16 uint32_t r, g, b;
17 };
18
19 struct line_fxp_step
20 {
21 int64_t dx_dk, dy_dk;
22 int32_t dr_dk, dg_dk, db_dk;
23 };
24
25 #define LINE_XY_FRACTBITS 32
26 #define LINE_RGB_FRACTBITS 12
27
28 template<bool goraud>
29 static INLINE void LinePointToFXPCoord(const line_point &point, const line_fxp_step &step, line_fxp_coord &coord)
30 {
31 coord.x = ((uint64_t)point.x << LINE_XY_FRACTBITS) | (UINT64_C(1) << (LINE_XY_FRACTBITS - 1));
32 coord.y = ((uint64_t)point.y << LINE_XY_FRACTBITS) | (UINT64_C(1) << (LINE_XY_FRACTBITS - 1));
33
34 coord.x -= 1024;
35
36 if(step.dy_dk < 0)
37 coord.y -= 1024;
38
39 if(goraud)
40 {
41 coord.r = (point.r << LINE_RGB_FRACTBITS) | (1 << (LINE_RGB_FRACTBITS - 1));
42 coord.g = (point.g << LINE_RGB_FRACTBITS) | (1 << (LINE_RGB_FRACTBITS - 1));
43 coord.b = (point.b << LINE_RGB_FRACTBITS) | (1 << (LINE_RGB_FRACTBITS - 1));
44 }
45 }
46
47 static INLINE int64_t LineDivide(int64_t delta, int32_t dk)
48 {
49 delta = (uint64_t)delta << LINE_XY_FRACTBITS;
50
51 if(delta < 0)
52 delta -= dk - 1;
53 if(delta > 0)
54 delta += dk - 1;
55
56 return(delta / dk);
57 }
58
59 template<bool goraud>
60 static INLINE void LinePointsToFXPStep(const line_point &point0, const line_point &point1, const int32_t dk, line_fxp_step &step)
61 {
62 if(!dk)
63 {
64 step.dx_dk = 0;
65 step.dy_dk = 0;
66
67 if(goraud)
68 {
69 step.dr_dk = 0;
70 step.dg_dk = 0;
71 step.db_dk = 0;
72 }
73 return;
74 }
75
76 step.dx_dk = LineDivide(point1.x - point0.x, dk);
77 step.dy_dk = LineDivide(point1.y - point0.y, dk);
78
79 if(goraud)
80 {
81 step.dr_dk = (int32_t)((uint32_t)(point1.r - point0.r) << LINE_RGB_FRACTBITS) / dk;
82 step.dg_dk = (int32_t)((uint32_t)(point1.g - point0.g) << LINE_RGB_FRACTBITS) / dk;
83 step.db_dk = (int32_t)((uint32_t)(point1.b - point0.b) << LINE_RGB_FRACTBITS) / dk;
84 }
85 }
86
87 template<bool goraud>
88 static INLINE void AddLineStep(line_fxp_coord &point, const line_fxp_step &step)
89 {
90 point.x += step.dx_dk;
91 point.y += step.dy_dk;
92
93 if(goraud)
94 {
95 point.r += step.dr_dk;
96 point.g += step.dg_dk;
97 point.b += step.db_dk;
98 }
99 }
100
101 template<bool goraud, int BlendMode, bool MaskEval_TA>
102 void PS_GPU::DrawLine(line_point *points)
103 {
104 int32_t i_dx;
105 int32_t i_dy;
106 int32_t k;
107 line_fxp_coord cur_point;
108 line_fxp_step step;
109
110 i_dx = abs(points[1].x - points[0].x);
111 i_dy = abs(points[1].y - points[0].y);
112 k = (i_dx > i_dy) ? i_dx : i_dy;
113
114 if(i_dx >= 1024)
115 return;
116
117 if(i_dy >= 512)
118 return;
119
120 if(points[0].x > points[1].x && k)
121 {
122 line_point tmp = points[1];
123
124 points[1] = points[0];
125 points[0] = tmp;
126 }
127
128 DrawTimeAvail -= k * 2;
129
130 LinePointsToFXPStep<goraud>(points[0], points[1], k, step);
131 LinePointToFXPCoord<goraud>(points[0], step, cur_point);
132
133 for(int32_t i = 0; i <= k; i++) // <= is not a typo.
134 {
135 // Sign extension is not necessary here for x and y, due to the maximum values that ClipX1 and ClipY1 can contain.
136 const int32_t x = (cur_point.x >> LINE_XY_FRACTBITS) & 2047;
137 const int32_t y = (cur_point.y >> LINE_XY_FRACTBITS) & 2047;
138
139 if(!LineSkipTest(this, y))
140 {
141 uint8_t r, g, b;
142 uint16_t pix = 0x8000;
143
144 if(goraud)
145 {
146 r = cur_point.r >> LINE_RGB_FRACTBITS;
147 g = cur_point.g >> LINE_RGB_FRACTBITS;
148 b = cur_point.b >> LINE_RGB_FRACTBITS;
149 }
150 else
151 {
152 r = points[0].r;
153 g = points[0].g;
154 b = points[0].b;
155 }
156
157 if(dtd)
158 {
159 pix |= DitherLUT[y & 3][x & 3][r] << 0;
160 pix |= DitherLUT[y & 3][x & 3][g] << 5;
161 pix |= DitherLUT[y & 3][x & 3][b] << 10;
162 }
163 else
164 {
165 pix |= (r >> 3) << 0;
166 pix |= (g >> 3) << 5;
167 pix |= (b >> 3) << 10;
168 }
169
170 // FIXME: There has to be a faster way than checking for being inside the drawing area for each pixel.
171 if(x >= ClipX0 && x <= ClipX1 && y >= ClipY0 && y <= ClipY1)
172 PlotPixel<BlendMode, MaskEval_TA, false>(x, y, pix);
173 }
174
175 AddLineStep<goraud>(cur_point, step);
176 }
177 }
178
179 template<bool polyline, bool goraud, int BlendMode, bool MaskEval_TA>
180 INLINE void PS_GPU::Command_DrawLine(const uint32_t *cb)
181 {
182 const uint8_t cc = cb[0] >> 24; // For pline handling later.
183 line_point points[2];
184
185 DrawTimeAvail -= 16; // FIXME, correct time.
186
187 if(polyline && InCmd == INCMD_PLINE)
188 {
189 //printf("PLINE N\n");
190 points[0] = InPLine_PrevPoint;
191 }
192 else
193 {
194 points[0].r = (*cb >> 0) & 0xFF;
195 points[0].g = (*cb >> 8) & 0xFF;
196 points[0].b = (*cb >> 16) & 0xFF;
197 cb++;
198
199 points[0].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX;
200 points[0].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY;
201 cb++;
202 }
203
204 if(goraud)
205 {
206 points[1].r = (*cb >> 0) & 0xFF;
207 points[1].g = (*cb >> 8) & 0xFF;
208 points[1].b = (*cb >> 16) & 0xFF;
209 cb++;
210 }
211 else
212 {
213 points[1].r = points[0].r;
214 points[1].g = points[0].g;
215 points[1].b = points[0].b;
216 }
217
218 points[1].x = sign_x_to_s32(11, ((*cb >> 0) & 0xFFFF)) + OffsX;
219 points[1].y = sign_x_to_s32(11, ((*cb >> 16) & 0xFFFF)) + OffsY;
220 cb++;
221
222 if(polyline)
223 {
224 InPLine_PrevPoint = points[1];
225
226 if(InCmd != INCMD_PLINE)
227 {
228 InCmd = INCMD_PLINE;
229 InCmd_CC = cc;
230 }
231 }
232
233 DrawLine<goraud, BlendMode, MaskEval_TA>(points);
234 }
0 #define COORD_FBS 12
1 #define COORD_MF_INT(n) ((n) << COORD_FBS)
2 #define COORD_POST_PADDING 12
3
4 struct i_group
5 {
6 uint32_t u, v;
7 uint32_t r, g, b;
8 };
9
10 struct i_deltas
11 {
12 uint32_t du_dx, dv_dx;
13 uint32_t dr_dx, dg_dx, db_dx;
14
15 uint32_t du_dy, dv_dy;
16 uint32_t dr_dy, dg_dy, db_dy;
17 };
18
19 /*
20 Store and do most math with interpolant coordinates and deltas as unsigned to avoid violating strict overflow(due to biasing),
21 but when actually grabbing the coordinates, treat them as signed(with signed right shift) so we can do saturation properly.
22 */
23 static INLINE int32_t COORD_GET_INT(int32_t n)
24 {
25 return(n >> COORD_FBS);
26 }
27
28 static INLINE int64_t MakePolyXFP(uint32_t x)
29 {
30 return ((uint64_t)x << 32) + ((UINT64_C(1) << 32) - (1 << 11));
31 }
32
33 static INLINE int64_t MakePolyXFPStep(int32_t dx, int32_t dy)
34 {
35 int64_t ret;
36 int64_t dx_ex = (int64_t)dx << 32;
37
38 if(dx_ex < 0)
39 dx_ex -= dy - 1;
40
41 if(dx_ex > 0)
42 dx_ex += dy - 1;
43
44 ret = dx_ex / dy;
45
46 return(ret);
47 }
48
49 static INLINE int32_t GetPolyXFP_Int(int64_t xfp)
50 {
51 return(xfp >> 32);
52 }
53
54 #define CALCIS(x,y) (((B.x - A.x) * (C.y - B.y)) - ((C.x - B.x) * (B.y - A.y)))
55
56 static INLINE bool CalcIDeltas(i_deltas &idl, const tri_vertex &A, const tri_vertex &B, const tri_vertex &C)
57 {
58 const unsigned sa = 32;
59 int64_t num = ((int64_t)COORD_MF_INT(1)) << sa;
60 int64_t denom = CALCIS(x, y);
61 int64_t one_div;
62
63 if(!denom)
64 return(false);
65
66 one_div = num / denom;
67
68 idl.dr_dx = ((one_div * CALCIS(r, y)) + 0x00000000) >> sa;
69 idl.dr_dy = ((one_div * CALCIS(x, r)) + 0x00000000) >> sa;
70
71 idl.dg_dx = ((one_div * CALCIS(g, y)) + 0x00000000) >> sa;
72 idl.dg_dy = ((one_div * CALCIS(x, g)) + 0x00000000) >> sa;
73
74 idl.db_dx = ((one_div * CALCIS(b, y)) + 0x00000000) >> sa;
75 idl.db_dy = ((one_div * CALCIS(x, b)) + 0x00000000) >> sa;
76
77 idl.du_dx = ((one_div * CALCIS(u, y)) + 0x00000000) >> sa;
78 idl.du_dy = ((one_div * CALCIS(x, u)) + 0x00000000) >> sa;
79
80 idl.dv_dx = ((one_div * CALCIS(v, y)) + 0x00000000) >> sa;
81 idl.dv_dy = ((one_div * CALCIS(x, v)) + 0x00000000) >> sa;
82
83 // idl.du_dx = ((int64_t)CALCIS(u, y) << COORD_FBS) / denom;
84 // idl.du_dy = ((int64_t)CALCIS(x, u) << COORD_FBS) / denom;
85
86 // idl.dv_dx = ((int64_t)CALCIS(v, y) << COORD_FBS) / denom;
87 // idl.dv_dy = ((int64_t)CALCIS(x, v) << COORD_FBS) / denom;
88
89 //printf("Denom=%lld - CIS_UY=%d, CIS_XU=%d, CIS_VY=%d, CIS_XV=%d\n", denom, CALCIS(u, y), CALCIS(x, u), CALCIS(v, y), CALCIS(x, v));
90 //printf(" du_dx=0x%08x, du_dy=0x%08x --- dv_dx=0x%08x, dv_dy=0x%08x\n", idl.du_dx, idl.du_dy, idl.dv_dx, idl.dv_dy);
91
92 return(true);
93 }
94 #undef CALCIS
95
96 template<bool goraud, bool textured>
97 static INLINE void AddIDeltas_DX(i_group &ig, const i_deltas &idl, uint32_t count = 1)
98 {
99 if(textured)
100 {
101 ig.u += idl.du_dx * count;
102 ig.v += idl.dv_dx * count;
103 }
104
105 if(goraud)
106 {
107 ig.r += idl.dr_dx * count;
108 ig.g += idl.dg_dx * count;
109 ig.b += idl.db_dx * count;
110 }
111 }
112
113 template<bool goraud, bool textured>
114 static INLINE void AddIDeltas_DY(i_group &ig, const i_deltas &idl, uint32_t count = 1)
115 {
116 if(textured)
117 {
118 ig.u += idl.du_dy * count;
119 ig.v += idl.dv_dy * count;
120 }
121
122 if(goraud)
123 {
124 ig.r += idl.dr_dy * count;
125 ig.g += idl.dg_dy * count;
126 ig.b += idl.db_dy * count;
127 }
128 }
129
130 template<bool goraud, bool textured, int BlendMode, bool TexMult, uint32_t TexMode_TA, bool MaskEval_TA>
131 INLINE void PS_GPU::DrawSpan(int y, uint32_t clut_offset, const int32_t x_start, const int32_t x_bound, i_group ig, const i_deltas &idl)
132 {
133 int32_t xs = x_start, xb = x_bound;
134
135 if(LineSkipTest(this, y))
136 return;
137
138 if(xs < xb) // (xs != xb)
139 {
140 if(xs < ClipX0)
141 xs = ClipX0;
142
143 if(xb > (ClipX1 + 1))
144 xb = ClipX1 + 1;
145
146 if(xs < xb)
147 {
148 DrawTimeAvail -= (xb - xs);
149
150 if(goraud || textured)
151 {
152 DrawTimeAvail -= (xb - xs);
153 }
154 else if((BlendMode >= 0) || MaskEval_TA)
155 {
156 DrawTimeAvail -= (((xb + 1) & ~1) - (xs & ~1)) >> 1;
157 }
158 }
159
160 if(textured)
161 {
162 ig.u += (xs * idl.du_dx) + (y * idl.du_dy);
163 ig.v += (xs * idl.dv_dx) + (y * idl.dv_dy);
164 }
165
166 if(goraud)
167 {
168 ig.r += (xs * idl.dr_dx) + (y * idl.dr_dy);
169 ig.g += (xs * idl.dg_dx) + (y * idl.dg_dy);
170 ig.b += (xs * idl.db_dx) + (y * idl.db_dy);
171 }
172
173 for(int32_t x = xs; MDFN_LIKELY(x < xb); x++)
174 {
175 uint32_t r, g, b;
176
177 if(goraud)
178 {
179 r = RGB8SAT[COORD_GET_INT(ig.r)];
180 g = RGB8SAT[COORD_GET_INT(ig.g)];
181 b = RGB8SAT[COORD_GET_INT(ig.b)];
182 }
183 else
184 {
185 r = COORD_GET_INT(ig.r);
186 g = COORD_GET_INT(ig.g);
187 b = COORD_GET_INT(ig.b);
188 }
189
190 if(textured)
191 {
192 uint16_t fbw = GetTexel<TexMode_TA>(clut_offset, COORD_GET_INT(ig.u), COORD_GET_INT(ig.v));
193
194 if(fbw)
195 {
196 if(TexMult)
197 fbw = ModTexel(fbw, r, g, b, (dtd) ? (x & 3) : 3, (dtd) ? (y & 3) : 2);
198 PlotPixel<BlendMode, MaskEval_TA, true>(x, y, fbw);
199 }
200 }
201 else
202 {
203 uint16_t pix = 0x8000;
204
205 if(goraud && dtd)
206 {
207 pix |= DitherLUT[y & 3][x & 3][r] << 0;
208 pix |= DitherLUT[y & 3][x & 3][g] << 5;
209 pix |= DitherLUT[y & 3][x & 3][b] << 10;
210 }
211 else
212 {
213 pix |= (r >> 3) << 0;
214 pix |= (g >> 3) << 5;
215 pix |= (b >> 3) << 10;
216 }
217
218 PlotPixel<BlendMode, MaskEval_TA, false>(x, y, pix);
219 }
220
221 AddIDeltas_DX<goraud, textured>(ig, idl);
222 //AddStep<goraud, textured>(perp_coord, perp_step);
223 }
224 }
225 }
226
227 template<bool goraud, bool textured, int BlendMode, bool TexMult, uint32_t TexMode_TA, bool MaskEval_TA>
228 void PS_GPU::DrawTriangle(tri_vertex *vertices, uint32_t clut)
229 {
230 i_deltas idl;
231
232 //
233 // Sort vertices by y.
234 //
235 if(vertices[2].y < vertices[1].y)
236 {
237 tri_vertex tmp = vertices[1];
238 vertices[1] = vertices[2];
239 vertices[2] = tmp;
240 }
241
242 if(vertices[1].y < vertices[0].y)
243 {
244 tri_vertex tmp = vertices[0];
245 vertices[0] = vertices[1];
246 vertices[1] = tmp;
247 }
248
249 if(vertices[2].y < vertices[1].y)
250 {
251 tri_vertex tmp = vertices[1];
252 vertices[1] = vertices[2];
253 vertices[2] = tmp;
254 }
255
256 if(vertices[0].y == vertices[2].y)
257 return;
258
259 if((vertices[2].y - vertices[0].y) >= 512)
260 {
261 //PSX_WARNING("[GPU] Triangle height too large: %d", (vertices[2].y - vertices[0].y));
262 return;
263 }
264
265 if(abs(vertices[2].x - vertices[0].x) >= 1024 ||
266 abs(vertices[2].x - vertices[1].x) >= 1024 ||
267 abs(vertices[1].x - vertices[0].x) >= 1024)
268 {
269 //PSX_WARNING("[GPU] Triangle width too large: %d %d %d", abs(vertices[2].x - vertices[0].x), abs(vertices[2].x - vertices[1].x), abs(vertices[1].x - vertices[0].x));
270 return;
271 }
272
273 if(!CalcIDeltas(idl, vertices[0], vertices[1], vertices[2]))
274 return;
275
276 // [0] should be top vertex, [2] should be bottom vertex, [1] should be off to the side vertex.
277 //
278 //
279 int32_t y_start = vertices[0].y;
280 int32_t y_middle = vertices[1].y;
281 int32_t y_bound = vertices[2].y;
282
283 int64_t base_coord;
284 int64_t base_step;
285
286 int64_t bound_coord_ul;
287 int64_t bound_coord_us;
288
289 int64_t bound_coord_ll;
290 int64_t bound_coord_ls;
291
292 bool right_facing;
293 //bool bottom_up;
294 i_group ig;
295
296 //
297 // Find vertex with lowest X coordinate, and use as the base for calculating interpolants from.
298 //
299 {
300 unsigned iggvi = 0;
301
302 //
303 // <=, not <
304 //
305 if(vertices[1].x <= vertices[iggvi].x)
306 iggvi = 1;
307
308 if(vertices[2].x <= vertices[iggvi].x)
309 iggvi = 2;
310
311 ig.u = COORD_MF_INT(vertices[iggvi].u) + (1 << (COORD_FBS - 1));
312 ig.v = COORD_MF_INT(vertices[iggvi].v) + (1 << (COORD_FBS - 1));
313 ig.r = COORD_MF_INT(vertices[iggvi].r);
314 ig.g = COORD_MF_INT(vertices[iggvi].g);
315 ig.b = COORD_MF_INT(vertices[iggvi].b);
316
317 AddIDeltas_DX<goraud, textured>(ig, idl, -vertices[iggvi].x);
318 AddIDeltas_DY<goraud, textured>(ig, idl, -vertices[iggvi].y);
319 }
320
321 base_coord = MakePolyXFP(vertices[0].x);
322 base_step = MakePolyXFPStep((vertices[2].x - vertices[0].x), (vertices[2].y - vertices[0].y));
323
324 bound_coord_ul = MakePolyXFP(vertices[0].x);
325 bound_coord_ll = MakePolyXFP(vertices[1].x);
326
327 //
328 //
329 //
330
331
332 if(vertices[1].y == vertices[0].y)
333 {
334 bound_coord_us = 0;
335 right_facing = (bool)(vertices[1].x > vertices[0].x);
336 }
337 else
338 {
339 bound_coord_us = MakePolyXFPStep((vertices[1].x - vertices[0].x), (vertices[1].y - vertices[0].y));
340 right_facing = (bool)(bound_coord_us > base_step);
341 }
342
343 if(vertices[2].y == vertices[1].y)
344 bound_coord_ls = 0;
345 else
346 bound_coord_ls = MakePolyXFPStep((vertices[2].x - vertices[1].x), (vertices[2].y - vertices[1].y));
347
348 if(y_start < ClipY0)
349 {
350 int32_t count = ClipY0 - y_start;
351
352 y_start = ClipY0;
353 base_coord += base_step * count;
354 bound_coord_ul += bound_coord_us * count;
355
356 if(y_middle < ClipY0)
357 {
358 int32_t count_ls = ClipY0 - y_middle;
359
360 y_middle = ClipY0;
361 bound_coord_ll += bound_coord_ls * count_ls;
362 }
363 }
364
365 if(y_bound > (ClipY1 + 1))
366 {
367 y_bound = ClipY1 + 1;
368
369 if(y_middle > y_bound)
370 y_middle = y_bound;
371 }
372
373 if(right_facing)
374 {
375 for(int32_t y = y_start; y < y_middle; y++)
376 {
377 DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(base_coord), GetPolyXFP_Int(bound_coord_ul), ig, idl);
378 base_coord += base_step;
379 bound_coord_ul += bound_coord_us;
380 }
381
382 for(int32_t y = y_middle; y < y_bound; y++)
383 {
384 DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(base_coord), GetPolyXFP_Int(bound_coord_ll), ig, idl);
385 base_coord += base_step;
386 bound_coord_ll += bound_coord_ls;
387 }
388 }
389 else
390 {
391 for(int32_t y = y_start; y < y_middle; y++)
392 {
393 DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(bound_coord_ul), GetPolyXFP_Int(base_coord), ig, idl);
394 base_coord += base_step;
395 bound_coord_ul += bound_coord_us;
396 }
397
398 for(int32_t y = y_middle; y < y_bound; y++)
399 {
400 DrawSpan<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(y, clut, GetPolyXFP_Int(bound_coord_ll), GetPolyXFP_Int(base_coord), ig, idl);
401 base_coord += base_step;
402 bound_coord_ll += bound_coord_ls;
403 }
404 }
405
406 #if 0
407 printf("[GPU] Vertices: %d:%d(r=%d, g=%d, b=%d) -> %d:%d(r=%d, g=%d, b=%d) -> %d:%d(r=%d, g=%d, b=%d)\n\n\n", vertices[0].x, vertices[0].y,
408 vertices[0].r, vertices[0].g, vertices[0].b,
409 vertices[1].x, vertices[1].y,
410 vertices[1].r, vertices[1].g, vertices[1].b,
411 vertices[2].x, vertices[2].y,
412 vertices[2].r, vertices[2].g, vertices[2].b);
413 #endif
414 }
415
416 template<int numvertices, bool goraud, bool textured, int BlendMode, bool TexMult, uint32_t TexMode_TA, bool MaskEval_TA>
417 INLINE void PS_GPU::Command_DrawPolygon(const uint32_t *cb)
418 {
419 const unsigned cb0 = cb[0];
420 tri_vertex vertices[3];
421 uint32_t clut = 0;
422 unsigned sv = 0;
423 //uint32_t tpage = 0;
424
425 // Base timing is approximate, and could be improved.
426 if(numvertices == 4 && InCmd == INCMD_QUAD)
427 DrawTimeAvail -= (28 + 18);
428 else
429 DrawTimeAvail -= (64 + 18);
430
431 if(goraud && textured)
432 DrawTimeAvail -= 150 * 3;
433 else if(goraud)
434 DrawTimeAvail -= 96 * 3;
435 else if(textured)
436 DrawTimeAvail -= 60 * 3;
437
438 if(numvertices == 4)
439 {
440 if(InCmd == INCMD_QUAD)
441 {
442 memcpy(&vertices[0], &InQuad_F3Vertices[1], 2 * sizeof(tri_vertex));
443 clut = InQuad_clut;
444 sv = 2;
445 }
446 }
447 //else
448 // memset(vertices, 0, sizeof(vertices));
449
450 for(unsigned v = sv; v < 3; v++)
451 {
452 if(v == 0 || goraud)
453 {
454 uint32_t raw_color = (*cb & 0xFFFFFF);
455
456 vertices[v].r = raw_color & 0xFF;
457 vertices[v].g = (raw_color >> 8) & 0xFF;
458 vertices[v].b = (raw_color >> 16) & 0xFF;
459
460 cb++;
461 }
462 else
463 {
464 vertices[v].r = vertices[0].r;
465 vertices[v].g = vertices[0].g;
466 vertices[v].b = vertices[0].b;
467 }
468
469 vertices[v].x = sign_x_to_s32(11, ((int16_t)(*cb & 0xFFFF))) + OffsX;
470 vertices[v].y = sign_x_to_s32(11, ((int16_t)(*cb >> 16))) + OffsY;
471 cb++;
472
473 if(textured)
474 {
475 vertices[v].u = (*cb & 0xFF);
476 vertices[v].v = (*cb >> 8) & 0xFF;
477
478 if(v == 0)
479 {
480 clut = ((*cb >> 16) & 0xFFFF) << 4;
481 }
482
483 cb++;
484 }
485 }
486
487 if(numvertices == 4)
488 {
489 if(InCmd == INCMD_QUAD)
490 {
491 InCmd = INCMD_NONE;
492 }
493 else
494 {
495 InCmd = INCMD_QUAD;
496 InCmd_CC = cb0 >> 24;
497 memcpy(&InQuad_F3Vertices[0], &vertices[0], sizeof(tri_vertex) * 3);
498 InQuad_clut = clut;
499 }
500 }
501
502 DrawTriangle<goraud, textured, BlendMode, TexMult, TexMode_TA, MaskEval_TA>(vertices, clut);
503 }
504
505 #undef COORD_POST_PADDING
506 #undef COORD_FBS
507 #undef COORD_MF_INT
0
1 template<bool textured, int BlendMode, bool TexMult, uint32_t TexMode_TA, bool MaskEval_TA, bool FlipX, bool FlipY>
2 void PS_GPU::DrawSprite(int32_t x_arg, int32_t y_arg, int32_t w, int32_t h, uint8_t u_arg, uint8_t v_arg, uint32_t color, uint32_t clut_offset)
3 {
4 const int32_t r = color & 0xFF;
5 const int32_t g = (color >> 8) & 0xFF;
6 const int32_t b = (color >> 16) & 0xFF;
7 const uint16_t fill_color = 0x8000 | ((r >> 3) << 0) | ((g >> 3) << 5) | ((b >> 3) << 10);
8
9 int32_t x_start, x_bound;
10 int32_t y_start, y_bound;
11 uint8_t u, v;
12 int v_inc = 1, u_inc = 1;
13
14 //printf("[GPU] Sprite: x=%d, y=%d, w=%d, h=%d\n", x_arg, y_arg, w, h);
15
16 x_start = x_arg;
17 x_bound = x_arg + w;
18
19 y_start = y_arg;
20 y_bound = y_arg + h;
21
22 if(textured)
23 {
24 u = u_arg;
25 v = v_arg;
26
27 //if(FlipX || FlipY || (u & 1) || (v & 1) || ((TexMode_TA == 0) && ((u & 3) || (v & 3))))
28 // fprintf(stderr, "Flippy: %d %d 0x%02x 0x%02x\n", FlipX, FlipY, u, v);
29
30 if(FlipX)
31 {
32 u_inc = -1;
33 u |= 1;
34 }
35 // FIXME: Something weird happens when lower bit of u is set and we're not doing horizontal flip, but I'm not sure what it is exactly(needs testing)
36 // It may only happen to the first pixel, so look for that case too during testing.
37 //else
38 // u = (u + 1) & ~1;
39
40 if(FlipY)
41 {
42 v_inc = -1;
43 }
44 }
45
46 if(x_start < ClipX0)
47 {
48 if(textured)
49 u += (ClipX0 - x_start) * u_inc;
50
51 x_start = ClipX0;
52 }
53
54 if(y_start < ClipY0)
55 {
56 if(textured)
57 v += (ClipY0 - y_start) * v_inc;
58
59 y_start = ClipY0;
60 }
61
62 if(x_bound > (ClipX1 + 1))
63 x_bound = ClipX1 + 1;
64
65 if(y_bound > (ClipY1 + 1))
66 y_bound = ClipY1 + 1;
67
68
69
70 //HeightMode && !dfe && ((y & 1) == ((DisplayFB_YStart + !field_atvs) & 1)) && !DisplayOff
71 //printf("%d:%d, %d, %d ---- heightmode=%d displayfb_ystart=%d field_atvs=%d displayoff=%d\n", w, h, scanline, dfe, HeightMode, DisplayFB_YStart, field_atvs, DisplayOff);
72
73 for(int32_t y = y_start; MDFN_LIKELY(y < y_bound); y++)
74 {
75 uint8_t u_r;
76
77 if(textured)
78 u_r = u;
79
80 if(!LineSkipTest(this, y))
81 {
82 if(y_bound > y_start && x_bound > x_start)
83 {
84 // Note(TODO): From tests on a PS1, even a 0-width sprite takes up time to "draw" proportional to its height.
85 int32_t suck_time = /* 8 + */ (x_bound - x_start);
86
87 if((BlendMode >= 0) || MaskEval_TA)
88 suck_time += (((x_bound + 1) & ~1) - (x_start & ~1)) >> 1;
89
90 DrawTimeAvail -= suck_time;
91 }
92
93 for(int32_t x = x_start; MDFN_LIKELY(x < x_bound); x++)
94 {
95 if(textured)
96 {
97 uint16_t fbw = GetTexel<TexMode_TA>(clut_offset, u_r, v);
98
99 if(fbw)
100 {
101 if(TexMult)
102 {
103 fbw = ModTexel(fbw, r, g, b, 3, 2);
104 }
105 PlotPixel<BlendMode, MaskEval_TA, true>(x, y, fbw);
106 }
107 }
108 else
109 PlotPixel<BlendMode, MaskEval_TA, false>(x, y, fill_color);
110
111 if(textured)
112 u_r += u_inc;
113 }
114 }
115 if(textured)
116 v += v_inc;
117 }
118 }
119
120 template<uint8_t raw_size, bool textured, int BlendMode, bool TexMult, uint32_t TexMode_TA, bool MaskEval_TA>
121 INLINE void PS_GPU::Command_DrawSprite(const uint32_t *cb)
122 {
123 int32_t x, y;
124 int32_t w, h;
125 uint8_t u = 0, v = 0;
126 uint32_t color = 0;
127 uint32_t clut = 0;
128
129 DrawTimeAvail -= 16; // FIXME, correct time.
130
131 color = *cb & 0x00FFFFFF;
132 cb++;
133
134 x = sign_x_to_s32(11, (*cb & 0xFFFF));
135 y = sign_x_to_s32(11, (*cb >> 16));
136 cb++;
137
138 if(textured)
139 {
140 u = *cb & 0xFF;
141 v = (*cb >> 8) & 0xFF;
142 clut = ((*cb >> 16) & 0xFFFF) << 4;
143 Update_CLUT_Cache<TexMode_TA>((*cb >> 16) & 0xFFFF);
144 cb++;
145 }
146
147 switch(raw_size)
148 {
149 default:
150 case 0:
151 w = (*cb & 0x3FF);
152 h = (*cb >> 16) & 0x1FF;
153 cb++;
154 break;
155
156 case 1:
157 w = 1;
158 h = 1;
159 break;
160
161 case 2:
162 w = 8;
163 h = 8;
164 break;
165
166 case 3:
167 w = 16;
168 h = 16;
169 break;
170 }
171
172 //printf("SPRITE: %d %d %d -- %d %d\n", raw_size, x, y, w, h);
173
174 x = sign_x_to_s32(11, x + OffsX);
175 y = sign_x_to_s32(11, y + OffsY);
176
177 switch(SpriteFlip & 0x3000)
178 {
179 case 0x0000:
180 if(!TexMult || color == 0x808080)
181 DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, false, false>(x, y, w, h, u, v, color, clut);
182 else
183 DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, false, false>(x, y, w, h, u, v, color, clut);
184 break;
185
186 case 0x1000:
187 if(!TexMult || color == 0x808080)
188 DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, true, false>(x, y, w, h, u, v, color, clut);
189 else
190 DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, true, false>(x, y, w, h, u, v, color, clut);
191 break;
192
193 case 0x2000:
194 if(!TexMult || color == 0x808080)
195 DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, false, true>(x, y, w, h, u, v, color, clut);
196 else
197 DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, false, true>(x, y, w, h, u, v, color, clut);
198 break;
199
200 case 0x3000:
201 if(!TexMult || color == 0x808080)
202 DrawSprite<textured, BlendMode, false, TexMode_TA, MaskEval_TA, true, true>(x, y, w, h, u, v, color, clut);
203 else
204 DrawSprite<textured, BlendMode, true, TexMode_TA, MaskEval_TA, true, true>(x, y, w, h, u, v, color, clut);
205 break;
206 }
207 }
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "gte.h"
19
20 #include "../clamp.h"
21
22 /* Notes:
23
24 AVSZ3/AVSZ4:
25 OTZ is MAC0 >> 12
26 OTZ overflow/underflow flag is set in an overflow condition even if MAC0 == 0.
27 sf field bit has no effect?
28
29 FLAG register:
30 Bits present mask: 0xfffff000
31
32 Checksum bit can't be directly set, it's apparently calculated like (bool)(FLAGS & 0x7f87e000)
33
34 Instructions effectively clear it 0 at start. (todo: test "invalid" instructions)
35
36 X/Y FIFO [3] register write pushes a copy down to [2]
37
38 */
39
40 typedef struct
41 {
42 int16_t MX[3][3];
43 int16_t dummy;
44 }
45 #ifndef _MSC_VER
46 __attribute__((__packed__))
47 #endif
48 gtematrix;
49
50 typedef struct
51 {
52 union
53 {
54 struct
55 {
56 uint8_t R;
57 uint8_t G;
58 uint8_t B;
59 uint8_t CD;
60 };
61 uint8_t Raw8[4];
62 };
63 } gtergb;
64
65 typedef struct
66 {
67 int16_t X;
68 int16_t Y;
69 } gtexy;
70
71 static uint32_t CR[32];
72 static uint32_t FLAGS; // Temporary for instruction execution, copied into CR[31] at end of instruction execution.
73
74 typedef union
75 {
76 gtematrix All[4];
77 int32_t Raw[4][5]; // Don't read from this(Raw[][]), only write(and when writing, if running on a big-endian platform, swap the upper 16-bits with the lower 16-bits)
78 int16_t Raw16[4][10];
79
80 struct
81 {
82 gtematrix Rot;
83 gtematrix Light;
84 gtematrix Color;
85 gtematrix AbbyNormal;
86 };
87 } Matrices_t;
88
89 static Matrices_t Matrices;
90
91 static union
92 {
93 int32_t All[4][4]; // Really only [4][3], but [4] to ease address calculation.
94
95 struct
96 {
97 int32_t T[4];
98 int32_t B[4];
99 int32_t FC[4];
100 int32_t Null[4];
101 };
102 } CRVectors;
103
104 static int32_t OFX;
105 static int32_t OFY;
106 static uint16_t H;
107 static int16_t DQA;
108 static int32_t DQB;
109
110 static int16_t ZSF3;
111 static int16_t ZSF4;
112
113
114 // Begin DR
115 static int16_t Vectors[3][4];
116 static gtergb RGB;
117 static uint16_t OTZ;
118
119 static int16_t IR[4];
120
121 #define IR0 IR[0]
122 #define IR1 IR[1]
123 #define IR2 IR[2]
124 #define IR3 IR[3]
125
126 static gtexy XY_FIFO[4];
127 static uint16_t Z_FIFO[4];
128 static gtergb RGB_FIFO[3];
129 static int32_t MAC[4];
130 static uint32_t LZCS;
131 static uint32_t LZCR;
132
133 static uint32_t Reg23;
134 // end DR
135
136 extern unsigned char widescreen_hack;
137
138 static INLINE uint8_t Sat5(int16_t cc)
139 {
140 if(cc < 0)
141 cc = 0;
142 if(cc > 0x1F)
143 cc = 0x1F;
144 return(cc);
145 }
146
147 //
148 // Newton-Raphson division table. (Initialized at startup; do NOT save in save states!)
149 //
150 static uint8_t DivTable[0x100 + 1];
151 static INLINE int32_t CalcRecip(uint16 divisor)
152 {
153 int32_t x = (0x101 + DivTable[(((divisor & 0x7FFF) + 0x40) >> 7)]);
154 int32_t tmp = (((int32_t)divisor * -x) + 0x80) >> 8;
155 int32_t tmp2 = ((x * (131072 + tmp)) + 0x80) >> 8;
156
157 return(tmp2);
158 }
159
160 void GTE_Init(void)
161 {
162 uint32_t divisor;
163
164 for(divisor = 0x8000; divisor < 0x10000; divisor += 0x80)
165 {
166 unsigned i;
167 uint32_t xa = 512;
168
169 for(i = 1; i < 5; i++)
170 xa = (xa * (1024 * 512 - ((divisor >> 7) * xa))) >> 18;
171
172 DivTable[(divisor >> 7) & 0xFF] = ((xa + 1) >> 1) - 0x101;
173 //printf("%04x, %02x\n", divisor, ((xa + 1) >> 1) - 0x101);
174 }
175
176 // To avoid a bounds limiting if statement in the emulation code:
177 DivTable[0x100] = DivTable[0xFF];
178 }
179
180
181 void GTE_Power(void)
182 {
183 memset(CR, 0, sizeof(CR));
184 //memset(DR, 0, sizeof(DR));
185
186 memset(Matrices.All, 0, sizeof(Matrices.All));
187 memset(CRVectors.All, 0, sizeof(CRVectors.All));
188 OFX = 0;
189 OFY = 0;
190 H = 0;
191 DQA = 0;
192 DQB = 0;
193 ZSF3 = 0;
194 ZSF4 = 0;
195
196
197 memset(Vectors, 0, sizeof(Vectors));
198 memset(&RGB, 0, sizeof(RGB));
199 OTZ = 0;
200 IR0 = 0;
201 IR1 = 0;
202 IR2 = 0;
203 IR3 = 0;
204
205 memset(XY_FIFO, 0, sizeof(XY_FIFO));
206 memset(Z_FIFO, 0, sizeof(Z_FIFO));
207 memset(RGB_FIFO, 0, sizeof(RGB_FIFO));
208 memset(MAC, 0, sizeof(MAC));
209 LZCS = 0;
210 LZCR = 0;
211
212 Reg23 = 0;
213 }
214
215 // TODO: Don't save redundant state, regarding CR cache variables
216 int GTE_StateAction(StateMem *sm, int load, int data_only)
217 {
218 SFORMAT StateRegs[] =
219 {
220 { CR, (uint32_t)(32 * sizeof(uint32_t)), MDFNSTATE_RLSB32 | 0, "CR" },
221 { &FLAGS, sizeof(FLAGS), MDFNSTATE_RLSB | 0, "FLAGS" },
222 SFARRAY16(&Matrices.Raw16[0][0], 4 * 10),
223
224 SFARRAY32(&CRVectors.All[0][0], 4 * 4),
225
226 SFVARN(OFX, "OFX"),
227 SFVARN(OFY, "OFY"),
228 SFVARN(H, "H"),
229 SFVARN(DQA, "DQA"),
230 SFVARN(DQB, "DQB"),
231
232 SFVARN(ZSF3, "ZSF3"),
233 SFVARN(ZSF4, "ZSF4"),
234 SFARRAY16(&Vectors[0][0], 3 * 4),
235
236 SFARRAY(RGB.Raw8, 4),
237 SFVARN(OTZ, "OTZ"),
238 SFARRAY16(IR, 4),
239
240 SFVAR(XY_FIFO[0].X),
241 SFVAR(XY_FIFO[0].Y),
242 SFVAR(XY_FIFO[1].X),
243 SFVAR(XY_FIFO[1].Y),
244 SFVAR(XY_FIFO[2].X),
245 SFVAR(XY_FIFO[2].Y),
246 SFVAR(XY_FIFO[3].X),
247 SFVAR(XY_FIFO[3].Y),
248
249 SFARRAY16(Z_FIFO, 4),
250
251 SFARRAY(RGB_FIFO[0].Raw8, 4),
252 SFARRAY(RGB_FIFO[1].Raw8, 4),
253 SFARRAY(RGB_FIFO[2].Raw8, 4),
254
255 SFARRAY32(MAC, 4),
256
257 SFVARN(LZCS, "LZCS"),
258 SFVARN(LZCR, "LZCR"),
259 SFVARN(Reg23, "Reg23"),
260
261 SFEND
262 };
263 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "GTE");
264
265 if(load)
266 {
267
268 }
269
270 return(ret);
271 }
272
273
274 void GTE_WriteCR(unsigned int which, uint32_t value)
275 {
276 static const uint32_t mask_table[32] = {
277 /* 0x00 */
278 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
279
280 /* 0x08 */
281 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
282
283 /* 0x10 */
284 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
285
286 /* 0x18 */
287 0xFFFFFFFF, 0xFFFFFFFF, 0x0000FFFF, 0x0000FFFF, 0xFFFFFFFF, 0x0000FFFF, 0x0000FFFF, 0xFFFFFFFF
288 };
289
290 //PSX_WARNING("[GTE] Write CR %d, 0x%08x", which, value);
291
292 value &= mask_table[which];
293
294 CR[which] = value | (CR[which] & ~mask_table[which]);
295
296 if(which < 24)
297 {
298 int we = which >> 3;
299 which &= 0x7;
300
301 if(which >= 5)
302 CRVectors.All[we][which - 5] = value;
303 else
304 {
305 #ifdef MSB_FIRST
306 Matrices.Raw[we][which] = (value << 16) | (value >> 16);
307 #else
308 Matrices.Raw[we][which] = value;
309 #endif
310 }
311 return;
312 }
313
314 switch(which)
315 {
316 case 24:
317 OFX = value;
318 break;
319
320 case 25:
321 OFY = value;
322 break;
323
324 case 26:
325 H = value;
326 break;
327
328 case 27:
329 DQA = value;
330 break;
331
332 case 28:
333 DQB = value;
334 break;
335
336 case 29:
337 ZSF3 = value;
338 break;
339
340 case 30:
341 ZSF4 = value;
342 break;
343
344 case 31:
345 CR[31] = (value & 0x7ffff000) | ((value & 0x7f87e000) ? (1 << 31) : 0);
346 break;
347 }
348 }
349
350 uint32_t GTE_ReadCR(unsigned int which)
351 {
352 uint32_t ret = 0;
353
354 switch(which)
355 {
356 default:
357 ret = CR[which];
358 if(which == 4 || which == 12 || which == 20)
359 ret = (int16)ret;
360 break;
361
362 case 24:
363 ret = OFX;
364 break;
365
366 case 25:
367 ret = OFY;
368 break;
369
370 case 26:
371 ret = (int16)H;
372 break;
373
374 case 27:
375 ret = (int16)DQA;
376 break;
377
378 case 28:
379 ret = DQB;
380 break;
381
382 case 29:
383 ret = (int16)ZSF3;
384 break;
385
386 case 30:
387 ret = (int16)ZSF4;
388 break;
389
390 case 31:
391 ret = CR[31];
392 break;
393 }
394
395 return(ret);
396 }
397
398 void GTE_WriteDR(unsigned int which, uint32_t value)
399 {
400 switch(which & 0x1F)
401 {
402 case 0:
403 Vectors[0][0] = value;
404 Vectors[0][1] = value >> 16;
405 break;
406
407 case 1:
408 Vectors[0][2] = value;
409 break;
410
411 case 2:
412 Vectors[1][0] = value;
413 Vectors[1][1] = value >> 16;
414 break;
415
416 case 3:
417 Vectors[1][2] = value;
418 break;
419
420 case 4:
421 Vectors[2][0] = value;
422 Vectors[2][1] = value >> 16;
423 break;
424
425 case 5:
426 Vectors[2][2] = value;
427 break;
428
429 case 6:
430 RGB.R = value >> 0;
431 RGB.G = value >> 8;
432 RGB.B = value >> 16;
433 RGB.CD = value >> 24;
434 break;
435
436 case 7:
437 OTZ = value;
438 break;
439
440 case 8:
441 IR0 = value;
442 break;
443
444 case 9:
445 IR1 = value;
446 break;
447
448 case 10:
449 IR2 = value;
450 break;
451
452 case 11:
453 IR3 = value;
454 break;
455
456 case 12:
457 XY_FIFO[0].X = value;
458 XY_FIFO[0].Y = value >> 16;
459 break;
460
461 case 13:
462 XY_FIFO[1].X = value;
463 XY_FIFO[1].Y = value >> 16;
464 break;
465
466 case 14:
467 XY_FIFO[2].X = value;
468 XY_FIFO[2].Y = value >> 16;
469 XY_FIFO[3].X = value;
470 XY_FIFO[3].Y = value >> 16;
471 break;
472
473 case 15:
474 XY_FIFO[3].X = value;
475 XY_FIFO[3].Y = value >> 16;
476
477 XY_FIFO[0] = XY_FIFO[1];
478 XY_FIFO[1] = XY_FIFO[2];
479 XY_FIFO[2] = XY_FIFO[3];
480 break;
481
482 case 16:
483 Z_FIFO[0] = value;
484 break;
485
486 case 17:
487 Z_FIFO[1] = value;
488 break;
489
490 case 18:
491 Z_FIFO[2] = value;
492 break;
493
494 case 19:
495 Z_FIFO[3] = value;
496 break;
497
498 case 20:
499 RGB_FIFO[0].R = value;
500 RGB_FIFO[0].G = value >> 8;
501 RGB_FIFO[0].B = value >> 16;
502 RGB_FIFO[0].CD = value >> 24;
503 break;
504
505 case 21:
506 RGB_FIFO[1].R = value;
507 RGB_FIFO[1].G = value >> 8;
508 RGB_FIFO[1].B = value >> 16;
509 RGB_FIFO[1].CD = value >> 24;
510 break;
511
512 case 22:
513 RGB_FIFO[2].R = value;
514 RGB_FIFO[2].G = value >> 8;
515 RGB_FIFO[2].B = value >> 16;
516 RGB_FIFO[2].CD = value >> 24;
517 break;
518
519 case 23:
520 Reg23 = value;
521 break;
522
523 case 24:
524 MAC[0] = value;
525 break;
526
527 case 25:
528 MAC[1] = value;
529 break;
530
531 case 26:
532 MAC[2] = value;
533 break;
534
535 case 27:
536 MAC[3] = value;
537 break;
538
539 case 28:
540 IR1 = ((value >> 0) & 0x1F) << 7;
541 IR2 = ((value >> 5) & 0x1F) << 7;
542 IR3 = ((value >> 10) & 0x1F) << 7;
543 break;
544
545 case 29: // Read-only
546 break;
547
548 case 30:
549 LZCS = value;
550 {
551 uint32_t test = value & 0x80000000;
552 LZCR = 0;
553
554 while((value & 0x80000000) == test && LZCR < 32)
555 {
556 LZCR++;
557 value <<= 1;
558 }
559 }
560 break;
561
562 case 31: // Read-only
563 break;
564 }
565 }
566
567 uint32_t GTE_ReadDR(unsigned int which)
568 {
569 uint32_t ret = 0;
570
571 switch(which & 0x1F)
572 {
573 case 0:
574 ret = (uint16_t)Vectors[0][0] | ((uint16_t)Vectors[0][1] << 16);
575 break;
576
577 case 1:
578 ret = (int16_t)Vectors[0][2];
579 break;
580
581 case 2:
582 ret = (uint16_t)Vectors[1][0] | ((uint16_t)Vectors[1][1] << 16);
583 break;
584
585 case 3:
586 ret = (int16_t)Vectors[1][2];
587 break;
588
589 case 4:
590 ret = (uint16_t)Vectors[2][0] | ((uint16_t)Vectors[2][1] << 16);
591 break;
592
593 case 5:
594 ret = (int16_t)Vectors[2][2];
595 break;
596
597 case 6:
598 ret = RGB.R | (RGB.G << 8) | (RGB.B << 16) | (RGB.CD << 24);
599 break;
600
601 case 7:
602 ret = (uint16_t)OTZ;
603 break;
604
605 case 8:
606 ret = (int16_t)IR0;
607 break;
608
609 case 9:
610 ret = (int16_t)IR1;
611 break;
612
613 case 10:
614 ret = (int16_t)IR2;
615 break;
616
617 case 11:
618 ret = (int16_t)IR3;
619 break;
620
621 case 12:
622 ret = (uint16_t)XY_FIFO[0].X | ((uint16_t)XY_FIFO[0].Y << 16);
623 break;
624
625 case 13:
626 ret = (uint16_t)XY_FIFO[1].X | ((uint16_t)XY_FIFO[1].Y << 16);
627 break;
628
629 case 14:
630 ret = (uint16_t)XY_FIFO[2].X | ((uint16_t)XY_FIFO[2].Y << 16);
631 break;
632
633 case 15:
634 ret = (uint16_t)XY_FIFO[3].X | ((uint16_t)XY_FIFO[3].Y << 16);
635 break;
636
637 case 16:
638 ret = (uint16_t)Z_FIFO[0];
639 break;
640
641 case 17:
642 ret = (uint16_t)Z_FIFO[1];
643 break;
644
645 case 18:
646 ret = (uint16_t)Z_FIFO[2];
647 break;
648
649 case 19:
650 ret = (uint16_t)Z_FIFO[3];
651 break;
652
653 case 20:
654 ret = RGB_FIFO[0].R | (RGB_FIFO[0].G << 8) | (RGB_FIFO[0].B << 16) | (RGB_FIFO[0].CD << 24);
655 break;
656
657 case 21:
658 ret = RGB_FIFO[1].R | (RGB_FIFO[1].G << 8) | (RGB_FIFO[1].B << 16) | (RGB_FIFO[1].CD << 24);
659 break;
660
661 case 22:
662 ret = RGB_FIFO[2].R | (RGB_FIFO[2].G << 8) | (RGB_FIFO[2].B << 16) | (RGB_FIFO[2].CD << 24);
663 break;
664
665 case 23:
666 ret = Reg23;
667 break;
668
669 case 24:
670 ret = MAC[0];
671 break;
672
673 case 25:
674 ret = MAC[1];
675 break;
676
677 case 26:
678 ret = MAC[2];
679 break;
680
681 case 27:
682 ret = MAC[3];
683 break;
684
685 case 28:
686 case 29:
687 ret = Sat5(IR1 >> 7) | (Sat5(IR2 >> 7) << 5) | (Sat5(IR3 >> 7) << 10);
688 break;
689
690 case 30:
691 ret = LZCS;
692 break;
693
694 case 31:
695 ret = LZCR;
696 break;
697 }
698 return(ret);
699 }
700
701 #define sign_x_to_s64(_bits, _value) (((int64_t)((uint64_t)(_value) << (64 - _bits))) >> (64 - _bits))
702
703 static INLINE int64_t A_MV(unsigned which, int64_t value)
704 {
705 if(value >= (INT64_C(1) << 43))
706 FLAGS |= 1 << (30 - which);
707
708 if(value < -(INT64_C(1) << 43))
709 FLAGS |= 1 << (27 - which);
710
711 return sign_x_to_s64(44, value);
712 }
713
714 static INLINE int64_t F(int64_t value)
715 {
716 if(value < -2147483648LL)
717 {
718 // flag set here
719 FLAGS |= 1 << 15;
720 }
721
722 if(value > 2147483647LL)
723 {
724 // flag set here
725 FLAGS |= 1 << 16;
726 }
727 return(value);
728 }
729
730
731 static INLINE int16_t Lm_B(unsigned int which, int32_t value, int lm)
732 {
733 int32_t tmp = lm << 15;
734
735 if(value < (-32768 + tmp))
736 {
737 // set flag here
738 FLAGS |= 1 << (24 - which);
739 value = -32768 + tmp;
740 }
741
742 if(value > 32767)
743 {
744 // Set flag here
745 FLAGS |= 1 << (24 - which);
746 value = 32767;
747 }
748
749 return(value);
750 }
751
752 static INLINE int16_t Lm_B_PTZ(unsigned int which, int32_t value, int32_t ftv_value, int lm)
753 {
754 int32_t tmp = lm << 15;
755
756 if(ftv_value < -32768)
757 FLAGS |= 1 << (24 - which);
758
759 if(ftv_value > 32767)
760 FLAGS |= 1 << (24 - which);
761
762 clamp(&value, (-32768 + tmp), 32767);
763
764 return(value);
765 }
766
767 static INLINE uint8_t Lm_C(unsigned int which, int32_t value)
768 {
769 if(value & ~0xFF)
770 {
771 // Set flag here
772 FLAGS |= 1 << (21 - which); // Tested with GPF
773
774 if(value < 0)
775 value = 0;
776
777 if(value > 255)
778 value = 255;
779 }
780
781 return(value);
782 }
783
784 static INLINE int32_t Lm_D(int32_t value, int unchained)
785 {
786 // Not sure if we should have it as int64, or just chain on to and special case when the F flags are set.
787 if(!unchained)
788 {
789 if(FLAGS & (1 << 15))
790 {
791 FLAGS |= 1 << 18;
792 return(0);
793 }
794
795 if(FLAGS & (1 << 16))
796 {
797 FLAGS |= 1 << 18;
798 return(0xFFFF);
799 }
800 }
801
802 if(value < 0)
803 {
804 // Set flag here
805 value = 0;
806 FLAGS |= 1 << 18; // Tested with AVSZ3
807 }
808 else if(value > 65535)
809 {
810 // Set flag here.
811 value = 65535;
812 FLAGS |= 1 << 18; // Tested with AVSZ3
813 }
814
815 return(value);
816 }
817
818 static INLINE int32_t Lm_G(unsigned int which, int32_t value)
819 {
820 if(value < -1024)
821 {
822 // Set flag here
823 value = -1024;
824 FLAGS |= 1 << (14 - which);
825 }
826
827 if(value > 1023)
828 {
829 // Set flag here.
830 value = 1023;
831 FLAGS |= 1 << (14 - which);
832 }
833
834 return(value);
835 }
836
837 // limit to 4096, not 4095
838 static INLINE int32_t Lm_H(int32_t value)
839 {
840 if(value < 0)
841 {
842 value = 0;
843 FLAGS |= 1 << 12;
844 }
845
846 if(value > 4096)
847 {
848 value = 4096;
849 FLAGS |= 1 << 12;
850 }
851
852 return(value);
853 }
854
855 static INLINE void MAC_to_RGB_FIFO(void)
856 {
857 RGB_FIFO[0] = RGB_FIFO[1];
858 RGB_FIFO[1] = RGB_FIFO[2];
859 RGB_FIFO[2].R = Lm_C(0, MAC[1] >> 4);
860 RGB_FIFO[2].G = Lm_C(1, MAC[2] >> 4);
861 RGB_FIFO[2].B = Lm_C(2, MAC[3] >> 4);
862 RGB_FIFO[2].CD = RGB.CD;
863 }
864
865
866 static INLINE void MAC_to_IR(int lm)
867 {
868 IR1 = Lm_B(0, MAC[1], lm);
869 IR2 = Lm_B(1, MAC[2], lm);
870 IR3 = Lm_B(2, MAC[3], lm);
871 }
872
873 static INLINE void MultiplyMatrixByVector(const gtematrix *matrix, const int16_t *v, const int32_t *crv, uint32_t sf, int lm)
874 {
875 unsigned i;
876
877 for(i = 0; i < 3; i++)
878 {
879 int64_t tmp;
880 int32_t mulr[3];
881
882 tmp = (uint64_t)(int64_t)crv[i] << 12;
883
884 if(matrix == &Matrices.AbbyNormal)
885 {
886 if(i == 0)
887 {
888 mulr[0] = -(RGB.R << 4);
889 mulr[1] = (RGB.R << 4);
890 mulr[2] = IR0;
891 }
892 else
893 {
894 mulr[0] = (int16_t)CR[i];
895 mulr[1] = (int16_t)CR[i];
896 mulr[2] = (int16_t)CR[i];
897 }
898 }
899 else
900 {
901 mulr[0] = matrix->MX[i][0];
902 mulr[1] = matrix->MX[i][1];
903 mulr[2] = matrix->MX[i][2];
904 }
905 mulr[0] *= v[0];
906 mulr[1] *= v[1];
907 mulr[2] *= v[2];
908
909 tmp = A_MV(i, tmp + mulr[0]);
910 if(crv == CRVectors.FC)
911 {
912 Lm_B(i, tmp >> sf, FALSE);
913 tmp = 0;
914 }
915
916 tmp = A_MV(i, tmp + mulr[1]);
917 tmp = A_MV(i, tmp + mulr[2]);
918
919 MAC[1 + i] = tmp >> sf;
920 }
921
922
923 MAC_to_IR(lm);
924 }
925
926
927 static INLINE void MultiplyMatrixByVector_PT(const gtematrix *matrix, const int16_t *v, const int32_t *crv, uint32_t sf, int lm)
928 {
929 int64_t tmp[3];
930 unsigned i;
931
932 for(i = 0; i < 3; i++)
933 {
934 int32_t mulr[3];
935
936 tmp[i] = (uint64_t)(int64_t)crv[i] << 12;
937
938 mulr[0] = matrix->MX[i][0] * v[0];
939 mulr[1] = matrix->MX[i][1] * v[1];
940 mulr[2] = matrix->MX[i][2] * v[2];
941
942 tmp[i] = A_MV(i, tmp[i] + mulr[0]);
943 tmp[i] = A_MV(i, tmp[i] + mulr[1]);
944 tmp[i] = A_MV(i, tmp[i] + mulr[2]);
945
946 MAC[1 + i] = tmp[i] >> sf;
947 }
948
949 IR1 = Lm_B(0, MAC[1], lm);
950 IR2 = Lm_B(1, MAC[2], lm);
951 //printf("FTV: %08x %08x\n", crv[2], (uint32)(tmp[2] >> 12));
952 IR3 = Lm_B_PTZ(2, MAC[3], tmp[2] >> 12, lm);
953
954 Z_FIFO[0] = Z_FIFO[1];
955 Z_FIFO[1] = Z_FIFO[2];
956 Z_FIFO[2] = Z_FIFO[3];
957 Z_FIFO[3] = Lm_D(tmp[2] >> 12, TRUE);
958 }
959
960 static int32_t SQR(uint32_t instr)
961 {
962 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
963 const int lm = (instr >> 10) & 1;
964
965 MAC[1] = ((IR1 * IR1) >> sf);
966 MAC[2] = ((IR2 * IR2) >> sf);
967 MAC[3] = ((IR3 * IR3) >> sf);
968
969 MAC_to_IR(lm);
970
971 return(5);
972 }
973
974
975 static int32_t MVMVA(uint32_t instr)
976 {
977 int16_t v[3];
978 const uint32_t mx = (instr >> 17) & 0x3;
979 const int32* cv = CRVectors.All[(instr >> 13) & 0x3];
980 const uint32_t v_i = (instr >> 15) & 0x3;
981 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
982 const int lm = (instr >> 10) & 1;
983
984 if(v_i == 3)
985 {
986 v[0] = IR1;
987 v[1] = IR2;
988 v[2] = IR3;
989 }
990 else
991 {
992 v[0] = Vectors[v_i][0];
993 v[1] = Vectors[v_i][1];
994 v[2] = Vectors[v_i][2];
995 }
996
997 MultiplyMatrixByVector(&Matrices.All[mx], v, cv, sf, lm);
998
999 return(8);
1000 }
1001
1002 static INLINE unsigned CountLeadingZeroU16(uint16_t val)
1003 {
1004 unsigned ret = 0;
1005
1006 while(!(val & 0x8000) && ret < 16)
1007 {
1008 val <<= 1;
1009 ret++;
1010 }
1011
1012 return ret;
1013 }
1014
1015 static INLINE uint32_t Divide(uint32_t dividend, uint32_t divisor)
1016 {
1017 //if((Z_FIFO[3] * 2) > H)
1018 if((divisor * 2) > dividend)
1019 {
1020 unsigned shift_bias = CountLeadingZeroU16(divisor);
1021
1022 dividend <<= shift_bias;
1023 divisor <<= shift_bias;
1024
1025 return ((int64_t)dividend * CalcRecip(divisor | 0x8000) + 32768) >> 16;
1026 }
1027
1028 FLAGS |= 1 << 17;
1029 return 0x1FFFF;
1030 }
1031
1032 static INLINE void TransformXY(int64_t h_div_sz)
1033 {
1034 MAC[0] = F((int64_t)OFX + IR1 * h_div_sz * ((widescreen_hack) ? 0.75 : 1.00)) >> 16;
1035 XY_FIFO[3].X = Lm_G(0, MAC[0]);
1036
1037 MAC[0] = F((int64_t)OFY + IR2 * h_div_sz) >> 16;
1038 XY_FIFO[3].Y = Lm_G(1, MAC[0]);
1039
1040 XY_FIFO[0] = XY_FIFO[1];
1041 XY_FIFO[1] = XY_FIFO[2];
1042 XY_FIFO[2] = XY_FIFO[3];
1043 }
1044
1045 static INLINE void TransformDQ(int64_t h_div_sz)
1046 {
1047 MAC[0] = F((int64_t)DQB + DQA * h_div_sz);
1048 IR0 = Lm_H(((int64_t)DQB + DQA * h_div_sz) >> 12);
1049 }
1050
1051 static int32_t RTPS(uint32_t instr)
1052 {
1053 int64_t h_div_sz;
1054 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1055 const int lm = (instr >> 10) & 1;
1056
1057 MultiplyMatrixByVector_PT(&Matrices.Rot, Vectors[0], CRVectors.T, sf, lm);
1058 h_div_sz = Divide(H, Z_FIFO[3]);
1059
1060 TransformXY(h_div_sz);
1061 TransformDQ(h_div_sz);
1062
1063 return(15);
1064 }
1065
1066 static int32_t RTPT(uint32_t instr)
1067 {
1068 unsigned i;
1069 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1070 const int lm = (instr >> 10) & 1;
1071
1072 for(i = 0; i < 3; i++)
1073 {
1074 int64_t h_div_sz;
1075
1076 MultiplyMatrixByVector_PT(&Matrices.Rot, Vectors[i], CRVectors.T, sf, lm);
1077 h_div_sz = Divide(H, Z_FIFO[3]);
1078
1079 TransformXY(h_div_sz);
1080
1081 if(i == 2)
1082 TransformDQ(h_div_sz);
1083 }
1084
1085 return(23);
1086 }
1087
1088 static INLINE void NormColor(uint32_t sf, int lm, uint32_t v)
1089 {
1090 int16_t tmp_vector[3];
1091
1092 MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm);
1093
1094 tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3;
1095 MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm);
1096
1097 MAC_to_RGB_FIFO();
1098 }
1099
1100 static int32_t NCS(uint32_t instr)
1101 {
1102 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1103 const int lm = (instr >> 10) & 1;
1104
1105 NormColor(sf, lm, 0);
1106
1107 return(14);
1108 }
1109
1110 static int32_t NCT(uint32_t instr)
1111 {
1112 unsigned i;
1113 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1114 const int lm = (instr >> 10) & 1;
1115
1116 for(i = 0; i < 3; i++)
1117 NormColor(sf, lm, i);
1118
1119 return(30);
1120 }
1121
1122 INLINE void NormColorColor(uint32_t v, uint32_t sf, int lm)
1123 {
1124 int16_t tmp_vector[3];
1125
1126 MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm);
1127
1128 tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3;
1129 MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm);
1130
1131 MAC[1] = ((RGB.R << 4) * IR1) >> sf;
1132 MAC[2] = ((RGB.G << 4) * IR2) >> sf;
1133 MAC[3] = ((RGB.B << 4) * IR3) >> sf;
1134
1135 MAC_to_IR(lm);
1136
1137 MAC_to_RGB_FIFO();
1138 }
1139
1140 static int32_t NCCS(uint32_t instr)
1141 {
1142 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1143 const int lm = (instr >> 10) & 1;
1144
1145 NormColorColor(0, sf, lm);
1146 return(17);
1147 }
1148
1149
1150 static int32_t NCCT(uint32_t instr)
1151 {
1152 unsigned i;
1153 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1154 const int lm = (instr >> 10) & 1;
1155
1156 for(i = 0; i < 3; i++)
1157 NormColorColor(i, sf, lm);
1158
1159 return(39);
1160 }
1161
1162 static INLINE void DepthCue(int mult_IR123, int RGB_from_FIFO, uint32_t sf, int lm)
1163 {
1164 int i;
1165 int32_t RGB_temp[3];
1166 int32_t IR_temp[3] = { IR1, IR2, IR3 };
1167
1168 //assert(sf);
1169 RGB_temp[0] = RGB.R;
1170 RGB_temp[1] = RGB.G;
1171 RGB_temp[2] = RGB.B;
1172
1173 if(RGB_from_FIFO)
1174 {
1175 RGB_temp[0] = RGB_FIFO[0].R;
1176 RGB_temp[1] = RGB_FIFO[0].G;
1177 RGB_temp[2] = RGB_FIFO[0].B;
1178 }
1179 RGB_temp[0] <<= 4;
1180 RGB_temp[1] <<= 4;
1181 RGB_temp[2] <<= 4;
1182
1183 if(mult_IR123)
1184 {
1185 for(i = 0; i < 3; i++)
1186 {
1187 MAC[1 + i] = A_MV(i, ((int64_t)((uint64_t)(int64_t)CRVectors.FC[i] << 12) - RGB_temp[i] * IR_temp[i])) >> sf;
1188 MAC[1 + i] = A_MV(i, (RGB_temp[i] * IR_temp[i] + IR0 * Lm_B(i, MAC[1 + i], FALSE))) >> sf;
1189 }
1190 }
1191 else
1192 {
1193 for(i = 0; i < 3; i++)
1194 {
1195 MAC[1 + i] = A_MV(i, ((int64_t)((uint64_t)(int64_t)CRVectors.FC[i] << 12) - (int32)((uint32)RGB_temp[i] << 12))) >> sf;
1196 MAC[1 + i] = A_MV(i, ((int64_t)((uint64_t)(int64_t)RGB_temp[i] << 12) + IR0 * Lm_B(i, MAC[1 + i], FALSE))) >> sf;
1197 }
1198 }
1199
1200 MAC_to_IR(lm);
1201
1202 MAC_to_RGB_FIFO();
1203 }
1204
1205
1206 static int32_t DCPL(uint32_t instr)
1207 {
1208 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1209 const int lm = (instr >> 10) & 1;
1210
1211 DepthCue(TRUE, FALSE, sf, lm);
1212
1213 return(8);
1214 }
1215
1216
1217 static int32_t DPCS(uint32_t instr)
1218 {
1219 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1220 const int lm = (instr >> 10) & 1;
1221
1222 DepthCue(FALSE, FALSE, sf, lm);
1223
1224 return(8);
1225 }
1226
1227 static int32_t DPCT(uint32_t instr)
1228 {
1229 unsigned i;
1230 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1231 const int lm = (instr >> 10) & 1;
1232
1233 for(i = 0; i < 3; i++)
1234 DepthCue(FALSE, TRUE, sf, lm);
1235
1236 return(17);
1237 }
1238
1239 static int32_t INTPL(uint32_t instr)
1240 {
1241 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1242 const int lm = (instr >> 10) & 1;
1243
1244 MAC[1] = A_MV(0, ((int64_t)((uint64_t)(int64_t)CRVectors.FC[0] << 12) - (int32)((uint32)(int32)IR1 << 12))) >> sf;
1245 MAC[2] = A_MV(1, ((int64_t)((uint64_t)(int64_t)CRVectors.FC[1] << 12) - (int32)((uint32)(int32)IR2 << 12))) >> sf;
1246 MAC[3] = A_MV(2, ((int64_t)((uint64_t)(int64_t)CRVectors.FC[2] << 12) - (int32)((uint32)(int32)IR3 << 12))) >> sf;
1247
1248 MAC[1] = A_MV(0, ((int64_t)((uint64_t)(int64_t)IR1 << 12) + IR0 * Lm_B(0, MAC[1], FALSE)) >> sf);
1249 MAC[2] = A_MV(1, ((int64_t)((uint64_t)(int64_t)IR2 << 12) + IR0 * Lm_B(1, MAC[2], FALSE)) >> sf);
1250 MAC[3] = A_MV(2, ((int64_t)((uint64_t)(int64_t)IR3 << 12) + IR0 * Lm_B(2, MAC[3], FALSE)) >> sf);
1251
1252 MAC_to_IR(lm);
1253
1254 MAC_to_RGB_FIFO();
1255
1256 return(8);
1257 }
1258
1259
1260 static INLINE void NormColorDepthCue(uint32_t v, uint32_t sf, int lm)
1261 {
1262 int16_t tmp_vector[3];
1263
1264 MultiplyMatrixByVector(&Matrices.Light, Vectors[v], CRVectors.Null, sf, lm);
1265
1266 tmp_vector[0] = IR1;
1267 tmp_vector[1] = IR2;
1268 tmp_vector[2] = IR3;
1269 MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm);
1270
1271 DepthCue(TRUE, FALSE, sf, lm);
1272 }
1273
1274 static int32_t NCDS(uint32_t instr)
1275 {
1276 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1277 const int lm = (instr >> 10) & 1;
1278
1279 NormColorDepthCue(0, sf, lm);
1280
1281 return(19);
1282 }
1283
1284 static int32_t NCDT(uint32_t instr)
1285 {
1286 unsigned i;
1287 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1288 const int lm = (instr >> 10) & 1;
1289
1290 for(i = 0; i < 3; i++)
1291 NormColorDepthCue(i, sf, lm);
1292
1293 return(44);
1294 }
1295
1296 static int32_t CC(uint32_t instr)
1297 {
1298 int16_t tmp_vector[3];
1299 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1300 const int lm = (instr >> 10) & 1;
1301
1302 tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3;
1303 MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm);
1304
1305 MAC[1] = ((RGB.R << 4) * IR1) >> sf;
1306 MAC[2] = ((RGB.G << 4) * IR2) >> sf;
1307 MAC[3] = ((RGB.B << 4) * IR3) >> sf;
1308
1309 MAC_to_IR(lm);
1310
1311 MAC_to_RGB_FIFO();
1312
1313 return(11);
1314 }
1315
1316 static int32_t CDP(uint32_t instr)
1317 {
1318 int16_t tmp_vector[3];
1319 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1320 const int lm = (instr >> 10) & 1;
1321
1322 tmp_vector[0] = IR1; tmp_vector[1] = IR2; tmp_vector[2] = IR3;
1323 MultiplyMatrixByVector(&Matrices.Color, tmp_vector, CRVectors.B, sf, lm);
1324
1325 DepthCue(TRUE, FALSE, sf, lm);
1326
1327 return(13);
1328 }
1329
1330 static int32_t NCLIP(uint32_t instr)
1331 {
1332 MAC[0] = F( (int64_t)(XY_FIFO[0].X * (XY_FIFO[1].Y - XY_FIFO[2].Y)) + (XY_FIFO[1].X * (XY_FIFO[2].Y - XY_FIFO[0].Y)) + (XY_FIFO[2].X * (XY_FIFO[0].Y - XY_FIFO[1].Y))
1333 );
1334
1335 return(8);
1336 }
1337
1338 static int32_t AVSZ3(uint32_t instr)
1339 {
1340 MAC[0] = F(((int64_t)ZSF3 * (Z_FIFO[1] + Z_FIFO[2] + Z_FIFO[3])));
1341
1342 OTZ = Lm_D(MAC[0] >> 12, FALSE);
1343
1344 return(5);
1345 }
1346
1347 static int32_t AVSZ4(uint32_t instr)
1348 {
1349 MAC[0] = F(((int64_t)ZSF4 * (Z_FIFO[0] + Z_FIFO[1] + Z_FIFO[2] + Z_FIFO[3])));
1350
1351 OTZ = Lm_D(MAC[0] >> 12, FALSE);
1352
1353 return(5);
1354 }
1355
1356
1357 // -32768 * -32768 - 32767 * -32768 = 2147450880
1358 // (2 ^ 31) - 1 = 2147483647
1359 static int32_t OP(uint32_t instr)
1360 {
1361 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1362 const int lm = (instr >> 10) & 1;
1363
1364 MAC[1] = ((Matrices.Rot.MX[1][1] * IR3) - (Matrices.Rot.MX[2][2] * IR2)) >> sf;
1365 MAC[2] = ((Matrices.Rot.MX[2][2] * IR1) - (Matrices.Rot.MX[0][0] * IR3)) >> sf;
1366 MAC[3] = ((Matrices.Rot.MX[0][0] * IR2) - (Matrices.Rot.MX[1][1] * IR1)) >> sf;
1367
1368 MAC_to_IR(lm);
1369
1370 return(6);
1371 }
1372
1373 static int32_t GPF(uint32_t instr)
1374 {
1375 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1376 const int lm = (instr >> 10) & 1;
1377
1378 MAC[1] = (IR0 * IR1) >> sf;
1379 MAC[2] = (IR0 * IR2) >> sf;
1380 MAC[3] = (IR0 * IR3) >> sf;
1381
1382 MAC_to_IR(lm);
1383
1384 MAC_to_RGB_FIFO();
1385
1386 return(5);
1387 }
1388
1389 static int32_t GPL(uint32_t instr)
1390 {
1391 const uint32_t sf = (instr & (1 << 19)) ? 12 : 0;
1392 const int lm = (instr >> 10) & 1;
1393
1394 MAC[1] = A_MV(0, (int64_t)((uint64_t)(int64_t)MAC[1] << sf) + (IR0 * IR1)) >> sf;
1395 MAC[2] = A_MV(1, (int64_t)((uint64_t)(int64_t)MAC[2] << sf) + (IR0 * IR2)) >> sf;
1396 MAC[3] = A_MV(2, (int64_t)((uint64_t)(int64_t)MAC[3] << sf) + (IR0 * IR3)) >> sf;
1397
1398 MAC_to_IR(lm);
1399
1400 MAC_to_RGB_FIFO();
1401
1402 return(5);
1403 }
1404
1405 /*
1406
1407 ---------------------------------------------------------------------------------------------
1408 | 24 23 22 21 20 | 19 | 18 17 | 16 15 | 14 13 | 12 11 | 10 | 9 8 7 6 | 5 4 3 2 1 0 |
1409 |-------------------------------------------------------------------------------------------|
1410 | (unused) | sf | mx | v | cv |(unused)| lm | (unused) | opcode |
1411 ---------------------------------------------------------------------------------------------
1412 (unused) = unused, ignored
1413
1414 sf = shift 12
1415
1416 mx = matrix selection
1417
1418 v = source vector
1419
1420 cv = add vector(translation/back/far color(bugged)/none)
1421
1422 (unused) = unused, ignored
1423
1424 lm = limit negative results to 0
1425
1426 (unused) = unused, ignored
1427
1428 opcode = operation code
1429 */
1430
1431 int32_t GTE_Instruction(uint32_t instr)
1432 {
1433 const unsigned code = instr & 0x3F;
1434 int32_t ret = 1;
1435
1436 FLAGS = 0;
1437
1438 switch(code)
1439 {
1440 default:
1441 break;
1442 case 0x00: // alternate?
1443 case 0x01:
1444 ret = RTPS(instr);
1445 break;
1446
1447 /*
1448 case 0x02: // UNSTABLE?
1449 break;
1450
1451 case 0x03: // UNSTABLE?
1452 break;
1453
1454 case 0x04: // Probably simple with v,cv,sf,mx,lm ignored. Same calculation as 0x3B?
1455 break;
1456
1457 case 0x05: // UNSTABLE?
1458 break;
1459 */
1460
1461 case 0x06:
1462 ret = NCLIP(instr);
1463 break;
1464
1465 /*
1466 case 0x07: // UNSTABLE?
1467 break;
1468
1469 case 0x08: // UNSTABLE?
1470 break;
1471
1472 case 0x09: // UNSTABLE?
1473 break;
1474
1475 case 0x0A: // UNSTABLE?
1476 break;
1477
1478 case 0x0B: // UNSTABLE?
1479 break;
1480
1481 */
1482
1483 case 0x0C:
1484 ret = OP(instr);
1485 break;
1486
1487 /*
1488 case 0x0D: // UNSTABLE?
1489 break;
1490
1491 case 0x0E: // UNSTABLE?
1492 break;
1493
1494 case 0x0F: // UNSTABLE?
1495 break;
1496 */
1497
1498 case 0x10:
1499 ret = DPCS(instr);
1500 break;
1501
1502 case 0x11:
1503 ret = INTPL(instr);
1504 break;
1505
1506 case 0x12:
1507 ret = MVMVA(instr);
1508 break;
1509
1510 case 0x13:
1511 ret = NCDS(instr);
1512 break;
1513
1514 case 0x14:
1515 ret = CDP(instr);
1516 break;
1517
1518
1519 /*
1520 case 0x15: // does one push on RGB FIFO, what else...
1521 break;
1522 */
1523
1524 case 0x16:
1525 ret = NCDT(instr);
1526 break;
1527
1528 /*
1529 case 0x17: // PARTIALLY UNSTABLE(depending on sf or v or cv or mx or lm), similar behavior under some conditions to 0x16?
1530 break;
1531
1532 case 0x18:
1533 break;
1534
1535 case 0x19:
1536 break;
1537 */
1538
1539 case 0x1A: // Alternate for 0x29?
1540 ret = DCPL(instr);
1541 break;
1542
1543 case 0x1B:
1544 ret = NCCS(instr);
1545 break;
1546
1547 case 0x1C:
1548 ret = CC(instr);
1549 break;
1550
1551 /*
1552 case 0x1D:
1553 break;
1554 */
1555
1556 case 0x1E:
1557 ret = NCS(instr);
1558 break;
1559
1560 /*
1561 case 0x1F:
1562 break;
1563 */
1564
1565 case 0x20:
1566 ret = NCT(instr);
1567 break;
1568 /*
1569 case 0x21:
1570 break;
1571
1572 case 0x22: // UNSTABLE?
1573 break;
1574
1575 case 0x23:
1576 break;
1577
1578 case 0x24:
1579 break;
1580
1581 case 0x25:
1582 break;
1583
1584 case 0x26:
1585 break;
1586
1587 case 0x27:
1588 break;
1589 */
1590
1591 case 0x28:
1592 ret = SQR(instr);
1593 break;
1594
1595 case 0x29:
1596 ret = DCPL(instr);
1597 break;
1598
1599 case 0x2A:
1600 ret = DPCT(instr);
1601 break;
1602
1603 /*
1604 case 0x2B:
1605 break;
1606
1607 case 0x2C:
1608 break;
1609 */
1610
1611 case 0x2D:
1612 ret = AVSZ3(instr);
1613 break;
1614
1615 case 0x2E:
1616 ret = AVSZ4(instr);
1617 break;
1618
1619 /*
1620 case 0x2F: // UNSTABLE?
1621 break;
1622 */
1623
1624 case 0x30:
1625 ret = RTPT(instr);
1626 break;
1627
1628 /*
1629 case 0x31: // UNSTABLE?
1630 break;
1631
1632 case 0x32: // UNSTABLE?
1633 break;
1634
1635 case 0x33: // UNSTABLE?
1636 break;
1637
1638 case 0x34: // UNSTABLE?
1639 break;
1640
1641 case 0x35: // UNSTABLE?
1642 break;
1643
1644 case 0x36: // UNSTABLE?
1645 break;
1646
1647 case 0x37: // UNSTABLE?
1648 break;
1649
1650 case 0x38:
1651 break;
1652
1653 case 0x39: // Probably simple with v,cv,sf,mx,lm ignored.
1654 break;
1655
1656 case 0x3A: // Probably simple with v,cv,sf,mx,lm ignored.
1657 break;
1658
1659 case 0x3B: // Probably simple with v,cv,sf,mx,lm ignored. Same calculation as 0x04?
1660 break;
1661
1662 case 0x3C: // UNSTABLE?
1663 break;
1664 */
1665
1666 case 0x3D:
1667 ret = GPF(instr);
1668 break;
1669
1670 case 0x3E:
1671 ret = GPL(instr);
1672 break;
1673
1674 case 0x3F:
1675 ret = NCCT(instr);
1676 break;
1677 }
1678
1679 if(FLAGS & 0x7f87e000)
1680 FLAGS |= 1 << 31;
1681
1682 CR[31] = FLAGS;
1683
1684 return(ret - 1);
1685 }
0 #ifndef __MDFN_PSX_GTE_H
1 #define __MDFN_PSX_GTE_H
2
3 void GTE_Init(void);
4 void GTE_Power(void);
5 int GTE_StateAction(StateMem *sm, int load, int data_only);
6
7 int32 GTE_Instruction(uint32_t instr);
8
9 void GTE_WriteCR(unsigned int which, uint32_t value);
10 void GTE_WriteDR(unsigned int which, uint32_t value);
11
12 uint32_t GTE_ReadCR(unsigned int which);
13 uint32_t GTE_ReadDR(unsigned int which);
14
15 #endif
0 #include "../psx.h"
1 #include "../frontio.h"
2 #include "dualanalog.h"
3
4 class InputDevice_DualAnalog : public InputDevice
5 {
6 public:
7
8 InputDevice_DualAnalog(bool joystick_mode_);
9 virtual ~InputDevice_DualAnalog();
10
11 virtual void Power(void);
12 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
13 virtual void UpdateInput(const void *data);
14
15 //
16 //
17 //
18 virtual void SetDTR(bool new_dtr);
19 virtual bool GetDSR(void);
20 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
21
22 private:
23
24 bool joystick_mode;
25 bool dtr;
26
27 uint8 buttons[2];
28 uint8 axes[2][2];
29
30 int32 command_phase;
31 uint32 bitpos;
32 uint8 receive_buffer;
33
34 uint8 command;
35
36 uint8 transmit_buffer[8];
37 uint32 transmit_pos;
38 uint32 transmit_count;
39 };
40
41 InputDevice_DualAnalog::InputDevice_DualAnalog(bool joystick_mode_) : joystick_mode(joystick_mode_)
42 {
43 Power();
44 }
45
46 InputDevice_DualAnalog::~InputDevice_DualAnalog()
47 {
48
49 }
50
51 void InputDevice_DualAnalog::Power(void)
52 {
53 dtr = 0;
54
55 buttons[0] = buttons[1] = 0;
56
57 command_phase = 0;
58
59 bitpos = 0;
60
61 receive_buffer = 0;
62
63 command = 0;
64
65 memset(transmit_buffer, 0, sizeof(transmit_buffer));
66
67 transmit_pos = 0;
68 transmit_count = 0;
69 }
70
71 int InputDevice_DualAnalog::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
72 {
73 SFORMAT StateRegs[] =
74 {
75 SFVAR(dtr),
76
77 SFARRAY(buttons, sizeof(buttons)),
78 SFARRAY(&axes[0][0], sizeof(axes)),
79
80 SFVAR(command_phase),
81 SFVAR(bitpos),
82 SFVAR(receive_buffer),
83
84 SFVAR(command),
85
86 SFARRAY(transmit_buffer, sizeof(transmit_buffer)),
87 SFVAR(transmit_pos),
88 SFVAR(transmit_count),
89
90 SFEND
91 };
92 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
93
94 if(load)
95 {
96 if((transmit_pos + transmit_count) > sizeof(transmit_buffer))
97 {
98 transmit_pos = 0;
99 transmit_count = 0;
100 }
101 }
102
103 return(ret);
104 }
105
106 void InputDevice_DualAnalog::UpdateInput(const void *data)
107 {
108 uint8 *d8 = (uint8 *)data;
109
110 buttons[0] = d8[0];
111 buttons[1] = d8[1];
112
113 for(int stick = 0; stick < 2; stick++)
114 {
115 for(int axis = 0; axis < 2; axis++)
116 {
117 const uint8* aba = &d8[2] + stick * 8 + axis * 4;
118 int32 tmp;
119
120 //revert to 0.9.33, should be fixed on libretro side instead
121 //tmp = 32768 + MDFN_de16lsb(&aba[0]) - ((int32)MDFN_de16lsb(&aba[2]) * 32768 / 32767);
122
123 tmp = 32768 + MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 4) - ((int32)MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 8) * 32768 / 32767);
124 tmp >>= 8;
125
126 axes[stick][axis] = tmp;
127 }
128 }
129
130 //printf("%d %d %d %d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]);
131
132 }
133
134
135 void InputDevice_DualAnalog::SetDTR(bool new_dtr)
136 {
137 if(!dtr && new_dtr)
138 {
139 command_phase = 0;
140 bitpos = 0;
141 transmit_pos = 0;
142 transmit_count = 0;
143 }
144 else if(dtr && !new_dtr)
145 {
146 //if(bitpos || transmit_count)
147 // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
148 }
149
150 dtr = new_dtr;
151 }
152
153 bool InputDevice_DualAnalog::GetDSR(void)
154 {
155 if(!dtr)
156 return(0);
157
158 if(!bitpos && transmit_count)
159 return(1);
160
161 return(0);
162 }
163
164 bool InputDevice_DualAnalog::Clock(bool TxD, int32 &dsr_pulse_delay)
165 {
166 bool ret = 1;
167
168 dsr_pulse_delay = 0;
169
170 if(!dtr)
171 return(1);
172
173 if(transmit_count)
174 ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
175
176 receive_buffer &= ~(1 << bitpos);
177 receive_buffer |= TxD << bitpos;
178 bitpos = (bitpos + 1) & 0x7;
179
180 if(!bitpos)
181 {
182 //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
183
184 if(transmit_count)
185 {
186 transmit_pos++;
187 transmit_count--;
188 }
189
190
191 switch(command_phase)
192 {
193 case 0:
194 if(receive_buffer != 0x01)
195 command_phase = -1;
196 else
197 {
198 transmit_buffer[0] = joystick_mode ? 0x53 : 0x73;
199 transmit_pos = 0;
200 transmit_count = 1;
201 command_phase++;
202 }
203 break;
204
205 case 1:
206 command = receive_buffer;
207 command_phase++;
208
209 transmit_buffer[0] = 0x5A;
210
211 //if(command != 0x42)
212 // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
213
214 if(command == 0x42)
215 {
216 transmit_buffer[1] = 0xFF ^ buttons[0];
217 transmit_buffer[2] = 0xFF ^ buttons[1];
218 transmit_buffer[3] = axes[0][0];
219 transmit_buffer[4] = axes[0][1];
220 transmit_buffer[5] = axes[1][0];
221 transmit_buffer[6] = axes[1][1];
222 transmit_pos = 0;
223 transmit_count = 7;
224 }
225 else
226 {
227 command_phase = -1;
228 transmit_buffer[1] = 0;
229 transmit_buffer[2] = 0;
230 transmit_pos = 0;
231 transmit_count = 0;
232 }
233 break;
234 case 2:
235 //if(receive_buffer)
236 // printf("%d: %02x\n", 7 - transmit_count, receive_buffer);
237 break;
238 }
239 }
240
241 if(!bitpos && transmit_count)
242 dsr_pulse_delay = 0x40; //0x100;
243
244 return(ret);
245 }
246
247 InputDevice *Device_DualAnalog_Create(bool joystick_mode)
248 {
249 return new InputDevice_DualAnalog(joystick_mode);
250 }
251
252
253 InputDeviceInputInfoStruct Device_DualAnalog_IDII[24] =
254 {
255 { "select", "SELECT", 4, IDIT_BUTTON, NULL },
256 { "l3", "Left Stick, Button(L3)", 18, IDIT_BUTTON, NULL },
257 { "r3", "Right stick, Button(R3)", 23, IDIT_BUTTON, NULL },
258 { "start", "START", 5, IDIT_BUTTON, NULL },
259 { "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" },
260 { "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" },
261 { "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" },
262 { "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" },
263
264 { "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL },
265 { "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL },
266 { "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL },
267 { "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL },
268
269 { "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL },
270 { "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL },
271 { "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL },
272 { "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
273
274 { "rstick_right", "Right Stick RIGHT →", 22, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
275 { "rstick_left", "Right Stick LEFT ←", 21, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
276 { "rstick_down", "Right Stick DOWN ↓", 20, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
277 { "rstick_up", "Right Stick UP ↑", 19, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
278
279 { "lstick_right", "Left Stick RIGHT →", 17, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
280 { "lstick_left", "Left Stick LEFT ←", 16, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
281 { "lstick_down", "Left Stick DOWN ↓", 15, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
282 { "lstick_up", "Left Stick UP ↑", 14, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
283
284 };
285
286 // Not sure if all these buttons are named correctly!
287 InputDeviceInputInfoStruct Device_AnalogJoy_IDII[24] =
288 {
289 { "select", "SELECT", 8, IDIT_BUTTON, NULL },
290 { NULL, "empty", 0, IDIT_BUTTON },
291 { NULL, "empty", 0, IDIT_BUTTON },
292 { "start", "START", 9, IDIT_BUTTON, NULL },
293 { "up", "Thumbstick UP ↑", 14, IDIT_BUTTON, "down" },
294 { "right", "Thumbstick RIGHT →", 17, IDIT_BUTTON, "left" },
295 { "down", "Thumbstick DOWN ↓", 15, IDIT_BUTTON, "up" },
296 { "left", "Thumbstick LEFT ←", 16, IDIT_BUTTON, "right" },
297
298 { "l2", "Left stick, Trigger", 2, IDIT_BUTTON, NULL },
299 { "r2", "Left stick, Pinky", 3, IDIT_BUTTON, NULL },
300 { "l1", "Left stick, L-thumb", 0, IDIT_BUTTON, NULL },
301 { "r1", "Left stick, R-thumb", 1, IDIT_BUTTON, NULL },
302
303 { "triangle", "Right stick, Pinky", 13, IDIT_BUTTON, NULL },
304 { "circle", "Right stick, R-thumb", 11, IDIT_BUTTON, NULL },
305 { "cross", "Right stick, L-thumb", 10, IDIT_BUTTON, NULL },
306 { "square", "Right stick, Trigger", 12, IDIT_BUTTON, NULL },
307
308 { "rstick_right", "Right Stick, RIGHT →", 21, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
309 { "rstick_left", "Right Stick, LEFT ←", 20, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
310 { "rstick_down", "Right Stick, BACK ↓", 19, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
311 { "rstick_up", "Right Stick, FORE ↑", 18, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
312
313 { "lstick_right", "Left Stick, RIGHT →", 7, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
314 { "lstick_left", "Left Stick, LEFT ←", 6, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
315 { "lstick_down", "Left Stick, BACK ↓", 5, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
316 { "lstick_up", "Left Stick, FORE ↑", 4, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
317
318 };
0 #ifndef __MDFN_PSX_INPUT_DUALANALOG_H
1 #define __MDFN_PSX_INPUT_DUALANALOG_H
2
3 InputDevice *Device_DualAnalog_Create(bool joystick_mode);
4 extern InputDeviceInputInfoStruct Device_DualAnalog_IDII[24];
5 extern InputDeviceInputInfoStruct Device_AnalogJoy_IDII[24];
6
7 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../psx.h"
18 #include "../frontio.h"
19 #include "dualshock.h"
20
21 /*
22 TODO:
23 If we ever call Update() more than once per video frame(IE 50/60Hz), we'll need to add debounce logic to the analog mode button evaluation code.
24 */
25
26 /* Notes:
27
28 Both DA and DS style rumblings work in both analog and digital modes.
29
30 Regarding getting Dual Shock style rumble working, Sony is evil and/or mean. The owl tells me to burn Sony with boiling oil.
31
32 To enable Dual Shock-style rumble, the game has to at least enter MAD MUNCHKINS MODE with command 0x43, and send the appropriate data(not the actual rumble type data per-se)
33 with command 0x4D.
34
35 DualAnalog-style rumble support seems to be borked until power loss if MAD MUNCHKINS MODE is even entered once...investigate further.
36
37 Command 0x44 in MAD MUNCHKINS MODE can turn on/off analog mode(and the light with it).
38
39 Command 0x42 in MAD MUNCHKINS MODE will return the analog mode style gamepad data, even when analog mode is off. In combination with command 0x44, this could hypothetically
40 be used for using the light in the gamepad as some kind of game mechanic).
41
42 Dual Analog-style rumble notes(some of which may apply to DS too):
43 Rumble appears to stop if you hold DTR active(TODO: for how long? instant?). (TODO: investigate if it's still stopped even if a memory card device number is sent. It may be, since rumble may
44 cause excessive current draw in combination with memory card access)
45
46 Rumble will work even if you interrupt the communication process after you've sent the rumble data(via command 0x42).
47 Though if you interrupt it when you've only sent partial rumble data, dragons will eat you and I don't know(seems to have timing-dependent or random effects or something;
48 based on VERY ROUGH testing).
49 */
50
51 class InputDevice_DualShock : public InputDevice
52 {
53 public:
54
55 InputDevice_DualShock(const std::string &arg_name);
56 virtual ~InputDevice_DualShock();
57
58 virtual void Power(void);
59 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
60 virtual void Update(const int32_t timestamp);
61 virtual void ResetTS(void);
62 virtual void UpdateInput(const void *data);
63
64 virtual void SetAMCT(bool enabled);
65 //
66 //
67 //
68 virtual void SetDTR(bool new_dtr);
69 virtual bool GetDSR(void);
70 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
71
72 private:
73
74 void CheckManualAnaModeChange(void);
75
76 //
77 //
78 bool cur_ana_button_state;
79 bool prev_ana_button_state;
80 int64 combo_anatoggle_counter;
81 //
82
83 bool da_rumble_compat;
84
85 bool analog_mode;
86 bool analog_mode_locked;
87
88 bool mad_munchkins;
89 uint8 rumble_magic[6];
90
91 uint8 rumble_param[2];
92
93 bool dtr;
94
95 uint8 buttons[2];
96 uint8 axes[2][2];
97
98 int32 command_phase;
99 uint32 bitpos;
100 uint8 receive_buffer;
101
102 uint8 command;
103
104 uint8 transmit_buffer[8];
105 uint32 transmit_pos;
106 uint32 transmit_count;
107
108 //
109 //
110 //
111 bool am_prev_info;
112 bool aml_prev_info;
113 std::string gp_name;
114 int32_t lastts;
115
116 //
117 //
118 bool amct_enabled;
119 };
120
121 InputDevice_DualShock::InputDevice_DualShock(const std::string &name)
122 {
123 gp_name = name;
124 Power();
125 am_prev_info = analog_mode;
126 aml_prev_info = analog_mode_locked;
127 amct_enabled = false;
128 }
129
130 InputDevice_DualShock::~InputDevice_DualShock()
131 {
132
133 }
134
135 void InputDevice_DualShock::Update(const int32_t timestamp)
136 {
137 lastts = timestamp;
138 }
139
140 void InputDevice_DualShock::ResetTS(void)
141 {
142 //printf("%lld\n", combo_anatoggle_counter);
143 if(combo_anatoggle_counter >= 0)
144 combo_anatoggle_counter += lastts;
145 lastts = 0;
146 }
147
148 void InputDevice_DualShock::SetAMCT(bool enabled)
149 {
150 amct_enabled = enabled;
151 if(amct_enabled)
152 analog_mode = false;
153 else
154 analog_mode = true;
155
156 MDFN_DispMessage(_("%s: Analog toggle is %s, sticks are %s"), gp_name.c_str(), amct_enabled ? _("ENABLED") : _("DISABLED"), analog_mode ? _("ON") : _("OFF"));
157 }
158
159 //
160 // This simulates the behavior of the actual DualShock(analog toggle button evaluation is suspended while DTR is active).
161 // Call in Update(), and whenever dtr goes inactive in the port access code.
162 void InputDevice_DualShock::CheckManualAnaModeChange(void)
163 {
164 if(!dtr)
165 {
166 bool need_mode_toggle = false;
167
168 if(amct_enabled)
169 {
170 if(buttons[0] == 0x09 && buttons[1] == 0x0f)
171 {
172 if(combo_anatoggle_counter == -1)
173 combo_anatoggle_counter = 0;
174 else if(combo_anatoggle_counter >= (44100 * 768))
175 {
176 need_mode_toggle = true;
177 combo_anatoggle_counter = -2;
178 }
179 }
180 else
181 combo_anatoggle_counter = -1;
182 }
183 else
184 {
185 combo_anatoggle_counter = -1;
186 if(cur_ana_button_state && (cur_ana_button_state != prev_ana_button_state))
187 {
188 need_mode_toggle = true;
189 }
190 }
191
192 if(need_mode_toggle)
193 {
194 if(analog_mode_locked)
195 {
196 //MDFN_DispMessage(_("%s: Analog mode is %s."), gp_name.c_str(), analog_mode ? _("on") : _("off"));
197 MDFN_DispMessage(_("%s: 2 Analog toggle is DISABLED, sticks are %s"), gp_name.c_str(), analog_mode ? _("ON") : _("OFF"));
198 }
199 else
200 analog_mode = !analog_mode;
201 }
202
203 prev_ana_button_state = cur_ana_button_state; // Don't move this outside of the if(!dtr) block!
204 }
205 }
206
207 void InputDevice_DualShock::Power(void)
208 {
209 combo_anatoggle_counter = -2;
210 lastts = 0;
211 //
212 //
213
214 dtr = 0;
215
216 buttons[0] = buttons[1] = 0;
217
218 command_phase = 0;
219
220 bitpos = 0;
221
222 receive_buffer = 0;
223
224 command = 0;
225
226 memset(transmit_buffer, 0, sizeof(transmit_buffer));
227
228 transmit_pos = 0;
229 transmit_count = 0;
230
231 analog_mode_locked = false;
232
233 mad_munchkins = false;
234 memset(rumble_magic, 0xFF, sizeof(rumble_magic));
235 memset(rumble_param, 0, sizeof(rumble_param));
236
237 da_rumble_compat = true;
238
239 prev_ana_button_state = false;
240 }
241
242 int InputDevice_DualShock::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
243 {
244 SFORMAT StateRegs[] =
245 {
246 SFVAR(cur_ana_button_state),
247 SFVAR(prev_ana_button_state),
248 SFVAR(combo_anatoggle_counter),
249
250 SFVAR(da_rumble_compat),
251
252 SFVAR(analog_mode),
253 SFVAR(analog_mode_locked),
254
255 SFVAR(mad_munchkins),
256 SFARRAY(rumble_magic, sizeof(rumble_magic)),
257
258 SFARRAY(rumble_param, sizeof(rumble_param)),
259
260 SFVAR(dtr),
261
262 SFARRAY(buttons, sizeof(buttons)),
263 SFARRAY(&axes[0][0], sizeof(axes)),
264
265 SFVAR(command_phase),
266 SFVAR(bitpos),
267 SFVAR(receive_buffer),
268
269 SFVAR(command),
270
271 SFARRAY(transmit_buffer, sizeof(transmit_buffer)),
272 SFVAR(transmit_pos),
273 SFVAR(transmit_count),
274
275 SFEND
276 };
277 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
278
279 if(load)
280 {
281 if((transmit_pos + transmit_count) > sizeof(transmit_buffer))
282 {
283 transmit_pos = 0;
284 transmit_count = 0;
285 }
286 }
287
288 return(ret);
289 }
290
291 void InputDevice_DualShock::UpdateInput(const void *data)
292 {
293 uint8 *d8 = (uint8 *)data;
294 uint8* const rumb_dp = &d8[3 + 16];
295
296 buttons[0] = d8[0];
297 buttons[1] = d8[1];
298 cur_ana_button_state = d8[2] & 0x01;
299
300 for(int stick = 0; stick < 2; stick++)
301 {
302 for(int axis = 0; axis < 2; axis++)
303 {
304 const uint8* aba = &d8[3] + stick * 8 + axis * 4;
305 int32 tmp;
306
307 //revert to 0.9.33, should be fixed on libretro side instead
308 //tmp = 32767 + MDFN_de16lsb(&aba[0]) - MDFN_de16lsb(&aba[2]);
309 //tmp = (tmp * 0x100) / 0xFFFF;
310
311 tmp = 32768 + MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 4) - ((int32)MDFN_de32lsb((const uint8 *)data + stick * 16 + axis * 8 + 8) * 32768 / 32767);
312 tmp >>= 8;
313 axes[stick][axis] = tmp;
314 }
315 }
316
317 //printf("%3d:%3d, %3d:%3d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]);
318
319 //printf("RUMBLE: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", rumble_magic[0], rumble_magic[1], rumble_magic[2], rumble_magic[3], rumble_magic[4], rumble_magic[5]);
320 //printf("%d, 0x%02x 0x%02x\n", da_rumble_compat, rumble_param[0], rumble_param[1]);
321 if(da_rumble_compat == false)
322 {
323 uint8 sneaky_weaky = 0;
324
325 if(rumble_param[0] == 0x01)
326 sneaky_weaky = 0xFF;
327
328 //revert to 0.9.33, should be fixed on libretro side instead
329 //MDFN_en16lsb(rumb_dp, (sneaky_weaky << 0) | (rumble_param[1] << 8));
330
331 MDFN_en32lsb(&d8[4 + 32 + 0], (sneaky_weaky << 0) | (rumble_param[1] << 8));
332 }
333 else
334 {
335 uint8 sneaky_weaky = 0;
336
337 if(((rumble_param[0] & 0xC0) == 0x40) && ((rumble_param[1] & 0x01) == 0x01))
338 sneaky_weaky = 0xFF;
339
340 //revert to 0.9.33, should be fixed on libretro side instead
341 //MDFN_en16lsb(rumb_dp, sneaky_weaky << 0);
342 MDFN_en32lsb(&d8[4 + 32 + 0], sneaky_weaky << 0);
343 }
344
345 //printf("%d %d %d %d\n", axes[0][0], axes[0][1], axes[1][0], axes[1][1]);
346
347 //
348 //
349 //
350 CheckManualAnaModeChange();
351
352 if(am_prev_info != analog_mode || aml_prev_info != analog_mode_locked)
353 {
354 //MDFN_DispMessage(_("%s: Analog mode is %s(%s)."), gp_name.c_str(), analog_mode ? _("on") : _("off"), analog_mode_locked ? _("locked") : _("unlocked"));
355 MDFN_DispMessage(_("%s: Analog toggle is %s, sticks are %s"), gp_name.c_str(), amct_enabled ? _("ENABLED") : _("DISABLED"), analog_mode ? _("ON") : _("OFF"));
356 }
357 aml_prev_info = analog_mode_locked;
358 am_prev_info = analog_mode;
359 }
360
361
362 void InputDevice_DualShock::SetDTR(bool new_dtr)
363 {
364 const bool old_dtr = dtr;
365 dtr = new_dtr; // Set it to new state before we call CheckManualAnaModeChange().
366
367 if(!old_dtr && dtr)
368 {
369 command_phase = 0;
370 bitpos = 0;
371 transmit_pos = 0;
372 transmit_count = 0;
373 }
374 else if(old_dtr && !dtr)
375 {
376 CheckManualAnaModeChange();
377 //if(bitpos || transmit_count)
378 // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
379 }
380 }
381
382 bool InputDevice_DualShock::GetDSR(void)
383 {
384 if(!dtr)
385 return(0);
386
387 if(!bitpos && transmit_count)
388 return(1);
389
390 return(0);
391 }
392
393 bool InputDevice_DualShock::Clock(bool TxD, int32 &dsr_pulse_delay)
394 {
395 bool ret = 1;
396
397 dsr_pulse_delay = 0;
398
399 if(!dtr)
400 return(1);
401
402 if(transmit_count)
403 ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
404
405 receive_buffer &= ~(1 << bitpos);
406 receive_buffer |= TxD << bitpos;
407 bitpos = (bitpos + 1) & 0x7;
408
409 if(!bitpos)
410 {
411 //if(command == 0x44)
412 //if(command == 0x4D) //mad_munchkins) // || command == 0x43)
413 // fprintf(stderr, "[PAD] Receive: %02x -- command=%02x, command_phase=%d, transmit_pos=%d\n", receive_buffer, command, command_phase, transmit_pos);
414
415 if(transmit_count)
416 {
417 transmit_pos++;
418 transmit_count--;
419 }
420
421 switch(command_phase)
422 {
423 case 0:
424 if(receive_buffer != 0x01)
425 command_phase = -1;
426 else
427 {
428 if(mad_munchkins)
429 {
430 transmit_buffer[0] = 0xF3;
431 transmit_pos = 0;
432 transmit_count = 1;
433 command_phase = 101;
434 }
435 else
436 {
437 transmit_buffer[0] = analog_mode ? 0x73 : 0x41;
438 transmit_pos = 0;
439 transmit_count = 1;
440 command_phase++;
441 }
442 }
443 break;
444
445 case 1:
446 command = receive_buffer;
447 command_phase++;
448
449 transmit_buffer[0] = 0x5A;
450
451 //fprintf(stderr, "Gamepad command: 0x%02x\n", command);
452 //if(command != 0x42 && command != 0x43)
453 // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
454
455 if(command == 0x42)
456 {
457 transmit_buffer[0] = 0x5A;
458 transmit_pos = 0;
459 transmit_count = 1;
460 command_phase = (command << 8) | 0x00;
461 }
462 else if(command == 0x43)
463 {
464 transmit_pos = 0;
465 if(analog_mode)
466 {
467 transmit_buffer[1] = 0xFF ^ buttons[0];
468 transmit_buffer[2] = 0xFF ^ buttons[1];
469 transmit_buffer[3] = axes[0][0];
470 transmit_buffer[4] = axes[0][1];
471 transmit_buffer[5] = axes[1][0];
472 transmit_buffer[6] = axes[1][1];
473 transmit_count = 7;
474 }
475 else
476 {
477 transmit_buffer[1] = 0xFF ^ buttons[0];
478 transmit_buffer[2] = 0xFF ^ buttons[1];
479 transmit_count = 3;
480 }
481 }
482 else
483 {
484 command_phase = -1;
485 transmit_buffer[1] = 0;
486 transmit_buffer[2] = 0;
487 transmit_pos = 0;
488 transmit_count = 0;
489 }
490 break;
491
492 case 2:
493 {
494 if(command == 0x43 && transmit_pos == 2 && (receive_buffer == 0x01))
495 {
496 //fprintf(stderr, "Mad Munchkins mode entered!\n");
497 mad_munchkins = true;
498
499 if(da_rumble_compat)
500 {
501 rumble_param[0] = 0;
502 rumble_param[1] = 0;
503 da_rumble_compat = false;
504 }
505 command_phase = -1;
506 }
507 }
508 break;
509
510 case 101:
511 command = receive_buffer;
512
513 //fprintf(stderr, "Mad Munchkins DualShock command: 0x%02x\n", command);
514
515 if(command >= 0x40 && command <= 0x4F)
516 {
517 transmit_buffer[0] = 0x5A;
518 transmit_pos = 0;
519 transmit_count = 1;
520 command_phase = (command << 8) | 0x00;
521 }
522 else
523 {
524 transmit_count = 0;
525 command_phase = -1;
526 }
527 break;
528
529 /************************/
530 /* MMMode 1, Command 0x40 */
531 /************************/
532 case 0x4000:
533 if(receive_buffer == 0x00)
534 {
535 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
536 command_phase++;
537 }
538 else
539 command_phase = -1;
540 break;
541
542 case 0x4001:
543 transmit_buffer[0] = 0x00;
544 transmit_buffer[1] = 0x00;
545 transmit_buffer[2] = 0x00;
546 transmit_buffer[3] = 0x00;
547 transmit_buffer[4] = 0x00;
548 transmit_pos = 0;
549 transmit_count = 5;
550 command_phase = -1;
551 break;
552
553
554 /************************/
555 /* MMMode 1, Command 0x41 */
556 /************************/
557 case 0x4100:
558 if(receive_buffer == 0x00)
559 {
560 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
561 command_phase++;
562 }
563 else
564 command_phase = -1;
565 break;
566
567 case 0x4101:
568 transmit_buffer[0] = 0x00;
569 transmit_buffer[1] = 0x00;
570 transmit_buffer[2] = 0x00;
571 transmit_buffer[3] = 0x00;
572 transmit_buffer[4] = 0x00;
573 transmit_pos = 0;
574 transmit_count = 5;
575 command_phase = -1;
576 break;
577
578 /**************************/
579 /* MMMode 0&1, Command 0x42 */
580 /**************************/
581 case 0x4200:
582 transmit_pos = 0;
583 if(analog_mode || mad_munchkins)
584 {
585 transmit_buffer[0] = 0xFF ^ buttons[0];
586 transmit_buffer[1] = 0xFF ^ buttons[1];
587 transmit_buffer[2] = axes[0][0];
588 transmit_buffer[3] = axes[0][1];
589 transmit_buffer[4] = axes[1][0];
590 transmit_buffer[5] = axes[1][1];
591 transmit_count = 6;
592 }
593 else
594 {
595 transmit_buffer[0] = 0xFF ^ buttons[0];
596 transmit_buffer[1] = 0xFF ^ buttons[1];
597 transmit_count = 2;
598
599 if(!(rumble_magic[2] & 0xFE))
600 {
601 transmit_buffer[transmit_count++] = 0x00;
602 transmit_buffer[transmit_count++] = 0x00;
603 }
604 }
605 command_phase++;
606 break;
607
608 case 0x4201: // Weak(in DS mode)
609 if(da_rumble_compat)
610 rumble_param[0] = receive_buffer;
611 // Dualshock weak
612 else if(rumble_magic[0] == 0x00 && rumble_magic[2] != 0x00 && rumble_magic[3] != 0x00 && rumble_magic[4] != 0x00 && rumble_magic[5] != 0x00)
613 rumble_param[0] = receive_buffer;
614 command_phase++;
615 break;
616
617 case 0x4202:
618 if(da_rumble_compat)
619 rumble_param[1] = receive_buffer;
620 else if(rumble_magic[1] == 0x01) // DualShock strong
621 rumble_param[1] = receive_buffer;
622 else if(rumble_magic[1] == 0x00 && rumble_magic[2] != 0x00 && rumble_magic[3] != 0x00 && rumble_magic[4] != 0x00 && rumble_magic[5] != 0x00) // DualShock weak
623 rumble_param[0] = receive_buffer;
624
625 command_phase++;
626 break;
627
628 case 0x4203:
629 if(da_rumble_compat)
630 {
631
632 }
633 else if(rumble_magic[1] == 0x00 && rumble_magic[2] == 0x01)
634 rumble_param[1] = receive_buffer; // DualShock strong.
635 command_phase++; // Nowhere here we come!
636 break;
637
638 /************************/
639 /* MMMode 1, Command 0x43 */
640 /************************/
641 case 0x4300:
642 if(receive_buffer == 0x00)
643 {
644 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
645 command_phase++;
646 }
647 else
648 command_phase = -1;
649 break;
650
651 case 0x4301:
652 if(receive_buffer == 0x00)
653 {
654 //fprintf(stderr, "Mad Munchkins mode left!\n");
655 mad_munchkins = false;
656 }
657 transmit_buffer[0] = 0x00;
658 transmit_buffer[1] = 0x00;
659 transmit_buffer[2] = 0x00;
660 transmit_buffer[3] = 0x00;
661 transmit_buffer[4] = 0x00;
662 transmit_pos = 0;
663 transmit_count = 5;
664 command_phase = -1;
665 break;
666
667 /************************/
668 /* MMMode 1, Command 0x44 */
669 /************************/
670 case 0x4400:
671 if(receive_buffer == 0x00)
672 {
673 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
674 command_phase++;
675 }
676 else
677 command_phase = -1;
678 break;
679
680 case 0x4401:
681 transmit_buffer[0] = 0x00;
682 transmit_buffer[1] = 0x00;
683 transmit_buffer[2] = 0x00;
684 transmit_buffer[3] = 0x00;
685 transmit_buffer[4] = 0x00;
686 transmit_pos = 0;
687 transmit_count = 5;
688 command_phase++;
689
690 // Ignores locking state.
691 switch(receive_buffer)
692 {
693 case 0x00:
694 analog_mode = false;
695 //fprintf(stderr, "Analog mode disabled\n");
696 break;
697
698 case 0x01:
699 analog_mode = true;
700 //fprintf(stderr, "Analog mode enabled\n");
701 break;
702 }
703 break;
704
705 case 0x4402:
706 switch(receive_buffer)
707 {
708 case 0x02:
709 analog_mode_locked = false;
710 break;
711
712 case 0x03:
713 analog_mode_locked = true;
714 break;
715 }
716 command_phase = -1;
717 break;
718
719 /************************/
720 /* MMMode 1, Command 0x45 */
721 /************************/
722 case 0x4500:
723 if(receive_buffer == 0x00)
724 {
725 transmit_buffer[0] = 0x01; /**/ transmit_pos = 0; transmit_count = 1; /**/
726 command_phase++;
727 }
728 else
729 command_phase = -1;
730 break;
731
732 case 0x4501:
733 transmit_buffer[0] = 0x02;
734 transmit_buffer[1] = analog_mode ? 0x01 : 0x00;
735 transmit_buffer[2] = 0x02;
736 transmit_buffer[3] = 0x01;
737 transmit_buffer[4] = 0x00;
738 transmit_pos = 0;
739 transmit_count = 5;
740 command_phase = -1;
741 break;
742
743
744 /************************/
745 /* MMMode 1, Command 0x46 */
746 /************************/
747 case 0x4600:
748 if(receive_buffer == 0x00)
749 {
750 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
751 command_phase++;
752 }
753 else
754 command_phase = -1;
755 break;
756
757 case 0x4601:
758 if(receive_buffer == 0x00)
759 {
760 transmit_buffer[0] = 0x00;
761 transmit_buffer[1] = 0x01;
762 transmit_buffer[2] = 0x02;
763 transmit_buffer[3] = 0x00;
764 transmit_buffer[4] = 0x0A;
765 }
766 else if(receive_buffer == 0x01)
767 {
768 transmit_buffer[0] = 0x00;
769 transmit_buffer[1] = 0x01;
770 transmit_buffer[2] = 0x01;
771 transmit_buffer[3] = 0x01;
772 transmit_buffer[4] = 0x14;
773 }
774 else
775 {
776 transmit_buffer[0] = 0x00;
777 transmit_buffer[1] = 0x00;
778 transmit_buffer[2] = 0x00;
779 transmit_buffer[3] = 0x00;
780 transmit_buffer[4] = 0x00;
781 }
782 transmit_pos = 0;
783 transmit_count = 5;
784 command_phase = -1;
785 break;
786
787 /************************/
788 /* MMMode 1, Command 0x47 */
789 /************************/
790 case 0x4700:
791 if(receive_buffer == 0x00)
792 {
793 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
794 command_phase++;
795 }
796 else
797 command_phase = -1;
798 break;
799
800 case 0x4701:
801 if(receive_buffer == 0x00)
802 {
803 transmit_buffer[0] = 0x00;
804 transmit_buffer[1] = 0x02;
805 transmit_buffer[2] = 0x00;
806 transmit_buffer[3] = 0x01;
807 transmit_buffer[4] = 0x00;
808 }
809 else
810 {
811 transmit_buffer[0] = 0x00;
812 transmit_buffer[1] = 0x00;
813 transmit_buffer[2] = 0x00;
814 transmit_buffer[3] = 0x00;
815 transmit_buffer[4] = 0x00;
816 }
817 transmit_pos = 0;
818 transmit_count = 5;
819 command_phase = -1;
820 break;
821
822 /************************/
823 /* MMMode 1, Command 0x48 */
824 /************************/
825 case 0x4800:
826 if(receive_buffer == 0x00)
827 {
828 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
829 command_phase++;
830 }
831 else
832 command_phase = -1;
833 break;
834
835 case 0x4801:
836 if(receive_buffer == 0x00)
837 {
838 transmit_buffer[0] = 0x00;
839 transmit_buffer[1] = 0x00;
840 transmit_buffer[2] = 0x00;
841 transmit_buffer[3] = 0x01;
842 transmit_buffer[4] = rumble_param[0];
843 }
844 else if(receive_buffer == 0x01)
845 {
846 transmit_buffer[0] = 0x00;
847 transmit_buffer[1] = 0x00;
848 transmit_buffer[2] = 0x00;
849 transmit_buffer[3] = 0x01;
850 transmit_buffer[4] = rumble_param[1];
851 }
852 else
853 {
854 transmit_buffer[0] = 0x00;
855 transmit_buffer[1] = 0x00;
856 transmit_buffer[2] = 0x00;
857 transmit_buffer[3] = 0x00;
858 transmit_buffer[4] = 0x00;
859 }
860 transmit_pos = 0;
861 transmit_count = 5;
862 command_phase = -1;
863 break;
864
865 /************************/
866 /* MMMode 1, Command 0x49 */
867 /************************/
868 case 0x4900:
869 if(receive_buffer == 0x00)
870 {
871 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
872 command_phase++;
873 }
874 else
875 command_phase = -1;
876 break;
877
878 case 0x4901:
879 transmit_buffer[0] = 0x00;
880 transmit_buffer[1] = 0x00;
881 transmit_buffer[2] = 0x00;
882 transmit_buffer[3] = 0x00;
883 transmit_buffer[4] = 0x00;
884 transmit_pos = 0;
885 transmit_count = 5;
886 command_phase = -1;
887 break;
888
889 /************************/
890 /* MMMode 1, Command 0x4A */
891 /************************/
892 case 0x4A00:
893 if(receive_buffer == 0x00)
894 {
895 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
896 command_phase++;
897 }
898 else
899 command_phase = -1;
900 break;
901
902 case 0x4A01:
903 transmit_buffer[0] = 0x00;
904 transmit_buffer[1] = 0x00;
905 transmit_buffer[2] = 0x00;
906 transmit_buffer[3] = 0x00;
907 transmit_buffer[4] = 0x00;
908 transmit_pos = 0;
909 transmit_count = 5;
910 command_phase = -1;
911 break;
912
913 /************************/
914 /* MMMode 1, Command 0x4B */
915 /************************/
916 case 0x4B00:
917 if(receive_buffer == 0x00)
918 {
919 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
920 command_phase++;
921 }
922 else
923 command_phase = -1;
924 break;
925
926 case 0x4B01:
927 transmit_buffer[0] = 0x00;
928 transmit_buffer[1] = 0x00;
929 transmit_buffer[2] = 0x00;
930 transmit_buffer[3] = 0x00;
931 transmit_buffer[4] = 0x00;
932 transmit_pos = 0;
933 transmit_count = 5;
934 command_phase = -1;
935 break;
936
937 /************************/
938 /* MMMode 1, Command 0x4C */
939 /************************/
940 case 0x4C00:
941 if(receive_buffer == 0x00)
942 {
943 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
944 command_phase++;
945 }
946 else
947 command_phase = -1;
948 break;
949
950 case 0x4C01:
951 if(receive_buffer == 0x00)
952 {
953 transmit_buffer[0] = 0x00;
954 transmit_buffer[1] = 0x00;
955 transmit_buffer[2] = 0x04;
956 transmit_buffer[3] = 0x00;
957 transmit_buffer[4] = 0x00;
958 }
959 else if(receive_buffer == 0x01)
960 {
961 transmit_buffer[0] = 0x00;
962 transmit_buffer[1] = 0x00;
963 transmit_buffer[2] = 0x07;
964 transmit_buffer[3] = 0x00;
965 transmit_buffer[4] = 0x00;
966 }
967 else
968 {
969 transmit_buffer[0] = 0x00;
970 transmit_buffer[1] = 0x00;
971 transmit_buffer[2] = 0x00;
972 transmit_buffer[3] = 0x00;
973 transmit_buffer[4] = 0x00;
974 }
975
976 transmit_pos = 0;
977 transmit_count = 5;
978 command_phase = -1;
979 break;
980
981 /************************/
982 /* MMMode 1, Command 0x4D */
983 /************************/
984 case 0x4D00:
985 if(receive_buffer == 0x00)
986 {
987 transmit_buffer[0] = rumble_magic[0]; /**/ transmit_pos = 0; transmit_count = 1; /**/
988 command_phase++;
989 }
990 else
991 command_phase = -1;
992 break;
993
994 case 0x4D01:
995 case 0x4D02:
996 case 0x4D03:
997 case 0x4D04:
998 case 0x4D05:
999 case 0x4D06:
1000 {
1001 unsigned index = command_phase - 0x4D01;
1002
1003 if(index < 5)
1004 {
1005 transmit_buffer[0] = rumble_magic[1 + index];
1006 transmit_pos = 0;
1007 transmit_count = 1;
1008 command_phase++;
1009 }
1010 else
1011 command_phase = -1;
1012
1013 rumble_magic[index] = receive_buffer;
1014 }
1015 break;
1016
1017 /************************/
1018 /* MMMode 1, Command 0x4E */
1019 /************************/
1020 case 0x4E00:
1021 if(receive_buffer == 0x00)
1022 {
1023 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
1024 command_phase++;
1025 }
1026 else
1027 command_phase = -1;
1028 break;
1029
1030 case 0x4E01:
1031 transmit_buffer[0] = 0x00;
1032 transmit_buffer[1] = 0x00;
1033 transmit_buffer[2] = 0x00;
1034 transmit_buffer[3] = 0x00;
1035 transmit_buffer[4] = 0x00;
1036 transmit_pos = 0;
1037 transmit_count = 5;
1038 command_phase = -1;
1039 break;
1040
1041
1042 /************************/
1043 /* MMMode 1, Command 0x4F */
1044 /************************/
1045 case 0x4F00:
1046 if(receive_buffer == 0x00)
1047 {
1048 transmit_buffer[0] = 0; /**/ transmit_pos = 0; transmit_count = 1; /**/
1049 command_phase++;
1050 }
1051 else
1052 command_phase = -1;
1053 break;
1054
1055 case 0x4F01:
1056 transmit_buffer[0] = 0x00;
1057 transmit_buffer[1] = 0x00;
1058 transmit_buffer[2] = 0x00;
1059 transmit_buffer[3] = 0x00;
1060 transmit_buffer[4] = 0x00;
1061 transmit_pos = 0;
1062 transmit_count = 5;
1063 command_phase = -1;
1064 break;
1065 }
1066 }
1067
1068 if(!bitpos && transmit_count)
1069 dsr_pulse_delay = 0x40; //0x100;
1070
1071 return(ret);
1072 }
1073
1074 InputDevice *Device_DualShock_Create(const std::string &name)
1075 {
1076 return new InputDevice_DualShock(name);
1077 }
1078
1079
1080 InputDeviceInputInfoStruct Device_DualShock_IDII[26] =
1081 {
1082 { "select", "SELECT", 4, IDIT_BUTTON, NULL },
1083 { "l3", "Left Stick, Button(L3)", 18, IDIT_BUTTON, NULL },
1084 { "r3", "Right stick, Button(R3)", 23, IDIT_BUTTON, NULL },
1085 { "start", "START", 5, IDIT_BUTTON, NULL },
1086 { "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" },
1087 { "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" },
1088 { "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" },
1089 { "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" },
1090
1091 { "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL },
1092 { "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL },
1093 { "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL },
1094 { "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL },
1095
1096 { "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL },
1097 { "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL },
1098 { "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL },
1099 { "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
1100
1101 { "analog", "Analog(mode toggle)", 24, IDIT_BUTTON, NULL },
1102
1103 { "rstick_right", "Right Stick RIGHT →", 22, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1104 { "rstick_left", "Right Stick LEFT ←", 21, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1105 { "rstick_down", "Right Stick DOWN ↓", 20, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1106 { "rstick_up", "Right Stick UP ↑", 19, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1107
1108 { "lstick_right", "Left Stick RIGHT →", 17, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1109 { "lstick_left", "Left Stick LEFT ←", 16, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1110 { "lstick_down", "Left Stick DOWN ↓", 15, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1111 { "lstick_up", "Left Stick UP ↑", 14, IDIT_BUTTON_ANALOG, NULL, { NULL, NULL, NULL }, IDIT_BUTTON_ANALOG_FLAG_SQLR },
1112
1113 { "rumble", "RUMBLE MONSTER RUMBA", 100, IDIT_RUMBLE },
1114 };
0 #ifndef __MDFN_PSX_INPUT_DUALSHOCK_H
1 #define __MDFN_PSX_INPUT_DUALSHOCK_H
2
3 #include <string>
4
5 InputDevice *Device_DualShock_Create(const std::string &name);
6 extern InputDeviceInputInfoStruct Device_DualShock_IDII[26];
7
8 #endif
0 #include "../psx.h"
1 #include "../frontio.h"
2 #include "gamepad.h"
3
4 class InputDevice_Gamepad : public InputDevice
5 {
6 public:
7
8 InputDevice_Gamepad();
9 virtual ~InputDevice_Gamepad();
10
11 virtual void Power(void);
12 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
13 virtual void UpdateInput(const void *data);
14
15 //
16 //
17 //
18 virtual void SetDTR(bool new_dtr);
19 virtual bool GetDSR(void);
20 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
21
22 private:
23
24 bool dtr;
25
26 uint8 buttons[2];
27
28 int32 command_phase;
29 uint32 bitpos;
30 uint8 receive_buffer;
31
32 uint8 command;
33
34 uint8 transmit_buffer[3];
35 uint32 transmit_pos;
36 uint32 transmit_count;
37 };
38
39 InputDevice_Gamepad::InputDevice_Gamepad()
40 {
41 Power();
42 }
43
44 InputDevice_Gamepad::~InputDevice_Gamepad()
45 {
46
47 }
48
49 void InputDevice_Gamepad::Power(void)
50 {
51 dtr = 0;
52
53 buttons[0] = buttons[1] = 0;
54
55 command_phase = 0;
56
57 bitpos = 0;
58
59 receive_buffer = 0;
60
61 command = 0;
62
63 memset(transmit_buffer, 0, sizeof(transmit_buffer));
64
65 transmit_pos = 0;
66 transmit_count = 0;
67 }
68
69 int InputDevice_Gamepad::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
70 {
71 SFORMAT StateRegs[] =
72 {
73 SFVAR(dtr),
74
75 SFARRAY(buttons, sizeof(buttons)),
76
77 SFVAR(command_phase),
78 SFVAR(bitpos),
79 SFVAR(receive_buffer),
80
81 SFVAR(command),
82
83 SFARRAY(transmit_buffer, sizeof(transmit_buffer)),
84 SFVAR(transmit_pos),
85 SFVAR(transmit_count),
86
87 SFEND
88 };
89 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
90
91 if(load)
92 {
93 if((transmit_pos + transmit_count) > sizeof(transmit_buffer))
94 {
95 transmit_pos = 0;
96 transmit_count = 0;
97 }
98 }
99
100 return(ret);
101 }
102
103
104 void InputDevice_Gamepad::UpdateInput(const void *data)
105 {
106 uint8 *d8 = (uint8 *)data;
107
108 buttons[0] = d8[0];
109 buttons[1] = d8[1];
110 }
111
112
113 void InputDevice_Gamepad::SetDTR(bool new_dtr)
114 {
115 if(!dtr && new_dtr)
116 {
117 command_phase = 0;
118 bitpos = 0;
119 transmit_pos = 0;
120 transmit_count = 0;
121 }
122 else if(dtr && !new_dtr)
123 {
124 //if(bitpos || transmit_count)
125 // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
126 }
127
128 dtr = new_dtr;
129 }
130
131 bool InputDevice_Gamepad::GetDSR(void)
132 {
133 if(!dtr)
134 return(0);
135
136 if(!bitpos && transmit_count)
137 return(1);
138
139 return(0);
140 }
141
142 bool InputDevice_Gamepad::Clock(bool TxD, int32 &dsr_pulse_delay)
143 {
144 bool ret = 1;
145
146 dsr_pulse_delay = 0;
147
148 if(!dtr)
149 return(1);
150
151 if(transmit_count)
152 ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
153
154 receive_buffer &= ~(1 << bitpos);
155 receive_buffer |= TxD << bitpos;
156 bitpos = (bitpos + 1) & 0x7;
157
158 if(!bitpos)
159 {
160 //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
161
162 if(transmit_count)
163 {
164 transmit_pos++;
165 transmit_count--;
166 }
167
168
169 switch(command_phase)
170 {
171 case 0:
172 if(receive_buffer != 0x01)
173 command_phase = -1;
174 else
175 {
176 transmit_buffer[0] = 0x41;
177 transmit_pos = 0;
178 transmit_count = 1;
179 command_phase++;
180 }
181 break;
182
183 case 1:
184 command = receive_buffer;
185 command_phase++;
186
187 transmit_buffer[0] = 0x5A;
188
189 //if(command != 0x42)
190 // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
191 //assert(command == 0x42);
192 if(command == 0x42)
193 {
194 //printf("PAD COmmand 0x42, sl=%u\n", GPU->GetScanlineNum());
195
196 transmit_buffer[1] = 0xFF ^ buttons[0];
197 transmit_buffer[2] = 0xFF ^ buttons[1];
198 transmit_pos = 0;
199 transmit_count = 3;
200 }
201 else
202 {
203 command_phase = -1;
204 transmit_buffer[1] = 0;
205 transmit_buffer[2] = 0;
206 transmit_pos = 0;
207 transmit_count = 0;
208 }
209 break;
210
211 }
212 }
213
214 if(!bitpos && transmit_count)
215 dsr_pulse_delay = 0x40; //0x100;
216
217 return(ret);
218 }
219
220 InputDevice *Device_Gamepad_Create(void)
221 {
222 return new InputDevice_Gamepad();
223 }
224
225
226 InputDeviceInputInfoStruct Device_Gamepad_IDII[16] =
227 {
228 { "select", "SELECT", 4, IDIT_BUTTON, NULL },
229 { NULL, "empty", 0, IDIT_BUTTON },
230 { NULL, "empty", 0, IDIT_BUTTON },
231 { "start", "START", 5, IDIT_BUTTON, NULL },
232 { "up", "UP ↑", 0, IDIT_BUTTON, "down" },
233 { "right", "RIGHT →", 3, IDIT_BUTTON, "left" },
234 { "down", "DOWN ↓", 1, IDIT_BUTTON, "up" },
235 { "left", "LEFT ←", 2, IDIT_BUTTON, "right" },
236
237 { "l2", "L2 (rear left shoulder)", 11, IDIT_BUTTON, NULL },
238 { "r2", "R2 (rear right shoulder)", 13, IDIT_BUTTON, NULL },
239 { "l1", "L1 (front left shoulder)", 10, IDIT_BUTTON, NULL },
240 { "r1", "R1 (front right shoulder)", 12, IDIT_BUTTON, NULL },
241
242 { "triangle", "△ (upper)", 6, IDIT_BUTTON_CAN_RAPID, NULL },
243 { "circle", "○ (right)", 9, IDIT_BUTTON_CAN_RAPID, NULL },
244 { "cross", "x (lower)", 7, IDIT_BUTTON_CAN_RAPID, NULL },
245 { "square", "□ (left)", 8, IDIT_BUTTON_CAN_RAPID, NULL },
246 };
247
248 InputDeviceInputInfoStruct Device_Dancepad_IDII[16] =
249 {
250 { "select", "SELECT", 0, IDIT_BUTTON, NULL },
251 { NULL, "empty", 0, IDIT_BUTTON },
252 { NULL, "empty", 0, IDIT_BUTTON },
253 { "start", "START", 1, IDIT_BUTTON, NULL },
254
255 { "up", "UP ↑", 3, IDIT_BUTTON, NULL },
256 { "right", "RIGHT →", 6, IDIT_BUTTON, NULL },
257 { "down", "DOWN ↓", 8, IDIT_BUTTON, NULL },
258 { "left", "LEFT ←", 5, IDIT_BUTTON, NULL },
259
260 { NULL, "empty", 0, IDIT_BUTTON, NULL },
261 { NULL, "empty", 0, IDIT_BUTTON, NULL },
262 { NULL, "empty", 0, IDIT_BUTTON, NULL },
263 { NULL, "empty", 0, IDIT_BUTTON, NULL },
264
265 { "triangle", "△ (lower left)", 7, IDIT_BUTTON, NULL },
266 { "circle", "○ (upper right)", 4, IDIT_BUTTON, NULL },
267 { "cross", "x (upper left)", 2, IDIT_BUTTON, NULL },
268 { "square", "□ (lower right)", 9, IDIT_BUTTON, NULL },
269 };
0 #ifndef __MDFN_PSX_INPUT_GAMEPAD_H
1 #define __MDFN_PSX_INPUT_GAMEPAD_H
2
3 InputDevice *Device_Gamepad_Create(void);
4 extern InputDeviceInputInfoStruct Device_Gamepad_IDII[16];
5 extern InputDeviceInputInfoStruct Device_Dancepad_IDII[16];
6
7 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../psx.h"
18 #include "../frontio.h"
19 #include "guncon.h"
20
21 class InputDevice_GunCon : public InputDevice
22 {
23 public:
24
25 InputDevice_GunCon(void);
26 virtual ~InputDevice_GunCon();
27
28 virtual void Power(void);
29 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
30 virtual void UpdateInput(const void *data);
31 virtual bool RequireNoFrameskip(void);
32 virtual int32_t GPULineHook(const int32_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider);
33
34 //
35 //
36 //
37 virtual void SetDTR(bool new_dtr);
38 virtual bool GetDSR(void);
39 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
40
41 private:
42
43 bool dtr;
44
45 uint8 buttons;
46 bool trigger_eff;
47 bool trigger_noclear;
48 uint16 hit_x, hit_y;
49
50 int16 nom_x, nom_y;
51 int32 os_shot_counter;
52 bool prev_oss;
53
54 int32 command_phase;
55 uint32 bitpos;
56 uint8 receive_buffer;
57
58 uint8 command;
59
60 uint8 transmit_buffer[16];
61 uint32 transmit_pos;
62 uint32 transmit_count;
63
64 //
65 // Video timing stuff
66 bool prev_vsync;
67 int line_counter;
68 };
69
70 InputDevice_GunCon::InputDevice_GunCon(void)
71 {
72 Power();
73 }
74
75 InputDevice_GunCon::~InputDevice_GunCon()
76 {
77
78 }
79
80 void InputDevice_GunCon::Power(void)
81 {
82 dtr = 0;
83
84 buttons = 0;
85 trigger_eff = 0;
86 trigger_noclear = 0;
87 hit_x = 0;
88 hit_y = 0;
89
90 nom_x = 0;
91 nom_y = 0;
92
93 os_shot_counter = 0;
94 prev_oss = 0;
95
96 command_phase = 0;
97
98 bitpos = 0;
99
100 receive_buffer = 0;
101
102 command = 0;
103
104 memset(transmit_buffer, 0, sizeof(transmit_buffer));
105
106 transmit_pos = 0;
107 transmit_count = 0;
108
109 prev_vsync = 0;
110 line_counter = 0;
111 }
112
113 int InputDevice_GunCon::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
114 {
115 SFORMAT StateRegs[] =
116 {
117 SFVAR(dtr),
118
119 SFVAR(buttons),
120 SFVAR(trigger_eff),
121 SFVAR(trigger_noclear),
122 SFVAR(hit_x),
123 SFVAR(hit_y),
124
125 SFVAR(nom_x),
126 SFVAR(nom_y),
127 SFVAR(os_shot_counter),
128 SFVAR(prev_oss),
129
130 SFVAR(command_phase),
131 SFVAR(bitpos),
132 SFVAR(receive_buffer),
133
134 SFVAR(command),
135
136 SFARRAY(transmit_buffer, sizeof(transmit_buffer)),
137 SFVAR(transmit_pos),
138 SFVAR(transmit_count),
139
140 SFVAR(prev_vsync),
141 SFVAR(line_counter),
142
143 SFEND
144 };
145 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
146
147 if(load)
148 {
149 if((transmit_pos + transmit_count) > sizeof(transmit_buffer))
150 {
151 transmit_pos = 0;
152 transmit_count = 0;
153 }
154 }
155
156 return(ret);
157 }
158
159 void InputDevice_GunCon::UpdateInput(const void *data)
160 {
161 uint8 *d8 = (uint8 *)data;
162
163 nom_x = (int16)MDFN_de16lsb(&d8[0]);
164 nom_y = (int16)MDFN_de16lsb(&d8[2]);
165
166 trigger_noclear = (bool)(d8[4] & 0x1);
167 trigger_eff |= trigger_noclear;
168
169 buttons = d8[4] >> 1;
170
171 if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz).
172 os_shot_counter--;
173
174 if((d8[4] & 0x8) && !prev_oss && os_shot_counter == 0)
175 os_shot_counter = 4;
176 prev_oss = d8[4] & 0x8;
177
178 //MDFN_DispMessage("%08x %08x", nom_x, nom_y);
179 }
180
181 bool InputDevice_GunCon::RequireNoFrameskip(void)
182 {
183 return(true);
184 }
185
186 int32_t InputDevice_GunCon::GPULineHook(const int32_t line_timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width,
187 const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider)
188 {
189 if(vsync && !prev_vsync)
190 line_counter = 0;
191
192 if(pixels && pix_clock)
193 {
194 const int avs = 16; // Not 16 for PAL, fixme.
195 int32 gx;
196 int32 gy;
197
198 gx = (nom_x * 2 + pix_clock_divider) / (pix_clock_divider * 2);
199 gy = nom_y;
200
201 for(int32 ix = gx; ix < (gx + (int32)(pix_clock / 762925)); ix++)
202 {
203 if(ix >= 0 && ix < (int)width && line_counter >= (avs + gy) && line_counter < (avs + gy + 8))
204 {
205 int r, g, b, a;
206
207 format->DecodeColor(pixels[ix], r, g, b, a);
208
209 if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;)
210 {
211 hit_x = (int64)(ix + pix_clock_offset) * 8000000 / pix_clock; // GunCon has what appears to be an 8.00MHz ceramic resonator in it.
212 hit_y = line_counter;
213 }
214 }
215 }
216
217 chair_x = gx;
218 chair_y = (avs + gy) - line_counter;
219 }
220
221 line_counter++;
222
223 return(PSX_EVENT_MAXTS);
224 }
225
226 void InputDevice_GunCon::SetDTR(bool new_dtr)
227 {
228 if(!dtr && new_dtr)
229 {
230 command_phase = 0;
231 bitpos = 0;
232 transmit_pos = 0;
233 transmit_count = 0;
234 }
235 else if(dtr && !new_dtr)
236 {
237 //if(bitpos || transmit_count)
238 // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
239 }
240
241 dtr = new_dtr;
242 }
243
244 bool InputDevice_GunCon::GetDSR(void)
245 {
246 if(!dtr)
247 return(0);
248
249 if(!bitpos && transmit_count)
250 return(1);
251
252 return(0);
253 }
254
255 bool InputDevice_GunCon::Clock(bool TxD, int32 &dsr_pulse_delay)
256 {
257 bool ret = 1;
258
259 dsr_pulse_delay = 0;
260
261 if(!dtr)
262 return(1);
263
264 if(transmit_count)
265 ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
266
267 receive_buffer &= ~(1 << bitpos);
268 receive_buffer |= TxD << bitpos;
269 bitpos = (bitpos + 1) & 0x7;
270
271 if(!bitpos)
272 {
273 //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
274
275 if(transmit_count)
276 {
277 transmit_pos++;
278 transmit_count--;
279 }
280
281
282 switch(command_phase)
283 {
284 case 0:
285 if(receive_buffer != 0x01)
286 command_phase = -1;
287 else
288 {
289 transmit_buffer[0] = 0x63;
290 transmit_pos = 0;
291 transmit_count = 1;
292 command_phase++;
293 }
294 break;
295
296 case 2:
297 //if(receive_buffer)
298 // printf("%02x\n", receive_buffer);
299 break;
300
301 case 1:
302 command = receive_buffer;
303 command_phase++;
304
305 transmit_buffer[0] = 0x5A;
306
307 //puts("MOO");
308 //if(command != 0x42)
309 // fprintf(stderr, "GunCon unhandled command: 0x%02x\n", command);
310 //assert(command == 0x42);
311 if(command == 0x42)
312 {
313 transmit_buffer[1] = 0xFF ^ ((buttons & 0x01) << 3);
314 transmit_buffer[2] = 0xFF ^ (trigger_eff << 5) ^ ((buttons & 0x02) << 5);
315
316 if(os_shot_counter > 0)
317 {
318 hit_x = 0x01;
319 hit_y = 0x0A;
320 transmit_buffer[2] |= (1 << 5);
321 if(os_shot_counter == 2 || os_shot_counter == 3)
322 {
323 transmit_buffer[2] &= ~(1 << 5);
324 }
325 }
326
327 MDFN_en16lsb(&transmit_buffer[3], hit_x);
328 MDFN_en16lsb(&transmit_buffer[5], hit_y);
329
330 hit_x = 0x01;
331 hit_y = 0x0A;
332
333 transmit_pos = 0;
334 transmit_count = 7;
335
336 trigger_eff = trigger_noclear;
337 }
338 else
339 {
340 command_phase = -1;
341 transmit_buffer[1] = 0;
342 transmit_buffer[2] = 0;
343 transmit_pos = 0;
344 transmit_count = 0;
345 }
346 break;
347
348 }
349 }
350
351 if(!bitpos && transmit_count)
352 dsr_pulse_delay = 100; //0x80; //0x40;
353
354 return(ret);
355 }
356
357 InputDevice *Device_GunCon_Create(void)
358 {
359 return new InputDevice_GunCon();
360 }
361
362
363 InputDeviceInputInfoStruct Device_GunCon_IDII[6] =
364 {
365 { "x_axis", "X Axis", -1, IDIT_X_AXIS },
366 { "y_axis", "Y Axis", -1, IDIT_Y_AXIS },
367
368 { "trigger", "Trigger", 0, IDIT_BUTTON, NULL },
369
370 { "a", "A", 1, IDIT_BUTTON, NULL },
371 { "b", "B", 2, IDIT_BUTTON, NULL },
372
373 { "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL }, // Useful for "Judge Dredd", and probably not much else.
374 };
0 #ifndef __MDFN_PSX_INPUT_GUNCON_H
1 #define __MDFN_PSX_INPUT_GUNCON_H
2
3 InputDevice *Device_GunCon_Create(void);
4 extern InputDeviceInputInfoStruct Device_GunCon_IDII[6];
5
6 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../psx.h"
18 #include "../frontio.h"
19 #include "justifier.h"
20
21 class InputDevice_Justifier : public InputDevice
22 {
23 public:
24
25 InputDevice_Justifier(void);
26 virtual ~InputDevice_Justifier();
27
28 virtual void Power(void);
29 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
30 virtual void UpdateInput(const void *data);
31 virtual bool RequireNoFrameskip(void);
32 virtual int32_t GPULineHook(const int32_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider);
33
34 //
35 //
36 //
37 virtual void SetDTR(bool new_dtr);
38 virtual bool GetDSR(void);
39 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
40
41 private:
42
43 bool dtr;
44
45 uint8 buttons;
46 bool trigger_eff;
47 bool trigger_noclear;
48
49 bool need_hit_detect;
50
51 int16 nom_x, nom_y;
52 int32 os_shot_counter;
53 bool prev_oss;
54
55 int32 command_phase;
56 uint32 bitpos;
57 uint8 receive_buffer;
58
59 uint8 command;
60
61 uint8 transmit_buffer[16];
62 uint32 transmit_pos;
63 uint32 transmit_count;
64
65 //
66 // Video timing stuff
67 bool prev_vsync;
68 int line_counter;
69
70 };
71
72 InputDevice_Justifier::InputDevice_Justifier(void)
73 {
74 Power();
75 }
76
77 InputDevice_Justifier::~InputDevice_Justifier()
78 {
79
80 }
81
82 void InputDevice_Justifier::Power(void)
83 {
84 dtr = 0;
85
86 buttons = 0;
87 trigger_eff = 0;
88 trigger_noclear = 0;
89
90 need_hit_detect = false;
91
92 nom_x = 0;
93 nom_y = 0;
94
95 os_shot_counter = 0;
96 prev_oss = 0;
97
98 command_phase = 0;
99
100 bitpos = 0;
101
102 receive_buffer = 0;
103
104 command = 0;
105
106 memset(transmit_buffer, 0, sizeof(transmit_buffer));
107
108 transmit_pos = 0;
109 transmit_count = 0;
110
111 prev_vsync = 0;
112 line_counter = 0;
113 }
114
115 void InputDevice_Justifier::UpdateInput(const void *data)
116 {
117 uint8 *d8 = (uint8 *)data;
118
119 nom_x = (int16)MDFN_de16lsb(&d8[0]);
120 nom_y = (int16)MDFN_de16lsb(&d8[2]);
121
122 trigger_noclear = (bool)(d8[4] & 0x1);
123 trigger_eff |= trigger_noclear;
124
125 buttons = (d8[4] >> 1) & 0x3;
126
127 if(os_shot_counter > 0) // FIXME if UpdateInput() is ever called more than once per video frame(at ~50 or ~60Hz).
128 os_shot_counter--;
129
130 if((d8[4] & 0x8) && !prev_oss && os_shot_counter == 0)
131 os_shot_counter = 10;
132 prev_oss = d8[4] & 0x8;
133 }
134
135 int InputDevice_Justifier::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
136 {
137 SFORMAT StateRegs[] =
138 {
139 SFVAR(dtr),
140
141 SFVAR(buttons),
142 SFVAR(trigger_eff),
143 SFVAR(trigger_noclear),
144
145 SFVAR(need_hit_detect),
146
147 SFVAR(nom_x),
148 SFVAR(nom_y),
149 SFVAR(os_shot_counter),
150 SFVAR(prev_oss),
151
152 SFVAR(command_phase),
153 SFVAR(bitpos),
154 SFVAR(receive_buffer),
155
156 SFVAR(command),
157
158 SFARRAY(transmit_buffer, sizeof(transmit_buffer)),
159 SFVAR(transmit_pos),
160 SFVAR(transmit_count),
161
162 SFVAR(prev_vsync),
163 SFVAR(line_counter),
164
165 SFEND
166 };
167 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
168
169 if(load)
170 {
171 if((transmit_pos + transmit_count) > sizeof(transmit_buffer))
172 {
173 transmit_pos = 0;
174 transmit_count = 0;
175 }
176 }
177
178 return(ret);
179 }
180
181 bool InputDevice_Justifier::RequireNoFrameskip(void)
182 {
183 return(true);
184 }
185
186 int32_t InputDevice_Justifier::GPULineHook(const int32_t timestamp, bool vsync, uint32 *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divider)
187 {
188 int32_t ret = PSX_EVENT_MAXTS;
189
190 if(vsync && !prev_vsync)
191 line_counter = 0;
192
193 if(pixels && pix_clock)
194 {
195 const int avs = 16; // Not 16 for PAL, fixme.
196 int32 gx;
197 int32 gy;
198 int32 gxa;
199
200 gx = (nom_x * 2 + pix_clock_divider) / (pix_clock_divider * 2);
201 gy = nom_y;
202 gxa = gx; // - (pix_clock / 400000);
203 //if(gxa < 0 && gx >= 0)
204 // gxa = 0;
205
206 if(!os_shot_counter && need_hit_detect && gxa >= 0 && gxa < (int)width && line_counter >= (avs + gy - 1) && line_counter <= (avs + gy + 1))
207 {
208 int r, g, b, a;
209
210 format->DecodeColor(pixels[gxa], r, g, b, a);
211
212 if((r + g + b) >= 0x40) // Wrong, but not COMPLETELY ABSOLUTELY wrong, at least. ;)
213 {
214 ret = timestamp + (int64)(gxa + pix_clock_offset) * (44100 * 768) / pix_clock - 177;
215 }
216 }
217
218 chair_x = gx;
219 chair_y = (avs + gy) - line_counter;
220 }
221
222 line_counter++;
223
224 return(ret);
225 }
226
227 void InputDevice_Justifier::SetDTR(bool new_dtr)
228 {
229 if(!dtr && new_dtr)
230 {
231 command_phase = 0;
232 bitpos = 0;
233 transmit_pos = 0;
234 transmit_count = 0;
235 }
236 else if(dtr && !new_dtr)
237 {
238 //if(bitpos || transmit_count)
239 // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
240 }
241
242 dtr = new_dtr;
243 }
244
245 bool InputDevice_Justifier::GetDSR(void)
246 {
247 if(!dtr)
248 return(0);
249
250 if(!bitpos && transmit_count)
251 return(1);
252
253 return(0);
254 }
255
256 bool InputDevice_Justifier::Clock(bool TxD, int32 &dsr_pulse_delay)
257 {
258 bool ret = 1;
259
260 dsr_pulse_delay = 0;
261
262 if(!dtr)
263 return(1);
264
265 if(transmit_count)
266 ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
267
268 receive_buffer &= ~(1 << bitpos);
269 receive_buffer |= TxD << bitpos;
270 bitpos = (bitpos + 1) & 0x7;
271
272 if(!bitpos)
273 {
274 //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
275
276 if(transmit_count)
277 {
278 transmit_pos++;
279 transmit_count--;
280 }
281
282
283 switch(command_phase)
284 {
285 case 0:
286 if(receive_buffer != 0x01)
287 command_phase = -1;
288 else
289 {
290 transmit_buffer[0] = 0x31;
291 transmit_pos = 0;
292 transmit_count = 1;
293 command_phase++;
294 }
295 break;
296
297 case 2:
298 //if(receive_buffer)
299 // printf("%02x\n", receive_buffer);
300 command_phase++;
301 break;
302
303 case 3:
304 need_hit_detect = receive_buffer & 0x10; // TODO, see if it's (val&0x10) == 0x10, or some other mask value.
305 command_phase++;
306 break;
307
308 case 1:
309 command = receive_buffer;
310 command_phase++;
311
312 transmit_buffer[0] = 0x5A;
313
314 //if(command != 0x42)
315 // fprintf(stderr, "Justifier unhandled command: 0x%02x\n", command);
316 //assert(command == 0x42);
317 if(command == 0x42)
318 {
319 transmit_buffer[1] = 0xFF ^ ((buttons & 2) << 2);
320 transmit_buffer[2] = 0xFF ^ (trigger_eff << 7) ^ ((buttons & 1) << 6);
321
322 if(os_shot_counter > 0)
323 {
324 transmit_buffer[2] |= (1 << 7);
325 if(os_shot_counter == 6 || os_shot_counter == 5)
326 {
327 transmit_buffer[2] &= ~(1 << 7);
328 }
329 }
330
331 transmit_pos = 0;
332 transmit_count = 3;
333
334 trigger_eff = trigger_noclear;
335 }
336 else
337 {
338 command_phase = -1;
339 transmit_buffer[1] = 0;
340 transmit_buffer[2] = 0;
341 transmit_pos = 0;
342 transmit_count = 0;
343 }
344 break;
345
346 }
347 }
348
349 if(!bitpos && transmit_count)
350 dsr_pulse_delay = 200;
351
352 return(ret);
353 }
354
355 InputDevice *Device_Justifier_Create(void)
356 {
357 return new InputDevice_Justifier();
358 }
359
360
361 InputDeviceInputInfoStruct Device_Justifier_IDII[6] =
362 {
363 { "x_axis", "X Axis", -1, IDIT_X_AXIS },
364 { "y_axis", "Y Axis", -1, IDIT_Y_AXIS },
365
366 { "trigger", "Trigger", 0, IDIT_BUTTON, NULL },
367
368 { "o", "O", 1, IDIT_BUTTON, NULL },
369 { "start", "Start", 2, IDIT_BUTTON, NULL },
370
371 { "offscreen_shot", "Offscreen Shot(Simulated)", 3, IDIT_BUTTON, NULL },
372 };
0 #ifndef __MDFN_PSX_INPUT_JUSTIFIER_H
1 #define __MDFN_PSX_INPUT_JUSTIFIER_H
2
3 InputDevice *Device_Justifier_Create(void);
4 extern InputDeviceInputInfoStruct Device_Justifier_IDII[6];
5
6 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 // I could find no other commands than 'R', 'W', and 'S' (not sure what 'S' is for, however)
18
19 #include "../psx.h"
20 #include "../frontio.h"
21 #include "memcard.h"
22
23 class InputDevice_Memcard : public InputDevice
24 {
25 public:
26
27 InputDevice_Memcard();
28 virtual ~InputDevice_Memcard();
29
30 virtual void Power(void);
31 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
32
33 //
34 //
35 //
36 virtual void SetDTR(bool new_dtr);
37 virtual bool GetDSR(void);
38 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
39
40 //
41 //
42 virtual uint8 *GetNVData(void);
43 virtual uint32 GetNVSize(void);
44 virtual void ReadNV(uint8 *buffer, uint32 offset, uint32 size);
45 virtual void WriteNV(const uint8 *buffer, uint32 offset, uint32 size);
46
47 virtual uint64 GetNVDirtyCount(void);
48 virtual void ResetNVDirtyCount(void);
49
50 private:
51
52 void Format(void);
53
54 bool presence_new;
55
56 uint8 card_data[1 << 17];
57 uint8 rw_buffer[128];
58 uint8 write_xor;
59
60 //
61 // Used to avoid saving unused memory cards' card data in save states.
62 // Set to false on object initialization, set to true when data is written to card_data that differs
63 // from existing data(either from loading a memory card saved to disk, or from a game writing to the memory card).
64 //
65 // Save and load its state to/from save states.
66 //
67 bool data_used;
68
69 //
70 // Do not save dirty_count in save states!
71 //
72 uint64 dirty_count;
73
74 bool dtr;
75 int32 command_phase;
76 uint32 bitpos;
77 uint8 receive_buffer;
78
79 uint8 command;
80 uint16 addr;
81 uint8 calced_xor;
82
83 uint8 transmit_buffer;
84 uint32 transmit_count;
85 };
86
87 void InputDevice_Memcard::Format(void)
88 {
89 memset(card_data, 0x00, sizeof(card_data));
90
91 card_data[0x00] = 0x4D;
92 card_data[0x01] = 0x43;
93 card_data[0x7F] = 0x0E;
94
95 for(unsigned int A = 0x80; A < 0x800; A += 0x80)
96 {
97 card_data[A + 0x00] = 0xA0;
98 card_data[A + 0x08] = 0xFF;
99 card_data[A + 0x09] = 0xFF;
100 card_data[A + 0x7F] = 0xA0;
101 }
102
103 for(unsigned int A = 0x0800; A < 0x1200; A += 0x80)
104 {
105 card_data[A + 0x00] = 0xFF;
106 card_data[A + 0x01] = 0xFF;
107 card_data[A + 0x02] = 0xFF;
108 card_data[A + 0x03] = 0xFF;
109 card_data[A + 0x08] = 0xFF;
110 card_data[A + 0x09] = 0xFF;
111 }
112 }
113
114 InputDevice_Memcard::InputDevice_Memcard()
115 {
116 Power();
117
118 data_used = false;
119 dirty_count = 0;
120
121 // Init memcard as formatted.
122 assert(sizeof(card_data) == (1 << 17));
123 Format();
124 }
125
126 InputDevice_Memcard::~InputDevice_Memcard()
127 {
128
129 }
130
131 void InputDevice_Memcard::Power(void)
132 {
133 dtr = 0;
134
135 //buttons[0] = buttons[1] = 0;
136
137 command_phase = 0;
138
139 bitpos = 0;
140
141 receive_buffer = 0;
142
143 command = 0;
144
145 transmit_buffer = 0;
146
147 transmit_count = 0;
148
149 addr = 0;
150
151 presence_new = true;
152 }
153
154 int InputDevice_Memcard::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
155 {
156 // Don't save dirty_count.
157 SFORMAT StateRegs[] =
158 {
159 SFVAR(presence_new),
160
161 SFARRAY(rw_buffer, sizeof(rw_buffer)),
162 SFVAR(write_xor),
163
164 SFVAR(dtr),
165 SFVAR(command_phase),
166 SFVAR(bitpos),
167 SFVAR(receive_buffer),
168
169 SFVAR(command),
170 SFVAR(addr),
171 SFVAR(calced_xor),
172
173 SFVAR(transmit_buffer),
174 SFVAR(transmit_count),
175
176 SFVAR(data_used),
177
178 SFEND
179 };
180
181 SFORMAT CD_StateRegs[] =
182 {
183 SFARRAY(card_data, sizeof(card_data)),
184 SFEND
185 };
186 int ret = 1;
187
188 if(MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name) != 0)
189 {
190 //printf("%s data_used=%d\n", section_name, data_used);
191 if(data_used)
192 {
193 std::string tmp_name = std::string(section_name) + "_DT";
194
195 ret &= MDFNSS_StateAction(sm, load, data_only, CD_StateRegs, tmp_name.c_str());
196 }
197
198 if(load)
199 {
200 if(data_used)
201 dirty_count++;
202 }
203 }
204 else
205 ret = 0;
206
207 return(ret);
208 }
209
210 void InputDevice_Memcard::SetDTR(bool new_dtr)
211 {
212 if(!dtr && new_dtr)
213 {
214 command_phase = 0;
215 bitpos = 0;
216 transmit_count = 0;
217 }
218 else if(dtr && !new_dtr)
219 {
220 if(command_phase > 0)
221 PSX_WARNING("[MCR] Communication aborted???");
222 }
223 dtr = new_dtr;
224 }
225
226 bool InputDevice_Memcard::GetDSR(void)
227 {
228 if(!dtr)
229 return(0);
230
231 if(!bitpos && transmit_count)
232 return(1);
233
234 return(0);
235 }
236
237 bool InputDevice_Memcard::Clock(bool TxD, int32 &dsr_pulse_delay)
238 {
239 bool ret = 1;
240
241 dsr_pulse_delay = 0;
242
243 if(!dtr)
244 return(1);
245
246 if(transmit_count)
247 ret = (transmit_buffer >> bitpos) & 1;
248
249 receive_buffer &= ~(1 << bitpos);
250 receive_buffer |= TxD << bitpos;
251 bitpos = (bitpos + 1) & 0x7;
252
253 if(!bitpos)
254 {
255 //if(command_phase > 0 || transmit_count)
256 // printf("[MCRDATA] Received_data=0x%02x, Sent_data=0x%02x\n", receive_buffer, transmit_buffer);
257
258 if(transmit_count)
259 {
260 transmit_count--;
261 }
262
263 if (command_phase >= 1024 && command_phase <= 1151)
264 {
265 // Transmit actual 128 bytes data
266 transmit_buffer = card_data[(addr << 7) + (command_phase - 1024)];
267 calced_xor ^= transmit_buffer;
268 transmit_count = 1;
269 command_phase++;
270 }
271 else if (command_phase >= 2048 && command_phase <= 2175)
272 {
273 calced_xor ^= receive_buffer;
274 rw_buffer[command_phase - 2048] = receive_buffer;
275
276 transmit_buffer = receive_buffer;
277 transmit_count = 1;
278 command_phase++;
279 }
280 else
281 switch(command_phase)
282 {
283 case 0:
284 if(receive_buffer != 0x81)
285 command_phase = -1;
286 else
287 {
288 //printf("[MCR] Device selected\n");
289 transmit_buffer = presence_new ? 0x08 : 0x00;
290 transmit_count = 1;
291 command_phase++;
292 }
293 break;
294
295 case 1:
296 command = receive_buffer;
297 //printf("[MCR] Command received: %c\n", command);
298 if(command == 'R' || command == 'W')
299 {
300 command_phase++;
301 transmit_buffer = 0x5A;
302 transmit_count = 1;
303 }
304 else
305 {
306 if(command == 'S')
307 {
308 PSX_WARNING("[MCR] Memcard S command unsupported.");
309 }
310
311 command_phase = -1;
312 transmit_buffer = 0;
313 transmit_count = 0;
314 }
315 break;
316
317 case 2:
318 transmit_buffer = 0x5D;
319 transmit_count = 1;
320 command_phase++;
321 break;
322
323 case 3:
324 transmit_buffer = 0x00;
325 transmit_count = 1;
326 if(command == 'R')
327 command_phase = 1000;
328 else if(command == 'W')
329 command_phase = 2000;
330 break;
331
332 //
333 // Read
334 //
335 case 1000:
336 addr = receive_buffer << 8;
337 transmit_buffer = receive_buffer;
338 transmit_count = 1;
339 command_phase++;
340 break;
341
342 case 1001:
343 addr |= receive_buffer & 0xFF;
344 transmit_buffer = '\\';
345 transmit_count = 1;
346 command_phase++;
347 break;
348
349 case 1002:
350 //printf("[MCR] READ ADDR=0x%04x\n", addr);
351 if(addr >= (sizeof(card_data) >> 7))
352 addr = 0xFFFF;
353
354 calced_xor = 0;
355 transmit_buffer = ']';
356 transmit_count = 1;
357 command_phase++;
358
359 // TODO: enable this code(or something like it) when CPU instruction timing is a bit better.
360 //
361 //dsr_pulse_delay = 32000;
362 //goto SkipDPD;
363 //
364
365 break;
366
367 case 1003:
368 transmit_buffer = addr >> 8;
369 calced_xor ^= transmit_buffer;
370 transmit_count = 1;
371 command_phase++;
372 break;
373
374 case 1004:
375 transmit_buffer = addr & 0xFF;
376 calced_xor ^= transmit_buffer;
377
378 if(addr == 0xFFFF)
379 {
380 transmit_count = 1;
381 command_phase = -1;
382 }
383 else
384 {
385 transmit_count = 1;
386 command_phase = 1024;
387 }
388 break;
389
390
391
392 // XOR
393 case (1024 + 128):
394 transmit_buffer = calced_xor;
395 transmit_count = 1;
396 command_phase++;
397 break;
398
399 // End flag
400 case (1024 + 129):
401 transmit_buffer = 'G';
402 transmit_count = 1;
403 command_phase = -1;
404 break;
405
406 //
407 // Write
408 //
409 case 2000:
410 calced_xor = receive_buffer;
411 addr = receive_buffer << 8;
412 transmit_buffer = receive_buffer;
413 transmit_count = 1;
414 command_phase++;
415 break;
416
417 case 2001:
418 calced_xor ^= receive_buffer;
419 addr |= receive_buffer & 0xFF;
420 //printf("[MCR] WRITE ADDR=0x%04x\n", addr);
421 transmit_buffer = receive_buffer;
422 transmit_count = 1;
423 command_phase = 2048;
424 break;
425 case (2048 + 128): // XOR
426 write_xor = receive_buffer;
427 transmit_buffer = '\\';
428 transmit_count = 1;
429 command_phase++;
430 break;
431
432 case (2048 + 129):
433 transmit_buffer = ']';
434 transmit_count = 1;
435 command_phase++;
436 break;
437
438 case (2048 + 130): // End flag
439 //MDFN_DispMessage("%02x %02x", calced_xor, write_xor);
440 //printf("[MCR] Write End. Actual_XOR=0x%02x, CW_XOR=0x%02x\n", calced_xor, write_xor);
441
442 if(calced_xor != write_xor)
443 transmit_buffer = 'N';
444 else if(addr >= (sizeof(card_data) >> 7))
445 transmit_buffer = 0xFF;
446 else
447 {
448 transmit_buffer = 'G';
449 presence_new = false;
450
451 // If the current data is different from the data to be written, increment the dirty count.
452 // memcpy()'ing over to card_data is also conditionalized here for a slight optimization.
453 if(memcmp(&card_data[addr << 7], rw_buffer, 128))
454 {
455 memcpy(&card_data[addr << 7], rw_buffer, 128);
456 dirty_count++;
457 data_used = true;
458 }
459 }
460
461 transmit_count = 1;
462 command_phase = -1;
463 break;
464
465 }
466
467 //if(command_phase != -1 || transmit_count)
468 // printf("[MCR] Receive: 0x%02x, Send: 0x%02x -- %d\n", receive_buffer, transmit_buffer, command_phase);
469 }
470
471 if(!bitpos && transmit_count)
472 dsr_pulse_delay = 0x100;
473
474 //SkipDPD: ;
475
476 return(ret);
477 }
478
479 uint8 *InputDevice_Memcard::GetNVData(void)
480 {
481 return card_data;
482 }
483
484 uint32 InputDevice_Memcard::GetNVSize(void)
485 {
486 return(sizeof(card_data));
487 }
488
489 void InputDevice_Memcard::ReadNV(uint8 *buffer, uint32 offset, uint32 size)
490 {
491 while(size--)
492 {
493 *buffer = card_data[offset & (sizeof(card_data) - 1)];
494 buffer++;
495 offset++;
496 }
497 }
498
499 void InputDevice_Memcard::WriteNV(const uint8 *buffer, uint32 offset, uint32 size)
500 {
501 if(size)
502 {
503 dirty_count++;
504 }
505
506 while(size--)
507 {
508 if(card_data[offset & (sizeof(card_data) - 1)] != *buffer)
509 data_used = true;
510
511 card_data[offset & (sizeof(card_data) - 1)] = *buffer;
512 buffer++;
513 offset++;
514 }
515 }
516
517 uint64 InputDevice_Memcard::GetNVDirtyCount(void)
518 {
519 return(dirty_count);
520 }
521
522 void InputDevice_Memcard::ResetNVDirtyCount(void)
523 {
524 dirty_count = 0;
525 }
526
527
528 InputDevice *Device_Memcard_Create(void)
529 {
530 return new InputDevice_Memcard();
531 }
0 #ifndef __MDFN_PSX_INPUT_MEMCARD_H
1 #define __MDFN_PSX_INPUT_MEMCARD_H
2
3 InputDevice *Device_Memcard_Create(void);
4
5 #endif
0 #include "../psx.h"
1 #include "../frontio.h"
2 #include "mouse.h"
3
4 class InputDevice_Mouse : public InputDevice
5 {
6 public:
7
8 InputDevice_Mouse();
9 virtual ~InputDevice_Mouse();
10
11 virtual void Power(void);
12 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
13 virtual void UpdateInput(const void *data);
14
15 virtual void Update(const int32_t timestamp);
16 virtual void ResetTS(void);
17
18 //
19 //
20 //
21 virtual void SetDTR(bool new_dtr);
22 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
23
24 private:
25
26 int32 lastts;
27 int32 clear_timeout;
28
29 bool dtr;
30
31 uint8 button;
32 uint8 button_post_mask;
33 int32 accum_xdelta;
34 int32 accum_ydelta;
35
36 int32 command_phase;
37 uint32 bitpos;
38 uint8 receive_buffer;
39
40 uint8 command;
41
42 uint8 transmit_buffer[5];
43 uint32 transmit_pos;
44 uint32 transmit_count;
45 };
46
47 InputDevice_Mouse::InputDevice_Mouse()
48 {
49 Power();
50 }
51
52 InputDevice_Mouse::~InputDevice_Mouse()
53 {
54
55 }
56
57 void InputDevice_Mouse::Update(const int32_t timestamp)
58 {
59 int32 cycles = timestamp - lastts;
60
61 clear_timeout += cycles;
62 if(clear_timeout >= (33868800 / 4))
63 {
64 //puts("Mouse timeout\n");
65 clear_timeout = 0;
66 accum_xdelta = 0;
67 accum_ydelta = 0;
68 button &= button_post_mask;
69 }
70
71 lastts = timestamp;
72 }
73
74 void InputDevice_Mouse::ResetTS(void)
75 {
76 lastts = 0;
77 }
78
79 void InputDevice_Mouse::Power(void)
80 {
81 lastts = 0;
82 clear_timeout = 0;
83
84 dtr = 0;
85
86 button = 0;
87 button_post_mask = 0;
88 accum_xdelta = 0;
89 accum_ydelta = 0;
90
91 command_phase = 0;
92
93 bitpos = 0;
94
95 receive_buffer = 0;
96
97 command = 0;
98
99 memset(transmit_buffer, 0, sizeof(transmit_buffer));
100
101 transmit_pos = 0;
102 transmit_count = 0;
103 }
104
105 int InputDevice_Mouse::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
106 {
107 SFORMAT StateRegs[] =
108 {
109 SFVAR(clear_timeout),
110
111 SFVAR(dtr),
112
113 SFVAR(button),
114 SFVAR(button_post_mask),
115 SFVAR(accum_xdelta),
116 SFVAR(accum_ydelta),
117
118 SFVAR(command_phase),
119 SFVAR(bitpos),
120 SFVAR(receive_buffer),
121
122 SFVAR(command),
123
124 SFARRAY(transmit_buffer, sizeof(transmit_buffer)),
125 SFVAR(transmit_pos),
126 SFVAR(transmit_count),
127
128 SFEND
129 };
130 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
131
132 if(load)
133 {
134 if((transmit_pos + transmit_count) > sizeof(transmit_buffer))
135 {
136 transmit_pos = 0;
137 transmit_count = 0;
138 }
139 }
140
141 return(ret);
142 }
143
144 void InputDevice_Mouse::UpdateInput(const void *data)
145 {
146 accum_xdelta += (int32)MDFN_de32lsb((uint8*)data + 0);
147 accum_ydelta += (int32)MDFN_de32lsb((uint8*)data + 4);
148
149 if(accum_xdelta > 30 * 127) accum_xdelta = 30 * 127;
150 if(accum_xdelta < 30 * -128) accum_xdelta = 30 * -128;
151
152 if(accum_ydelta > 30 * 127) accum_ydelta = 30 * 127;
153 if(accum_ydelta < 30 * -128) accum_ydelta = 30 * -128;
154
155 button |= *((uint8 *)data + 8);
156 button_post_mask = *((uint8 *)data + 8);
157
158 //if(button)
159 // MDFN_DispMessage("Button\n");
160 //printf("%d %d\n", accum_xdelta, accum_ydelta);
161 }
162
163
164 void InputDevice_Mouse::SetDTR(bool new_dtr)
165 {
166 if(!dtr && new_dtr)
167 {
168 command_phase = 0;
169 bitpos = 0;
170 transmit_pos = 0;
171 transmit_count = 0;
172 }
173 else if(dtr && !new_dtr)
174 {
175 //if(bitpos || transmit_count)
176 // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
177 }
178
179 dtr = new_dtr;
180 }
181
182 bool InputDevice_Mouse::Clock(bool TxD, int32 &dsr_pulse_delay)
183 {
184 bool ret = 1;
185
186 dsr_pulse_delay = 0;
187
188 if(!dtr)
189 return(1);
190
191 if(transmit_count)
192 ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
193
194 receive_buffer &= ~(1 << bitpos);
195 receive_buffer |= TxD << bitpos;
196 bitpos = (bitpos + 1) & 0x7;
197
198 if(!bitpos)
199 {
200 //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
201
202 if(transmit_count)
203 {
204 transmit_pos++;
205 transmit_count--;
206 }
207
208
209 switch(command_phase)
210 {
211 case 0:
212 if(receive_buffer != 0x01)
213 command_phase = -1;
214 else
215 {
216 transmit_buffer[0] = 0x12;
217 transmit_pos = 0;
218 transmit_count = 1;
219 command_phase++;
220 }
221 break;
222
223 case 1:
224 command = receive_buffer;
225 command_phase++;
226
227 transmit_buffer[0] = 0x5A;
228
229 if(command == 0x42)
230 {
231 int32 xdelta = accum_xdelta;
232 int32 ydelta = accum_ydelta;
233
234 if(xdelta < -128) xdelta = -128;
235 if(xdelta > 127) xdelta = 127;
236
237 if(ydelta < -128) ydelta = -128;
238 if(ydelta > 127) ydelta = 127;
239
240 transmit_buffer[1] = 0xFF;
241 transmit_buffer[2] = 0xFC ^ (button << 2);
242 transmit_buffer[3] = xdelta;
243 transmit_buffer[4] = ydelta;
244
245 accum_xdelta -= xdelta;
246 accum_ydelta -= ydelta;
247
248 button &= button_post_mask;
249
250 transmit_pos = 0;
251 transmit_count = 5;
252
253 clear_timeout = 0;
254 }
255 else
256 {
257 command_phase = -1;
258 transmit_pos = 0;
259 transmit_count = 0;
260 }
261 break;
262
263 }
264 }
265
266 if(!bitpos && transmit_count)
267 dsr_pulse_delay = 0x40; //0x100;
268
269 return(ret);
270 }
271
272 InputDevice *Device_Mouse_Create(void)
273 {
274 return new InputDevice_Mouse();
275 }
276
277
278 InputDeviceInputInfoStruct Device_Mouse_IDII[4] =
279 {
280 { "x_axis", "X Axis", -1, IDIT_X_AXIS_REL },
281 { "y_axis", "Y Axis", -1, IDIT_Y_AXIS_REL },
282 { "right", "Right Button", 1, IDIT_BUTTON, NULL },
283 { "left", "Left Button", 0, IDIT_BUTTON, NULL },
284 };
0 #ifndef __MDFN_PSX_INPUT_MOUSE_H
1 #define __MDFN_PSX_INPUT_MOUSE_H
2
3 InputDevice *Device_Mouse_Create(void);
4 extern InputDeviceInputInfoStruct Device_Mouse_IDII[4];
5
6 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../psx.h"
18 #include "../frontio.h"
19 #include "multitap.h"
20
21 /*
22 TODO: PS1 multitap appears to have some internal knowledge of controller IDs, so it won't get "stuck" waiting for data from a controller that'll never
23 come. We currently sort of "cheat" due to how the dsr_pulse_delay stuff works, but in the future we should try to emulate this multitap functionality.
24
25 Also, full-mode read startup and subport controller ID read timing isn't quite right, so we should fix that too.
26 */
27
28 /*
29 Notes from tests on real thing(not necessarily emulated the same way here):
30
31 Manual port selection read mode:
32 Write 0x01-0x04 instead of 0x01 as first byte, selects port(1=A,2=B,3=C,4=D) to access.
33
34 Ports that don't exist(0x00, 0x05-0xFF) or don't have a device plugged in will not respond(no DSR pulse).
35
36 Full read mode:
37 Bit0 of third byte(from-zero-index=0x02) should be set to 1 to enter full read mode, on subsequent reads.
38
39 Appears to require a controller to be plugged into the port specified by the first byte as per manual port selection read mode,
40 to write the byte necessary to enter full-read mode; but once the third byte with the bit set has been written, no controller in
41 that port is required for doing full reads(and the manual port selection is ignored when doing a full read).
42
43 However, if there are no controllers plugged in, the returned data will be short:
44 % 0: 0xff
45 % 1: 0x80
46 % 2: 0x5a
47
48 Example full-read bytestream(with controllers plugged into port A, port B, and port C, with port D empty):
49 % 0: 0xff
50 % 1: 0x80
51 % 2: 0x5a
52
53 % 3: 0x73 (Port A controller data start)
54 % 4: 0x5a
55 % 5: 0xff
56 % 6: 0xff
57 % 7: 0x80
58 % 8: 0x8c
59 % 9: 0x79
60 % 10: 0x8f
61
62 % 11: 0x53 (Port B controller data start)
63 % 12: 0x5a
64 % 13: 0xff
65 % 14: 0xff
66 % 15: 0x80
67 % 16: 0x80
68 % 17: 0x75
69 % 18: 0x8e
70
71 % 19: 0x41 (Port C controller data start)
72 % 20: 0x5a
73 % 21: 0xff
74 % 22: 0xff
75 % 23: 0xff
76 % 24: 0xff
77 % 25: 0xff
78 % 26: 0xff
79
80 % 27: 0xff (Port D controller data start)
81 % 28: 0xff
82 % 29: 0xff
83 % 30: 0xff
84 % 31: 0xff
85 % 32: 0xff
86 % 33: 0xff
87 % 34: 0xff
88
89 */
90
91 InputDevice_Multitap::InputDevice_Multitap()
92 {
93 for(int i = 0; i < 4; i++)
94 {
95 pad_devices[i] = NULL;
96 mc_devices[i] = NULL;
97 }
98 Power();
99 }
100
101 InputDevice_Multitap::~InputDevice_Multitap()
102 {
103 }
104
105 void InputDevice_Multitap::SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device)
106 {
107 assert(sub_index < 4);
108
109 //printf("%d\n", sub_index);
110
111 pad_devices[sub_index] = device;
112 mc_devices[sub_index] = mc_device;
113 }
114
115
116 void InputDevice_Multitap::Power(void)
117 {
118 selected_device = -1;
119 bit_counter = 0;
120 receive_buffer = 0;
121 byte_counter = 0;
122
123 mc_mode = false;
124 full_mode = false;
125 full_mode_setting = false;
126
127 prev_fm_success = false;
128 memset(sb, 0, sizeof(sb));
129
130 fm_dp = 0;
131 memset(fm_buffer, 0, sizeof(fm_buffer));
132 fm_command_error = false;
133
134 for(int i = 0; i < 4; i++)
135 {
136 if(pad_devices[i])
137 pad_devices[i]->Power();
138
139 if(mc_devices[i])
140 mc_devices[i]->Power();
141 }
142 }
143
144 int InputDevice_Multitap::StateAction(StateMem* sm, int load, int data_only, const char* section_name)
145 {
146 SFORMAT StateRegs[] =
147 {
148 SFVAR(dtr),
149
150 SFVAR(selected_device),
151 SFVAR(full_mode_setting),
152
153 SFVAR(full_mode),
154 SFVAR(mc_mode),
155
156 SFVAR(prev_fm_success),
157
158 SFVAR(fm_dp),
159 SFARRAY(&fm_buffer[0][0], sizeof(fm_buffer) / sizeof(fm_buffer[0][0])),
160 SFARRAY(&sb[0][0], sizeof(sb) / sizeof(sb[0][0])),
161
162 SFVAR(fm_command_error),
163
164 SFVAR(command),
165 SFVAR(receive_buffer),
166 SFVAR(bit_counter),
167 SFVAR(byte_counter),
168
169 SFEND
170 };
171 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, section_name);
172
173 if(load)
174 {
175
176 }
177
178 return(ret);
179 }
180
181 void InputDevice_Multitap::SetDTR(bool new_dtr)
182 {
183 bool old_dtr = dtr;
184 dtr = new_dtr;
185
186 if(!dtr)
187 {
188 if(old_dtr)
189 {
190 //printf("Multitap stop.\n");
191 }
192
193 bit_counter = 0;
194 receive_buffer = 0;
195 selected_device = -1;
196 mc_mode = false;
197 full_mode = false;
198 }
199
200 if(!old_dtr && dtr)
201 {
202 full_mode = full_mode_setting;
203
204 if(!prev_fm_success)
205 {
206 unsigned i;
207 memset(sb, 0, sizeof(sb));
208 for(i = 0; i < 4; i++)
209 sb[i][0] = 0x42;
210 }
211
212 prev_fm_success = false;
213
214 byte_counter = 0;
215
216 //if(full_mode)
217 // printf("Multitap start: %d\n", full_mode);
218 }
219
220 for(int i = 0; i < 4; i++)
221 {
222 pad_devices[i]->SetDTR(dtr);
223 mc_devices[i]->SetDTR(dtr);
224 }
225 }
226
227 bool InputDevice_Multitap::GetDSR(void)
228 {
229 return(0);
230 }
231
232 bool InputDevice_Multitap::Clock(bool TxD, int32 &dsr_pulse_delay)
233 {
234 if(!dtr)
235 return(1);
236
237 bool ret = 1;
238 int32 tmp_pulse_delay[2][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
239
240 //printf("Receive bit: %d\n", TxD);
241 //printf("TxD %d\n", TxD);
242
243 receive_buffer &= ~ (1 << bit_counter);
244 receive_buffer |= TxD << bit_counter;
245
246 if(1)
247 {
248 if(byte_counter == 0)
249 {
250 bool mangled_txd = TxD;
251
252 if(bit_counter < 4)
253 mangled_txd = (0x01 >> bit_counter) & 1;
254
255 for(unsigned i = 0; i < 4; i++)
256 {
257 pad_devices[i]->Clock(mangled_txd, tmp_pulse_delay[0][i]);
258 mc_devices[i]->Clock(mangled_txd, tmp_pulse_delay[1][i]);
259 }
260 }
261 else
262 {
263 if(full_mode)
264 {
265 if(byte_counter == 1)
266 ret = (0x80 >> bit_counter) & 1;
267 else if(byte_counter == 2)
268 ret = (0x5A >> bit_counter) & 1;
269 else if(byte_counter >= 0x03 && byte_counter < 0x03 + 0x08 * 4)
270 {
271 if(!fm_command_error && byte_counter < (0x03 + 0x08))
272 {
273 unsigned i;
274 for(i = 0; i < 4; i++)
275 {
276 fm_buffer[i][byte_counter - 0x03] &= (pad_devices[i]->Clock((sb[i][byte_counter - 0x03] >> bit_counter) & 1, tmp_pulse_delay[0][i]) << bit_counter) | (~(1U << bit_counter));
277 }
278 }
279 ret &= ((&fm_buffer[0][0])[byte_counter - 0x03] >> bit_counter) & 1;
280 }
281 }
282 else // to if(full_mode)
283 {
284 if((unsigned)selected_device < 4)
285 {
286 ret &= pad_devices[selected_device]->Clock(TxD, tmp_pulse_delay[0][selected_device]);
287 ret &= mc_devices[selected_device]->Clock(TxD, tmp_pulse_delay[1][selected_device]);
288 }
289 }
290 } // end else to if(byte_counter == 0)
291 }
292
293 //
294 //
295 //
296
297 bit_counter = (bit_counter + 1) & 0x7;
298 if(bit_counter == 0)
299 {
300 //printf("MT Receive: 0x%02x\n", receive_buffer);
301 if(byte_counter == 0)
302 {
303 mc_mode = (bool)(receive_buffer & 0xF0);
304 if(mc_mode)
305 full_mode = false;
306
307 //printf("Zoomba: 0x%02x\n", receive_buffer);
308 //printf("Full mode: %d %d %d\n", full_mode, bit_counter, byte_counter);
309
310 if(full_mode)
311 {
312 memset(fm_buffer, 0xFF, sizeof(fm_buffer));
313 selected_device = 0;
314 }
315 else
316 {
317 //printf("Device select: %02x\n", receive_buffer);
318 selected_device = ((receive_buffer & 0xF) - 1) & 0xFF;
319 }
320 }
321
322 if(byte_counter == 1)
323 {
324 command = receive_buffer;
325 fm_command_error = false;
326
327 //printf("Multitap sub-command: %02x\n", command);
328
329 if(full_mode && command != 0x42)
330 fm_command_error = true;
331 }
332
333 if((!mc_mode || full_mode) && byte_counter == 2)
334 {
335 //printf("Full mode setting: %02x\n", receive_buffer);
336 full_mode_setting = receive_buffer & 0x01;
337 }
338
339 if(full_mode)
340 {
341 if(byte_counter >= 3 + 8 * 0 && byte_counter < (3 + 8 * 4))
342 {
343 const unsigned adjbi = byte_counter - 3;
344 sb[adjbi >> 3][adjbi & 0x7] = receive_buffer;
345 }
346
347 if(byte_counter == 33)
348 prev_fm_success = true;
349 }
350
351 // Handle DSR stuff
352 if(full_mode)
353 {
354 if(byte_counter == 0) // Next byte: 0x80
355 {
356 dsr_pulse_delay = 1000;
357
358 fm_dp = 0;
359 for(unsigned i = 0; i < 4; i++)
360 fm_dp |= (((bool)(tmp_pulse_delay[0][i])) << i);
361 }
362 else if(byte_counter == 1) // Next byte: 0x5A
363 dsr_pulse_delay = 0x40;
364 else if(byte_counter == 2) // Next byte(typically, controller-dependent): 0x41
365 {
366 if(fm_dp)
367 dsr_pulse_delay = 0x40;
368 else
369 {
370 byte_counter = 255;
371 dsr_pulse_delay = 0;
372 }
373 }
374 else if(byte_counter >= 3 && byte_counter < 34) // Next byte when byte_counter==3 (typically, controller-dependent): 0x5A
375 {
376 if(byte_counter < 10)
377 {
378 unsigned i;
379 int d = 0x40;
380
381 for(i = 0; i < 4; i++)
382 {
383 int32 tpd = tmp_pulse_delay[0][i];
384
385 if(byte_counter == 3 && (fm_dp & (1U << i)) && tpd == 0)
386 {
387 //printf("SNORG: %u %02x\n", i, sb[i][0]);
388 fm_command_error = true;
389 }
390
391 if(tpd > d)
392 d = tpd;
393 }
394
395 dsr_pulse_delay = d;
396 }
397 else
398 dsr_pulse_delay = 0x20;
399
400 if(byte_counter == 3 && fm_command_error)
401 {
402 byte_counter = 255;
403 dsr_pulse_delay = 0;
404 }
405 }
406 } // end if(full_mode)
407 else
408 {
409 if((unsigned)selected_device < 4)
410 {
411 dsr_pulse_delay = std::max<int32>(tmp_pulse_delay[0][selected_device], tmp_pulse_delay[1][selected_device]);
412 }
413 }
414
415
416 //
417 //
418 //
419
420 //printf("Byte Counter Increment\n");
421 if(byte_counter < 255)
422 byte_counter++;
423 }
424
425
426
427 return(ret);
428 }
0 #ifndef __MDFN_PSX_INPUT_MULTITAP_H
1 #define __MDFN_PSX_INPUT_MULTITAP_H
2
3 class InputDevice_Multitap : public InputDevice
4 {
5 public:
6
7 InputDevice_Multitap();
8 virtual ~InputDevice_Multitap();
9 virtual void Power(void);
10 virtual int StateAction(StateMem* sm, int load, int data_only, const char* section_name);
11
12 void SetSubDevice(unsigned int sub_index, InputDevice *device, InputDevice *mc_device);
13
14 //
15 //
16 //
17 virtual void SetDTR(bool new_dtr);
18 virtual bool GetDSR(void);
19 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
20
21 private:
22
23 InputDevice *pad_devices[4];
24 InputDevice *mc_devices[4];
25
26 bool dtr;
27
28 int selected_device;
29 bool full_mode_setting;
30
31 bool full_mode;
32 bool mc_mode;
33 bool prev_fm_success;
34
35 uint8 fm_dp; // Device-present.
36 uint8 fm_buffer[4][8];
37
38 uint8 sb[4][8];
39
40 bool fm_command_error;
41
42 uint8 command;
43 uint8 receive_buffer;
44 uint8 bit_counter;
45 uint8 byte_counter;
46 };
47
48 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../psx.h"
18 #include "../frontio.h"
19 #include "negcon.h"
20
21 class InputDevice_neGcon : public InputDevice
22 {
23 public:
24
25 InputDevice_neGcon(void);
26 virtual ~InputDevice_neGcon();
27
28 virtual void Power(void);
29 virtual void UpdateInput(const void *data);
30
31 //
32 //
33 //
34 virtual void SetDTR(bool new_dtr);
35 virtual bool GetDSR(void);
36 virtual bool Clock(bool TxD, int32 &dsr_pulse_delay);
37
38 private:
39
40 bool dtr;
41
42 uint8 buttons[2];
43 uint8 twist;
44 uint8 anabuttons[3];
45
46 int32 command_phase;
47 uint32 bitpos;
48 uint8 receive_buffer;
49
50 uint8 command;
51
52 uint8 transmit_buffer[8];
53 uint32 transmit_pos;
54 uint32 transmit_count;
55 };
56
57 InputDevice_neGcon::InputDevice_neGcon(void)
58 {
59 Power();
60 }
61
62 InputDevice_neGcon::~InputDevice_neGcon()
63 {
64
65 }
66
67 void InputDevice_neGcon::Power(void)
68 {
69 dtr = 0;
70
71 buttons[0] = buttons[1] = 0;
72 twist = 0;
73 anabuttons[0] = 0;
74 anabuttons[1] = 0;
75 anabuttons[2] = 0;
76
77 command_phase = 0;
78
79 bitpos = 0;
80
81 receive_buffer = 0;
82
83 command = 0;
84
85 memset(transmit_buffer, 0, sizeof(transmit_buffer));
86
87 transmit_pos = 0;
88 transmit_count = 0;
89 }
90
91 void InputDevice_neGcon::UpdateInput(const void *data)
92 {
93 uint8 *d8 = (uint8 *)data;
94
95 buttons[0] = d8[0];
96 buttons[1] = d8[1];
97
98 twist = ((32768 + MDFN_de32lsb((const uint8 *)data + 4) - (((int32)MDFN_de32lsb((const uint8 *)data + 8) * 32768 + 16383) / 32767)) * 255 + 32767) / 65535;
99
100 anabuttons[0] = (MDFN_de32lsb((const uint8 *)data + 12) * 255 + 16383) / 32767;
101 anabuttons[1] = (MDFN_de32lsb((const uint8 *)data + 16) * 255 + 16383) / 32767;
102 anabuttons[2] = (MDFN_de32lsb((const uint8 *)data + 20) * 255 + 16383) / 32767;
103
104 //printf("%02x %02x %02x %02x\n", twist, anabuttons[0], anabuttons[1], anabuttons[2]);
105 }
106
107
108 void InputDevice_neGcon::SetDTR(bool new_dtr)
109 {
110 if(!dtr && new_dtr)
111 {
112 command_phase = 0;
113 bitpos = 0;
114 transmit_pos = 0;
115 transmit_count = 0;
116 }
117 else if(dtr && !new_dtr)
118 {
119 //if(bitpos || transmit_count)
120 // printf("[PAD] Abort communication!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
121 }
122
123 dtr = new_dtr;
124 }
125
126 bool InputDevice_neGcon::GetDSR(void)
127 {
128 if(!dtr)
129 return(0);
130
131 if(!bitpos && transmit_count)
132 return(1);
133
134 return(0);
135 }
136
137 bool InputDevice_neGcon::Clock(bool TxD, int32 &dsr_pulse_delay)
138 {
139 bool ret = 1;
140
141 dsr_pulse_delay = 0;
142
143 if(!dtr)
144 return(1);
145
146 if(transmit_count)
147 ret = (transmit_buffer[transmit_pos] >> bitpos) & 1;
148
149 receive_buffer &= ~(1 << bitpos);
150 receive_buffer |= TxD << bitpos;
151 bitpos = (bitpos + 1) & 0x7;
152
153 if(!bitpos)
154 {
155 //printf("[PAD] Receive: %02x -- command_phase=%d\n", receive_buffer, command_phase);
156
157 if(transmit_count)
158 {
159 transmit_pos++;
160 transmit_count--;
161 }
162
163
164 switch(command_phase)
165 {
166 case 0:
167 if(receive_buffer != 0x01)
168 command_phase = -1;
169 else
170 {
171 transmit_buffer[0] = 0x23;
172 transmit_pos = 0;
173 transmit_count = 1;
174 command_phase++;
175 dsr_pulse_delay = 256;
176 }
177 break;
178
179 case 1:
180 command = receive_buffer;
181 command_phase++;
182
183 transmit_buffer[0] = 0x5A;
184
185 //if(command != 0x42)
186 // fprintf(stderr, "Gamepad unhandled command: 0x%02x\n", command);
187
188 if(command == 0x42)
189 {
190 transmit_buffer[1] = 0xFF ^ buttons[0];
191 transmit_buffer[2] = 0xFF ^ buttons[1];
192 transmit_buffer[3] = twist; // Twist, 0x00 through 0xFF, 0x80 center.
193 transmit_buffer[4] = anabuttons[0]; // Analog button I, 0x00 through 0xFF, 0x00 = no pressing, 0xFF = max.
194 transmit_buffer[5] = anabuttons[1]; // Analog button II, ""
195 transmit_buffer[6] = anabuttons[2]; // Left shoulder analog button, ""
196 transmit_pos = 0;
197 transmit_count = 7;
198 dsr_pulse_delay = 256;
199 }
200 else
201 {
202 command_phase = -1;
203 transmit_buffer[1] = 0;
204 transmit_buffer[2] = 0;
205 transmit_pos = 0;
206 transmit_count = 0;
207 }
208 break;
209
210 case 2:
211 if(transmit_count > 0)
212 dsr_pulse_delay = 128;
213 break;
214 }
215 }
216
217 return(ret);
218 }
219
220 InputDevice *Device_neGcon_Create(void)
221 {
222 return new InputDevice_neGcon();
223 }
224
225
226 InputDeviceInputInfoStruct Device_neGcon_IDII[21] =
227 {
228 { NULL, "empty", -1, IDIT_BUTTON, NULL },
229 { NULL, "empty", -1, IDIT_BUTTON, NULL },
230 { NULL, "empty", -1, IDIT_BUTTON, NULL },
231 { "start", "START", 4, IDIT_BUTTON, NULL },
232 { "up", "D-Pad UP ↑", 0, IDIT_BUTTON, "down" },
233 { "right", "D-Pad RIGHT →", 3, IDIT_BUTTON, "left" },
234 { "down", "D-Pad DOWN ↓", 1, IDIT_BUTTON, "up" },
235 { "left", "D-Pad LEFT ←", 2, IDIT_BUTTON, "right" },
236
237 { NULL, "empty", -1, IDIT_BUTTON, NULL },
238 { NULL, "empty", -1, IDIT_BUTTON, NULL },
239 { NULL, "empty", -1, IDIT_BUTTON, NULL },
240 { "r", "Right Shoulder", 12, IDIT_BUTTON },
241
242 { "b", "B", 9, IDIT_BUTTON, NULL },
243 { "a", "A", 10, IDIT_BUTTON, NULL },
244 { NULL, "empty", -1, IDIT_BUTTON, NULL },
245 { NULL, "empty", -1, IDIT_BUTTON, NULL },
246
247 { "twist_cwise", "Twist ↓|↑ (Analog, Turn Right)", 6, IDIT_BUTTON_ANALOG },
248 { "twist_ccwise", "Twist ↑|↓ (Analog, Turn Left)", 5, IDIT_BUTTON_ANALOG },
249 { "i", "I (Analog)", 8, IDIT_BUTTON_ANALOG },
250 { "ii", "II (Analog)", 7, IDIT_BUTTON_ANALOG },
251
252 { "l", "Left Shoulder (Analog)", 11, IDIT_BUTTON_ANALOG },
253 };
0 #ifndef __MDFN_PSX_INPUT_NEGCON_H
1 #define __MDFN_PSX_INPUT_NEGCON_H
2
3 InputDevice *Device_neGcon_Create(void);
4 extern InputDeviceInputInfoStruct Device_neGcon_IDII[21];
5
6 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18
19 static uint16_t Asserted;
20 static uint16_t Mask;
21 static uint16_t Status;
22
23 #define Recalc() CPU->AssertIRQ(0, (bool)(Status & Mask))
24
25 void IRQ_Power(void)
26 {
27 Asserted = 0;
28 Status = 0;
29 Mask = 0;
30
31 Recalc();
32 }
33
34 int IRQ_StateAction(void *data, int load, int data_only)
35 {
36 SFORMAT StateRegs[] =
37 {
38 SFVAR(Asserted),
39 SFVAR(Mask),
40 SFVAR(Status),
41 SFEND
42 };
43 int ret = MDFNSS_StateAction(data, load, data_only, StateRegs, "IRQ");
44
45 if(load)
46 {
47 Recalc();
48 }
49
50 return(ret);
51 }
52
53
54 void IRQ_Assert(int which, bool status)
55 {
56 uint32_t old_Asserted = Asserted;
57 //PSX_WARNING("[IRQ] Assert: %d %d", which, status);
58
59 //if(which == IRQ_SPU && status && (Asserted & (1 << which)))
60 // MDFN_DispMessage("SPU IRQ glitch??");
61
62 Asserted &= ~(1 << which);
63
64 if(status)
65 {
66 Asserted |= 1 << which;
67 //Status |= 1 << which;
68 Status |= (old_Asserted ^ Asserted) & Asserted;
69 }
70
71 Recalc();
72 }
73
74
75 void IRQ_Write(uint32_t A, uint32_t V)
76 {
77 // FIXME if we ever have "accurate" bus emulation
78 V <<= (A & 3) * 8;
79
80 //printf("[IRQ] Write: 0x%08x 0x%08x --- PAD TEMP\n", A, V);
81
82 if(A & 4)
83 Mask = V;
84 else
85 {
86 Status &= V;
87 //Status |= Asserted;
88 }
89
90 Recalc();
91 }
92
93
94 uint32_t IRQ_Read(uint32_t A)
95 {
96 uint32_t ret = Status;
97
98 if(A & 4)
99 ret = Mask;
100
101 // FIXME: Might want to move this out to psx.cpp eventually.
102 ret |= 0x1F800000;
103 ret >>= (A & 3) * 8;
104
105 //printf("[IRQ] Read: 0x%08x 0x%08x --- PAD TEMP\n", A, ret);
106
107 return(ret);
108 }
109
110
111 void IRQ_Reset(void)
112 {
113 Asserted = 0;
114 Status = 0;
115 Mask = 0;
116
117 Recalc();
118 }
119
120
121 uint32_t IRQ_GetRegister(unsigned int which, char *special, const uint32_t special_len)
122 {
123 switch(which)
124 {
125 case IRQ_GSREG_ASSERTED:
126 return Asserted;
127 case IRQ_GSREG_STATUS:
128 return Status;
129 case IRQ_GSREG_MASK:
130 return Mask;
131 }
132
133 return 0;
134 }
135
136 void IRQ_SetRegister(unsigned int which, uint32_t value)
137 {
138 switch(which)
139 {
140 case IRQ_GSREG_ASSERTED:
141 Asserted = value;
142 break;
143
144 case IRQ_GSREG_STATUS:
145 Status = value;
146 break;
147
148 case IRQ_GSREG_MASK:
149 Mask = value;
150 break;
151 default:
152 return;
153 }
154
155 Recalc();
156 }
0 #ifndef __MDFN_PSX_IRQ_H
1 #define __MDFN_PSX_IRQ_H
2
3 #include <stdint.h>
4
5 enum
6 {
7 IRQ_VBLANK = 0,
8 IRQ_GPU = 1,
9 IRQ_CD = 2,
10 IRQ_DMA = 3,
11 IRQ_TIMER_0 = 4,
12 IRQ_TIMER_1 = 5,
13 IRQ_TIMER_2 = 6,
14 IRQ_SIO = 7,
15 IRQ_SPU = 9,
16 IRQ_PIO = 10
17 };
18
19 enum
20 {
21 IRQ_GSREG_ASSERTED = 0,
22 IRQ_GSREG_STATUS = 1,
23 IRQ_GSREG_MASK = 2
24 };
25
26 void IRQ_Power(void);
27 void IRQ_Assert(int which, bool asserted);
28
29 void IRQ_Write(uint32_t A, uint32_t V);
30 uint32_t IRQ_Read(uint32_t A);
31
32 uint32_t IRQ_GetRegister(unsigned int which, char *special, const uint32_t special_len);
33 void IRQ_SetRegister(unsigned int which, uint32_t value);
34
35 int IRQ_StateAction(void *data, int load, int data_only);
36
37 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 /*
18 MDEC_READ_FIFO(tfr) vs InCounter vs MDEC_DMACanRead() is a bit fragile right now. Actually, the entire horrible state machine monstrosity is fragile.
19
20 TODO: OutFIFOReady, so <16bpp works right.
21
22 TODO CODE:
23
24 bool InFIFOReady;
25
26 if(InFIFO.CanWrite())
27 {
28 InFIFO.Write(V);
29
30 if(InCommand)
31 {
32 if(InCounter != 0xFFFF)
33 {
34 InCounter--;
35
36 // This condition when InFIFO.CanWrite() != 0 is a bit buggy on real hardware, decoding loop *seems* to be reading too
37 // much and pulling garbage from the FIFO.
38 if(InCounter == 0xFFFF)
39 InFIFOReady = true;
40 }
41
42 if(InFIFO.CanWrite() == 0)
43 InFIFOReady = true;
44 }
45 }
46 */
47
48 // Good test-case games:
49 // Dragon Knight 4(bad disc?)
50 // Final Fantasy 7 intro movie.
51 // GameShark Version 4.0 intro movie; (clever) abuse of DMA channel 0.
52 // SimCity 2000 startup.
53
54
55 #include "psx.h"
56 #include "mdec.h"
57
58 #include "../masmem.h"
59 #include "FastFIFO.h"
60 #include <math.h>
61
62 #if defined(__SSE2__)
63 #include <xmmintrin.h>
64 #include <emmintrin.h>
65 #endif
66
67 #if defined(ARCH_POWERPC_ALTIVEC) && defined(HAVE_ALTIVEC_H)
68 #include <altivec.h>
69 #endif
70
71 static int32 ClockCounter;
72 static unsigned MDRPhase;
73 static FastFIFO<uint32, 0x20> InFIFO;
74 static FastFIFO<uint32, 0x20> OutFIFO;
75
76 static int8 block_y[8][8];
77 static int8 block_cb[8][8]; // [y >> 1][x >> 1]
78 static int8 block_cr[8][8]; // [y >> 1][x >> 1]
79
80 static uint32 Control;
81 static uint32 Command;
82 static bool InCommand;
83
84 static uint8 QMatrix[2][64];
85 static uint32 QMIndex;
86
87 static int16 IDCTMatrix[64] MDFN_ALIGN(16);
88 static uint32 IDCTMIndex;
89
90 static uint8 QScale;
91
92 static int16 Coeff[64] MDFN_ALIGN(16);
93 static uint32 CoeffIndex;
94 static uint32 DecodeWB;
95
96 static union
97 {
98 uint32 pix32[48];
99 uint16 pix16[96];
100 uint8 pix8[192];
101 } PixelBuffer;
102 static uint32 PixelBufferReadOffset;
103 static uint32 PixelBufferCount32;
104
105 static uint16 InCounter;
106
107 static uint8 RAMOffsetY;
108 static uint8 RAMOffsetCounter;
109 static uint8 RAMOffsetWWS;
110
111 static const uint8 ZigZag[64] =
112 {
113 0x00, 0x08, 0x01, 0x02, 0x09, 0x10, 0x18, 0x11,
114 0x0a, 0x03, 0x04, 0x0b, 0x12, 0x19, 0x20, 0x28,
115 0x21, 0x1a, 0x13, 0x0c, 0x05, 0x06, 0x0d, 0x14,
116 0x1b, 0x22, 0x29, 0x30, 0x38, 0x31, 0x2a, 0x23,
117 0x1c, 0x15, 0x0e, 0x07, 0x0f, 0x16, 0x1d, 0x24,
118 0x2b, 0x32, 0x39, 0x3a, 0x33, 0x2c, 0x25, 0x1e,
119 0x17, 0x1f, 0x26, 0x2d, 0x34, 0x3b, 0x3c, 0x35,
120 0x2e, 0x27, 0x2f, 0x36, 0x3d, 0x3e, 0x37, 0x3f,
121 };
122
123 void MDEC_Power(void)
124 {
125 ClockCounter = 0;
126 MDRPhase = 0;
127
128 InFIFO.Flush();
129 OutFIFO.Flush();
130
131 memset(block_y, 0, sizeof(block_y));
132 memset(block_cb, 0, sizeof(block_cb));
133 memset(block_cr, 0, sizeof(block_cr));
134
135 Control = 0;
136 Command = 0;
137 InCommand = false;
138
139 memset(QMatrix, 0, sizeof(QMatrix));
140 QMIndex = 0;
141
142 memset(IDCTMatrix, 0, sizeof(IDCTMatrix));
143 IDCTMIndex = 0;
144
145 QScale = 0;
146
147 memset(Coeff, 0, sizeof(Coeff));
148 CoeffIndex = 0;
149 DecodeWB = 0;
150
151 memset(PixelBuffer.pix32, 0, sizeof(PixelBuffer.pix32));
152 PixelBufferReadOffset = 0;
153 PixelBufferCount32 = 0;
154
155 InCounter = 0;
156
157 RAMOffsetY = 0;
158 RAMOffsetCounter = 0;
159 RAMOffsetWWS = 0;
160 }
161
162 int MDEC_StateAction(StateMem *sm, int load, int data_only)
163 {
164 SFORMAT StateRegs[] =
165 {
166 SFVAR(ClockCounter),
167 SFVAR(MDRPhase),
168
169 #define SFFIFO32(fifoobj) SFARRAY32(&fifoobj.data[0], sizeof(fifoobj.data) / sizeof(fifoobj.data[0])), \
170 SFVAR(fifoobj.read_pos), \
171 SFVAR(fifoobj.write_pos), \
172 SFVAR(fifoobj.in_count)
173
174 SFFIFO32(InFIFO),
175 SFFIFO32(OutFIFO),
176 #undef SFFIFO
177
178 SFARRAY(&block_y[0][0], sizeof(block_y) / sizeof(block_y[0][0])),
179 SFARRAY(&block_cb[0][0], sizeof(block_cb) / sizeof(block_cb[0][0])),
180 SFARRAY(&block_cr[0][0], sizeof(block_cr) / sizeof(block_cr[0][0])),
181
182 SFVAR(Control),
183 SFVAR(Command),
184 SFVAR(InCommand),
185
186 SFARRAY(&QMatrix[0][0], sizeof(QMatrix) / sizeof(QMatrix[0][0])),
187 SFVAR(QMIndex),
188
189 SFARRAY16(&IDCTMatrix[0], sizeof(IDCTMatrix) / sizeof(IDCTMatrix[0])),
190 SFVAR(IDCTMIndex),
191
192 SFVAR(QScale),
193
194 SFARRAY16(&Coeff[0], sizeof(Coeff) / sizeof(Coeff[0])),
195 SFVAR(CoeffIndex),
196 SFVAR(DecodeWB),
197
198 SFARRAY32(&PixelBuffer.pix32[0], sizeof(PixelBuffer.pix32) / sizeof(PixelBuffer.pix32[0])),
199 SFVAR(PixelBufferReadOffset),
200 SFVAR(PixelBufferCount32),
201
202 SFVAR(InCounter),
203
204 SFVAR(RAMOffsetY),
205 SFVAR(RAMOffsetCounter),
206 SFVAR(RAMOffsetWWS),
207
208 SFEND
209 };
210
211 int ret = MDFNSS_StateAction(sm, load, data_only, StateRegs, "MDEC");
212
213 if(load)
214 {
215 InFIFO.SaveStatePostLoad();
216 OutFIFO.SaveStatePostLoad();
217 }
218
219 return(ret);
220 }
221
222 static INLINE int8 Mask9ClampS8(int32 v)
223 {
224 v = sign_x_to_s32(9, v);
225
226 if(v < -128)
227 v = -128;
228
229 if(v > 127)
230 v = 127;
231
232 return v;
233 }
234
235 template<typename T>
236 static void IDCT_1D_Multi(int16 *in_coeff, T *out_coeff)
237 {
238 #if defined(__SSE2__)
239 {
240 for(unsigned col = 0; col < 8; col++)
241 {
242 __m128i c = _mm_load_si128((__m128i *)&in_coeff[(col * 8)]);
243
244 for(unsigned x = 0; x < 8; x++)
245 {
246 __m128i sum;
247 __m128i m;
248 int32 tmp[4] MDFN_ALIGN(16);
249
250 m = _mm_load_si128((__m128i *)&IDCTMatrix[(x * 8)]);
251 sum = _mm_madd_epi16(m, c);
252 sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (3 << 0) | (2 << 2) | (1 << 4) | (0 << 6)));
253 sum = _mm_add_epi32(sum, _mm_shuffle_epi32(sum, (1 << 0) | (0 << 2)));
254
255 //_mm_store_ss((float *)&tmp[0], (__m128)sum);
256 _mm_store_si128((__m128i*)tmp, sum);
257
258 if(sizeof(T) == 1)
259 out_coeff[(col * 8) + x] = Mask9ClampS8((tmp[0] + 0x4000) >> 15);
260 else
261 out_coeff[(x * 8) + col] = (tmp[0] + 0x4000) >> 15;
262 }
263 }
264 }
265 #else
266 for(unsigned col = 0; col < 8; col++)
267 {
268 for(unsigned x = 0; x < 8; x++)
269 {
270 int32 sum = 0;
271
272 for(unsigned u = 0; u < 8; u++)
273 {
274 sum += (in_coeff[(col * 8) + u] * IDCTMatrix[(x * 8) + u]);
275 }
276
277 if(sizeof(T) == 1)
278 out_coeff[(col * 8) + x] = Mask9ClampS8((sum + 0x4000) >> 15);
279 else
280 out_coeff[(x * 8) + col] = (sum + 0x4000) >> 15;
281 }
282 }
283 #endif
284 }
285
286 static void IDCT(int16 *in_coeff, int8 *out_coeff)
287 {
288 int16 tmpbuf[64] MDFN_ALIGN(16);
289
290 IDCT_1D_Multi<int16>(in_coeff, tmpbuf);
291 IDCT_1D_Multi<int8>(tmpbuf, out_coeff);
292 }
293
294 static INLINE void YCbCr_to_RGB(const int8 y, const int8 cb, const int8 cr, int &r, int &g, int &b)
295 {
296 // The formula for green is still a bit off(precision/rounding issues when both cb and cr are non-zero).
297 r = Mask9ClampS8(y + (((359 * cr) + 0x80) >> 8));
298 //g = Mask9ClampS8(y + (((-88 * cb) + (-183 * cr) + 0x80) >> 8));
299 g = Mask9ClampS8(y + ((((-88 * cb) &~ 0x1F) + ((-183 * cr) &~ 0x07) + 0x80) >> 8));
300 b = Mask9ClampS8(y + (((454 * cb) + 0x80) >> 8));
301
302 r ^= 0x80;
303 g ^= 0x80;
304 b ^= 0x80;
305 }
306
307 static INLINE uint16 RGB_to_RGB555(uint8 r, uint8 g, uint8 b)
308 {
309 r = (r + 4) >> 3;
310 g = (g + 4) >> 3;
311 b = (b + 4) >> 3;
312
313 if(r > 0x1F)
314 r = 0x1F;
315
316 if(g > 0x1F)
317 g = 0x1F;
318
319 if(b > 0x1F)
320 b = 0x1F;
321
322 return((r << 0) | (g << 5) | (b << 10));
323 }
324
325 static void EncodeImage(const unsigned ybn)
326 {
327 //printf("ENCODE, %d\n", (Command & 0x08000000) ? 256 : 384);
328
329 PixelBufferCount32 = 0;
330
331 switch((Command >> 27) & 0x3)
332 {
333 case 0: // 4bpp
334 {
335 const uint8 us_xor = (Command & (1U << 26)) ? 0x00 : 0x88;
336 uint8* pix_out = PixelBuffer.pix8;
337
338 for(int y = 0; y < 8; y++)
339 {
340 for(int x = 0; x < 8; x += 2)
341 {
342 uint8 p0 = std::min<int>(127, block_y[y][x + 0] + 8);
343 uint8 p1 = std::min<int>(127, block_y[y][x + 1] + 8);
344
345 *pix_out = ((p0 >> 4) | (p1 & 0xF0)) ^ us_xor;
346 pix_out++;
347 }
348 }
349 PixelBufferCount32 = 8;
350 }
351 break;
352
353
354 case 1: // 8bpp
355 {
356 const uint8 us_xor = (Command & (1U << 26)) ? 0x00 : 0x80;
357 uint8* pix_out = PixelBuffer.pix8;
358
359 for(int y = 0; y < 8; y++)
360 {
361 for(int x = 0; x < 8; x++)
362 {
363 *pix_out = (uint8)block_y[y][x] ^ us_xor;
364 pix_out++;
365 }
366 }
367 PixelBufferCount32 = 16;
368 }
369 break;
370
371 case 2: // 24bpp
372 {
373 const uint8 rgb_xor = (Command & (1U << 26)) ? 0x80 : 0x00;
374 uint8* pix_out = PixelBuffer.pix8;
375
376 for(int y = 0; y < 8; y++)
377 {
378 const int8* by = &block_y[y][0];
379 const int8* cb = &block_cb[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
380 const int8* cr = &block_cr[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
381
382 for(int x = 0; x < 8; x++)
383 {
384 int r, g, b;
385
386 YCbCr_to_RGB(by[x], cb[x >> 1], cr[x >> 1], r, g, b);
387
388 pix_out[0] = r ^ rgb_xor;
389 pix_out[1] = g ^ rgb_xor;
390 pix_out[2] = b ^ rgb_xor;
391 pix_out += 3;
392 }
393 }
394 PixelBufferCount32 = 48;
395 }
396 break;
397
398 case 3: // 16bpp
399 {
400 uint16 pixel_xor = ((Command & 0x02000000) ? 0x8000 : 0x0000) | ((Command & (1U << 26)) ? 0x4210 : 0x0000);
401 uint16* pix_out = PixelBuffer.pix16;
402
403 for(int y = 0; y < 8; y++)
404 {
405 const int8* by = &block_y[y][0];
406 const int8* cb = &block_cb[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
407 const int8* cr = &block_cr[(y >> 1) | ((ybn & 2) << 1)][(ybn & 1) << 2];
408
409 for(int x = 0; x < 8; x++)
410 {
411 int r, g, b;
412
413 YCbCr_to_RGB(by[x], cb[x >> 1], cr[x >> 1], r, g, b);
414
415 StoreU16_LE(pix_out, pixel_xor ^ RGB_to_RGB555(r, g, b));
416 pix_out++;
417 }
418 }
419 PixelBufferCount32 = 32;
420 }
421 break;
422
423 }
424 }
425
426 static INLINE void WriteImageData(uint16 V, int32* eat_cycles)
427 {
428 const uint32 qmw = (bool)(DecodeWB < 2);
429
430 //printf("MDEC DMA SubWrite: %04x, %d\n", V, CoeffIndex);
431
432 if(!CoeffIndex)
433 {
434 if(V == 0xFE00)
435 {
436 //printf("FE00 @ %u\n", DecodeWB);
437 return;
438 }
439
440 QScale = V >> 10;
441
442 {
443 int q = QMatrix[qmw][0]; // No QScale here!
444 int ci = sign_10_to_s16(V & 0x3FF);
445 int tmp;
446
447 if(q != 0)
448 tmp = (int32)((uint32)(ci * q) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
449 else
450 tmp = (uint32)(ci * 2) << 4;
451
452 // Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
453 Coeff[ZigZag[0]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
454 CoeffIndex++;
455 }
456 }
457 else
458 {
459 if(V == 0xFE00)
460 {
461 while(CoeffIndex < 64)
462 Coeff[ZigZag[CoeffIndex++]] = 0;
463 }
464 else
465 {
466 uint32 rlcount = V >> 10;
467
468 for(uint32 i = 0; i < rlcount && CoeffIndex < 64; i++)
469 {
470 Coeff[ZigZag[CoeffIndex]] = 0;
471 CoeffIndex++;
472 }
473
474 if(CoeffIndex < 64)
475 {
476 int q = QScale * QMatrix[qmw][CoeffIndex];
477 int ci = sign_10_to_s16(V & 0x3FF);
478 int tmp;
479
480 if(q != 0)
481 tmp = (int32)((uint32)((ci * q) >> 3) << 4) + (ci ? ((ci < 0) ? 8 : -8) : 0);
482 else
483 tmp = (uint32)(ci * 2) << 4;
484
485 // Not sure if it should be 0x3FFF or 0x3FF0 or maybe 0x3FF8?
486 Coeff[ZigZag[CoeffIndex]] = std::min<int>(0x3FFF, std::max<int>(-0x4000, tmp));
487 CoeffIndex++;
488 }
489 }
490 }
491
492 if(CoeffIndex == 64)
493 {
494 CoeffIndex = 0;
495
496 //printf("Block %d finished\n", DecodeWB);
497
498 switch(DecodeWB)
499 {
500 case 0:
501 IDCT(Coeff, &block_cr[0][0]);
502 break;
503 case 1:
504 IDCT(Coeff, &block_cb[0][0]);
505 break;
506 case 2:
507 case 3:
508 case 4:
509 case 5:
510 IDCT(Coeff, &block_y[0][0]);
511 break;
512 }
513
514 // Timing in the actual PS1 MDEC is complex due to (apparent) pipelining, but the average when decoding a large number of blocks is
515 // about 512. We'll go with a lower value here to be conservative due to timing granularity and other timing deficiencies in Mednafen. BUT, don't
516 // go lower than 460, or Parasite Eve 2's 3D models will stutter like crazy during FMV-background sequences.
517 //
518 *eat_cycles += 474;
519
520 if(DecodeWB >= 2)
521 EncodeImage((DecodeWB + 4) % 6);
522
523 DecodeWB++;
524 if(DecodeWB == (((Command >> 27) & 2) ? 6 : 3))
525 DecodeWB = ((Command >> 27) & 2) ? 0 : 2;
526 }
527 }
528
529 void MDEC_Run(int32 clocks)
530 {
531 static const unsigned MDRPhaseBias = 0 + 1;
532
533 //MDFN_DispMessage("%u", OutFIFO.CanRead());
534
535 ClockCounter += clocks;
536
537 if(ClockCounter > 128)
538 {
539 //if(MDRPhase != 0)
540 // printf("SNORT: %d\n", ClockCounter);
541 ClockCounter = 128;
542 }
543
544 switch(MDRPhase + MDRPhaseBias)
545 {
546 for(;;)
547 {
548 InCommand = false;
549 { { case 1: if(!(InFIFO.CanRead())) { MDRPhase = 2 - MDRPhaseBias - 1; return; } }; Command = InFIFO.Read(); };
550 InCommand = true;
551 { ClockCounter -= (1); { case 3: if(!(ClockCounter > 0)) { MDRPhase = 4 - MDRPhaseBias - 1; return; } }; };
552
553 //printf("****************** Command: %08x, %02x\n", Command, Command >> 29);
554
555 //
556 //
557 //
558 if(((Command >> 29) & 0x7) == 1)
559 {
560 InCounter = Command & 0xFFFF;
561 OutFIFO.Flush();
562 //OutBuffer.Flush();
563
564 PixelBufferCount32 = 0;
565 CoeffIndex = 0;
566
567 if((Command >> 27) & 2)
568 DecodeWB = 0;
569 else
570 DecodeWB = 2;
571
572 switch((Command >> 27) & 0x3)
573 {
574 case 0:
575 case 1: RAMOffsetWWS = 0; break;
576 case 2: RAMOffsetWWS = 6; break;
577 case 3: RAMOffsetWWS = 4; break;
578 }
579 RAMOffsetY = 0;
580 RAMOffsetCounter = RAMOffsetWWS;
581
582 InCounter--;
583 do
584 {
585 uint32 tfr;
586 int32 need_eat; // = 0;
587
588 { { case 5: if(!(InFIFO.CanRead())) { MDRPhase = 6 - MDRPhaseBias - 1; return; } }; tfr = InFIFO.Read(); };
589 InCounter--;
590
591 // printf("KA: %04x %08x\n", InCounter, tfr);
592
593 need_eat = 0;
594 PixelBufferCount32 = 0;
595 WriteImageData(tfr, &need_eat);
596 WriteImageData(tfr >> 16, &need_eat);
597
598 { ClockCounter -= (need_eat); { case 7: if(!(ClockCounter > 0)) { MDRPhase = 8 - MDRPhaseBias - 1; return; } }; };
599
600 PixelBufferReadOffset = 0;
601 while(PixelBufferReadOffset != PixelBufferCount32)
602 {
603 { { case 9: if(!(OutFIFO.CanWrite())) { MDRPhase = 10 - MDRPhaseBias - 1; return; } }; OutFIFO.Write(LoadU32_LE(&PixelBuffer.pix32[PixelBufferReadOffset++])); };
604 }
605 } while(InCounter != 0xFFFF);
606 }
607 //
608 //
609 //
610 else if(((Command >> 29) & 0x7) == 2)
611 {
612 QMIndex = 0;
613 InCounter = 0x10 + ((Command & 0x1) ? 0x10 : 0x00);
614
615 InCounter--;
616 do
617 {
618 uint32 tfr;
619
620 { { case 11: if(!(InFIFO.CanRead())) { MDRPhase = 12 - MDRPhaseBias - 1; return; } }; tfr = InFIFO.Read(); };
621 InCounter--;
622
623 //printf("KA: %04x %08x\n", InCounter, tfr);
624
625 for(int i = 0; i < 4; i++)
626 {
627 QMatrix[QMIndex >> 6][QMIndex & 0x3F] = (uint8)tfr;
628 QMIndex = (QMIndex + 1) & 0x7F;
629 tfr >>= 8;
630 }
631 } while(InCounter != 0xFFFF);
632 }
633 //
634 //
635 //
636 else if(((Command >> 29) & 0x7) == 3)
637 {
638 IDCTMIndex = 0;
639 InCounter = 0x20;
640
641 InCounter--;
642 do
643 {
644 uint32 tfr;
645
646 { { case 13: if(!(InFIFO.CanRead())) { MDRPhase = 14 - MDRPhaseBias - 1; return; } }; tfr = InFIFO.Read(); };
647 InCounter--;
648
649 for(unsigned i = 0; i < 2; i++)
650 {
651 IDCTMatrix[((IDCTMIndex & 0x7) << 3) | ((IDCTMIndex >> 3) & 0x7)] = (int16)(tfr & 0xFFFF) >> 3;
652 IDCTMIndex = (IDCTMIndex + 1) & 0x3F;
653
654 tfr >>= 16;
655 }
656 } while(InCounter != 0xFFFF);
657 }
658 else
659 {
660 InCounter = Command & 0xFFFF;
661 }
662 } // end for(;;)
663 }
664 }
665
666 void MDEC_DMAWrite(uint32 V)
667 {
668 if(!InFIFO.CanWrite())
669 return;
670
671 InFIFO.Write(V);
672 MDEC_Run(0);
673 }
674
675 uint32 MDEC_DMARead(uint32* offs)
676 {
677 uint32 V = 0;
678
679 *offs = 0;
680
681 if(MDFN_LIKELY(OutFIFO.CanRead()))
682 {
683 V = OutFIFO.Read();
684
685 *offs = (RAMOffsetY & 0x7) * RAMOffsetWWS;
686
687 if(RAMOffsetY & 0x08)
688 {
689 *offs = (*offs - RAMOffsetWWS*7);
690 }
691
692 RAMOffsetCounter--;
693 if(!RAMOffsetCounter)
694 {
695 RAMOffsetCounter = RAMOffsetWWS;
696 RAMOffsetY++;
697 }
698
699 MDEC_Run(0);
700 }
701
702 return(V);
703 }
704
705 bool MDEC_DMACanWrite(void)
706 {
707 return((InFIFO.CanWrite() >= 0x20) && (Control & (1U << 30)) && InCommand && InCounter != 0xFFFF);
708 }
709
710 bool MDEC_DMACanRead(void)
711 {
712 return((OutFIFO.CanRead() >= 0x20) && (Control & (1U << 29)));
713 }
714
715 void MDEC_Write(const int32_t timestamp, uint32 A, uint32 V)
716 {
717 //PSX_WARNING("[MDEC] Write: 0x%08x 0x%08x, %d --- %u %u", A, V, timestamp, InFIFO.CanRead(), OutFIFO.CanRead());
718 if(A & 4)
719 {
720 if(V & 0x80000000) // Reset?
721 {
722 MDRPhase = 0;
723 InCounter = 0;
724 Command = 0;
725 InCommand = false;
726
727 PixelBufferCount32 = 0;
728 ClockCounter = 0;
729 QMIndex = 0;
730 IDCTMIndex = 0;
731
732 QScale = 0;
733
734 memset(Coeff, 0, sizeof(Coeff));
735 CoeffIndex = 0;
736 DecodeWB = 0;
737
738 InFIFO.Flush();
739 OutFIFO.Flush();
740 }
741 Control = V & 0x7FFFFFFF;
742 }
743 else
744 {
745 if(InFIFO.CanWrite())
746 {
747 InFIFO.Write(V);
748
749 if(!InCommand)
750 {
751 if(ClockCounter < 1)
752 ClockCounter = 1;
753 }
754 MDEC_Run(0);
755 }
756 }
757 }
758
759 uint32 MDEC_Read(const int32_t timestamp, uint32 A)
760 {
761 uint32 ret = 0;
762
763 if(A & 4)
764 {
765 ret = 0;
766
767 ret |= (OutFIFO.CanRead() == 0) << 31;
768 ret |= (InFIFO.CanWrite() == 0) << 30;
769 ret |= InCommand << 29;
770
771 ret |= MDEC_DMACanWrite() << 28;
772 ret |= MDEC_DMACanRead() << 27;
773
774 ret |= ((Command >> 25) & 0xF) << 23;
775
776 // Needs refactoring elsewhere to work right: ret |= ((DecodeWB + 4) % 6) << 16;
777
778 ret |= InCounter & 0xFFFF;
779 }
780 else
781 {
782 if(OutFIFO.CanRead())
783 ret = OutFIFO.Read();
784 }
785
786 //PSX_WARNING("[MDEC] Read: 0x%08x 0x%08x -- %d %d", A, ret, InputBuffer.CanRead(), InCounter);
787
788 return(ret);
789 }
0 #ifndef __MDFN_PSX_MDEC_H
1 #define __MDFN_PSX_MDEC_H
2
3 void MDEC_DMAWrite(uint32_t V);
4
5 uint32_t MDEC_DMARead(uint32_t *offs);
6
7 void MDEC_Write(const int32_t timestamp, uint32_t A, uint32_t V);
8 uint32_t MDEC_Read(const int32_t timestamp, uint32_t A);
9
10 void MDEC_Power(void);
11
12 bool MDEC_DMACanWrite(void);
13 bool MDEC_DMACanRead(void);
14 void MDEC_Run(int32 clocks);
15
16 int MDEC_StateAction(StateMem *sm, int load, int data_only);
17
18 #endif
0 Capcom games(MMX4, MMX5, etc) - Sensitive about CD access and XA timing(XA playback problems).
1
2 Viewpoint - Extra-sensitive about GPU LL DMA timing? (It was generating exceptions for some timings...)
0 ***Major issues***
1
2 Tomb Raider(PAL)
3 (reported, and confirmed) "was fighting Tomb Raider PAL this night, when you get out of pool in Lara's home the game
4 bugs out: issues GetlocP, waits for it to complete and expects seek to be NOT complete (i.e. older location)"
5 Thoughts on emulating:
6 CalcSpinupTime()
7 DS_SPINUP
8 StatusAfterSpinup ORRR we could scrap that StatusAfter* idea and have some kind of fancy function callback system...
9
10 Monkey Hero
11 Locks up shortly after title screen. It's straddling a framebuffer write command's parameters across two linked-list
12 blocks(2 words at the end of the first block, and 1 word at the beginning of the next block). AFAIK, this construct will only
13 work on the real thing under *very* strict timing constraints. Probably explains why it reportedly doesn't work on the PS2.
14 It's as easy to fix as changing a certain 2 to a 3 in the GPU command table, and probably won't break anything,
15 but I'm still reluctant to do it...
16
17 Simple 1500 Series Vol. 057 - The Maze
18 Locks up during startup; looks to be poorly programmed and extremely sensitive to seek timing.
19
20 Transformers - Beast Wars Transmetals
21 Locks up during loading screen. (CD timing issue)
22 It looks like a terrible game though, at least.
23
24 ----------------------------------------------------------------------------------------------
25
26 ***Medium issues***
27
28 Championship Motocross 2001
29 Invisible driver. GHOSTRIDER~ The palette data in RAM is apparently being selectively zero'd out between
30 the DMA from CDC and the DMA to GPU for some reason. Timing issue related maybe? (Probably CPU instruction timing issue)
31
32 Nicktoons Racing
33 Totally fubared sound effects. Likely CPU instruction timing-related(decreasing the IPC fixes this problem), or perhaps timing
34 related to SPU RAM writes?
35
36 Resident Evil - Director's Cut(non-Dual Shock-version)
37 Controller configuration screen pops up on some screen transitions; probably one of those stupid seek timing-related issues.
38
39 -----------------------------------------------------------------------------------------------
40
41 ***Lesser issues***
42
43 Final Fantasy 8
44 Reported 3D model(character) flicker at some points in the game - look into it.
45
46 Tactics Ogre
47 Menu/Overlay elements on the map screen periodically flicker; seems to be a timing thing probably related to the sound engine
48 in the game. Although upon further inspection, it may be a GPU command timing issue in that we're emulating the GPU primitive
49 drawing faster than occurs on an actual PS1. Might require texture cache simulation to some degree.
50
51 Castrol Honda Superbike Racing
52 Graphical glitches on startup, menus(fixed now probably), and loading screens. (What is with all
53 these racing games having weird timing-related problems, it's like some sort of curse)
54
55 Vigilante 8
56 Has weird red and green(and a few blue) garbage pixels in patches sometimes during gameplay; "garbage" pixel placement
57 is somewhat sparse, so it might not even be noticeable if it were to occur on a PS1 with composite or S-video output, due to limited
58 chroma bandwidth.
59
60 Final Fantasy 7
61 "Sony Computer blah blah" game startup image is a bit glitchy; interlacing-related glitch. That part is really sensitive to CPU, GPU, DMA,
62 and RAM timing...
63
64 Adventures of Lomax, The
65 "QSOUND" loading screen during startup is a flickery mess; interlacing-related glitch from the looks of it.
66 Maybe it's like that on an actual PS1 too?
67
68 Nightmare Creatures
69 BIOS reverb sound excessively contaminates beginning of game.
70
71 Shadow Master
72 Might have broken startup images.
73
74 WipeOut 3
75 Music stops playing after a long while; maybe it's supposed to do that?
76
77 -----------------------------------------------------------------------------------------------
78
79 ***Chaotic timing issues(listed here for reference and testing after any future timing tweaks or improvements)***
80
81 Battle Arena Toshinden
82 NBA Jam Extreme
83 Zero Divide
84 Run too fast if CPU and(/or?) GPU operations execute too fast. Probably not an issue anymore, but still
85 listed here for reference.
86
87 iS: Internal Section
88 Arcade Party Pak (Toobin)
89 Next Tetris, The
90 Extremely sensitive about interlacing semantics, especially in regards to the high bit of the GPU status register when entering
91 interlaced 480-height mode.
92
93 Ballblazer Champions
94 Excessively sensitive to timing issues; might lock up during startup sometimes.
95
96 FIFA - Road to Worldcup 98 (USA)
97 Used to lock up during startup; probably CPU instruction timing-related, or MDEC timing related,
98 or CDC timing related, or DMA timing related, or maybe the moon phase is to blame!
99
100 [CDC] WARNING: Interrupting command 0x02, phase=0, timeleft=1195 with command=0x02
101 [CDC] Bad number(5) of args(first check) for command 0x02
102 0x39 0x23 0x22 0x41 0x67
103
104 Freestyle Motocross: McGrath vs. Pastrana
105 Used to suffer from random fairly long(but finite) freezes during gameplay. Possibly CPU instruction-timing
106 related. Possibly CDC-timing related.
107
108 [CDC] Command: ReadN ---
109 [CDC] Command: Standby ---
110 [CDC] Command: Nop ---
111 [CDC] Command: Setmode --- 0xa0
112 [CDC] Command: Setloc --- 0x08 0x13 0x53
113 [CDC] Command: ReadN ---
114 20076
115 [CDC] Command: Standby ---
116 [CDC] Command: Nop ---
117 [CDC] Command: Setmode --- 0xa0
118 [CDC] Command: Setloc --- 0x08 0x13 0x61
119 0x800668B8
120
121 Resident Evil 2
122 Lockup on second disc in a certain place; probably related to seek timing. Seems to be fixed now, but still listed
123 here for reference.
124
125
126 Nightmare Creatures
127 Shoddy CD reading code that's unreasonably sensitive to CD access timings. It's a wonder it even ever works on an actual
128 PS1(my copy of it certainly doesn't).
129
130 Wing Commander 4
131 Used to lock up sometimes during FMV sequences(might be sensitive to seek delays or SPU IRQ timings).
132
133 -----------------------------------------------------------------------------------------------
134
135 Star Wars Dark Forces notes(for working towards removing a kludge/hack in the DMA IRQ handling)
136 PC=0x8001B124: [DMA] Write: 1f8010f4 008a0000, DMAIntStatus=0000000c
137 if(V == 0x008a0000 && DMAIntStatus == 0x0000000c)
138 DBG_Break(); // V |= 8 << 24; //V |= 4 << 24;
139
140 Add a means of grabbing and passing CIRC data, when using a physical CD, from Mednafen core to the PSX module so that the correct
141 subheader fields can be chosen when there is a mismatch between the two instances of each field during XA ADPCM playback.
142
143 Ensure(long-term, IE a note to the FUTURE) that input device state is latched in independent variables at the start of the
144 input device's handling of a state read command, so that when games are reading device state across an MDFNI_Emulate() boundary, the
145 data won't change in the middle, which could hypothetically cause problems in some rare circumstances(and make entering
146 button combos in games more finicky).
147
148 Respect device(GPU, SPU, etc.) DMA mode/memory access mode bits(more for homebrew's sake than commercial games').
149
150 Test if Dual Analog vibration compatibility mode can be restored with DualShock after using DualShock extended features if the "Analog"
151 mode button on the gamepad is pressed after the extended features are used.
152
153 Test time delta between GPU LL DMA end and GPU non-busy status for various primitive types in sequence on a PS1.
154
155 Test IRQ and COP0 latencies; PSX IRQ controller latency, software IRQ bit latency, latency of both relevant COP0 IRQ enable bits.
156
157 Test IRQ with LWC2.
158
159 Test IRQ with COP0 instructions(interrupted execution or not?).
160
161 Determine maximum quad height and width. See if drawing is an all-or-nothing thing, or if one triangle of the pair will still be drawn
162 if it's not too large.
163
164 Test 0x0 and 1x1 polygon throughput for all triangle and quad drawing commands.
165
166 Fix line drawing algorithm to match test results on the real thing.
167
168
169 The SPU in the PS1 might sometimes drop voice-on events when playing an ADPCM block that loops to itself(and was also the first and only
170 ADPCM block, at least in the test program I noticed the issue in); investigate further.
171
172
173
174 Make sure debugger COPn disassembly is correct(no typos or whatnot).
0 Sources of helpful information used in PS1 emulation(though some of it, especially older compiled information,
1 is wrong to some degree or incomplete, but it's still useful):
2
3 PCSX(and derivatives/forks)
4 MAME/MESS
5 P.E.Op.S
6
7 Blade Lib
8 psxsdk
9
10 doomed's PSX documents
11 bITmASTER's document
12 Neill Corlett's SPU documents
13 T.Fujita's SIO documents
14 ChrlyMac
15 Exophase
16 mizvekov
17 notaz
18 pSXAuthor
19 smf(blog)
20 shalma(forum posts, changelogs)
21 drhell's site
22 jac's CD-XA document
23 "The PlayStation 1 Video (STR) Format" - M. Sabin
24 Various PS1 emulator compatibility lists(for identifying problematic games)
25
26
27 MIPS RISC Architecture - Gerry Kane (1st and 2nd editions)
28 MIPS Programmer's Handbook, The
29
30 -----------
31 General(non-PS1-specific) CD/CDROM information and code:
32
33 SCSI-3 Multimedia Commands Revision 10A
34 ECMA-130
35
36 cdrdao
37 dvdisaster
0 Castlevania Chronicles - Music.
1 Chrono Cross - FMV.
2 Dance Dance Revolution - Gameplay music.
3 Dance Dance Revolution: Disney Mix - Gameplay music.
4 Eithea - Sneaky evil usage, along with manual loop address override abuse.
5 Koudelka
6 Legend of Mana - FMV(really finicky about DMA timing).
7 Medal of Honor
8 Misadventures of Tron Bonne - Dialogue.
9 Nicktoons Racing - FMV, gameplay music.
10 Tales of Destiny - Battle voices. Japanese version 1.0 is particularly sensitive to how SPU IRQs are emulated, and tends to lock up after Mary's "Moushuuken" is used if emulated improperly.
11 Thousand Arms - Dialogue.
12 Um Jammer Lammy
13 Valkyrie Profile - Used extensively for dialogue, in-battle and out.
14 Wing Commander 4 - FMV.
0 #include <stdio.h>
1 #include <inttypes.h>
2 #include <stdlib.h>
3
4 typedef int8_t int8;
5 typedef int16_t int16;
6 typedef int32_t int32;
7 typedef int64_t int64;
8
9 typedef uint8_t uint8;
10 typedef uint16_t uint16;
11 typedef uint32_t uint32;
12 typedef uint64_t uint64;
13
14 #define INLINE inline
15
16 static INLINE int64 MakePolyXFP(int32 x)
17 {
18 return ((int64)x << 32) + ((1LL << 32) - (1 << 11));
19 }
20
21 static INLINE int64 MakePolyXFPStep(int32 dx, int32 dy)
22 {
23 int64 ret;
24 int64 dx_ex = (int64)dx << 32;
25
26 if(dx_ex < 0)
27 dx_ex -= dy - 1;
28
29 if(dx_ex > 0)
30 dx_ex += dy - 1;
31
32 ret = dx_ex / dy;
33
34 return(ret);
35 }
36
37 static INLINE int32 GetPolyXFP_Int(int64 xfp)
38 {
39 return(xfp >> 32);
40 }
41
42
43 // Test X delta of -1023 ... 1023
44 // Test Y delta of 1 ... 511
45 int main()
46 {
47 for(int xbase = -1; xbase < 1025; xbase += 1025)
48 {
49 for(int dx = -1023; dx <= 1023; dx++)
50 {
51 for(int dy = 1; dy <= 511; dy++)
52 {
53 int64 x_coord, x_step;
54 int32 alt_x_coord;
55 int32 alt_x_error;
56
57 x_coord = MakePolyXFP(xbase);
58 x_step = MakePolyXFPStep(dx, dy);
59
60 alt_x_coord = xbase;
61
62 if(dx >= 0)
63 alt_x_error = dy - 1;
64 else
65 alt_x_error = 0;
66
67 for(int step = 0; step < dy; step++)
68 {
69 if(GetPolyXFP_Int(x_coord) != alt_x_coord)
70 {
71 printf("xbase=%d, dx=%d, dy=%d, step=%d --- xfpx=%d, altx=%d\n", xbase, dx, dy, step, GetPolyXFP_Int(x_coord), alt_x_coord);
72 }
73 x_coord += x_step;
74
75 alt_x_error += abs(dx);
76 while(alt_x_error >= dy)
77 {
78 if(dx < 0)
79 alt_x_coord--;
80 else
81 alt_x_coord++;
82 alt_x_error -= dy;
83 }
84 }
85 }
86 }
87 }
88 }
0 #ifndef __MDFN_PSX_PSX_H
1 #define __MDFN_PSX_PSX_H
2
3 #include "../mednafen.h"
4 #include "../masmem.h"
5 #include "../include/trio/trio.h"
6
7 #include "../cdrom/cdromif.h"
8 #include "../general.h"
9 #include "../FileStream.h"
10
11 // Comment out these 2 defines for extra speeeeed.
12 #define PSX_DBGPRINT_ENABLE 1
13 #define PSX_EVENT_SYSTEM_CHECKS 1
14
15 // It's highly unlikely the user will want these if they're intentionally compiling without the debugger.
16 #ifndef WANT_DEBUGGER
17 #undef PSX_DBGPRINT_ENABLE
18 #undef PSX_EVENT_SYSTEM_CHECKS
19 #endif
20
21 #define PSX_DBG_ERROR 0 // Emulator-level error.
22 #define PSX_DBG_WARNING 1 // Warning about game doing questionable things/hitting stuff that might not be emulated correctly.
23 #define PSX_DBG_BIOS_PRINT 2 // BIOS printf/putchar output.
24 #define PSX_DBG_SPARSE 3 // Sparse(relatively) information debug messages(CDC commands).
25 #define PSX_DBG_FLOOD 4 // Heavy informational debug messages(GPU commands; TODO).
26
27 #if PSX_DBGPRINT_ENABLE
28 void PSX_DBG(unsigned level, const char *format, ...) throw() MDFN_COLD MDFN_FORMATSTR(printf, 2, 3);
29
30 #define PSX_WARNING(format, ...) { PSX_DBG(PSX_DBG_WARNING, format "\n", ## __VA_ARGS__); }
31 #define PSX_DBGINFO(format, ...) { }
32 #else
33 static void PSX_DBG(unsigned level, const char* format, ...) { }
34 static void PSX_WARNING(const char* format, ...) { }
35 static void PSX_DBGINFO(const char* format, ...) { }
36 #endif
37
38 bool MDFN_FASTCALL PSX_EventHandler(const int32_t timestamp);
39
40 void MDFN_FASTCALL PSX_MemWrite8(int32_t timestamp, uint32_t A, uint32_t V);
41 void MDFN_FASTCALL PSX_MemWrite16(int32_t timestamp, uint32_t A, uint32_t V);
42 void MDFN_FASTCALL PSX_MemWrite24(int32_t timestamp, uint32_t A, uint32_t V);
43 void MDFN_FASTCALL PSX_MemWrite32(int32_t timestamp, uint32_t A, uint32_t V);
44
45 uint8_t MDFN_FASTCALL PSX_MemRead8(int32_t &timestamp, uint32_t A);
46 uint16_t MDFN_FASTCALL PSX_MemRead16(int32_t &timestamp, uint32_t A);
47 uint32_t MDFN_FASTCALL PSX_MemRead24(int32_t &timestamp, uint32_t A);
48 uint32_t MDFN_FASTCALL PSX_MemRead32(int32_t &timestamp, uint32_t A);
49
50 uint8_t PSX_MemPeek8(uint32_t A);
51 uint16_t PSX_MemPeek16(uint32_t A);
52 uint32_t PSX_MemPeek32(uint32_t A);
53
54 // Should write to WO-locations if possible
55 #if 0
56 void PSX_MemPoke8(uint32_t A, uint8_t V);
57 void PSX_MemPoke16(uint32_t A, uint16_t V);
58 void PSX_MemPoke32(uint32_t A, uint32_t V);
59 #endif
60
61 void PSX_RequestMLExit(void);
62 void ForceEventUpdates(const int32_t timestamp);
63
64 enum
65 {
66 PSX_EVENT__SYNFIRST = 0,
67 PSX_EVENT_GPU,
68 PSX_EVENT_CDC,
69 //PSX_EVENT_SPU,
70 PSX_EVENT_TIMER,
71 PSX_EVENT_DMA,
72 PSX_EVENT_FIO,
73 PSX_EVENT__SYNLAST,
74 PSX_EVENT__COUNT
75 };
76
77 #define PSX_EVENT_MAXTS 0x20000000
78 void PSX_SetEventNT(const int type, const int32_t next_timestamp);
79
80 void PSX_SetDMACycleSteal(unsigned stealage);
81
82 void PSX_GPULineHook(const int32_t timestamp, const int32_t line_timestamp, bool vsync, uint32_t *pixels, const MDFN_PixelFormat* const format, const unsigned width, const unsigned pix_clock_offset, const unsigned pix_clock, const unsigned pix_clock_divide);
83
84 uint32_t PSX_GetRandU32(uint32_t mina, uint32_t maxa);
85
86 #include "dis.h"
87 #include "cpu.h"
88 #include "irq.h"
89 #include "gpu.h"
90 #include "dma.h"
91 #include "debug.h"
92
93 class PS_CDC;
94 class PS_SPU;
95
96 extern PS_CPU *CPU;
97 extern PS_GPU *GPU;
98 extern PS_CDC *CDC;
99 extern PS_SPU *SPU;
100 extern MultiAccessSizeMem<2048 * 1024, uint32_t, false> MainRAM;
101
102 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "sio.h"
19
20 // Dummy implementation.
21
22 static uint16_t Status;
23 static uint16_t Mode;
24 static uint16_t Control;
25 static uint16_t BaudRate;
26 static uint32_t DataBuffer;
27
28 void SIO_Power(void)
29 {
30 Status = 0;
31 Mode = 0;
32 Control = 0;
33 BaudRate = 0;
34 DataBuffer = 0;
35 }
36
37 uint32_t SIO_Read(int32_t timestamp, uint32_t A)
38 {
39 uint32_t ret = 0;
40
41 switch(A & 0xE)
42 {
43 case 0x0:
44 //case 0x2:
45 ret = DataBuffer >> ((A & 2) * 8);
46 break;
47
48 case 0x4:
49 ret = Status;
50 break;
51
52 case 0x8:
53 ret = Mode;
54 break;
55
56 case 0xA:
57 ret = Control;
58 break;
59
60 case 0xE:
61 ret = BaudRate;
62 break;
63 default:
64 #if 0
65 PSX_WARNING("[SIO] Unknown read: 0x%08x -- %d\n", A, timestamp);
66 #endif
67 break;
68 }
69
70 return (ret >> ((A & 1) * 8));
71 }
72
73 void SIO_Write(int32_t timestamp, uint32_t A, uint32_t V)
74 {
75 V <<= (A & 1) * 8;
76
77 switch(A & 0xE)
78 {
79
80 case 0x0:
81 //case 0x2:
82 V <<= (A & 2) * 8;
83 DataBuffer = V;
84 break;
85
86 case 0x8:
87 Mode = V;
88 break;
89
90 case 0xA:
91 Control = V;
92 break;
93
94 case 0xE:
95 BaudRate = V;
96 break;
97 default:
98 #if 0
99 PSX_WARNING("[SIO] Unknown write: 0x%08x 0x%08x -- %d\n", A, V, timestamp);
100 #endif
101 break;
102 }
103 }
104
105 int SIO_StateAction(void *data, int load, int data_only)
106 {
107 SFORMAT StateRegs[] =
108 {
109 SFVAR(Status),
110 SFVAR(Mode),
111 SFVAR(Control),
112 SFVAR(BaudRate),
113 SFVAR(DataBuffer),
114
115 SFEND
116 };
117 int ret = MDFNSS_StateAction(data, load, data_only, StateRegs, "SIO");
118
119 if(load)
120 {
121
122 }
123
124 return(ret);
125 }
0 #ifndef __MDFN_PSX_SIO_H
1 #define __MDFN_PSX_SIO_H
2
3 #include <stdint.h>
4
5 void SIO_Write(int32_t timestamp, uint32_t A, uint32_t V);
6 uint32_t SIO_Read(int32_t timestamp, uint32_t A);
7 void SIO_Power(void);
8
9 int SIO_StateAction(void *data, int load, int data_only);
10
11 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 /* TODO:
18 Note to self: Emulating the SPU at more timing accuracy than sample, and emulating the whole SPU RAM write port FIFO thing and hypothetical periodic FIFO commit to
19 SPU RAM(maybe every 32 CPU cycles, with exceptions?) will likely necessitate a much more timing-accurate CPU core, and emulation of the SPU delay register(or at least the
20 effects of the standard value written to it), to avoid game glitches. Probably more trouble than it's worth....
21
22 SPU IRQ emulation isn't totally correct, behavior is kind of complex; run more tests on PS1.
23
24 Test reverb upsampler on the real thing.
25
26 Alter reverb algorithm to process in the pattern of L,R,L,R,L,R on each input sample, instead of doing both L and R on every 2 input samples(make
27 sure the real thing does it this way too, I think it at least runs the downsampler this way).
28
29 Alter reverb algorithm to perform saturation more often, as occurs on the real thing.
30
31 See if sample flag & 0x8 does anything weird, like suppressing the program-readable block end flag setting.
32
33 Determine the actual purpose of global register 0x2C(is it REALLY an address multiplier? And if so, does it affect the reverb offsets too?)
34
35 For ADSR and volume sweep, should the divider be reset to 0 on &0x8000 == true, or should the upper bit be cleared?
36
37 Should shift occur on all stages of ADPCM sample decoding, or only at the end?
38
39 On the real thing, there's some kind of weirdness with ADSR when you voice on when attack_rate(raw) = 0x7F; the envelope level register is repeatedly
40 reset to 0, which you can see by manual writes to the envelope level register. Normally in the attack phase when attack_rate = 0x7F, enveloping is effectively stuck/paused such that the value you write is sticky and won't be replaced or reset. Note that after you voice on, you can write a new attack_rate < 0x7F, and enveloping will work "normally" again shortly afterwards. You can even write an attack_rate of 0x7F at that point to pause enveloping clocking. I doubt any games rely on this, but it's something to keep in mind if we ever need greater insight as to how the SPU functions at a low-level in order to emulate it at cycle granularity rather than sample granularity, and it may not be a bad idea to investigate this oddity further and emulate it in the future regardless.
41
42 Voice 1 and 3 waveform output writes to SPURAM might not be correct(noted due to problems reading this area of SPU RAM on the real thing
43 based on my expectations of how this should work).
44 */
45
46 /*
47 Notes:
48
49 All addresses(for 16-bit access, at least) within the SPU address space appear to be fully read/write as if they were RAM, though
50 values at some addresses(like the envelope current value) will be "overwritten" by the sound processing at certain times.
51
52 32-bit and 8-bit reads act as if it were RAM(not tested with all addresses, but a few, assuming the rest are the same), but 8-bit writes
53 to odd addresses appear to be ignored, and 8-bit writes to even addresses are treated as 16-bit writes(most likely, but, need to code custom assembly to
54 fully test the upper 8 bits). NOTE: the preceding information doesn't necessarily cover accesses with side effects, they still need to be tested; and it
55 of course covers reads/writes from the point of view of software running on the CPU.
56
57 It doesn't appear to be possible to enable FM on the first channel/voice(channel/voice 0).
58
59 Lower bit of channel start address appears to be masked out to 0(such that ADPCM block decoding is always 8 16-bit units, 16 bytes, aligned), as far as
60 block-decoding and flag-set program-readable loop address go.
61 */
62
63 /*
64 Update() isn't called on Read and Writes for performance reasons, it's called with sufficient granularity from the event
65 system, though this will obviously need to change if we ever emulate the SPU with better precision than per-sample(pair).
66 */
67
68 #include "psx.h"
69 #include "cdc.h"
70 #include "spu.h"
71 #include "../../libretro.h"
72
73 uint32_t IntermediateBufferPos;
74 int16_t IntermediateBuffer[4096][2];
75
76 //#define SPUIRQ_DBG(format, ...) { printf("[SPUIRQDBG] " format " -- Voice 22 CA=0x%06x,LA=0x%06x\n", ## __VA_ARGS__, Voices[22].CurAddr, Voices[22].LoopAddr); }
77
78 static INLINE void SPUIRQ_DBG(const char *fmt, ...)
79 {
80 }
81
82 static const int16 FIR_Table[256][4] =
83 {
84 #include "spu_fir_table.inc"
85 };
86
87 PS_SPU::PS_SPU()
88 {
89 IntermediateBufferPos = 0;
90 memset(IntermediateBuffer, 0, sizeof(IntermediateBuffer));
91
92 }
93
94 PS_SPU::~PS_SPU()
95 {
96 }
97
98 void PS_SPU::Power(void)
99 {
100 clock_divider = 768;
101
102 memset(SPURAM, 0, sizeof(SPURAM));
103
104 for(int i = 0; i < 24; i++)
105 {
106 memset(Voices[i].DecodeBuffer, 0, sizeof(Voices[i].DecodeBuffer));
107 Voices[i].DecodeM2 = 0;
108 Voices[i].DecodeM1 = 0;
109
110 Voices[i].DecodePlayDelay = 0;
111 Voices[i].DecodeWritePos = 0;
112 Voices[i].DecodeReadPos = 0;
113 Voices[i].DecodeAvail = 0;
114
115 Voices[i].DecodeShift = 0;
116 Voices[i].DecodeWeight = 0;
117 Voices[i].DecodeFlags = 0;
118
119 Voices[i].IgnoreSampLA = false;
120
121 Voices[i].Sweep[0].Power();
122 Voices[i].Sweep[1].Power();
123
124 Voices[i].Pitch = 0;
125 Voices[i].CurPhase = 0;
126
127 Voices[i].StartAddr = 0;
128
129 Voices[i].CurAddr = 0;
130
131 Voices[i].ADSRControl = 0;
132
133 Voices[i].LoopAddr = 0;
134
135 Voices[i].PreLRSample = 0;
136
137 memset(&Voices[i].ADSR, 0, sizeof(SPU_ADSR));
138 }
139
140 GlobalSweep[0].Power();
141 GlobalSweep[1].Power();
142
143 NoiseDivider = 0;
144 NoiseCounter = 0;
145 LFSR = 0;
146
147 FM_Mode = 0;
148 Noise_Mode = 0;
149 Reverb_Mode = 0;
150 ReverbWA = 0;
151
152 ReverbVol[0] = ReverbVol[1] = 0;
153
154 CDVol[0] = CDVol[1] = 0;
155
156 ExternVol[0] = ExternVol[1] = 0;
157
158 IRQAddr = 0;
159
160 RWAddr = 0;
161
162 SPUControl = 0;
163
164 VoiceOn = 0;
165 VoiceOff = 0;
166
167 BlockEnd = 0;
168
169 CWA = 0;
170
171 memset(Regs, 0, sizeof(Regs));
172
173 memset(RDSB, 0, sizeof(RDSB));
174
175 memset(RUSB, 0, sizeof(RUSB));
176 RvbResPos = 0;
177
178 ReverbCur = ReverbWA;
179
180 IRQAsserted = false;
181 }
182
183 static INLINE void CalcVCDelta(const uint8 zs, uint8 speed, bool log_mode, bool dec_mode, bool inv_increment, int16 Current, int &increment, int &divinco)
184 {
185 increment = (7 - (speed & 0x3));
186
187 if(inv_increment)
188 increment = ~increment;
189
190 divinco = 32768;
191
192 if(speed < 0x2C)
193 increment = (unsigned)increment << ((0x2F - speed) >> 2);
194
195 if(speed >= 0x30)
196 divinco >>= (speed - 0x2C) >> 2;
197
198 if(log_mode)
199 {
200 if(dec_mode) // Log decrement mode
201 increment = (Current * increment) >> 15;
202 else // Log increment mode
203 {
204 if((Current & 0x7FFF) >= 0x6000)
205 {
206 if(speed < 0x28)
207 increment >>= 2;
208 else if(speed >= 0x2C)
209 divinco >>= 2;
210 else // 0x28 ... 0x2B
211 {
212 increment >>= 1;
213 divinco >>= 1;
214 }
215 }
216 }
217 } // end if(log_mode)
218
219 if(divinco == 0 && speed < zs) //0x7F)
220 divinco = 1;
221 }
222
223
224 INLINE void SPU_Sweep::Power(void)
225 {
226 Control = 0;
227 Current = 0;
228 Divider = 0;
229 }
230
231 INLINE void SPU_Sweep::WriteControl(uint16 value)
232 {
233 Control = value;
234 }
235
236 INLINE int16 SPU_Sweep::ReadVolume(void)
237 {
238 return((int16)Current);
239 }
240
241 void SPU_Sweep::Clock(void)
242 {
243 if(!(Control & 0x8000))
244 {
245 Current = (Control & 0x7FFF) << 1;
246 return;
247 }
248
249 if(Control & 0x8000) // Sweep enabled
250 {
251 const bool log_mode = (bool)(Control & 0x4000);
252 const bool dec_mode = (bool)(Control & 0x2000);
253 const bool inv_mode = (bool)(Control & 0x1000);
254 const bool inv_increment = (dec_mode ^ inv_mode) | (dec_mode & log_mode);
255 const uint16 vc_cv_xor = (inv_mode & !(dec_mode & log_mode)) ? 0xFFFF : 0x0000;
256 const uint16 TestInvert = inv_mode ? 0xFFFF : 0x0000;
257 int increment;
258 int divinco;
259
260 CalcVCDelta(0x7F, Control & 0x7F, log_mode, dec_mode, inv_increment, (int16)(Current ^ vc_cv_xor), increment, divinco);
261 //printf("%d %d\n", divinco, increment);
262
263 if((dec_mode & !(inv_mode & log_mode)) && ((Current & 0x8000) == (inv_mode ? 0x0000 : 0x8000) || (Current == 0)))
264 {
265 //
266 // Not sure if this condition should stop the Divider adding or force the increment value to 0.
267 //
268 Current = 0;
269 }
270 else
271 {
272 Divider += divinco;
273
274 if(Divider & 0x8000)
275 {
276 Divider = 0;
277
278 if(dec_mode || ((Current ^ TestInvert) != 0x7FFF))
279 {
280 uint16 PrevCurrent = Current;
281 Current = Current + increment;
282
283 //printf("%04x %04x\n", PrevCurrent, Current);
284
285 if(!dec_mode && ((Current ^ PrevCurrent) & 0x8000) && ((Current ^ TestInvert) & 0x8000))
286 Current = 0x7FFF ^ TestInvert;
287 }
288 }
289 }
290 }
291 }
292
293 INLINE void SPU_Sweep::WriteVolume(int16 value)
294 {
295 Current = value;
296 }
297
298
299 //
300 // Take care not to trigger SPU IRQ for the next block before its decoding start.
301 //
302 void PS_SPU::RunDecoder(SPU_Voice *voice)
303 {
304 // 5 through 0xF appear to be 0 on the real thing.
305 static const int32 Weights[16][2] =
306 {
307 // s-1 s-2
308 { 0, 0 },
309 { 60, 0 },
310 { 115, -52 },
311 { 98, -55 },
312 { 122, -60 },
313 };
314
315 if(voice->DecodeAvail >= 11)
316 {
317 if(SPUControl & 0x40)
318 {
319 unsigned test_addr = (voice->CurAddr - 1) & 0x3FFFF;
320 if(IRQAddr == test_addr || IRQAddr == (test_addr & 0x3FFF8))
321 {
322 //SPUIRQ_DBG("SPU IRQ (VDA): 0x%06x", addr);
323 IRQAsserted = true;
324 IRQ_Assert(IRQ_SPU, IRQAsserted);
325 }
326 }
327 return;
328 }
329
330 if((voice->CurAddr & 0x7) == 0)
331 {
332 // Handle delayed flags from the previously-decoded block.
333 //
334 // NOTE: The timing of setting the BlockEnd bit here, and forcing ADSR envelope volume to 0, is a bit late. (And I'm not sure if it should be done once
335 // per decoded block, or more than once, but that's probably not something games would rely on, but we should test it anyway).
336 //
337 // Correctish timing can be achieved by moving this block of code up above voice->DecodeAvail >= 11, and sticking it inside an: if(voice->DecodeAvail <= 12),
338 // though more tests are needed on the ADPCM decoding process as a whole before we should actually make such a change. Additionally, we'd probably
339 // have to separate the CurAddr = LoopAddr logic, so we don't generate spurious early SPU IRQs.
340 if(voice->DecodeFlags & 0x1)
341 {
342 voice->CurAddr = voice->LoopAddr & ~0x7;
343
344 BlockEnd |= 1 << (voice - Voices);
345
346 if(!(voice->DecodeFlags & 0x2)) // Force enveloping to 0 if not "looping". TODO: Should we reset the ADSR divider counter too?
347 {
348 if(!(Noise_Mode & (1 << (voice - Voices))))
349 {
350 voice->ADSR.Phase = ADSR_RELEASE;
351 voice->ADSR.EnvLevel = 0;
352 }
353 }
354 }
355 }
356
357 //for(int z = 0; z < 4; z++)
358 {
359
360 if(SPUControl & 0x40)
361 {
362 unsigned test_addr = voice->CurAddr & 0x3FFFF;
363 if(IRQAddr == test_addr || IRQAddr == (test_addr & 0x3FFF8))
364 {
365 //SPUIRQ_DBG("SPU IRQ: 0x%06x", addr);
366 IRQAsserted = true;
367 IRQ_Assert(IRQ_SPU, IRQAsserted);
368 }
369 }
370
371 if((voice->CurAddr & 0x7) == 0)
372 {
373 const uint16 CV = SPURAM[voice->CurAddr];
374 voice->DecodeShift = CV & 0xF;
375 voice->DecodeWeight = (CV >> 4) & 0xF;
376 voice->DecodeFlags = (CV >> 8) & 0xFF;
377
378 if(voice->DecodeFlags & 0x4)
379 {
380 if(!voice->IgnoreSampLA)
381 {
382 voice->LoopAddr = voice->CurAddr;
383 }
384 else
385 {
386 if(voice->LoopAddr != voice->CurAddr)
387 {
388 PSX_DBG(PSX_DBG_FLOOD, "[SPU] Ignore: LoopAddr=0x%08x, SampLA=0x%08x\n", voice->LoopAddr, voice->CurAddr);
389 }
390 }
391 }
392 voice->CurAddr = (voice->CurAddr + 1) & 0x3FFFF;
393 }
394
395 //
396 // Don't else this block; we need to ALWAYS decode 4 samples per call to RunDecoder() if DecodeAvail < 11, or else sample playback
397 // at higher rates will fail horribly.
398 //
399 {
400 const int32 weight_m1 = Weights[voice->DecodeWeight][0];
401 const int32 weight_m2 = Weights[voice->DecodeWeight][1];
402 uint16 CV;
403 unsigned shift;
404 uint32 coded;
405 int16 *tb = &voice->DecodeBuffer[voice->DecodeWritePos];
406
407 CV = SPURAM[voice->CurAddr];
408 shift = voice->DecodeShift;
409
410 if(MDFN_UNLIKELY(shift > 12))
411 {
412 //PSX_DBG(PSX_DBG_FLOOD, "[SPU] Buggy/Illegal ADPCM block shift value on voice %u: %u\n", (unsigned)(voice - Voices), shift);
413
414 shift = 8;
415 CV &= 0x8888;
416 }
417
418 coded = (uint32)CV << 12;
419
420
421 for(int i = 0; i < 4; i++)
422 {
423 int32 sample = (int16)(coded & 0xF000) >> shift;
424
425 sample += ((voice->DecodeM2 * weight_m2) >> 6);
426 sample += ((voice->DecodeM1 * weight_m1) >> 6);
427
428 clamp(&sample, -32768, 32767);
429
430 tb[i] = sample;
431 voice->DecodeM2 = voice->DecodeM1;
432 voice->DecodeM1 = sample;
433 coded >>= 4;
434 }
435 voice->DecodeWritePos = (voice->DecodeWritePos + 4) & 0x1F;
436 voice->DecodeAvail += 4;
437 voice->CurAddr = (voice->CurAddr + 1) & 0x3FFFF;
438 }
439 }
440 }
441
442 void PS_SPU::CacheEnvelope(SPU_Voice *voice)
443 {
444 uint32_t raw = voice->ADSRControl;
445 SPU_ADSR *ADSR = &voice->ADSR;
446 int32_t Sl = (raw >> 0) & 0x0F;
447 int32_t Dr = (raw >> 4) & 0x0F;
448 int32_t Ar = (raw >> 8) & 0x7F;
449
450 int32_t Rr = (raw >> 16) & 0x1F;
451 int32_t Sr = (raw >> 22) & 0x7F;
452
453 ADSR->AttackExp = (bool)(raw & (1 << 15));
454 ADSR->ReleaseExp = (bool)(raw & (1 << 21));
455 ADSR->SustainExp = (bool)(raw & (1 << 31));
456 ADSR->SustainDec = (bool)(raw & (1 << 30));
457
458 ADSR->AttackRate = Ar;
459 ADSR->DecayRate = Dr << 2;
460 ADSR->SustainRate = Sr;
461 ADSR->ReleaseRate = Rr << 2;
462
463 ADSR->SustainLevel = (Sl + 1) << 11;
464 }
465
466 void PS_SPU::ResetEnvelope(SPU_Voice *voice)
467 {
468 SPU_ADSR *ADSR = &voice->ADSR;
469
470 ADSR->EnvLevel = 0;
471 ADSR->Divider = 0;
472 ADSR->Phase = ADSR_ATTACK;
473 }
474
475 void PS_SPU::ReleaseEnvelope(SPU_Voice *voice)
476 {
477 SPU_ADSR *ADSR = &voice->ADSR;
478
479 ADSR->Divider = 0;
480 ADSR->Phase = ADSR_RELEASE;
481 }
482
483
484 void PS_SPU::RunEnvelope(SPU_Voice *voice)
485 {
486 SPU_ADSR *ADSR = &voice->ADSR;
487 int increment;
488 int divinco;
489 int16 uoflow_reset;
490
491 if(ADSR->Phase == ADSR_ATTACK && ADSR->EnvLevel == 0x7FFF)
492 ADSR->Phase++;
493
494 //static INLINE void CalcVCDelta(const uint8 zs, uint8 speed, bool log_mode, bool decrement, bool inv_increment, int16 Current, int &increment, int &divinco)
495 switch(ADSR->Phase)
496 {
497 default: assert(0);
498 break;
499
500 case ADSR_ATTACK:
501 CalcVCDelta(0x7F, ADSR->AttackRate, ADSR->AttackExp, false, false, (int16)ADSR->EnvLevel, increment, divinco);
502 uoflow_reset = 0x7FFF;
503 break;
504
505 case ADSR_DECAY:
506 CalcVCDelta(0x1F << 2, ADSR->DecayRate, true, true, true, (int16)ADSR->EnvLevel, increment, divinco);
507 uoflow_reset = 0;
508 break;
509
510 case ADSR_SUSTAIN:
511 CalcVCDelta(0x7F, ADSR->SustainRate, ADSR->SustainExp, ADSR->SustainDec, ADSR->SustainDec, (int16)ADSR->EnvLevel, increment, divinco);
512 uoflow_reset = ADSR->SustainDec ? 0 : 0x7FFF;
513 break;
514
515 case ADSR_RELEASE:
516 CalcVCDelta(0x1F << 2, ADSR->ReleaseRate, ADSR->ReleaseExp, true, true, (int16)ADSR->EnvLevel, increment, divinco);
517 uoflow_reset = 0;
518 break;
519 }
520
521 ADSR->Divider += divinco;
522 if(ADSR->Divider & 0x8000)
523 {
524 const uint16 prev_level = ADSR->EnvLevel;
525
526 ADSR->Divider = 0;
527 ADSR->EnvLevel += increment;
528
529 if(ADSR->Phase == ADSR_ATTACK)
530 {
531 // If previous the upper bit was 0, but now it's 1, handle overflow.
532 if(((prev_level ^ ADSR->EnvLevel) & ADSR->EnvLevel) & 0x8000)
533 ADSR->EnvLevel = uoflow_reset;
534 }
535 else
536 {
537 if(ADSR->EnvLevel & 0x8000)
538 ADSR->EnvLevel = uoflow_reset;
539 }
540 if(ADSR->Phase == ADSR_DECAY && (uint16)ADSR->EnvLevel < ADSR->SustainLevel)
541 ADSR->Phase++;
542 }
543 }
544
545 INLINE void PS_SPU::CheckIRQAddr(uint32 addr)
546 {
547 if(SPUControl & 0x40)
548 {
549 if(IRQAddr != addr)
550 return;
551
552 //SPUIRQ_DBG("SPU IRQ (ALT): 0x%06x", addr);
553 IRQAsserted = true;
554 IRQ_Assert(IRQ_SPU, IRQAsserted);
555 }
556 }
557
558 INLINE void PS_SPU::WriteSPURAM(uint32 addr, uint16 value)
559 {
560 CheckIRQAddr(addr);
561
562 SPURAM[addr] = value;
563 }
564
565 INLINE uint16 PS_SPU::ReadSPURAM(uint32 addr)
566 {
567 CheckIRQAddr(addr);
568 return(SPURAM[addr]);
569 }
570
571 static INLINE int16 ReverbSat(int32 samp)
572 {
573 if(samp > 32767)
574 samp = 32767;
575
576 if(samp < -32768)
577 samp = -32768;
578
579 return(samp);
580 }
581
582
583 INLINE uint32 PS_SPU::Get_Reverb_Offset(uint32 in_offset)
584 {
585 uint32 offset = ReverbCur + (in_offset & 0x3FFFF);
586
587 offset += ReverbWA & ((int32)(offset << 13) >> 31);
588 offset &= 0x3FFFF;
589
590 // For debugging in case there are any problems with games misprogramming the reverb registers in a race-conditiony manner that
591 // causes important data in SPU RAM to be trashed:
592 //if(offset < ReverbWA)
593 // printf("BARF: offset=%05x reverbwa=%05x reverbcur=%05x in_offset=%05x\n", offset, ReverbWA, ReverbCur, in_offset & 0x3FFFF);
594
595 return(offset);
596 }
597
598 int16 NO_INLINE PS_SPU::RD_RVB(uint16 raw_offs, int32 extra_offs)
599 {
600 return ReadSPURAM(Get_Reverb_Offset((raw_offs << 2) + extra_offs));
601 }
602
603 void NO_INLINE PS_SPU::WR_RVB(uint16 raw_offs, int16 sample)
604 {
605 WriteSPURAM(Get_Reverb_Offset(raw_offs << 2), sample);
606 }
607
608 //
609 // Zeroes optimized out; middle removed too(it's 16384)
610 static const int16 ResampTable[20] =
611 {
612 -1, 2, -10, 35, -103, 266, -616, 1332, -2960, 10246, 10246, -2960, 1332, -616, 266, -103, 35, -10, 2, -1,
613 };
614
615 static INLINE int32 Reverb4422(const int16 *src)
616 {
617 int32 out = 0; // 32-bits is adequate(it won't overflow)
618
619 for(unsigned i = 0; i < 20; i++)
620 out += ResampTable[i] * src[i * 2];
621
622 // Middle non-zero
623 out += 0x4000 * src[19];
624
625 out >>= 15;
626
627 clamp(&out, -32768, 32767);
628
629 return(out);
630 }
631
632 static INLINE int32 Reverb2244(const int16 *src)
633 {
634 unsigned i;
635 int32_t out = 0; /* 32bits is adequate (it won't overflow) */
636
637 for(i = 0; i < 20; i++)
638 out += ResampTable[i] * src[i];
639
640 out >>= 14;
641
642 clamp(&out, -32768, 32767);
643
644 return out;
645 }
646
647 static int32 IIASM(const int16 IIR_ALPHA, const int16 insamp)
648 {
649 if(MDFN_UNLIKELY(IIR_ALPHA == -32768))
650 {
651 if(insamp == -32768)
652 return 0;
653 return insamp * -65536;
654 }
655
656 return insamp * (32768 - IIR_ALPHA);
657 }
658
659 //
660 // Take care to thoroughly test the reverb resampling code when modifying anything that uses RvbResPos.
661 //
662 void PS_SPU::RunReverb(const int32* in, int32* out)
663 {
664 int32 upsampled[2] = { 0, 0 };
665
666 for(unsigned lr = 0; lr < 2; lr++)
667 {
668 RDSB[lr][RvbResPos | 0x00] = in[lr];
669 RDSB[lr][RvbResPos | 0x40] = in[lr]; // So we don't have to &/bounds check in our MAC loop
670 }
671
672 if(RvbResPos & 1)
673 {
674 int32 downsampled[2];
675
676 for(unsigned lr = 0; lr < 2; lr++)
677 downsampled[lr] = Reverb4422(&RDSB[lr][(RvbResPos - 39) & 0x3F]);
678
679 /* Run algorithm */
680 if(SPUControl & 0x80)
681 {
682 int16 ACC0, ACC1;
683 int16 FB_A0, FB_A1, FB_B0, FB_B1;
684
685 int16 IIR_INPUT_A0 = ReverbSat(((RD_RVB(IIR_SRC_A0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15));
686 int16 IIR_INPUT_A1 = ReverbSat(((RD_RVB(IIR_SRC_A1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15));
687 int16 IIR_INPUT_B0 = ReverbSat(((RD_RVB(IIR_SRC_B0) * IIR_COEF) >> 15) + ((downsampled[0] * IN_COEF_L) >> 15));
688 int16 IIR_INPUT_B1 = ReverbSat(((RD_RVB(IIR_SRC_B1) * IIR_COEF) >> 15) + ((downsampled[1] * IN_COEF_R) >> 15));
689
690 int16 IIR_A0 = ReverbSat((((IIR_INPUT_A0 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_A0, -1)) >> 14)) >> 1);
691 int16 IIR_A1 = ReverbSat((((IIR_INPUT_A1 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_A1, -1)) >> 14)) >> 1);
692 int16 IIR_B0 = ReverbSat((((IIR_INPUT_B0 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_B0, -1)) >> 14)) >> 1);
693 int16 IIR_B1 = ReverbSat((((IIR_INPUT_B1 * IIR_ALPHA) >> 14) + (IIASM(IIR_ALPHA, RD_RVB(IIR_DEST_B1, -1)) >> 14)) >> 1);
694
695 WR_RVB(IIR_DEST_A0, IIR_A0);
696 WR_RVB(IIR_DEST_A1, IIR_A1);
697 WR_RVB(IIR_DEST_B0, IIR_B0);
698 WR_RVB(IIR_DEST_B1, IIR_B1);
699
700 ACC0 = ReverbSat((((RD_RVB(ACC_SRC_A0) * ACC_COEF_A) >> 14) +
701 ((RD_RVB(ACC_SRC_B0) * ACC_COEF_B) >> 14) +
702 ((RD_RVB(ACC_SRC_C0) * ACC_COEF_C) >> 14) +
703 ((RD_RVB(ACC_SRC_D0) * ACC_COEF_D) >> 14)) >> 1);
704
705 ACC1 = ReverbSat((((RD_RVB(ACC_SRC_A1) * ACC_COEF_A) >> 14) +
706 ((RD_RVB(ACC_SRC_B1) * ACC_COEF_B) >> 14) +
707 ((RD_RVB(ACC_SRC_C1) * ACC_COEF_C) >> 14) +
708 ((RD_RVB(ACC_SRC_D1) * ACC_COEF_D) >> 14)) >> 1);
709
710 FB_A0 = RD_RVB(MIX_DEST_A0 - FB_SRC_A);
711 FB_A1 = RD_RVB(MIX_DEST_A1 - FB_SRC_A);
712 FB_B0 = RD_RVB(MIX_DEST_B0 - FB_SRC_B);
713 FB_B1 = RD_RVB(MIX_DEST_B1 - FB_SRC_B);
714
715 WR_RVB(MIX_DEST_A0, ReverbSat(ACC0 - ((FB_A0 * FB_ALPHA) >> 15)));
716 WR_RVB(MIX_DEST_A1, ReverbSat(ACC1 - ((FB_A1 * FB_ALPHA) >> 15)));
717
718 WR_RVB(MIX_DEST_B0, ReverbSat(((FB_ALPHA * ACC0) >> 15) - ((FB_A0 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B0 * FB_X) >> 15)));
719 WR_RVB(MIX_DEST_B1, ReverbSat(((FB_ALPHA * ACC1) >> 15) - ((FB_A1 * (int16)(0x8000 ^ FB_ALPHA)) >> 15) - ((FB_B1 * FB_X) >> 15)));
720 }
721
722 /* Get output samplesq */
723 RUSB[0][(RvbResPos >> 1) | 0x20] = RUSB[0][RvbResPos >> 1] = (RD_RVB(MIX_DEST_A0) + RD_RVB(MIX_DEST_B0)) >> 1;
724 RUSB[1][(RvbResPos >> 1) | 0x20] = RUSB[1][RvbResPos >> 1] = (RD_RVB(MIX_DEST_A1) + RD_RVB(MIX_DEST_B1)) >> 1;
725
726 ReverbCur = (ReverbCur + 1) & 0x3FFFF;
727 if(!ReverbCur)
728 ReverbCur = ReverbWA;
729
730 for(unsigned lr = 0; lr < 2; lr++)
731 {
732 const int16 *src = &RUSB[lr][((RvbResPos - 39) & 0x3F) >> 1];
733 upsampled[lr] = src[9]; /* Reverb 2244 (Middle non-zero */
734 }
735 }
736 else
737 {
738 for(unsigned lr = 0; lr < 2; lr++)
739 {
740 const int16 *src = &RUSB[lr][((RvbResPos - 39) & 0x3F) >> 1];
741 upsampled[lr] = Reverb2244(src);
742 }
743 }
744
745 RvbResPos = (RvbResPos + 1) & 0x3F;
746
747 for(unsigned lr = 0; lr < 2; lr++)
748 out[lr] = upsampled[lr];
749 }
750
751
752 INLINE void PS_SPU::RunNoise(void)
753 {
754 const unsigned rf = ((SPUControl >> 8) & 0x3F);
755 uint32 NoiseDividerInc = (2 << (rf >> 2));
756 uint32 NoiseCounterInc = 4 + (rf & 0x3);
757
758 if(rf >= 0x3C)
759 {
760 NoiseDividerInc = 0x8000;
761 NoiseCounterInc = 8;
762 }
763
764 NoiseDivider += NoiseDividerInc;
765
766 if(NoiseDivider & 0x8000)
767 {
768 NoiseDivider = 0;
769
770 NoiseCounter += NoiseCounterInc;
771
772 if(NoiseCounter & 0x8)
773 {
774 NoiseCounter &= 0x7;
775 LFSR = (LFSR << 1) | (((LFSR >> 15) ^ (LFSR >> 12) ^ (LFSR >> 11) ^ (LFSR >> 10) ^ 1) & 1);
776 }
777 }
778 }
779
780 int32 PS_SPU::UpdateFromCDC(int32 clocks)
781 {
782 //int32 clocks = timestamp - lastts;
783 int32 sample_clocks = 0;
784 //lastts = timestamp;
785
786 clock_divider -= clocks;
787
788 while(clock_divider <= 0)
789 {
790 clock_divider += 768;
791 sample_clocks++;
792 }
793
794 while(sample_clocks > 0)
795 {
796 // xxx[0] = left, xxx[1] = right
797
798 // Accumulated sound output.
799 int32 accum[2] = { 0, 0 };
800
801 // Accumulated sound output for reverb input
802 int32 accum_fv[2] = { 0, 0 };
803
804 // Output of reverb processing.
805 int32 reverb[2] = { 0, 0 };
806
807 // Final output.
808 int32 output[2] = { 0, 0 };
809
810 const uint32 PhaseModCache = FM_Mode & ~ 1;
811 /*
812 **
813 ** 0x1F801DAE Notes and Conjecture:
814 ** -------------------------------------------------------------------------------------
815 ** | 15 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 4 3 2 1 0 |
816 ** | ? | *13| ? | ba | *10 | wrr|rdr| df | is | c |
817 ** -------------------------------------------------------------------------------------
818 **
819 ** c - Appears to be delayed copy of lower 6 bits from 0x1F801DAA.
820 **
821 ** is - Interrupt asserted out status. (apparently not instantaneous status though...)
822 **
823 ** df - Related to (c & 0x30) == 0x20 or (c & 0x30) == 0x30, at least.
824 ** 0 = DMA busy(FIFO not empty when in DMA write mode?)?
825 ** 1 = DMA ready? Something to do with the FIFO?
826 **
827 ** rdr - Read(DMA read?) Ready?
828 **
829 ** wrr - Write(DMA write?) Ready?
830 **
831 ** *10 - Unknown. Some sort of (FIFO?) busy status?(BIOS tests for this bit in places)
832 **
833 ** ba - Alternates between 0 and 1, even when SPUControl bit15 is 0; might be related to CD audio and voice 1 and 3 writing to SPU RAM.
834 **
835 ** *13 - Unknown, was set to 1 when testing with an SPU delay system reg value of 0x200921E1(test result might not be reliable, re-run).
836 */
837 SPUStatus = SPUControl & 0x3F;
838 SPUStatus |= IRQAsserted ? 0x40 : 0x00;
839
840 if(Regs[0xD6] == 0x4) // TODO: Investigate more(case 0x2C in global regs r/w handler)
841 SPUStatus |= (CWA & 0x100) ? 0x800 : 0x000;
842
843 for(int voice_num = 0; voice_num < 24; voice_num++)
844 {
845 SPU_Voice *voice = &Voices[voice_num];
846 int32 voice_pvs;
847
848 voice->PreLRSample = 0;
849
850 //PSX_WARNING("[SPU] Voice %d CurPhase=%08x, pitch=%04x, CurAddr=%08x", voice_num, voice->CurPhase, voice->Pitch, voice->CurAddr);
851
852 //
853 // Decode new samples if necessary.
854 //
855 RunDecoder(voice);
856
857
858 //
859 //
860 //
861 int l, r;
862
863 if(Noise_Mode & (1 << voice_num))
864 voice_pvs = (int16)LFSR;
865 else
866 {
867 const int si = voice->DecodeReadPos;
868 const int pi = ((voice->CurPhase & 0xFFF) >> 4);
869
870 voice_pvs = ((voice->DecodeBuffer[(si + 0) & 0x1F] * FIR_Table[pi][0]) +
871 (voice->DecodeBuffer[(si + 1) & 0x1F] * FIR_Table[pi][1]) +
872 (voice->DecodeBuffer[(si + 2) & 0x1F] * FIR_Table[pi][2]) +
873 (voice->DecodeBuffer[(si + 3) & 0x1F] * FIR_Table[pi][3])) >> 15;
874 }
875
876 voice_pvs = (voice_pvs * (int16)voice->ADSR.EnvLevel) >> 15;
877 voice->PreLRSample = voice_pvs;
878
879 if(voice_num == 1 || voice_num == 3)
880 {
881 int index = voice_num >> 1;
882
883 WriteSPURAM(0x400 | (index * 0x200) | CWA, voice_pvs);
884 }
885
886
887 l = (voice_pvs * voice->Sweep[0].ReadVolume()) >> 15;
888 r = (voice_pvs * voice->Sweep[1].ReadVolume()) >> 15;
889
890 accum[0] += l;
891 accum[1] += r;
892
893 if(Reverb_Mode & (1 << voice_num))
894 {
895 accum_fv[0] += l;
896 accum_fv[1] += r;
897 }
898
899 // Run sweep
900 for(int lr = 0; lr < 2; lr++)
901 voice->Sweep[lr].Clock();
902
903 // Increment stuff
904 if(!voice->DecodePlayDelay)
905 {
906 unsigned phase_inc;
907
908 // Run enveloping
909 RunEnvelope(voice);
910
911 if(PhaseModCache & (1 << voice_num))
912 {
913 // This old formula: phase_inc = (voice->Pitch * ((voice - 1)->PreLRSample + 0x8000)) >> 15;
914 // is incorrect, as it does not handle carrier pitches >= 0x8000 properly.
915 phase_inc = voice->Pitch + (((int16)voice->Pitch * ((voice - 1)->PreLRSample)) >> 15);
916 }
917 else
918 phase_inc = voice->Pitch;
919
920 if(phase_inc > 0x3FFF)
921 phase_inc = 0x3FFF;
922
923 {
924 const uint32 tmp_phase = voice->CurPhase + phase_inc;
925 const unsigned used = tmp_phase >> 12;
926
927 voice->CurPhase = tmp_phase & 0xFFF;
928 voice->DecodeAvail -= used;
929 voice->DecodeReadPos = (voice->DecodeReadPos + used) & 0x1F;
930 }
931 }
932 else
933 voice->DecodePlayDelay--;
934
935 if(VoiceOff & (1U << voice_num))
936 {
937 if(voice->ADSR.Phase != ADSR_RELEASE)
938 {
939 ReleaseEnvelope(voice);
940 }
941 }
942
943 if(VoiceOn & (1U << voice_num))
944 {
945 //printf("Voice On: %u\n", voice_num);
946
947 ResetEnvelope(voice);
948
949 voice->DecodeFlags = 0;
950 voice->DecodeWritePos = 0;
951 voice->DecodeReadPos = 0;
952 voice->DecodeAvail = 0;
953 voice->DecodePlayDelay = 4;
954
955 BlockEnd &= ~(1 << voice_num);
956
957 //
958 // Weight/filter previous value initialization:
959 //
960 voice->DecodeM2 = 0;
961 voice->DecodeM1 = 0;
962
963 voice->CurPhase = 0;
964 voice->CurAddr = voice->StartAddr & ~0x7;
965 voice->IgnoreSampLA = false;
966 }
967
968 if(!(SPUControl & 0x8000))
969 {
970 voice->ADSR.Phase = ADSR_RELEASE;
971 voice->ADSR.EnvLevel = 0;
972 }
973 }
974
975 VoiceOff = 0;
976 VoiceOn = 0;
977
978 // "Mute" control doesn't seem to affect CD audio(though CD audio reverb wasn't tested...)
979 // TODO: If we add sub-sample timing accuracy, see if it's checked for every channel at different times, or just once.
980 if(!(SPUControl & 0x4000))
981 {
982 accum[0] = 0;
983 accum[1] = 0;
984 accum_fv[0] = 0;
985 accum_fv[1] = 0;
986 }
987
988 // Get CD-DA
989 {
990 int32 cda_raw[2];
991 int32 cdav[2];
992
993 CDC->GetCDAudio(cda_raw); // PS_CDC::GetCDAudio() guarantees the variables passed by reference will be set to 0,
994 // and that their range shall be -32768 through 32767.
995
996 WriteSPURAM(CWA | 0x000, cda_raw[0]);
997 WriteSPURAM(CWA | 0x200, cda_raw[1]);
998
999 for(unsigned i = 0; i < 2; i++)
1000 cdav[i] = (cda_raw[i] * CDVol[i]) >> 15;
1001
1002 if(SPUControl & 0x0001)
1003 {
1004 accum[0] += cdav[0];
1005 accum[1] += cdav[1];
1006
1007 if(SPUControl & 0x0004) // TODO: Test this bit(and see if it is really dependent on bit0)
1008 {
1009 accum_fv[0] += cdav[0];
1010 accum_fv[1] += cdav[1];
1011 }
1012 }
1013 }
1014
1015 CWA = (CWA + 1) & 0x1FF;
1016
1017 RunNoise();
1018
1019 for (unsigned lr = 0; lr < 2; lr++)
1020 clamp(&accum_fv[lr], -32768, 32767);
1021
1022 RunReverb(accum_fv, reverb);
1023
1024 for(unsigned lr = 0; lr < 2; lr++)
1025 {
1026 accum[lr] += ((reverb[lr] * ReverbVol[lr]) >> 15);
1027 clamp(&accum[lr], -32768, 32767);
1028 output[lr] = (accum[lr] * GlobalSweep[lr].ReadVolume()) >> 15;
1029 clamp(&output[lr], -32768, 32767);
1030 }
1031
1032 if(IntermediateBufferPos < 4096) // Overflow might occur in some debugger use cases.
1033 {
1034 // 75%, for some (resampling) headroom.
1035 for(unsigned lr = 0; lr < 2; lr++)
1036 IntermediateBuffer[IntermediateBufferPos][lr] = (output[lr] * 3 + 2) >> 2;
1037
1038 IntermediateBufferPos++;
1039 }
1040
1041 sample_clocks--;
1042
1043 // Clock global sweep
1044 for(unsigned lr = 0; lr < 2; lr++)
1045 GlobalSweep[lr].Clock();
1046 }
1047
1048 //assert(clock_divider < 768);
1049
1050 return clock_divider;
1051 }
1052
1053 void PS_SPU::WriteDMA(uint32 V)
1054 {
1055 //SPUIRQ_DBG("DMA Write, RWAddr after=0x%06x", RWAddr);
1056 WriteSPURAM(RWAddr, V);
1057 RWAddr = (RWAddr + 1) & 0x3FFFF;
1058
1059 WriteSPURAM(RWAddr, V >> 16);
1060 RWAddr = (RWAddr + 1) & 0x3FFFF;
1061
1062
1063 CheckIRQAddr(RWAddr);
1064 }
1065
1066 uint32 PS_SPU::ReadDMA(void)
1067 {
1068 uint32 ret = (uint16)ReadSPURAM(RWAddr);
1069 RWAddr = (RWAddr + 1) & 0x3FFFF;
1070
1071 ret |= (uint32)(uint16)ReadSPURAM(RWAddr) << 16;
1072 RWAddr = (RWAddr + 1) & 0x3FFFF;
1073
1074 CheckIRQAddr(RWAddr);
1075
1076 //SPUIRQ_DBG("DMA Read, RWAddr after=0x%06x", RWAddr);
1077
1078 return(ret);
1079 }
1080
1081 void PS_SPU::Write(int32_t timestamp, uint32 A, uint16 V)
1082 {
1083 //if((A & 0x3FF) < 0x180)
1084 // PSX_WARNING("[SPU] Write: %08x %04x", A, V);
1085
1086 A &= 0x3FF;
1087
1088 if(A >= 0x200)
1089 {
1090 //printf("Write: %08x %04x\n", A, V);
1091 if(A < 0x260)
1092 {
1093 SPU_Voice *voice = &Voices[(A - 0x200) >> 2];
1094 voice->Sweep[(A & 2) >> 1].WriteVolume(V);
1095 }
1096 else if(A < 0x280)
1097 AuxRegs[(A & 0x1F) >> 1] = V;
1098
1099 return;
1100 }
1101
1102 if(A < 0x180)
1103 {
1104 SPU_Voice *voice = &Voices[A >> 4];
1105
1106 switch(A & 0xF)
1107 {
1108 case 0x00:
1109 case 0x02:
1110 voice->Sweep[(A & 2) >> 1].WriteControl(V);
1111 break;
1112 case 0x04:
1113 voice->Pitch = V;
1114 break;
1115 case 0x06:
1116 voice->StartAddr = (V << 2) & 0x3FFFF;
1117 break;
1118 case 0x08:
1119 voice->ADSRControl &= 0xFFFF0000;
1120 voice->ADSRControl |= V;
1121 CacheEnvelope(voice);
1122 break;
1123 case 0x0A:
1124 voice->ADSRControl &= 0x0000FFFF;
1125 voice->ADSRControl |= V << 16;
1126 CacheEnvelope(voice);
1127 break;
1128 case 0x0C:
1129 voice->ADSR.EnvLevel = V;
1130 break;
1131 case 0x0E:
1132 voice->LoopAddr = (V << 2) & 0x3FFFF;
1133 voice->IgnoreSampLA = true;
1134 #if 0
1135 if((voice - Voices) == 22)
1136 {
1137 SPUIRQ_DBG("Manual loop address setting for voice %d: %04x", (int)(voice - Voices), V);
1138 }
1139 #endif
1140 break;
1141 }
1142 }
1143 else
1144 {
1145 switch(A & 0x7F)
1146 {
1147 case 0x00:
1148 case 0x02: GlobalSweep[(A & 2) >> 1].WriteControl(V);
1149 break;
1150
1151 case 0x04: ReverbVol[0] = (int16)V;
1152 break;
1153
1154 case 0x06: ReverbVol[1] = (int16)V;
1155 break;
1156
1157 // Voice ON:
1158 case 0x08: VoiceOn &= 0xFFFF0000;
1159 VoiceOn |= V << 0;
1160 break;
1161
1162 case 0x0a: VoiceOn &= 0x0000FFFF;
1163 VoiceOn |= (V & 0xFF) << 16;
1164 break;
1165
1166 // Voice OFF:
1167 case 0x0c: VoiceOff &= 0xFFFF0000;
1168 VoiceOff |= V << 0;
1169 break;
1170
1171 case 0x0e: VoiceOff &= 0x0000FFFF;
1172 VoiceOff |= (V & 0xFF) << 16;
1173 break;
1174
1175 case 0x10: FM_Mode &= 0xFFFF0000;
1176 FM_Mode |= V << 0;
1177 break;
1178
1179 case 0x12: FM_Mode &= 0x0000FFFF;
1180 FM_Mode |= (V & 0xFF) << 16;
1181 break;
1182
1183 case 0x14: Noise_Mode &= 0xFFFF0000;
1184 Noise_Mode |= V << 0;
1185 break;
1186
1187 case 0x16: Noise_Mode &= 0x0000FFFF;
1188 Noise_Mode |= (V & 0xFF) << 16;
1189 break;
1190
1191 case 0x18: Reverb_Mode &= 0xFFFF0000;
1192 Reverb_Mode |= V << 0;
1193 break;
1194
1195 case 0x1A: Reverb_Mode &= 0x0000FFFF;
1196 Reverb_Mode |= (V & 0xFF) << 16;
1197 break;
1198
1199 case 0x1C: BlockEnd &= 0xFFFF0000;
1200 BlockEnd |= V << 0;
1201 break;
1202
1203 case 0x1E: BlockEnd &= 0x0000FFFF;
1204 BlockEnd |= V << 16;
1205 break;
1206
1207 case 0x22: ReverbWA = (V << 2) & 0x3FFFF;
1208 ReverbCur = ReverbWA;
1209 //PSX_WARNING("[SPU] Reverb WA set: 0x%04x", V);
1210 break;
1211
1212 case 0x24:
1213 IRQAddr = (V << 2) & 0x3FFFF;
1214 CheckIRQAddr(RWAddr);
1215 //SPUIRQ_DBG("Set IRQAddr=0x%06x", IRQAddr);
1216 break;
1217
1218 case 0x26:
1219 RWAddr = (V << 2) & 0x3FFFF;
1220 CheckIRQAddr(RWAddr);
1221 //SPUIRQ_DBG("Set RWAddr=0x%06x", RWAddr);
1222 break;
1223
1224 case 0x28: WriteSPURAM(RWAddr, V);
1225 RWAddr = (RWAddr + 1) & 0x3FFFF;
1226 CheckIRQAddr(RWAddr);
1227 break;
1228
1229 case 0x2A: //if((SPUControl & 0x80) && !(V & 0x80))
1230 // printf("\n\n\n\n ************** REVERB PROCESSING DISABLED\n\n\n\n");
1231
1232 SPUControl = V;
1233 //SPUIRQ_DBG("Set SPUControl=0x%04x -- IRQA=%06x, RWA=%06x", V, IRQAddr, RWAddr);
1234 //printf("SPU control write: %04x\n", V);
1235 if(!(V & 0x40))
1236 {
1237 IRQAsserted = false;
1238 IRQ_Assert(IRQ_SPU, IRQAsserted);
1239 }
1240 CheckIRQAddr(RWAddr);
1241 break;
1242
1243 case 0x2C: PSX_WARNING("[SPU] Global reg 0x2c set: 0x%04x", V);
1244 break;
1245
1246 case 0x30: CDVol[0] = V;
1247 break;
1248
1249 case 0x32: CDVol[1] = V;
1250 break;
1251
1252 case 0x34: ExternVol[0] = V;
1253 break;
1254
1255 case 0x36: ExternVol[1] = V;
1256 break;
1257
1258 case 0x38:
1259 case 0x3A: GlobalSweep[(A & 2) >> 1].WriteVolume(V);
1260 break;
1261 }
1262 }
1263
1264 Regs[(A & 0x1FF) >> 1] = V;
1265 }
1266
1267 uint16 PS_SPU::Read(int32_t timestamp, uint32 A)
1268 {
1269 A &= 0x3FF;
1270
1271 PSX_DBGINFO("[SPU] Read: %08x", A);
1272
1273 if(A >= 0x200)
1274 {
1275 if(A < 0x260)
1276 {
1277 SPU_Voice *voice = &Voices[(A - 0x200) >> 2];
1278
1279 //printf("Read: %08x %04x\n", A, voice->Sweep[(A & 2) >> 1].ReadVolume());
1280
1281 return voice->Sweep[(A & 2) >> 1].ReadVolume();
1282 }
1283 else if(A < 0x280)
1284 return(AuxRegs[(A & 0x1F) >> 1]);
1285
1286 return(0xFFFF);
1287 }
1288
1289
1290 if(A < 0x180)
1291 {
1292 SPU_Voice *voice = &Voices[A >> 4];
1293
1294 switch(A & 0xF)
1295 {
1296 case 0x0C:
1297 return(voice->ADSR.EnvLevel);
1298 case 0x0E:
1299 return(voice->LoopAddr >> 2);
1300 }
1301 }
1302 else
1303 {
1304 switch(A & 0x7F)
1305 {
1306 case 0x1C:
1307 return(BlockEnd);
1308 case 0x1E:
1309 return(BlockEnd >> 16);
1310 case 0x26:
1311 //PSX_WARNING("[SPU] RWADDR Read");
1312 break;
1313 case 0x28:
1314 //PSX_WARNING("[SPU] SPURAM Read port(?) Read");
1315 {
1316 uint16 ret = ReadSPURAM(RWAddr);
1317
1318 RWAddr = (RWAddr + 1) & 0x3FFFF;
1319 CheckIRQAddr(RWAddr);
1320
1321 return (ret);
1322 }
1323
1324 case 0x2a:
1325 return(SPUControl);
1326
1327 /* FIXME: What is this used for? */
1328 case 0x3C:
1329 //PSX_WARNING("[SPU] Read Unknown: %08x", A);
1330 return(0);
1331 case 0x38:
1332 case 0x3A:
1333 return(GlobalSweep[(A & 2) >> 1].ReadVolume());
1334 }
1335 }
1336
1337 return(Regs[(A & 0x1FF) >> 1]);
1338 }
1339
1340 int PS_SPU::StateAction(StateMem *sm, int load, int data_only)
1341 {
1342 SFORMAT StateRegs[] =
1343 {
1344 #define SFSWEEP(r) SFVAR((r).Control), \
1345 SFVAR((r).Current), \
1346 SFVAR((r).Divider)
1347
1348 #define SFVOICE(n) SFARRAY16(&Voices[n].DecodeBuffer[0], sizeof(Voices[n].DecodeBuffer) / sizeof(Voices[n].DecodeBuffer[0])), \
1349 SFVAR(Voices[n].DecodeM2), \
1350 SFVAR(Voices[n].DecodeM1), \
1351 SFVAR(Voices[n].DecodePlayDelay), \
1352 SFVAR(Voices[n].DecodeWritePos), \
1353 SFVAR(Voices[n].DecodeReadPos), \
1354 SFVAR(Voices[n].DecodeAvail), \
1355 SFVAR(Voices[n].DecodeShift), \
1356 SFVAR(Voices[n].DecodeWeight), \
1357 SFVAR(Voices[n].DecodeFlags), \
1358 SFVAR(Voices[n].IgnoreSampLA), \
1359 \
1360 SFSWEEP(Voices[n].Sweep[0]), \
1361 SFSWEEP(Voices[n].Sweep[1]), \
1362 \
1363 SFVAR(Voices[n].Pitch), \
1364 SFVAR(Voices[n].CurPhase), \
1365 \
1366 SFVAR(Voices[n].StartAddr), \
1367 SFVAR(Voices[n].CurAddr), \
1368 SFVAR(Voices[n].ADSRControl), \
1369 SFVAR(Voices[n].LoopAddr), \
1370 SFVAR(Voices[n].PreLRSample), \
1371 \
1372 SFVAR(Voices[n].ADSR.EnvLevel), \
1373 SFVAR(Voices[n].ADSR.Divider), \
1374 SFVAR(Voices[n].ADSR.Phase), \
1375 \
1376 SFVAR(Voices[n].ADSR.AttackExp), \
1377 SFVAR(Voices[n].ADSR.SustainExp), \
1378 SFVAR(Voices[n].ADSR.SustainDec), \
1379 SFVAR(Voices[n].ADSR.ReleaseExp), \
1380 \
1381 SFVAR(Voices[n].ADSR.AttackRate), \
1382 SFVAR(Voices[n].ADSR.DecayRate), \
1383 SFVAR(Voices[n].ADSR.SustainRate), \
1384 SFVAR(Voices[n].ADSR.ReleaseRate), \
1385 \
1386 SFVAR(Voices[n].ADSR.SustainLevel)
1387
1388 SFVOICE(0),
1389 SFVOICE(1),
1390 SFVOICE(2),
1391 SFVOICE(3),
1392 SFVOICE(4),
1393 SFVOICE(5),
1394 SFVOICE(6),
1395 SFVOICE(7),
1396 SFVOICE(8),
1397 SFVOICE(9),
1398 SFVOICE(10),
1399 SFVOICE(11),
1400 SFVOICE(12),
1401 SFVOICE(13),
1402 SFVOICE(14),
1403 SFVOICE(15),
1404 SFVOICE(16),
1405 SFVOICE(17),
1406 SFVOICE(18),
1407 SFVOICE(19),
1408 SFVOICE(20),
1409 SFVOICE(21),
1410 SFVOICE(22),
1411 SFVOICE(23),
1412 #undef SFVOICE
1413
1414 SFVAR(NoiseDivider),
1415 SFVAR(NoiseCounter),
1416 SFVAR(LFSR),
1417
1418 SFVAR(FM_Mode),
1419 SFVAR(Noise_Mode),
1420 SFVAR(Reverb_Mode),
1421
1422 SFVAR(ReverbWA),
1423
1424 SFSWEEP(GlobalSweep[0]),
1425 SFSWEEP(GlobalSweep[1]),
1426
1427 SFARRAY32(ReverbVol, sizeof(ReverbVol) / sizeof(ReverbVol[0])),
1428
1429 SFARRAY32(CDVol, sizeof(CDVol) / sizeof(CDVol[0])),
1430 SFARRAY32(ExternVol, sizeof(ExternVol) / sizeof(ExternVol[0])),
1431
1432 SFVAR(IRQAddr),
1433
1434 SFVAR(RWAddr),
1435
1436 SFVAR(SPUControl),
1437
1438 SFVAR(VoiceOn),
1439 SFVAR(VoiceOff),
1440
1441 SFVAR(BlockEnd),
1442
1443 SFVAR(CWA),
1444
1445 SFARRAY16(Regs, sizeof(Regs) / sizeof(Regs[0])),
1446 SFARRAY16(AuxRegs, sizeof(AuxRegs) / sizeof(AuxRegs[0])),
1447
1448 SFARRAY16(&RDSB[0][0], sizeof(RDSB) / sizeof(RDSB[0][0])),
1449 SFVAR(RvbResPos),
1450
1451 SFARRAY16(&RUSB[0][0], sizeof(RUSB) / sizeof(RUSB[0][0])),
1452
1453 SFVAR(ReverbCur),
1454 SFVAR(IRQAsserted),
1455
1456 SFVAR(clock_divider),
1457
1458 SFARRAY16(SPURAM, 524288 / sizeof(uint16)),
1459 SFEND
1460 };
1461 #undef SFSWEEP
1462 int ret = 1;
1463
1464 ret &= MDFNSS_StateAction(sm, load, data_only, StateRegs, "SPU");
1465
1466 if(load)
1467 {
1468 for(unsigned i = 0; i < 24; i++)
1469 {
1470 Voices[i].DecodeReadPos &= 0x1F;
1471 Voices[i].DecodeWritePos &= 0x1F;
1472 }
1473
1474 RvbResPos &= 0x3F;
1475
1476 IRQ_Assert(IRQ_SPU, IRQAsserted);
1477 }
1478
1479 return(ret);
1480 }
1481
1482 uint16 PS_SPU::PeekSPURAM(uint32 address)
1483 {
1484 return(SPURAM[address & 0x3FFFF]);
1485 }
1486
1487 void PS_SPU::PokeSPURAM(uint32 address, uint16 value)
1488 {
1489 SPURAM[address & 0x3FFFF] = value;
1490 }
1491
1492 uint32 PS_SPU::GetRegister(unsigned int which, char *special, const uint32 special_len)
1493 {
1494 if(which >= 0x8000)
1495 {
1496 unsigned int v = (which - 0x8000) >> 8;
1497
1498 switch((which & 0xFF) | 0x8000)
1499 {
1500 case GSREG_V0_VOL_CTRL_L:
1501 return Regs[v * 8 + 0x0];
1502 case GSREG_V0_VOL_CTRL_R:
1503 return Regs[v * 8 + 0x1];
1504 case GSREG_V0_VOL_L:
1505 return Voices[v].Sweep[0].ReadVolume() & 0xFFFF;
1506 case GSREG_V0_VOL_R:
1507 return Voices[v].Sweep[1].ReadVolume() & 0xFFFF;
1508 case GSREG_V0_PITCH:
1509 return Voices[v].Pitch;
1510 case GSREG_V0_STARTADDR:
1511 return Voices[v].StartAddr;
1512 case GSREG_V0_ADSR_CTRL:
1513 return Voices[v].ADSRControl;
1514 case GSREG_V0_ADSR_LEVEL:
1515 return Voices[v].ADSR.EnvLevel;
1516 case GSREG_V0_LOOP_ADDR:
1517 return Voices[v].LoopAddr;
1518 case GSREG_V0_READ_ADDR:
1519 return Voices[v].CurAddr;
1520 }
1521 }
1522 else if (which >= 18 && which <= 49)
1523 return ReverbRegs[which - GSREG_FB_SRC_A];
1524 else switch(which)
1525 {
1526 case GSREG_SPUCONTROL:
1527 return SPUControl;
1528 case GSREG_FM_ON:
1529 return FM_Mode;
1530 case GSREG_NOISE_ON:
1531 return Noise_Mode;
1532 case GSREG_REVERB_ON:
1533 return Reverb_Mode;
1534 case GSREG_CDVOL_L:
1535 return (uint16)CDVol[0];
1536 case GSREG_CDVOL_R:
1537 return (uint16)CDVol[1];
1538 case GSREG_MAINVOL_CTRL_L:
1539 return Regs[0xC0];
1540 case GSREG_MAINVOL_CTRL_R:
1541 return Regs[0xC1];
1542 case GSREG_MAINVOL_L:
1543 return GlobalSweep[0].ReadVolume() & 0xFFFF;
1544 case GSREG_MAINVOL_R:
1545 return GlobalSweep[1].ReadVolume() & 0xFFFF;
1546 case GSREG_RVBVOL_L:
1547 return (uint16)ReverbVol[0];
1548 case GSREG_RVBVOL_R:
1549 return (uint16)ReverbVol[1];
1550 case GSREG_RWADDR:
1551 return RWAddr;
1552 case GSREG_IRQADDR:
1553 return IRQAddr;
1554 case GSREG_REVERBWA:
1555 return ReverbWA >> 2;
1556 case GSREG_VOICEON:
1557 return VoiceOn;
1558 case GSREG_VOICEOFF:
1559 return VoiceOff;
1560 case GSREG_BLOCKEND:
1561 return BlockEnd;
1562 }
1563
1564 return 0xDEADBEEF;
1565 }
1566
1567 void PS_SPU::SetRegister(unsigned int which, uint32 value)
1568 {
1569 if(which >= GSREG_FB_SRC_A && which <= GSREG_IN_COEF_R)
1570 ReverbRegs[which - GSREG_FB_SRC_A] = value;
1571 else switch(which)
1572 {
1573 case GSREG_SPUCONTROL:
1574 SPUControl = value;
1575 break;
1576
1577 case GSREG_FM_ON:
1578 FM_Mode = value & 0xFFFFFF;
1579 break;
1580
1581 case GSREG_NOISE_ON:
1582 Noise_Mode = value & 0xFFFFFF;
1583 break;
1584
1585 case GSREG_REVERB_ON:
1586 Reverb_Mode = value & 0xFFFFFF;
1587 break;
1588
1589 case GSREG_CDVOL_L:
1590 CDVol[0] = (int16)value;
1591 break;
1592
1593 case GSREG_CDVOL_R:
1594 CDVol[1] = (int16)value;
1595 break;
1596
1597 case GSREG_MAINVOL_CTRL_L:
1598 Regs[0xC0] = value;
1599 GlobalSweep[0].WriteControl(value);
1600 //GlobalSweep[0].Control = value;
1601 break;
1602
1603 case GSREG_MAINVOL_CTRL_R:
1604 Regs[0xC1] = value;
1605 GlobalSweep[1].WriteControl(value);
1606 //GlobalSweep[1].Control = value;
1607 break;
1608
1609 case GSREG_MAINVOL_L:
1610 GlobalSweep[0].WriteVolume(value);
1611 break;
1612
1613 case GSREG_MAINVOL_R:
1614 GlobalSweep[1].WriteVolume(value);
1615 break;
1616
1617 case GSREG_RVBVOL_L:
1618 ReverbVol[0] = (int16)value;
1619 break;
1620
1621 case GSREG_RVBVOL_R:
1622 ReverbVol[1] = (int16)value;
1623 break;
1624
1625 case GSREG_RWADDR:
1626 RWAddr = value & 0x3FFFF;
1627 break;
1628
1629 case GSREG_IRQADDR:
1630 IRQAddr = value & 0x3FFFC;
1631 break;
1632
1633 //
1634 // REVERB_WA
1635 //
1636
1637 case GSREG_VOICEON:
1638 VoiceOn = value & 0xFFFFFF;
1639 break;
1640
1641 case GSREG_VOICEOFF:
1642 VoiceOff = value & 0xFFFFFF;
1643 break;
1644
1645 case GSREG_BLOCKEND:
1646 BlockEnd = value & 0xFFFFFF;
1647 break;
1648 }
1649 }
0 #ifndef __MDFN_PSX_SPU_H
1 #define __MDFN_PSX_SPU_H
2
3 extern uint32_t IntermediateBufferPos;
4 extern int16_t IntermediateBuffer[4096][2];
5
6 enum
7 {
8 ADSR_ATTACK = 0,
9 ADSR_DECAY = 1,
10 ADSR_SUSTAIN = 2,
11 ADSR_RELEASE = 3
12 };
13
14 // Buffers 44.1KHz samples, should have enough for two(worst-case scenario) video frames(2* ~735 frames NTSC, 2* ~882 PAL) plus jitter plus enough for the resampler leftovers.
15 // We'll just go with 4096 because powers of 2 are AWESOME and such.
16
17 struct SPU_ADSR
18 {
19 uint16_t EnvLevel; // We typecast it to (int16) in several places, but keep it here as (uint16) to prevent signed overflow/underflow, which compilers
20 // may not treat consistently.
21 uint32_t Divider;
22 uint32_t Phase;
23
24 bool AttackExp;
25 bool SustainExp;
26 bool SustainDec;
27 bool ReleaseExp;
28
29 int32_t AttackRate; // Ar
30 int32_t DecayRate; // Dr * 4
31 int32_t SustainRate; // Sr
32 int32_t ReleaseRate; // Rr * 4
33
34 int32_t SustainLevel; // (Sl + 1) << 11
35 };
36
37 class PS_SPU;
38 class SPU_Sweep
39 {
40 friend class PS_SPU; // For save states - FIXME(remove in future?)
41
42 public:
43 SPU_Sweep() { }
44 ~SPU_Sweep() { }
45
46 void Power(void);
47
48 void WriteControl(uint16_t value);
49 int16 ReadVolume(void);
50
51 void WriteVolume(int16 value);
52
53 void Clock(void);
54
55 private:
56 uint16_t Control;
57 uint16_t Current;
58 uint32_t Divider;
59 };
60
61 struct SPU_Voice
62 {
63 int16 DecodeBuffer[0x20];
64 int16 DecodeM2;
65 int16 DecodeM1;
66
67 uint32 DecodePlayDelay;
68 uint32 DecodeWritePos;
69 uint32 DecodeReadPos;
70 uint32 DecodeAvail;
71
72 bool IgnoreSampLA;
73
74 uint8 DecodeShift;
75 uint8 DecodeWeight;
76 uint8_t DecodeFlags;
77
78 SPU_Sweep Sweep[2];
79
80 uint16_t Pitch;
81 uint32_t CurPhase;
82
83 uint32_t StartAddr;
84
85 uint32_t CurAddr;
86
87 uint32_t ADSRControl;
88
89 uint32_t LoopAddr;
90
91 int32_t PreLRSample; // After enveloping, but before L/R volume. Range of -32768 to 32767
92
93 SPU_ADSR ADSR;
94 };
95
96 class PS_SPU
97 {
98 public:
99
100 PS_SPU();
101 ~PS_SPU();
102
103 int StateAction(StateMem *sm, int load, int data_only);
104
105 void Power(void);
106 void Write(int32_t timestamp, uint32_t A, uint16_t V);
107 uint16_t Read(int32_t timestamp, uint32_t A);
108
109 void WriteDMA(uint32_t V);
110 uint32_t ReadDMA(void);
111
112 int32_t UpdateFromCDC(int32_t clocks);
113
114 private:
115
116 void CheckIRQAddr(uint32_t addr);
117 void WriteSPURAM(uint32_t addr, uint16_t value);
118 uint16_t ReadSPURAM(uint32_t addr);
119
120 void RunDecoder(SPU_Voice *voice);
121
122 void CacheEnvelope(SPU_Voice *voice);
123 void ResetEnvelope(SPU_Voice *voice);
124 void ReleaseEnvelope(SPU_Voice *voice);
125 void RunEnvelope(SPU_Voice *voice);
126
127
128 void RunReverb(const int32* in, int32* out);
129 void RunNoise(void);
130 bool GetCDAudio(int32_t &l, int32_t &r);
131
132 SPU_Voice Voices[24];
133
134 uint32_t NoiseDivider;
135 uint32_t NoiseCounter;
136 uint16_t LFSR;
137
138 uint32_t FM_Mode;
139 uint32_t Noise_Mode;
140 uint32_t Reverb_Mode;
141
142 uint32_t ReverbWA;
143
144 SPU_Sweep GlobalSweep[2]; // Doesn't affect reverb volume!
145
146 int32_t ReverbVol[2];
147
148 int32_t CDVol[2];
149 int32_t ExternVol[2];
150
151 uint32_t IRQAddr;
152
153 uint32_t RWAddr;
154
155 uint16_t SPUControl;
156
157 uint32_t VoiceOn;
158 uint32_t VoiceOff;
159
160 uint32_t BlockEnd;
161
162 uint32_t CWA;
163
164 union
165 {
166 uint16_t Regs[0x100];
167 struct
168 {
169 uint16_t VoiceRegs[0xC0];
170 union
171 {
172 uint16_t GlobalRegs[0x20];
173 struct
174 {
175 uint16_t _Global0[0x17];
176 uint16_t SPUStatus;
177 uint16_t _Global1[0x08];
178 };
179 };
180 union
181 {
182 uint16 ReverbRegs[0x20];
183
184 struct
185 {
186 uint16 FB_SRC_A;
187 uint16 FB_SRC_B;
188 int16 IIR_ALPHA;
189 int16 ACC_COEF_A;
190 int16 ACC_COEF_B;
191 int16 ACC_COEF_C;
192 int16 ACC_COEF_D;
193 int16 IIR_COEF;
194 int16 FB_ALPHA;
195 int16 FB_X;
196 uint16 IIR_DEST_A0;
197 uint16 IIR_DEST_A1;
198 uint16 ACC_SRC_A0;
199 uint16 ACC_SRC_A1;
200 uint16 ACC_SRC_B0;
201 uint16 ACC_SRC_B1;
202 uint16 IIR_SRC_A0;
203 uint16 IIR_SRC_A1;
204 uint16 IIR_DEST_B0;
205 uint16 IIR_DEST_B1;
206 uint16 ACC_SRC_C0;
207 uint16 ACC_SRC_C1;
208 uint16 ACC_SRC_D0;
209 uint16 ACC_SRC_D1;
210 uint16 IIR_SRC_B1;
211 uint16 IIR_SRC_B0;
212 uint16 MIX_DEST_A0;
213 uint16 MIX_DEST_A1;
214 uint16 MIX_DEST_B0;
215 uint16 MIX_DEST_B1;
216 int16 IN_COEF_L;
217 int16 IN_COEF_R;
218 };
219 };
220 };
221 };
222
223 uint16_t AuxRegs[0x10];
224
225 int16 RDSB[2][128]; // [40]
226 int16 RUSB[2][64];
227 int32_t RvbResPos;
228
229 uint32_t ReverbCur;
230
231 uint32_t Get_Reverb_Offset(uint32_t offset);
232 int16 RD_RVB(uint16 raw_offs, int32 extra_offs = 0);
233 void WR_RVB(uint16 raw_offs, int16 sample);
234
235 bool IRQAsserted;
236
237 int32_t clock_divider;
238
239 uint16_t SPURAM[524288 / sizeof(uint16)];
240
241 int last_rate;
242 uint32_t last_quality;
243
244 public:
245 enum
246 {
247 GSREG_SPUCONTROL = 0,
248
249 GSREG_FM_ON,
250 GSREG_NOISE_ON,
251 GSREG_REVERB_ON,
252
253 GSREG_CDVOL_L,
254 GSREG_CDVOL_R,
255
256 GSREG_MAINVOL_CTRL_L,
257 GSREG_MAINVOL_CTRL_R,
258
259 GSREG_MAINVOL_L,
260 GSREG_MAINVOL_R,
261
262 GSREG_RVBVOL_L,
263 GSREG_RVBVOL_R,
264
265 GSREG_RWADDR,
266
267 GSREG_IRQADDR,
268
269 GSREG_REVERBWA,
270
271 GSREG_VOICEON,
272 GSREG_VOICEOFF,
273 GSREG_BLOCKEND,
274
275 // Note: the order of these should match the reverb reg array
276 GSREG_FB_SRC_A,
277 GSREG_FB_SRC_B,
278 GSREG_IIR_ALPHA,
279 GSREG_ACC_COEF_A,
280 GSREG_ACC_COEF_B,
281 GSREG_ACC_COEF_C,
282 GSREG_ACC_COEF_D,
283 GSREG_IIR_COEF,
284 GSREG_FB_ALPHA,
285 GSREG_FB_X,
286 GSREG_IIR_DEST_A0,
287 GSREG_IIR_DEST_A1,
288 GSREG_ACC_SRC_A0,
289 GSREG_ACC_SRC_A1,
290 GSREG_ACC_SRC_B0,
291 GSREG_ACC_SRC_B1,
292 GSREG_IIR_SRC_A0,
293 GSREG_IIR_SRC_A1,
294 GSREG_IIR_DEST_B0,
295 GSREG_IIR_DEST_B1,
296 GSREG_ACC_SRC_C0,
297 GSREG_ACC_SRC_C1,
298 GSREG_ACC_SRC_D0,
299 GSREG_ACC_SRC_D1,
300 GSREG_IIR_SRC_B1,
301 GSREG_IIR_SRC_B0,
302 GSREG_MIX_DEST_A0,
303 GSREG_MIX_DEST_A1,
304 GSREG_MIX_DEST_B0,
305 GSREG_MIX_DEST_B1,
306 GSREG_IN_COEF_L,
307 GSREG_IN_COEF_R,
308
309
310 // Multiply v * 256 for each extra voice
311 GSREG_V0_VOL_CTRL_L = 0x8000,
312 GSREG_V0_VOL_CTRL_R,
313 GSREG_V0_VOL_L,
314 GSREG_V0_VOL_R,
315 GSREG_V0_PITCH,
316 GSREG_V0_STARTADDR,
317 GSREG_V0_ADSR_CTRL,
318 GSREG_V0_ADSR_LEVEL,
319 GSREG_V0_LOOP_ADDR,
320 GSREG_V0_READ_ADDR
321 };
322
323 uint32_t GetRegister(unsigned int which, char *special, const uint32_t special_len);
324 void SetRegister(unsigned int which, uint32_t value);
325
326 uint16_t PeekSPURAM(uint32_t address);
327 void PokeSPURAM(uint32_t address, uint16_t value);
328 };
329
330 #endif
0 { (int16)0x12c7, (int16)0x59b3, (int16)0x1307, (int16)0xffff },
1 { (int16)0x1288, (int16)0x59b2, (int16)0x1347, (int16)0xffff },
2 { (int16)0x1249, (int16)0x59b0, (int16)0x1388, (int16)0xffff },
3 { (int16)0x120b, (int16)0x59ad, (int16)0x13c9, (int16)0xffff },
4 { (int16)0x11cd, (int16)0x59a9, (int16)0x140b, (int16)0xffff },
5 { (int16)0x118f, (int16)0x59a4, (int16)0x144d, (int16)0xffff },
6 { (int16)0x1153, (int16)0x599e, (int16)0x1490, (int16)0xffff },
7 { (int16)0x1116, (int16)0x5997, (int16)0x14d4, (int16)0xffff },
8 { (int16)0x10db, (int16)0x598f, (int16)0x1517, (int16)0xffff },
9 { (int16)0x109f, (int16)0x5986, (int16)0x155c, (int16)0xffff },
10 { (int16)0x1065, (int16)0x597c, (int16)0x15a0, (int16)0xffff },
11 { (int16)0x102a, (int16)0x5971, (int16)0x15e6, (int16)0xffff },
12 { (int16)0x0ff1, (int16)0x5965, (int16)0x162c, (int16)0xffff },
13 { (int16)0x0fb7, (int16)0x5958, (int16)0x1672, (int16)0xffff },
14 { (int16)0x0f7f, (int16)0x5949, (int16)0x16b9, (int16)0xffff },
15 { (int16)0x0f46, (int16)0x593a, (int16)0x1700, (int16)0xffff },
16 { (int16)0x0f0f, (int16)0x592a, (int16)0x1747, (int16)0x0000 },
17 { (int16)0x0ed7, (int16)0x5919, (int16)0x1790, (int16)0x0000 },
18 { (int16)0x0ea1, (int16)0x5907, (int16)0x17d8, (int16)0x0000 },
19 { (int16)0x0e6b, (int16)0x58f4, (int16)0x1821, (int16)0x0000 },
20 { (int16)0x0e35, (int16)0x58e0, (int16)0x186b, (int16)0x0000 },
21 { (int16)0x0e00, (int16)0x58cb, (int16)0x18b5, (int16)0x0000 },
22 { (int16)0x0dcb, (int16)0x58b5, (int16)0x1900, (int16)0x0000 },
23 { (int16)0x0d97, (int16)0x589e, (int16)0x194b, (int16)0x0001 },
24 { (int16)0x0d63, (int16)0x5886, (int16)0x1996, (int16)0x0001 },
25 { (int16)0x0d30, (int16)0x586d, (int16)0x19e2, (int16)0x0001 },
26 { (int16)0x0cfd, (int16)0x5853, (int16)0x1a2e, (int16)0x0001 },
27 { (int16)0x0ccb, (int16)0x5838, (int16)0x1a7b, (int16)0x0002 },
28 { (int16)0x0c99, (int16)0x581c, (int16)0x1ac8, (int16)0x0002 },
29 { (int16)0x0c68, (int16)0x57ff, (int16)0x1b16, (int16)0x0002 },
30 { (int16)0x0c38, (int16)0x57e2, (int16)0x1b64, (int16)0x0003 },
31 { (int16)0x0c07, (int16)0x57c3, (int16)0x1bb3, (int16)0x0003 },
32 { (int16)0x0bd8, (int16)0x57a3, (int16)0x1c02, (int16)0x0003 },
33 { (int16)0x0ba9, (int16)0x5782, (int16)0x1c51, (int16)0x0004 },
34 { (int16)0x0b7a, (int16)0x5761, (int16)0x1ca1, (int16)0x0004 },
35 { (int16)0x0b4c, (int16)0x573e, (int16)0x1cf1, (int16)0x0005 },
36 { (int16)0x0b1e, (int16)0x571b, (int16)0x1d42, (int16)0x0005 },
37 { (int16)0x0af1, (int16)0x56f6, (int16)0x1d93, (int16)0x0006 },
38 { (int16)0x0ac4, (int16)0x56d1, (int16)0x1de5, (int16)0x0007 },
39 { (int16)0x0a98, (int16)0x56ab, (int16)0x1e37, (int16)0x0007 },
40 { (int16)0x0a6c, (int16)0x5684, (int16)0x1e89, (int16)0x0008 },
41 { (int16)0x0a40, (int16)0x565b, (int16)0x1edc, (int16)0x0009 },
42 { (int16)0x0a16, (int16)0x5632, (int16)0x1f2f, (int16)0x0009 },
43 { (int16)0x09eb, (int16)0x5609, (int16)0x1f82, (int16)0x000a },
44 { (int16)0x09c1, (int16)0x55de, (int16)0x1fd6, (int16)0x000b },
45 { (int16)0x0998, (int16)0x55b2, (int16)0x202a, (int16)0x000c },
46 { (int16)0x096f, (int16)0x5585, (int16)0x207f, (int16)0x000d },
47 { (int16)0x0946, (int16)0x5558, (int16)0x20d4, (int16)0x000e },
48 { (int16)0x091e, (int16)0x5529, (int16)0x2129, (int16)0x000f },
49 { (int16)0x08f7, (int16)0x54fa, (int16)0x217f, (int16)0x0010 },
50 { (int16)0x08d0, (int16)0x54ca, (int16)0x21d5, (int16)0x0011 },
51 { (int16)0x08a9, (int16)0x5499, (int16)0x222c, (int16)0x0012 },
52 { (int16)0x0883, (int16)0x5467, (int16)0x2282, (int16)0x0013 },
53 { (int16)0x085d, (int16)0x5434, (int16)0x22da, (int16)0x0015 },
54 { (int16)0x0838, (int16)0x5401, (int16)0x2331, (int16)0x0016 },
55 { (int16)0x0813, (int16)0x53cc, (int16)0x2389, (int16)0x0018 },
56 { (int16)0x07ef, (int16)0x5397, (int16)0x23e1, (int16)0x0019 },
57 { (int16)0x07cb, (int16)0x5361, (int16)0x2439, (int16)0x001b },
58 { (int16)0x07a7, (int16)0x532a, (int16)0x2492, (int16)0x001c },
59 { (int16)0x0784, (int16)0x52f3, (int16)0x24eb, (int16)0x001e },
60 { (int16)0x0762, (int16)0x52ba, (int16)0x2545, (int16)0x0020 },
61 { (int16)0x0740, (int16)0x5281, (int16)0x259e, (int16)0x0021 },
62 { (int16)0x071e, (int16)0x5247, (int16)0x25f8, (int16)0x0023 },
63 { (int16)0x06fd, (int16)0x520c, (int16)0x2653, (int16)0x0025 },
64 { (int16)0x06dc, (int16)0x51d0, (int16)0x26ad, (int16)0x0027 },
65 { (int16)0x06bb, (int16)0x5194, (int16)0x2708, (int16)0x0029 },
66 { (int16)0x069b, (int16)0x5156, (int16)0x2763, (int16)0x002c },
67 { (int16)0x067c, (int16)0x5118, (int16)0x27be, (int16)0x002e },
68 { (int16)0x065c, (int16)0x50da, (int16)0x281a, (int16)0x0030 },
69 { (int16)0x063e, (int16)0x509a, (int16)0x2876, (int16)0x0033 },
70 { (int16)0x061f, (int16)0x505a, (int16)0x28d2, (int16)0x0035 },
71 { (int16)0x0601, (int16)0x5019, (int16)0x292e, (int16)0x0038 },
72 { (int16)0x05e4, (int16)0x4fd7, (int16)0x298b, (int16)0x003a },
73 { (int16)0x05c7, (int16)0x4f95, (int16)0x29e7, (int16)0x003d },
74 { (int16)0x05aa, (int16)0x4f52, (int16)0x2a44, (int16)0x0040 },
75 { (int16)0x058e, (int16)0x4f0e, (int16)0x2aa1, (int16)0x0043 },
76 { (int16)0x0572, (int16)0x4ec9, (int16)0x2aff, (int16)0x0046 },
77 { (int16)0x0556, (int16)0x4e84, (int16)0x2b5c, (int16)0x0049 },
78 { (int16)0x053b, (int16)0x4e3e, (int16)0x2bba, (int16)0x004d },
79 { (int16)0x0520, (int16)0x4df7, (int16)0x2c18, (int16)0x0050 },
80 { (int16)0x0506, (int16)0x4db0, (int16)0x2c76, (int16)0x0054 },
81 { (int16)0x04ec, (int16)0x4d68, (int16)0x2cd4, (int16)0x0057 },
82 { (int16)0x04d2, (int16)0x4d20, (int16)0x2d33, (int16)0x005b },
83 { (int16)0x04b9, (int16)0x4cd7, (int16)0x2d91, (int16)0x005f },
84 { (int16)0x04a0, (int16)0x4c8d, (int16)0x2df0, (int16)0x0063 },
85 { (int16)0x0488, (int16)0x4c42, (int16)0x2e4f, (int16)0x0067 },
86 { (int16)0x0470, (int16)0x4bf7, (int16)0x2eae, (int16)0x006b },
87 { (int16)0x0458, (int16)0x4bac, (int16)0x2f0d, (int16)0x006f },
88 { (int16)0x0441, (int16)0x4b5f, (int16)0x2f6c, (int16)0x0074 },
89 { (int16)0x042a, (int16)0x4b13, (int16)0x2fcc, (int16)0x0078 },
90 { (int16)0x0413, (int16)0x4ac5, (int16)0x302b, (int16)0x007d },
91 { (int16)0x03fc, (int16)0x4a77, (int16)0x308b, (int16)0x0082 },
92 { (int16)0x03e7, (int16)0x4a29, (int16)0x30ea, (int16)0x0087 },
93 { (int16)0x03d1, (int16)0x49d9, (int16)0x314a, (int16)0x008c },
94 { (int16)0x03bc, (int16)0x498a, (int16)0x31aa, (int16)0x0091 },
95 { (int16)0x03a7, (int16)0x493a, (int16)0x3209, (int16)0x0096 },
96 { (int16)0x0392, (int16)0x48e9, (int16)0x3269, (int16)0x009c },
97 { (int16)0x037e, (int16)0x4898, (int16)0x32c9, (int16)0x00a1 },
98 { (int16)0x036a, (int16)0x4846, (int16)0x3329, (int16)0x00a7 },
99 { (int16)0x0356, (int16)0x47f4, (int16)0x3389, (int16)0x00ad },
100 { (int16)0x0343, (int16)0x47a1, (int16)0x33e9, (int16)0x00b3 },
101 { (int16)0x0330, (int16)0x474e, (int16)0x3449, (int16)0x00ba },
102 { (int16)0x031d, (int16)0x46fa, (int16)0x34a9, (int16)0x00c0 },
103 { (int16)0x030b, (int16)0x46a6, (int16)0x3509, (int16)0x00c7 },
104 { (int16)0x02f9, (int16)0x4651, (int16)0x3569, (int16)0x00cd },
105 { (int16)0x02e7, (int16)0x45fc, (int16)0x35c9, (int16)0x00d4 },
106 { (int16)0x02d6, (int16)0x45a6, (int16)0x3629, (int16)0x00db },
107 { (int16)0x02c4, (int16)0x4550, (int16)0x3689, (int16)0x00e3 },
108 { (int16)0x02b4, (int16)0x44fa, (int16)0x36e8, (int16)0x00ea },
109 { (int16)0x02a3, (int16)0x44a3, (int16)0x3748, (int16)0x00f2 },
110 { (int16)0x0293, (int16)0x444c, (int16)0x37a8, (int16)0x00fa },
111 { (int16)0x0283, (int16)0x43f4, (int16)0x3807, (int16)0x0101 },
112 { (int16)0x0273, (int16)0x439c, (int16)0x3867, (int16)0x010a },
113 { (int16)0x0264, (int16)0x4344, (int16)0x38c6, (int16)0x0112 },
114 { (int16)0x0255, (int16)0x42eb, (int16)0x3926, (int16)0x011b },
115 { (int16)0x0246, (int16)0x4292, (int16)0x3985, (int16)0x0123 },
116 { (int16)0x0237, (int16)0x4239, (int16)0x39e4, (int16)0x012c },
117 { (int16)0x0229, (int16)0x41df, (int16)0x3a43, (int16)0x0135 },
118 { (int16)0x021b, (int16)0x4185, (int16)0x3aa2, (int16)0x013f },
119 { (int16)0x020d, (int16)0x412a, (int16)0x3b00, (int16)0x0148 },
120 { (int16)0x0200, (int16)0x40d0, (int16)0x3b5f, (int16)0x0152 },
121 { (int16)0x01f2, (int16)0x4074, (int16)0x3bbd, (int16)0x015c },
122 { (int16)0x01e5, (int16)0x4019, (int16)0x3c1b, (int16)0x0166 },
123 { (int16)0x01d9, (int16)0x3fbd, (int16)0x3c79, (int16)0x0171 },
124 { (int16)0x01cc, (int16)0x3f62, (int16)0x3cd7, (int16)0x017b },
125 { (int16)0x01c0, (int16)0x3f05, (int16)0x3d35, (int16)0x0186 },
126 { (int16)0x01b4, (int16)0x3ea9, (int16)0x3d92, (int16)0x0191 },
127 { (int16)0x01a8, (int16)0x3e4c, (int16)0x3def, (int16)0x019c },
128 { (int16)0x019c, (int16)0x3def, (int16)0x3e4c, (int16)0x01a8 },
129 { (int16)0x0191, (int16)0x3d92, (int16)0x3ea9, (int16)0x01b4 },
130 { (int16)0x0186, (int16)0x3d35, (int16)0x3f05, (int16)0x01c0 },
131 { (int16)0x017b, (int16)0x3cd7, (int16)0x3f62, (int16)0x01cc },
132 { (int16)0x0171, (int16)0x3c79, (int16)0x3fbd, (int16)0x01d9 },
133 { (int16)0x0166, (int16)0x3c1b, (int16)0x4019, (int16)0x01e5 },
134 { (int16)0x015c, (int16)0x3bbd, (int16)0x4074, (int16)0x01f2 },
135 { (int16)0x0152, (int16)0x3b5f, (int16)0x40d0, (int16)0x0200 },
136 { (int16)0x0148, (int16)0x3b00, (int16)0x412a, (int16)0x020d },
137 { (int16)0x013f, (int16)0x3aa2, (int16)0x4185, (int16)0x021b },
138 { (int16)0x0135, (int16)0x3a43, (int16)0x41df, (int16)0x0229 },
139 { (int16)0x012c, (int16)0x39e4, (int16)0x4239, (int16)0x0237 },
140 { (int16)0x0123, (int16)0x3985, (int16)0x4292, (int16)0x0246 },
141 { (int16)0x011b, (int16)0x3926, (int16)0x42eb, (int16)0x0255 },
142 { (int16)0x0112, (int16)0x38c6, (int16)0x4344, (int16)0x0264 },
143 { (int16)0x010a, (int16)0x3867, (int16)0x439c, (int16)0x0273 },
144 { (int16)0x0101, (int16)0x3807, (int16)0x43f4, (int16)0x0283 },
145 { (int16)0x00fa, (int16)0x37a8, (int16)0x444c, (int16)0x0293 },
146 { (int16)0x00f2, (int16)0x3748, (int16)0x44a3, (int16)0x02a3 },
147 { (int16)0x00ea, (int16)0x36e8, (int16)0x44fa, (int16)0x02b4 },
148 { (int16)0x00e3, (int16)0x3689, (int16)0x4550, (int16)0x02c4 },
149 { (int16)0x00db, (int16)0x3629, (int16)0x45a6, (int16)0x02d6 },
150 { (int16)0x00d4, (int16)0x35c9, (int16)0x45fc, (int16)0x02e7 },
151 { (int16)0x00cd, (int16)0x3569, (int16)0x4651, (int16)0x02f9 },
152 { (int16)0x00c7, (int16)0x3509, (int16)0x46a6, (int16)0x030b },
153 { (int16)0x00c0, (int16)0x34a9, (int16)0x46fa, (int16)0x031d },
154 { (int16)0x00ba, (int16)0x3449, (int16)0x474e, (int16)0x0330 },
155 { (int16)0x00b3, (int16)0x33e9, (int16)0x47a1, (int16)0x0343 },
156 { (int16)0x00ad, (int16)0x3389, (int16)0x47f4, (int16)0x0356 },
157 { (int16)0x00a7, (int16)0x3329, (int16)0x4846, (int16)0x036a },
158 { (int16)0x00a1, (int16)0x32c9, (int16)0x4898, (int16)0x037e },
159 { (int16)0x009c, (int16)0x3269, (int16)0x48e9, (int16)0x0392 },
160 { (int16)0x0096, (int16)0x3209, (int16)0x493a, (int16)0x03a7 },
161 { (int16)0x0091, (int16)0x31aa, (int16)0x498a, (int16)0x03bc },
162 { (int16)0x008c, (int16)0x314a, (int16)0x49d9, (int16)0x03d1 },
163 { (int16)0x0087, (int16)0x30ea, (int16)0x4a29, (int16)0x03e7 },
164 { (int16)0x0082, (int16)0x308b, (int16)0x4a77, (int16)0x03fc },
165 { (int16)0x007d, (int16)0x302b, (int16)0x4ac5, (int16)0x0413 },
166 { (int16)0x0078, (int16)0x2fcc, (int16)0x4b13, (int16)0x042a },
167 { (int16)0x0074, (int16)0x2f6c, (int16)0x4b5f, (int16)0x0441 },
168 { (int16)0x006f, (int16)0x2f0d, (int16)0x4bac, (int16)0x0458 },
169 { (int16)0x006b, (int16)0x2eae, (int16)0x4bf7, (int16)0x0470 },
170 { (int16)0x0067, (int16)0x2e4f, (int16)0x4c42, (int16)0x0488 },
171 { (int16)0x0063, (int16)0x2df0, (int16)0x4c8d, (int16)0x04a0 },
172 { (int16)0x005f, (int16)0x2d91, (int16)0x4cd7, (int16)0x04b9 },
173 { (int16)0x005b, (int16)0x2d33, (int16)0x4d20, (int16)0x04d2 },
174 { (int16)0x0057, (int16)0x2cd4, (int16)0x4d68, (int16)0x04ec },
175 { (int16)0x0054, (int16)0x2c76, (int16)0x4db0, (int16)0x0506 },
176 { (int16)0x0050, (int16)0x2c18, (int16)0x4df7, (int16)0x0520 },
177 { (int16)0x004d, (int16)0x2bba, (int16)0x4e3e, (int16)0x053b },
178 { (int16)0x0049, (int16)0x2b5c, (int16)0x4e84, (int16)0x0556 },
179 { (int16)0x0046, (int16)0x2aff, (int16)0x4ec9, (int16)0x0572 },
180 { (int16)0x0043, (int16)0x2aa1, (int16)0x4f0e, (int16)0x058e },
181 { (int16)0x0040, (int16)0x2a44, (int16)0x4f52, (int16)0x05aa },
182 { (int16)0x003d, (int16)0x29e7, (int16)0x4f95, (int16)0x05c7 },
183 { (int16)0x003a, (int16)0x298b, (int16)0x4fd7, (int16)0x05e4 },
184 { (int16)0x0038, (int16)0x292e, (int16)0x5019, (int16)0x0601 },
185 { (int16)0x0035, (int16)0x28d2, (int16)0x505a, (int16)0x061f },
186 { (int16)0x0033, (int16)0x2876, (int16)0x509a, (int16)0x063e },
187 { (int16)0x0030, (int16)0x281a, (int16)0x50da, (int16)0x065c },
188 { (int16)0x002e, (int16)0x27be, (int16)0x5118, (int16)0x067c },
189 { (int16)0x002c, (int16)0x2763, (int16)0x5156, (int16)0x069b },
190 { (int16)0x0029, (int16)0x2708, (int16)0x5194, (int16)0x06bb },
191 { (int16)0x0027, (int16)0x26ad, (int16)0x51d0, (int16)0x06dc },
192 { (int16)0x0025, (int16)0x2653, (int16)0x520c, (int16)0x06fd },
193 { (int16)0x0023, (int16)0x25f8, (int16)0x5247, (int16)0x071e },
194 { (int16)0x0021, (int16)0x259e, (int16)0x5281, (int16)0x0740 },
195 { (int16)0x0020, (int16)0x2545, (int16)0x52ba, (int16)0x0762 },
196 { (int16)0x001e, (int16)0x24eb, (int16)0x52f3, (int16)0x0784 },
197 { (int16)0x001c, (int16)0x2492, (int16)0x532a, (int16)0x07a7 },
198 { (int16)0x001b, (int16)0x2439, (int16)0x5361, (int16)0x07cb },
199 { (int16)0x0019, (int16)0x23e1, (int16)0x5397, (int16)0x07ef },
200 { (int16)0x0018, (int16)0x2389, (int16)0x53cc, (int16)0x0813 },
201 { (int16)0x0016, (int16)0x2331, (int16)0x5401, (int16)0x0838 },
202 { (int16)0x0015, (int16)0x22da, (int16)0x5434, (int16)0x085d },
203 { (int16)0x0013, (int16)0x2282, (int16)0x5467, (int16)0x0883 },
204 { (int16)0x0012, (int16)0x222c, (int16)0x5499, (int16)0x08a9 },
205 { (int16)0x0011, (int16)0x21d5, (int16)0x54ca, (int16)0x08d0 },
206 { (int16)0x0010, (int16)0x217f, (int16)0x54fa, (int16)0x08f7 },
207 { (int16)0x000f, (int16)0x2129, (int16)0x5529, (int16)0x091e },
208 { (int16)0x000e, (int16)0x20d4, (int16)0x5558, (int16)0x0946 },
209 { (int16)0x000d, (int16)0x207f, (int16)0x5585, (int16)0x096f },
210 { (int16)0x000c, (int16)0x202a, (int16)0x55b2, (int16)0x0998 },
211 { (int16)0x000b, (int16)0x1fd6, (int16)0x55de, (int16)0x09c1 },
212 { (int16)0x000a, (int16)0x1f82, (int16)0x5609, (int16)0x09eb },
213 { (int16)0x0009, (int16)0x1f2f, (int16)0x5632, (int16)0x0a16 },
214 { (int16)0x0009, (int16)0x1edc, (int16)0x565b, (int16)0x0a40 },
215 { (int16)0x0008, (int16)0x1e89, (int16)0x5684, (int16)0x0a6c },
216 { (int16)0x0007, (int16)0x1e37, (int16)0x56ab, (int16)0x0a98 },
217 { (int16)0x0007, (int16)0x1de5, (int16)0x56d1, (int16)0x0ac4 },
218 { (int16)0x0006, (int16)0x1d93, (int16)0x56f6, (int16)0x0af1 },
219 { (int16)0x0005, (int16)0x1d42, (int16)0x571b, (int16)0x0b1e },
220 { (int16)0x0005, (int16)0x1cf1, (int16)0x573e, (int16)0x0b4c },
221 { (int16)0x0004, (int16)0x1ca1, (int16)0x5761, (int16)0x0b7a },
222 { (int16)0x0004, (int16)0x1c51, (int16)0x5782, (int16)0x0ba9 },
223 { (int16)0x0003, (int16)0x1c02, (int16)0x57a3, (int16)0x0bd8 },
224 { (int16)0x0003, (int16)0x1bb3, (int16)0x57c3, (int16)0x0c07 },
225 { (int16)0x0003, (int16)0x1b64, (int16)0x57e2, (int16)0x0c38 },
226 { (int16)0x0002, (int16)0x1b16, (int16)0x57ff, (int16)0x0c68 },
227 { (int16)0x0002, (int16)0x1ac8, (int16)0x581c, (int16)0x0c99 },
228 { (int16)0x0002, (int16)0x1a7b, (int16)0x5838, (int16)0x0ccb },
229 { (int16)0x0001, (int16)0x1a2e, (int16)0x5853, (int16)0x0cfd },
230 { (int16)0x0001, (int16)0x19e2, (int16)0x586d, (int16)0x0d30 },
231 { (int16)0x0001, (int16)0x1996, (int16)0x5886, (int16)0x0d63 },
232 { (int16)0x0001, (int16)0x194b, (int16)0x589e, (int16)0x0d97 },
233 { (int16)0x0000, (int16)0x1900, (int16)0x58b5, (int16)0x0dcb },
234 { (int16)0x0000, (int16)0x18b5, (int16)0x58cb, (int16)0x0e00 },
235 { (int16)0x0000, (int16)0x186b, (int16)0x58e0, (int16)0x0e35 },
236 { (int16)0x0000, (int16)0x1821, (int16)0x58f4, (int16)0x0e6b },
237 { (int16)0x0000, (int16)0x17d8, (int16)0x5907, (int16)0x0ea1 },
238 { (int16)0x0000, (int16)0x1790, (int16)0x5919, (int16)0x0ed7 },
239 { (int16)0x0000, (int16)0x1747, (int16)0x592a, (int16)0x0f0f },
240 { (int16)0xffff, (int16)0x1700, (int16)0x593a, (int16)0x0f46 },
241 { (int16)0xffff, (int16)0x16b9, (int16)0x5949, (int16)0x0f7f },
242 { (int16)0xffff, (int16)0x1672, (int16)0x5958, (int16)0x0fb7 },
243 { (int16)0xffff, (int16)0x162c, (int16)0x5965, (int16)0x0ff1 },
244 { (int16)0xffff, (int16)0x15e6, (int16)0x5971, (int16)0x102a },
245 { (int16)0xffff, (int16)0x15a0, (int16)0x597c, (int16)0x1065 },
246 { (int16)0xffff, (int16)0x155c, (int16)0x5986, (int16)0x109f },
247 { (int16)0xffff, (int16)0x1517, (int16)0x598f, (int16)0x10db },
248 { (int16)0xffff, (int16)0x14d4, (int16)0x5997, (int16)0x1116 },
249 { (int16)0xffff, (int16)0x1490, (int16)0x599e, (int16)0x1153 },
250 { (int16)0xffff, (int16)0x144d, (int16)0x59a4, (int16)0x118f },
251 { (int16)0xffff, (int16)0x140b, (int16)0x59a9, (int16)0x11cd },
252 { (int16)0xffff, (int16)0x13c9, (int16)0x59ad, (int16)0x120b },
253 { (int16)0xffff, (int16)0x1388, (int16)0x59b0, (int16)0x1249 },
254 { (int16)0xffff, (int16)0x1347, (int16)0x59b2, (int16)0x1288 },
255 { (int16)0xffff, (int16)0x1307, (int16)0x59b3, (int16)0x12c7 },
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "psx.h"
18 #include "timer.h"
19
20 /*
21 Notes(some of it may be incomplete or wrong in subtle ways)
22
23 Control bits:
24 Lower 3 bits of mode, for timer1(when mode is | 0x100):
25 0x1 = don't count while in vblank(except that the first count while in vblank does go through)
26 0x3 = vblank going inactive triggers timer reset, then some interesting behavior where counting again is delayed...
27 0x5 = vblank going inactive triggers timer reset, and only count within vblank.
28 0x7 = Wait until vblank goes active then inactive, then start counting?
29 For timer2:
30 0x1 = timer stopped(TODO: confirm on real system)
31
32 Target mode enabled 0x008
33 IRQ enable 0x010
34 --?Affects 0x400 status flag?-- 0x020
35 IRQ evaluation auto-reset 0x040
36 --unknown-- 0x080
37 Clock selection 0x100
38 Divide by 8(timer 2 only?) 0x200
39
40 Counter:
41 Reset to 0 on writes to the mode/status register.
42
43 Status flags:
44 Unknown flag 0x0400
45 Compare flag 0x0800
46 Cleared on mode/status read.
47 Set when: //ever Counter == 0(proooobably, need to investigate lower 3 bits in relation to this).
48
49
50 Overflow/Carry flag 0x1000
51 Cleared on mode/status read.
52 Set when counter overflows from 0xFFFF->0.
53
54 Hidden flags:
55 IRQ done
56 Cleared on writes to the mode/status register, on writes to the count register, and apparently automatically when the counter
57 increments if (Mode & 0x40) [Note: If target mode is enabled, and target is 0, IRQ done flag won't be automatically reset]
58
59 There seems to be a brief period(edge condition?) where, if count to target is enabled, you can (sometimes?) read the target value in the count
60 register before it's reset to 0. I doubt any games rely on this, but who knows. Maybe a PSX equivalent of the PC Engine "Battle Royale"? ;)
61
62 When the counter == 0, the compare flag is set. An IRQ will be generated if (Mode & 0x10), and the hidden IRQ done flag will be set.
63 */
64
65 /*
66 Dec. 26, 2011 Note
67 Due to problems I've had with my GPU timing test program, timer2 appears to be unreliable(clocks are skipped?) when target mode is enabled and the full
68 33MHz clock is used(rather than 33MHz / 8). TODO: Investigate further and confirm(or not).
69
70 Jan. 15, 2013 Note:
71 Counters using GPU clock sources(hretrace,dot clock) reportedly will with a low probability return wrong count values on an actual PS1, so keep this in mind
72 when writing test programs(IE keep reading the count value until two consecutive reads return the same value).
73 */
74
75 /*
76 FIXME: Clock appropriately(and update events) when using SetRegister() via the debugger.
77
78 TODO: If we ever return randomish values to "simulate" open bus, remember to change the return type and such of the TIMER_Read() function to full 32-bit too.
79 */
80
81 struct Timer
82 {
83 uint32_t Mode;
84 int32_t Counter; // Only 16-bit, but 32-bit here for detecting counting past target.
85 int32_t Target;
86
87 int32_t Div8Counter;
88
89 bool IRQDone;
90 int32_t DoZeCounting;
91 };
92
93 static bool vblank;
94 static bool hretrace;
95 static Timer Timers[3];
96 static int32_t lastts;
97
98 static int32_t CalcNextEvent(int32_t next_event)
99 {
100 int i;
101
102 for(i = 0; i < 3; i++)
103 {
104 int32_t target, count_delta;
105
106 /* If clocked by GPU, abort for this timer(will result in poor granularity
107 * for pixel-clock-derived timer IRQs, but whatever).
108 */
109 if((i == 0 || i == 1) && (Timers[i].Mode & 0x100))
110 continue;
111
112 /* If IRQ is disabled, abort for this timer. */
113 if(!(Timers[i].Mode & 0x10))
114 continue;
115
116 if((Timers[i].Mode & 0x8) && (Timers[i].Counter == 0) && (Timers[i].Target == 0) && !Timers[i].IRQDone)
117 {
118 next_event = 1;
119 continue;
120 }
121
122 target = ((Timers[i].Mode & 0x8) && (Timers[i].Counter < Timers[i].Target)) ? Timers[i].Target : 0x10000;
123
124 count_delta = target - Timers[i].Counter;
125
126 //PSX_DBG(PSX_DBG_ERROR, "timer %d count_delta <= 0!!! %d %d\n", i, target, Timers[i].Counter);
127 if(count_delta <= 0)
128 continue;
129
130 {
131 int32_t tmp_clocks;
132
133 if(Timers[i].DoZeCounting <= 0)
134 continue;
135
136 if((i == 0x2) && (Timers[i].Mode & 0x1))
137 continue;
138
139 if((i == 0x2) && (Timers[i].Mode & 0x200))
140 {
141 assert(Timers[i].Div8Counter >= 0 && Timers[i].Div8Counter < 8);
142 tmp_clocks = ((count_delta - 1) * 8) + (8 - Timers[i].Div8Counter);
143 }
144 else
145 tmp_clocks = count_delta;
146
147 assert(tmp_clocks > 0);
148
149 if(next_event > tmp_clocks)
150 next_event = tmp_clocks;
151 }
152 }
153
154 return(next_event);
155 }
156
157 static void ClockTimer(int i, uint32_t clocks)
158 {
159 int32_t before = Timers[i].Counter;
160 int32_t target = 0x10000;
161 bool zero_tm = false;
162
163 if(Timers[i].DoZeCounting <= 0)
164 clocks = 0;
165
166 if(i == 0x2)
167 {
168 uint32_t d8_clocks;
169
170 Timers[i].Div8Counter += clocks;
171 d8_clocks = Timers[i].Div8Counter >> 3;
172 Timers[i].Div8Counter -= d8_clocks << 3;
173
174 if(Timers[i].Mode & 0x200) // Divide by 8, at least for timer 0x2
175 clocks = d8_clocks;
176
177 if(Timers[i].Mode & 1)
178 clocks = 0;
179 }
180
181 if(Timers[i].Mode & 0x008)
182 target = Timers[i].Target;
183
184 if(target == 0 && Timers[i].Counter == 0)
185 zero_tm = true;
186 else
187 Timers[i].Counter += clocks;
188
189 if(clocks && (Timers[i].Mode & 0x40))
190 Timers[i].IRQDone = false;
191
192 if((before < target && Timers[i].Counter >= target) || zero_tm || Timers[i].Counter > 0xFFFF)
193 {
194 #if 0
195 if(Timers[i].Mode & 0x10)
196 {
197 if((Timers[i].Counter - target) > 3)
198 PSX_WARNING("Timer %d IRQ trigger error: %d", i, Timers[i].Counter - target);
199 }
200
201 #endif
202
203
204 Timers[i].Mode |= 0x0800;
205
206 if(Timers[i].Counter > 0xFFFF)
207 {
208 Timers[i].Counter -= 0x10000;
209
210 if(target == 0x10000)
211 Timers[i].Mode |= 0x1000;
212
213 if(!target)
214 Timers[i].Counter = 0;
215 }
216
217 if(target)
218 Timers[i].Counter -= (Timers[i].Counter / target) * target;
219
220 if((Timers[i].Mode & 0x10) && !Timers[i].IRQDone)
221 {
222 Timers[i].IRQDone = true;
223
224 IRQ_Assert(IRQ_TIMER_0 + i, true);
225 IRQ_Assert(IRQ_TIMER_0 + i, false);
226 }
227
228 if(Timers[i].Counter && (Timers[i].Mode & 0x40))
229 Timers[i].IRQDone = false;
230 }
231 }
232
233 void TIMER_SetVBlank(bool status)
234 {
235 switch(Timers[1].Mode & 0x7)
236 {
237 case 0x1:
238 Timers[1].DoZeCounting = !status;
239 break;
240
241 case 0x3:
242 if(vblank && !status)
243 Timers[1].Counter = 0;
244 break;
245
246 case 0x5:
247 Timers[1].DoZeCounting = status;
248 if(vblank && !status)
249 Timers[1].Counter = 0;
250 break;
251
252 case 0x7:
253 if(Timers[1].DoZeCounting == -1)
254 {
255 if(!vblank && status)
256 Timers[1].DoZeCounting = 0;
257 }
258 else if(Timers[1].DoZeCounting == 0)
259 {
260 if(vblank && !status)
261 Timers[1].DoZeCounting = 1;
262 }
263 break;
264 }
265 vblank = status;
266 }
267
268 void TIMER_SetHRetrace(bool status)
269 {
270 if(hretrace && !status)
271 {
272 if((Timers[0].Mode & 0x7) == 0x3)
273 Timers[0].Counter = 0;
274 }
275
276 hretrace = status;
277 }
278
279 void TIMER_AddDotClocks(uint32_t count)
280 {
281 if(Timers[0].Mode & 0x100)
282 ClockTimer(0, count);
283 }
284
285 void TIMER_ClockHRetrace(void)
286 {
287 if(Timers[1].Mode & 0x100)
288 ClockTimer(1, 1);
289 }
290
291 int32_t TIMER_Update(const int32_t timestamp)
292 {
293 int32_t cpu_clocks = timestamp - lastts;
294 int32_t i;
295
296 for(i = 0; i < 3; i++)
297 {
298 if(Timers[i].Mode & 0x100)
299 continue;
300
301 ClockTimer(i, cpu_clocks);
302 }
303
304 lastts = timestamp;
305
306 return(timestamp + CalcNextEvent(1024));
307 }
308
309 static void CalcCountingStart(unsigned which)
310 {
311 switch(Timers[which].Mode & 0x07)
312 {
313 case 0x1:
314 Timers[which].DoZeCounting = !vblank;
315 break;
316
317 case 0x5:
318 Timers[which].DoZeCounting = vblank;
319 break;
320
321 case 0x7:
322 Timers[which].DoZeCounting = -1;
323 break;
324 }
325 }
326
327 void TIMER_Write(const int32_t timestamp, uint32_t A, uint16_t V)
328 {
329 int which = (A >> 4) & 0x3;
330
331 TIMER_Update(timestamp);
332
333 V <<= (A & 3) * 8;
334
335 //PSX_DBGINFO("[TIMER] Write: %08x %04x\n", A, V);
336
337 if(which >= 3)
338 return;
339
340 // TODO: See if the "Timers[which].Counter" part of the IRQ if() statements below is what a real PSX does.
341 switch(A & 0xC)
342 {
343 case 0x0:
344 Timers[which].IRQDone = false;
345 #if 1
346 if(Timers[which].Counter && (V & 0xFFFF) == 0)
347 {
348 Timers[which].Mode |= 0x0800;
349 if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone)
350 {
351 Timers[which].IRQDone = true;
352 IRQ_Assert(IRQ_TIMER_0 + which, true);
353 IRQ_Assert(IRQ_TIMER_0 + which, false);
354 }
355 }
356 #endif
357 Timers[which].Counter = V & 0xFFFF;
358 break;
359 case 0x4:
360 Timers[which].Mode = (V & 0x3FF) | (Timers[which].Mode & 0x1C00);
361 Timers[which].IRQDone = false;
362 #if 1
363 if(Timers[which].Counter)
364 {
365 Timers[which].Mode |= 0x0800;
366 if((Timers[which].Mode & 0x10) && !Timers[which].IRQDone)
367 {
368 Timers[which].IRQDone = true;
369 IRQ_Assert(IRQ_TIMER_0 + which, true);
370 IRQ_Assert(IRQ_TIMER_0 + which, false);
371 }
372 }
373 Timers[which].Counter = 0;
374 #endif
375 Timers[which].DoZeCounting = true;
376 if (which == 1)
377 CalcCountingStart(which); // Call after setting .Mode
378 break;
379 case 0x8:
380 Timers[which].Target = V & 0xFFFF;
381 break;
382 case 0xC:
383 // Open bus
384 break;
385 }
386
387 // TIMER_Update(timestamp);
388
389 PSX_SetEventNT(PSX_EVENT_TIMER, timestamp + CalcNextEvent(1024));
390 }
391
392 uint16_t TIMER_Read(const int32_t timestamp, uint32_t A)
393 {
394 uint16_t ret = 0;
395 int which = (A >> 4) & 0x3;
396
397 /* if which is greater than or equal to 3,
398 * Open Bus Read. */
399
400 if(which < 3)
401 {
402 TIMER_Update(timestamp);
403
404 switch(A & 0xC)
405 {
406 case 0x0:
407 ret = Timers[which].Counter;
408 break;
409 case 0x4:
410 ret = Timers[which].Mode;
411 Timers[which].Mode &= ~0x1800;
412 break;
413 case 0x8:
414 ret = Timers[which].Target;
415 break;
416 case 0xC:
417 //PSX_WARNING("[TIMER] Open Bus Read: 0x%08x", A);
418 break;
419 }
420 }
421
422 return(ret >> ((A & 3) * 8));
423 }
424
425
426 void TIMER_ResetTS(void)
427 {
428 lastts = 0;
429 }
430
431 void TIMER_Power(void)
432 {
433 lastts = 0;
434
435 hretrace = false;
436 vblank = false;
437 memset(Timers, 0, sizeof(Timers));
438 }
439
440
441 int TIMER_StateAction(void *data, int load, int data_only)
442 {
443 int ret;
444 SFORMAT StateRegs[] =
445 {
446 #define SFTIMER(n) SFVARN(Timers[n].Mode, #n "Mode"), \
447 SFVARN(Timers[n].Counter, #n "Counter"), \
448 SFVARN(Timers[n].Target, #n "Target"), \
449 SFVARN(Timers[n].Div8Counter, #n "Div8Counter"), \
450 SFVARN(Timers[n].IRQDone, #n "IRQDone"), \
451 SFVARN(Timers[n].DoZeCounting, #n "DoZeCounting")
452 SFTIMER(0),
453 SFTIMER(1),
454 SFTIMER(2),
455 #undef SFTIMER
456
457 SFVAR(vblank),
458 SFVAR(hretrace),
459 SFEND
460 };
461 ret = MDFNSS_StateAction(data, load, data_only, StateRegs, "TIMER");
462
463 if(load)
464 {
465
466 }
467
468 return(ret);
469 }
470
471 uint32_t TIMER_GetRegister(unsigned int which, char *special, const uint32_t special_len)
472 {
473 int tw = (which >> 4) & 0x3;
474
475 switch(which & 0xF)
476 {
477 case TIMER_GSREG_COUNTER0:
478 return Timers[tw].Counter;
479 case TIMER_GSREG_MODE0:
480 return Timers[tw].Mode;
481 case TIMER_GSREG_TARGET0:
482 return Timers[tw].Target;
483 }
484
485 return 0;
486 }
487
488 void TIMER_SetRegister(unsigned int which, uint32_t value)
489 {
490 int tw = (which >> 4) & 0x3;
491
492 switch(which & 0xF)
493 {
494 case TIMER_GSREG_COUNTER0:
495 Timers[tw].Counter = value & 0xFFFF;
496 break;
497
498 case TIMER_GSREG_MODE0:
499 Timers[tw].Mode = value & 0xFFFF;
500 break;
501
502 case TIMER_GSREG_TARGET0:
503 Timers[tw].Target = value & 0xFFFF;
504 break;
505 }
506
507 }
0 #ifndef __MDFN_PSX_TIMER_H
1 #define __MDFN_PSX_TIMER_H
2
3 #include <stdint.h>
4
5 enum
6 {
7 TIMER_GSREG_COUNTER0 = 0x00,
8 TIMER_GSREG_MODE0,
9 TIMER_GSREG_TARGET0,
10
11 TIMER_GSREG_COUNTER1 = 0x10,
12 TIMER_GSREG_MODE1,
13 TIMER_GSREG_TARGET1,
14
15 TIMER_GSREG_COUNTER2 = 0x20,
16 TIMER_GSREG_MODE2,
17 TIMER_GSREG_TARGET2
18 };
19
20 uint32_t TIMER_GetRegister(unsigned int which, char *special, const uint32_t special_len);
21 void TIMER_SetRegister(unsigned int which, uint32_t value);
22
23
24 void TIMER_Write(const int32_t timestamp, uint32_t A, uint16_t V);
25 uint16_t TIMER_Read(const int32_t timestamp, uint32_t A);
26
27 void TIMER_AddDotClocks(uint32_t count);
28 void TIMER_ClockHRetrace(void);
29 void TIMER_SetHRetrace(bool status);
30 void TIMER_SetVBlank(bool status);
31
32 int32_t TIMER_Update(const int32_t);
33 void TIMER_ResetTS(void);
34
35 void TIMER_Power(void);
36 int TIMER_StateAction(void *data, int load, int data_only);
37
38 #endif
0 #ifndef _MDFN_SETTINGS_COMMON_H
1 #define _MDFN_SETTINGS_COMMON_H
2
3 #include <stdint.h>
4
5 typedef enum
6 {
7 MDFNST_INT = 0,
8 MDFNST_UINT,
9 MDFNST_BOOL,
10 MDFNST_FLOAT,
11 MDFNST_STRING,
12 MDFNST_ENUM,
13 MDFNST_ALIAS
14 } MDFNSettingType;
15
16 #define MDFNSF_NOFLAGS 0
17
18 #define MDFNSF_CAT_INPUT (1 << 8)
19 #define MDFNSF_CAT_SOUND (1 << 9)
20 #define MDFNSF_CAT_VIDEO (1 << 10)
21
22 #define MDFNSF_EMU_STATE (1 << 17)
23 #define MDFNSF_UNTRUSTED_SAFE (1 << 18)
24
25 #define MDFNSF_SUPPRESS_DOC (1 << 19)
26 #define MDFNSF_COMMON_TEMPLATE (1 << 20)
27
28 #define MDFNSF_REQUIRES_RELOAD (1 << 24)
29 #define MDFNSF_REQUIRES_RESTART (1 << 25)
30
31 typedef struct
32 {
33 const char *string;
34 int number;
35 const char *description;
36 const char *description_extra;
37 } MDFNSetting_EnumList;
38
39 typedef struct
40 {
41 const char *name;
42 uint32 flags;
43 const char *description;
44 const char *description_extra;
45
46 MDFNSettingType type;
47 const char *default_value;
48 const char *minimum;
49 const char *maximum;
50 bool (*validate_func)(const char *name, const char *value);
51 void (*ChangeNotification)(const char *name);
52 const MDFNSetting_EnumList *enum_list;
53 } MDFNSetting;
54
55 typedef struct __MDFNCS
56 {
57 char *name;
58 char *value;
59 char *game_override;
60 const MDFNSetting *desc;
61 void (*ChangeNotification)(const char *name);
62
63 uint32_t name_hash;
64 } MDFNCS;
65
66 #endif
0 #ifndef _MDFN_SETTINGS_DRIVER_H
1 #define _MDFN_SETTINGS_DRIVER_H
2
3 #include "settings-common.h"
4
5 bool MDFNI_SetSetting(const char *name, const char *value, bool NetplayOverride = FALSE);
6 bool MDFNI_SetSettingB(const char *name, bool value);
7 bool MDFNI_SetSettingUI(const char *name, uint64_t value);
8
9 bool MDFNI_DumpSettingsDef(const char *path);
10
11 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include <errno.h>
18 #include <string.h>
19
20 #include <string>
21
22 #include "mednafen.h"
23 #include "settings.h"
24
25 int setting_initial_scanline = 0;
26 int setting_initial_scanline_pal = 0;
27 int setting_last_scanline = 239;
28 int setting_last_scanline_pal = 287;
29
30 uint32_t setting_psx_multitap_port_1 = 0;
31 uint32_t setting_psx_multitap_port_2 = 0;
32 uint32_t setting_psx_analog_toggle = 0;
33 uint32_t setting_psx_fastboot = 1;
34
35 extern char retro_cd_base_name[4096];
36 extern char retro_save_directory[4096];
37 extern char retro_base_directory[4096];
38
39 bool MDFN_SaveSettings(const char *path)
40 {
41 return(1);
42 }
43
44 uint64_t MDFN_GetSettingUI(const char *name)
45 {
46 if (!strcmp("psx.spu.resamp_quality", name)) /* make configurable */
47 return 4;
48
49 fprintf(stderr, "unhandled setting UI: %s\n", name);
50 return 0;
51 }
52
53 int64 MDFN_GetSettingI(const char *name)
54 {
55 if (!strcmp("psx.region_default", name)) /* make configurable */
56 return 1; /* REGION_JP = 0, REGION_NA = 1, REGION_EU = 2 */
57 if (!strcmp("psx.slstart", name))
58 return setting_initial_scanline;
59 if (!strcmp("psx.slstartp", name))
60 return setting_initial_scanline_pal;
61 if (!strcmp("psx.slend", name))
62 return setting_last_scanline;
63 if (!strcmp("psx.slendp", name))
64 return setting_last_scanline_pal;
65 fprintf(stderr, "unhandled setting I: %s\n", name);
66 return 0;
67 }
68
69 double MDFN_GetSettingF(const char *name)
70 {
71 if (!strcmp("psx.input.mouse_sensitivity", name))
72 return 1.00; /* TODO - make configurable */
73
74 fprintf(stderr, "unhandled setting F: %s\n", name);
75 return 0;
76 }
77
78 bool MDFN_GetSettingB(const char *name)
79 {
80 if (!strcmp("cheats", name))
81 return 0;
82 /* LIBRETRO */
83 if (!strcmp("libretro.cd_load_into_ram", name))
84 return 0;
85 if (!strcmp("psx.input.port1.memcard", name))
86 return 1;
87 if (!strcmp("psx.input.port2.memcard", name))
88 return 1;
89 if (!strcmp("psx.input.port3.memcard", name))
90 return 1;
91 if (!strcmp("psx.input.port4.memcard", name))
92 return 1;
93 if (!strcmp("psx.input.port5.memcard", name))
94 return 1;
95 if (!strcmp("psx.input.port6.memcard", name))
96 return 1;
97 if (!strcmp("psx.input.port7.memcard", name))
98 return 1;
99 if (!strcmp("psx.input.port8.memcard", name))
100 return 1;
101 if (!strcmp("psx.input.pport1.multitap", name)) /* make configurable */
102 return setting_psx_multitap_port_1;
103 if (!strcmp("psx.input.pport2.multitap", name)) /* make configurable */
104 return setting_psx_multitap_port_2;
105 if (!strcmp("psx.region_autodetect", name)) /* make configurable */
106 return 1;
107 if (!strcmp("psx.input.analog_mode_ct", name)) /* make configurable */
108 return setting_psx_analog_toggle;
109 if (!strcmp("psx.fastboot", name))
110 return setting_psx_fastboot;
111 /* CDROM */
112 if (!strcmp("cdrom.lec_eval", name))
113 return 1;
114 /* FILESYS */
115 if (!strcmp("filesys.untrusted_fip_check", name))
116 return 0;
117 if (!strcmp("filesys.disablesavegz", name))
118 return 1;
119 fprintf(stderr, "unhandled setting B: %s\n", name);
120 return 0;
121 }
122
123 std::string MDFN_GetSettingS(const char *name)
124 {
125 if (!strcmp("psx.bios_eu", name))
126 return std::string("scph5502.bin");
127 if (!strcmp("psx.bios_jp", name))
128 return std::string("scph5500.bin");
129 if (!strcmp("psx.bios_na", name))
130 return std::string("scph5501.bin");
131 if (!strcmp("psx.region_default", name)) /* make configurable */
132 return "na";
133 /* FILESYS */
134 if (!strcmp("filesys.path_firmware", name))
135 return std::string(retro_base_directory);
136 if (!strcmp("filesys.path_sav", name))
137 return std::string(retro_save_directory);
138 if (!strcmp("filesys.path_state", name))
139 return std::string(retro_save_directory);
140 if (!strcmp("filesys.fname_state", name))
141 {
142 char fullpath[4096];
143 snprintf(fullpath, sizeof(fullpath), "%s.sav", retro_cd_base_name);
144 return std::string(fullpath);
145 }
146 if (!strcmp("filesys.fname_sav", name))
147 {
148 char fullpath[4096];
149 snprintf(fullpath, sizeof(fullpath), "%s.bsv", retro_cd_base_name);
150 return std::string(fullpath);
151 }
152 fprintf(stderr, "unhandled setting S: %s\n", name);
153 return 0;
154 }
155
156 bool MDFNI_SetSetting(const char *name, const char *value, bool NetplayOverride)
157 {
158 return false;
159 }
160
161 bool MDFNI_SetSettingB(const char *name, bool value)
162 {
163 return false;
164 }
165
166 bool MDFNI_SetSettingUI(const char *name, uint64_t value)
167 {
168 return false;
169 }
170
171 bool MDFNI_DumpSettingsDef(const char *path)
172 {
173 return true;
174 }
0 #ifndef MDFN_SETTINGS_H
1 #define MDFN_SETTINGS_H
2
3 #include <string>
4
5 extern uint32_t setting_psx_multitap_port_1;
6 extern uint32_t setting_psx_multitap_port_2;
7 extern uint32_t setting_psx_analog_toggle;
8 extern uint32_t setting_psx_fastboot;
9 extern int setting_initial_scanline;
10 extern int setting_initial_scanline_pal;
11 extern int setting_last_scanline;
12 extern int setting_last_scanline_pal;
13
14 // This should assert() or something if the setting isn't found, since it would
15 // be a totally tubular error!
16 uint64 MDFN_GetSettingUI(const char *name);
17 int64 MDFN_GetSettingI(const char *name);
18 double MDFN_GetSettingF(const char *name);
19 bool MDFN_GetSettingB(const char *name);
20 std::string MDFN_GetSettingS(const char *name);
21 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include <string.h>
18
19 #include <map>
20
21 #include "mednafen.h"
22 #include "driver.h"
23 #include "general.h"
24 #include "state.h"
25 #include "video.h"
26 #include "msvc_compat.h"
27
28 #define RLSB MDFNSTATE_RLSB //0x80000000
29
30 int32_t smem_read(StateMem *st, void *buffer, uint32_t len)
31 {
32 if ((len + st->loc) > st->len)
33 return 0;
34
35 memcpy(buffer, st->data + st->loc, len);
36 st->loc += len;
37
38 return(len);
39 }
40
41 int32_t smem_write(StateMem *st, void *buffer, uint32_t len)
42 {
43 if ((len + st->loc) > st->malloced)
44 {
45 uint32_t newsize = (st->malloced >= 32768) ? st->malloced : (st->initial_malloc ? st->initial_malloc : 32768);
46
47 while(newsize < (len + st->loc))
48 newsize *= 2;
49 st->data = (uint8_t *)realloc(st->data, newsize);
50 st->malloced = newsize;
51 }
52 memcpy(st->data + st->loc, buffer, len);
53 st->loc += len;
54
55 if (st->loc > st->len)
56 st->len = st->loc;
57
58 return(len);
59 }
60
61 int32_t smem_putc(StateMem *st, int value)
62 {
63 uint8_t tmpval = value;
64 if(smem_write(st, &tmpval, 1) != 1)
65 return(-1);
66 return(1);
67 }
68
69 int32_t smem_tell(StateMem *st)
70 {
71 return(st->loc);
72 }
73
74 int32_t smem_seek(StateMem *st, uint32_t offset, int whence)
75 {
76 switch(whence)
77 {
78 case SEEK_SET: st->loc = offset; break;
79 case SEEK_END: st->loc = st->len - offset; break;
80 case SEEK_CUR: st->loc += offset; break;
81 }
82
83 if(st->loc > st->len)
84 {
85 st->loc = st->len;
86 return(-1);
87 }
88
89 if(st->loc < 0)
90 {
91 st->loc = 0;
92 return(-1);
93 }
94
95 return(0);
96 }
97
98 int smem_write32le(StateMem *st, uint32_t b)
99 {
100 uint8_t s[4];
101 s[0]=b;
102 s[1]=b>>8;
103 s[2]=b>>16;
104 s[3]=b>>24;
105 return((smem_write(st, s, 4)<4)?0:4);
106 }
107
108 int smem_read32le(StateMem *st, uint32_t *b)
109 {
110 uint8_t s[4];
111
112 if(smem_read(st, s, 4) < 4)
113 return(0);
114
115 *b = s[0] | (s[1] << 8) | (s[2] << 16) | (s[3] << 24);
116
117 return(4);
118 }
119
120 static bool SubWrite(StateMem *st, SFORMAT *sf, const char *name_prefix = NULL)
121 {
122 while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct.
123 {
124 if(!sf->size || !sf->v)
125 {
126 sf++;
127 continue;
128 }
129
130 if(sf->size == (uint32_t)~0) /* Link to another struct. */
131 {
132 if(!SubWrite(st, (SFORMAT *)sf->v, name_prefix))
133 return(0);
134
135 sf++;
136 continue;
137 }
138
139 int32_t bytesize = sf->size;
140
141 char nameo[1 + 256];
142 int slen;
143
144 slen = snprintf(nameo + 1, 256, "%s%s", name_prefix ? name_prefix : "", sf->name);
145 nameo[0] = slen;
146
147 if(slen >= 255)
148 {
149 printf("Warning: state variable name possibly too long: %s %s %s %d\n", sf->name, name_prefix, nameo, slen);
150 slen = 255;
151 }
152
153 smem_write(st, nameo, 1 + nameo[0]);
154 smem_write32le(st, bytesize);
155
156 #ifdef MSB_FIRST
157 /* Flip the byte order... */
158 if(sf->flags & MDFNSTATE_BOOL)
159 {
160
161 }
162 else if(sf->flags & MDFNSTATE_RLSB64)
163 Endian_A64_NE_to_LE(sf->v, bytesize / sizeof(uint64_t));
164 else if(sf->flags & MDFNSTATE_RLSB32)
165 Endian_A32_NE_to_LE(sf->v, bytesize / sizeof(uint32_t));
166 else if(sf->flags & MDFNSTATE_RLSB16)
167 Endian_A16_NE_to_LE(sf->v, bytesize / sizeof(uint16_t));
168 else if(sf->flags & RLSB)
169 Endian_V_NE_to_LE(sf->v, bytesize);
170 #endif
171
172 // Special case for the evil bool type, to convert bool to 1-byte elements.
173 // Don't do it if we're only saving the raw data.
174 if(sf->flags & MDFNSTATE_BOOL)
175 {
176 for(int32_t bool_monster = 0; bool_monster < bytesize; bool_monster++)
177 {
178 uint8_t tmp_bool = ((bool *)sf->v)[bool_monster];
179 //printf("Bool write: %.31s\n", sf->name);
180 smem_write(st, &tmp_bool, 1);
181 }
182 }
183 else
184 smem_write(st, (uint8_t *)sf->v, bytesize);
185
186 #ifdef MSB_FIRST
187 /* Now restore the original byte order. */
188 if(sf->flags & MDFNSTATE_BOOL)
189 {
190
191 }
192 else if(sf->flags & MDFNSTATE_RLSB64)
193 Endian_A64_LE_to_NE(sf->v, bytesize / sizeof(uint64_t));
194 else if(sf->flags & MDFNSTATE_RLSB32)
195 Endian_A32_LE_to_NE(sf->v, bytesize / sizeof(uint32_t));
196 else if(sf->flags & MDFNSTATE_RLSB16)
197 Endian_A16_LE_to_NE(sf->v, bytesize / sizeof(uint16_t));
198 else if(sf->flags & RLSB)
199 Endian_V_LE_to_NE(sf->v, bytesize);
200 #endif
201 sf++;
202 }
203
204 return(TRUE);
205 }
206
207 static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf)
208 {
209 int32_t data_start_pos;
210 int32_t end_pos;
211
212 uint8_t sname_tmp[32];
213
214 memset(sname_tmp, 0, sizeof(sname_tmp));
215 strncpy((char *)sname_tmp, sname, 32);
216
217 if(strlen(sname) > 32)
218 printf("Warning: section name is too long: %s\n", sname);
219
220 smem_write(st, sname_tmp, 32);
221
222 smem_write32le(st, 0); // We'll come back and write this later.
223
224 data_start_pos = smem_tell(st);
225
226 if(!SubWrite(st, sf))
227 return(0);
228
229 end_pos = smem_tell(st);
230
231 smem_seek(st, data_start_pos - 4, SEEK_SET);
232 smem_write32le(st, end_pos - data_start_pos);
233 smem_seek(st, end_pos, SEEK_SET);
234
235 return(end_pos - data_start_pos);
236 }
237
238 struct compare_cstr
239 {
240 bool operator()(const char *s1, const char *s2) const
241 {
242 return(strcmp(s1, s2) < 0);
243 }
244 };
245
246 typedef std::map<const char *, SFORMAT *, compare_cstr> SFMap_t;
247
248 static void MakeSFMap(SFORMAT *sf, SFMap_t &sfmap)
249 {
250 while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct.
251 {
252 if(!sf->size || !sf->v)
253 {
254 sf++;
255 continue;
256 }
257
258 if(sf->size == (uint32_t)~0) /* Link to another SFORMAT structure. */
259 MakeSFMap((SFORMAT *)sf->v, sfmap);
260 else
261 {
262 assert(sf->name);
263
264 if(sfmap.find(sf->name) != sfmap.end())
265 printf("Duplicate save state variable in internal emulator structures(CLUB THE PROGRAMMERS WITH BREADSTICKS): %s\n", sf->name);
266
267 sfmap[sf->name] = sf;
268 }
269
270 sf++;
271 }
272 }
273
274 // Fast raw chunk reader
275 static void DOReadChunk(StateMem *st, SFORMAT *sf)
276 {
277 while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name.
278 // These two should both be zero only at the end of a struct.
279 {
280 if(!sf->size || !sf->v)
281 {
282 sf++;
283 continue;
284 }
285
286 if(sf->size == (uint32_t) ~0) // Link to another SFORMAT struct
287 {
288 DOReadChunk(st, (SFORMAT *)sf->v);
289 sf++;
290 continue;
291 }
292
293 int32_t bytesize = sf->size;
294
295 // Loading raw data, bool types are stored as they appear in memory, not as single bytes in the full state format.
296 // In the SFORMAT structure, the size member for bool entries is the number of bool elements, not the total in-memory size,
297 // so we adjust it here.
298 if(sf->flags & MDFNSTATE_BOOL)
299 bytesize *= sizeof(bool);
300
301 smem_read(st, (uint8_t *)sf->v, bytesize);
302 sf++;
303 }
304 }
305
306 static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size)
307 {
308 int temp;
309
310 {
311 SFMap_t sfmap;
312 SFMap_t sfmap_found; // Used for identifying variables that are missing in the save state.
313
314 MakeSFMap(sf, sfmap);
315
316 temp = smem_tell(st);
317 while(smem_tell(st) < (temp + size))
318 {
319 uint32_t recorded_size; // In bytes
320 uint8_t toa[1 + 256]; // Don't change to char unless cast toa[0] to unsigned to smem_read() and other places.
321
322 if(smem_read(st, toa, 1) != 1)
323 {
324 puts("Unexpected EOF");
325 return(0);
326 }
327
328 if(smem_read(st, toa + 1, toa[0]) != toa[0])
329 {
330 puts("Unexpected EOF?");
331 return 0;
332 }
333
334 toa[1 + toa[0]] = 0;
335
336 smem_read32le(st, &recorded_size);
337
338 SFMap_t::iterator sfmit;
339
340 sfmit = sfmap.find((char *)toa + 1);
341
342 if(sfmit != sfmap.end())
343 {
344 SFORMAT *tmp = sfmit->second;
345 uint32_t expected_size = tmp->size; // In bytes
346
347 if(recorded_size != expected_size)
348 {
349 printf("Variable in save state wrong size: %s. Need: %d, got: %d\n", toa + 1, expected_size, recorded_size);
350 if(smem_seek(st, recorded_size, SEEK_CUR) < 0)
351 {
352 puts("Seek error");
353 return(0);
354 }
355 }
356 else
357 {
358 sfmap_found[tmp->name] = tmp;
359
360 smem_read(st, (uint8_t *)tmp->v, expected_size);
361
362 if(tmp->flags & MDFNSTATE_BOOL)
363 {
364 // Converting downwards is necessary for the case of sizeof(bool) > 1
365 for(int32_t bool_monster = expected_size - 1; bool_monster >= 0; bool_monster--)
366 {
367 ((bool *)tmp->v)[bool_monster] = ((uint8_t *)tmp->v)[bool_monster];
368 }
369 }
370 #ifdef MSB_FIRST
371 if(tmp->flags & MDFNSTATE_RLSB64)
372 Endian_A64_LE_to_NE(tmp->v, expected_size / sizeof(uint64_t));
373 else if(tmp->flags & MDFNSTATE_RLSB32)
374 Endian_A32_LE_to_NE(tmp->v, expected_size / sizeof(uint32_t));
375 else if(tmp->flags & MDFNSTATE_RLSB16)
376 Endian_A16_LE_to_NE(tmp->v, expected_size / sizeof(uint16_t));
377 else if(tmp->flags & RLSB)
378 Endian_V_LE_to_NE(tmp->v, expected_size);
379 #endif
380 }
381 }
382 else
383 {
384 printf("Unknown variable in save state: %s\n", toa + 1);
385 if(smem_seek(st, recorded_size, SEEK_CUR) < 0)
386 {
387 puts("Seek error");
388 return(0);
389 }
390 }
391 } // while(...)
392
393 for(SFMap_t::const_iterator it = sfmap.begin(); it != sfmap.end(); it++)
394 {
395 if(sfmap_found.find(it->second->name) == sfmap_found.end())
396 {
397 printf("Variable missing from save state: %s\n", it->second->name);
398 }
399 }
400
401 assert(smem_tell(st) == (temp + size));
402 }
403 return 1;
404 }
405
406 static int CurrentState = 0;
407
408 /* This function is called by the game driver(NES, GB, GBA) to save a state. */
409 int MDFNSS_StateAction(void *st_p, int load, int data_only, std::vector <SSDescriptor> &sections)
410 {
411 StateMem *st = (StateMem*)st_p;
412 std::vector<SSDescriptor>::iterator section;
413
414 if(load)
415 {
416 {
417 char sname[32];
418
419 for(section = sections.begin(); section != sections.end(); section++)
420 {
421 int found = 0;
422 uint32_t tmp_size;
423 uint32_t total = 0;
424
425 while(smem_read(st, (uint8_t *)sname, 32) == 32)
426 {
427 if(smem_read32le(st, &tmp_size) != 4)
428 return(0);
429
430 total += tmp_size + 32 + 4;
431
432 // Yay, we found the section
433 if(!strncmp(sname, section->name, 32))
434 {
435 if(!ReadStateChunk(st, section->sf, tmp_size))
436 {
437 printf("Error reading chunk: %s\n", section->name);
438 return(0);
439 }
440 found = 1;
441 break;
442 }
443 else
444 {
445 if(smem_seek(st, tmp_size, SEEK_CUR) < 0)
446 {
447 puts("Chunk seek failure");
448 return(0);
449 }
450 }
451 }
452 if(smem_seek(st, -total, SEEK_CUR) < 0)
453 {
454 puts("Reverse seek error");
455 return(0);
456 }
457 if(!found && !section->optional) // Not found. We are sad!
458 {
459 printf("Section missing: %.32s\n", section->name);
460 return(0);
461 }
462 }
463 }
464 }
465 else
466 {
467 for(section = sections.begin(); section != sections.end(); section++)
468 {
469 if(!WriteStateChunk(st, section->name, section->sf))
470 return(0);
471 }
472 }
473
474 return(1);
475 }
476
477 int MDFNSS_StateAction(void *st_p, int load, int data_only, SFORMAT *sf, const char *name, bool optional)
478 {
479 StateMem *st = (StateMem*)st_p;
480 std::vector <SSDescriptor> love;
481
482 love.push_back(SSDescriptor(sf, name, optional));
483 return(MDFNSS_StateAction(st, load, 0, love));
484 }
485
486 int MDFNSS_SaveSM(void *st_p, int, int, const void*, const void*, const void*)
487 {
488 uint8_t header[32];
489 StateMem *st = (StateMem*)st_p;
490 static const char *header_magic = "MDFNSVST";
491 int neowidth = 0, neoheight = 0;
492
493 memset(header, 0, sizeof(header));
494 memcpy(header, header_magic, 8);
495
496 MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC);
497 MDFN_en32lsb(header + 24, neowidth);
498 MDFN_en32lsb(header + 28, neoheight);
499 smem_write(st, header, 32);
500
501 if(!MDFNGameInfo->StateAction(st, 0, 0))
502 return(0);
503
504 uint32_t sizy = smem_tell(st);
505 smem_seek(st, 16 + 4, SEEK_SET);
506 smem_write32le(st, sizy);
507
508 return(1);
509 }
510
511 int MDFNSS_LoadSM(void *st_p, int, int)
512 {
513 uint8_t header[32];
514 uint32_t stateversion;
515 StateMem *st = (StateMem*)st_p;
516
517 smem_read(st, header, 32);
518
519 if(memcmp(header, "MEDNAFENSVESTATE", 16) && memcmp(header, "MDFNSVST", 8))
520 return(0);
521
522 stateversion = MDFN_de32lsb(header + 16);
523
524 return(MDFNGameInfo->StateAction(st, stateversion, 0));
525 }
0 #ifndef _STATE_H
1 #define _STATE_H
2
3 typedef struct
4 {
5 uint8_t *data;
6 uint32_t loc;
7 uint32_t len;
8 uint32_t malloced;
9 uint32_t initial_malloc; // A setting!
10 } StateMem;
11
12 // Eh, we abuse the smem_* in-memory stream code
13 // in a few other places. :)
14 int32_t smem_read(StateMem *st, void *buffer, uint32_t len);
15 int32_t smem_write(StateMem *st, void *buffer, uint32_t len);
16 int32_t smem_putc(StateMem *st, int value);
17 int32_t smem_tell(StateMem *st);
18 int32_t smem_seek(StateMem *st, uint32_t offset, int whence);
19 int smem_write32le(StateMem *st, uint32_t b);
20 int smem_read32le(StateMem *st, uint32_t *b);
21
22 int MDFNSS_SaveSM(void *st, int, int, const void*, const void*, const void*);
23 int MDFNSS_LoadSM(void *st, int, int);
24
25 // Flag for a single, >= 1 byte native-endian variable
26 #define MDFNSTATE_RLSB 0x80000000
27
28 // 32-bit native-endian elements
29 #define MDFNSTATE_RLSB32 0x40000000
30
31 // 16-bit native-endian elements
32 #define MDFNSTATE_RLSB16 0x20000000
33
34 // 64-bit native-endian elements
35 #define MDFNSTATE_RLSB64 0x10000000
36
37 #define MDFNSTATE_BOOL 0x08000000
38
39 typedef struct {
40 void *v; // Pointer to the variable/array
41 uint32_t size; // Length, in bytes, of the data to be saved EXCEPT:
42 // In the case of MDFNSTATE_BOOL, it is the number of bool elements to save(bool is not always 1-byte).
43 // If 0, the subchunk isn't saved.
44 uint32_t flags; // Flags
45 const char *name; // Name
46 //uint32_t struct_size; // Only used for MDFNSTATE_ARRAYOFS, sizeof(struct) that members of the linked SFORMAT struct are in.
47 } SFORMAT;
48
49 INLINE bool SF_IS_BOOL(bool *) { return(1); }
50 INLINE bool SF_IS_BOOL(void *) { return(0); }
51
52 INLINE uint32_t SF_FORCE_AB(bool *) { return(0); }
53
54 INLINE uint32_t SF_FORCE_A8(int8_t *) { return(0); }
55 INLINE uint32_t SF_FORCE_A8(uint8_t *) { return(0); }
56
57 INLINE uint32_t SF_FORCE_A16(int16_t *) { return(0); }
58 INLINE uint32_t SF_FORCE_A16(uint16_t *) { return(0); }
59
60 INLINE uint32_t SF_FORCE_A32(int32_t *) { return(0); }
61 INLINE uint32_t SF_FORCE_A32(uint32_t *) { return(0); }
62
63 INLINE uint32_t SF_FORCE_A64(int64_t *) { return(0); }
64 INLINE uint32_t SF_FORCE_A64(uint64_t *) { return(0); }
65
66 INLINE uint32_t SF_FORCE_D(double *) { return(0); }
67
68 #define SFVARN(x, n) { &(x), SF_IS_BOOL(&(x)) ? 1 : sizeof(x), MDFNSTATE_RLSB | (SF_IS_BOOL(&(x)) ? MDFNSTATE_BOOL : 0), n }
69 #define SFVAR(x) SFVARN((x), #x)
70
71 #define SFARRAYN(x, l, n) { (x), (uint32_t)(l), 0 | SF_FORCE_A8(x), n }
72 #define SFARRAY(x, l) SFARRAYN((x), (l), #x)
73
74 #define SFARRAYBN(x, l, n) { (x), (uint32_t)(l), MDFNSTATE_BOOL | SF_FORCE_AB(x), n }
75 #define SFARRAYB(x, l) SFARRAYBN((x), (l), #x)
76
77 #define SFARRAY16N(x, l, n) { (x), (uint32_t)((l) * sizeof(uint16_t)), MDFNSTATE_RLSB16 | SF_FORCE_A16(x), n }
78 #define SFARRAY16(x, l) SFARRAY16N((x), (l), #x)
79
80 #define SFARRAY32N(x, l, n) { (x), (uint32_t)((l) * sizeof(uint32_t)), MDFNSTATE_RLSB32 | SF_FORCE_A32(x), n }
81 #define SFARRAY32(x, l) SFARRAY32N((x), (l), #x)
82
83 #define SFARRAY64N(x, l, n) { (x), (uint32_t)((l) * sizeof(uint64_t)), MDFNSTATE_RLSB64 | SF_FORCE_A64(x), n }
84 #define SFARRAY64(x, l) SFARRAY64N((x), (l), #x)
85
86 #define SFARRAYDN(x, l, n) { (x), (uint32_t)((l) * 8), MDFNSTATE_RLSB64 | SF_FORCE_D(x), n }
87 #define SFARRAYD(x, l) SFARRAYDN((x), (l), #x)
88
89 #define SFEND { 0, 0, 0, 0 }
90
91 #include <vector>
92
93 // State-Section Descriptor
94 class SSDescriptor
95 {
96 public:
97 SSDescriptor(SFORMAT *n_sf, const char *n_name, bool n_optional = 0)
98 {
99 sf = n_sf;
100 name = n_name;
101 optional = n_optional;
102 }
103 ~SSDescriptor(void)
104 {
105
106 }
107
108 SFORMAT *sf;
109 const char *name;
110 bool optional;
111 };
112
113 int MDFNSS_StateAction(void *st, int load, int data_only, std::vector <SSDescriptor> &sections);
114 int MDFNSS_StateAction(void *st, int load, int data_only, SFORMAT *sf, const char *name, bool optional = 0);
115
116 #endif
0 *** 20020517: 1.0.2 ***
1
2 Playback bugfix to floor1; mode mistakenly used for sizing instead
3 of blockflag
4
5 *** 20020515: 1.0.1 ***
6
7 Added complete API documentation to source tarball. No code
8 changes.
9
10 *** 20020412: 1.0.1 ***
11
12 Fixed a clipping bug that affected ARM processors; negative
13 overflows were being properly clipped, but then clobbered to
14 positive by the positive overflow chec (asm_arm.h:CLIP_TO_15)
15
16 *** 20020403: 1.0.0 ***
17
18 Initial version
0 Copyright (c) 2002, Xiph.org Foundation
1
2 Redistribution and use in source and binary forms, with or without
3 modification, are permitted provided that the following conditions
4 are met:
5
6 - Redistributions of source code must retain the above copyright
7 notice, this list of conditions and the following disclaimer.
8
9 - Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12
13 - Neither the name of the Xiph.org Foundation nor the names of its
14 contributors may be used to endorse or promote products derived from
15 this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
21 OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 This README covers the Ogg Vorbis 'Tremor' integer playback codec
1 source as of date 2002 09 02, version 1.0.0.
2
3 ******
4
5 The C source in this package will build on any ANSI C compiler and
6 function completely and properly on any platform. The included build
7 system assumes GNU build system and make tools (m4, automake,
8 autoconf, libtool and gmake). GCC is not required, although GCC is
9 the most tested compiler. To build using GNU tools, type in the
10 source directory:
11
12 ./autogen.sh
13 make
14
15 Currently, the source implements playback in pure C on all platforms
16 except ARM, where a [currently] small amount of assembly (see
17 asm_arm.h) is used to implement 64 bit math operations and fast LSP
18 computation. If building on ARM without the benefit of GNU build
19 system tools, be sure that '_ARM_ASSEM_' is #defined by the build
20 system if this assembly is desired, else the resulting library will
21 use whatever 64 bit math builtins the compiler implements.
22
23 No math library is required by this source. No floating point
24 operations are used at any point in either setup or decode. This
25 decoder library will properly decode any past, current or future
26 Vorbis I file or stream.
27
28 ********
29
30 The build system produces a static and [when supported by the OS]
31 dynamic library named 'libvorbisidec'. This library exposes an API
32 nearly identical to the BSD reference library's 'libvorbisfile',
33 including all the features familiar to users of vorbisfile. This API
34 is similar enough that the proper header file to include is named
35 'ivorbisfile.h' [included in the source build directory]. Lower level
36 libvorbis-style headers and structures are in 'ivorbiscodec.h'
37 [included in the source build directory]. A simple example program,
38 ivorbisfile_example.c, can be built with 'make example'.
39
40 ********
41
42 Detailed Tremor API Documentation begins at doc/index.html
43
44 Monty
45 xiph.org
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: arm7 and later wide math functions
14
15 ********************************************************************/
16
17 #ifdef _ARM_ASSEM_
18
19 #if !defined(_V_WIDE_MATH) && !defined(_LOW_ACCURACY_)
20 #define _V_WIDE_MATH
21
22 static inline ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) {
23 int lo,hi;
24 asm volatile("smull\t%0, %1, %2, %3"
25 : "=&r"(lo),"=&r"(hi)
26 : "%r"(x),"r"(y)
27 : "cc");
28 return(hi);
29 }
30
31 static inline ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) {
32 return MULT32(x,y)<<1;
33 }
34
35 static inline ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) {
36 int lo,hi;
37 asm volatile("smull %0, %1, %2, %3\n\t"
38 "movs %0, %0, lsr #15\n\t"
39 "adc %1, %0, %1, lsl #17\n\t"
40 : "=&r"(lo),"=&r"(hi)
41 : "%r"(x),"r"(y)
42 : "cc");
43 return(hi);
44 }
45
46 #define MB() asm volatile ("" : : : "memory")
47
48 static inline void XPROD32(ogg_int32_t a, ogg_int32_t b,
49 ogg_int32_t t, ogg_int32_t v,
50 ogg_int32_t *x, ogg_int32_t *y)
51 {
52 int x1, y1, l;
53 asm( "smull %0, %1, %4, %6\n\t"
54 "smlal %0, %1, %5, %7\n\t"
55 "rsb %3, %4, #0\n\t"
56 "smull %0, %2, %5, %6\n\t"
57 "smlal %0, %2, %3, %7"
58 : "=&r" (l), "=&r" (x1), "=&r" (y1), "=r" (a)
59 : "3" (a), "r" (b), "r" (t), "r" (v)
60 : "cc" );
61 *x = x1;
62 MB();
63 *y = y1;
64 }
65
66 static inline void XPROD31(ogg_int32_t a, ogg_int32_t b,
67 ogg_int32_t t, ogg_int32_t v,
68 ogg_int32_t *x, ogg_int32_t *y)
69 {
70 int x1, y1, l;
71 asm( "smull %0, %1, %4, %6\n\t"
72 "smlal %0, %1, %5, %7\n\t"
73 "rsb %3, %4, #0\n\t"
74 "smull %0, %2, %5, %6\n\t"
75 "smlal %0, %2, %3, %7"
76 : "=&r" (l), "=&r" (x1), "=&r" (y1), "=r" (a)
77 : "3" (a), "r" (b), "r" (t), "r" (v)
78 : "cc" );
79 *x = x1 << 1;
80 MB();
81 *y = y1 << 1;
82 }
83
84 static inline void XNPROD31(ogg_int32_t a, ogg_int32_t b,
85 ogg_int32_t t, ogg_int32_t v,
86 ogg_int32_t *x, ogg_int32_t *y)
87 {
88 int x1, y1, l;
89 asm( "rsb %2, %4, #0\n\t"
90 "smull %0, %1, %3, %5\n\t"
91 "smlal %0, %1, %2, %6\n\t"
92 "smull %0, %2, %4, %5\n\t"
93 "smlal %0, %2, %3, %6"
94 : "=&r" (l), "=&r" (x1), "=&r" (y1)
95 : "r" (a), "r" (b), "r" (t), "r" (v)
96 : "cc" );
97 *x = x1 << 1;
98 MB();
99 *y = y1 << 1;
100 }
101
102 #endif
103
104 #ifndef _V_CLIP_MATH
105 #define _V_CLIP_MATH
106
107 static inline ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
108 int tmp;
109 asm volatile("subs %1, %0, #32768\n\t"
110 "movpl %0, #0x7f00\n\t"
111 "orrpl %0, %0, #0xff\n"
112 "adds %1, %0, #32768\n\t"
113 "movmi %0, #0x8000"
114 : "+r"(x),"=r"(tmp)
115 :
116 : "cc");
117 return(x);
118 }
119
120 #endif
121
122 #ifndef _V_LSP_MATH_ASM
123 #define _V_LSP_MATH_ASM
124
125 static inline void lsp_loop_asm(ogg_uint32_t *qip,ogg_uint32_t *pip,
126 ogg_int32_t *qexpp,
127 ogg_int32_t *ilsp,ogg_int32_t wi,
128 ogg_int32_t m){
129
130 ogg_uint32_t qi=*qip,pi=*pip;
131 ogg_int32_t qexp=*qexpp;
132
133 asm("mov r0,%3;"
134 "movs r1,%5,asr#1;"
135 "add r0,r0,r1,lsl#3;"
136 "beq 2f;\n"
137 "1:"
138
139 "ldmdb r0!,{r1,r3};"
140 "subs r1,r1,%4;" //ilsp[j]-wi
141 "rsbmi r1,r1,#0;" //labs(ilsp[j]-wi)
142 "umull %0,r2,r1,%0;" //qi*=labs(ilsp[j]-wi)
143
144 "subs r1,r3,%4;" //ilsp[j+1]-wi
145 "rsbmi r1,r1,#0;" //labs(ilsp[j+1]-wi)
146 "umull %1,r3,r1,%1;" //pi*=labs(ilsp[j+1]-wi)
147
148 "cmn r2,r3;" // shift down 16?
149 "beq 0f;"
150 "add %2,%2,#16;"
151 "mov %0,%0,lsr #16;"
152 "orr %0,%0,r2,lsl #16;"
153 "mov %1,%1,lsr #16;"
154 "orr %1,%1,r3,lsl #16;"
155 "0:"
156 "cmp r0,%3;\n"
157 "bhi 1b;\n"
158
159 "2:"
160 // odd filter assymetry
161 "ands r0,%5,#1;\n"
162 "beq 3f;\n"
163 "add r0,%3,%5,lsl#2;\n"
164
165 "ldr r1,[r0,#-4];\n"
166 "mov r0,#0x4000;\n"
167
168 "subs r1,r1,%4;\n" //ilsp[j]-wi
169 "rsbmi r1,r1,#0;\n" //labs(ilsp[j]-wi)
170 "umull %0,r2,r1,%0;\n" //qi*=labs(ilsp[j]-wi)
171 "umull %1,r3,r0,%1;\n" //pi*=labs(ilsp[j+1]-wi)
172
173 "cmn r2,r3;\n" // shift down 16?
174 "beq 3f;\n"
175 "add %2,%2,#16;\n"
176 "mov %0,%0,lsr #16;\n"
177 "orr %0,%0,r2,lsl #16;\n"
178 "mov %1,%1,lsr #16;\n"
179 "orr %1,%1,r3,lsl #16;\n"
180
181 //qi=(pi>>shift)*labs(ilsp[j]-wi);
182 //pi=(qi>>shift)*labs(ilsp[j+1]-wi);
183 //qexp+=shift;
184
185 //}
186
187 /* normalize to max 16 sig figs */
188 "3:"
189 "mov r2,#0;"
190 "orr r1,%0,%1;"
191 "tst r1,#0xff000000;"
192 "addne r2,r2,#8;"
193 "movne r1,r1,lsr #8;"
194 "tst r1,#0x00f00000;"
195 "addne r2,r2,#4;"
196 "movne r1,r1,lsr #4;"
197 "tst r1,#0x000c0000;"
198 "addne r2,r2,#2;"
199 "movne r1,r1,lsr #2;"
200 "tst r1,#0x00020000;"
201 "addne r2,r2,#1;"
202 "movne r1,r1,lsr #1;"
203 "tst r1,#0x00010000;"
204 "addne r2,r2,#1;"
205 "mov %0,%0,lsr r2;"
206 "mov %1,%1,lsr r2;"
207 "add %2,%2,r2;"
208
209 : "+r"(qi),"+r"(pi),"+r"(qexp)
210 : "r"(ilsp),"r"(wi),"r"(m)
211 : "r0","r1","r2","r3","cc");
212
213 *qip=qi;
214 *pip=pi;
215 *qexpp=qexp;
216 }
217
218 static inline void lsp_norm_asm(ogg_uint32_t *qip,ogg_int32_t *qexpp){
219
220 ogg_uint32_t qi=*qip;
221 ogg_int32_t qexp=*qexpp;
222
223 asm("tst %0,#0x0000ff00;"
224 "moveq %0,%0,lsl #8;"
225 "subeq %1,%1,#8;"
226 "tst %0,#0x0000f000;"
227 "moveq %0,%0,lsl #4;"
228 "subeq %1,%1,#4;"
229 "tst %0,#0x0000c000;"
230 "moveq %0,%0,lsl #2;"
231 "subeq %1,%1,#2;"
232 "tst %0,#0x00008000;"
233 "moveq %0,%0,lsl #1;"
234 "subeq %1,%1,#1;"
235 : "+r"(qi),"+r"(qexp)
236 :
237 : "cc");
238 *qip=qi;
239 *qexpp=qexp;
240 }
241
242 #endif
243 #endif
244
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: backend and mapping structures
14
15 ********************************************************************/
16
17 /* this is exposed up here because we need it for static modes.
18 Lookups for each backend aren't exposed because there's no reason
19 to do so */
20
21 #ifndef _vorbis_backend_h_
22 #define _vorbis_backend_h_
23
24 #include "codec_internal.h"
25
26 /* this would all be simpler/shorter with templates, but.... */
27 /* Transform backend generic *************************************/
28
29 /* only mdct right now. Flesh it out more if we ever transcend mdct
30 in the transform domain */
31
32 /* Floor backend generic *****************************************/
33 typedef struct{
34 vorbis_info_floor *(*unpack)(vorbis_info *,oggpack_buffer *);
35 vorbis_look_floor *(*look) (vorbis_dsp_state *,vorbis_info_mode *,
36 vorbis_info_floor *);
37 void (*free_info) (vorbis_info_floor *);
38 void (*free_look) (vorbis_look_floor *);
39 void *(*inverse1) (struct vorbis_block *,vorbis_look_floor *);
40 int (*inverse2) (struct vorbis_block *,vorbis_look_floor *,
41 void *buffer,ogg_int32_t *);
42 } vorbis_func_floor;
43
44 typedef struct{
45 int order;
46 long rate;
47 long barkmap;
48
49 int ampbits;
50 int ampdB;
51
52 int numbooks; /* <= 16 */
53 int books[16];
54
55 } vorbis_info_floor0;
56
57 #define VIF_POSIT 63
58 #define VIF_CLASS 16
59 #define VIF_PARTS 31
60 typedef struct{
61 int partitions; /* 0 to 31 */
62 int partitionclass[VIF_PARTS]; /* 0 to 15 */
63
64 int class_dim[VIF_CLASS]; /* 1 to 8 */
65 int class_subs[VIF_CLASS]; /* 0,1,2,3 (bits: 1<<n poss) */
66 int class_book[VIF_CLASS]; /* subs ^ dim entries */
67 int class_subbook[VIF_CLASS][8]; /* [VIF_CLASS][subs] */
68
69
70 int mult; /* 1 2 3 or 4 */
71 int postlist[VIF_POSIT+2]; /* first two implicit */
72
73 } vorbis_info_floor1;
74
75 /* Residue backend generic *****************************************/
76 typedef struct{
77 vorbis_info_residue *(*unpack)(vorbis_info *,oggpack_buffer *);
78 vorbis_look_residue *(*look) (vorbis_dsp_state *,vorbis_info_mode *,
79 vorbis_info_residue *);
80 void (*free_info) (vorbis_info_residue *);
81 void (*free_look) (vorbis_look_residue *);
82 int (*inverse) (struct vorbis_block *,vorbis_look_residue *,
83 ogg_int32_t **,int *,int);
84 } vorbis_func_residue;
85
86 typedef struct vorbis_info_residue0{
87 /* block-partitioned VQ coded straight residue */
88 long begin;
89 long end;
90
91 /* first stage (lossless partitioning) */
92 int grouping; /* group n vectors per partition */
93 int partitions; /* possible codebooks for a partition */
94 int partvals; /* partitions ^ groupbook dim */
95 int groupbook; /* huffbook for partitioning */
96 int secondstages[64]; /* expanded out to pointers in lookup */
97 int booklist[512]; /* list of second stage books */
98 } vorbis_info_residue0;
99
100 /* Mapping backend generic *****************************************/
101 typedef struct{
102 vorbis_info_mapping *(*unpack)(vorbis_info *,oggpack_buffer *);
103 vorbis_look_mapping *(*look) (vorbis_dsp_state *,vorbis_info_mode *,
104 vorbis_info_mapping *);
105 void (*free_info) (vorbis_info_mapping *);
106 void (*free_look) (vorbis_look_mapping *);
107 int (*inverse) (struct vorbis_block *vb,vorbis_look_mapping *);
108 } vorbis_func_mapping;
109
110 typedef struct vorbis_info_mapping0{
111 int submaps; /* <= 16 */
112 int chmuxlist[256]; /* up to 256 channels in a Vorbis stream */
113
114 int floorsubmap[16]; /* [mux] submap to floors */
115 int residuesubmap[16]; /* [mux] submap to residue */
116
117 int psy[2]; /* by blocktype; impulse/padding for short,
118 transition/normal for long */
119
120 int coupling_steps;
121 int coupling_mag[256];
122 int coupling_ang[256];
123 } vorbis_info_mapping0;
124
125 #endif
126
127
128
129
130
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
3 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
4 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
5 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
6 * *
7 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
8 * by the Xiph.Org Foundation http://www.xiph.org/ *
9 * *
10 ********************************************************************
11
12 function: packing variable sized words into an octet stream
13 last mod: $Id: bitwise.c 18051 2011-08-04 17:56:39Z giles $
14
15 ********************************************************************/
16
17 /* We're 'LSb' endian; if we write a word but read individual bits,
18 then we'll read the lsb first */
19
20 #include <string.h>
21 #include <stdlib.h>
22 #include <limits.h>
23 #include "ogg.h"
24
25 #define BUFFER_INCREMENT 256
26
27 static const unsigned long mask[]=
28 {0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f,
29 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff,
30 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff,
31 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff,
32 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff,
33 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff,
34 0x3fffffff,0x7fffffff,0xffffffff };
35
36 static const unsigned int mask8B[]=
37 {0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff};
38
39 void oggpack_writeinit(oggpack_buffer *b){
40 memset(b,0,sizeof(*b));
41 b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT);
42 b->buffer[0]='\0';
43 b->storage=BUFFER_INCREMENT;
44 }
45
46 void oggpackB_writeinit(oggpack_buffer *b){
47 oggpack_writeinit(b);
48 }
49
50 int oggpack_writecheck(oggpack_buffer *b){
51 if(!b->ptr || !b->storage)return -1;
52 return 0;
53 }
54
55 int oggpackB_writecheck(oggpack_buffer *b){
56 return oggpack_writecheck(b);
57 }
58
59 void oggpack_writetrunc(oggpack_buffer *b,long bits){
60 long bytes=bits>>3;
61 if(b->ptr){
62 bits-=bytes*8;
63 b->ptr=b->buffer+bytes;
64 b->endbit=bits;
65 b->endbyte=bytes;
66 *b->ptr&=mask[bits];
67 }
68 }
69
70 void oggpackB_writetrunc(oggpack_buffer *b,long bits){
71 long bytes=bits>>3;
72 if(b->ptr){
73 bits-=bytes*8;
74 b->ptr=b->buffer+bytes;
75 b->endbit=bits;
76 b->endbyte=bytes;
77 *b->ptr&=mask8B[bits];
78 }
79 }
80
81 /* Takes only up to 32 bits. */
82 void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){
83 if(bits<0 || bits>32) goto err;
84 if(b->endbyte>=b->storage-4){
85 void *ret;
86 if(!b->ptr)return;
87 if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
88 ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
89 if(!ret) goto err;
90 b->buffer=ret;
91 b->storage+=BUFFER_INCREMENT;
92 b->ptr=b->buffer+b->endbyte;
93 }
94
95 value&=mask[bits];
96 bits+=b->endbit;
97
98 b->ptr[0]|=value<<b->endbit;
99
100 if(bits>=8){
101 b->ptr[1]=(unsigned char)(value>>(8-b->endbit));
102 if(bits>=16){
103 b->ptr[2]=(unsigned char)(value>>(16-b->endbit));
104 if(bits>=24){
105 b->ptr[3]=(unsigned char)(value>>(24-b->endbit));
106 if(bits>=32){
107 if(b->endbit)
108 b->ptr[4]=(unsigned char)(value>>(32-b->endbit));
109 else
110 b->ptr[4]=0;
111 }
112 }
113 }
114 }
115
116 b->endbyte+=bits/8;
117 b->ptr+=bits/8;
118 b->endbit=bits&7;
119 return;
120 err:
121 oggpack_writeclear(b);
122 }
123
124 /* Takes only up to 32 bits. */
125 void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){
126 if(bits<0 || bits>32) goto err;
127 if(b->endbyte>=b->storage-4){
128 void *ret;
129 if(!b->ptr)return;
130 if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err;
131 ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT);
132 if(!ret) goto err;
133 b->buffer=ret;
134 b->storage+=BUFFER_INCREMENT;
135 b->ptr=b->buffer+b->endbyte;
136 }
137
138 value=(value&mask[bits])<<(32-bits);
139 bits+=b->endbit;
140
141 b->ptr[0]|=value>>(24+b->endbit);
142
143 if(bits>=8){
144 b->ptr[1]=(unsigned char)(value>>(16+b->endbit));
145 if(bits>=16){
146 b->ptr[2]=(unsigned char)(value>>(8+b->endbit));
147 if(bits>=24){
148 b->ptr[3]=(unsigned char)(value>>(b->endbit));
149 if(bits>=32){
150 if(b->endbit)
151 b->ptr[4]=(unsigned char)(value<<(8-b->endbit));
152 else
153 b->ptr[4]=0;
154 }
155 }
156 }
157 }
158
159 b->endbyte+=bits/8;
160 b->ptr+=bits/8;
161 b->endbit=bits&7;
162 return;
163 err:
164 oggpack_writeclear(b);
165 }
166
167 void oggpack_writealign(oggpack_buffer *b){
168 int bits=8-b->endbit;
169 if(bits<8)
170 oggpack_write(b,0,bits);
171 }
172
173 void oggpackB_writealign(oggpack_buffer *b){
174 int bits=8-b->endbit;
175 if(bits<8)
176 oggpackB_write(b,0,bits);
177 }
178
179 static void oggpack_writecopy_helper(oggpack_buffer *b,
180 void *source,
181 long bits,
182 void (*w)(oggpack_buffer *,
183 unsigned long,
184 int),
185 int msb){
186 unsigned char *ptr=(unsigned char *)source;
187
188 long bytes=bits/8;
189 bits-=bytes*8;
190
191 if(b->endbit){
192 int i;
193 /* unaligned copy. Do it the hard way. */
194 for(i=0;i<bytes;i++)
195 w(b,(unsigned long)(ptr[i]),8);
196 }else{
197 /* aligned block copy */
198 if(b->endbyte+bytes+1>=b->storage){
199 void *ret;
200 if(!b->ptr) goto err;
201 if(b->endbyte+bytes+BUFFER_INCREMENT>b->storage) goto err;
202 b->storage=b->endbyte+bytes+BUFFER_INCREMENT;
203 ret=_ogg_realloc(b->buffer,b->storage);
204 if(!ret) goto err;
205 b->buffer=ret;
206 b->ptr=b->buffer+b->endbyte;
207 }
208
209 memmove(b->ptr,source,bytes);
210 b->ptr+=bytes;
211 b->endbyte+=bytes;
212 *b->ptr=0;
213
214 }
215 if(bits){
216 if(msb)
217 w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits);
218 else
219 w(b,(unsigned long)(ptr[bytes]),bits);
220 }
221 return;
222 err:
223 oggpack_writeclear(b);
224 }
225
226 void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){
227 oggpack_writecopy_helper(b,source,bits,oggpack_write,0);
228 }
229
230 void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){
231 oggpack_writecopy_helper(b,source,bits,oggpackB_write,1);
232 }
233
234 void oggpack_reset(oggpack_buffer *b){
235 if(!b->ptr)return;
236 b->ptr=b->buffer;
237 b->buffer[0]=0;
238 b->endbit=b->endbyte=0;
239 }
240
241 void oggpackB_reset(oggpack_buffer *b){
242 oggpack_reset(b);
243 }
244
245 void oggpack_writeclear(oggpack_buffer *b){
246 if(b->buffer)_ogg_free(b->buffer);
247 memset(b,0,sizeof(*b));
248 }
249
250 void oggpackB_writeclear(oggpack_buffer *b){
251 oggpack_writeclear(b);
252 }
253
254 void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
255 memset(b,0,sizeof(*b));
256 b->buffer=b->ptr=buf;
257 b->storage=bytes;
258 }
259
260 void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){
261 oggpack_readinit(b,buf,bytes);
262 }
263
264 /* Read in bits without advancing the bitptr; bits <= 32 */
265 long oggpack_look(oggpack_buffer *b,int bits){
266 unsigned long ret;
267 unsigned long m;
268
269 if(bits<0 || bits>32) return -1;
270 m=mask[bits];
271 bits+=b->endbit;
272
273 if(b->endbyte >= b->storage-4){
274 /* not the main path */
275 if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
276 /* special case to avoid reading b->ptr[0], which might be past the end of
277 the buffer; also skips some useless accounting */
278 else if(!bits)return(0L);
279 }
280
281 ret=b->ptr[0]>>b->endbit;
282 if(bits>8){
283 ret|=b->ptr[1]<<(8-b->endbit);
284 if(bits>16){
285 ret|=b->ptr[2]<<(16-b->endbit);
286 if(bits>24){
287 ret|=b->ptr[3]<<(24-b->endbit);
288 if(bits>32 && b->endbit)
289 ret|=b->ptr[4]<<(32-b->endbit);
290 }
291 }
292 }
293 return(m&ret);
294 }
295
296 /* Read in bits without advancing the bitptr; bits <= 32 */
297 long oggpackB_look(oggpack_buffer *b,int bits){
298 unsigned long ret;
299 int m=32-bits;
300
301 if(m<0 || m>32) return -1;
302 bits+=b->endbit;
303
304 if(b->endbyte >= b->storage-4){
305 /* not the main path */
306 if(b->endbyte > b->storage-((bits+7)>>3)) return -1;
307 /* special case to avoid reading b->ptr[0], which might be past the end of
308 the buffer; also skips some useless accounting */
309 else if(!bits)return(0L);
310 }
311
312 ret=b->ptr[0]<<(24+b->endbit);
313 if(bits>8){
314 ret|=b->ptr[1]<<(16+b->endbit);
315 if(bits>16){
316 ret|=b->ptr[2]<<(8+b->endbit);
317 if(bits>24){
318 ret|=b->ptr[3]<<(b->endbit);
319 if(bits>32 && b->endbit)
320 ret|=b->ptr[4]>>(8-b->endbit);
321 }
322 }
323 }
324 return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1);
325 }
326
327 long oggpack_look1(oggpack_buffer *b){
328 if(b->endbyte>=b->storage)return(-1);
329 return((b->ptr[0]>>b->endbit)&1);
330 }
331
332 long oggpackB_look1(oggpack_buffer *b){
333 if(b->endbyte>=b->storage)return(-1);
334 return((b->ptr[0]>>(7-b->endbit))&1);
335 }
336
337 void oggpack_adv(oggpack_buffer *b,int bits){
338 bits+=b->endbit;
339
340 if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
341
342 b->ptr+=bits/8;
343 b->endbyte+=bits/8;
344 b->endbit=bits&7;
345 return;
346
347 overflow:
348 b->ptr=NULL;
349 b->endbyte=b->storage;
350 b->endbit=1;
351 }
352
353 void oggpackB_adv(oggpack_buffer *b,int bits){
354 oggpack_adv(b,bits);
355 }
356
357 void oggpack_adv1(oggpack_buffer *b){
358 if(++(b->endbit)>7){
359 b->endbit=0;
360 b->ptr++;
361 b->endbyte++;
362 }
363 }
364
365 void oggpackB_adv1(oggpack_buffer *b){
366 oggpack_adv1(b);
367 }
368
369 /* bits <= 32 */
370 long oggpack_read(oggpack_buffer *b,int bits){
371 long ret;
372 unsigned long m;
373
374 if(bits<0 || bits>32) goto err;
375 m=mask[bits];
376 bits+=b->endbit;
377
378 if(b->endbyte >= b->storage-4){
379 /* not the main path */
380 if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
381 /* special case to avoid reading b->ptr[0], which might be past the end of
382 the buffer; also skips some useless accounting */
383 else if(!bits)return(0L);
384 }
385
386 ret=b->ptr[0]>>b->endbit;
387 if(bits>8){
388 ret|=b->ptr[1]<<(8-b->endbit);
389 if(bits>16){
390 ret|=b->ptr[2]<<(16-b->endbit);
391 if(bits>24){
392 ret|=b->ptr[3]<<(24-b->endbit);
393 if(bits>32 && b->endbit){
394 ret|=b->ptr[4]<<(32-b->endbit);
395 }
396 }
397 }
398 }
399 ret&=m;
400 b->ptr+=bits/8;
401 b->endbyte+=bits/8;
402 b->endbit=bits&7;
403 return ret;
404
405 overflow:
406 err:
407 b->ptr=NULL;
408 b->endbyte=b->storage;
409 b->endbit=1;
410 return -1L;
411 }
412
413 /* bits <= 32 */
414 long oggpackB_read(oggpack_buffer *b,int bits){
415 long ret;
416 long m=32-bits;
417
418 if(m<0 || m>32) goto err;
419 bits+=b->endbit;
420
421 if(b->endbyte+4>=b->storage){
422 /* not the main path */
423 if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow;
424 /* special case to avoid reading b->ptr[0], which might be past the end of
425 the buffer; also skips some useless accounting */
426 else if(!bits)return(0L);
427 }
428
429 ret=b->ptr[0]<<(24+b->endbit);
430 if(bits>8){
431 ret|=b->ptr[1]<<(16+b->endbit);
432 if(bits>16){
433 ret|=b->ptr[2]<<(8+b->endbit);
434 if(bits>24){
435 ret|=b->ptr[3]<<(b->endbit);
436 if(bits>32 && b->endbit)
437 ret|=b->ptr[4]>>(8-b->endbit);
438 }
439 }
440 }
441 ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1);
442
443 b->ptr+=bits/8;
444 b->endbyte+=bits/8;
445 b->endbit=bits&7;
446 return ret;
447
448 overflow:
449 err:
450 b->ptr=NULL;
451 b->endbyte=b->storage;
452 b->endbit=1;
453 return -1L;
454 }
455
456 long oggpack_read1(oggpack_buffer *b){
457 long ret;
458
459 if(b->endbyte >= b->storage) goto overflow;
460 ret=(b->ptr[0]>>b->endbit)&1;
461
462 b->endbit++;
463 if(b->endbit>7){
464 b->endbit=0;
465 b->ptr++;
466 b->endbyte++;
467 }
468 return ret;
469
470 overflow:
471 b->ptr=NULL;
472 b->endbyte=b->storage;
473 b->endbit=1;
474 return -1L;
475 }
476
477 long oggpackB_read1(oggpack_buffer *b){
478 long ret;
479
480 if(b->endbyte >= b->storage) goto overflow;
481 ret=(b->ptr[0]>>(7-b->endbit))&1;
482
483 b->endbit++;
484 if(b->endbit>7){
485 b->endbit=0;
486 b->ptr++;
487 b->endbyte++;
488 }
489 return ret;
490
491 overflow:
492 b->ptr=NULL;
493 b->endbyte=b->storage;
494 b->endbit=1;
495 return -1L;
496 }
497
498 long oggpack_bytes(oggpack_buffer *b){
499 return(b->endbyte+(b->endbit+7)/8);
500 }
501
502 long oggpack_bits(oggpack_buffer *b){
503 return(b->endbyte*8+b->endbit);
504 }
505
506 long oggpackB_bytes(oggpack_buffer *b){
507 return oggpack_bytes(b);
508 }
509
510 long oggpackB_bits(oggpack_buffer *b){
511 return oggpack_bits(b);
512 }
513
514 unsigned char *oggpack_get_buffer(oggpack_buffer *b){
515 return(b->buffer);
516 }
517
518 unsigned char *oggpackB_get_buffer(oggpack_buffer *b){
519 return oggpack_get_buffer(b);
520 }
521
522 /* Self test of the bitwise routines; everything else is based on
523 them, so they damned well better be solid. */
524
525 #ifdef _V_SELFTEST
526 #include <stdio.h>
527
528 static int ilog(unsigned int v){
529 int ret=0;
530 while(v){
531 ret++;
532 v>>=1;
533 }
534 return(ret);
535 }
536
537 oggpack_buffer o;
538 oggpack_buffer r;
539
540 void report(char *in){
541 fprintf(stderr,"%s",in);
542 exit(1);
543 }
544
545 void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){
546 long bytes,i;
547 unsigned char *buffer;
548
549 oggpack_reset(&o);
550 for(i=0;i<vals;i++)
551 oggpack_write(&o,b[i],bits?bits:ilog(b[i]));
552 buffer=oggpack_get_buffer(&o);
553 bytes=oggpack_bytes(&o);
554 if(bytes!=compsize)report("wrong number of bytes!\n");
555 for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
556 for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
557 report("wrote incorrect value!\n");
558 }
559 oggpack_readinit(&r,buffer,bytes);
560 for(i=0;i<vals;i++){
561 int tbit=bits?bits:ilog(b[i]);
562 if(oggpack_look(&r,tbit)==-1)
563 report("out of data!\n");
564 if(oggpack_look(&r,tbit)!=(b[i]&mask[tbit]))
565 report("looked at incorrect value!\n");
566 if(tbit==1)
567 if(oggpack_look1(&r)!=(b[i]&mask[tbit]))
568 report("looked at single bit incorrect value!\n");
569 if(tbit==1){
570 if(oggpack_read1(&r)!=(b[i]&mask[tbit]))
571 report("read incorrect single bit value!\n");
572 }else{
573 if(oggpack_read(&r,tbit)!=(b[i]&mask[tbit]))
574 report("read incorrect value!\n");
575 }
576 }
577 if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
578 }
579
580 void cliptestB(unsigned long *b,int vals,int bits,int *comp,int compsize){
581 long bytes,i;
582 unsigned char *buffer;
583
584 oggpackB_reset(&o);
585 for(i=0;i<vals;i++)
586 oggpackB_write(&o,b[i],bits?bits:ilog(b[i]));
587 buffer=oggpackB_get_buffer(&o);
588 bytes=oggpackB_bytes(&o);
589 if(bytes!=compsize)report("wrong number of bytes!\n");
590 for(i=0;i<bytes;i++)if(buffer[i]!=comp[i]){
591 for(i=0;i<bytes;i++)fprintf(stderr,"%x %x\n",(int)buffer[i],(int)comp[i]);
592 report("wrote incorrect value!\n");
593 }
594 oggpackB_readinit(&r,buffer,bytes);
595 for(i=0;i<vals;i++){
596 int tbit=bits?bits:ilog(b[i]);
597 if(oggpackB_look(&r,tbit)==-1)
598 report("out of data!\n");
599 if(oggpackB_look(&r,tbit)!=(b[i]&mask[tbit]))
600 report("looked at incorrect value!\n");
601 if(tbit==1)
602 if(oggpackB_look1(&r)!=(b[i]&mask[tbit]))
603 report("looked at single bit incorrect value!\n");
604 if(tbit==1){
605 if(oggpackB_read1(&r)!=(b[i]&mask[tbit]))
606 report("read incorrect single bit value!\n");
607 }else{
608 if(oggpackB_read(&r,tbit)!=(b[i]&mask[tbit]))
609 report("read incorrect value!\n");
610 }
611 }
612 if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
613 }
614
615 int main(void){
616 unsigned char *buffer;
617 long bytes,i;
618 static unsigned long testbuffer1[]=
619 {18,12,103948,4325,543,76,432,52,3,65,4,56,32,42,34,21,1,23,32,546,456,7,
620 567,56,8,8,55,3,52,342,341,4,265,7,67,86,2199,21,7,1,5,1,4};
621 int test1size=43;
622
623 static unsigned long testbuffer2[]=
624 {216531625L,1237861823,56732452,131,3212421,12325343,34547562,12313212,
625 1233432,534,5,346435231,14436467,7869299,76326614,167548585,
626 85525151,0,12321,1,349528352};
627 int test2size=21;
628
629 static unsigned long testbuffer3[]=
630 {1,0,14,0,1,0,12,0,1,0,0,0,1,1,0,1,0,1,0,1,0,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,
631 0,1,30,1,1,1,0,0,1,0,0,0,12,0,11,0,1,0,0,1};
632 int test3size=56;
633
634 static unsigned long large[]=
635 {2136531625L,2137861823,56732452,131,3212421,12325343,34547562,12313212,
636 1233432,534,5,2146435231,14436467,7869299,76326614,167548585,
637 85525151,0,12321,1,2146528352};
638
639 int onesize=33;
640 static int one[33]={146,25,44,151,195,15,153,176,233,131,196,65,85,172,47,40,
641 34,242,223,136,35,222,211,86,171,50,225,135,214,75,172,
642 223,4};
643 static int oneB[33]={150,101,131,33,203,15,204,216,105,193,156,65,84,85,222,
644 8,139,145,227,126,34,55,244,171,85,100,39,195,173,18,
645 245,251,128};
646
647 int twosize=6;
648 static int two[6]={61,255,255,251,231,29};
649 static int twoB[6]={247,63,255,253,249,120};
650
651 int threesize=54;
652 static int three[54]={169,2,232,252,91,132,156,36,89,13,123,176,144,32,254,
653 142,224,85,59,121,144,79,124,23,67,90,90,216,79,23,83,
654 58,135,196,61,55,129,183,54,101,100,170,37,127,126,10,
655 100,52,4,14,18,86,77,1};
656 static int threeB[54]={206,128,42,153,57,8,183,251,13,89,36,30,32,144,183,
657 130,59,240,121,59,85,223,19,228,180,134,33,107,74,98,
658 233,253,196,135,63,2,110,114,50,155,90,127,37,170,104,
659 200,20,254,4,58,106,176,144,0};
660
661 int foursize=38;
662 static int four[38]={18,6,163,252,97,194,104,131,32,1,7,82,137,42,129,11,72,
663 132,60,220,112,8,196,109,64,179,86,9,137,195,208,122,169,
664 28,2,133,0,1};
665 static int fourB[38]={36,48,102,83,243,24,52,7,4,35,132,10,145,21,2,93,2,41,
666 1,219,184,16,33,184,54,149,170,132,18,30,29,98,229,67,
667 129,10,4,32};
668
669 int fivesize=45;
670 static int five[45]={169,2,126,139,144,172,30,4,80,72,240,59,130,218,73,62,
671 241,24,210,44,4,20,0,248,116,49,135,100,110,130,181,169,
672 84,75,159,2,1,0,132,192,8,0,0,18,22};
673 static int fiveB[45]={1,84,145,111,245,100,128,8,56,36,40,71,126,78,213,226,
674 124,105,12,0,133,128,0,162,233,242,67,152,77,205,77,
675 172,150,169,129,79,128,0,6,4,32,0,27,9,0};
676
677 int sixsize=7;
678 static int six[7]={17,177,170,242,169,19,148};
679 static int sixB[7]={136,141,85,79,149,200,41};
680
681 /* Test read/write together */
682 /* Later we test against pregenerated bitstreams */
683 oggpack_writeinit(&o);
684
685 fprintf(stderr,"\nSmall preclipped packing (LSb): ");
686 cliptest(testbuffer1,test1size,0,one,onesize);
687 fprintf(stderr,"ok.");
688
689 fprintf(stderr,"\nNull bit call (LSb): ");
690 cliptest(testbuffer3,test3size,0,two,twosize);
691 fprintf(stderr,"ok.");
692
693 fprintf(stderr,"\nLarge preclipped packing (LSb): ");
694 cliptest(testbuffer2,test2size,0,three,threesize);
695 fprintf(stderr,"ok.");
696
697 fprintf(stderr,"\n32 bit preclipped packing (LSb): ");
698 oggpack_reset(&o);
699 for(i=0;i<test2size;i++)
700 oggpack_write(&o,large[i],32);
701 buffer=oggpack_get_buffer(&o);
702 bytes=oggpack_bytes(&o);
703 oggpack_readinit(&r,buffer,bytes);
704 for(i=0;i<test2size;i++){
705 if(oggpack_look(&r,32)==-1)report("out of data. failed!");
706 if(oggpack_look(&r,32)!=large[i]){
707 fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpack_look(&r,32),large[i],
708 oggpack_look(&r,32),large[i]);
709 report("read incorrect value!\n");
710 }
711 oggpack_adv(&r,32);
712 }
713 if(oggpack_bytes(&r)!=bytes)report("leftover bytes after read!\n");
714 fprintf(stderr,"ok.");
715
716 fprintf(stderr,"\nSmall unclipped packing (LSb): ");
717 cliptest(testbuffer1,test1size,7,four,foursize);
718 fprintf(stderr,"ok.");
719
720 fprintf(stderr,"\nLarge unclipped packing (LSb): ");
721 cliptest(testbuffer2,test2size,17,five,fivesize);
722 fprintf(stderr,"ok.");
723
724 fprintf(stderr,"\nSingle bit unclipped packing (LSb): ");
725 cliptest(testbuffer3,test3size,1,six,sixsize);
726 fprintf(stderr,"ok.");
727
728 fprintf(stderr,"\nTesting read past end (LSb): ");
729 oggpack_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
730 for(i=0;i<64;i++){
731 if(oggpack_read(&r,1)!=0){
732 fprintf(stderr,"failed; got -1 prematurely.\n");
733 exit(1);
734 }
735 }
736 if(oggpack_look(&r,1)!=-1 ||
737 oggpack_read(&r,1)!=-1){
738 fprintf(stderr,"failed; read past end without -1.\n");
739 exit(1);
740 }
741 oggpack_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
742 if(oggpack_read(&r,30)!=0 || oggpack_read(&r,16)!=0){
743 fprintf(stderr,"failed 2; got -1 prematurely.\n");
744 exit(1);
745 }
746
747 if(oggpack_look(&r,18)!=0 ||
748 oggpack_look(&r,18)!=0){
749 fprintf(stderr,"failed 3; got -1 prematurely.\n");
750 exit(1);
751 }
752 if(oggpack_look(&r,19)!=-1 ||
753 oggpack_look(&r,19)!=-1){
754 fprintf(stderr,"failed; read past end without -1.\n");
755 exit(1);
756 }
757 if(oggpack_look(&r,32)!=-1 ||
758 oggpack_look(&r,32)!=-1){
759 fprintf(stderr,"failed; read past end without -1.\n");
760 exit(1);
761 }
762 oggpack_writeclear(&o);
763 fprintf(stderr,"ok.\n");
764
765 /********** lazy, cut-n-paste retest with MSb packing ***********/
766
767 /* Test read/write together */
768 /* Later we test against pregenerated bitstreams */
769 oggpackB_writeinit(&o);
770
771 fprintf(stderr,"\nSmall preclipped packing (MSb): ");
772 cliptestB(testbuffer1,test1size,0,oneB,onesize);
773 fprintf(stderr,"ok.");
774
775 fprintf(stderr,"\nNull bit call (MSb): ");
776 cliptestB(testbuffer3,test3size,0,twoB,twosize);
777 fprintf(stderr,"ok.");
778
779 fprintf(stderr,"\nLarge preclipped packing (MSb): ");
780 cliptestB(testbuffer2,test2size,0,threeB,threesize);
781 fprintf(stderr,"ok.");
782
783 fprintf(stderr,"\n32 bit preclipped packing (MSb): ");
784 oggpackB_reset(&o);
785 for(i=0;i<test2size;i++)
786 oggpackB_write(&o,large[i],32);
787 buffer=oggpackB_get_buffer(&o);
788 bytes=oggpackB_bytes(&o);
789 oggpackB_readinit(&r,buffer,bytes);
790 for(i=0;i<test2size;i++){
791 if(oggpackB_look(&r,32)==-1)report("out of data. failed!");
792 if(oggpackB_look(&r,32)!=large[i]){
793 fprintf(stderr,"%ld != %ld (%lx!=%lx):",oggpackB_look(&r,32),large[i],
794 oggpackB_look(&r,32),large[i]);
795 report("read incorrect value!\n");
796 }
797 oggpackB_adv(&r,32);
798 }
799 if(oggpackB_bytes(&r)!=bytes)report("leftover bytes after read!\n");
800 fprintf(stderr,"ok.");
801
802 fprintf(stderr,"\nSmall unclipped packing (MSb): ");
803 cliptestB(testbuffer1,test1size,7,fourB,foursize);
804 fprintf(stderr,"ok.");
805
806 fprintf(stderr,"\nLarge unclipped packing (MSb): ");
807 cliptestB(testbuffer2,test2size,17,fiveB,fivesize);
808 fprintf(stderr,"ok.");
809
810 fprintf(stderr,"\nSingle bit unclipped packing (MSb): ");
811 cliptestB(testbuffer3,test3size,1,sixB,sixsize);
812 fprintf(stderr,"ok.");
813
814 fprintf(stderr,"\nTesting read past end (MSb): ");
815 oggpackB_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
816 for(i=0;i<64;i++){
817 if(oggpackB_read(&r,1)!=0){
818 fprintf(stderr,"failed; got -1 prematurely.\n");
819 exit(1);
820 }
821 }
822 if(oggpackB_look(&r,1)!=-1 ||
823 oggpackB_read(&r,1)!=-1){
824 fprintf(stderr,"failed; read past end without -1.\n");
825 exit(1);
826 }
827 oggpackB_readinit(&r,(unsigned char *)"\0\0\0\0\0\0\0\0",8);
828 if(oggpackB_read(&r,30)!=0 || oggpackB_read(&r,16)!=0){
829 fprintf(stderr,"failed 2; got -1 prematurely.\n");
830 exit(1);
831 }
832
833 if(oggpackB_look(&r,18)!=0 ||
834 oggpackB_look(&r,18)!=0){
835 fprintf(stderr,"failed 3; got -1 prematurely.\n");
836 exit(1);
837 }
838 if(oggpackB_look(&r,19)!=-1 ||
839 oggpackB_look(&r,19)!=-1){
840 fprintf(stderr,"failed; read past end without -1.\n");
841 exit(1);
842 }
843 if(oggpackB_look(&r,32)!=-1 ||
844 oggpackB_look(&r,32)!=-1){
845 fprintf(stderr,"failed; read past end without -1.\n");
846 exit(1);
847 }
848 oggpackB_writeclear(&o);
849 fprintf(stderr,"ok.\n\n");
850
851
852 return(0);
853 }
854 #endif /* _V_SELFTEST */
855
856 #undef BUFFER_INCREMENT
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: PCM data vector blocking, windowing and dis/reassembly
14
15 ********************************************************************/
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include "ogg.h"
21 #include "ivorbiscodec.h"
22 #include "codec_internal.h"
23
24 #include "window.h"
25 #include "registry.h"
26 #include "misc.h"
27 #include "tremor_shared.h"
28
29
30 /* pcm accumulator examples (not exhaustive):
31
32 <-------------- lW ---------------->
33 <--------------- W ---------------->
34 : .....|..... _______________ |
35 : .''' | '''_--- | |\ |
36 :.....''' |_____--- '''......| | \_______|
37 :.................|__________________|_______|__|______|
38 |<------ Sl ------>| > Sr < |endW
39 |beginSl |endSl | |endSr
40 |beginW |endlW |beginSr
41
42
43 |< lW >|
44 <--------------- W ---------------->
45 | | .. ______________ |
46 | | ' `/ | ---_ |
47 |___.'___/`. | ---_____|
48 |_______|__|_______|_________________|
49 | >|Sl|< |<------ Sr ----->|endW
50 | | |endSl |beginSr |endSr
51 |beginW | |endlW
52 mult[0] |beginSl mult[n]
53
54 <-------------- lW ----------------->
55 |<--W-->|
56 : .............. ___ | |
57 : .''' |`/ \ | |
58 :.....''' |/`....\|...|
59 :.........................|___|___|___|
60 |Sl |Sr |endW
61 | | |endSr
62 | |beginSr
63 | |endSl
64 |beginSl
65 |beginW
66 */
67
68 /* block abstraction setup *********************************************/
69
70 #ifndef WORD_ALIGN
71 #define WORD_ALIGN 8
72 #endif
73
74 int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){
75 memset(vb,0,sizeof(*vb));
76 vb->vd=v;
77 vb->localalloc=0;
78 vb->localstore=NULL;
79
80 return(0);
81 }
82
83 void *_vorbis_block_alloc(vorbis_block *vb,long bytes){
84 bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1);
85 if(bytes+vb->localtop>vb->localalloc){
86 /* can't just _ogg_realloc... there are outstanding pointers */
87 if(vb->localstore){
88 struct alloc_chain *link=(struct alloc_chain *)_ogg_malloc(sizeof(*link));
89 vb->totaluse+=vb->localtop;
90 link->next=vb->reap;
91 link->ptr=vb->localstore;
92 vb->reap=link;
93 }
94 /* highly conservative */
95 vb->localalloc=bytes;
96 vb->localstore=_ogg_malloc(vb->localalloc);
97 vb->localtop=0;
98 }
99 {
100 void *ret=(void *)(((char *)vb->localstore)+vb->localtop);
101 vb->localtop+=bytes;
102 return ret;
103 }
104 }
105
106 /* reap the chain, pull the ripcord */
107 void _vorbis_block_ripcord(vorbis_block *vb){
108 /* reap the chain */
109 struct alloc_chain *reap=vb->reap;
110 while(reap){
111 struct alloc_chain *next=reap->next;
112 _ogg_free(reap->ptr);
113 memset(reap,0,sizeof(*reap));
114 _ogg_free(reap);
115 reap=next;
116 }
117 /* consolidate storage */
118 if(vb->totaluse){
119 vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc);
120 vb->localalloc+=vb->totaluse;
121 vb->totaluse=0;
122 }
123
124 /* pull the ripcord */
125 vb->localtop=0;
126 vb->reap=NULL;
127 }
128
129 int vorbis_block_clear(vorbis_block *vb){
130 _vorbis_block_ripcord(vb);
131 if(vb->localstore)_ogg_free(vb->localstore);
132
133 memset(vb,0,sizeof(*vb));
134 return(0);
135 }
136
137 static int _vds_init(vorbis_dsp_state *v,vorbis_info *vi){
138 int i;
139 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
140 private_state *b=NULL;
141
142 if(ci==NULL) return 1;
143
144 memset(v,0,sizeof(*v));
145 b=(private_state *)(v->backend_state=_ogg_calloc(1,sizeof(*b)));
146
147 v->vi=vi;
148 b->modebits=ilog(ci->modes);
149
150 /* Vorbis I uses only window type 0 */
151 b->window[0]=_vorbis_window(0,ci->blocksizes[0]/2);
152 b->window[1]=_vorbis_window(0,ci->blocksizes[1]/2);
153
154 /* finish the codebooks */
155 if(!ci->fullbooks){
156 ci->fullbooks=(codebook *)_ogg_calloc(ci->books,sizeof(*ci->fullbooks));
157 for(i=0;i<ci->books;i++){
158 if(ci->book_param[i]==NULL)
159 goto abort_books;
160 if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i]))
161 goto abort_books;
162 /* decode codebooks are now standalone after init */
163 vorbis_staticbook_destroy(ci->book_param[i]);
164 ci->book_param[i]=NULL;
165 }
166 }
167
168 v->pcm_storage=ci->blocksizes[1];
169 v->pcm=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcm));
170 v->pcmret=(ogg_int32_t **)_ogg_malloc(vi->channels*sizeof(*v->pcmret));
171 for(i=0;i<vi->channels;i++)
172 v->pcm[i]=(ogg_int32_t *)_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i]));
173
174 /* all 1 (large block) or 0 (small block) */
175 /* explicitly set for the sake of clarity */
176 v->lW=0; /* previous window size */
177 v->W=0; /* current window size */
178
179 /* initialize all the mapping/backend lookups */
180 b->mode=(vorbis_look_mapping **)_ogg_calloc(ci->modes,sizeof(*b->mode));
181 for(i=0;i<ci->modes;i++){
182 int mapnum=ci->mode_param[i]->mapping;
183 int maptype=ci->map_type[mapnum];
184 b->mode[i]=_mapping_P[maptype]->look(v,ci->mode_param[i],
185 ci->map_param[mapnum]);
186 }
187 return 0;
188 abort_books:
189 for(i=0;i<ci->books;i++){
190 if(ci->book_param[i]!=NULL){
191 vorbis_staticbook_destroy(ci->book_param[i]);
192 ci->book_param[i]=NULL;
193 }
194 }
195 vorbis_dsp_clear(v);
196 return -1;
197 }
198
199 int vorbis_synthesis_restart(vorbis_dsp_state *v){
200 vorbis_info *vi=v->vi;
201 codec_setup_info *ci;
202
203 if(!v->backend_state)return -1;
204 if(!vi)return -1;
205 ci=vi->codec_setup;
206 if(!ci)return -1;
207
208 v->centerW=ci->blocksizes[1]/2;
209 v->pcm_current=v->centerW;
210
211 v->pcm_returned=-1;
212 v->granulepos=-1;
213 v->sequence=-1;
214 ((private_state *)(v->backend_state))->sample_count=-1;
215
216 return(0);
217 }
218
219 int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){
220 if(_vds_init(v,vi))return 1;
221 vorbis_synthesis_restart(v);
222
223 return 0;
224 }
225
226 void vorbis_dsp_clear(vorbis_dsp_state *v){
227 int i;
228 if(v){
229 vorbis_info *vi=v->vi;
230 codec_setup_info *ci=(codec_setup_info *)(vi?vi->codec_setup:NULL);
231 private_state *b=(private_state *)v->backend_state;
232
233 if(v->pcm){
234 for(i=0;i<vi->channels;i++)
235 if(v->pcm[i])_ogg_free(v->pcm[i]);
236 _ogg_free(v->pcm);
237 if(v->pcmret)_ogg_free(v->pcmret);
238 }
239
240 /* free mode lookups; these are actually vorbis_look_mapping structs */
241 if(ci){
242 for(i=0;i<ci->modes;i++){
243 int mapnum=ci->mode_param[i]->mapping;
244 int maptype=ci->map_type[mapnum];
245 if(b && b->mode)_mapping_P[maptype]->free_look(b->mode[i]);
246 }
247 }
248
249 if(b){
250 if(b->mode)_ogg_free(b->mode);
251 _ogg_free(b);
252 }
253
254 memset(v,0,sizeof(*v));
255 }
256 }
257
258 /* Unlike in analysis, the window is only partially applied for each
259 block. The time domain envelope is not yet handled at the point of
260 calling (as it relies on the previous block). */
261
262 int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){
263 vorbis_info *vi=v->vi;
264 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
265 private_state *b=v->backend_state;
266 int i,j;
267
268 if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL);
269
270 v->lW=v->W;
271 v->W=vb->W;
272 v->nW=-1;
273
274 if((v->sequence==-1)||
275 (v->sequence+1 != vb->sequence)){
276 v->granulepos=-1; /* out of sequence; lose count */
277 b->sample_count=-1;
278 }
279
280 v->sequence=vb->sequence;
281
282 if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly
283 was called on block */
284 int n=ci->blocksizes[v->W]/2;
285 int n0=ci->blocksizes[0]/2;
286 int n1=ci->blocksizes[1]/2;
287
288 int thisCenter;
289 int prevCenter;
290
291 if(v->centerW){
292 thisCenter=n1;
293 prevCenter=0;
294 }else{
295 thisCenter=0;
296 prevCenter=n1;
297 }
298
299 /* v->pcm is now used like a two-stage double buffer. We don't want
300 to have to constantly shift *or* adjust memory usage. Don't
301 accept a new block until the old is shifted out */
302
303 /* overlap/add PCM */
304
305 for(j=0;j<vi->channels;j++){
306 /* the overlap/add section */
307 if(v->lW){
308 if(v->W){
309 /* large/large */
310 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
311 ogg_int32_t *p=vb->pcm[j];
312 for(i=0;i<n1;i++)
313 pcm[i]+=p[i];
314 }else{
315 /* large/small */
316 ogg_int32_t *pcm=v->pcm[j]+prevCenter+n1/2-n0/2;
317 ogg_int32_t *p=vb->pcm[j];
318 for(i=0;i<n0;i++)
319 pcm[i]+=p[i];
320 }
321 }else{
322 if(v->W){
323 /* small/large */
324 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
325 ogg_int32_t *p=vb->pcm[j]+n1/2-n0/2;
326 for(i=0;i<n0;i++)
327 pcm[i]+=p[i];
328 for(;i<n1/2+n0/2;i++)
329 pcm[i]=p[i];
330 }else{
331 /* small/small */
332 ogg_int32_t *pcm=v->pcm[j]+prevCenter;
333 ogg_int32_t *p=vb->pcm[j];
334 for(i=0;i<n0;i++)
335 pcm[i]+=p[i];
336 }
337 }
338
339 /* the copy section */
340 {
341 ogg_int32_t *pcm=v->pcm[j]+thisCenter;
342 ogg_int32_t *p=vb->pcm[j]+n;
343 for(i=0;i<n;i++)
344 pcm[i]=p[i];
345 }
346 }
347
348 if(v->centerW)
349 v->centerW=0;
350 else
351 v->centerW=n1;
352
353 /* deal with initial packet state; we do this using the explicit
354 pcm_returned==-1 flag otherwise we're sensitive to first block
355 being short or long */
356
357 if(v->pcm_returned==-1){
358 v->pcm_returned=thisCenter;
359 v->pcm_current=thisCenter;
360 }else{
361 v->pcm_returned=prevCenter;
362 v->pcm_current=prevCenter+
363 ci->blocksizes[v->lW]/4+
364 ci->blocksizes[v->W]/4;
365 }
366
367 }
368
369 /* track the frame number... This is for convenience, but also
370 making sure our last packet doesn't end with added padding. If
371 the last packet is partial, the number of samples we'll have to
372 return will be past the vb->granulepos.
373
374 This is not foolproof! It will be confused if we begin
375 decoding at the last page after a seek or hole. In that case,
376 we don't have a starting point to judge where the last frame
377 is. For this reason, vorbisfile will always try to make sure
378 it reads the last two marked pages in proper sequence */
379
380 if(b->sample_count==-1){
381 b->sample_count=0;
382 }else{
383 b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
384 }
385
386 if(v->granulepos==-1){
387 if(vb->granulepos!=-1){ /* only set if we have a position to set to */
388
389 v->granulepos=vb->granulepos;
390
391 /* is this a short page? */
392 if(b->sample_count>v->granulepos){
393 /* corner case; if this is both the first and last audio page,
394 then spec says the end is cut, not beginning */
395 long extra=b->sample_count-vb->granulepos;
396
397 /* we use ogg_int64_t for granule positions because a
398 uint64 isn't universally available. Unfortunately,
399 that means granposes can be 'negative' and result in
400 extra being negative */
401 if(extra<0)
402 extra=0;
403
404 if(vb->eofflag){
405 /* trim the end */
406 /* no preceeding granulepos; assume we started at zero (we'd
407 have to in a short single-page stream) */
408 /* granulepos could be -1 due to a seek, but that would result
409 in a long coun`t, not short count */
410
411 /* Guard against corrupt/malicious frames that set EOP and
412 a backdated granpos; don't rewind more samples than we
413 actually have */
414 if(extra > v->pcm_current - v->pcm_returned)
415 extra = v->pcm_current - v->pcm_returned;
416
417 v->pcm_current-=extra;
418 }else{
419 /* trim the beginning */
420 v->pcm_returned+=extra;
421 if(v->pcm_returned>v->pcm_current)
422 v->pcm_returned=v->pcm_current;
423 }
424
425 }
426
427 }
428 }else{
429 v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4;
430 if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){
431
432 if(v->granulepos>vb->granulepos){
433 long extra=v->granulepos-vb->granulepos;
434
435 if(extra)
436 if(vb->eofflag){
437 /* partial last frame. Strip the extra samples off */
438
439 /* Guard against corrupt/malicious frames that set EOP and
440 a backdated granpos; don't rewind more samples than we
441 actually have */
442 if(extra > v->pcm_current - v->pcm_returned)
443 extra = v->pcm_current - v->pcm_returned;
444
445 /* we use ogg_int64_t for granule positions because a
446 uint64 isn't universally available. Unfortunately,
447 that means granposes can be 'negative' and result in
448 extra being negative */
449 if(extra<0)
450 extra=0;
451
452 v->pcm_current-=extra;
453
454 } /* else {Shouldn't happen *unless* the bitstream is out of
455 spec. Either way, believe the bitstream } */
456 } /* else {Shouldn't happen *unless* the bitstream is out of
457 spec. Either way, believe the bitstream } */
458 v->granulepos=vb->granulepos;
459 }
460 }
461
462 /* Update, cleanup */
463
464 if(vb->eofflag)v->eofflag=1;
465 return(0);
466 }
467
468 /* pcm==NULL indicates we just want the pending samples, no more */
469 int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm){
470 vorbis_info *vi=v->vi;
471 if(v->pcm_returned>-1 && v->pcm_returned<v->pcm_current){
472 if(pcm){
473 int i;
474 for(i=0;i<vi->channels;i++)
475 v->pcmret[i]=v->pcm[i]+v->pcm_returned;
476 *pcm=v->pcmret;
477 }
478 return(v->pcm_current-v->pcm_returned);
479 }
480 return(0);
481 }
482
483 int vorbis_synthesis_read(vorbis_dsp_state *v,int bytes){
484 if(bytes && v->pcm_returned+bytes>v->pcm_current)return(OV_EINVAL);
485 v->pcm_returned+=bytes;
486 return(0);
487 }
488
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2008 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: shared block functions
14
15 ********************************************************************/
16
17 #ifndef _V_BLOCK_
18 #define _V_BLOCK_
19
20 extern void _vorbis_block_ripcord(vorbis_block *vb);
21 extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes);
22
23 #endif
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: basic codebook pack/unpack/code/decode operations
14
15 ********************************************************************/
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <math.h>
20 #include "ogg.h"
21 #include "ivorbiscodec.h"
22 #include "codebook.h"
23 #include "misc.h"
24 #include "tremor_shared.h"
25
26 /* unpacks a codebook from the packet buffer into the codebook struct,
27 readies the codebook auxiliary structures for decode *************/
28 static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){
29 long i,j;
30 static_codebook *s=_ogg_calloc(1,sizeof(*s));
31
32 /* make sure alignment is correct */
33 if(oggpack_read(opb,24)!=0x564342)goto _eofout;
34
35 /* first the basic parameters */
36 s->dim=oggpack_read(opb,16);
37 s->entries=oggpack_read(opb,24);
38 if(s->entries==-1)goto _eofout;
39
40 if(ilog(s->dim)+ ilog(s->entries)>24)goto _eofout;
41
42 /* codeword ordering.... length ordered or unordered? */
43 switch((int)oggpack_read(opb,1)){
44 case 0:{
45 long unused;
46 /* allocated but unused entries? */
47 unused=oggpack_read(opb,1);
48 if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb))
49 goto _eofout;
50 /* unordered */
51 s->lengthlist=(long *)_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
52
53 /* allocated but unused entries? */
54 if(unused){
55 /* yes, unused entries */
56
57 for(i=0;i<s->entries;i++){
58 if(oggpack_read(opb,1)){
59 long num=oggpack_read(opb,5);
60 if(num==-1)goto _eofout;
61 s->lengthlist[i]=num+1;
62 }else
63 s->lengthlist[i]=0;
64 }
65 }else{
66 /* all entries used; no tagging */
67 for(i=0;i<s->entries;i++){
68 long num=oggpack_read(opb,5);
69 if(num==-1)goto _eofout;
70 s->lengthlist[i]=num+1;
71 }
72 }
73
74 break;
75 }
76 case 1:
77 /* ordered */
78 {
79 long length=oggpack_read(opb,5)+1;
80 if(length==0)goto _eofout;
81 s->lengthlist=(long *)_ogg_malloc(sizeof(*s->lengthlist)*s->entries);
82
83 for(i=0;i<s->entries;){
84 long num=oggpack_read(opb, ilog(s->entries-i));
85 if(num==-1)goto _eofout;
86 if(length>32 || num>s->entries-i ||
87 (num>0 && (num-1)>>(length>>1)>>((length+1)>>1))>0){
88 goto _errout;
89 }
90 for(j=0;j<num;j++,i++)
91 s->lengthlist[i]=length;
92 length++;
93 }
94 }
95 break;
96 default:
97 /* EOF */
98 goto _eofout;
99 }
100
101 /* Do we have a mapping to unpack? */
102 switch((s->maptype=oggpack_read(opb,4))){
103 case 0:
104 /* no mapping */
105 break;
106 case 1: case 2:
107 /* implicitly populated value mapping */
108 /* explicitly populated value mapping */
109
110 s->q_min=oggpack_read(opb,32);
111 s->q_delta=oggpack_read(opb,32);
112 s->q_quant=oggpack_read(opb,4)+1;
113 s->q_sequencep=oggpack_read(opb,1);
114 if(s->q_sequencep==-1)goto _eofout;
115
116 {
117 int quantvals=0;
118 switch(s->maptype){
119 case 1:
120 quantvals=(s->dim==0?0:_book_maptype1_quantvals(s));
121 break;
122 case 2:
123 quantvals=s->entries*s->dim;
124 break;
125 }
126
127 /* quantized values */
128 if((quantvals*s->q_quant+7)>>3>opb->storage-oggpack_bytes(opb))
129 goto _eofout;
130 s->quantlist=(long *)_ogg_malloc(sizeof(*s->quantlist)*quantvals);
131 for(i=0;i<quantvals;i++)
132 s->quantlist[i]=oggpack_read(opb,s->q_quant);
133
134 if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout;
135 }
136 break;
137 default:
138 goto _errout;
139 }
140
141 /* all set */
142 return(s);
143
144 _errout:
145 _eofout:
146 vorbis_staticbook_destroy(s);
147 return(NULL);
148 }
149
150 STIN long decode_packed_entry_number(codebook *book,
151 oggpack_buffer *b){
152 int read=book->dec_maxlength;
153 long lo,hi;
154 long lok = oggpack_look(b,book->dec_firsttablen);
155
156 if (lok >= 0) {
157 long entry = book->dec_firsttable[lok];
158 if(entry&0x80000000UL){
159 lo=(entry>>15)&0x7fff;
160 hi=book->used_entries-(entry&0x7fff);
161 }else{
162 oggpack_adv(b, book->dec_codelengths[entry-1]);
163 return(entry-1);
164 }
165 }else{
166 lo=0;
167 hi=book->used_entries;
168 }
169
170 lok = oggpack_look(b, read);
171
172 while(lok<0 && read>1)
173 lok = oggpack_look(b, --read);
174
175 if(lok<0){
176 oggpack_adv(b,1); /* force eop */
177 return -1;
178 }
179
180 /* bisect search for the codeword in the ordered list */
181 {
182 ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok);
183
184 while(hi-lo>1){
185 long p=(hi-lo)>>1;
186 long test=book->codelist[lo+p]>testword;
187 lo+=p&(test-1);
188 hi-=p&(-test);
189 }
190
191 if(book->dec_codelengths[lo]<=read){
192 oggpack_adv(b, book->dec_codelengths[lo]);
193 return(lo);
194 }
195 }
196
197 oggpack_adv(b, read+1);
198 return(-1);
199 }
200
201 /* Decode side is specced and easier, because we don't need to find
202 matches using different criteria; we simply read and map. There are
203 two things we need to do 'depending':
204
205 We may need to support interleave. We don't really, but it's
206 convenient to do it here rather than rebuild the vector later.
207
208 Cascades may be additive or multiplicitive; this is not inherent in
209 the codebook, but set in the code using the codebook. Like
210 interleaving, it's easiest to do it here.
211 addmul==0 -> declarative (set the value)
212 addmul==1 -> additive
213 addmul==2 -> multiplicitive */
214
215 /* returns the [original, not compacted] entry number or -1 on eof *********/
216 long vorbis_book_decode(codebook *book, oggpack_buffer *b){
217 if(book->used_entries>0){
218 long packed_entry=decode_packed_entry_number(book,b);
219 if(packed_entry>=0)
220 return(book->dec_index[packed_entry]);
221 }
222
223 /* if there's no dec_index, the codebook unpacking isn't collapsed */
224 return(-1);
225 }
226
227 /* returns 0 on OK or -1 on eof *************************************/
228 /* decode vector / dim granularity gaurding is done in the upper layer */
229 long vorbis_book_decodevs_add(codebook *book,ogg_int32_t *a,
230 oggpack_buffer *b,int n,int point){
231 if(book->used_entries>0){
232 int step=n/book->dim;
233 long *entry = (long *)alloca(sizeof(*entry)*step);
234 ogg_int32_t **t = (ogg_int32_t **)alloca(sizeof(*t)*step);
235 int i,j,o;
236 int shift=point-book->binarypoint;
237
238 if(shift>=0){
239 for (i = 0; i < step; i++) {
240 entry[i]=decode_packed_entry_number(book,b);
241 if(entry[i]==-1)return(-1);
242 t[i] = book->valuelist+entry[i]*book->dim;
243 }
244 for(i=0,o=0;i<book->dim;i++,o+=step)
245 for (j=0;j<step;j++)
246 a[o+j]+=t[j][i]>>shift;
247 }else{
248 for (i = 0; i < step; i++) {
249 entry[i]=decode_packed_entry_number(book,b);
250 if(entry[i]==-1)return(-1);
251 t[i] = book->valuelist+entry[i]*book->dim;
252 }
253 for(i=0,o=0;i<book->dim;i++,o+=step)
254 for (j=0;j<step;j++)
255 a[o+j]+=t[j][i]<<-shift;
256 }
257 }
258 return(0);
259 }
260
261 /* decode vector / dim granularity gaurding is done in the upper layer */
262 long vorbis_book_decodev_add(codebook *book,ogg_int32_t *a,
263 oggpack_buffer *b,int n,int point){
264 if(book->used_entries>0){
265 int i,j,entry;
266 ogg_int32_t *t;
267 int shift=point-book->binarypoint;
268
269 if(shift>=0){
270 for(i=0;i<n;){
271 entry = decode_packed_entry_number(book,b);
272 if(entry==-1)return(-1);
273 t = book->valuelist+entry*book->dim;
274 for (j=0;j<book->dim;)
275 a[i++]+=t[j++]>>shift;
276 }
277 }else{
278 for(i=0;i<n;){
279 entry = decode_packed_entry_number(book,b);
280 if(entry==-1)return(-1);
281 t = book->valuelist+entry*book->dim;
282 for (j=0;j<book->dim;)
283 a[i++]+=t[j++]<<-shift;
284 }
285 }
286 }
287 return(0);
288 }
289
290 /* unlike the others, we guard against n not being an integer number
291 of <dim> internally rather than in the upper layer (called only by
292 floor0) */
293 long vorbis_book_decodev_set(codebook *book,ogg_int32_t *a,
294 oggpack_buffer *b,int n,int point){
295 if(book->used_entries>0){
296 int i,j,entry;
297 ogg_int32_t *t;
298 int shift=point-book->binarypoint;
299
300 if(shift>=0){
301
302 for(i=0;i<n;){
303 entry = decode_packed_entry_number(book,b);
304 if(entry==-1)return(-1);
305 t = book->valuelist+entry*book->dim;
306 for (j=0;i<n && j<book->dim;){
307 a[i++]=t[j++]>>shift;
308 }
309 }
310 }else{
311
312 for(i=0;i<n;){
313 entry = decode_packed_entry_number(book,b);
314 if(entry==-1)return(-1);
315 t = book->valuelist+entry*book->dim;
316 for (j=0;i<n && j<book->dim;){
317 a[i++]=t[j++]<<-shift;
318 }
319 }
320 }
321 }else{
322
323 int i,j;
324 for(i=0;i<n;){
325 a[i++]=0;
326 }
327 }
328 return(0);
329 }
330
331 /* decode vector / dim granularity gaurding is done in the upper layer */
332 long vorbis_book_decodevv_add(codebook *book,ogg_int32_t **a,\
333 long offset,int ch,
334 oggpack_buffer *b,int n,int point){
335 if(book->used_entries>0){
336 long i,j,entry;
337 int chptr=0;
338 int shift=point-book->binarypoint;
339
340 if(shift>=0){
341
342 for(i=offset;i<offset+n;){
343 entry = decode_packed_entry_number(book,b);
344 if(entry==-1)return(-1);
345 {
346 const ogg_int32_t *t = book->valuelist+entry*book->dim;
347 for (j=0;j<book->dim;j++){
348 a[chptr++][i]+=t[j]>>shift;
349 if(chptr==ch){
350 chptr=0;
351 i++;
352 }
353 }
354 }
355 }
356 }else{
357
358 for(i=offset;i<offset+n;){
359 entry = decode_packed_entry_number(book,b);
360 if(entry==-1)return(-1);
361 {
362 const ogg_int32_t *t = book->valuelist+entry*book->dim;
363 for (j=0;j<book->dim;j++){
364 a[chptr++][i]+=t[j]<<-shift;
365 if(chptr==ch){
366 chptr=0;
367 i++;
368 }
369 }
370 }
371 }
372 }
373 }
374 return(0);
375 }
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: basic shared codebook operations
14
15 ********************************************************************/
16
17 #ifndef _V_CODEBOOK_H_
18 #define _V_CODEBOOK_H_
19
20 #include "ogg.h"
21
22 /* This structure encapsulates huffman and VQ style encoding books; it
23 doesn't do anything specific to either.
24
25 valuelist/quantlist are nonNULL (and q_* significant) only if
26 there's entry->value mapping to be done.
27
28 If encode-side mapping must be done (and thus the entry needs to be
29 hunted), the auxiliary encode pointer will point to a decision
30 tree. This is true of both VQ and huffman, but is mostly useful
31 with VQ.
32
33 */
34
35 typedef struct static_codebook{
36 long dim; /* codebook dimensions (elements per vector) */
37 long entries; /* codebook entries */
38 long *lengthlist; /* codeword lengths in bits */
39
40 /* mapping ***************************************************************/
41 int maptype; /* 0=none
42 1=implicitly populated values from map column
43 2=listed arbitrary values */
44
45 /* The below does a linear, single monotonic sequence mapping. */
46 long q_min; /* packed 32 bit float; quant value 0 maps to minval */
47 long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
48 int q_quant; /* bits: 0 < quant <= 16 */
49 int q_sequencep; /* bitflag */
50
51 long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map
52 map == 2: list of dim*entries quantized entry vals
53 */
54 } static_codebook;
55
56 typedef struct codebook{
57 long dim; /* codebook dimensions (elements per vector) */
58 long entries; /* codebook entries */
59 long used_entries; /* populated codebook entries */
60
61 /* the below are ordered by bitreversed codeword and only used
62 entries are populated */
63 int binarypoint;
64 ogg_int32_t *valuelist; /* list of dim*entries actual entry values */
65 ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */
66
67 int *dec_index;
68 char *dec_codelengths;
69 ogg_uint32_t *dec_firsttable;
70 int dec_firsttablen;
71 int dec_maxlength;
72
73 long q_min; /* packed 32 bit float; quant value 0 maps to minval */
74 long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */
75
76 } codebook;
77
78 extern void vorbis_staticbook_destroy(static_codebook *b);
79 extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source);
80
81 extern void vorbis_book_clear(codebook *b);
82 extern long _book_maptype1_quantvals(const static_codebook *b);
83
84 extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b);
85
86 extern long vorbis_book_decode(codebook *book, oggpack_buffer *b);
87 extern long vorbis_book_decodevs_add(codebook *book, ogg_int32_t *a,
88 oggpack_buffer *b,int n,int point);
89 extern long vorbis_book_decodev_set(codebook *book, ogg_int32_t *a,
90 oggpack_buffer *b,int n,int point);
91 extern long vorbis_book_decodev_add(codebook *book, ogg_int32_t *a,
92 oggpack_buffer *b,int n,int point);
93 extern long vorbis_book_decodevv_add(codebook *book, ogg_int32_t **a,
94 long off,int ch,
95 oggpack_buffer *b,int n,int point);
96
97 extern int _ilog(unsigned int v);
98
99
100 #endif
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: libvorbis codec headers
14
15 ********************************************************************/
16
17 #ifndef _V_CODECI_H_
18 #define _V_CODECI_H_
19
20 #include "codebook.h"
21
22 typedef void vorbis_look_mapping;
23 typedef void vorbis_look_floor;
24 typedef void vorbis_look_residue;
25 typedef void vorbis_look_transform;
26
27 /* mode ************************************************************/
28 typedef struct {
29 int blockflag;
30 int windowtype;
31 int transformtype;
32 int mapping;
33 } vorbis_info_mode;
34
35 typedef void vorbis_info_floor;
36 typedef void vorbis_info_residue;
37 typedef void vorbis_info_mapping;
38
39 typedef struct private_state {
40 /* local lookup storage */
41 const void *window[2];
42
43 /* backend lookups are tied to the mode, not the backend or naked mapping */
44 int modebits;
45 vorbis_look_mapping **mode;
46
47 ogg_int64_t sample_count;
48
49 } private_state;
50
51 /* codec_setup_info contains all the setup information specific to the
52 specific compression/decompression mode in progress (eg,
53 psychoacoustic settings, channel setup, options, codebook
54 etc).
55 *********************************************************************/
56
57 typedef struct codec_setup_info {
58
59 /* Vorbis supports only short and long blocks, but allows the
60 encoder to choose the sizes */
61
62 long blocksizes[2];
63
64 /* modes are the primary means of supporting on-the-fly different
65 blocksizes, different channel mappings (LR or M/A),
66 different residue backends, etc. Each mode consists of a
67 blocksize flag and a mapping (along with the mapping setup */
68
69 int modes;
70 int maps;
71 int times;
72 int floors;
73 int residues;
74 int books;
75
76 vorbis_info_mode *mode_param[64];
77 int map_type[64];
78 vorbis_info_mapping *map_param[64];
79 int time_type[64];
80 int floor_type[64];
81 vorbis_info_floor *floor_param[64];
82 int residue_type[64];
83 vorbis_info_residue *residue_param[64];
84 static_codebook *book_param[256];
85 codebook *fullbooks;
86
87 int passlimit[32]; /* iteration limit per couple/quant pass */
88 int coupling_passes;
89 } codec_setup_info;
90
91 #endif
0 #ifndef __CONFIG_TYPES_H__
1 #define __CONFIG_TYPES_H__
2
3 #include <inttypes.h>
4
5 typedef int16_t ogg_int16_t;
6 typedef uint16_t ogg_uint16_t;
7 typedef int32_t ogg_int32_t;
8 typedef uint32_t ogg_uint32_t;
9 typedef int64_t ogg_int64_t;
10
11 #endif
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: floor backend 0 implementation
14
15 ********************************************************************/
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <math.h>
20 #include "ogg.h"
21 #include "ivorbiscodec.h"
22 #include "codec_internal.h"
23 #include "registry.h"
24 #include "codebook.h"
25 #include "misc.h"
26 #include "block.h"
27
28 #define LSP_FRACBITS 14
29
30 typedef struct {
31 long n;
32 int ln;
33 int m;
34 int *linearmap;
35
36 vorbis_info_floor0 *vi;
37 ogg_int32_t *lsp_look;
38
39 } vorbis_look_floor0;
40
41 /*************** LSP decode ********************/
42
43 #include "lsp_lookup.h"
44
45 /* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in
46 16.16 format
47 returns in m.8 format */
48
49 static long ADJUST_SQRT2[2]={8192,5792};
50 STIN ogg_int32_t vorbis_invsqlook_i(long a,long e){
51 long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1);
52 long d=a&INVSQ_LOOKUP_I_MASK; /* 0.10 */
53 long val=INVSQ_LOOKUP_I[i]- /* 1.16 */
54 ((INVSQ_LOOKUP_IDel[i]*d)>>INVSQ_LOOKUP_I_SHIFT); /* result 1.16 */
55 val*=ADJUST_SQRT2[e&1];
56 e=(e>>1)+21;
57 return(val>>e);
58 }
59
60 /* interpolated lookup based fromdB function, domain -140dB to 0dB only */
61 /* a is in n.12 format */
62 STIN ogg_int32_t vorbis_fromdBlook_i(long a){
63 int i=(-a)>>(12-FROMdB2_SHIFT);
64 if(i<0) return 0x7fffffff;
65 if(i>=(FROMdB_LOOKUP_SZ<<FROMdB_SHIFT))return 0;
66
67 return FROMdB_LOOKUP[i>>FROMdB_SHIFT] * FROMdB2_LOOKUP[i&FROMdB2_MASK];
68 }
69
70 /* interpolated lookup based cos function, domain 0 to PI only */
71 /* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */
72 STIN ogg_int32_t vorbis_coslook_i(long a){
73 int i=a>>COS_LOOKUP_I_SHIFT;
74 int d=a&COS_LOOKUP_I_MASK;
75 return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
76 COS_LOOKUP_I_SHIFT);
77 }
78
79 /* interpolated lookup based cos function */
80 /* a is in 0.16 format, where 0==0, 2^^16==PI, return .LSP_FRACBITS */
81 STIN ogg_int32_t vorbis_coslook2_i(long a){
82 a=a&0x1ffff;
83
84 if(a>0x10000)a=0x20000-a;
85 {
86 int i=a>>COS_LOOKUP_I_SHIFT;
87 int d=a&COS_LOOKUP_I_MASK;
88 a=((COS_LOOKUP_I[i]<<COS_LOOKUP_I_SHIFT)-
89 d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>>
90 (COS_LOOKUP_I_SHIFT-LSP_FRACBITS+14);
91 }
92
93 return(a);
94 }
95
96 static const int barklook[28]={
97 0,100,200,301, 405,516,635,766,
98 912,1077,1263,1476, 1720,2003,2333,2721,
99 3184,3742,4428,5285, 6376,7791,9662,12181,
100 15624,20397,27087,36554
101 };
102
103 /* used in init only; interpolate the long way */
104 STIN ogg_int32_t toBARK(int n){
105 int i;
106 for(i=0;i<27;i++)
107 if(n>=barklook[i] && n<barklook[i+1])break;
108
109 if(i==27){
110 return 27<<15;
111 }else{
112 int gap=barklook[i+1]-barklook[i];
113 int del=n-barklook[i];
114
115 return((i<<15)+((del<<15)/gap));
116 }
117 }
118
119 static const unsigned char MLOOP_1[64]={
120 0,10,11,11, 12,12,12,12, 13,13,13,13, 13,13,13,13,
121 14,14,14,14, 14,14,14,14, 14,14,14,14, 14,14,14,14,
122 15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
123 15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15,
124 };
125
126 static const unsigned char MLOOP_2[64]={
127 0,4,5,5, 6,6,6,6, 7,7,7,7, 7,7,7,7,
128 8,8,8,8, 8,8,8,8, 8,8,8,8, 8,8,8,8,
129 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,
130 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9,
131 };
132
133 static const unsigned char MLOOP_3[8]={0,1,2,2,3,3,3,3};
134
135 void vorbis_lsp_to_curve(ogg_int32_t *curve,int *map,int n,int ln,
136 ogg_int32_t *lsp,int m,
137 ogg_int32_t amp,
138 ogg_int32_t ampoffset,
139 ogg_int32_t *icos){
140
141 /* 0 <= m < 256 */
142
143 /* set up for using all int later */
144 int i;
145 int ampoffseti=ampoffset*4096;
146 int ampi=amp;
147 ogg_int32_t *ilsp=(ogg_int32_t *)alloca(m*sizeof(*ilsp));
148 /* lsp is in 8.24, range 0 to PI; coslook wants it in .16 0 to 1*/
149 for(i=0;i<m;i++){
150 #ifndef _LOW_ACCURACY_
151 ogg_int32_t val=MULT32(lsp[i],0x517cc2);
152 #else
153 ogg_int32_t val=((lsp[i]>>10)*0x517d)>>14;
154 #endif
155
156 /* safeguard against a malicious stream */
157 if(val<0 || (val>>COS_LOOKUP_I_SHIFT)>=COS_LOOKUP_I_SZ){
158 memset(curve,0,sizeof(*curve)*n);
159 return;
160 }
161
162 ilsp[i]=vorbis_coslook_i(val);
163 }
164
165 i=0;
166 while(i<n){
167 int j,k=map[i];
168 ogg_uint32_t pi=46341; /* 2**-.5 in 0.16 */
169 ogg_uint32_t qi=46341;
170 ogg_int32_t qexp=0,shift;
171 ogg_int32_t wi=icos[k];
172
173 #ifdef _V_LSP_MATH_ASM
174 lsp_loop_asm(&qi,&pi,&qexp,ilsp,wi,m);
175
176 pi=((pi*pi)>>16);
177 qi=((qi*qi)>>16);
178
179 if(m&1){
180 qexp= qexp*2-28*((m+1)>>1)+m;
181 pi*=(1<<14)-((wi*wi)>>14);
182 qi+=pi>>14;
183 }else{
184 qexp= qexp*2-13*m;
185
186 pi*=(1<<14)-wi;
187 qi*=(1<<14)+wi;
188
189 qi=(qi+pi)>>14;
190 }
191
192 if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */
193 qi>>=1; qexp++;
194 }else
195 lsp_norm_asm(&qi,&qexp);
196
197 #else
198
199 j=1;
200 if(m>1){
201 qi*=labs(ilsp[0]-wi);
202 pi*=labs(ilsp[1]-wi);
203
204 for(j+=2;j<m;j+=2){
205 if(!(shift=MLOOP_1[(pi|qi)>>25]))
206 if(!(shift=MLOOP_2[(pi|qi)>>19]))
207 shift=MLOOP_3[(pi|qi)>>16];
208 qi=(qi>>shift)*labs(ilsp[j-1]-wi);
209 pi=(pi>>shift)*labs(ilsp[j]-wi);
210 qexp+=shift;
211 }
212 }
213 if(!(shift=MLOOP_1[(pi|qi)>>25]))
214 if(!(shift=MLOOP_2[(pi|qi)>>19]))
215 shift=MLOOP_3[(pi|qi)>>16];
216
217 /* pi,qi normalized collectively, both tracked using qexp */
218
219 if(m&1){
220 /* odd order filter; slightly assymetric */
221 /* the last coefficient */
222 qi=(qi>>shift)*labs(ilsp[j-1]-wi);
223 pi=(pi>>shift)<<14;
224 qexp+=shift;
225
226 if(!(shift=MLOOP_1[(pi|qi)>>25]))
227 if(!(shift=MLOOP_2[(pi|qi)>>19]))
228 shift=MLOOP_3[(pi|qi)>>16];
229
230 pi>>=shift;
231 qi>>=shift;
232 qexp+=shift-14*((m+1)>>1);
233
234 pi=((pi*pi)>>16);
235 qi=((qi*qi)>>16);
236 qexp=qexp*2+m;
237
238 pi*=(1<<14)-((wi*wi)>>14);
239 qi+=pi>>14;
240
241 }else{
242 /* even order filter; still symmetric */
243
244 /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't
245 worth tracking step by step */
246
247 pi>>=shift;
248 qi>>=shift;
249 qexp+=shift-7*m;
250
251 pi=((pi*pi)>>16);
252 qi=((qi*qi)>>16);
253 qexp=qexp*2+m;
254
255 pi*=(1<<14)-wi;
256 qi*=(1<<14)+wi;
257 qi=(qi+pi)>>14;
258
259 }
260
261
262 /* we've let the normalization drift because it wasn't important;
263 however, for the lookup, things must be normalized again. We
264 need at most one right shift or a number of left shifts */
265
266 if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */
267 qi>>=1; qexp++;
268 }else
269 while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/
270 qi<<=1; qexp--;
271 }
272
273 #endif
274
275 amp=vorbis_fromdBlook_i(ampi* /* n.4 */
276 vorbis_invsqlook_i(qi,qexp)-
277 /* m.8, m+n<=8 */
278 ampoffseti); /* 8.12[0] */
279
280 #ifdef _LOW_ACCURACY_
281 amp>>=9;
282 #endif
283 curve[i]= MULT31_SHIFT15(curve[i],amp);
284 while(map[++i]==k) curve[i]= MULT31_SHIFT15(curve[i],amp);
285 }
286 }
287
288 /*************** vorbis decode glue ************/
289
290 static void floor0_free_info(vorbis_info_floor *i){
291 vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
292 if(info){
293 memset(info,0,sizeof(*info));
294 _ogg_free(info);
295 }
296 }
297
298 static void floor0_free_look(vorbis_look_floor *i){
299 vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
300 if(look){
301
302 if(look->linearmap)_ogg_free(look->linearmap);
303 if(look->lsp_look)_ogg_free(look->lsp_look);
304 memset(look,0,sizeof(*look));
305 _ogg_free(look);
306 }
307 }
308
309 static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){
310 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
311 int j;
312
313 vorbis_info_floor0 *info=(vorbis_info_floor0 *)_ogg_malloc(sizeof(*info));
314 info->order=oggpack_read(opb,8);
315 info->rate=oggpack_read(opb,16);
316 info->barkmap=oggpack_read(opb,16);
317 info->ampbits=oggpack_read(opb,6);
318 info->ampdB=oggpack_read(opb,8);
319 info->numbooks=oggpack_read(opb,4)+1;
320
321 if(info->order<1)goto err_out;
322 if(info->rate<1)goto err_out;
323 if(info->barkmap<1)goto err_out;
324 if(info->numbooks<1)goto err_out;
325
326 for(j=0;j<info->numbooks;j++){
327 info->books[j]=oggpack_read(opb,8);
328 if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out;
329 if(ci->book_param[info->books[j]]->maptype==0)goto err_out;
330 if(ci->book_param[info->books[j]]->dim<1)goto err_out;
331 }
332 return(info);
333
334 err_out:
335 floor0_free_info(info);
336 return(NULL);
337 }
338
339 /* initialize Bark scale and normalization lookups. We could do this
340 with static tables, but Vorbis allows a number of possible
341 combinations, so it's best to do it computationally.
342
343 The below is authoritative in terms of defining scale mapping.
344 Note that the scale depends on the sampling rate as well as the
345 linear block and mapping sizes */
346
347 static vorbis_look_floor *floor0_look (vorbis_dsp_state *vd,vorbis_info_mode *mi,
348 vorbis_info_floor *i){
349 int j;
350 vorbis_info *vi=vd->vi;
351 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
352 vorbis_info_floor0 *info=(vorbis_info_floor0 *)i;
353 vorbis_look_floor0 *look=(vorbis_look_floor0 *)_ogg_calloc(1,sizeof(*look));
354 look->m=info->order;
355 look->n=ci->blocksizes[mi->blockflag]/2;
356 look->ln=info->barkmap;
357 look->vi=info;
358
359 /* the mapping from a linear scale to a smaller bark scale is
360 straightforward. We do *not* make sure that the linear mapping
361 does not skip bark-scale bins; the decoder simply skips them and
362 the encoder may do what it wishes in filling them. They're
363 necessary in some mapping combinations to keep the scale spacing
364 accurate */
365 look->linearmap=(int *)_ogg_malloc((look->n+1)*sizeof(*look->linearmap));
366 for(j=0;j<look->n;j++){
367
368 int val=(look->ln*
369 ((toBARK(info->rate/2*j/look->n)<<11)/toBARK(info->rate/2)))>>11;
370
371 if(val>=look->ln)val=look->ln-1; /* guard against the approximation */
372 look->linearmap[j]=val;
373 }
374 look->linearmap[j]=-1;
375
376 look->lsp_look=(ogg_int32_t *)_ogg_malloc(look->ln*sizeof(*look->lsp_look));
377 for(j=0;j<look->ln;j++)
378 look->lsp_look[j]=vorbis_coslook2_i(0x10000*j/look->ln);
379
380 return look;
381 }
382
383 static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){
384 vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
385 vorbis_info_floor0 *info=look->vi;
386 int j,k;
387
388 int ampraw=oggpack_read(&vb->opb,info->ampbits);
389 if(ampraw>0){ /* also handles the -1 out of data case */
390 long maxval=(1<<info->ampbits)-1;
391 int amp=((ampraw*info->ampdB)<<4)/maxval;
392 int booknum=oggpack_read(&vb->opb, ilog(info->numbooks));
393
394 if(booknum!=-1 && booknum<info->numbooks){ /* be paranoid */
395 codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup;
396 codebook *b=ci->fullbooks+info->books[booknum];
397 ogg_int32_t last=0;
398 ogg_int32_t *lsp=(ogg_int32_t *)_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+1));
399
400 if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m,-24)==-1)goto eop;
401 for(j=0;j<look->m;){
402 for(k=0;j<look->m && k<b->dim;k++,j++)lsp[j]+=last;
403 last=lsp[j-1];
404 }
405
406 lsp[look->m]=amp;
407 return(lsp);
408 }
409 }
410 eop:
411 return(NULL);
412 }
413
414 static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i,
415 void *memo,ogg_int32_t *out){
416 vorbis_look_floor0 *look=(vorbis_look_floor0 *)i;
417 vorbis_info_floor0 *info=look->vi;
418
419 if(memo){
420 ogg_int32_t *lsp=(ogg_int32_t *)memo;
421 ogg_int32_t amp=lsp[look->m];
422
423 /* take the coefficients back to a spectral envelope curve */
424 vorbis_lsp_to_curve(out,look->linearmap,look->n,look->ln,
425 lsp,look->m,amp,info->ampdB,look->lsp_look);
426 return(1);
427 }
428 memset(out,0,sizeof(*out)*look->n);
429 return(0);
430 }
431
432 /* export hooks */
433 vorbis_func_floor floor0_exportbundle={
434 &floor0_unpack,&floor0_look,&floor0_free_info,
435 &floor0_free_look,&floor0_inverse1,&floor0_inverse2
436 };
437
438
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: floor backend 1 implementation
14
15 ********************************************************************/
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <math.h>
20 #include "ogg.h"
21 #include "ivorbiscodec.h"
22 #include "codec_internal.h"
23 #include "registry.h"
24 #include "codebook.h"
25 #include "misc.h"
26 #include "block.h"
27 #include "tremor_shared.h"
28
29 #define floor1_rangedB 140 /* floor 1 fixed at -140dB to 0dB range */
30
31 typedef struct {
32 int forward_index[VIF_POSIT+2];
33
34 int hineighbor[VIF_POSIT];
35 int loneighbor[VIF_POSIT];
36 int posts;
37
38 int n;
39 int quant_q;
40 vorbis_info_floor1 *vi;
41
42 } vorbis_look_floor1;
43
44 /***********************************************/
45
46 static void floor1_free_info(vorbis_info_floor *i){
47 vorbis_info_floor1 *info=(vorbis_info_floor1 *)i;
48 if(info){
49 memset(info,0,sizeof(*info));
50 _ogg_free(info);
51 }
52 }
53
54 static void floor1_free_look(vorbis_look_floor *i){
55 vorbis_look_floor1 *look=(vorbis_look_floor1 *)i;
56 if(look){
57 memset(look,0,sizeof(*look));
58 _ogg_free(look);
59 }
60 }
61
62 static int icomp(const void *a,const void *b){
63 return(**(int **)a-**(int **)b);
64 }
65
66 static vorbis_info_floor *floor1_unpack (vorbis_info *vi,oggpack_buffer *opb){
67 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
68 int j,k,count=0,maxclass=-1,rangebits;
69
70 vorbis_info_floor1 *info=(vorbis_info_floor1 *)_ogg_calloc(1,sizeof(*info));
71 /* read partitions */
72 info->partitions=oggpack_read(opb,5); /* only 0 to 31 legal */
73 for(j=0;j<info->partitions;j++){
74 info->partitionclass[j]=oggpack_read(opb,4); /* only 0 to 15 legal */
75 if(info->partitionclass[j]<0)goto err_out;
76 if(maxclass<info->partitionclass[j])maxclass=info->partitionclass[j];
77 }
78
79 /* read partition classes */
80 for(j=0;j<maxclass+1;j++){
81 info->class_dim[j]=oggpack_read(opb,3)+1; /* 1 to 8 */
82 info->class_subs[j]=oggpack_read(opb,2); /* 0,1,2,3 bits */
83 if(info->class_subs[j]<0)
84 goto err_out;
85 if(info->class_subs[j])info->class_book[j]=oggpack_read(opb,8);
86 if(info->class_book[j]<0 || info->class_book[j]>=ci->books)
87 goto err_out;
88 for(k=0;k<(1<<info->class_subs[j]);k++){
89 info->class_subbook[j][k]=oggpack_read(opb,8)-1;
90 if(info->class_subbook[j][k]<-1 || info->class_subbook[j][k]>=ci->books)
91 goto err_out;
92 }
93 }
94
95 /* read the post list */
96 info->mult=oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */
97 rangebits=oggpack_read(opb,4);
98 if(rangebits<0)goto err_out;
99
100 for(j=0,k=0;j<info->partitions;j++){
101 count+=info->class_dim[info->partitionclass[j]];
102 if(count>VIF_POSIT)goto err_out;
103 for(;k<count;k++){
104 int t=info->postlist[k+2]=oggpack_read(opb,rangebits);
105 if(t<0 || t>=(1<<rangebits))
106 goto err_out;
107 }
108 }
109 info->postlist[0]=0;
110 info->postlist[1]=1<<rangebits;
111
112 /* don't allow repeated values in post list as they'd result in
113 zero-length segments */
114 {
115 int *sortpointer[VIF_POSIT+2];
116 for(j=0;j<count+2;j++)sortpointer[j]=info->postlist+j;
117 qsort(sortpointer,count+2,sizeof(*sortpointer),icomp);
118
119 for(j=1;j<count+2;j++)
120 if(*sortpointer[j-1]==*sortpointer[j])goto err_out;
121 }
122
123 return(info);
124
125 err_out:
126 floor1_free_info(info);
127 return(NULL);
128 }
129
130 static vorbis_look_floor *floor1_look(vorbis_dsp_state *vd,vorbis_info_mode *mi,
131 vorbis_info_floor *in){
132
133 int *sortpointer[VIF_POSIT+2];
134 vorbis_info_floor1 *info=(vorbis_info_floor1 *)in;
135 vorbis_look_floor1 *look=(vorbis_look_floor1 *)_ogg_calloc(1,sizeof(*look));
136 int i,j,n=0;
137
138 look->vi=info;
139 look->n=info->postlist[1];
140
141 /* we drop each position value in-between already decoded values,
142 and use linear interpolation to predict each new value past the
143 edges. The positions are read in the order of the position
144 list... we precompute the bounding positions in the lookup. Of
145 course, the neighbors can change (if a position is declined), but
146 this is an initial mapping */
147
148 for(i=0;i<info->partitions;i++)n+=info->class_dim[info->partitionclass[i]];
149 n+=2;
150 look->posts=n;
151
152 /* also store a sorted position index */
153 for(i=0;i<n;i++)sortpointer[i]=info->postlist+i;
154 qsort(sortpointer,n,sizeof(*sortpointer),icomp);
155
156 /* points from sort order back to range number */
157 for(i=0;i<n;i++)look->forward_index[i]=sortpointer[i]-info->postlist;
158
159 /* quantize values to multiplier spec */
160 switch(info->mult){
161 case 1: /* 1024 -> 256 */
162 look->quant_q=256;
163 break;
164 case 2: /* 1024 -> 128 */
165 look->quant_q=128;
166 break;
167 case 3: /* 1024 -> 86 */
168 look->quant_q=86;
169 break;
170 case 4: /* 1024 -> 64 */
171 look->quant_q=64;
172 break;
173 }
174
175 /* discover our neighbors for decode where we don't use fit flags
176 (that would push the neighbors outward) */
177 for(i=0;i<n-2;i++){
178 int lo=0;
179 int hi=1;
180 int lx=0;
181 int hx=look->n;
182 int currentx=info->postlist[i+2];
183 for(j=0;j<i+2;j++){
184 int x=info->postlist[j];
185 if(x>lx && x<currentx){
186 lo=j;
187 lx=x;
188 }
189 if(x<hx && x>currentx){
190 hi=j;
191 hx=x;
192 }
193 }
194 look->loneighbor[i]=lo;
195 look->hineighbor[i]=hi;
196 }
197
198 return(look);
199 }
200
201 static int render_point(int x0,int x1,int y0,int y1,int x){
202 y0&=0x7fff; /* mask off flag */
203 y1&=0x7fff;
204
205 {
206 int dy=y1-y0;
207 int adx=x1-x0;
208 int ady=abs(dy);
209 int err=ady*(x-x0);
210
211 int off=err/adx;
212 if(dy<0)return(y0-off);
213 return(y0+off);
214 }
215 }
216
217 #ifdef _LOW_ACCURACY_
218 # define XdB(n) ((((n)>>8)+1)>>1)
219 #else
220 # define XdB(n) (n)
221 #endif
222
223 static const ogg_int32_t FLOOR_fromdB_LOOKUP[256]={
224 XdB(0x000000e5), XdB(0x000000f4), XdB(0x00000103), XdB(0x00000114),
225 XdB(0x00000126), XdB(0x00000139), XdB(0x0000014e), XdB(0x00000163),
226 XdB(0x0000017a), XdB(0x00000193), XdB(0x000001ad), XdB(0x000001c9),
227 XdB(0x000001e7), XdB(0x00000206), XdB(0x00000228), XdB(0x0000024c),
228 XdB(0x00000272), XdB(0x0000029b), XdB(0x000002c6), XdB(0x000002f4),
229 XdB(0x00000326), XdB(0x0000035a), XdB(0x00000392), XdB(0x000003cd),
230 XdB(0x0000040c), XdB(0x00000450), XdB(0x00000497), XdB(0x000004e4),
231 XdB(0x00000535), XdB(0x0000058c), XdB(0x000005e8), XdB(0x0000064a),
232 XdB(0x000006b3), XdB(0x00000722), XdB(0x00000799), XdB(0x00000818),
233 XdB(0x0000089e), XdB(0x0000092e), XdB(0x000009c6), XdB(0x00000a69),
234 XdB(0x00000b16), XdB(0x00000bcf), XdB(0x00000c93), XdB(0x00000d64),
235 XdB(0x00000e43), XdB(0x00000f30), XdB(0x0000102d), XdB(0x0000113a),
236 XdB(0x00001258), XdB(0x0000138a), XdB(0x000014cf), XdB(0x00001629),
237 XdB(0x0000179a), XdB(0x00001922), XdB(0x00001ac4), XdB(0x00001c82),
238 XdB(0x00001e5c), XdB(0x00002055), XdB(0x0000226f), XdB(0x000024ac),
239 XdB(0x0000270e), XdB(0x00002997), XdB(0x00002c4b), XdB(0x00002f2c),
240 XdB(0x0000323d), XdB(0x00003581), XdB(0x000038fb), XdB(0x00003caf),
241 XdB(0x000040a0), XdB(0x000044d3), XdB(0x0000494c), XdB(0x00004e10),
242 XdB(0x00005323), XdB(0x0000588a), XdB(0x00005e4b), XdB(0x0000646b),
243 XdB(0x00006af2), XdB(0x000071e5), XdB(0x0000794c), XdB(0x0000812e),
244 XdB(0x00008993), XdB(0x00009283), XdB(0x00009c09), XdB(0x0000a62d),
245 XdB(0x0000b0f9), XdB(0x0000bc79), XdB(0x0000c8b9), XdB(0x0000d5c4),
246 XdB(0x0000e3a9), XdB(0x0000f274), XdB(0x00010235), XdB(0x000112fd),
247 XdB(0x000124dc), XdB(0x000137e4), XdB(0x00014c29), XdB(0x000161bf),
248 XdB(0x000178bc), XdB(0x00019137), XdB(0x0001ab4a), XdB(0x0001c70e),
249 XdB(0x0001e4a1), XdB(0x0002041f), XdB(0x000225aa), XdB(0x00024962),
250 XdB(0x00026f6d), XdB(0x000297f0), XdB(0x0002c316), XdB(0x0002f109),
251 XdB(0x000321f9), XdB(0x00035616), XdB(0x00038d97), XdB(0x0003c8b4),
252 XdB(0x000407a7), XdB(0x00044ab2), XdB(0x00049218), XdB(0x0004de23),
253 XdB(0x00052f1e), XdB(0x0005855c), XdB(0x0005e135), XdB(0x00064306),
254 XdB(0x0006ab33), XdB(0x00071a24), XdB(0x0007904b), XdB(0x00080e20),
255 XdB(0x00089422), XdB(0x000922da), XdB(0x0009bad8), XdB(0x000a5cb6),
256 XdB(0x000b091a), XdB(0x000bc0b1), XdB(0x000c8436), XdB(0x000d5471),
257 XdB(0x000e3233), XdB(0x000f1e5f), XdB(0x001019e4), XdB(0x001125c1),
258 XdB(0x00124306), XdB(0x001372d5), XdB(0x0014b663), XdB(0x00160ef7),
259 XdB(0x00177df0), XdB(0x001904c1), XdB(0x001aa4f9), XdB(0x001c603d),
260 XdB(0x001e384f), XdB(0x00202f0f), XdB(0x0022467a), XdB(0x002480b1),
261 XdB(0x0026dff7), XdB(0x002966b3), XdB(0x002c1776), XdB(0x002ef4fc),
262 XdB(0x0032022d), XdB(0x00354222), XdB(0x0038b828), XdB(0x003c67c2),
263 XdB(0x004054ae), XdB(0x004482e8), XdB(0x0048f6af), XdB(0x004db488),
264 XdB(0x0052c142), XdB(0x005821ff), XdB(0x005ddc33), XdB(0x0063f5b0),
265 XdB(0x006a74a7), XdB(0x00715faf), XdB(0x0078bdce), XdB(0x0080967f),
266 XdB(0x0088f1ba), XdB(0x0091d7f9), XdB(0x009b5247), XdB(0x00a56a41),
267 XdB(0x00b02a27), XdB(0x00bb9ce2), XdB(0x00c7ce12), XdB(0x00d4ca17),
268 XdB(0x00e29e20), XdB(0x00f15835), XdB(0x0101074b), XdB(0x0111bb4e),
269 XdB(0x01238531), XdB(0x01367704), XdB(0x014aa402), XdB(0x016020a7),
270 XdB(0x017702c3), XdB(0x018f6190), XdB(0x01a955cb), XdB(0x01c4f9cf),
271 XdB(0x01e269a8), XdB(0x0201c33b), XdB(0x0223265a), XdB(0x0246b4ea),
272 XdB(0x026c9302), XdB(0x0294e716), XdB(0x02bfda13), XdB(0x02ed9793),
273 XdB(0x031e4e09), XdB(0x03522ee4), XdB(0x03896ed0), XdB(0x03c445e2),
274 XdB(0x0402efd6), XdB(0x0445ac4b), XdB(0x048cbefc), XdB(0x04d87013),
275 XdB(0x05290c67), XdB(0x057ee5ca), XdB(0x05da5364), XdB(0x063bb204),
276 XdB(0x06a36485), XdB(0x0711d42b), XdB(0x0787710e), XdB(0x0804b299),
277 XdB(0x088a17ef), XdB(0x0918287e), XdB(0x09af747c), XdB(0x0a50957e),
278 XdB(0x0afc2f19), XdB(0x0bb2ef7f), XdB(0x0c759034), XdB(0x0d44d6ca),
279 XdB(0x0e2195bc), XdB(0x0f0cad0d), XdB(0x10070b62), XdB(0x1111aeea),
280 XdB(0x122da66c), XdB(0x135c120f), XdB(0x149e24d9), XdB(0x15f525b1),
281 XdB(0x176270e3), XdB(0x18e7794b), XdB(0x1a85c9ae), XdB(0x1c3f06d1),
282 XdB(0x1e14f07d), XdB(0x200963d7), XdB(0x221e5ccd), XdB(0x2455f870),
283 XdB(0x26b2770b), XdB(0x29363e2b), XdB(0x2be3db5c), XdB(0x2ebe06b6),
284 XdB(0x31c7a55b), XdB(0x3503ccd4), XdB(0x3875c5aa), XdB(0x3c210f44),
285 XdB(0x4009632b), XdB(0x4432b8cf), XdB(0x48a149bc), XdB(0x4d59959e),
286 XdB(0x52606733), XdB(0x57bad899), XdB(0x5d6e593a), XdB(0x6380b298),
287 XdB(0x69f80e9a), XdB(0x70dafda8), XdB(0x78307d76), XdB(0x7fffffff),
288 };
289
290 static void render_line(int n, int x0,int x1,int y0,int y1,ogg_int32_t *d){
291 int dy=y1-y0;
292 int adx=x1-x0;
293 int ady=abs(dy);
294 int base=dy/adx;
295 int sy=(dy<0?base-1:base+1);
296 int x=x0;
297 int y=y0;
298 int err=0;
299
300 if(n>x1)n=x1;
301 ady-=abs(base*adx);
302
303 if(x<n)
304 d[x]= MULT31_SHIFT15(d[x],FLOOR_fromdB_LOOKUP[y]);
305
306 while(++x<n){
307 err=err+ady;
308 if(err>=adx){
309 err-=adx;
310 y+=sy;
311 }else{
312 y+=base;
313 }
314 d[x]= MULT31_SHIFT15(d[x],FLOOR_fromdB_LOOKUP[y]);
315 }
316 }
317
318 static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){
319 vorbis_look_floor1 *look=(vorbis_look_floor1 *)in;
320 vorbis_info_floor1 *info=look->vi;
321 codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup;
322
323 int i,j,k;
324 codebook *books=ci->fullbooks;
325
326 /* unpack wrapped/predicted values from stream */
327 if(oggpack_read(&vb->opb,1)==1){
328 int *fit_value=(int *)_vorbis_block_alloc(vb,(look->posts)*sizeof(*fit_value));
329
330 fit_value[0]=oggpack_read(&vb->opb,ilog(look->quant_q-1));
331 fit_value[1]=oggpack_read(&vb->opb,ilog(look->quant_q-1));
332
333 /* partition by partition */
334 /* partition by partition */
335 for(i=0,j=2;i<info->partitions;i++){
336 int classv=info->partitionclass[i];
337 int cdim=info->class_dim[classv];
338 int csubbits=info->class_subs[classv];
339 int csub=1<<csubbits;
340 int cval=0;
341
342 /* decode the partition's first stage cascade value */
343 if(csubbits){
344 cval=vorbis_book_decode(books+info->class_book[classv],&vb->opb);
345
346 if(cval==-1)goto eop;
347 }
348
349 for(k=0;k<cdim;k++){
350 int book=info->class_subbook[classv][cval&(csub-1)];
351 cval>>=csubbits;
352 if(book>=0){
353 if((fit_value[j+k]=vorbis_book_decode(books+book,&vb->opb))==-1)
354 goto eop;
355 }else{
356 fit_value[j+k]=0;
357 }
358 }
359 j+=cdim;
360 }
361
362 /* unwrap positive values and reconsitute via linear interpolation */
363 for(i=2;i<look->posts;i++){
364 int predicted=render_point(info->postlist[look->loneighbor[i-2]],
365 info->postlist[look->hineighbor[i-2]],
366 fit_value[look->loneighbor[i-2]],
367 fit_value[look->hineighbor[i-2]],
368 info->postlist[i]);
369 int hiroom=look->quant_q-predicted;
370 int loroom=predicted;
371 int room=(hiroom<loroom?hiroom:loroom)<<1;
372 int val=fit_value[i];
373
374 if(val){
375 if(val>=room){
376 if(hiroom>loroom){
377 val = val-loroom;
378 }else{
379 val = -1-(val-hiroom);
380 }
381 }else{
382 if(val&1){
383 val= -((val+1)>>1);
384 }else{
385 val>>=1;
386 }
387 }
388
389 fit_value[i]=(val+predicted)&0x7fff;;
390 fit_value[look->loneighbor[i-2]]&=0x7fff;
391 fit_value[look->hineighbor[i-2]]&=0x7fff;
392
393 }else{
394 fit_value[i]=predicted|0x8000;
395 }
396
397 }
398
399 return(fit_value);
400 }
401 eop:
402 return(NULL);
403 }
404
405 static int floor1_inverse2(vorbis_block *vb,vorbis_look_floor *in,void *memo,
406 ogg_int32_t *out){
407 vorbis_look_floor1 *look=(vorbis_look_floor1 *)in;
408 vorbis_info_floor1 *info=look->vi;
409
410 codec_setup_info *ci=(codec_setup_info *)vb->vd->vi->codec_setup;
411 int n=ci->blocksizes[vb->W]/2;
412 int j;
413
414 if(memo){
415 /* render the lines */
416 int *fit_value=(int *)memo;
417 int hx=0;
418 int lx=0;
419 int ly=fit_value[0]*info->mult;
420 /* guard lookup against out-of-range values */
421 ly=(ly<0?0:ly>255?255:ly);
422
423 for(j=1;j<look->posts;j++){
424 int current=look->forward_index[j];
425 int hy=fit_value[current]&0x7fff;
426 if(hy==fit_value[current]){
427
428 hx=info->postlist[current];
429 hy*=info->mult;
430 /* guard lookup against out-of-range values */
431 hy=(hy<0?0:hy>255?255:hy);
432
433 render_line(n,lx,hx,ly,hy,out);
434
435 lx=hx;
436 ly=hy;
437 }
438 }
439 for(j=hx;j<n;j++)out[j]*=ly; /* be certain */
440 return(1);
441 }
442 memset(out,0,sizeof(*out)*n);
443 return(0);
444 }
445
446 /* export hooks */
447 vorbis_func_floor floor1_exportbundle={
448 &floor1_unpack,&floor1_look,&floor1_free_info,
449 &floor1_free_look,&floor1_inverse1,&floor1_inverse2
450 };
451
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. *
3 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
4 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
5 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
6 * *
7 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 *
8 * by the Xiph.Org Foundation http://www.xiph.org/ *
9 * *
10 ********************************************************************
11
12 function: code raw packets into framed OggSquish stream and
13 decode Ogg streams back into raw packets
14 last mod: $Id: framing.c 18052 2011-08-04 17:57:02Z giles $
15
16 note: The CRC code is directly derived from public domain code by
17 Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html
18 for details.
19
20 ********************************************************************/
21
22 #include <stdlib.h>
23 #include <string.h>
24 #include "ogg.h"
25
26 /* A complete description of Ogg framing exists in docs/framing.html */
27
28 int ogg_page_version(const ogg_page *og){
29 return((int)(og->header[4]));
30 }
31
32 int ogg_page_continued(const ogg_page *og){
33 return((int)(og->header[5]&0x01));
34 }
35
36 int ogg_page_bos(const ogg_page *og){
37 return((int)(og->header[5]&0x02));
38 }
39
40 int ogg_page_eos(const ogg_page *og){
41 return((int)(og->header[5]&0x04));
42 }
43
44 ogg_int64_t ogg_page_granulepos(const ogg_page *og){
45 unsigned char *page=og->header;
46 ogg_int64_t granulepos=page[13]&(0xff);
47 granulepos= (granulepos<<8)|(page[12]&0xff);
48 granulepos= (granulepos<<8)|(page[11]&0xff);
49 granulepos= (granulepos<<8)|(page[10]&0xff);
50 granulepos= (granulepos<<8)|(page[9]&0xff);
51 granulepos= (granulepos<<8)|(page[8]&0xff);
52 granulepos= (granulepos<<8)|(page[7]&0xff);
53 granulepos= (granulepos<<8)|(page[6]&0xff);
54 return(granulepos);
55 }
56
57 int ogg_page_serialno(const ogg_page *og){
58 return(og->header[14] |
59 (og->header[15]<<8) |
60 (og->header[16]<<16) |
61 (og->header[17]<<24));
62 }
63
64 long ogg_page_pageno(const ogg_page *og){
65 return(og->header[18] |
66 (og->header[19]<<8) |
67 (og->header[20]<<16) |
68 (og->header[21]<<24));
69 }
70
71
72
73 /* returns the number of packets that are completed on this page (if
74 the leading packet is begun on a previous page, but ends on this
75 page, it's counted */
76
77 /* NOTE:
78 If a page consists of a packet begun on a previous page, and a new
79 packet begun (but not completed) on this page, the return will be:
80 ogg_page_packets(page) ==1,
81 ogg_page_continued(page) !=0
82
83 If a page happens to be a single packet that was begun on a
84 previous page, and spans to the next page (in the case of a three or
85 more page packet), the return will be:
86 ogg_page_packets(page) ==0,
87 ogg_page_continued(page) !=0
88 */
89
90 int ogg_page_packets(const ogg_page *og){
91 int i,n=og->header[26],count=0;
92 for(i=0;i<n;i++)
93 if(og->header[27+i]<255)count++;
94 return(count);
95 }
96
97
98 static const ogg_uint32_t crc_lookup[256]={
99 0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,
100 0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005,
101 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,
102 0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd,
103 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,
104 0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75,
105 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,
106 0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd,
107 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,
108 0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5,
109 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,
110 0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d,
111 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,
112 0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95,
113 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,
114 0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d,
115 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,
116 0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072,
117 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,
118 0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca,
119 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,
120 0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02,
121 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,
122 0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba,
123 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,
124 0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692,
125 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,
126 0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a,
127 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,
128 0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2,
129 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,
130 0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a,
131 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,
132 0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb,
133 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,
134 0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53,
135 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,
136 0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b,
137 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,
138 0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623,
139 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,
140 0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b,
141 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,
142 0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3,
143 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,
144 0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b,
145 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,
146 0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3,
147 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,
148 0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c,
149 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,
150 0x68860bfd,0x6c47164a,0x61043093,0x65c52d24,
151 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,
152 0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec,
153 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,
154 0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654,
155 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,
156 0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c,
157 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,
158 0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4,
159 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,
160 0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c,
161 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,
162 0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4};
163
164 /* init the encode/decode logical stream state */
165
166 int ogg_stream_init(ogg_stream_state *os,int serialno){
167 if(os){
168 memset(os,0,sizeof(*os));
169 os->body_storage=16*1024;
170 os->lacing_storage=1024;
171
172 os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data));
173 os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals));
174 os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals));
175
176 if(!os->body_data || !os->lacing_vals || !os->granule_vals){
177 ogg_stream_clear(os);
178 return -1;
179 }
180
181 os->serialno=serialno;
182
183 return(0);
184 }
185 return(-1);
186 }
187
188 /* async/delayed error detection for the ogg_stream_state */
189 int ogg_stream_check(ogg_stream_state *os){
190 if(!os || !os->body_data) return -1;
191 return 0;
192 }
193
194 /* _clear does not free os, only the non-flat storage within */
195 int ogg_stream_clear(ogg_stream_state *os){
196 if(os){
197 if(os->body_data)_ogg_free(os->body_data);
198 if(os->lacing_vals)_ogg_free(os->lacing_vals);
199 if(os->granule_vals)_ogg_free(os->granule_vals);
200
201 memset(os,0,sizeof(*os));
202 }
203 return(0);
204 }
205
206 int ogg_stream_destroy(ogg_stream_state *os){
207 if(os){
208 ogg_stream_clear(os);
209 _ogg_free(os);
210 }
211 return(0);
212 }
213
214 /* Helpers for ogg_stream_encode; this keeps the structure and
215 what's happening fairly clear */
216
217 static int _os_body_expand(ogg_stream_state *os,int needed){
218 if(os->body_storage<=os->body_fill+needed){
219 void *ret;
220 ret=_ogg_realloc(os->body_data,(os->body_storage+needed+1024)*
221 sizeof(*os->body_data));
222 if(!ret){
223 ogg_stream_clear(os);
224 return -1;
225 }
226 os->body_storage+=(needed+1024);
227 os->body_data=ret;
228 }
229 return 0;
230 }
231
232 static int _os_lacing_expand(ogg_stream_state *os,int needed){
233 if(os->lacing_storage<=os->lacing_fill+needed){
234 void *ret;
235 ret=_ogg_realloc(os->lacing_vals,(os->lacing_storage+needed+32)*
236 sizeof(*os->lacing_vals));
237 if(!ret){
238 ogg_stream_clear(os);
239 return -1;
240 }
241 os->lacing_vals=ret;
242 ret=_ogg_realloc(os->granule_vals,(os->lacing_storage+needed+32)*
243 sizeof(*os->granule_vals));
244 if(!ret){
245 ogg_stream_clear(os);
246 return -1;
247 }
248 os->granule_vals=ret;
249 os->lacing_storage+=(needed+32);
250 }
251 return 0;
252 }
253
254 /* checksum the page */
255 /* Direct table CRC; note that this will be faster in the future if we
256 perform the checksum simultaneously with other copies */
257
258 void ogg_page_checksum_set(ogg_page *og){
259 if(og){
260 ogg_uint32_t crc_reg=0;
261 int i;
262
263 /* safety; needed for API behavior, but not framing code */
264 og->header[22]=0;
265 og->header[23]=0;
266 og->header[24]=0;
267 og->header[25]=0;
268
269 for(i=0;i<og->header_len;i++)
270 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->header[i]];
271 for(i=0;i<og->body_len;i++)
272 crc_reg=(crc_reg<<8)^crc_lookup[((crc_reg >> 24)&0xff)^og->body[i]];
273
274 og->header[22]=(unsigned char)(crc_reg&0xff);
275 og->header[23]=(unsigned char)((crc_reg>>8)&0xff);
276 og->header[24]=(unsigned char)((crc_reg>>16)&0xff);
277 og->header[25]=(unsigned char)((crc_reg>>24)&0xff);
278 }
279 }
280
281 /* submit data to the internal buffer of the framing engine */
282 int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count,
283 long e_o_s, ogg_int64_t granulepos){
284
285 int bytes = 0, lacing_vals, i;
286
287 if(ogg_stream_check(os)) return -1;
288 if(!iov) return 0;
289
290 for (i = 0; i < count; ++i) bytes += (int)iov[i].iov_len;
291 lacing_vals=bytes/255+1;
292
293 if(os->body_returned){
294 /* advance packet data according to the body_returned pointer. We
295 had to keep it around to return a pointer into the buffer last
296 call */
297
298 os->body_fill-=os->body_returned;
299 if(os->body_fill)
300 memmove(os->body_data,os->body_data+os->body_returned,
301 os->body_fill);
302 os->body_returned=0;
303 }
304
305 /* make sure we have the buffer storage */
306 if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals))
307 return -1;
308
309 /* Copy in the submitted packet. Yes, the copy is a waste; this is
310 the liability of overly clean abstraction for the time being. It
311 will actually be fairly easy to eliminate the extra copy in the
312 future */
313
314 for (i = 0; i < count; ++i) {
315 memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len);
316 os->body_fill += (int)iov[i].iov_len;
317 }
318
319 /* Store lacing vals for this packet */
320 for(i=0;i<lacing_vals-1;i++){
321 os->lacing_vals[os->lacing_fill+i]=255;
322 os->granule_vals[os->lacing_fill+i]=os->granulepos;
323 }
324 os->lacing_vals[os->lacing_fill+i]=bytes%255;
325 os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos;
326
327 /* flag the first segment as the beginning of the packet */
328 os->lacing_vals[os->lacing_fill]|= 0x100;
329
330 os->lacing_fill+=lacing_vals;
331
332 /* for the sake of completeness */
333 os->packetno++;
334
335 if(e_o_s)os->e_o_s=1;
336
337 return(0);
338 }
339
340 int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){
341 ogg_iovec_t iov;
342 iov.iov_base = op->packet;
343 iov.iov_len = op->bytes;
344 return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos);
345 }
346
347 /* Conditionally flush a page; force==0 will only flush nominal-size
348 pages, force==1 forces us to flush a page regardless of page size
349 so long as there's any data available at all. */
350 static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){
351 int i;
352 int vals=0;
353 int maxvals=(os->lacing_fill>255?255:os->lacing_fill);
354 int bytes=0;
355 long acc=0;
356 ogg_int64_t granule_pos=-1;
357
358 if(ogg_stream_check(os)) return(0);
359 if(maxvals==0) return(0);
360
361 /* construct a page */
362 /* decide how many segments to include */
363
364 /* If this is the initial header case, the first page must only include
365 the initial header packet */
366 if(os->b_o_s==0){ /* 'initial header page' case */
367 granule_pos=0;
368 for(vals=0;vals<maxvals;vals++){
369 if((os->lacing_vals[vals]&0x0ff)<255){
370 vals++;
371 break;
372 }
373 }
374 }else{
375
376 /* The extra packets_done, packet_just_done logic here attempts to do two things:
377 1) Don't unneccessarily span pages.
378 2) Unless necessary, don't flush pages if there are less than four packets on
379 them; this expands page size to reduce unneccessary overhead if incoming packets
380 are large.
381 These are not necessary behaviors, just 'always better than naive flushing'
382 without requiring an application to explicitly request a specific optimized
383 behavior. We'll want an explicit behavior setup pathway eventually as well. */
384
385 int packets_done=0;
386 int packet_just_done=0;
387 for(vals=0;vals<maxvals;vals++){
388 if(acc>nfill && packet_just_done>=4){
389 force=1;
390 break;
391 }
392 acc+=os->lacing_vals[vals]&0x0ff;
393 if((os->lacing_vals[vals]&0xff)<255){
394 granule_pos=os->granule_vals[vals];
395 packet_just_done=++packets_done;
396 }else
397 packet_just_done=0;
398 }
399 if(vals==255)force=1;
400 }
401
402 if(!force) return(0);
403
404 /* construct the header in temp storage */
405 memcpy(os->header,"OggS",4);
406
407 /* stream structure version */
408 os->header[4]=0x00;
409
410 /* continued packet flag? */
411 os->header[5]=0x00;
412 if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01;
413 /* first page flag? */
414 if(os->b_o_s==0)os->header[5]|=0x02;
415 /* last page flag? */
416 if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04;
417 os->b_o_s=1;
418
419 /* 64 bits of PCM position */
420 for(i=6;i<14;i++){
421 os->header[i]=(unsigned char)(granule_pos&0xff);
422 granule_pos>>=8;
423 }
424
425 /* 32 bits of stream serial number */
426 {
427 long serialno=os->serialno;
428 for(i=14;i<18;i++){
429 os->header[i]=(unsigned char)(serialno&0xff);
430 serialno>>=8;
431 }
432 }
433
434 /* 32 bits of page counter (we have both counter and page header
435 because this val can roll over) */
436 if(os->pageno==-1)os->pageno=0; /* because someone called
437 stream_reset; this would be a
438 strange thing to do in an
439 encode stream, but it has
440 plausible uses */
441 {
442 long pageno=os->pageno++;
443 for(i=18;i<22;i++){
444 os->header[i]=(unsigned char)(pageno&0xff);
445 pageno>>=8;
446 }
447 }
448
449 /* zero for computation; filled in later */
450 os->header[22]=0;
451 os->header[23]=0;
452 os->header[24]=0;
453 os->header[25]=0;
454
455 /* segment table */
456 os->header[26]=(unsigned char)(vals&0xff);
457 for(i=0;i<vals;i++)
458 bytes+=os->header[i+27]=(unsigned char)(os->lacing_vals[i]&0xff);
459
460 /* set pointers in the ogg_page struct */
461 og->header=os->header;
462 og->header_len=os->header_fill=vals+27;
463 og->body=os->body_data+os->body_returned;
464 og->body_len=bytes;
465
466 /* advance the lacing data and set the body_returned pointer */
467
468 os->lacing_fill-=vals;
469 memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals));
470 memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals));
471 os->body_returned+=bytes;
472
473 /* calculate the checksum */
474
475 ogg_page_checksum_set(og);
476
477 /* done */
478 return(1);
479 }
480
481 /* This will flush remaining packets into a page (returning nonzero),
482 even if there is not enough data to trigger a flush normally
483 (undersized page). If there are no packets or partial packets to
484 flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will
485 try to flush a normal sized page like ogg_stream_pageout; a call to
486 ogg_stream_flush does not guarantee that all packets have flushed.
487 Only a return value of 0 from ogg_stream_flush indicates all packet
488 data is flushed into pages.
489
490 since ogg_stream_flush will flush the last page in a stream even if
491 it's undersized, you almost certainly want to use ogg_stream_pageout
492 (and *not* ogg_stream_flush) unless you specifically need to flush
493 a page regardless of size in the middle of a stream. */
494
495 int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){
496 return ogg_stream_flush_i(os,og,1,4096);
497 }
498
499 /* Like the above, but an argument is provided to adjust the nominal
500 page size for applications which are smart enough to provide their
501 own delay based flushing */
502
503 int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){
504 return ogg_stream_flush_i(os,og,1,nfill);
505 }
506
507 /* This constructs pages from buffered packet segments. The pointers
508 returned are to static buffers; do not free. The returned buffers are
509 good only until the next call (using the same ogg_stream_state) */
510
511 int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){
512 int force=0;
513 if(ogg_stream_check(os)) return 0;
514
515 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
516 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
517 force=1;
518
519 return(ogg_stream_flush_i(os,og,force,4096));
520 }
521
522 /* Like the above, but an argument is provided to adjust the nominal
523 page size for applications which are smart enough to provide their
524 own delay based flushing */
525
526 int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){
527 int force=0;
528 if(ogg_stream_check(os)) return 0;
529
530 if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */
531 (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */
532 force=1;
533
534 return(ogg_stream_flush_i(os,og,force,nfill));
535 }
536
537 int ogg_stream_eos(ogg_stream_state *os){
538 if(ogg_stream_check(os)) return 1;
539 return os->e_o_s;
540 }
541
542 /* DECODING PRIMITIVES: packet streaming layer **********************/
543
544 /* This has two layers to place more of the multi-serialno and paging
545 control in the application's hands. First, we expose a data buffer
546 using ogg_sync_buffer(). The app either copies into the
547 buffer, or passes it directly to read(), etc. We then call
548 ogg_sync_wrote() to tell how many bytes we just added.
549
550 Pages are returned (pointers into the buffer in ogg_sync_state)
551 by ogg_sync_pageout(). The page is then submitted to
552 ogg_stream_pagein() along with the appropriate
553 ogg_stream_state* (ie, matching serialno). We then get raw
554 packets out calling ogg_stream_packetout() with a
555 ogg_stream_state. */
556
557 /* initialize the struct to a known state */
558 int ogg_sync_init(ogg_sync_state *oy){
559 if(oy){
560 oy->storage = -1; /* used as a readiness flag */
561 memset(oy,0,sizeof(*oy));
562 }
563 return(0);
564 }
565
566 /* clear non-flat storage within */
567 int ogg_sync_clear(ogg_sync_state *oy){
568 if(oy){
569 if(oy->data)_ogg_free(oy->data);
570 memset(oy,0,sizeof(*oy));
571 }
572 return(0);
573 }
574
575 int ogg_sync_destroy(ogg_sync_state *oy){
576 if(oy){
577 ogg_sync_clear(oy);
578 _ogg_free(oy);
579 }
580 return(0);
581 }
582
583 int ogg_sync_check(ogg_sync_state *oy){
584 if(oy->storage<0) return -1;
585 return 0;
586 }
587
588 char *ogg_sync_buffer(ogg_sync_state *oy, long size){
589 if(ogg_sync_check(oy)) return NULL;
590
591 /* first, clear out any space that has been previously returned */
592 if(oy->returned){
593 oy->fill-=oy->returned;
594 if(oy->fill>0)
595 memmove(oy->data,oy->data+oy->returned,oy->fill);
596 oy->returned=0;
597 }
598
599 if(size>oy->storage-oy->fill){
600 /* We need to extend the internal buffer */
601 long newsize=size+oy->fill+4096; /* an extra page to be nice */
602 void *ret;
603
604 if(oy->data)
605 ret=_ogg_realloc(oy->data,newsize);
606 else
607 ret=_ogg_malloc(newsize);
608 if(!ret){
609 ogg_sync_clear(oy);
610 return NULL;
611 }
612 oy->data=ret;
613 oy->storage=newsize;
614 }
615
616 /* expose a segment at least as large as requested at the fill mark */
617 return((char *)oy->data+oy->fill);
618 }
619
620 int ogg_sync_wrote(ogg_sync_state *oy, long bytes){
621 if(ogg_sync_check(oy))return -1;
622 if(oy->fill+bytes>oy->storage)return -1;
623 oy->fill+=bytes;
624 return(0);
625 }
626
627 /* sync the stream. This is meant to be useful for finding page
628 boundaries.
629
630 return values for this:
631 -n) skipped n bytes
632 0) page not ready; more data (no bytes skipped)
633 n) page synced at current location; page length n bytes
634
635 */
636
637 long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){
638 unsigned char *page=oy->data+oy->returned;
639 unsigned char *next;
640 long bytes=oy->fill-oy->returned;
641
642 if(ogg_sync_check(oy))return 0;
643
644 if(oy->headerbytes==0){
645 int headerbytes,i;
646 if(bytes<27)return(0); /* not enough for a header */
647
648 /* verify capture pattern */
649 if(memcmp(page,"OggS",4))goto sync_fail;
650
651 headerbytes=page[26]+27;
652 if(bytes<headerbytes)return(0); /* not enough for header + seg table */
653
654 /* count up body length in the segment table */
655
656 for(i=0;i<page[26];i++)
657 oy->bodybytes+=page[27+i];
658 oy->headerbytes=headerbytes;
659 }
660
661 if(oy->bodybytes+oy->headerbytes>bytes)return(0);
662
663 /* The whole test page is buffered. Verify the checksum */
664 {
665 /* Grab the checksum bytes, set the header field to zero */
666 char chksum[4];
667 ogg_page log;
668
669 memcpy(chksum,page+22,4);
670 memset(page+22,0,4);
671
672 /* set up a temp page struct and recompute the checksum */
673 log.header=page;
674 log.header_len=oy->headerbytes;
675 log.body=page+oy->headerbytes;
676 log.body_len=oy->bodybytes;
677 ogg_page_checksum_set(&log);
678
679 /* Compare */
680 if(memcmp(chksum,page+22,4)){
681 /* D'oh. Mismatch! Corrupt page (or miscapture and not a page
682 at all) */
683 /* replace the computed checksum with the one actually read in */
684 memcpy(page+22,chksum,4);
685
686 /* Bad checksum. Lose sync */
687 goto sync_fail;
688 }
689 }
690
691 /* yes, have a whole page all ready to go */
692 {
693 unsigned char *page=oy->data+oy->returned;
694 long bytes;
695
696 if(og){
697 og->header=page;
698 og->header_len=oy->headerbytes;
699 og->body=page+oy->headerbytes;
700 og->body_len=oy->bodybytes;
701 }
702
703 oy->unsynced=0;
704 oy->returned+=(bytes=oy->headerbytes+oy->bodybytes);
705 oy->headerbytes=0;
706 oy->bodybytes=0;
707 return(bytes);
708 }
709
710 sync_fail:
711
712 oy->headerbytes=0;
713 oy->bodybytes=0;
714
715 /* search for possible capture */
716 next=memchr(page+1,'O',bytes-1);
717 if(!next)
718 next=oy->data+oy->fill;
719
720 oy->returned=(int)(next-oy->data);
721 return((long)-(next-page));
722 }
723
724 /* sync the stream and get a page. Keep trying until we find a page.
725 Suppress 'sync errors' after reporting the first.
726
727 return values:
728 -1) recapture (hole in data)
729 0) need more data
730 1) page returned
731
732 Returns pointers into buffered data; invalidated by next call to
733 _stream, _clear, _init, or _buffer */
734
735 int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){
736
737 if(ogg_sync_check(oy))return 0;
738
739 /* all we need to do is verify a page at the head of the stream
740 buffer. If it doesn't verify, we look for the next potential
741 frame */
742
743 for(;;){
744 long ret=ogg_sync_pageseek(oy,og);
745 if(ret>0){
746 /* have a page */
747 return(1);
748 }
749 if(ret==0){
750 /* need more data */
751 return(0);
752 }
753
754 /* head did not start a synced page... skipped some bytes */
755 if(!oy->unsynced){
756 oy->unsynced=1;
757 return(-1);
758 }
759
760 /* loop. keep looking */
761
762 }
763 }
764
765 /* add the incoming page to the stream state; we decompose the page
766 into packet segments here as well. */
767
768 int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){
769 unsigned char *header=og->header;
770 unsigned char *body=og->body;
771 long bodysize=og->body_len;
772 int segptr=0;
773
774 int version=ogg_page_version(og);
775 int continued=ogg_page_continued(og);
776 int bos=ogg_page_bos(og);
777 int eos=ogg_page_eos(og);
778 ogg_int64_t granulepos=ogg_page_granulepos(og);
779 int serialno=ogg_page_serialno(og);
780 long pageno=ogg_page_pageno(og);
781 int segments=header[26];
782
783 if(ogg_stream_check(os)) return -1;
784
785 /* clean up 'returned data' */
786 {
787 long lr=os->lacing_returned;
788 long br=os->body_returned;
789
790 /* body data */
791 if(br){
792 os->body_fill-=br;
793 if(os->body_fill)
794 memmove(os->body_data,os->body_data+br,os->body_fill);
795 os->body_returned=0;
796 }
797
798 if(lr){
799 /* segment table */
800 if(os->lacing_fill-lr){
801 memmove(os->lacing_vals,os->lacing_vals+lr,
802 (os->lacing_fill-lr)*sizeof(*os->lacing_vals));
803 memmove(os->granule_vals,os->granule_vals+lr,
804 (os->lacing_fill-lr)*sizeof(*os->granule_vals));
805 }
806 os->lacing_fill-=lr;
807 os->lacing_packet-=lr;
808 os->lacing_returned=0;
809 }
810 }
811
812 /* check the serial number */
813 if(serialno!=os->serialno)return(-1);
814 if(version>0)return(-1);
815
816 if(_os_lacing_expand(os,segments+1)) return -1;
817
818 /* are we in sequence? */
819 if(pageno!=os->pageno){
820 int i;
821
822 /* unroll previous partial packet (if any) */
823 for(i=os->lacing_packet;i<os->lacing_fill;i++)
824 os->body_fill-=os->lacing_vals[i]&0xff;
825 os->lacing_fill=os->lacing_packet;
826
827 /* make a note of dropped data in segment table */
828 if(os->pageno!=-1){
829 os->lacing_vals[os->lacing_fill++]=0x400;
830 os->lacing_packet++;
831 }
832 }
833
834 /* are we a 'continued packet' page? If so, we may need to skip
835 some segments */
836 if(continued){
837 if(os->lacing_fill<1 ||
838 os->lacing_vals[os->lacing_fill-1]==0x400){
839 bos=0;
840 for(;segptr<segments;segptr++){
841 int val=header[27+segptr];
842 body+=val;
843 bodysize-=val;
844 if(val<255){
845 segptr++;
846 break;
847 }
848 }
849 }
850 }
851
852 if(bodysize){
853 if(_os_body_expand(os,bodysize)) return -1;
854 memcpy(os->body_data+os->body_fill,body,bodysize);
855 os->body_fill+=bodysize;
856 }
857
858 {
859 int saved=-1;
860 while(segptr<segments){
861 int val=header[27+segptr];
862 os->lacing_vals[os->lacing_fill]=val;
863 os->granule_vals[os->lacing_fill]=-1;
864
865 if(bos){
866 os->lacing_vals[os->lacing_fill]|=0x100;
867 bos=0;
868 }
869
870 if(val<255)saved=os->lacing_fill;
871
872 os->lacing_fill++;
873 segptr++;
874
875 if(val<255)os->lacing_packet=os->lacing_fill;
876 }
877
878 /* set the granulepos on the last granuleval of the last full packet */
879 if(saved!=-1){
880 os->granule_vals[saved]=granulepos;
881 }
882
883 }
884
885 if(eos){
886 os->e_o_s=1;
887 if(os->lacing_fill>0)
888 os->lacing_vals[os->lacing_fill-1]|=0x200;
889 }
890
891 os->pageno=pageno+1;
892
893 return(0);
894 }
895
896 /* clear things to an initial state. Good to call, eg, before seeking */
897 int ogg_sync_reset(ogg_sync_state *oy){
898 if(ogg_sync_check(oy))return -1;
899
900 oy->fill=0;
901 oy->returned=0;
902 oy->unsynced=0;
903 oy->headerbytes=0;
904 oy->bodybytes=0;
905 return(0);
906 }
907
908 int ogg_stream_reset(ogg_stream_state *os){
909 if(ogg_stream_check(os)) return -1;
910
911 os->body_fill=0;
912 os->body_returned=0;
913
914 os->lacing_fill=0;
915 os->lacing_packet=0;
916 os->lacing_returned=0;
917
918 os->header_fill=0;
919
920 os->e_o_s=0;
921 os->b_o_s=0;
922 os->pageno=-1;
923 os->packetno=0;
924 os->granulepos=0;
925
926 return(0);
927 }
928
929 int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){
930 if(ogg_stream_check(os)) return -1;
931 ogg_stream_reset(os);
932 os->serialno=serialno;
933 return(0);
934 }
935
936 static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){
937
938 /* The last part of decode. We have the stream broken into packet
939 segments. Now we need to group them into packets (or return the
940 out of sync markers) */
941
942 int ptr=os->lacing_returned;
943
944 if(os->lacing_packet<=ptr)return(0);
945
946 if(os->lacing_vals[ptr]&0x400){
947 /* we need to tell the codec there's a gap; it might need to
948 handle previous packet dependencies. */
949 os->lacing_returned++;
950 os->packetno++;
951 return(-1);
952 }
953
954 if(!op && !adv)return(1); /* just using peek as an inexpensive way
955 to ask if there's a whole packet
956 waiting */
957
958 /* Gather the whole packet. We'll have no holes or a partial packet */
959 {
960 int size=os->lacing_vals[ptr]&0xff;
961 long bytes=size;
962 int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */
963 int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */
964
965 while(size==255){
966 int val=os->lacing_vals[++ptr];
967 size=val&0xff;
968 if(val&0x200)eos=0x200;
969 bytes+=size;
970 }
971
972 if(op){
973 op->e_o_s=eos;
974 op->b_o_s=bos;
975 op->packet=os->body_data+os->body_returned;
976 op->packetno=os->packetno;
977 op->granulepos=os->granule_vals[ptr];
978 op->bytes=bytes;
979 }
980
981 if(adv){
982 os->body_returned+=bytes;
983 os->lacing_returned=ptr+1;
984 os->packetno++;
985 }
986 }
987 return(1);
988 }
989
990 int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){
991 if(ogg_stream_check(os)) return 0;
992 return _packetout(os,op,1);
993 }
994
995 int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){
996 if(ogg_stream_check(os)) return 0;
997 return _packetout(os,op,0);
998 }
999
1000 void ogg_packet_clear(ogg_packet *op) {
1001 _ogg_free(op->packet);
1002 memset(op, 0, sizeof(*op));
1003 }
1004
1005 #ifdef _V_SELFTEST
1006 #include <stdio.h>
1007
1008 ogg_stream_state os_en, os_de;
1009 ogg_sync_state oy;
1010
1011 void checkpacket(ogg_packet *op,long len, int no, long pos){
1012 long j;
1013 static int sequence=0;
1014 static int lastno=0;
1015
1016 if(op->bytes!=len){
1017 fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len);
1018 exit(1);
1019 }
1020 if(op->granulepos!=pos){
1021 fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos);
1022 exit(1);
1023 }
1024
1025 /* packet number just follows sequence/gap; adjust the input number
1026 for that */
1027 if(no==0){
1028 sequence=0;
1029 }else{
1030 sequence++;
1031 if(no>lastno+1)
1032 sequence++;
1033 }
1034 lastno=no;
1035 if(op->packetno!=sequence){
1036 fprintf(stderr,"incorrect packet sequence %ld != %d\n",
1037 (long)(op->packetno),sequence);
1038 exit(1);
1039 }
1040
1041 /* Test data */
1042 for(j=0;j<op->bytes;j++)
1043 if(op->packet[j]!=((j+no)&0xff)){
1044 fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n",
1045 j,op->packet[j],(j+no)&0xff);
1046 exit(1);
1047 }
1048 }
1049
1050 void check_page(unsigned char *data,const int *header,ogg_page *og){
1051 long j;
1052 /* Test data */
1053 for(j=0;j<og->body_len;j++)
1054 if(og->body[j]!=data[j]){
1055 fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n",
1056 j,data[j],og->body[j]);
1057 exit(1);
1058 }
1059
1060 /* Test header */
1061 for(j=0;j<og->header_len;j++){
1062 if(og->header[j]!=header[j]){
1063 fprintf(stderr,"header content mismatch at pos %ld:\n",j);
1064 for(j=0;j<header[26]+27;j++)
1065 fprintf(stderr," (%ld)%02x:%02x",j,header[j],og->header[j]);
1066 fprintf(stderr,"\n");
1067 exit(1);
1068 }
1069 }
1070 if(og->header_len!=header[26]+27){
1071 fprintf(stderr,"header length incorrect! (%ld!=%d)\n",
1072 og->header_len,header[26]+27);
1073 exit(1);
1074 }
1075 }
1076
1077 void print_header(ogg_page *og){
1078 int j;
1079 fprintf(stderr,"\nHEADER:\n");
1080 fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n",
1081 og->header[0],og->header[1],og->header[2],og->header[3],
1082 (int)og->header[4],(int)og->header[5]);
1083
1084 fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n",
1085 (og->header[9]<<24)|(og->header[8]<<16)|
1086 (og->header[7]<<8)|og->header[6],
1087 (og->header[17]<<24)|(og->header[16]<<16)|
1088 (og->header[15]<<8)|og->header[14],
1089 ((long)(og->header[21])<<24)|(og->header[20]<<16)|
1090 (og->header[19]<<8)|og->header[18]);
1091
1092 fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (",
1093 (int)og->header[22],(int)og->header[23],
1094 (int)og->header[24],(int)og->header[25],
1095 (int)og->header[26]);
1096
1097 for(j=27;j<og->header_len;j++)
1098 fprintf(stderr,"%d ",(int)og->header[j]);
1099 fprintf(stderr,")\n\n");
1100 }
1101
1102 void copy_page(ogg_page *og){
1103 unsigned char *temp=_ogg_malloc(og->header_len);
1104 memcpy(temp,og->header,og->header_len);
1105 og->header=temp;
1106
1107 temp=_ogg_malloc(og->body_len);
1108 memcpy(temp,og->body,og->body_len);
1109 og->body=temp;
1110 }
1111
1112 void free_page(ogg_page *og){
1113 _ogg_free (og->header);
1114 _ogg_free (og->body);
1115 }
1116
1117 void error(void){
1118 fprintf(stderr,"error!\n");
1119 exit(1);
1120 }
1121
1122 /* 17 only */
1123 const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06,
1124 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1125 0x01,0x02,0x03,0x04,0,0,0,0,
1126 0x15,0xed,0xec,0x91,
1127 1,
1128 17};
1129
1130 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1131 const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02,
1132 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1133 0x01,0x02,0x03,0x04,0,0,0,0,
1134 0x59,0x10,0x6c,0x2c,
1135 1,
1136 17};
1137 const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04,
1138 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00,
1139 0x01,0x02,0x03,0x04,1,0,0,0,
1140 0x89,0x33,0x85,0xce,
1141 13,
1142 254,255,0,255,1,255,245,255,255,0,
1143 255,255,90};
1144
1145 /* nil packets; beginning,middle,end */
1146 const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02,
1147 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1148 0x01,0x02,0x03,0x04,0,0,0,0,
1149 0xff,0x7b,0x23,0x17,
1150 1,
1151 0};
1152 const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04,
1153 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00,
1154 0x01,0x02,0x03,0x04,1,0,0,0,
1155 0x5c,0x3f,0x66,0xcb,
1156 17,
1157 17,254,255,0,0,255,1,0,255,245,255,255,0,
1158 255,255,90,0};
1159
1160 /* large initial packet */
1161 const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02,
1162 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1163 0x01,0x02,0x03,0x04,0,0,0,0,
1164 0x01,0x27,0x31,0xaa,
1165 18,
1166 255,255,255,255,255,255,255,255,
1167 255,255,255,255,255,255,255,255,255,10};
1168
1169 const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04,
1170 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1171 0x01,0x02,0x03,0x04,1,0,0,0,
1172 0x7f,0x4e,0x8a,0xd2,
1173 4,
1174 255,4,255,0};
1175
1176
1177 /* continuing packet test */
1178 const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02,
1179 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1180 0x01,0x02,0x03,0x04,0,0,0,0,
1181 0xff,0x7b,0x23,0x17,
1182 1,
1183 0};
1184
1185 const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00,
1186 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1187 0x01,0x02,0x03,0x04,1,0,0,0,
1188 0xf8,0x3c,0x19,0x79,
1189 255,
1190 255,255,255,255,255,255,255,255,
1191 255,255,255,255,255,255,255,255,
1192 255,255,255,255,255,255,255,255,
1193 255,255,255,255,255,255,255,255,
1194 255,255,255,255,255,255,255,255,
1195 255,255,255,255,255,255,255,255,
1196 255,255,255,255,255,255,255,255,
1197 255,255,255,255,255,255,255,255,
1198 255,255,255,255,255,255,255,255,
1199 255,255,255,255,255,255,255,255,
1200 255,255,255,255,255,255,255,255,
1201 255,255,255,255,255,255,255,255,
1202 255,255,255,255,255,255,255,255,
1203 255,255,255,255,255,255,255,255,
1204 255,255,255,255,255,255,255,255,
1205 255,255,255,255,255,255,255,255,
1206 255,255,255,255,255,255,255,255,
1207 255,255,255,255,255,255,255,255,
1208 255,255,255,255,255,255,255,255,
1209 255,255,255,255,255,255,255,255,
1210 255,255,255,255,255,255,255,255,
1211 255,255,255,255,255,255,255,255,
1212 255,255,255,255,255,255,255,255,
1213 255,255,255,255,255,255,255,255,
1214 255,255,255,255,255,255,255,255,
1215 255,255,255,255,255,255,255,255,
1216 255,255,255,255,255,255,255,255,
1217 255,255,255,255,255,255,255,255,
1218 255,255,255,255,255,255,255,255,
1219 255,255,255,255,255,255,255,255,
1220 255,255,255,255,255,255,255,255,
1221 255,255,255,255,255,255,255};
1222
1223 const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05,
1224 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00,
1225 0x01,0x02,0x03,0x04,2,0,0,0,
1226 0x38,0xe6,0xb6,0x28,
1227 6,
1228 255,220,255,4,255,0};
1229
1230
1231 /* spill expansion test */
1232 const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02,
1233 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1234 0x01,0x02,0x03,0x04,0,0,0,0,
1235 0xff,0x7b,0x23,0x17,
1236 1,
1237 0};
1238
1239 const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00,
1240 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1241 0x01,0x02,0x03,0x04,1,0,0,0,
1242 0xce,0x8f,0x17,0x1a,
1243 23,
1244 255,255,255,255,255,255,255,255,
1245 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0};
1246
1247
1248 const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04,
1249 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00,
1250 0x01,0x02,0x03,0x04,2,0,0,0,
1251 0x9b,0xb2,0x50,0xa1,
1252 1,
1253 0};
1254
1255 /* page with the 255 segment limit */
1256 const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02,
1257 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1258 0x01,0x02,0x03,0x04,0,0,0,0,
1259 0xff,0x7b,0x23,0x17,
1260 1,
1261 0};
1262
1263 const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00,
1264 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00,
1265 0x01,0x02,0x03,0x04,1,0,0,0,
1266 0xed,0x2a,0x2e,0xa7,
1267 255,
1268 10,10,10,10,10,10,10,10,
1269 10,10,10,10,10,10,10,10,
1270 10,10,10,10,10,10,10,10,
1271 10,10,10,10,10,10,10,10,
1272 10,10,10,10,10,10,10,10,
1273 10,10,10,10,10,10,10,10,
1274 10,10,10,10,10,10,10,10,
1275 10,10,10,10,10,10,10,10,
1276 10,10,10,10,10,10,10,10,
1277 10,10,10,10,10,10,10,10,
1278 10,10,10,10,10,10,10,10,
1279 10,10,10,10,10,10,10,10,
1280 10,10,10,10,10,10,10,10,
1281 10,10,10,10,10,10,10,10,
1282 10,10,10,10,10,10,10,10,
1283 10,10,10,10,10,10,10,10,
1284 10,10,10,10,10,10,10,10,
1285 10,10,10,10,10,10,10,10,
1286 10,10,10,10,10,10,10,10,
1287 10,10,10,10,10,10,10,10,
1288 10,10,10,10,10,10,10,10,
1289 10,10,10,10,10,10,10,10,
1290 10,10,10,10,10,10,10,10,
1291 10,10,10,10,10,10,10,10,
1292 10,10,10,10,10,10,10,10,
1293 10,10,10,10,10,10,10,10,
1294 10,10,10,10,10,10,10,10,
1295 10,10,10,10,10,10,10,10,
1296 10,10,10,10,10,10,10,10,
1297 10,10,10,10,10,10,10,10,
1298 10,10,10,10,10,10,10,10,
1299 10,10,10,10,10,10,10};
1300
1301 const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04,
1302 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00,
1303 0x01,0x02,0x03,0x04,2,0,0,0,
1304 0x6c,0x3b,0x82,0x3d,
1305 1,
1306 50};
1307
1308
1309 /* packet that overspans over an entire page */
1310 const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02,
1311 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1312 0x01,0x02,0x03,0x04,0,0,0,0,
1313 0xff,0x7b,0x23,0x17,
1314 1,
1315 0};
1316
1317 const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00,
1318 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1319 0x01,0x02,0x03,0x04,1,0,0,0,
1320 0x68,0x22,0x7c,0x3d,
1321 255,
1322 100,
1323 255,255,255,255,255,255,255,255,
1324 255,255,255,255,255,255,255,255,
1325 255,255,255,255,255,255,255,255,
1326 255,255,255,255,255,255,255,255,
1327 255,255,255,255,255,255,255,255,
1328 255,255,255,255,255,255,255,255,
1329 255,255,255,255,255,255,255,255,
1330 255,255,255,255,255,255,255,255,
1331 255,255,255,255,255,255,255,255,
1332 255,255,255,255,255,255,255,255,
1333 255,255,255,255,255,255,255,255,
1334 255,255,255,255,255,255,255,255,
1335 255,255,255,255,255,255,255,255,
1336 255,255,255,255,255,255,255,255,
1337 255,255,255,255,255,255,255,255,
1338 255,255,255,255,255,255,255,255,
1339 255,255,255,255,255,255,255,255,
1340 255,255,255,255,255,255,255,255,
1341 255,255,255,255,255,255,255,255,
1342 255,255,255,255,255,255,255,255,
1343 255,255,255,255,255,255,255,255,
1344 255,255,255,255,255,255,255,255,
1345 255,255,255,255,255,255,255,255,
1346 255,255,255,255,255,255,255,255,
1347 255,255,255,255,255,255,255,255,
1348 255,255,255,255,255,255,255,255,
1349 255,255,255,255,255,255,255,255,
1350 255,255,255,255,255,255,255,255,
1351 255,255,255,255,255,255,255,255,
1352 255,255,255,255,255,255,255,255,
1353 255,255,255,255,255,255,255,255,
1354 255,255,255,255,255,255};
1355
1356 const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01,
1357 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
1358 0x01,0x02,0x03,0x04,2,0,0,0,
1359 0xf4,0x87,0xba,0xf3,
1360 255,
1361 255,255,255,255,255,255,255,255,
1362 255,255,255,255,255,255,255,255,
1363 255,255,255,255,255,255,255,255,
1364 255,255,255,255,255,255,255,255,
1365 255,255,255,255,255,255,255,255,
1366 255,255,255,255,255,255,255,255,
1367 255,255,255,255,255,255,255,255,
1368 255,255,255,255,255,255,255,255,
1369 255,255,255,255,255,255,255,255,
1370 255,255,255,255,255,255,255,255,
1371 255,255,255,255,255,255,255,255,
1372 255,255,255,255,255,255,255,255,
1373 255,255,255,255,255,255,255,255,
1374 255,255,255,255,255,255,255,255,
1375 255,255,255,255,255,255,255,255,
1376 255,255,255,255,255,255,255,255,
1377 255,255,255,255,255,255,255,255,
1378 255,255,255,255,255,255,255,255,
1379 255,255,255,255,255,255,255,255,
1380 255,255,255,255,255,255,255,255,
1381 255,255,255,255,255,255,255,255,
1382 255,255,255,255,255,255,255,255,
1383 255,255,255,255,255,255,255,255,
1384 255,255,255,255,255,255,255,255,
1385 255,255,255,255,255,255,255,255,
1386 255,255,255,255,255,255,255,255,
1387 255,255,255,255,255,255,255,255,
1388 255,255,255,255,255,255,255,255,
1389 255,255,255,255,255,255,255,255,
1390 255,255,255,255,255,255,255,255,
1391 255,255,255,255,255,255,255,255,
1392 255,255,255,255,255,255,255};
1393
1394 const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05,
1395 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
1396 0x01,0x02,0x03,0x04,3,0,0,0,
1397 0xf7,0x2f,0x6c,0x60,
1398 5,
1399 254,255,4,255,0};
1400
1401 /* packet that overspans over an entire page */
1402 const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02,
1403 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
1404 0x01,0x02,0x03,0x04,0,0,0,0,
1405 0xff,0x7b,0x23,0x17,
1406 1,
1407 0};
1408
1409 const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00,
1410 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00,
1411 0x01,0x02,0x03,0x04,1,0,0,0,
1412 0x68,0x22,0x7c,0x3d,
1413 255,
1414 100,
1415 255,255,255,255,255,255,255,255,
1416 255,255,255,255,255,255,255,255,
1417 255,255,255,255,255,255,255,255,
1418 255,255,255,255,255,255,255,255,
1419 255,255,255,255,255,255,255,255,
1420 255,255,255,255,255,255,255,255,
1421 255,255,255,255,255,255,255,255,
1422 255,255,255,255,255,255,255,255,
1423 255,255,255,255,255,255,255,255,
1424 255,255,255,255,255,255,255,255,
1425 255,255,255,255,255,255,255,255,
1426 255,255,255,255,255,255,255,255,
1427 255,255,255,255,255,255,255,255,
1428 255,255,255,255,255,255,255,255,
1429 255,255,255,255,255,255,255,255,
1430 255,255,255,255,255,255,255,255,
1431 255,255,255,255,255,255,255,255,
1432 255,255,255,255,255,255,255,255,
1433 255,255,255,255,255,255,255,255,
1434 255,255,255,255,255,255,255,255,
1435 255,255,255,255,255,255,255,255,
1436 255,255,255,255,255,255,255,255,
1437 255,255,255,255,255,255,255,255,
1438 255,255,255,255,255,255,255,255,
1439 255,255,255,255,255,255,255,255,
1440 255,255,255,255,255,255,255,255,
1441 255,255,255,255,255,255,255,255,
1442 255,255,255,255,255,255,255,255,
1443 255,255,255,255,255,255,255,255,
1444 255,255,255,255,255,255,255,255,
1445 255,255,255,255,255,255,255,255,
1446 255,255,255,255,255,255};
1447
1448 const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05,
1449 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00,
1450 0x01,0x02,0x03,0x04,2,0,0,0,
1451 0xd4,0xe0,0x60,0xe5,
1452 1,
1453 0};
1454
1455 void test_pack(const int *pl, const int **headers, int byteskip,
1456 int pageskip, int packetskip){
1457 unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */
1458 long inptr=0;
1459 long outptr=0;
1460 long deptr=0;
1461 long depacket=0;
1462 long granule_pos=7,pageno=0;
1463 int i,j,packets,pageout=pageskip;
1464 int eosflag=0;
1465 int bosflag=0;
1466
1467 int byteskipcount=0;
1468
1469 ogg_stream_reset(&os_en);
1470 ogg_stream_reset(&os_de);
1471 ogg_sync_reset(&oy);
1472
1473 for(packets=0;packets<packetskip;packets++)
1474 depacket+=pl[packets];
1475
1476 for(packets=0;;packets++)if(pl[packets]==-1)break;
1477
1478 for(i=0;i<packets;i++){
1479 /* construct a test packet */
1480 ogg_packet op;
1481 int len=pl[i];
1482
1483 op.packet=data+inptr;
1484 op.bytes=len;
1485 op.e_o_s=(pl[i+1]<0?1:0);
1486 op.granulepos=granule_pos;
1487
1488 granule_pos+=1024;
1489
1490 for(j=0;j<len;j++)data[inptr++]=i+j;
1491
1492 /* submit the test packet */
1493 ogg_stream_packetin(&os_en,&op);
1494
1495 /* retrieve any finished pages */
1496 {
1497 ogg_page og;
1498
1499 while(ogg_stream_pageout(&os_en,&og)){
1500 /* We have a page. Check it carefully */
1501
1502 fprintf(stderr,"%ld, ",pageno);
1503
1504 if(headers[pageno]==NULL){
1505 fprintf(stderr,"coded too many pages!\n");
1506 exit(1);
1507 }
1508
1509 check_page(data+outptr,headers[pageno],&og);
1510
1511 outptr+=og.body_len;
1512 pageno++;
1513 if(pageskip){
1514 bosflag=1;
1515 pageskip--;
1516 deptr+=og.body_len;
1517 }
1518
1519 /* have a complete page; submit it to sync/decode */
1520
1521 {
1522 ogg_page og_de;
1523 ogg_packet op_de,op_de2;
1524 char *buf=ogg_sync_buffer(&oy,og.header_len+og.body_len);
1525 char *next=buf;
1526 byteskipcount+=og.header_len;
1527 if(byteskipcount>byteskip){
1528 memcpy(next,og.header,byteskipcount-byteskip);
1529 next+=byteskipcount-byteskip;
1530 byteskipcount=byteskip;
1531 }
1532
1533 byteskipcount+=og.body_len;
1534 if(byteskipcount>byteskip){
1535 memcpy(next,og.body,byteskipcount-byteskip);
1536 next+=byteskipcount-byteskip;
1537 byteskipcount=byteskip;
1538 }
1539
1540 ogg_sync_wrote(&oy,next-buf);
1541
1542 while(1){
1543 int ret=ogg_sync_pageout(&oy,&og_de);
1544 if(ret==0)break;
1545 if(ret<0)continue;
1546 /* got a page. Happy happy. Verify that it's good. */
1547
1548 fprintf(stderr,"(%d), ",pageout);
1549
1550 check_page(data+deptr,headers[pageout],&og_de);
1551 deptr+=og_de.body_len;
1552 pageout++;
1553
1554 /* submit it to deconstitution */
1555 ogg_stream_pagein(&os_de,&og_de);
1556
1557 /* packets out? */
1558 while(ogg_stream_packetpeek(&os_de,&op_de2)>0){
1559 ogg_stream_packetpeek(&os_de,NULL);
1560 ogg_stream_packetout(&os_de,&op_de); /* just catching them all */
1561
1562 /* verify peek and out match */
1563 if(memcmp(&op_de,&op_de2,sizeof(op_de))){
1564 fprintf(stderr,"packetout != packetpeek! pos=%ld\n",
1565 depacket);
1566 exit(1);
1567 }
1568
1569 /* verify the packet! */
1570 /* check data */
1571 if(memcmp(data+depacket,op_de.packet,op_de.bytes)){
1572 fprintf(stderr,"packet data mismatch in decode! pos=%ld\n",
1573 depacket);
1574 exit(1);
1575 }
1576 /* check bos flag */
1577 if(bosflag==0 && op_de.b_o_s==0){
1578 fprintf(stderr,"b_o_s flag not set on packet!\n");
1579 exit(1);
1580 }
1581 if(bosflag && op_de.b_o_s){
1582 fprintf(stderr,"b_o_s flag incorrectly set on packet!\n");
1583 exit(1);
1584 }
1585 bosflag=1;
1586 depacket+=op_de.bytes;
1587
1588 /* check eos flag */
1589 if(eosflag){
1590 fprintf(stderr,"Multiple decoded packets with eos flag!\n");
1591 exit(1);
1592 }
1593
1594 if(op_de.e_o_s)eosflag=1;
1595
1596 /* check granulepos flag */
1597 if(op_de.granulepos!=-1){
1598 fprintf(stderr," granule:%ld ",(long)op_de.granulepos);
1599 }
1600 }
1601 }
1602 }
1603 }
1604 }
1605 }
1606 _ogg_free(data);
1607 if(headers[pageno]!=NULL){
1608 fprintf(stderr,"did not write last page!\n");
1609 exit(1);
1610 }
1611 if(headers[pageout]!=NULL){
1612 fprintf(stderr,"did not decode last page!\n");
1613 exit(1);
1614 }
1615 if(inptr!=outptr){
1616 fprintf(stderr,"encoded page data incomplete!\n");
1617 exit(1);
1618 }
1619 if(inptr!=deptr){
1620 fprintf(stderr,"decoded page data incomplete!\n");
1621 exit(1);
1622 }
1623 if(inptr!=depacket){
1624 fprintf(stderr,"decoded packet data incomplete!\n");
1625 exit(1);
1626 }
1627 if(!eosflag){
1628 fprintf(stderr,"Never got a packet with EOS set!\n");
1629 exit(1);
1630 }
1631 fprintf(stderr,"ok.\n");
1632 }
1633
1634 int main(void){
1635
1636 ogg_stream_init(&os_en,0x04030201);
1637 ogg_stream_init(&os_de,0x04030201);
1638 ogg_sync_init(&oy);
1639
1640 /* Exercise each code path in the framing code. Also verify that
1641 the checksums are working. */
1642
1643 {
1644 /* 17 only */
1645 const int packets[]={17, -1};
1646 const int *headret[]={head1_0,NULL};
1647
1648 fprintf(stderr,"testing single page encoding... ");
1649 test_pack(packets,headret,0,0,0);
1650 }
1651
1652 {
1653 /* 17, 254, 255, 256, 500, 510, 600 byte, pad */
1654 const int packets[]={17, 254, 255, 256, 500, 510, 600, -1};
1655 const int *headret[]={head1_1,head2_1,NULL};
1656
1657 fprintf(stderr,"testing basic page encoding... ");
1658 test_pack(packets,headret,0,0,0);
1659 }
1660
1661 {
1662 /* nil packets; beginning,middle,end */
1663 const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1};
1664 const int *headret[]={head1_2,head2_2,NULL};
1665
1666 fprintf(stderr,"testing basic nil packets... ");
1667 test_pack(packets,headret,0,0,0);
1668 }
1669
1670 {
1671 /* large initial packet */
1672 const int packets[]={4345,259,255,-1};
1673 const int *headret[]={head1_3,head2_3,NULL};
1674
1675 fprintf(stderr,"testing initial-packet lacing > 4k... ");
1676 test_pack(packets,headret,0,0,0);
1677 }
1678
1679 {
1680 /* continuing packet test; with page spill expansion, we have to
1681 overflow the lacing table. */
1682 const int packets[]={0,65500,259,255,-1};
1683 const int *headret[]={head1_4,head2_4,head3_4,NULL};
1684
1685 fprintf(stderr,"testing single packet page span... ");
1686 test_pack(packets,headret,0,0,0);
1687 }
1688
1689 {
1690 /* spill expand packet test */
1691 const int packets[]={0,4345,259,255,0,0,-1};
1692 const int *headret[]={head1_4b,head2_4b,head3_4b,NULL};
1693
1694 fprintf(stderr,"testing page spill expansion... ");
1695 test_pack(packets,headret,0,0,0);
1696 }
1697
1698 /* page with the 255 segment limit */
1699 {
1700
1701 const int packets[]={0,10,10,10,10,10,10,10,10,
1702 10,10,10,10,10,10,10,10,
1703 10,10,10,10,10,10,10,10,
1704 10,10,10,10,10,10,10,10,
1705 10,10,10,10,10,10,10,10,
1706 10,10,10,10,10,10,10,10,
1707 10,10,10,10,10,10,10,10,
1708 10,10,10,10,10,10,10,10,
1709 10,10,10,10,10,10,10,10,
1710 10,10,10,10,10,10,10,10,
1711 10,10,10,10,10,10,10,10,
1712 10,10,10,10,10,10,10,10,
1713 10,10,10,10,10,10,10,10,
1714 10,10,10,10,10,10,10,10,
1715 10,10,10,10,10,10,10,10,
1716 10,10,10,10,10,10,10,10,
1717 10,10,10,10,10,10,10,10,
1718 10,10,10,10,10,10,10,10,
1719 10,10,10,10,10,10,10,10,
1720 10,10,10,10,10,10,10,10,
1721 10,10,10,10,10,10,10,10,
1722 10,10,10,10,10,10,10,10,
1723 10,10,10,10,10,10,10,10,
1724 10,10,10,10,10,10,10,10,
1725 10,10,10,10,10,10,10,10,
1726 10,10,10,10,10,10,10,10,
1727 10,10,10,10,10,10,10,10,
1728 10,10,10,10,10,10,10,10,
1729 10,10,10,10,10,10,10,10,
1730 10,10,10,10,10,10,10,10,
1731 10,10,10,10,10,10,10,10,
1732 10,10,10,10,10,10,10,50,-1};
1733 const int *headret[]={head1_5,head2_5,head3_5,NULL};
1734
1735 fprintf(stderr,"testing max packet segments... ");
1736 test_pack(packets,headret,0,0,0);
1737 }
1738
1739 {
1740 /* packet that overspans over an entire page */
1741 const int packets[]={0,100,130049,259,255,-1};
1742 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1743
1744 fprintf(stderr,"testing very large packets... ");
1745 test_pack(packets,headret,0,0,0);
1746 }
1747
1748 {
1749 /* test for the libogg 1.1.1 resync in large continuation bug
1750 found by Josh Coalson) */
1751 const int packets[]={0,100,130049,259,255,-1};
1752 const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL};
1753
1754 fprintf(stderr,"testing continuation resync in very large packets... ");
1755 test_pack(packets,headret,100,2,3);
1756 }
1757
1758 {
1759 /* term only page. why not? */
1760 const int packets[]={0,100,64770,-1};
1761 const int *headret[]={head1_7,head2_7,head3_7,NULL};
1762
1763 fprintf(stderr,"testing zero data page (1 nil packet)... ");
1764 test_pack(packets,headret,0,0,0);
1765 }
1766
1767
1768
1769 {
1770 /* build a bunch of pages for testing */
1771 unsigned char *data=_ogg_malloc(1024*1024);
1772 int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1};
1773 int inptr=0,i,j;
1774 ogg_page og[5];
1775
1776 ogg_stream_reset(&os_en);
1777
1778 for(i=0;pl[i]!=-1;i++){
1779 ogg_packet op;
1780 int len=pl[i];
1781
1782 op.packet=data+inptr;
1783 op.bytes=len;
1784 op.e_o_s=(pl[i+1]<0?1:0);
1785 op.granulepos=(i+1)*1000;
1786
1787 for(j=0;j<len;j++)data[inptr++]=i+j;
1788 ogg_stream_packetin(&os_en,&op);
1789 }
1790
1791 _ogg_free(data);
1792
1793 /* retrieve finished pages */
1794 for(i=0;i<5;i++){
1795 if(ogg_stream_pageout(&os_en,&og[i])==0){
1796 fprintf(stderr,"Too few pages output building sync tests!\n");
1797 exit(1);
1798 }
1799 copy_page(&og[i]);
1800 }
1801
1802 /* Test lost pages on pagein/packetout: no rollback */
1803 {
1804 ogg_page temp;
1805 ogg_packet test;
1806
1807 fprintf(stderr,"Testing loss of pages... ");
1808
1809 ogg_sync_reset(&oy);
1810 ogg_stream_reset(&os_de);
1811 for(i=0;i<5;i++){
1812 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1813 og[i].header_len);
1814 ogg_sync_wrote(&oy,og[i].header_len);
1815 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1816 ogg_sync_wrote(&oy,og[i].body_len);
1817 }
1818
1819 ogg_sync_pageout(&oy,&temp);
1820 ogg_stream_pagein(&os_de,&temp);
1821 ogg_sync_pageout(&oy,&temp);
1822 ogg_stream_pagein(&os_de,&temp);
1823 ogg_sync_pageout(&oy,&temp);
1824 /* skip */
1825 ogg_sync_pageout(&oy,&temp);
1826 ogg_stream_pagein(&os_de,&temp);
1827
1828 /* do we get the expected results/packets? */
1829
1830 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1831 checkpacket(&test,0,0,0);
1832 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1833 checkpacket(&test,1,1,-1);
1834 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1835 checkpacket(&test,1,2,-1);
1836 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1837 checkpacket(&test,98,3,-1);
1838 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1839 checkpacket(&test,4079,4,5000);
1840 if(ogg_stream_packetout(&os_de,&test)!=-1){
1841 fprintf(stderr,"Error: loss of page did not return error\n");
1842 exit(1);
1843 }
1844 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1845 checkpacket(&test,76,9,-1);
1846 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1847 checkpacket(&test,34,10,-1);
1848 fprintf(stderr,"ok.\n");
1849 }
1850
1851 /* Test lost pages on pagein/packetout: rollback with continuation */
1852 {
1853 ogg_page temp;
1854 ogg_packet test;
1855
1856 fprintf(stderr,"Testing loss of pages (rollback required)... ");
1857
1858 ogg_sync_reset(&oy);
1859 ogg_stream_reset(&os_de);
1860 for(i=0;i<5;i++){
1861 memcpy(ogg_sync_buffer(&oy,og[i].header_len),og[i].header,
1862 og[i].header_len);
1863 ogg_sync_wrote(&oy,og[i].header_len);
1864 memcpy(ogg_sync_buffer(&oy,og[i].body_len),og[i].body,og[i].body_len);
1865 ogg_sync_wrote(&oy,og[i].body_len);
1866 }
1867
1868 ogg_sync_pageout(&oy,&temp);
1869 ogg_stream_pagein(&os_de,&temp);
1870 ogg_sync_pageout(&oy,&temp);
1871 ogg_stream_pagein(&os_de,&temp);
1872 ogg_sync_pageout(&oy,&temp);
1873 ogg_stream_pagein(&os_de,&temp);
1874 ogg_sync_pageout(&oy,&temp);
1875 /* skip */
1876 ogg_sync_pageout(&oy,&temp);
1877 ogg_stream_pagein(&os_de,&temp);
1878
1879 /* do we get the expected results/packets? */
1880
1881 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1882 checkpacket(&test,0,0,0);
1883 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1884 checkpacket(&test,1,1,-1);
1885 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1886 checkpacket(&test,1,2,-1);
1887 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1888 checkpacket(&test,98,3,-1);
1889 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1890 checkpacket(&test,4079,4,5000);
1891 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1892 checkpacket(&test,1,5,-1);
1893 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1894 checkpacket(&test,1,6,-1);
1895 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1896 checkpacket(&test,2954,7,-1);
1897 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1898 checkpacket(&test,2057,8,9000);
1899 if(ogg_stream_packetout(&os_de,&test)!=-1){
1900 fprintf(stderr,"Error: loss of page did not return error\n");
1901 exit(1);
1902 }
1903 if(ogg_stream_packetout(&os_de,&test)!=1)error();
1904 checkpacket(&test,300,17,18000);
1905 fprintf(stderr,"ok.\n");
1906 }
1907
1908 /* the rest only test sync */
1909 {
1910 ogg_page og_de;
1911 /* Test fractional page inputs: incomplete capture */
1912 fprintf(stderr,"Testing sync on partial inputs... ");
1913 ogg_sync_reset(&oy);
1914 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1915 3);
1916 ogg_sync_wrote(&oy,3);
1917 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1918
1919 /* Test fractional page inputs: incomplete fixed header */
1920 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3,
1921 20);
1922 ogg_sync_wrote(&oy,20);
1923 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1924
1925 /* Test fractional page inputs: incomplete header */
1926 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23,
1927 5);
1928 ogg_sync_wrote(&oy,5);
1929 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1930
1931 /* Test fractional page inputs: incomplete body */
1932
1933 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28,
1934 og[1].header_len-28);
1935 ogg_sync_wrote(&oy,og[1].header_len-28);
1936 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1937
1938 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000);
1939 ogg_sync_wrote(&oy,1000);
1940 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1941
1942 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000,
1943 og[1].body_len-1000);
1944 ogg_sync_wrote(&oy,og[1].body_len-1000);
1945 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1946
1947 fprintf(stderr,"ok.\n");
1948 }
1949
1950 /* Test fractional page inputs: page + incomplete capture */
1951 {
1952 ogg_page og_de;
1953 fprintf(stderr,"Testing sync on 1+partial inputs... ");
1954 ogg_sync_reset(&oy);
1955
1956 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1957 og[1].header_len);
1958 ogg_sync_wrote(&oy,og[1].header_len);
1959
1960 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1961 og[1].body_len);
1962 ogg_sync_wrote(&oy,og[1].body_len);
1963
1964 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1965 20);
1966 ogg_sync_wrote(&oy,20);
1967 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1968 if(ogg_sync_pageout(&oy,&og_de)>0)error();
1969
1970 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20,
1971 og[1].header_len-20);
1972 ogg_sync_wrote(&oy,og[1].header_len-20);
1973 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1974 og[1].body_len);
1975 ogg_sync_wrote(&oy,og[1].body_len);
1976 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
1977
1978 fprintf(stderr,"ok.\n");
1979 }
1980
1981 /* Test recapture: garbage + page */
1982 {
1983 ogg_page og_de;
1984 fprintf(stderr,"Testing search for capture... ");
1985 ogg_sync_reset(&oy);
1986
1987 /* 'garbage' */
1988 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1989 og[1].body_len);
1990 ogg_sync_wrote(&oy,og[1].body_len);
1991
1992 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
1993 og[1].header_len);
1994 ogg_sync_wrote(&oy,og[1].header_len);
1995
1996 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
1997 og[1].body_len);
1998 ogg_sync_wrote(&oy,og[1].body_len);
1999
2000 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2001 20);
2002 ogg_sync_wrote(&oy,20);
2003 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2004 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2005 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2006
2007 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20,
2008 og[2].header_len-20);
2009 ogg_sync_wrote(&oy,og[2].header_len-20);
2010 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2011 og[2].body_len);
2012 ogg_sync_wrote(&oy,og[2].body_len);
2013 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2014
2015 fprintf(stderr,"ok.\n");
2016 }
2017
2018 /* Test recapture: page + garbage + page */
2019 {
2020 ogg_page og_de;
2021 fprintf(stderr,"Testing recapture... ");
2022 ogg_sync_reset(&oy);
2023
2024 memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header,
2025 og[1].header_len);
2026 ogg_sync_wrote(&oy,og[1].header_len);
2027
2028 memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,
2029 og[1].body_len);
2030 ogg_sync_wrote(&oy,og[1].body_len);
2031
2032 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2033 og[2].header_len);
2034 ogg_sync_wrote(&oy,og[2].header_len);
2035
2036 memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header,
2037 og[2].header_len);
2038 ogg_sync_wrote(&oy,og[2].header_len);
2039
2040 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2041
2042 memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body,
2043 og[2].body_len-5);
2044 ogg_sync_wrote(&oy,og[2].body_len-5);
2045
2046 memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header,
2047 og[3].header_len);
2048 ogg_sync_wrote(&oy,og[3].header_len);
2049
2050 memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body,
2051 og[3].body_len);
2052 ogg_sync_wrote(&oy,og[3].body_len);
2053
2054 if(ogg_sync_pageout(&oy,&og_de)>0)error();
2055 if(ogg_sync_pageout(&oy,&og_de)<=0)error();
2056
2057 fprintf(stderr,"ok.\n");
2058 }
2059
2060 /* Free page data that was previously copied */
2061 {
2062 for(i=0;i<5;i++){
2063 free_page(&og[i]);
2064 }
2065 }
2066 }
2067
2068 return(0);
2069 }
2070
2071 #endif
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: maintain the info structure, info <-> header packets
14
15 ********************************************************************/
16
17 /* general handling of the header and the vorbis_info structure (and
18 substructures) */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <ctype.h>
23 #include <limits.h>
24 #include "ogg.h"
25 #include "ivorbiscodec.h"
26 #include "codec_internal.h"
27 #include "codebook.h"
28 #include "registry.h"
29 #include "window.h"
30 #include "misc.h"
31
32 /* helpers */
33 static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){
34 while(bytes--){
35 *buf++=oggpack_read(o,8);
36 }
37 }
38
39 void vorbis_comment_init(vorbis_comment *vc){
40 memset(vc,0,sizeof(*vc));
41 }
42
43 /* This is more or less the same as strncasecmp - but that doesn't exist
44 * everywhere, and this is a fairly trivial function, so we include it */
45 static int tagcompare(const char *s1, const char *s2, int n){
46 int c=0;
47 while(c < n){
48 if(toupper(s1[c]) != toupper(s2[c]))
49 return !0;
50 c++;
51 }
52 return 0;
53 }
54
55 char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count){
56 long i;
57 int found = 0;
58 int taglen = strlen(tag)+1; /* +1 for the = we append */
59 char *fulltag = (char *)alloca(taglen+ 1);
60
61 strcpy(fulltag, tag);
62 strcat(fulltag, "=");
63
64 for(i=0;i<vc->comments;i++){
65 if(!tagcompare(vc->user_comments[i], fulltag, taglen)){
66 if(count == found)
67 /* We return a pointer to the data, not a copy */
68 return vc->user_comments[i] + taglen;
69 else
70 found++;
71 }
72 }
73 return NULL; /* didn't find anything */
74 }
75
76 int vorbis_comment_query_count(vorbis_comment *vc, char *tag){
77 int i,count=0;
78 int taglen = strlen(tag)+1; /* +1 for the = we append */
79 char *fulltag = (char *)alloca(taglen+1);
80 strcpy(fulltag,tag);
81 strcat(fulltag, "=");
82
83 for(i=0;i<vc->comments;i++){
84 if(!tagcompare(vc->user_comments[i], fulltag, taglen))
85 count++;
86 }
87
88 return count;
89 }
90
91 void vorbis_comment_clear(vorbis_comment *vc){
92 if(vc){
93 long i;
94 if(vc->user_comments){
95 for(i=0;i<vc->comments;i++)
96 if(vc->user_comments[i])_ogg_free(vc->user_comments[i]);
97 _ogg_free(vc->user_comments);
98 }
99 if(vc->comment_lengths)_ogg_free(vc->comment_lengths);
100 if(vc->vendor)_ogg_free(vc->vendor);
101 memset(vc,0,sizeof(*vc));
102 }
103 }
104
105 /* blocksize 0 is guaranteed to be short, 1 is guarantted to be long.
106 They may be equal, but short will never ge greater than long */
107 int vorbis_info_blocksize(vorbis_info *vi,int zo){
108 codec_setup_info *ci = (codec_setup_info *)vi->codec_setup;
109 return ci ? ci->blocksizes[zo] : -1;
110 }
111
112 /* used by synthesis, which has a full, alloced vi */
113 void vorbis_info_init(vorbis_info *vi){
114 memset(vi,0,sizeof(*vi));
115 vi->codec_setup=(codec_setup_info *)_ogg_calloc(1,sizeof(codec_setup_info));
116 }
117
118 void vorbis_info_clear(vorbis_info *vi){
119 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
120 int i;
121
122 if(ci){
123
124 for(i=0;i<ci->modes;i++)
125 if(ci->mode_param[i])_ogg_free(ci->mode_param[i]);
126
127 for(i=0;i<ci->maps;i++) /* unpack does the range checking */
128 if(ci->map_param[i])
129 _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]);
130
131 for(i=0;i<ci->floors;i++) /* unpack does the range checking */
132 if(ci->floor_param[i])
133 _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]);
134
135 for(i=0;i<ci->residues;i++) /* unpack does the range checking */
136 if(ci->residue_param[i])
137 _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]);
138
139 for(i=0;i<ci->books;i++){
140 if(ci->book_param[i]){
141 /* knows if the book was not alloced */
142 vorbis_staticbook_destroy(ci->book_param[i]);
143 }
144 if(ci->fullbooks)
145 vorbis_book_clear(ci->fullbooks+i);
146 }
147 if(ci->fullbooks)
148 _ogg_free(ci->fullbooks);
149
150 _ogg_free(ci);
151 }
152
153 memset(vi,0,sizeof(*vi));
154 }
155
156 /* Header packing/unpacking ********************************************/
157
158 static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){
159 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
160 if(!ci)return(OV_EFAULT);
161
162 vi->version=oggpack_read(opb,32);
163 if(vi->version!=0)return(OV_EVERSION);
164
165 vi->channels=oggpack_read(opb,8);
166 vi->rate=oggpack_read(opb,32);
167
168 vi->bitrate_upper=oggpack_read(opb,32);
169 vi->bitrate_nominal=oggpack_read(opb,32);
170 vi->bitrate_lower=oggpack_read(opb,32);
171
172 ci->blocksizes[0]=1<<oggpack_read(opb,4);
173 ci->blocksizes[1]=1<<oggpack_read(opb,4);
174
175 if(vi->rate<1)goto err_out;
176 if(vi->channels<1)goto err_out;
177 if(ci->blocksizes[0]<64)goto err_out;
178 if(ci->blocksizes[1]<ci->blocksizes[0])goto err_out;
179 if(ci->blocksizes[1]>8192)goto err_out;
180
181 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
182
183 return(0);
184 err_out:
185 vorbis_info_clear(vi);
186 return(OV_EBADHEADER);
187 }
188
189 static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){
190 int i;
191 int vendorlen;
192 vendorlen=oggpack_read(opb,32);
193 if(vendorlen<0)goto err_out;
194 if(vendorlen>opb->storage-oggpack_bytes(opb))goto err_out;
195 vc->vendor=(char *)_ogg_calloc(vendorlen+1,1);
196 if(vc->vendor==NULL)goto err_out;
197 _v_readstring(opb,vc->vendor,vendorlen);
198 i=oggpack_read(opb,32);
199 if(i<0||i>=INT_MAX||i>(opb->storage-oggpack_bytes(opb))>>2)goto err_out;
200 vc->user_comments=(char **)_ogg_calloc(i+1,sizeof(*vc->user_comments));
201 vc->comment_lengths=(int *)_ogg_calloc(i+1, sizeof(*vc->comment_lengths));
202 if(vc->user_comments==NULL||vc->comment_lengths==NULL)goto err_out;
203 vc->comments=i;
204
205 for(i=0;i<vc->comments;i++){
206 int len=oggpack_read(opb,32);
207 if(len<0||len>opb->storage-oggpack_bytes(opb))goto err_out;
208 vc->comment_lengths[i]=len;
209 vc->user_comments[i]=(char *)_ogg_calloc(len+1,1);
210 if(vc->user_comments[i]==NULL){
211 vc->comments=i;
212 goto err_out;
213 }
214 _v_readstring(opb,vc->user_comments[i],len);
215 }
216 if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */
217
218 return(0);
219 err_out:
220 vorbis_comment_clear(vc);
221 return(OV_EBADHEADER);
222 }
223
224 /* all of the real encoding details are here. The modes, books,
225 everything */
226 static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){
227 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
228 int i;
229 if(!ci)return(OV_EFAULT);
230
231 /* codebooks */
232 ci->books=oggpack_read(opb,8)+1;
233 if(ci->books<=0)goto err_out;
234 for(i=0;i<ci->books;i++){
235 ci->book_param[i]=vorbis_staticbook_unpack(opb);
236 if(!ci->book_param[i])goto err_out;
237 }
238
239 /* time backend settings */
240 ci->times=oggpack_read(opb,6)+1;
241 if(ci->times<=0)goto err_out;
242 for(i=0;i<ci->times;i++){
243 ci->time_type[i]=oggpack_read(opb,16);
244 if(ci->time_type[i]<0 || ci->time_type[i]>=VI_TIMEB)goto err_out;
245 /* ci->time_param[i]=_time_P[ci->time_type[i]]->unpack(vi,opb);
246 Vorbis I has no time backend */
247 /*if(!ci->time_param[i])goto err_out;*/
248 }
249
250 /* floor backend settings */
251 ci->floors=oggpack_read(opb,6)+1;
252 if(ci->floors<=0)goto err_out;
253 for(i=0;i<ci->floors;i++){
254 ci->floor_type[i]=oggpack_read(opb,16);
255 if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out;
256 ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb);
257 if(!ci->floor_param[i])goto err_out;
258 }
259
260 /* residue backend settings */
261 ci->residues=oggpack_read(opb,6)+1;
262 if(ci->residues<=0)goto err_out;
263 for(i=0;i<ci->residues;i++){
264 ci->residue_type[i]=oggpack_read(opb,16);
265 if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out;
266 ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb);
267 if(!ci->residue_param[i])goto err_out;
268 }
269
270 /* map backend settings */
271 ci->maps=oggpack_read(opb,6)+1;
272 if(ci->maps<=0)goto err_out;
273 for(i=0;i<ci->maps;i++){
274 ci->map_type[i]=oggpack_read(opb,16);
275 if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out;
276 ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb);
277 if(!ci->map_param[i])goto err_out;
278 }
279
280 /* mode settings */
281 ci->modes=oggpack_read(opb,6)+1;
282 if(ci->modes<=0)goto err_out;
283 for(i=0;i<ci->modes;i++){
284 ci->mode_param[i]=(vorbis_info_mode *)_ogg_calloc(1,sizeof(*ci->mode_param[i]));
285 ci->mode_param[i]->blockflag=oggpack_read(opb,1);
286 ci->mode_param[i]->windowtype=oggpack_read(opb,16);
287 ci->mode_param[i]->transformtype=oggpack_read(opb,16);
288 ci->mode_param[i]->mapping=oggpack_read(opb,8);
289
290 if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out;
291 if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out;
292 if(ci->mode_param[i]->mapping>=ci->maps)goto err_out;
293 if(ci->mode_param[i]->mapping<0)goto err_out;
294 }
295
296 if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */
297
298 return(0);
299 err_out:
300 vorbis_info_clear(vi);
301 return(OV_EBADHEADER);
302 }
303
304 /* Is this packet a vorbis ID header? */
305 int vorbis_synthesis_idheader(ogg_packet *op){
306 oggpack_buffer opb;
307 char buffer[6];
308
309 if(op){
310 oggpack_readinit(&opb,op->packet,op->bytes);
311
312 if(!op->b_o_s)
313 return(0); /* Not the initial packet */
314
315 if(oggpack_read(&opb,8) != 1)
316 return 0; /* not an ID header */
317
318 memset(buffer,0,6);
319 _v_readstring(&opb,buffer,6);
320 if(memcmp(buffer,"vorbis",6))
321 return 0; /* not vorbis */
322
323 return 1;
324 }
325
326 return 0;
327 }
328
329 /* The Vorbis header is in three packets; the initial small packet in
330 the first page that identifies basic parameters, a second packet
331 with bitstream comments and a third packet that holds the
332 codebook. */
333
334 int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){
335 oggpack_buffer opb;
336
337 if(op){
338 oggpack_readinit(&opb,op->packet,op->bytes);
339
340 /* Which of the three types of header is this? */
341 /* Also verify header-ness, vorbis */
342 {
343 char buffer[6];
344 int packtype=oggpack_read(&opb,8);
345 memset(buffer,0,6);
346 _v_readstring(&opb,buffer,6);
347 if(memcmp(buffer,"vorbis",6)){
348 /* not a vorbis header */
349 return(OV_ENOTVORBIS);
350 }
351 switch(packtype){
352 case 0x01: /* least significant *bit* is read first */
353 if(!op->b_o_s){
354 /* Not the initial packet */
355 return(OV_EBADHEADER);
356 }
357 if(vi->rate!=0){
358 /* previously initialized info header */
359 return(OV_EBADHEADER);
360 }
361
362 return(_vorbis_unpack_info(vi,&opb));
363
364 case 0x03: /* least significant *bit* is read first */
365 if(vi->rate==0){
366 /* um... we didn't get the initial header */
367 return(OV_EBADHEADER);
368 }
369
370 return(_vorbis_unpack_comment(vc,&opb));
371
372 case 0x05: /* least significant *bit* is read first */
373 if(vi->rate==0 || vc->vendor==NULL){
374 /* um... we didn;t get the initial header or comments yet */
375 return(OV_EBADHEADER);
376 }
377
378 return(_vorbis_unpack_books(vi,&opb));
379
380 default:
381 /* Not a valid vorbis header type */
382 return(OV_EBADHEADER);
383 break;
384 }
385 }
386 }
387 return(OV_EBADHEADER);
388 }
389
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: libvorbis codec headers
14
15 ********************************************************************/
16
17 #ifndef _vorbis_codec_h_
18 #define _vorbis_codec_h_
19
20 #ifdef __cplusplus
21 extern "C"
22 {
23 #endif /* __cplusplus */
24
25 #include "ogg.h"
26
27 typedef struct vorbis_info{
28 int version;
29 int channels;
30 long rate;
31
32 /* The below bitrate declarations are *hints*.
33 Combinations of the three values carry the following implications:
34
35 all three set to the same value:
36 implies a fixed rate bitstream
37 only nominal set:
38 implies a VBR stream that averages the nominal bitrate. No hard
39 upper/lower limit
40 upper and or lower set:
41 implies a VBR bitstream that obeys the bitrate limits. nominal
42 may also be set to give a nominal rate.
43 none set:
44 the coder does not care to speculate.
45 */
46
47 long bitrate_upper;
48 long bitrate_nominal;
49 long bitrate_lower;
50 long bitrate_window;
51
52 void *codec_setup;
53 } vorbis_info;
54
55 /* vorbis_dsp_state buffers the current vorbis audio
56 analysis/synthesis state. The DSP state belongs to a specific
57 logical bitstream ****************************************************/
58 typedef struct vorbis_dsp_state{
59 int analysisp;
60 vorbis_info *vi;
61
62 ogg_int32_t **pcm;
63 ogg_int32_t **pcmret;
64 int pcm_storage;
65 int pcm_current;
66 int pcm_returned;
67
68 int preextrapolate;
69 int eofflag;
70
71 long lW;
72 long W;
73 long nW;
74 long centerW;
75
76 ogg_int64_t granulepos;
77 ogg_int64_t sequence;
78
79 void *backend_state;
80 } vorbis_dsp_state;
81
82 typedef struct vorbis_block{
83 /* necessary stream state for linking to the framing abstraction */
84 ogg_int32_t **pcm; /* this is a pointer into local storage */
85 oggpack_buffer opb;
86
87 long lW;
88 long W;
89 long nW;
90 int pcmend;
91 int mode;
92
93 int eofflag;
94 ogg_int64_t granulepos;
95 ogg_int64_t sequence;
96 vorbis_dsp_state *vd; /* For read-only access of configuration */
97
98 /* local storage to avoid remallocing; it's up to the mapping to
99 structure it */
100 void *localstore;
101 long localtop;
102 long localalloc;
103 long totaluse;
104 struct alloc_chain *reap;
105
106 } vorbis_block;
107
108 /* vorbis_block is a single block of data to be processed as part of
109 the analysis/synthesis stream; it belongs to a specific logical
110 bitstream, but is independant from other vorbis_blocks belonging to
111 that logical bitstream. *************************************************/
112
113 struct alloc_chain{
114 void *ptr;
115 struct alloc_chain *next;
116 };
117
118 /* vorbis_info contains all the setup information specific to the
119 specific compression/decompression mode in progress (eg,
120 psychoacoustic settings, channel setup, options, codebook
121 etc). vorbis_info and substructures are in backends.h.
122 *********************************************************************/
123
124 /* the comments are not part of vorbis_info so that vorbis_info can be
125 static storage */
126 typedef struct vorbis_comment{
127 /* unlimited user comment fields. libvorbis writes 'libvorbis'
128 whatever vendor is set to in encode */
129 char **user_comments;
130 int *comment_lengths;
131 int comments;
132 char *vendor;
133
134 } vorbis_comment;
135
136
137 /* libvorbis encodes in two abstraction layers; first we perform DSP
138 and produce a packet (see docs/analysis.txt). The packet is then
139 coded into a framed OggSquish bitstream by the second layer (see
140 docs/framing.txt). Decode is the reverse process; we sync/frame
141 the bitstream and extract individual packets, then decode the
142 packet back into PCM audio.
143
144 The extra framing/packetizing is used in streaming formats, such as
145 files. Over the net (such as with UDP), the framing and
146 packetization aren't necessary as they're provided by the transport
147 and the streaming layer is not used */
148
149 /* Vorbis PRIMITIVES: general ***************************************/
150
151 extern void vorbis_info_init(vorbis_info *vi);
152 extern void vorbis_info_clear(vorbis_info *vi);
153 extern int vorbis_info_blocksize(vorbis_info *vi,int zo);
154 extern void vorbis_comment_init(vorbis_comment *vc);
155 extern void vorbis_comment_add(vorbis_comment *vc, char *comment);
156 extern void vorbis_comment_add_tag(vorbis_comment *vc,
157 char *tag, char *contents);
158 extern char *vorbis_comment_query(vorbis_comment *vc, char *tag, int count);
159 extern int vorbis_comment_query_count(vorbis_comment *vc, char *tag);
160 extern void vorbis_comment_clear(vorbis_comment *vc);
161
162 extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb);
163 extern int vorbis_block_clear(vorbis_block *vb);
164 extern void vorbis_dsp_clear(vorbis_dsp_state *v);
165
166 /* Vorbis PRIMITIVES: synthesis layer *******************************/
167 extern int vorbis_synthesis_idheader(ogg_packet *op);
168 extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,
169 ogg_packet *op);
170
171 extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi);
172 extern int vorbis_synthesis_restart(vorbis_dsp_state *v);
173 extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op);
174 extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op);
175 extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb);
176 extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,ogg_int32_t ***pcm);
177 extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples);
178 extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op);
179
180 /* Vorbis ERRORS and return codes ***********************************/
181
182 #define OV_FALSE -1
183 #define OV_EOF -2
184 #define OV_HOLE -3
185
186 #define OV_EREAD -128
187 #define OV_EFAULT -129
188 #define OV_EIMPL -130
189 #define OV_EINVAL -131
190 #define OV_ENOTVORBIS -132
191 #define OV_EBADHEADER -133
192 #define OV_EVERSION -134
193 #define OV_ENOTAUDIO -135
194 #define OV_EBADPACKET -136
195 #define OV_EBADLINK -137
196 #define OV_ENOSEEK -138
197
198 #ifdef __cplusplus
199 }
200 #endif /* __cplusplus */
201
202 #endif
203
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: stdio-based convenience library for opening/seeking/decoding
14
15 ********************************************************************/
16
17 #ifndef _OV_FILE_H_
18 #define _OV_FILE_H_
19
20 #ifdef __cplusplus
21 extern "C"
22 {
23 #endif /* __cplusplus */
24
25 #include <stdio.h>
26 #include "ivorbiscodec.h"
27
28 #define CHUNKSIZE 1024
29 /* The function prototypes for the callbacks are basically the same as for
30 * the stdio functions fread, fseek, fclose, ftell.
31 * The one difference is that the FILE * arguments have been replaced with
32 * a void * - this is to be used as a pointer to whatever internal data these
33 * functions might need. In the stdio case, it's just a FILE * cast to a void *
34 *
35 * If you use other functions, check the docs for these functions and return
36 * the right values. For seek_func(), you *MUST* return -1 if the stream is
37 * unseekable
38 */
39 typedef struct {
40 size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource);
41 int (*seek_func) (void *datasource, ogg_int64_t offset, int whence);
42 int (*close_func) (void *datasource);
43 long (*tell_func) (void *datasource);
44 } ov_callbacks;
45
46 #define NOTOPEN 0
47 #define PARTOPEN 1
48 #define OPENED 2
49 #define STREAMSET 3
50 #define INITSET 4
51
52 typedef struct OggVorbis_File {
53 void *datasource; /* Pointer to a FILE *, etc. */
54 int seekable;
55 ogg_int64_t offset;
56 ogg_int64_t end;
57 ogg_sync_state oy;
58
59 /* If the FILE handle isn't seekable (eg, a pipe), only the current
60 stream appears */
61 int links;
62 ogg_int64_t *offsets;
63 ogg_int64_t *dataoffsets;
64 ogg_uint32_t *serialnos;
65 ogg_int64_t *pcmlengths;
66 vorbis_info *vi;
67 vorbis_comment *vc;
68
69 /* Decoding working state local storage */
70 ogg_int64_t pcm_offset;
71 int ready_state;
72 ogg_uint32_t current_serialno;
73 int current_link;
74
75 ogg_int64_t bittrack;
76 ogg_int64_t samptrack;
77
78 ogg_stream_state os; /* take physical pages, weld into a logical
79 stream of packets */
80 vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */
81 vorbis_block vb; /* local working space for packet->PCM decode */
82
83 ov_callbacks callbacks;
84
85 } OggVorbis_File;
86
87 extern int ov_clear(OggVorbis_File *vf);
88 extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes);
89 extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf,
90 const char *initial, long ibytes, ov_callbacks callbacks);
91
92 extern long ov_bitrate(OggVorbis_File *vf,int i);
93 extern long ov_bitrate_instant(OggVorbis_File *vf);
94 extern long ov_streams(OggVorbis_File *vf);
95 extern long ov_seekable(OggVorbis_File *vf);
96 extern long ov_serialnumber(OggVorbis_File *vf,int i);
97
98 extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i);
99 extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i);
100 extern ogg_int64_t ov_time_total(OggVorbis_File *vf,int i);
101
102 extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos);
103 extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos);
104 extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
105 extern int ov_time_seek(OggVorbis_File *vf,ogg_int64_t pos);
106 extern int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t pos);
107
108 extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf);
109 extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf);
110
111 extern vorbis_info *ov_info(OggVorbis_File *vf,int link);
112
113 extern long ov_read(OggVorbis_File *vf,char *buffer,int length,
114 int *bitstream);
115
116 #ifdef __cplusplus
117 }
118 #endif /* __cplusplus */
119
120 #endif
121
122
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: lookup data
14
15 ********************************************************************/
16
17 #ifndef _V_LOOKUP_DATA_H_
18 #define _V_LOOKUP_DATA_H_
19
20 #include "os_types.h"
21
22 #define FROMdB_LOOKUP_SZ 35
23 #define FROMdB2_LOOKUP_SZ 32
24 #define FROMdB_SHIFT 5
25 #define FROMdB2_SHIFT 3
26 #define FROMdB2_MASK 31
27
28 static const ogg_int32_t FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={
29 0x003fffff, 0x0028619b, 0x00197a96, 0x0010137a,
30 0x000a24b0, 0x00066666, 0x000409c3, 0x00028c42,
31 0x00019b8c, 0x000103ab, 0x0000a3d7, 0x00006760,
32 0x0000413a, 0x00002928, 0x000019f8, 0x00001062,
33 0x00000a56, 0x00000686, 0x0000041e, 0x00000299,
34 0x000001a3, 0x00000109, 0x000000a7, 0x00000069,
35 0x00000042, 0x0000002a, 0x0000001a, 0x00000011,
36 0x0000000b, 0x00000007, 0x00000004, 0x00000003,
37 0x00000002, 0x00000001, 0x00000001};
38
39 static const ogg_int32_t FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={
40 0x000001fc, 0x000001f5, 0x000001ee, 0x000001e7,
41 0x000001e0, 0x000001d9, 0x000001d2, 0x000001cc,
42 0x000001c5, 0x000001bf, 0x000001b8, 0x000001b2,
43 0x000001ac, 0x000001a6, 0x000001a0, 0x0000019a,
44 0x00000194, 0x0000018e, 0x00000188, 0x00000183,
45 0x0000017d, 0x00000178, 0x00000172, 0x0000016d,
46 0x00000168, 0x00000163, 0x0000015e, 0x00000159,
47 0x00000154, 0x0000014f, 0x0000014a, 0x00000145,
48 };
49
50 #define INVSQ_LOOKUP_I_SHIFT 10
51 #define INVSQ_LOOKUP_I_MASK 1023
52 static const long INVSQ_LOOKUP_I[64+1]={
53 92682, 91966, 91267, 90583,
54 89915, 89261, 88621, 87995,
55 87381, 86781, 86192, 85616,
56 85051, 84497, 83953, 83420,
57 82897, 82384, 81880, 81385,
58 80899, 80422, 79953, 79492,
59 79039, 78594, 78156, 77726,
60 77302, 76885, 76475, 76072,
61 75674, 75283, 74898, 74519,
62 74146, 73778, 73415, 73058,
63 72706, 72359, 72016, 71679,
64 71347, 71019, 70695, 70376,
65 70061, 69750, 69444, 69141,
66 68842, 68548, 68256, 67969,
67 67685, 67405, 67128, 66855,
68 66585, 66318, 66054, 65794,
69 65536,
70 };
71
72 static const long INVSQ_LOOKUP_IDel[64]={
73 716, 699, 684, 668,
74 654, 640, 626, 614,
75 600, 589, 576, 565,
76 554, 544, 533, 523,
77 513, 504, 495, 486,
78 477, 469, 461, 453,
79 445, 438, 430, 424,
80 417, 410, 403, 398,
81 391, 385, 379, 373,
82 368, 363, 357, 352,
83 347, 343, 337, 332,
84 328, 324, 319, 315,
85 311, 306, 303, 299,
86 294, 292, 287, 284,
87 280, 277, 273, 270,
88 267, 264, 260, 258,
89 };
90
91 #define COS_LOOKUP_I_SHIFT 9
92 #define COS_LOOKUP_I_MASK 511
93 #define COS_LOOKUP_I_SZ 128
94 static const ogg_int32_t COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={
95 16384, 16379, 16364, 16340,
96 16305, 16261, 16207, 16143,
97 16069, 15986, 15893, 15791,
98 15679, 15557, 15426, 15286,
99 15137, 14978, 14811, 14635,
100 14449, 14256, 14053, 13842,
101 13623, 13395, 13160, 12916,
102 12665, 12406, 12140, 11866,
103 11585, 11297, 11003, 10702,
104 10394, 10080, 9760, 9434,
105 9102, 8765, 8423, 8076,
106 7723, 7366, 7005, 6639,
107 6270, 5897, 5520, 5139,
108 4756, 4370, 3981, 3590,
109 3196, 2801, 2404, 2006,
110 1606, 1205, 804, 402,
111 0, -401, -803, -1204,
112 -1605, -2005, -2403, -2800,
113 -3195, -3589, -3980, -4369,
114 -4755, -5138, -5519, -5896,
115 -6269, -6638, -7004, -7365,
116 -7722, -8075, -8422, -8764,
117 -9101, -9433, -9759, -10079,
118 -10393, -10701, -11002, -11296,
119 -11584, -11865, -12139, -12405,
120 -12664, -12915, -13159, -13394,
121 -13622, -13841, -14052, -14255,
122 -14448, -14634, -14810, -14977,
123 -15136, -15285, -15425, -15556,
124 -15678, -15790, -15892, -15985,
125 -16068, -16142, -16206, -16260,
126 -16304, -16339, -16363, -16378,
127 -16383,
128 };
129
130 #endif
131
132
133
134
135
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: channel mapping 0 implementation
14
15 ********************************************************************/
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <math.h>
21 #include "ogg.h"
22 #include "ivorbiscodec.h"
23 #include "mdct.h"
24 #include "codec_internal.h"
25 #include "codebook.h"
26 #include "window.h"
27 #include "registry.h"
28 #include "misc.h"
29 #include "tremor_shared.h"
30
31 /* simplistic, wasteful way of doing this (unique lookup for each
32 mode/submapping); there should be a central repository for
33 identical lookups. That will require minor work, so I'm putting it
34 off as low priority.
35
36 Why a lookup for each backend in a given mode? Because the
37 blocksize is set by the mode, and low backend lookups may require
38 parameters from other areas of the mode/mapping */
39
40 typedef struct {
41 vorbis_info_mode *mode;
42 vorbis_info_mapping0 *map;
43
44 vorbis_look_floor **floor_look;
45
46 vorbis_look_residue **residue_look;
47
48 vorbis_func_floor **floor_func;
49 vorbis_func_residue **residue_func;
50
51 int ch;
52 long lastframe; /* if a different mode is called, we need to
53 invalidate decay */
54 } vorbis_look_mapping0;
55
56 static void mapping0_free_info(vorbis_info_mapping *i){
57 vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i;
58 if(info){
59 memset(info,0,sizeof(*info));
60 _ogg_free(info);
61 }
62 }
63
64 static void mapping0_free_look(vorbis_look_mapping *look){
65 int i;
66 vorbis_look_mapping0 *l=(vorbis_look_mapping0 *)look;
67 if(l){
68
69 for(i=0;i<l->map->submaps;i++){
70 l->floor_func[i]->free_look(l->floor_look[i]);
71 l->residue_func[i]->free_look(l->residue_look[i]);
72 }
73
74 _ogg_free(l->floor_func);
75 _ogg_free(l->residue_func);
76 _ogg_free(l->floor_look);
77 _ogg_free(l->residue_look);
78 memset(l,0,sizeof(*l));
79 _ogg_free(l);
80 }
81 }
82
83 static vorbis_look_mapping *mapping0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
84 vorbis_info_mapping *m){
85 int i;
86 vorbis_info *vi=vd->vi;
87 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
88 vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)_ogg_calloc(1,sizeof(*look));
89 vorbis_info_mapping0 *info=look->map=(vorbis_info_mapping0 *)m;
90 look->mode=vm;
91
92 look->floor_look=(vorbis_look_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_look));
93
94 look->residue_look=(vorbis_look_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_look));
95
96 look->floor_func=(vorbis_func_floor **)_ogg_calloc(info->submaps,sizeof(*look->floor_func));
97 look->residue_func=(vorbis_func_residue **)_ogg_calloc(info->submaps,sizeof(*look->residue_func));
98
99 for(i=0;i<info->submaps;i++){
100 int floornum=info->floorsubmap[i];
101 int resnum=info->residuesubmap[i];
102
103 look->floor_func[i]=_floor_P[ci->floor_type[floornum]];
104 look->floor_look[i]=look->floor_func[i]->
105 look(vd,vm,ci->floor_param[floornum]);
106 look->residue_func[i]=_residue_P[ci->residue_type[resnum]];
107 look->residue_look[i]=look->residue_func[i]->
108 look(vd,vm,ci->residue_param[resnum]);
109
110 }
111
112 look->ch=vi->channels;
113
114 return(look);
115 }
116
117 /* also responsible for range checking */
118 static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){
119 int i,b;
120 vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)_ogg_calloc(1,sizeof(*info));
121 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
122 memset(info,0,sizeof(*info));
123
124 b=oggpack_read(opb,1);
125 if(b<0)goto err_out;
126 if(b){
127 info->submaps=oggpack_read(opb,4)+1;
128 if(info->submaps<=0)goto err_out;
129 }else
130 info->submaps=1;
131
132 b=oggpack_read(opb,1);
133 if(b<0)goto err_out;
134 if(b){
135 info->coupling_steps=oggpack_read(opb,8)+1;
136 if(info->coupling_steps<=0)goto err_out;
137 for(i=0;i<info->coupling_steps;i++){
138 int testM=info->coupling_mag[i]=oggpack_read(opb,ilog(vi->channels));
139 int testA=info->coupling_ang[i]=oggpack_read(opb,ilog(vi->channels));
140
141 if(testM<0 ||
142 testA<0 ||
143 testM==testA ||
144 testM>=vi->channels ||
145 testA>=vi->channels) goto err_out;
146 }
147
148 }
149
150 if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */
151
152 if(info->submaps>1){
153 for(i=0;i<vi->channels;i++){
154 info->chmuxlist[i]=oggpack_read(opb,4);
155 if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out;
156 }
157 }
158 for(i=0;i<info->submaps;i++){
159 int temp=oggpack_read(opb,8);
160 if(temp>=ci->times)goto err_out;
161 info->floorsubmap[i]=oggpack_read(opb,8);
162 if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out;
163 info->residuesubmap[i]=oggpack_read(opb,8);
164 if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0)
165 goto err_out;
166 }
167
168 return info;
169
170 err_out:
171 mapping0_free_info(info);
172 return(NULL);
173 }
174
175 static int seq=0;
176 static int mapping0_inverse(vorbis_block *vb,vorbis_look_mapping *l){
177 vorbis_dsp_state *vd=vb->vd;
178 vorbis_info *vi=vd->vi;
179 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
180 private_state *b=(private_state *)vd->backend_state;
181 vorbis_look_mapping0 *look=(vorbis_look_mapping0 *)l;
182 vorbis_info_mapping0 *info=look->map;
183
184 int i,j;
185 long n=vb->pcmend=ci->blocksizes[vb->W];
186
187 ogg_int32_t **pcmbundle=(ogg_int32_t **)alloca(sizeof(*pcmbundle)*vi->channels);
188 int *zerobundle=(int *)alloca(sizeof(*zerobundle)*vi->channels);
189
190 int *nonzero =(int *)alloca(sizeof(*nonzero)*vi->channels);
191 void **floormemo=(void **)alloca(sizeof(*floormemo)*vi->channels);
192
193 /* time domain information decode (note that applying the
194 information would have to happen later; we'll probably add a
195 function entry to the harness for that later */
196 /* NOT IMPLEMENTED */
197
198 /* recover the spectral envelope; store it in the PCM vector for now */
199 for(i=0;i<vi->channels;i++){
200 int submap=info->chmuxlist[i];
201 floormemo[i]=look->floor_func[submap]->
202 inverse1(vb,look->floor_look[submap]);
203 if(floormemo[i])
204 nonzero[i]=1;
205 else
206 nonzero[i]=0;
207 memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2);
208 }
209
210 /* channel coupling can 'dirty' the nonzero listing */
211 for(i=0;i<info->coupling_steps;i++){
212 if(nonzero[info->coupling_mag[i]] ||
213 nonzero[info->coupling_ang[i]]){
214 nonzero[info->coupling_mag[i]]=1;
215 nonzero[info->coupling_ang[i]]=1;
216 }
217 }
218
219 /* recover the residue into our working vectors */
220 for(i=0;i<info->submaps;i++){
221 int ch_in_bundle=0;
222 for(j=0;j<vi->channels;j++){
223 if(info->chmuxlist[j]==i){
224 if(nonzero[j])
225 zerobundle[ch_in_bundle]=1;
226 else
227 zerobundle[ch_in_bundle]=0;
228 pcmbundle[ch_in_bundle++]=vb->pcm[j];
229 }
230 }
231
232 look->residue_func[i]->inverse(vb,look->residue_look[i],
233 pcmbundle,zerobundle,ch_in_bundle);
234 }
235
236 //for(j=0;j<vi->channels;j++)
237 //_analysis_output("coupled",seq+j,vb->pcm[j],-8,n/2,0,0);
238
239
240 /* channel coupling */
241 for(i=info->coupling_steps-1;i>=0;i--){
242 ogg_int32_t *pcmM=vb->pcm[info->coupling_mag[i]];
243 ogg_int32_t *pcmA=vb->pcm[info->coupling_ang[i]];
244
245 for(j=0;j<n/2;j++){
246 ogg_int32_t mag=pcmM[j];
247 ogg_int32_t ang=pcmA[j];
248
249 if(mag>0)
250 if(ang>0){
251 pcmM[j]=mag;
252 pcmA[j]=mag-ang;
253 }else{
254 pcmA[j]=mag;
255 pcmM[j]=mag+ang;
256 }
257 else
258 if(ang>0){
259 pcmM[j]=mag;
260 pcmA[j]=mag+ang;
261 }else{
262 pcmA[j]=mag;
263 pcmM[j]=mag-ang;
264 }
265 }
266 }
267
268 //for(j=0;j<vi->channels;j++)
269 //_analysis_output("residue",seq+j,vb->pcm[j],-8,n/2,0,0);
270
271 /* compute and apply spectral envelope */
272 for(i=0;i<vi->channels;i++){
273 ogg_int32_t *pcm=vb->pcm[i];
274 int submap=info->chmuxlist[i];
275 look->floor_func[submap]->
276 inverse2(vb,look->floor_look[submap],floormemo[i],pcm);
277 }
278
279 //for(j=0;j<vi->channels;j++)
280 //_analysis_output("mdct",seq+j,vb->pcm[j],-24,n/2,0,1);
281
282 /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */
283 /* only MDCT right now.... */
284 for(i=0;i<vi->channels;i++){
285 ogg_int32_t *pcm=vb->pcm[i];
286 mdct_backward(n,pcm,pcm);
287 }
288
289 //for(j=0;j<vi->channels;j++)
290 //_analysis_output("imdct",seq+j,vb->pcm[j],-24,n,0,0);
291
292 /* window the data */
293 for(i=0;i<vi->channels;i++){
294 ogg_int32_t *pcm=vb->pcm[i];
295 if(nonzero[i])
296 _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW);
297 else
298 for(j=0;j<n;j++)
299 pcm[j]=0;
300
301 }
302
303 //for(j=0;j<vi->channels;j++)
304 //_analysis_output("window",seq+j,vb->pcm[j],-24,n,0,0);
305
306 seq+=vi->channels;
307 /* all done! */
308 return(0);
309 }
310
311 /* export hooks */
312 vorbis_func_mapping mapping0_exportbundle={
313 &mapping0_unpack,
314 &mapping0_look,
315 &mapping0_free_info,
316 &mapping0_free_look,
317 &mapping0_inverse
318 };
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: normalized modified discrete cosine transform
14 power of two length transform only [64 <= n ]
15 last mod: $Id: mdct.c,v 1.9 2002/10/16 09:17:39 xiphmont Exp $
16
17 Original algorithm adapted long ago from _The use of multirate filter
18 banks for coding of high quality digital audio_, by T. Sporer,
19 K. Brandenburg and B. Edler, collection of the European Signal
20 Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pp
21 211-214
22
23 The below code implements an algorithm that no longer looks much like
24 that presented in the paper, but the basic structure remains if you
25 dig deep enough to see it.
26
27 This module DOES NOT INCLUDE code to generate/apply the window
28 function. Everybody has their own weird favorite including me... I
29 happen to like the properties of y=sin(.5PI*sin^2(x)), but others may
30 vehemently disagree.
31
32 ********************************************************************/
33
34 #include "ivorbiscodec.h"
35 #include "codebook.h"
36 #include "misc.h"
37 #include "mdct.h"
38 #include "mdct_lookup.h"
39
40
41 /* 8 point butterfly (in place) */
42 STIN void mdct_butterfly_8(DATA_TYPE *x){
43
44 REG_TYPE r0 = x[4] + x[0];
45 REG_TYPE r1 = x[4] - x[0];
46 REG_TYPE r2 = x[5] + x[1];
47 REG_TYPE r3 = x[5] - x[1];
48 REG_TYPE r4 = x[6] + x[2];
49 REG_TYPE r5 = x[6] - x[2];
50 REG_TYPE r6 = x[7] + x[3];
51 REG_TYPE r7 = x[7] - x[3];
52
53 x[0] = r5 + r3;
54 x[1] = r7 - r1;
55 x[2] = r5 - r3;
56 x[3] = r7 + r1;
57 x[4] = r4 - r0;
58 x[5] = r6 - r2;
59 x[6] = r4 + r0;
60 x[7] = r6 + r2;
61 MB();
62 }
63
64 /* 16 point butterfly (in place, 4 register) */
65 STIN void mdct_butterfly_16(DATA_TYPE *x){
66
67 REG_TYPE r0, r1;
68
69 r0 = x[ 0] - x[ 8]; x[ 8] += x[ 0];
70 r1 = x[ 1] - x[ 9]; x[ 9] += x[ 1];
71 x[ 0] = MULT31((r0 + r1) , cPI2_8);
72 x[ 1] = MULT31((r1 - r0) , cPI2_8);
73 MB();
74
75 r0 = x[10] - x[ 2]; x[10] += x[ 2];
76 r1 = x[ 3] - x[11]; x[11] += x[ 3];
77 x[ 2] = r1; x[ 3] = r0;
78 MB();
79
80 r0 = x[12] - x[ 4]; x[12] += x[ 4];
81 r1 = x[13] - x[ 5]; x[13] += x[ 5];
82 x[ 4] = MULT31((r0 - r1) , cPI2_8);
83 x[ 5] = MULT31((r0 + r1) , cPI2_8);
84 MB();
85
86 r0 = x[14] - x[ 6]; x[14] += x[ 6];
87 r1 = x[15] - x[ 7]; x[15] += x[ 7];
88 x[ 6] = r0; x[ 7] = r1;
89 MB();
90
91 mdct_butterfly_8(x);
92 mdct_butterfly_8(x+8);
93 }
94
95 /* 32 point butterfly (in place, 4 register) */
96 STIN void mdct_butterfly_32(DATA_TYPE *x){
97
98 REG_TYPE r0, r1;
99
100 r0 = x[30] - x[14]; x[30] += x[14];
101 r1 = x[31] - x[15]; x[31] += x[15];
102 x[14] = r0; x[15] = r1;
103 MB();
104
105 r0 = x[28] - x[12]; x[28] += x[12];
106 r1 = x[29] - x[13]; x[29] += x[13];
107 XNPROD31( r0, r1, cPI1_8, cPI3_8, &x[12], &x[13] );
108 MB();
109
110 r0 = x[26] - x[10]; x[26] += x[10];
111 r1 = x[27] - x[11]; x[27] += x[11];
112 x[10] = MULT31((r0 - r1) , cPI2_8);
113 x[11] = MULT31((r0 + r1) , cPI2_8);
114 MB();
115
116 r0 = x[24] - x[ 8]; x[24] += x[ 8];
117 r1 = x[25] - x[ 9]; x[25] += x[ 9];
118 XNPROD31( r0, r1, cPI3_8, cPI1_8, &x[ 8], &x[ 9] );
119 MB();
120
121 r0 = x[22] - x[ 6]; x[22] += x[ 6];
122 r1 = x[ 7] - x[23]; x[23] += x[ 7];
123 x[ 6] = r1; x[ 7] = r0;
124 MB();
125
126 r0 = x[ 4] - x[20]; x[20] += x[ 4];
127 r1 = x[ 5] - x[21]; x[21] += x[ 5];
128 XPROD31 ( r0, r1, cPI3_8, cPI1_8, &x[ 4], &x[ 5] );
129 MB();
130
131 r0 = x[ 2] - x[18]; x[18] += x[ 2];
132 r1 = x[ 3] - x[19]; x[19] += x[ 3];
133 x[ 2] = MULT31((r1 + r0) , cPI2_8);
134 x[ 3] = MULT31((r1 - r0) , cPI2_8);
135 MB();
136
137 r0 = x[ 0] - x[16]; x[16] += x[ 0];
138 r1 = x[ 1] - x[17]; x[17] += x[ 1];
139 XPROD31 ( r0, r1, cPI1_8, cPI3_8, &x[ 0], &x[ 1] );
140 MB();
141
142 mdct_butterfly_16(x);
143 mdct_butterfly_16(x+16);
144 }
145
146 /* N/stage point generic N stage butterfly (in place, 2 register) */
147 STIN void mdct_butterfly_generic(DATA_TYPE *x,int points,int step){
148
149 LOOKUP_T *T = sincos_lookup0;
150 DATA_TYPE *x1 = x + points - 8;
151 DATA_TYPE *x2 = x + (points>>1) - 8;
152 REG_TYPE r0;
153 REG_TYPE r1;
154
155 do{
156 r0 = x1[6] - x2[6]; x1[6] += x2[6];
157 r1 = x2[7] - x1[7]; x1[7] += x2[7];
158 XPROD31( r1, r0, T[0], T[1], &x2[6], &x2[7] ); T+=step;
159
160 r0 = x1[4] - x2[4]; x1[4] += x2[4];
161 r1 = x2[5] - x1[5]; x1[5] += x2[5];
162 XPROD31( r1, r0, T[0], T[1], &x2[4], &x2[5] ); T+=step;
163
164 r0 = x1[2] - x2[2]; x1[2] += x2[2];
165 r1 = x2[3] - x1[3]; x1[3] += x2[3];
166 XPROD31( r1, r0, T[0], T[1], &x2[2], &x2[3] ); T+=step;
167
168 r0 = x1[0] - x2[0]; x1[0] += x2[0];
169 r1 = x2[1] - x1[1]; x1[1] += x2[1];
170 XPROD31( r1, r0, T[0], T[1], &x2[0], &x2[1] ); T+=step;
171
172 x1-=8; x2-=8;
173 }while(T<sincos_lookup0+1024);
174 do{
175 r0 = x1[6] - x2[6]; x1[6] += x2[6];
176 r1 = x1[7] - x2[7]; x1[7] += x2[7];
177 XNPROD31( r0, r1, T[0], T[1], &x2[6], &x2[7] ); T-=step;
178
179 r0 = x1[4] - x2[4]; x1[4] += x2[4];
180 r1 = x1[5] - x2[5]; x1[5] += x2[5];
181 XNPROD31( r0, r1, T[0], T[1], &x2[4], &x2[5] ); T-=step;
182
183 r0 = x1[2] - x2[2]; x1[2] += x2[2];
184 r1 = x1[3] - x2[3]; x1[3] += x2[3];
185 XNPROD31( r0, r1, T[0], T[1], &x2[2], &x2[3] ); T-=step;
186
187 r0 = x1[0] - x2[0]; x1[0] += x2[0];
188 r1 = x1[1] - x2[1]; x1[1] += x2[1];
189 XNPROD31( r0, r1, T[0], T[1], &x2[0], &x2[1] ); T-=step;
190
191 x1-=8; x2-=8;
192 }while(T>sincos_lookup0);
193 do{
194 r0 = x2[6] - x1[6]; x1[6] += x2[6];
195 r1 = x2[7] - x1[7]; x1[7] += x2[7];
196 XPROD31( r0, r1, T[0], T[1], &x2[6], &x2[7] ); T+=step;
197
198 r0 = x2[4] - x1[4]; x1[4] += x2[4];
199 r1 = x2[5] - x1[5]; x1[5] += x2[5];
200 XPROD31( r0, r1, T[0], T[1], &x2[4], &x2[5] ); T+=step;
201
202 r0 = x2[2] - x1[2]; x1[2] += x2[2];
203 r1 = x2[3] - x1[3]; x1[3] += x2[3];
204 XPROD31( r0, r1, T[0], T[1], &x2[2], &x2[3] ); T+=step;
205
206 r0 = x2[0] - x1[0]; x1[0] += x2[0];
207 r1 = x2[1] - x1[1]; x1[1] += x2[1];
208 XPROD31( r0, r1, T[0], T[1], &x2[0], &x2[1] ); T+=step;
209
210 x1-=8; x2-=8;
211 }while(T<sincos_lookup0+1024);
212 do{
213 r0 = x1[6] - x2[6]; x1[6] += x2[6];
214 r1 = x2[7] - x1[7]; x1[7] += x2[7];
215 XNPROD31( r1, r0, T[0], T[1], &x2[6], &x2[7] ); T-=step;
216
217 r0 = x1[4] - x2[4]; x1[4] += x2[4];
218 r1 = x2[5] - x1[5]; x1[5] += x2[5];
219 XNPROD31( r1, r0, T[0], T[1], &x2[4], &x2[5] ); T-=step;
220
221 r0 = x1[2] - x2[2]; x1[2] += x2[2];
222 r1 = x2[3] - x1[3]; x1[3] += x2[3];
223 XNPROD31( r1, r0, T[0], T[1], &x2[2], &x2[3] ); T-=step;
224
225 r0 = x1[0] - x2[0]; x1[0] += x2[0];
226 r1 = x2[1] - x1[1]; x1[1] += x2[1];
227 XNPROD31( r1, r0, T[0], T[1], &x2[0], &x2[1] ); T-=step;
228
229 x1-=8; x2-=8;
230 }while(T>sincos_lookup0);
231 }
232
233 STIN void mdct_butterflies(DATA_TYPE *x,int points,int shift){
234
235 int stages=8-shift;
236 int i,j;
237
238 for(i=0;--stages>0;i++){
239 for(j=0;j<(1<<i);j++)
240 mdct_butterfly_generic(x+(points>>i)*j,points>>i,4<<(i+shift));
241 }
242
243 for(j=0;j<points;j+=32)
244 mdct_butterfly_32(x+j);
245
246 }
247
248 static unsigned char bitrev[16]={0,8,4,12,2,10,6,14,1,9,5,13,3,11,7,15};
249
250 STIN int bitrev12(int x){
251 return bitrev[x>>8]|(bitrev[(x&0x0f0)>>4]<<4)|(((int)bitrev[x&0x00f])<<8);
252 }
253
254 STIN void mdct_bitreverse(DATA_TYPE *x,int n,int step,int shift){
255
256 int bit = 0;
257 DATA_TYPE *w0 = x;
258 DATA_TYPE *w1 = x = w0+(n>>1);
259 LOOKUP_T *T = (step>=4)?(sincos_lookup0+(step>>1)):sincos_lookup1;
260 LOOKUP_T *Ttop = T+1024;
261 DATA_TYPE r2;
262
263 do{
264 DATA_TYPE r3 = bitrev12(bit++);
265 DATA_TYPE *x0 = x + ((r3 ^ 0xfff)>>shift) -1;
266 DATA_TYPE *x1 = x + (r3>>shift);
267
268 REG_TYPE r0 = x0[0] + x1[0];
269 REG_TYPE r1 = x1[1] - x0[1];
270
271 XPROD32( r0, r1, T[1], T[0], &r2, &r3 ); T+=step;
272
273 w1 -= 4;
274
275 r0 = (x0[1] + x1[1])>>1;
276 r1 = (x0[0] - x1[0])>>1;
277 w0[0] = r0 + r2;
278 w0[1] = r1 + r3;
279 w1[2] = r0 - r2;
280 w1[3] = r3 - r1;
281
282 r3 = bitrev12(bit++);
283 x0 = x + ((r3 ^ 0xfff)>>shift) -1;
284 x1 = x + (r3>>shift);
285
286 r0 = x0[0] + x1[0];
287 r1 = x1[1] - x0[1];
288
289 XPROD32( r0, r1, T[1], T[0], &r2, &r3 ); T+=step;
290
291 r0 = (x0[1] + x1[1])>>1;
292 r1 = (x0[0] - x1[0])>>1;
293 w0[2] = r0 + r2;
294 w0[3] = r1 + r3;
295 w1[0] = r0 - r2;
296 w1[1] = r3 - r1;
297
298 w0 += 4;
299 }while(T<Ttop);
300 do{
301 DATA_TYPE r3 = bitrev12(bit++);
302 DATA_TYPE *x0 = x + ((r3 ^ 0xfff)>>shift) -1;
303 DATA_TYPE *x1 = x + (r3>>shift);
304
305 REG_TYPE r0 = x0[0] + x1[0];
306 REG_TYPE r1 = x1[1] - x0[1];
307
308 T-=step; XPROD32( r0, r1, T[0], T[1], &r2, &r3 );
309
310 w1 -= 4;
311
312 r0 = (x0[1] + x1[1])>>1;
313 r1 = (x0[0] - x1[0])>>1;
314 w0[0] = r0 + r2;
315 w0[1] = r1 + r3;
316 w1[2] = r0 - r2;
317 w1[3] = r3 - r1;
318
319 r3 = bitrev12(bit++);
320 x0 = x + ((r3 ^ 0xfff)>>shift) -1;
321 x1 = x + (r3>>shift);
322
323 r0 = x0[0] + x1[0];
324 r1 = x1[1] - x0[1];
325
326 T-=step; XPROD32( r0, r1, T[0], T[1], &r2, &r3 );
327
328 r0 = (x0[1] + x1[1])>>1;
329 r1 = (x0[0] - x1[0])>>1;
330 w0[2] = r0 + r2;
331 w0[3] = r1 + r3;
332 w1[0] = r0 - r2;
333 w1[1] = r3 - r1;
334
335 w0 += 4;
336 }while(w0<w1);
337 }
338
339 void mdct_backward(int n, DATA_TYPE *in, DATA_TYPE *out){
340 int n2=n>>1;
341 int n4=n>>2;
342 DATA_TYPE *iX;
343 DATA_TYPE *oX;
344 LOOKUP_T *T;
345 LOOKUP_T *V;
346 int shift;
347 int step;
348
349 for (shift=6;!(n&(1<<shift));shift++);
350 shift=13-shift;
351 step=2<<shift;
352
353 /* rotate */
354
355 iX = in+n2-7;
356 oX = out+n2+n4;
357 T = sincos_lookup0;
358
359 do{
360 oX-=4;
361 XPROD31( iX[4], iX[6], T[0], T[1], &oX[2], &oX[3] ); T+=step;
362 XPROD31( iX[0], iX[2], T[0], T[1], &oX[0], &oX[1] ); T+=step;
363 iX-=8;
364 }while(iX>=in+n4);
365 do{
366 oX-=4;
367 XPROD31( iX[4], iX[6], T[1], T[0], &oX[2], &oX[3] ); T-=step;
368 XPROD31( iX[0], iX[2], T[1], T[0], &oX[0], &oX[1] ); T-=step;
369 iX-=8;
370 }while(iX>=in);
371
372 iX = in+n2-8;
373 oX = out+n2+n4;
374 T = sincos_lookup0;
375
376 do{
377 T+=step; XNPROD31( iX[6], iX[4], T[0], T[1], &oX[0], &oX[1] );
378 T+=step; XNPROD31( iX[2], iX[0], T[0], T[1], &oX[2], &oX[3] );
379 iX-=8;
380 oX+=4;
381 }while(iX>=in+n4);
382 do{
383 T-=step; XNPROD31( iX[6], iX[4], T[1], T[0], &oX[0], &oX[1] );
384 T-=step; XNPROD31( iX[2], iX[0], T[1], T[0], &oX[2], &oX[3] );
385 iX-=8;
386 oX+=4;
387 }while(iX>=in);
388
389 mdct_butterflies(out+n2,n2,shift);
390 mdct_bitreverse(out,n,step,shift);
391
392 /* rotate + window */
393
394 step>>=2;
395 {
396 DATA_TYPE *oX1=out+n2+n4;
397 DATA_TYPE *oX2=out+n2+n4;
398 DATA_TYPE *iX =out;
399
400 switch(step) {
401 default: {
402 T=(step>=4)?(sincos_lookup0+(step>>1)):sincos_lookup1;
403 do{
404 oX1-=4;
405 XPROD31( iX[0], -iX[1], T[0], T[1], &oX1[3], &oX2[0] ); T+=step;
406 XPROD31( iX[2], -iX[3], T[0], T[1], &oX1[2], &oX2[1] ); T+=step;
407 XPROD31( iX[4], -iX[5], T[0], T[1], &oX1[1], &oX2[2] ); T+=step;
408 XPROD31( iX[6], -iX[7], T[0], T[1], &oX1[0], &oX2[3] ); T+=step;
409 oX2+=4;
410 iX+=8;
411 }while(iX<oX1);
412 break;
413 }
414
415 case 1: {
416 /* linear interpolation between table values: offset=0.5, step=1 */
417 REG_TYPE t0,t1,v0,v1;
418 T = sincos_lookup0;
419 V = sincos_lookup1;
420 t0 = (*T++)>>1;
421 t1 = (*T++)>>1;
422 do{
423 oX1-=4;
424
425 t0 += (v0 = (*V++)>>1);
426 t1 += (v1 = (*V++)>>1);
427 XPROD31( iX[0], -iX[1], t0, t1, &oX1[3], &oX2[0] );
428 v0 += (t0 = (*T++)>>1);
429 v1 += (t1 = (*T++)>>1);
430 XPROD31( iX[2], -iX[3], v0, v1, &oX1[2], &oX2[1] );
431 t0 += (v0 = (*V++)>>1);
432 t1 += (v1 = (*V++)>>1);
433 XPROD31( iX[4], -iX[5], t0, t1, &oX1[1], &oX2[2] );
434 v0 += (t0 = (*T++)>>1);
435 v1 += (t1 = (*T++)>>1);
436 XPROD31( iX[6], -iX[7], v0, v1, &oX1[0], &oX2[3] );
437
438 oX2+=4;
439 iX+=8;
440 }while(iX<oX1);
441 break;
442 }
443
444 case 0: {
445 /* linear interpolation between table values: offset=0.25, step=0.5 */
446 REG_TYPE t0,t1,v0,v1,q0,q1;
447 T = sincos_lookup0;
448 V = sincos_lookup1;
449 t0 = *T++;
450 t1 = *T++;
451 do{
452 oX1-=4;
453
454 v0 = *V++;
455 v1 = *V++;
456 t0 += (q0 = (v0-t0)>>2);
457 t1 += (q1 = (v1-t1)>>2);
458 XPROD31( iX[0], -iX[1], t0, t1, &oX1[3], &oX2[0] );
459 t0 = v0-q0;
460 t1 = v1-q1;
461 XPROD31( iX[2], -iX[3], t0, t1, &oX1[2], &oX2[1] );
462
463 t0 = *T++;
464 t1 = *T++;
465 v0 += (q0 = (t0-v0)>>2);
466 v1 += (q1 = (t1-v1)>>2);
467 XPROD31( iX[4], -iX[5], v0, v1, &oX1[1], &oX2[2] );
468 v0 = t0-q0;
469 v1 = t1-q1;
470 XPROD31( iX[6], -iX[7], v0, v1, &oX1[0], &oX2[3] );
471
472 oX2+=4;
473 iX+=8;
474 }while(iX<oX1);
475 break;
476 }
477 }
478
479 iX=out+n2+n4;
480 oX1=out+n4;
481 oX2=oX1;
482
483 do{
484 oX1-=4;
485 iX-=4;
486
487 oX2[0] = -(oX1[3] = iX[3]);
488 oX2[1] = -(oX1[2] = iX[2]);
489 oX2[2] = -(oX1[1] = iX[1]);
490 oX2[3] = -(oX1[0] = iX[0]);
491
492 oX2+=4;
493 }while(oX2<iX);
494
495 iX=out+n2+n4;
496 oX1=out+n2+n4;
497 oX2=out+n2;
498
499 do{
500 oX1-=4;
501 oX1[0]= iX[3];
502 oX1[1]= iX[2];
503 oX1[2]= iX[1];
504 oX1[3]= iX[0];
505 iX+=4;
506 }while(oX1>oX2);
507 }
508 }
509
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: modified discrete cosine transform prototypes
14
15 ********************************************************************/
16
17 #ifndef _OGG_mdct_H_
18 #define _OGG_mdct_H_
19
20 #include "ivorbiscodec.h"
21 #include "misc.h"
22
23 #define DATA_TYPE ogg_int32_t
24 #define REG_TYPE register ogg_int32_t
25
26 #ifdef _LOW_ACCURACY_
27 #define cPI3_8 (0x0062)
28 #define cPI2_8 (0x00b5)
29 #define cPI1_8 (0x00ed)
30 #else
31 #define cPI3_8 (0x30fbc54d)
32 #define cPI2_8 (0x5a82799a)
33 #define cPI1_8 (0x7641af3d)
34 #endif
35
36 extern void mdct_forward(int n, DATA_TYPE *in, DATA_TYPE *out);
37 extern void mdct_backward(int n, DATA_TYPE *in, DATA_TYPE *out);
38
39 #endif
40
41
42
43
44
45
46
47
48
49
50
51
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: sin,cos lookup tables
14
15 ********************************************************************/
16
17 #include "misc.h"
18
19 /* {sin(2*i*PI/4096), cos(2*i*PI/4096)}, with i = 0 to 512 */
20 static const LOOKUP_T sincos_lookup0[1026] = {
21 X(0x00000000), X(0x7fffffff), X(0x003243f5), X(0x7ffff621),
22 X(0x006487e3), X(0x7fffd886), X(0x0096cbc1), X(0x7fffa72c),
23 X(0x00c90f88), X(0x7fff6216), X(0x00fb5330), X(0x7fff0943),
24 X(0x012d96b1), X(0x7ffe9cb2), X(0x015fda03), X(0x7ffe1c65),
25 X(0x01921d20), X(0x7ffd885a), X(0x01c45ffe), X(0x7ffce093),
26 X(0x01f6a297), X(0x7ffc250f), X(0x0228e4e2), X(0x7ffb55ce),
27 X(0x025b26d7), X(0x7ffa72d1), X(0x028d6870), X(0x7ff97c18),
28 X(0x02bfa9a4), X(0x7ff871a2), X(0x02f1ea6c), X(0x7ff75370),
29 X(0x03242abf), X(0x7ff62182), X(0x03566a96), X(0x7ff4dbd9),
30 X(0x0388a9ea), X(0x7ff38274), X(0x03bae8b2), X(0x7ff21553),
31 X(0x03ed26e6), X(0x7ff09478), X(0x041f6480), X(0x7feeffe1),
32 X(0x0451a177), X(0x7fed5791), X(0x0483ddc3), X(0x7feb9b85),
33 X(0x04b6195d), X(0x7fe9cbc0), X(0x04e8543e), X(0x7fe7e841),
34 X(0x051a8e5c), X(0x7fe5f108), X(0x054cc7b1), X(0x7fe3e616),
35 X(0x057f0035), X(0x7fe1c76b), X(0x05b137df), X(0x7fdf9508),
36 X(0x05e36ea9), X(0x7fdd4eec), X(0x0615a48b), X(0x7fdaf519),
37 X(0x0647d97c), X(0x7fd8878e), X(0x067a0d76), X(0x7fd6064c),
38 X(0x06ac406f), X(0x7fd37153), X(0x06de7262), X(0x7fd0c8a3),
39 X(0x0710a345), X(0x7fce0c3e), X(0x0742d311), X(0x7fcb3c23),
40 X(0x077501be), X(0x7fc85854), X(0x07a72f45), X(0x7fc560cf),
41 X(0x07d95b9e), X(0x7fc25596), X(0x080b86c2), X(0x7fbf36aa),
42 X(0x083db0a7), X(0x7fbc040a), X(0x086fd947), X(0x7fb8bdb8),
43 X(0x08a2009a), X(0x7fb563b3), X(0x08d42699), X(0x7fb1f5fc),
44 X(0x09064b3a), X(0x7fae7495), X(0x09386e78), X(0x7faadf7c),
45 X(0x096a9049), X(0x7fa736b4), X(0x099cb0a7), X(0x7fa37a3c),
46 X(0x09cecf89), X(0x7f9faa15), X(0x0a00ece8), X(0x7f9bc640),
47 X(0x0a3308bd), X(0x7f97cebd), X(0x0a6522fe), X(0x7f93c38c),
48 X(0x0a973ba5), X(0x7f8fa4b0), X(0x0ac952aa), X(0x7f8b7227),
49 X(0x0afb6805), X(0x7f872bf3), X(0x0b2d7baf), X(0x7f82d214),
50 X(0x0b5f8d9f), X(0x7f7e648c), X(0x0b919dcf), X(0x7f79e35a),
51 X(0x0bc3ac35), X(0x7f754e80), X(0x0bf5b8cb), X(0x7f70a5fe),
52 X(0x0c27c389), X(0x7f6be9d4), X(0x0c59cc68), X(0x7f671a05),
53 X(0x0c8bd35e), X(0x7f62368f), X(0x0cbdd865), X(0x7f5d3f75),
54 X(0x0cefdb76), X(0x7f5834b7), X(0x0d21dc87), X(0x7f531655),
55 X(0x0d53db92), X(0x7f4de451), X(0x0d85d88f), X(0x7f489eaa),
56 X(0x0db7d376), X(0x7f434563), X(0x0de9cc40), X(0x7f3dd87c),
57 X(0x0e1bc2e4), X(0x7f3857f6), X(0x0e4db75b), X(0x7f32c3d1),
58 X(0x0e7fa99e), X(0x7f2d1c0e), X(0x0eb199a4), X(0x7f2760af),
59 X(0x0ee38766), X(0x7f2191b4), X(0x0f1572dc), X(0x7f1baf1e),
60 X(0x0f475bff), X(0x7f15b8ee), X(0x0f7942c7), X(0x7f0faf25),
61 X(0x0fab272b), X(0x7f0991c4), X(0x0fdd0926), X(0x7f0360cb),
62 X(0x100ee8ad), X(0x7efd1c3c), X(0x1040c5bb), X(0x7ef6c418),
63 X(0x1072a048), X(0x7ef05860), X(0x10a4784b), X(0x7ee9d914),
64 X(0x10d64dbd), X(0x7ee34636), X(0x11082096), X(0x7edc9fc6),
65 X(0x1139f0cf), X(0x7ed5e5c6), X(0x116bbe60), X(0x7ecf1837),
66 X(0x119d8941), X(0x7ec8371a), X(0x11cf516a), X(0x7ec14270),
67 X(0x120116d5), X(0x7eba3a39), X(0x1232d979), X(0x7eb31e78),
68 X(0x1264994e), X(0x7eabef2c), X(0x1296564d), X(0x7ea4ac58),
69 X(0x12c8106f), X(0x7e9d55fc), X(0x12f9c7aa), X(0x7e95ec1a),
70 X(0x132b7bf9), X(0x7e8e6eb2), X(0x135d2d53), X(0x7e86ddc6),
71 X(0x138edbb1), X(0x7e7f3957), X(0x13c0870a), X(0x7e778166),
72 X(0x13f22f58), X(0x7e6fb5f4), X(0x1423d492), X(0x7e67d703),
73 X(0x145576b1), X(0x7e5fe493), X(0x148715ae), X(0x7e57dea7),
74 X(0x14b8b17f), X(0x7e4fc53e), X(0x14ea4a1f), X(0x7e47985b),
75 X(0x151bdf86), X(0x7e3f57ff), X(0x154d71aa), X(0x7e37042a),
76 X(0x157f0086), X(0x7e2e9cdf), X(0x15b08c12), X(0x7e26221f),
77 X(0x15e21445), X(0x7e1d93ea), X(0x16139918), X(0x7e14f242),
78 X(0x16451a83), X(0x7e0c3d29), X(0x1676987f), X(0x7e0374a0),
79 X(0x16a81305), X(0x7dfa98a8), X(0x16d98a0c), X(0x7df1a942),
80 X(0x170afd8d), X(0x7de8a670), X(0x173c6d80), X(0x7ddf9034),
81 X(0x176dd9de), X(0x7dd6668f), X(0x179f429f), X(0x7dcd2981),
82 X(0x17d0a7bc), X(0x7dc3d90d), X(0x1802092c), X(0x7dba7534),
83 X(0x183366e9), X(0x7db0fdf8), X(0x1864c0ea), X(0x7da77359),
84 X(0x18961728), X(0x7d9dd55a), X(0x18c7699b), X(0x7d9423fc),
85 X(0x18f8b83c), X(0x7d8a5f40), X(0x192a0304), X(0x7d808728),
86 X(0x195b49ea), X(0x7d769bb5), X(0x198c8ce7), X(0x7d6c9ce9),
87 X(0x19bdcbf3), X(0x7d628ac6), X(0x19ef0707), X(0x7d58654d),
88 X(0x1a203e1b), X(0x7d4e2c7f), X(0x1a517128), X(0x7d43e05e),
89 X(0x1a82a026), X(0x7d3980ec), X(0x1ab3cb0d), X(0x7d2f0e2b),
90 X(0x1ae4f1d6), X(0x7d24881b), X(0x1b161479), X(0x7d19eebf),
91 X(0x1b4732ef), X(0x7d0f4218), X(0x1b784d30), X(0x7d048228),
92 X(0x1ba96335), X(0x7cf9aef0), X(0x1bda74f6), X(0x7ceec873),
93 X(0x1c0b826a), X(0x7ce3ceb2), X(0x1c3c8b8c), X(0x7cd8c1ae),
94 X(0x1c6d9053), X(0x7ccda169), X(0x1c9e90b8), X(0x7cc26de5),
95 X(0x1ccf8cb3), X(0x7cb72724), X(0x1d00843d), X(0x7cabcd28),
96 X(0x1d31774d), X(0x7ca05ff1), X(0x1d6265dd), X(0x7c94df83),
97 X(0x1d934fe5), X(0x7c894bde), X(0x1dc4355e), X(0x7c7da505),
98 X(0x1df5163f), X(0x7c71eaf9), X(0x1e25f282), X(0x7c661dbc),
99 X(0x1e56ca1e), X(0x7c5a3d50), X(0x1e879d0d), X(0x7c4e49b7),
100 X(0x1eb86b46), X(0x7c4242f2), X(0x1ee934c3), X(0x7c362904),
101 X(0x1f19f97b), X(0x7c29fbee), X(0x1f4ab968), X(0x7c1dbbb3),
102 X(0x1f7b7481), X(0x7c116853), X(0x1fac2abf), X(0x7c0501d2),
103 X(0x1fdcdc1b), X(0x7bf88830), X(0x200d888d), X(0x7bebfb70),
104 X(0x203e300d), X(0x7bdf5b94), X(0x206ed295), X(0x7bd2a89e),
105 X(0x209f701c), X(0x7bc5e290), X(0x20d0089c), X(0x7bb9096b),
106 X(0x21009c0c), X(0x7bac1d31), X(0x21312a65), X(0x7b9f1de6),
107 X(0x2161b3a0), X(0x7b920b89), X(0x219237b5), X(0x7b84e61f),
108 X(0x21c2b69c), X(0x7b77ada8), X(0x21f3304f), X(0x7b6a6227),
109 X(0x2223a4c5), X(0x7b5d039e), X(0x225413f8), X(0x7b4f920e),
110 X(0x22847de0), X(0x7b420d7a), X(0x22b4e274), X(0x7b3475e5),
111 X(0x22e541af), X(0x7b26cb4f), X(0x23159b88), X(0x7b190dbc),
112 X(0x2345eff8), X(0x7b0b3d2c), X(0x23763ef7), X(0x7afd59a4),
113 X(0x23a6887f), X(0x7aef6323), X(0x23d6cc87), X(0x7ae159ae),
114 X(0x24070b08), X(0x7ad33d45), X(0x243743fa), X(0x7ac50dec),
115 X(0x24677758), X(0x7ab6cba4), X(0x2497a517), X(0x7aa8766f),
116 X(0x24c7cd33), X(0x7a9a0e50), X(0x24f7efa2), X(0x7a8b9348),
117 X(0x25280c5e), X(0x7a7d055b), X(0x2558235f), X(0x7a6e648a),
118 X(0x2588349d), X(0x7a5fb0d8), X(0x25b84012), X(0x7a50ea47),
119 X(0x25e845b6), X(0x7a4210d8), X(0x26184581), X(0x7a332490),
120 X(0x26483f6c), X(0x7a24256f), X(0x26783370), X(0x7a151378),
121 X(0x26a82186), X(0x7a05eead), X(0x26d809a5), X(0x79f6b711),
122 X(0x2707ebc7), X(0x79e76ca7), X(0x2737c7e3), X(0x79d80f6f),
123 X(0x27679df4), X(0x79c89f6e), X(0x27976df1), X(0x79b91ca4),
124 X(0x27c737d3), X(0x79a98715), X(0x27f6fb92), X(0x7999dec4),
125 X(0x2826b928), X(0x798a23b1), X(0x2856708d), X(0x797a55e0),
126 X(0x288621b9), X(0x796a7554), X(0x28b5cca5), X(0x795a820e),
127 X(0x28e5714b), X(0x794a7c12), X(0x29150fa1), X(0x793a6361),
128 X(0x2944a7a2), X(0x792a37fe), X(0x29743946), X(0x7919f9ec),
129 X(0x29a3c485), X(0x7909a92d), X(0x29d34958), X(0x78f945c3),
130 X(0x2a02c7b8), X(0x78e8cfb2), X(0x2a323f9e), X(0x78d846fb),
131 X(0x2a61b101), X(0x78c7aba2), X(0x2a911bdc), X(0x78b6fda8),
132 X(0x2ac08026), X(0x78a63d11), X(0x2aefddd8), X(0x789569df),
133 X(0x2b1f34eb), X(0x78848414), X(0x2b4e8558), X(0x78738bb3),
134 X(0x2b7dcf17), X(0x786280bf), X(0x2bad1221), X(0x7851633b),
135 X(0x2bdc4e6f), X(0x78403329), X(0x2c0b83fa), X(0x782ef08b),
136 X(0x2c3ab2b9), X(0x781d9b65), X(0x2c69daa6), X(0x780c33b8),
137 X(0x2c98fbba), X(0x77fab989), X(0x2cc815ee), X(0x77e92cd9),
138 X(0x2cf72939), X(0x77d78daa), X(0x2d263596), X(0x77c5dc01),
139 X(0x2d553afc), X(0x77b417df), X(0x2d843964), X(0x77a24148),
140 X(0x2db330c7), X(0x7790583e), X(0x2de2211e), X(0x777e5cc3),
141 X(0x2e110a62), X(0x776c4edb), X(0x2e3fec8b), X(0x775a2e89),
142 X(0x2e6ec792), X(0x7747fbce), X(0x2e9d9b70), X(0x7735b6af),
143 X(0x2ecc681e), X(0x77235f2d), X(0x2efb2d95), X(0x7710f54c),
144 X(0x2f29ebcc), X(0x76fe790e), X(0x2f58a2be), X(0x76ebea77),
145 X(0x2f875262), X(0x76d94989), X(0x2fb5fab2), X(0x76c69647),
146 X(0x2fe49ba7), X(0x76b3d0b4), X(0x30133539), X(0x76a0f8d2),
147 X(0x3041c761), X(0x768e0ea6), X(0x30705217), X(0x767b1231),
148 X(0x309ed556), X(0x76680376), X(0x30cd5115), X(0x7654e279),
149 X(0x30fbc54d), X(0x7641af3d), X(0x312a31f8), X(0x762e69c4),
150 X(0x3158970e), X(0x761b1211), X(0x3186f487), X(0x7607a828),
151 X(0x31b54a5e), X(0x75f42c0b), X(0x31e39889), X(0x75e09dbd),
152 X(0x3211df04), X(0x75ccfd42), X(0x32401dc6), X(0x75b94a9c),
153 X(0x326e54c7), X(0x75a585cf), X(0x329c8402), X(0x7591aedd),
154 X(0x32caab6f), X(0x757dc5ca), X(0x32f8cb07), X(0x7569ca99),
155 X(0x3326e2c3), X(0x7555bd4c), X(0x3354f29b), X(0x75419de7),
156 X(0x3382fa88), X(0x752d6c6c), X(0x33b0fa84), X(0x751928e0),
157 X(0x33def287), X(0x7504d345), X(0x340ce28b), X(0x74f06b9e),
158 X(0x343aca87), X(0x74dbf1ef), X(0x3468aa76), X(0x74c7663a),
159 X(0x34968250), X(0x74b2c884), X(0x34c4520d), X(0x749e18cd),
160 X(0x34f219a8), X(0x7489571c), X(0x351fd918), X(0x74748371),
161 X(0x354d9057), X(0x745f9dd1), X(0x357b3f5d), X(0x744aa63f),
162 X(0x35a8e625), X(0x74359cbd), X(0x35d684a6), X(0x74208150),
163 X(0x36041ad9), X(0x740b53fb), X(0x3631a8b8), X(0x73f614c0),
164 X(0x365f2e3b), X(0x73e0c3a3), X(0x368cab5c), X(0x73cb60a8),
165 X(0x36ba2014), X(0x73b5ebd1), X(0x36e78c5b), X(0x73a06522),
166 X(0x3714f02a), X(0x738acc9e), X(0x37424b7b), X(0x73752249),
167 X(0x376f9e46), X(0x735f6626), X(0x379ce885), X(0x73499838),
168 X(0x37ca2a30), X(0x7333b883), X(0x37f76341), X(0x731dc70a),
169 X(0x382493b0), X(0x7307c3d0), X(0x3851bb77), X(0x72f1aed9),
170 X(0x387eda8e), X(0x72db8828), X(0x38abf0ef), X(0x72c54fc1),
171 X(0x38d8fe93), X(0x72af05a7), X(0x39060373), X(0x7298a9dd),
172 X(0x3932ff87), X(0x72823c67), X(0x395ff2c9), X(0x726bbd48),
173 X(0x398cdd32), X(0x72552c85), X(0x39b9bebc), X(0x723e8a20),
174 X(0x39e6975e), X(0x7227d61c), X(0x3a136712), X(0x7211107e),
175 X(0x3a402dd2), X(0x71fa3949), X(0x3a6ceb96), X(0x71e35080),
176 X(0x3a99a057), X(0x71cc5626), X(0x3ac64c0f), X(0x71b54a41),
177 X(0x3af2eeb7), X(0x719e2cd2), X(0x3b1f8848), X(0x7186fdde),
178 X(0x3b4c18ba), X(0x716fbd68), X(0x3b78a007), X(0x71586b74),
179 X(0x3ba51e29), X(0x71410805), X(0x3bd19318), X(0x7129931f),
180 X(0x3bfdfecd), X(0x71120cc5), X(0x3c2a6142), X(0x70fa74fc),
181 X(0x3c56ba70), X(0x70e2cbc6), X(0x3c830a50), X(0x70cb1128),
182 X(0x3caf50da), X(0x70b34525), X(0x3cdb8e09), X(0x709b67c0),
183 X(0x3d07c1d6), X(0x708378ff), X(0x3d33ec39), X(0x706b78e3),
184 X(0x3d600d2c), X(0x70536771), X(0x3d8c24a8), X(0x703b44ad),
185 X(0x3db832a6), X(0x7023109a), X(0x3de4371f), X(0x700acb3c),
186 X(0x3e10320d), X(0x6ff27497), X(0x3e3c2369), X(0x6fda0cae),
187 X(0x3e680b2c), X(0x6fc19385), X(0x3e93e950), X(0x6fa90921),
188 X(0x3ebfbdcd), X(0x6f906d84), X(0x3eeb889c), X(0x6f77c0b3),
189 X(0x3f1749b8), X(0x6f5f02b2), X(0x3f430119), X(0x6f463383),
190 X(0x3f6eaeb8), X(0x6f2d532c), X(0x3f9a5290), X(0x6f1461b0),
191 X(0x3fc5ec98), X(0x6efb5f12), X(0x3ff17cca), X(0x6ee24b57),
192 X(0x401d0321), X(0x6ec92683), X(0x40487f94), X(0x6eaff099),
193 X(0x4073f21d), X(0x6e96a99d), X(0x409f5ab6), X(0x6e7d5193),
194 X(0x40cab958), X(0x6e63e87f), X(0x40f60dfb), X(0x6e4a6e66),
195 X(0x4121589b), X(0x6e30e34a), X(0x414c992f), X(0x6e174730),
196 X(0x4177cfb1), X(0x6dfd9a1c), X(0x41a2fc1a), X(0x6de3dc11),
197 X(0x41ce1e65), X(0x6dca0d14), X(0x41f93689), X(0x6db02d29),
198 X(0x42244481), X(0x6d963c54), X(0x424f4845), X(0x6d7c3a98),
199 X(0x427a41d0), X(0x6d6227fa), X(0x42a5311b), X(0x6d48047e),
200 X(0x42d0161e), X(0x6d2dd027), X(0x42faf0d4), X(0x6d138afb),
201 X(0x4325c135), X(0x6cf934fc), X(0x4350873c), X(0x6cdece2f),
202 X(0x437b42e1), X(0x6cc45698), X(0x43a5f41e), X(0x6ca9ce3b),
203 X(0x43d09aed), X(0x6c8f351c), X(0x43fb3746), X(0x6c748b3f),
204 X(0x4425c923), X(0x6c59d0a9), X(0x4450507e), X(0x6c3f055d),
205 X(0x447acd50), X(0x6c242960), X(0x44a53f93), X(0x6c093cb6),
206 X(0x44cfa740), X(0x6bee3f62), X(0x44fa0450), X(0x6bd3316a),
207 X(0x452456bd), X(0x6bb812d1), X(0x454e9e80), X(0x6b9ce39b),
208 X(0x4578db93), X(0x6b81a3cd), X(0x45a30df0), X(0x6b66536b),
209 X(0x45cd358f), X(0x6b4af279), X(0x45f7526b), X(0x6b2f80fb),
210 X(0x4621647d), X(0x6b13fef5), X(0x464b6bbe), X(0x6af86c6c),
211 X(0x46756828), X(0x6adcc964), X(0x469f59b4), X(0x6ac115e2),
212 X(0x46c9405c), X(0x6aa551e9), X(0x46f31c1a), X(0x6a897d7d),
213 X(0x471cece7), X(0x6a6d98a4), X(0x4746b2bc), X(0x6a51a361),
214 X(0x47706d93), X(0x6a359db9), X(0x479a1d67), X(0x6a1987b0),
215 X(0x47c3c22f), X(0x69fd614a), X(0x47ed5be6), X(0x69e12a8c),
216 X(0x4816ea86), X(0x69c4e37a), X(0x48406e08), X(0x69a88c19),
217 X(0x4869e665), X(0x698c246c), X(0x48935397), X(0x696fac78),
218 X(0x48bcb599), X(0x69532442), X(0x48e60c62), X(0x69368bce),
219 X(0x490f57ee), X(0x6919e320), X(0x49389836), X(0x68fd2a3d),
220 X(0x4961cd33), X(0x68e06129), X(0x498af6df), X(0x68c387e9),
221 X(0x49b41533), X(0x68a69e81), X(0x49dd282a), X(0x6889a4f6),
222 X(0x4a062fbd), X(0x686c9b4b), X(0x4a2f2be6), X(0x684f8186),
223 X(0x4a581c9e), X(0x683257ab), X(0x4a8101de), X(0x68151dbe),
224 X(0x4aa9dba2), X(0x67f7d3c5), X(0x4ad2a9e2), X(0x67da79c3),
225 X(0x4afb6c98), X(0x67bd0fbd), X(0x4b2423be), X(0x679f95b7),
226 X(0x4b4ccf4d), X(0x67820bb7), X(0x4b756f40), X(0x676471c0),
227 X(0x4b9e0390), X(0x6746c7d8), X(0x4bc68c36), X(0x67290e02),
228 X(0x4bef092d), X(0x670b4444), X(0x4c177a6e), X(0x66ed6aa1),
229 X(0x4c3fdff4), X(0x66cf8120), X(0x4c6839b7), X(0x66b187c3),
230 X(0x4c9087b1), X(0x66937e91), X(0x4cb8c9dd), X(0x6675658c),
231 X(0x4ce10034), X(0x66573cbb), X(0x4d092ab0), X(0x66390422),
232 X(0x4d31494b), X(0x661abbc5), X(0x4d595bfe), X(0x65fc63a9),
233 X(0x4d8162c4), X(0x65ddfbd3), X(0x4da95d96), X(0x65bf8447),
234 X(0x4dd14c6e), X(0x65a0fd0b), X(0x4df92f46), X(0x65826622),
235 X(0x4e210617), X(0x6563bf92), X(0x4e48d0dd), X(0x6545095f),
236 X(0x4e708f8f), X(0x6526438f), X(0x4e984229), X(0x65076e25),
237 X(0x4ebfe8a5), X(0x64e88926), X(0x4ee782fb), X(0x64c99498),
238 X(0x4f0f1126), X(0x64aa907f), X(0x4f369320), X(0x648b7ce0),
239 X(0x4f5e08e3), X(0x646c59bf), X(0x4f857269), X(0x644d2722),
240 X(0x4faccfab), X(0x642de50d), X(0x4fd420a4), X(0x640e9386),
241 X(0x4ffb654d), X(0x63ef3290), X(0x50229da1), X(0x63cfc231),
242 X(0x5049c999), X(0x63b0426d), X(0x5070e92f), X(0x6390b34a),
243 X(0x5097fc5e), X(0x637114cc), X(0x50bf031f), X(0x635166f9),
244 X(0x50e5fd6d), X(0x6331a9d4), X(0x510ceb40), X(0x6311dd64),
245 X(0x5133cc94), X(0x62f201ac), X(0x515aa162), X(0x62d216b3),
246 X(0x518169a5), X(0x62b21c7b), X(0x51a82555), X(0x6292130c),
247 X(0x51ced46e), X(0x6271fa69), X(0x51f576ea), X(0x6251d298),
248 X(0x521c0cc2), X(0x62319b9d), X(0x524295f0), X(0x6211557e),
249 X(0x5269126e), X(0x61f1003f), X(0x528f8238), X(0x61d09be5),
250 X(0x52b5e546), X(0x61b02876), X(0x52dc3b92), X(0x618fa5f7),
251 X(0x53028518), X(0x616f146c), X(0x5328c1d0), X(0x614e73da),
252 X(0x534ef1b5), X(0x612dc447), X(0x537514c2), X(0x610d05b7),
253 X(0x539b2af0), X(0x60ec3830), X(0x53c13439), X(0x60cb5bb7),
254 X(0x53e73097), X(0x60aa7050), X(0x540d2005), X(0x60897601),
255 X(0x5433027d), X(0x60686ccf), X(0x5458d7f9), X(0x604754bf),
256 X(0x547ea073), X(0x60262dd6), X(0x54a45be6), X(0x6004f819),
257 X(0x54ca0a4b), X(0x5fe3b38d), X(0x54efab9c), X(0x5fc26038),
258 X(0x55153fd4), X(0x5fa0fe1f), X(0x553ac6ee), X(0x5f7f8d46),
259 X(0x556040e2), X(0x5f5e0db3), X(0x5585adad), X(0x5f3c7f6b),
260 X(0x55ab0d46), X(0x5f1ae274), X(0x55d05faa), X(0x5ef936d1),
261 X(0x55f5a4d2), X(0x5ed77c8a), X(0x561adcb9), X(0x5eb5b3a2),
262 X(0x56400758), X(0x5e93dc1f), X(0x566524aa), X(0x5e71f606),
263 X(0x568a34a9), X(0x5e50015d), X(0x56af3750), X(0x5e2dfe29),
264 X(0x56d42c99), X(0x5e0bec6e), X(0x56f9147e), X(0x5de9cc33),
265 X(0x571deefa), X(0x5dc79d7c), X(0x5742bc06), X(0x5da5604f),
266 X(0x57677b9d), X(0x5d8314b1), X(0x578c2dba), X(0x5d60baa7),
267 X(0x57b0d256), X(0x5d3e5237), X(0x57d5696d), X(0x5d1bdb65),
268 X(0x57f9f2f8), X(0x5cf95638), X(0x581e6ef1), X(0x5cd6c2b5),
269 X(0x5842dd54), X(0x5cb420e0), X(0x58673e1b), X(0x5c9170bf),
270 X(0x588b9140), X(0x5c6eb258), X(0x58afd6bd), X(0x5c4be5b0),
271 X(0x58d40e8c), X(0x5c290acc), X(0x58f838a9), X(0x5c0621b2),
272 X(0x591c550e), X(0x5be32a67), X(0x594063b5), X(0x5bc024f0),
273 X(0x59646498), X(0x5b9d1154), X(0x598857b2), X(0x5b79ef96),
274 X(0x59ac3cfd), X(0x5b56bfbd), X(0x59d01475), X(0x5b3381ce),
275 X(0x59f3de12), X(0x5b1035cf), X(0x5a1799d1), X(0x5aecdbc5),
276 X(0x5a3b47ab), X(0x5ac973b5), X(0x5a5ee79a), X(0x5aa5fda5),
277 X(0x5a82799a), X(0x5a82799a)
278 };
279
280 /* {sin((2*i+1)*PI/4096), cos((2*i+1)*PI/4096)}, with i = 0 to 511 */
281 static const LOOKUP_T sincos_lookup1[1024] = {
282 X(0x001921fb), X(0x7ffffd88), X(0x004b65ee), X(0x7fffe9cb),
283 X(0x007da9d4), X(0x7fffc251), X(0x00afeda8), X(0x7fff8719),
284 X(0x00e23160), X(0x7fff3824), X(0x011474f6), X(0x7ffed572),
285 X(0x0146b860), X(0x7ffe5f03), X(0x0178fb99), X(0x7ffdd4d7),
286 X(0x01ab3e97), X(0x7ffd36ee), X(0x01dd8154), X(0x7ffc8549),
287 X(0x020fc3c6), X(0x7ffbbfe6), X(0x024205e8), X(0x7ffae6c7),
288 X(0x027447b0), X(0x7ff9f9ec), X(0x02a68917), X(0x7ff8f954),
289 X(0x02d8ca16), X(0x7ff7e500), X(0x030b0aa4), X(0x7ff6bcf0),
290 X(0x033d4abb), X(0x7ff58125), X(0x036f8a51), X(0x7ff4319d),
291 X(0x03a1c960), X(0x7ff2ce5b), X(0x03d407df), X(0x7ff1575d),
292 X(0x040645c7), X(0x7fefcca4), X(0x04388310), X(0x7fee2e30),
293 X(0x046abfb3), X(0x7fec7c02), X(0x049cfba7), X(0x7feab61a),
294 X(0x04cf36e5), X(0x7fe8dc78), X(0x05017165), X(0x7fe6ef1c),
295 X(0x0533ab20), X(0x7fe4ee06), X(0x0565e40d), X(0x7fe2d938),
296 X(0x05981c26), X(0x7fe0b0b1), X(0x05ca5361), X(0x7fde7471),
297 X(0x05fc89b8), X(0x7fdc247a), X(0x062ebf22), X(0x7fd9c0ca),
298 X(0x0660f398), X(0x7fd74964), X(0x06932713), X(0x7fd4be46),
299 X(0x06c5598a), X(0x7fd21f72), X(0x06f78af6), X(0x7fcf6ce8),
300 X(0x0729bb4e), X(0x7fcca6a7), X(0x075bea8c), X(0x7fc9ccb2),
301 X(0x078e18a7), X(0x7fc6df08), X(0x07c04598), X(0x7fc3dda9),
302 X(0x07f27157), X(0x7fc0c896), X(0x08249bdd), X(0x7fbd9fd0),
303 X(0x0856c520), X(0x7fba6357), X(0x0888ed1b), X(0x7fb7132b),
304 X(0x08bb13c5), X(0x7fb3af4e), X(0x08ed3916), X(0x7fb037bf),
305 X(0x091f5d06), X(0x7facac7f), X(0x09517f8f), X(0x7fa90d8e),
306 X(0x0983a0a7), X(0x7fa55aee), X(0x09b5c048), X(0x7fa1949e),
307 X(0x09e7de6a), X(0x7f9dbaa0), X(0x0a19fb04), X(0x7f99ccf4),
308 X(0x0a4c1610), X(0x7f95cb9a), X(0x0a7e2f85), X(0x7f91b694),
309 X(0x0ab0475c), X(0x7f8d8de1), X(0x0ae25d8d), X(0x7f895182),
310 X(0x0b147211), X(0x7f850179), X(0x0b4684df), X(0x7f809dc5),
311 X(0x0b7895f0), X(0x7f7c2668), X(0x0baaa53b), X(0x7f779b62),
312 X(0x0bdcb2bb), X(0x7f72fcb4), X(0x0c0ebe66), X(0x7f6e4a5e),
313 X(0x0c40c835), X(0x7f698461), X(0x0c72d020), X(0x7f64aabf),
314 X(0x0ca4d620), X(0x7f5fbd77), X(0x0cd6da2d), X(0x7f5abc8a),
315 X(0x0d08dc3f), X(0x7f55a7fa), X(0x0d3adc4e), X(0x7f507fc7),
316 X(0x0d6cda53), X(0x7f4b43f2), X(0x0d9ed646), X(0x7f45f47b),
317 X(0x0dd0d01f), X(0x7f409164), X(0x0e02c7d7), X(0x7f3b1aad),
318 X(0x0e34bd66), X(0x7f359057), X(0x0e66b0c3), X(0x7f2ff263),
319 X(0x0e98a1e9), X(0x7f2a40d2), X(0x0eca90ce), X(0x7f247ba5),
320 X(0x0efc7d6b), X(0x7f1ea2dc), X(0x0f2e67b8), X(0x7f18b679),
321 X(0x0f604faf), X(0x7f12b67c), X(0x0f923546), X(0x7f0ca2e7),
322 X(0x0fc41876), X(0x7f067bba), X(0x0ff5f938), X(0x7f0040f6),
323 X(0x1027d784), X(0x7ef9f29d), X(0x1059b352), X(0x7ef390ae),
324 X(0x108b8c9b), X(0x7eed1b2c), X(0x10bd6356), X(0x7ee69217),
325 X(0x10ef377d), X(0x7edff570), X(0x11210907), X(0x7ed94538),
326 X(0x1152d7ed), X(0x7ed28171), X(0x1184a427), X(0x7ecbaa1a),
327 X(0x11b66dad), X(0x7ec4bf36), X(0x11e83478), X(0x7ebdc0c6),
328 X(0x1219f880), X(0x7eb6aeca), X(0x124bb9be), X(0x7eaf8943),
329 X(0x127d7829), X(0x7ea85033), X(0x12af33ba), X(0x7ea1039b),
330 X(0x12e0ec6a), X(0x7e99a37c), X(0x1312a230), X(0x7e922fd6),
331 X(0x13445505), X(0x7e8aa8ac), X(0x137604e2), X(0x7e830dff),
332 X(0x13a7b1bf), X(0x7e7b5fce), X(0x13d95b93), X(0x7e739e1d),
333 X(0x140b0258), X(0x7e6bc8eb), X(0x143ca605), X(0x7e63e03b),
334 X(0x146e4694), X(0x7e5be40c), X(0x149fe3fc), X(0x7e53d462),
335 X(0x14d17e36), X(0x7e4bb13c), X(0x1503153a), X(0x7e437a9c),
336 X(0x1534a901), X(0x7e3b3083), X(0x15663982), X(0x7e32d2f4),
337 X(0x1597c6b7), X(0x7e2a61ed), X(0x15c95097), X(0x7e21dd73),
338 X(0x15fad71b), X(0x7e194584), X(0x162c5a3b), X(0x7e109a24),
339 X(0x165dd9f0), X(0x7e07db52), X(0x168f5632), X(0x7dff0911),
340 X(0x16c0cef9), X(0x7df62362), X(0x16f2443e), X(0x7ded2a47),
341 X(0x1723b5f9), X(0x7de41dc0), X(0x17552422), X(0x7ddafdce),
342 X(0x17868eb3), X(0x7dd1ca75), X(0x17b7f5a3), X(0x7dc883b4),
343 X(0x17e958ea), X(0x7dbf298d), X(0x181ab881), X(0x7db5bc02),
344 X(0x184c1461), X(0x7dac3b15), X(0x187d6c82), X(0x7da2a6c6),
345 X(0x18aec0db), X(0x7d98ff17), X(0x18e01167), X(0x7d8f4409),
346 X(0x19115e1c), X(0x7d85759f), X(0x1942a6f3), X(0x7d7b93da),
347 X(0x1973ebe6), X(0x7d719eba), X(0x19a52ceb), X(0x7d679642),
348 X(0x19d669fc), X(0x7d5d7a74), X(0x1a07a311), X(0x7d534b50),
349 X(0x1a38d823), X(0x7d4908d9), X(0x1a6a0929), X(0x7d3eb30f),
350 X(0x1a9b361d), X(0x7d3449f5), X(0x1acc5ef6), X(0x7d29cd8c),
351 X(0x1afd83ad), X(0x7d1f3dd6), X(0x1b2ea43a), X(0x7d149ad5),
352 X(0x1b5fc097), X(0x7d09e489), X(0x1b90d8bb), X(0x7cff1af5),
353 X(0x1bc1ec9e), X(0x7cf43e1a), X(0x1bf2fc3a), X(0x7ce94dfb),
354 X(0x1c240786), X(0x7cde4a98), X(0x1c550e7c), X(0x7cd333f3),
355 X(0x1c861113), X(0x7cc80a0f), X(0x1cb70f43), X(0x7cbcccec),
356 X(0x1ce80906), X(0x7cb17c8d), X(0x1d18fe54), X(0x7ca618f3),
357 X(0x1d49ef26), X(0x7c9aa221), X(0x1d7adb73), X(0x7c8f1817),
358 X(0x1dabc334), X(0x7c837ad8), X(0x1ddca662), X(0x7c77ca65),
359 X(0x1e0d84f5), X(0x7c6c06c0), X(0x1e3e5ee5), X(0x7c602fec),
360 X(0x1e6f342c), X(0x7c5445e9), X(0x1ea004c1), X(0x7c4848ba),
361 X(0x1ed0d09d), X(0x7c3c3860), X(0x1f0197b8), X(0x7c3014de),
362 X(0x1f325a0b), X(0x7c23de35), X(0x1f63178f), X(0x7c179467),
363 X(0x1f93d03c), X(0x7c0b3777), X(0x1fc4840a), X(0x7bfec765),
364 X(0x1ff532f2), X(0x7bf24434), X(0x2025dcec), X(0x7be5ade6),
365 X(0x205681f1), X(0x7bd9047c), X(0x208721f9), X(0x7bcc47fa),
366 X(0x20b7bcfe), X(0x7bbf7860), X(0x20e852f6), X(0x7bb295b0),
367 X(0x2118e3dc), X(0x7ba59fee), X(0x21496fa7), X(0x7b989719),
368 X(0x2179f64f), X(0x7b8b7b36), X(0x21aa77cf), X(0x7b7e4c45),
369 X(0x21daf41d), X(0x7b710a49), X(0x220b6b32), X(0x7b63b543),
370 X(0x223bdd08), X(0x7b564d36), X(0x226c4996), X(0x7b48d225),
371 X(0x229cb0d5), X(0x7b3b4410), X(0x22cd12bd), X(0x7b2da2fa),
372 X(0x22fd6f48), X(0x7b1feee5), X(0x232dc66d), X(0x7b1227d3),
373 X(0x235e1826), X(0x7b044dc7), X(0x238e646a), X(0x7af660c2),
374 X(0x23beab33), X(0x7ae860c7), X(0x23eeec78), X(0x7ada4dd8),
375 X(0x241f2833), X(0x7acc27f7), X(0x244f5e5c), X(0x7abdef25),
376 X(0x247f8eec), X(0x7aafa367), X(0x24afb9da), X(0x7aa144bc),
377 X(0x24dfdf20), X(0x7a92d329), X(0x250ffeb7), X(0x7a844eae),
378 X(0x25401896), X(0x7a75b74f), X(0x25702cb7), X(0x7a670d0d),
379 X(0x25a03b11), X(0x7a584feb), X(0x25d0439f), X(0x7a497feb),
380 X(0x26004657), X(0x7a3a9d0f), X(0x26304333), X(0x7a2ba75a),
381 X(0x26603a2c), X(0x7a1c9ece), X(0x26902b39), X(0x7a0d836d),
382 X(0x26c01655), X(0x79fe5539), X(0x26effb76), X(0x79ef1436),
383 X(0x271fda96), X(0x79dfc064), X(0x274fb3ae), X(0x79d059c8),
384 X(0x277f86b5), X(0x79c0e062), X(0x27af53a6), X(0x79b15435),
385 X(0x27df1a77), X(0x79a1b545), X(0x280edb23), X(0x79920392),
386 X(0x283e95a1), X(0x79823f20), X(0x286e49ea), X(0x797267f2),
387 X(0x289df7f8), X(0x79627e08), X(0x28cd9fc1), X(0x79528167),
388 X(0x28fd4140), X(0x79427210), X(0x292cdc6d), X(0x79325006),
389 X(0x295c7140), X(0x79221b4b), X(0x298bffb2), X(0x7911d3e2),
390 X(0x29bb87bc), X(0x790179cd), X(0x29eb0957), X(0x78f10d0f),
391 X(0x2a1a847b), X(0x78e08dab), X(0x2a49f920), X(0x78cffba3),
392 X(0x2a796740), X(0x78bf56f9), X(0x2aa8ced3), X(0x78ae9fb0),
393 X(0x2ad82fd2), X(0x789dd5cb), X(0x2b078a36), X(0x788cf94c),
394 X(0x2b36ddf7), X(0x787c0a36), X(0x2b662b0e), X(0x786b088c),
395 X(0x2b957173), X(0x7859f44f), X(0x2bc4b120), X(0x7848cd83),
396 X(0x2bf3ea0d), X(0x7837942b), X(0x2c231c33), X(0x78264849),
397 X(0x2c52478a), X(0x7814e9df), X(0x2c816c0c), X(0x780378f1),
398 X(0x2cb089b1), X(0x77f1f581), X(0x2cdfa071), X(0x77e05f91),
399 X(0x2d0eb046), X(0x77ceb725), X(0x2d3db928), X(0x77bcfc3f),
400 X(0x2d6cbb10), X(0x77ab2ee2), X(0x2d9bb5f6), X(0x77994f11),
401 X(0x2dcaa9d5), X(0x77875cce), X(0x2df996a3), X(0x7775581d),
402 X(0x2e287c5a), X(0x776340ff), X(0x2e575af3), X(0x77511778),
403 X(0x2e863267), X(0x773edb8b), X(0x2eb502ae), X(0x772c8d3a),
404 X(0x2ee3cbc1), X(0x771a2c88), X(0x2f128d99), X(0x7707b979),
405 X(0x2f41482e), X(0x76f5340e), X(0x2f6ffb7a), X(0x76e29c4b),
406 X(0x2f9ea775), X(0x76cff232), X(0x2fcd4c19), X(0x76bd35c7),
407 X(0x2ffbe95d), X(0x76aa670d), X(0x302a7f3a), X(0x76978605),
408 X(0x30590dab), X(0x768492b4), X(0x308794a6), X(0x76718d1c),
409 X(0x30b61426), X(0x765e7540), X(0x30e48c22), X(0x764b4b23),
410 X(0x3112fc95), X(0x76380ec8), X(0x31416576), X(0x7624c031),
411 X(0x316fc6be), X(0x76115f63), X(0x319e2067), X(0x75fdec60),
412 X(0x31cc7269), X(0x75ea672a), X(0x31fabcbd), X(0x75d6cfc5),
413 X(0x3228ff5c), X(0x75c32634), X(0x32573a3f), X(0x75af6a7b),
414 X(0x32856d5e), X(0x759b9c9b), X(0x32b398b3), X(0x7587bc98),
415 X(0x32e1bc36), X(0x7573ca75), X(0x330fd7e1), X(0x755fc635),
416 X(0x333debab), X(0x754bafdc), X(0x336bf78f), X(0x7537876c),
417 X(0x3399fb85), X(0x75234ce8), X(0x33c7f785), X(0x750f0054),
418 X(0x33f5eb89), X(0x74faa1b3), X(0x3423d78a), X(0x74e63108),
419 X(0x3451bb81), X(0x74d1ae55), X(0x347f9766), X(0x74bd199f),
420 X(0x34ad6b32), X(0x74a872e8), X(0x34db36df), X(0x7493ba34),
421 X(0x3508fa66), X(0x747eef85), X(0x3536b5be), X(0x746a12df),
422 X(0x356468e2), X(0x74552446), X(0x359213c9), X(0x744023bc),
423 X(0x35bfb66e), X(0x742b1144), X(0x35ed50c9), X(0x7415ece2),
424 X(0x361ae2d3), X(0x7400b69a), X(0x36486c86), X(0x73eb6e6e),
425 X(0x3675edd9), X(0x73d61461), X(0x36a366c6), X(0x73c0a878),
426 X(0x36d0d746), X(0x73ab2ab4), X(0x36fe3f52), X(0x73959b1b),
427 X(0x372b9ee3), X(0x737ff9ae), X(0x3758f5f2), X(0x736a4671),
428 X(0x37864477), X(0x73548168), X(0x37b38a6d), X(0x733eaa96),
429 X(0x37e0c7cc), X(0x7328c1ff), X(0x380dfc8d), X(0x7312c7a5),
430 X(0x383b28a9), X(0x72fcbb8c), X(0x38684c19), X(0x72e69db7),
431 X(0x389566d6), X(0x72d06e2b), X(0x38c278d9), X(0x72ba2cea),
432 X(0x38ef821c), X(0x72a3d9f7), X(0x391c8297), X(0x728d7557),
433 X(0x39497a43), X(0x7276ff0d), X(0x39766919), X(0x7260771b),
434 X(0x39a34f13), X(0x7249dd86), X(0x39d02c2a), X(0x72333251),
435 X(0x39fd0056), X(0x721c7580), X(0x3a29cb91), X(0x7205a716),
436 X(0x3a568dd4), X(0x71eec716), X(0x3a834717), X(0x71d7d585),
437 X(0x3aaff755), X(0x71c0d265), X(0x3adc9e86), X(0x71a9bdba),
438 X(0x3b093ca3), X(0x71929789), X(0x3b35d1a5), X(0x717b5fd3),
439 X(0x3b625d86), X(0x7164169d), X(0x3b8ee03e), X(0x714cbbeb),
440 X(0x3bbb59c7), X(0x71354fc0), X(0x3be7ca1a), X(0x711dd220),
441 X(0x3c143130), X(0x7106430e), X(0x3c408f03), X(0x70eea28e),
442 X(0x3c6ce38a), X(0x70d6f0a4), X(0x3c992ec0), X(0x70bf2d53),
443 X(0x3cc5709e), X(0x70a7589f), X(0x3cf1a91c), X(0x708f728b),
444 X(0x3d1dd835), X(0x70777b1c), X(0x3d49fde1), X(0x705f7255),
445 X(0x3d761a19), X(0x70475839), X(0x3da22cd7), X(0x702f2ccd),
446 X(0x3dce3614), X(0x7016f014), X(0x3dfa35c8), X(0x6ffea212),
447 X(0x3e262bee), X(0x6fe642ca), X(0x3e52187f), X(0x6fcdd241),
448 X(0x3e7dfb73), X(0x6fb5507a), X(0x3ea9d4c3), X(0x6f9cbd79),
449 X(0x3ed5a46b), X(0x6f841942), X(0x3f016a61), X(0x6f6b63d8),
450 X(0x3f2d26a0), X(0x6f529d40), X(0x3f58d921), X(0x6f39c57d),
451 X(0x3f8481dd), X(0x6f20dc92), X(0x3fb020ce), X(0x6f07e285),
452 X(0x3fdbb5ec), X(0x6eeed758), X(0x40074132), X(0x6ed5bb10),
453 X(0x4032c297), X(0x6ebc8db0), X(0x405e3a16), X(0x6ea34f3d),
454 X(0x4089a7a8), X(0x6e89ffb9), X(0x40b50b46), X(0x6e709f2a),
455 X(0x40e064ea), X(0x6e572d93), X(0x410bb48c), X(0x6e3daaf8),
456 X(0x4136fa27), X(0x6e24175c), X(0x416235b2), X(0x6e0a72c5),
457 X(0x418d6729), X(0x6df0bd35), X(0x41b88e84), X(0x6dd6f6b1),
458 X(0x41e3abbc), X(0x6dbd1f3c), X(0x420ebecb), X(0x6da336dc),
459 X(0x4239c7aa), X(0x6d893d93), X(0x4264c653), X(0x6d6f3365),
460 X(0x428fbabe), X(0x6d551858), X(0x42baa4e6), X(0x6d3aec6e),
461 X(0x42e584c3), X(0x6d20afac), X(0x43105a50), X(0x6d066215),
462 X(0x433b2585), X(0x6cec03af), X(0x4365e65b), X(0x6cd1947c),
463 X(0x43909ccd), X(0x6cb71482), X(0x43bb48d4), X(0x6c9c83c3),
464 X(0x43e5ea68), X(0x6c81e245), X(0x44108184), X(0x6c67300b),
465 X(0x443b0e21), X(0x6c4c6d1a), X(0x44659039), X(0x6c319975),
466 X(0x449007c4), X(0x6c16b521), X(0x44ba74bd), X(0x6bfbc021),
467 X(0x44e4d71c), X(0x6be0ba7b), X(0x450f2edb), X(0x6bc5a431),
468 X(0x45397bf4), X(0x6baa7d49), X(0x4563be60), X(0x6b8f45c7),
469 X(0x458df619), X(0x6b73fdae), X(0x45b82318), X(0x6b58a503),
470 X(0x45e24556), X(0x6b3d3bcb), X(0x460c5cce), X(0x6b21c208),
471 X(0x46366978), X(0x6b0637c1), X(0x46606b4e), X(0x6aea9cf8),
472 X(0x468a624a), X(0x6acef1b2), X(0x46b44e65), X(0x6ab335f4),
473 X(0x46de2f99), X(0x6a9769c1), X(0x470805df), X(0x6a7b8d1e),
474 X(0x4731d131), X(0x6a5fa010), X(0x475b9188), X(0x6a43a29a),
475 X(0x478546de), X(0x6a2794c1), X(0x47aef12c), X(0x6a0b7689),
476 X(0x47d8906d), X(0x69ef47f6), X(0x48022499), X(0x69d3090e),
477 X(0x482badab), X(0x69b6b9d3), X(0x48552b9b), X(0x699a5a4c),
478 X(0x487e9e64), X(0x697dea7b), X(0x48a805ff), X(0x69616a65),
479 X(0x48d16265), X(0x6944da10), X(0x48fab391), X(0x6928397e),
480 X(0x4923f97b), X(0x690b88b5), X(0x494d341e), X(0x68eec7b9),
481 X(0x49766373), X(0x68d1f68f), X(0x499f8774), X(0x68b5153a),
482 X(0x49c8a01b), X(0x689823bf), X(0x49f1ad61), X(0x687b2224),
483 X(0x4a1aaf3f), X(0x685e106c), X(0x4a43a5b0), X(0x6840ee9b),
484 X(0x4a6c90ad), X(0x6823bcb7), X(0x4a957030), X(0x68067ac3),
485 X(0x4abe4433), X(0x67e928c5), X(0x4ae70caf), X(0x67cbc6c0),
486 X(0x4b0fc99d), X(0x67ae54ba), X(0x4b387af9), X(0x6790d2b6),
487 X(0x4b6120bb), X(0x677340ba), X(0x4b89badd), X(0x67559eca),
488 X(0x4bb24958), X(0x6737ecea), X(0x4bdacc28), X(0x671a2b20),
489 X(0x4c034345), X(0x66fc596f), X(0x4c2baea9), X(0x66de77dc),
490 X(0x4c540e4e), X(0x66c0866d), X(0x4c7c622d), X(0x66a28524),
491 X(0x4ca4aa41), X(0x66847408), X(0x4ccce684), X(0x6666531d),
492 X(0x4cf516ee), X(0x66482267), X(0x4d1d3b7a), X(0x6629e1ec),
493 X(0x4d455422), X(0x660b91af), X(0x4d6d60df), X(0x65ed31b5),
494 X(0x4d9561ac), X(0x65cec204), X(0x4dbd5682), X(0x65b0429f),
495 X(0x4de53f5a), X(0x6591b38c), X(0x4e0d1c30), X(0x657314cf),
496 X(0x4e34ecfc), X(0x6554666d), X(0x4e5cb1b9), X(0x6535a86b),
497 X(0x4e846a60), X(0x6516dacd), X(0x4eac16eb), X(0x64f7fd98),
498 X(0x4ed3b755), X(0x64d910d1), X(0x4efb4b96), X(0x64ba147d),
499 X(0x4f22d3aa), X(0x649b08a0), X(0x4f4a4f89), X(0x647bed3f),
500 X(0x4f71bf2e), X(0x645cc260), X(0x4f992293), X(0x643d8806),
501 X(0x4fc079b1), X(0x641e3e38), X(0x4fe7c483), X(0x63fee4f8),
502 X(0x500f0302), X(0x63df7c4d), X(0x50363529), X(0x63c0043b),
503 X(0x505d5af1), X(0x63a07cc7), X(0x50847454), X(0x6380e5f6),
504 X(0x50ab814d), X(0x63613fcd), X(0x50d281d5), X(0x63418a50),
505 X(0x50f975e6), X(0x6321c585), X(0x51205d7b), X(0x6301f171),
506 X(0x5147388c), X(0x62e20e17), X(0x516e0715), X(0x62c21b7e),
507 X(0x5194c910), X(0x62a219aa), X(0x51bb7e75), X(0x628208a1),
508 X(0x51e22740), X(0x6261e866), X(0x5208c36a), X(0x6241b8ff),
509 X(0x522f52ee), X(0x62217a72), X(0x5255d5c5), X(0x62012cc2),
510 X(0x527c4bea), X(0x61e0cff5), X(0x52a2b556), X(0x61c06410),
511 X(0x52c91204), X(0x619fe918), X(0x52ef61ee), X(0x617f5f12),
512 X(0x5315a50e), X(0x615ec603), X(0x533bdb5d), X(0x613e1df0),
513 X(0x536204d7), X(0x611d66de), X(0x53882175), X(0x60fca0d2),
514 X(0x53ae3131), X(0x60dbcbd1), X(0x53d43406), X(0x60bae7e1),
515 X(0x53fa29ed), X(0x6099f505), X(0x542012e1), X(0x6078f344),
516 X(0x5445eedb), X(0x6057e2a2), X(0x546bbdd7), X(0x6036c325),
517 X(0x54917fce), X(0x601594d1), X(0x54b734ba), X(0x5ff457ad),
518 X(0x54dcdc96), X(0x5fd30bbc), X(0x5502775c), X(0x5fb1b104),
519 X(0x55280505), X(0x5f90478a), X(0x554d858d), X(0x5f6ecf53),
520 X(0x5572f8ed), X(0x5f4d4865), X(0x55985f20), X(0x5f2bb2c5),
521 X(0x55bdb81f), X(0x5f0a0e77), X(0x55e303e6), X(0x5ee85b82),
522 X(0x5608426e), X(0x5ec699e9), X(0x562d73b2), X(0x5ea4c9b3),
523 X(0x565297ab), X(0x5e82eae5), X(0x5677ae54), X(0x5e60fd84),
524 X(0x569cb7a8), X(0x5e3f0194), X(0x56c1b3a1), X(0x5e1cf71c),
525 X(0x56e6a239), X(0x5dfade20), X(0x570b8369), X(0x5dd8b6a7),
526 X(0x5730572e), X(0x5db680b4), X(0x57551d80), X(0x5d943c4e),
527 X(0x5779d65b), X(0x5d71e979), X(0x579e81b8), X(0x5d4f883b),
528 X(0x57c31f92), X(0x5d2d189a), X(0x57e7afe4), X(0x5d0a9a9a),
529 X(0x580c32a7), X(0x5ce80e41), X(0x5830a7d6), X(0x5cc57394),
530 X(0x58550f6c), X(0x5ca2ca99), X(0x58796962), X(0x5c801354),
531 X(0x589db5b3), X(0x5c5d4dcc), X(0x58c1f45b), X(0x5c3a7a05),
532 X(0x58e62552), X(0x5c179806), X(0x590a4893), X(0x5bf4a7d2),
533 X(0x592e5e19), X(0x5bd1a971), X(0x595265df), X(0x5bae9ce7),
534 X(0x59765fde), X(0x5b8b8239), X(0x599a4c12), X(0x5b68596d),
535 X(0x59be2a74), X(0x5b452288), X(0x59e1faff), X(0x5b21dd90),
536 X(0x5a05bdae), X(0x5afe8a8b), X(0x5a29727b), X(0x5adb297d),
537 X(0x5a4d1960), X(0x5ab7ba6c), X(0x5a70b258), X(0x5a943d5e),
538 };
539
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: miscellaneous math and prototypes
14
15 ********************************************************************/
16
17 #ifndef _V_RANDOM_H_
18 #define _V_RANDOM_H_
19 #include "ivorbiscodec.h"
20 #include "os.h"
21 #include "tremor_shared.h"
22
23 #ifdef _LOW_ACCURACY_
24 # define X(n) (((((n)>>22)+1)>>1) - ((((n)>>22)+1)>>9))
25 # define LOOKUP_T const unsigned char
26 #else
27 # define X(n) (n)
28 # define LOOKUP_T const ogg_int32_t
29 #endif
30
31 #include "asm_arm.h"
32 #include <stdlib.h> /* for abs() */
33
34 #ifndef _V_WIDE_MATH
35 #define _V_WIDE_MATH
36
37 #ifndef _LOW_ACCURACY_
38 /* 64 bit multiply */
39
40 #if !(defined WIN32 && defined WINCE)
41 #include <sys/types.h>
42 #endif
43
44 union magic
45 {
46 struct
47 {
48 #ifdef MSB_FIRST
49 ogg_int32_t hi;
50 ogg_int32_t lo;
51 #else
52 ogg_int32_t lo;
53 ogg_int32_t hi;
54 #endif
55 } halves;
56 ogg_int64_t whole;
57 };
58
59 STIN ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) {
60 union magic magic;
61 magic.whole = (ogg_int64_t)x * y;
62 return magic.halves.hi;
63 }
64
65 STIN ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) {
66 return MULT32(x,y)<<1;
67 }
68
69 STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) {
70 union magic magic;
71 magic.whole = (ogg_int64_t)x * y;
72 return ((ogg_uint32_t)(magic.halves.lo)>>15) | ((magic.halves.hi)<<17);
73 }
74
75 #else
76 /* 32 bit multiply, more portable but less accurate */
77
78 /*
79 * Note: Precision is biased towards the first argument therefore ordering
80 * is important. Shift values were chosen for the best sound quality after
81 * many listening tests.
82 */
83
84 /*
85 * For MULT32 and MULT31: The second argument is always a lookup table
86 * value already preshifted from 31 to 8 bits. We therefore take the
87 * opportunity to save on text space and use unsigned char for those
88 * tables in this case.
89 */
90
91 STIN ogg_int32_t MULT32(ogg_int32_t x, ogg_int32_t y) {
92 return (x >> 9) * y; /* y preshifted >>23 */
93 }
94
95 STIN ogg_int32_t MULT31(ogg_int32_t x, ogg_int32_t y) {
96 return (x >> 8) * y; /* y preshifted >>23 */
97 }
98
99 STIN ogg_int32_t MULT31_SHIFT15(ogg_int32_t x, ogg_int32_t y) {
100 return (x >> 6) * y; /* y preshifted >>9 */
101 }
102
103 #endif
104
105 /*
106 * This should be used as a memory barrier, forcing all cached values in
107 * registers to wr writen back to memory. Might or might not be beneficial
108 * depending on the architecture and compiler.
109 */
110 #define MB()
111
112 /*
113 * The XPROD functions are meant to optimize the cross products found all
114 * over the place in mdct.c by forcing memory operation ordering to avoid
115 * unnecessary register reloads as soon as memory is being written to.
116 * However this is only beneficial on CPUs with a sane number of general
117 * purpose registers which exclude the Intel x86. On Intel, better let the
118 * compiler actually reload registers directly from original memory by using
119 * macros.
120 */
121
122 #ifdef __i386__
123
124 #define XPROD32(_a, _b, _t, _v, _x, _y) \
125 { *(_x)=MULT32(_a,_t)+MULT32(_b,_v); \
126 *(_y)=MULT32(_b,_t)-MULT32(_a,_v); }
127 #define XPROD31(_a, _b, _t, _v, _x, _y) \
128 { *(_x)=MULT31(_a,_t)+MULT31(_b,_v); \
129 *(_y)=MULT31(_b,_t)-MULT31(_a,_v); }
130 #define XNPROD31(_a, _b, _t, _v, _x, _y) \
131 { *(_x)=MULT31(_a,_t)-MULT31(_b,_v); \
132 *(_y)=MULT31(_b,_t)+MULT31(_a,_v); }
133
134 #else
135
136 STIN void XPROD32(ogg_int32_t a, ogg_int32_t b,
137 ogg_int32_t t, ogg_int32_t v,
138 ogg_int32_t *x, ogg_int32_t *y)
139 {
140 *x = MULT32(a, t) + MULT32(b, v);
141 *y = MULT32(b, t) - MULT32(a, v);
142 }
143
144 STIN void XPROD31(ogg_int32_t a, ogg_int32_t b,
145 ogg_int32_t t, ogg_int32_t v,
146 ogg_int32_t *x, ogg_int32_t *y)
147 {
148 *x = MULT31(a, t) + MULT31(b, v);
149 *y = MULT31(b, t) - MULT31(a, v);
150 }
151
152 STIN void XNPROD31(ogg_int32_t a, ogg_int32_t b,
153 ogg_int32_t t, ogg_int32_t v,
154 ogg_int32_t *x, ogg_int32_t *y)
155 {
156 *x = MULT31(a, t) - MULT31(b, v);
157 *y = MULT31(b, t) + MULT31(a, v);
158 }
159
160 #endif
161
162 #endif
163
164 #ifndef _V_CLIP_MATH
165 #define _V_CLIP_MATH
166
167 STIN ogg_int32_t CLIP_TO_15(ogg_int32_t x) {
168 int ret=x;
169 ret-= ((x<=32767)-1)&(x-32767);
170 ret-= ((x>=-32768)-1)&(x+32768);
171 return(ret);
172 }
173
174 #endif
175
176 STIN ogg_int32_t VFLOAT_MULT(ogg_int32_t a,ogg_int32_t ap,
177 ogg_int32_t b,ogg_int32_t bp,
178 ogg_int32_t *p){
179 if(a && b){
180 #ifndef _LOW_ACCURACY_
181 *p=ap+bp+32;
182 return MULT32(a,b);
183 #else
184 *p=ap+bp+31;
185 return (a>>15)*(b>>16);
186 #endif
187 }else
188 return 0;
189 }
190
191 STIN ogg_int32_t VFLOAT_MULTI(ogg_int32_t a,ogg_int32_t ap,
192 ogg_int32_t i,
193 ogg_int32_t *p){
194
195 int ip= ilog(abs(i))-31;
196 return VFLOAT_MULT(a,ap,i<<-ip,ip,p);
197 }
198
199 STIN ogg_int32_t VFLOAT_ADD(ogg_int32_t a,ogg_int32_t ap,
200 ogg_int32_t b,ogg_int32_t bp,
201 ogg_int32_t *p){
202
203 if(!a){
204 *p=bp;
205 return b;
206 }else if(!b){
207 *p=ap;
208 return a;
209 }
210
211 /* yes, this can leak a bit. */
212 if(ap>bp){
213 int shift=ap-bp+1;
214 *p=ap+1;
215 a>>=1;
216 if(shift<32){
217 b=(b+(1<<(shift-1)))>>shift;
218 }else{
219 b=0;
220 }
221 }else{
222 int shift=bp-ap+1;
223 *p=bp+1;
224 b>>=1;
225 if(shift<32){
226 a=(a+(1<<(shift-1)))>>shift;
227 }else{
228 a=0;
229 }
230 }
231
232 a+=b;
233 if((a&0xc0000000)==0xc0000000 ||
234 (a&0xc0000000)==0){
235 a<<=1;
236 (*p)--;
237 }
238 return(a);
239 }
240
241 #endif
242
243
244
245
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
3 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
4 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
5 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
6 * *
7 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 *
8 * by the Xiph.Org Foundation http://www.xiph.org/ *
9 * *
10 ********************************************************************
11
12 function: toplevel libogg include
13 last mod: $Id: ogg.h 18044 2011-08-01 17:55:20Z gmaxwell $
14
15 ********************************************************************/
16 #ifndef _OGG_H
17 #define _OGG_H
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 #include <stddef.h>
24 #include "os_types.h"
25
26 typedef struct {
27 void *iov_base;
28 size_t iov_len;
29 } ogg_iovec_t;
30
31 typedef struct {
32 long endbyte;
33 int endbit;
34
35 unsigned char *buffer;
36 unsigned char *ptr;
37 long storage;
38 } oggpack_buffer;
39
40 /* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/
41
42 typedef struct {
43 unsigned char *header;
44 long header_len;
45 unsigned char *body;
46 long body_len;
47 } ogg_page;
48
49 /* ogg_stream_state contains the current encode/decode state of a logical
50 Ogg bitstream **********************************************************/
51
52 typedef struct {
53 unsigned char *body_data; /* bytes from packet bodies */
54 long body_storage; /* storage elements allocated */
55 long body_fill; /* elements stored; fill mark */
56 long body_returned; /* elements of fill returned */
57
58
59 int *lacing_vals; /* The values that will go to the segment table */
60 ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact
61 this way, but it is simple coupled to the
62 lacing fifo */
63 long lacing_storage;
64 long lacing_fill;
65 long lacing_packet;
66 long lacing_returned;
67
68 unsigned char header[282]; /* working space for header encode */
69 int header_fill;
70
71 int e_o_s; /* set when we have buffered the last packet in the
72 logical bitstream */
73 int b_o_s; /* set after we've written the initial page
74 of a logical bitstream */
75 long serialno;
76 long pageno;
77 ogg_int64_t packetno; /* sequence number for decode; the framing
78 knows where there's a hole in the data,
79 but we need coupling so that the codec
80 (which is in a separate abstraction
81 layer) also knows about the gap */
82 ogg_int64_t granulepos;
83
84 } ogg_stream_state;
85
86 /* ogg_packet is used to encapsulate the data and metadata belonging
87 to a single raw Ogg/Vorbis packet *************************************/
88
89 typedef struct {
90 unsigned char *packet;
91 long bytes;
92 long b_o_s;
93 long e_o_s;
94
95 ogg_int64_t granulepos;
96
97 ogg_int64_t packetno; /* sequence number for decode; the framing
98 knows where there's a hole in the data,
99 but we need coupling so that the codec
100 (which is in a separate abstraction
101 layer) also knows about the gap */
102 } ogg_packet;
103
104 typedef struct {
105 unsigned char *data;
106 int storage;
107 int fill;
108 int returned;
109
110 int unsynced;
111 int headerbytes;
112 int bodybytes;
113 } ogg_sync_state;
114
115 /* Ogg BITSTREAM PRIMITIVES: bitstream ************************/
116
117 extern void oggpack_writeinit(oggpack_buffer *b);
118 extern int oggpack_writecheck(oggpack_buffer *b);
119 extern void oggpack_writetrunc(oggpack_buffer *b,long bits);
120 extern void oggpack_writealign(oggpack_buffer *b);
121 extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits);
122 extern void oggpack_reset(oggpack_buffer *b);
123 extern void oggpack_writeclear(oggpack_buffer *b);
124 extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
125 extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits);
126 extern long oggpack_look(oggpack_buffer *b,int bits);
127 extern long oggpack_look1(oggpack_buffer *b);
128 extern void oggpack_adv(oggpack_buffer *b,int bits);
129 extern void oggpack_adv1(oggpack_buffer *b);
130 extern long oggpack_read(oggpack_buffer *b,int bits);
131 extern long oggpack_read1(oggpack_buffer *b);
132 extern long oggpack_bytes(oggpack_buffer *b);
133 extern long oggpack_bits(oggpack_buffer *b);
134 extern unsigned char *oggpack_get_buffer(oggpack_buffer *b);
135
136 extern void oggpackB_writeinit(oggpack_buffer *b);
137 extern int oggpackB_writecheck(oggpack_buffer *b);
138 extern void oggpackB_writetrunc(oggpack_buffer *b,long bits);
139 extern void oggpackB_writealign(oggpack_buffer *b);
140 extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits);
141 extern void oggpackB_reset(oggpack_buffer *b);
142 extern void oggpackB_writeclear(oggpack_buffer *b);
143 extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes);
144 extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits);
145 extern long oggpackB_look(oggpack_buffer *b,int bits);
146 extern long oggpackB_look1(oggpack_buffer *b);
147 extern void oggpackB_adv(oggpack_buffer *b,int bits);
148 extern void oggpackB_adv1(oggpack_buffer *b);
149 extern long oggpackB_read(oggpack_buffer *b,int bits);
150 extern long oggpackB_read1(oggpack_buffer *b);
151 extern long oggpackB_bytes(oggpack_buffer *b);
152 extern long oggpackB_bits(oggpack_buffer *b);
153 extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b);
154
155 /* Ogg BITSTREAM PRIMITIVES: encoding **************************/
156
157 extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op);
158 extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov,
159 int count, long e_o_s, ogg_int64_t granulepos);
160 extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og);
161 extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill);
162 extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og);
163 extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill);
164
165 /* Ogg BITSTREAM PRIMITIVES: decoding **************************/
166
167 extern int ogg_sync_init(ogg_sync_state *oy);
168 extern int ogg_sync_clear(ogg_sync_state *oy);
169 extern int ogg_sync_reset(ogg_sync_state *oy);
170 extern int ogg_sync_destroy(ogg_sync_state *oy);
171 extern int ogg_sync_check(ogg_sync_state *oy);
172
173 extern char *ogg_sync_buffer(ogg_sync_state *oy, long size);
174 extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes);
175 extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og);
176 extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og);
177 extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og);
178 extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op);
179 extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op);
180
181 /* Ogg BITSTREAM PRIMITIVES: general ***************************/
182
183 extern int ogg_stream_init(ogg_stream_state *os,int serialno);
184 extern int ogg_stream_clear(ogg_stream_state *os);
185 extern int ogg_stream_reset(ogg_stream_state *os);
186 extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno);
187 extern int ogg_stream_destroy(ogg_stream_state *os);
188 extern int ogg_stream_check(ogg_stream_state *os);
189 extern int ogg_stream_eos(ogg_stream_state *os);
190
191 extern void ogg_page_checksum_set(ogg_page *og);
192
193 extern int ogg_page_version(const ogg_page *og);
194 extern int ogg_page_continued(const ogg_page *og);
195 extern int ogg_page_bos(const ogg_page *og);
196 extern int ogg_page_eos(const ogg_page *og);
197 extern ogg_int64_t ogg_page_granulepos(const ogg_page *og);
198 extern int ogg_page_serialno(const ogg_page *og);
199 extern long ogg_page_pageno(const ogg_page *og);
200 extern int ogg_page_packets(const ogg_page *og);
201
202 extern void ogg_packet_clear(ogg_packet *op);
203
204
205 #ifdef __cplusplus
206 }
207 #endif
208
209 #endif /* _OGG_H */
0 #ifndef _OS_H
1 #define _OS_H
2 /********************************************************************
3 * *
4 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
5 * *
6 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
7 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
8 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
9 * *
10 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
11 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
12 * *
13 ********************************************************************
14
15 function: #ifdef jail to whip a few platforms into the UNIX ideal.
16
17 ********************************************************************/
18
19 #include <math.h>
20 #include "os_types.h"
21
22 #ifndef _V_IFDEFJAIL_H_
23 # define _V_IFDEFJAIL_H_
24
25 # ifdef __GNUC__
26 # define STIN static __inline__
27 # elif _WIN32
28 # define STIN static __inline
29 # endif
30 #else
31 # define STIN static
32 #endif
33
34 #ifndef M_PI
35 # define M_PI (3.1415926536f)
36 #endif
37
38 #ifdef _WIN32
39 # include <malloc.h>
40 # define rint(x) (floor((x)+0.5f))
41 # define NO_FLOAT_MATH_LIB
42 # define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b))
43 # define LITTLE_ENDIAN 1
44 #endif
45
46 #ifdef HAVE_ALLOCA_H
47 # include <alloca.h>
48 #endif
49
50 #ifdef USE_MEMORY_H
51 # include <memory.h>
52 #endif
53
54 #ifndef min
55 # define min(x,y) ((x)>(y)?(y):(x))
56 #endif
57
58 #ifndef max
59 # define max(x,y) ((x)<(y)?(y):(x))
60 #endif
61
62 #endif /* _OS_H */
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
3 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
4 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
5 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
6 * *
7 * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
8 * by the Xiph.Org Foundation http://www.xiph.org/ *
9 * *
10 ********************************************************************
11
12 function: #ifdef jail to whip a few platforms into the UNIX ideal.
13 last mod: $Id: os_types.h 17712 2010-12-03 17:10:02Z xiphmont $
14
15 ********************************************************************/
16 #ifndef _OS_TYPES_H
17 #define _OS_TYPES_H
18
19 /* make it easy on the folks that want to compile the libs with a
20 different malloc than stdlib */
21 #define _ogg_malloc malloc
22 #define _ogg_calloc calloc
23 #define _ogg_realloc realloc
24 #define _ogg_free free
25
26 #if defined(_WIN32)
27
28 # if defined(__CYGWIN__)
29 # include <stdint.h>
30 typedef int16_t ogg_int16_t;
31 typedef uint16_t ogg_uint16_t;
32 typedef int32_t ogg_int32_t;
33 typedef uint32_t ogg_uint32_t;
34 typedef int64_t ogg_int64_t;
35 typedef uint64_t ogg_uint64_t;
36 # elif defined(__MINGW32__)
37 # include <sys/types.h>
38 typedef short ogg_int16_t;
39 typedef unsigned short ogg_uint16_t;
40 typedef int ogg_int32_t;
41 typedef unsigned int ogg_uint32_t;
42 typedef long long ogg_int64_t;
43 typedef unsigned long long ogg_uint64_t;
44 # elif defined(__MWERKS__)
45 typedef long long ogg_int64_t;
46 typedef int ogg_int32_t;
47 typedef unsigned int ogg_uint32_t;
48 typedef short ogg_int16_t;
49 typedef unsigned short ogg_uint16_t;
50 # else
51 /* MSVC/Borland */
52 typedef __int64 ogg_int64_t;
53 typedef __int32 ogg_int32_t;
54 typedef unsigned __int32 ogg_uint32_t;
55 typedef __int16 ogg_int16_t;
56 typedef unsigned __int16 ogg_uint16_t;
57 # endif
58
59 #elif defined(__MACOS__)
60
61 # include <sys/types.h>
62 typedef SInt16 ogg_int16_t;
63 typedef UInt16 ogg_uint16_t;
64 typedef SInt32 ogg_int32_t;
65 typedef UInt32 ogg_uint32_t;
66 typedef SInt64 ogg_int64_t;
67
68 #elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */
69
70 # include <inttypes.h>
71 typedef int16_t ogg_int16_t;
72 typedef uint16_t ogg_uint16_t;
73 typedef int32_t ogg_int32_t;
74 typedef uint32_t ogg_uint32_t;
75 typedef int64_t ogg_int64_t;
76
77 #elif defined(__HAIKU__)
78
79 /* Haiku */
80 # include <sys/types.h>
81 typedef short ogg_int16_t;
82 typedef unsigned short ogg_uint16_t;
83 typedef int ogg_int32_t;
84 typedef unsigned int ogg_uint32_t;
85 typedef long long ogg_int64_t;
86
87 #elif defined(__BEOS__)
88
89 /* Be */
90 # include <inttypes.h>
91 typedef int16_t ogg_int16_t;
92 typedef uint16_t ogg_uint16_t;
93 typedef int32_t ogg_int32_t;
94 typedef uint32_t ogg_uint32_t;
95 typedef int64_t ogg_int64_t;
96
97 #elif defined (__EMX__)
98
99 /* OS/2 GCC */
100 typedef short ogg_int16_t;
101 typedef unsigned short ogg_uint16_t;
102 typedef int ogg_int32_t;
103 typedef unsigned int ogg_uint32_t;
104 typedef long long ogg_int64_t;
105
106 #elif defined (DJGPP)
107
108 /* DJGPP */
109 typedef short ogg_int16_t;
110 typedef int ogg_int32_t;
111 typedef unsigned int ogg_uint32_t;
112 typedef long long ogg_int64_t;
113
114 #elif defined(R5900)
115
116 /* PS2 EE */
117 typedef long ogg_int64_t;
118 typedef int ogg_int32_t;
119 typedef unsigned ogg_uint32_t;
120 typedef short ogg_int16_t;
121
122 #elif defined(__SYMBIAN32__)
123
124 /* Symbian GCC */
125 typedef signed short ogg_int16_t;
126 typedef unsigned short ogg_uint16_t;
127 typedef signed int ogg_int32_t;
128 typedef unsigned int ogg_uint32_t;
129 typedef long long int ogg_int64_t;
130
131 #elif defined(__TMS320C6X__)
132
133 /* TI C64x compiler */
134 typedef signed short ogg_int16_t;
135 typedef unsigned short ogg_uint16_t;
136 typedef signed int ogg_int32_t;
137 typedef unsigned int ogg_uint32_t;
138 typedef long long int ogg_int64_t;
139
140 #else
141
142 # include "config_types.h"
143
144 #endif
145
146 #endif /* _OS_TYPES_H */
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: registry for floor, res backends and channel mappings
14
15 ********************************************************************/
16
17 #include "ivorbiscodec.h"
18 #include "codec_internal.h"
19 #include "registry.h"
20 #include "misc.h"
21
22
23 /* seems like major overkill now; the backend numbers will grow into
24 the infrastructure soon enough */
25
26 extern vorbis_func_floor floor0_exportbundle;
27 extern vorbis_func_floor floor1_exportbundle;
28 extern vorbis_func_residue residue0_exportbundle;
29 extern vorbis_func_residue residue1_exportbundle;
30 extern vorbis_func_residue residue2_exportbundle;
31 extern vorbis_func_mapping mapping0_exportbundle;
32
33 vorbis_func_floor *_floor_P[]={
34 &floor0_exportbundle,
35 &floor1_exportbundle,
36 };
37
38 vorbis_func_residue *_residue_P[]={
39 &residue0_exportbundle,
40 &residue1_exportbundle,
41 &residue2_exportbundle,
42 };
43
44 vorbis_func_mapping *_mapping_P[]={
45 &mapping0_exportbundle,
46 };
47
48
49
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: registry for time, floor, res backends and channel mappings
14
15 ********************************************************************/
16
17 #ifndef _V_REG_H_
18 #define _V_REG_H_
19
20 #define VI_TRANSFORMB 1
21 #define VI_WINDOWB 1
22 #define VI_TIMEB 1
23 #define VI_FLOORB 2
24 #define VI_RESB 3
25 #define VI_MAPB 1
26
27 #include "backends.h"
28
29 #if defined(_WIN32) && defined(VORBISDLL_IMPORT)
30 # define EXTERN __declspec(dllimport) extern
31 #else
32 # define EXTERN extern
33 #endif
34
35 EXTERN vorbis_func_floor *_floor_P[];
36 EXTERN vorbis_func_residue *_residue_P[];
37 EXTERN vorbis_func_mapping *_mapping_P[];
38
39 #endif
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: residue backend 0, 1 and 2 implementation
14
15 ********************************************************************/
16
17 #include <stdlib.h>
18 #include <string.h>
19 #include <math.h>
20 #include "ogg.h"
21 #include "ivorbiscodec.h"
22 #include "codec_internal.h"
23 #include "registry.h"
24 #include "codebook.h"
25 #include "misc.h"
26 #include "os.h"
27 #include "block.h"
28 #include "tremor_shared.h"
29
30 typedef struct {
31 vorbis_info_residue0 *info;
32 int map;
33
34 int parts;
35 int stages;
36 codebook *fullbooks;
37 codebook *phrasebook;
38 codebook ***partbooks;
39
40 int partvals;
41 int **decodemap;
42
43 } vorbis_look_residue0;
44
45 void res0_free_info(vorbis_info_residue *i){
46 vorbis_info_residue0 *info=(vorbis_info_residue0 *)i;
47 if(info){
48 memset(info,0,sizeof(*info));
49 _ogg_free(info);
50 }
51 }
52
53 void res0_free_look(vorbis_look_residue *i){
54 int j;
55 if(i){
56
57 vorbis_look_residue0 *look=(vorbis_look_residue0 *)i;
58
59 for(j=0;j<look->parts;j++)
60 if(look->partbooks[j])_ogg_free(look->partbooks[j]);
61 _ogg_free(look->partbooks);
62 for(j=0;j<look->partvals;j++)
63 _ogg_free(look->decodemap[j]);
64 _ogg_free(look->decodemap);
65
66 memset(look,0,sizeof(*look));
67 _ogg_free(look);
68 }
69 }
70
71 static int icount(unsigned int v){
72 int ret=0;
73 while(v){
74 ret+=v&1;
75 v>>=1;
76 }
77 return(ret);
78 }
79
80 /* vorbis_info is for range checking */
81 vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){
82 int j,acc=0;
83 vorbis_info_residue0 *info=(vorbis_info_residue0 *)_ogg_calloc(1,sizeof(*info));
84 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
85
86 info->begin=oggpack_read(opb,24);
87 info->end=oggpack_read(opb,24);
88 info->grouping=oggpack_read(opb,24)+1;
89 info->partitions=oggpack_read(opb,6)+1;
90 info->groupbook=oggpack_read(opb,8);
91
92 /* check for premature EOP */
93 if(info->groupbook<0)goto errout;
94
95 for(j=0;j<info->partitions;j++){
96 int cascade=oggpack_read(opb,3);
97 int cflag=oggpack_read(opb,1);
98 if(cflag<0) goto errout;
99 if(cflag){
100 int c=oggpack_read(opb,5);
101 if(c<0) goto errout;
102 cascade|=(c<<3);
103 }
104 info->secondstages[j]=cascade;
105
106 acc+=icount(cascade);
107 }
108 for(j=0;j<acc;j++){
109 int book=oggpack_read(opb,8);
110 if(book<0) goto errout;
111 info->booklist[j]=book;
112 }
113
114 if(info->groupbook>=ci->books)goto errout;
115 for(j=0;j<acc;j++){
116 if(info->booklist[j]>=ci->books)goto errout;
117 if(ci->book_param[info->booklist[j]]->maptype==0)goto errout;
118 }
119
120 /* verify the phrasebook is not specifying an impossible or
121 inconsistent partitioning scheme. */
122 /* modify the phrasebook ranging check from r16327; an early beta
123 encoder had a bug where it used an oversized phrasebook by
124 accident. These files should continue to be playable, but don't
125 allow an exploit */
126 {
127 int entries = ci->book_param[info->groupbook]->entries;
128 int dim = ci->book_param[info->groupbook]->dim;
129 int partvals = 1;
130 if (dim<1) goto errout;
131 while(dim>0){
132 partvals *= info->partitions;
133 if(partvals > entries) goto errout;
134 dim--;
135 }
136 info->partvals = partvals;
137 }
138
139 return(info);
140 errout:
141 res0_free_info(info);
142 return(NULL);
143 }
144
145 vorbis_look_residue *res0_look(vorbis_dsp_state *vd,vorbis_info_mode *vm,
146 vorbis_info_residue *vr){
147 vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr;
148 vorbis_look_residue0 *look=(vorbis_look_residue0 *)_ogg_calloc(1,sizeof(*look));
149 codec_setup_info *ci=(codec_setup_info *)vd->vi->codec_setup;
150
151 int j,k,acc=0;
152 int dim;
153 int maxstage=0;
154 look->info=info;
155 look->map=vm->mapping;
156
157 look->parts=info->partitions;
158 look->fullbooks=ci->fullbooks;
159 look->phrasebook=ci->fullbooks+info->groupbook;
160 dim=look->phrasebook->dim;
161
162 look->partbooks=(codebook ***)_ogg_calloc(look->parts,sizeof(*look->partbooks));
163
164 for(j=0;j<look->parts;j++){
165 int stages=ilog(info->secondstages[j]);
166 if(stages){
167 if(stages>maxstage)maxstage=stages;
168 look->partbooks[j]=(codebook **)_ogg_calloc(stages,sizeof(*look->partbooks[j]));
169 for(k=0;k<stages;k++)
170 if(info->secondstages[j]&(1<<k)){
171 look->partbooks[j][k]=ci->fullbooks+info->booklist[acc++];
172 #ifdef TRAIN_RES
173 look->training_data[k][j]=calloc(look->partbooks[j][k]->entries,
174 sizeof(***look->training_data));
175 #endif
176 }
177 }
178 }
179
180 look->partvals=look->parts;
181 for(j=1;j<dim;j++)look->partvals*=look->parts;
182 look->stages=maxstage;
183 look->decodemap=(int **)_ogg_malloc(look->partvals*sizeof(*look->decodemap));
184 for(j=0;j<look->partvals;j++){
185 long val=j;
186 long mult=look->partvals/look->parts;
187 look->decodemap[j]=(int *)_ogg_malloc(dim*sizeof(*look->decodemap[j]));
188 for(k=0;k<dim;k++){
189 long deco=val/mult;
190 val-=deco*mult;
191 mult/=look->parts;
192 look->decodemap[j][k]=deco;
193 }
194 }
195
196 return(look);
197 }
198
199
200 /* a truncated packet here just means 'stop working'; it's not an error */
201 static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl,
202 ogg_int32_t **in,int ch,
203 long (*decodepart)(codebook *, ogg_int32_t *,
204 oggpack_buffer *,int,int)){
205
206 long i,j,k,l,s;
207 vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
208 vorbis_info_residue0 *info=look->info;
209
210 /* move all this setup out later */
211 int samples_per_partition=info->grouping;
212 int partitions_per_word=look->phrasebook->dim;
213 int max=vb->pcmend>>1;
214 int end=(info->end<max?info->end:max);
215 int n=end-info->begin;
216
217 if(n>0){
218 int partvals=n/samples_per_partition;
219 int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
220 int ***partword=(int ***)alloca(ch*sizeof(*partword));
221
222 for(j=0;j<ch;j++)
223 partword[j]=(int **)_vorbis_block_alloc(vb,partwords*sizeof(*partword[j]));
224
225 for(s=0;s<look->stages;s++){
226
227 /* each loop decodes on partition codeword containing
228 partitions_pre_word partitions */
229 for(i=0,l=0;i<partvals;l++){
230 if(s==0){
231 /* fetch the partition word for each channel */
232 for(j=0;j<ch;j++){
233 int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
234 if(temp==-1 || temp>=info->partvals)goto eopbreak;
235 partword[j][l]=look->decodemap[temp];
236 if(partword[j][l]==NULL)goto errout;
237 }
238 }
239
240 /* now we decode residual values for the partitions */
241 for(k=0;k<partitions_per_word && i<partvals;k++,i++)
242 for(j=0;j<ch;j++){
243 long offset=info->begin+i*samples_per_partition;
244 if(info->secondstages[partword[j][l][k]]&(1<<s)){
245 codebook *stagebook=look->partbooks[partword[j][l][k]][s];
246 if(stagebook){
247 if(decodepart(stagebook,in[j]+offset,&vb->opb,
248 samples_per_partition,-8)==-1)goto eopbreak;
249 }
250 }
251 }
252 }
253 }
254 }
255 errout:
256 eopbreak:
257 return(0);
258 }
259
260 int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl,
261 ogg_int32_t **in,int *nonzero,int ch){
262 int i,used=0;
263 for(i=0;i<ch;i++)
264 if(nonzero[i])
265 in[used++]=in[i];
266 if(used)
267 return(_01inverse(vb,vl,in,used,vorbis_book_decodevs_add));
268 else
269 return(0);
270 }
271
272 int res1_inverse(vorbis_block *vb,vorbis_look_residue *vl,
273 ogg_int32_t **in,int *nonzero,int ch){
274 int i,used=0;
275 for(i=0;i<ch;i++)
276 if(nonzero[i])
277 in[used++]=in[i];
278 if(used)
279 return(_01inverse(vb,vl,in,used,vorbis_book_decodev_add));
280 else
281 return(0);
282 }
283
284 /* duplicate code here as speed is somewhat more important */
285 int res2_inverse(vorbis_block *vb,vorbis_look_residue *vl,
286 ogg_int32_t **in,int *nonzero,int ch){
287 long i,k,l,s;
288 vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl;
289 vorbis_info_residue0 *info=look->info;
290
291 /* move all this setup out later */
292 int samples_per_partition=info->grouping;
293 int partitions_per_word=look->phrasebook->dim;
294 int max=(vb->pcmend*ch)>>1;
295 int end=(info->end<max?info->end:max);
296 int n=end-info->begin;
297
298 if(n>0){
299
300 int partvals=n/samples_per_partition;
301 int partwords=(partvals+partitions_per_word-1)/partitions_per_word;
302 int **partword=(int **)_vorbis_block_alloc(vb,partwords*sizeof(*partword));
303 int beginoff=info->begin/ch;
304
305 for(i=0;i<ch;i++)if(nonzero[i])break;
306 if(i==ch)return(0); /* no nonzero vectors */
307
308 samples_per_partition/=ch;
309
310 for(s=0;s<look->stages;s++){
311 for(i=0,l=0;i<partvals;l++){
312
313 if(s==0){
314 /* fetch the partition word */
315 int temp=vorbis_book_decode(look->phrasebook,&vb->opb);
316 if(temp==-1 || temp>=info->partvals)goto eopbreak;
317 partword[l]=look->decodemap[temp];
318 if(partword[l]==NULL)goto errout;
319 }
320
321 /* now we decode residual values for the partitions */
322 for(k=0;k<partitions_per_word && i<partvals;k++,i++)
323 if(info->secondstages[partword[l][k]]&(1<<s)){
324 codebook *stagebook=look->partbooks[partword[l][k]][s];
325
326 if(stagebook){
327 if(vorbis_book_decodevv_add(stagebook,in,
328 i*samples_per_partition+beginoff,ch,
329 &vb->opb,
330 samples_per_partition,-8)==-1)
331 goto eopbreak;
332 }
333 }
334 }
335 }
336 }
337 errout:
338 eopbreak:
339 return(0);
340 }
341
342
343 vorbis_func_residue residue0_exportbundle={
344 &res0_unpack,
345 &res0_look,
346 &res0_free_info,
347 &res0_free_look,
348 &res0_inverse
349 };
350
351 vorbis_func_residue residue1_exportbundle={
352 &res0_unpack,
353 &res0_look,
354 &res0_free_info,
355 &res0_free_look,
356 &res1_inverse
357 };
358
359 vorbis_func_residue residue2_exportbundle={
360 &res0_unpack,
361 &res0_look,
362 &res0_free_info,
363 &res0_free_look,
364 &res2_inverse
365 };
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: basic shared codebook operations
14
15 ********************************************************************/
16
17 #include <stdlib.h>
18 #include <math.h>
19 #include <string.h>
20 #include "ogg.h"
21 #include "misc.h"
22 #include "ivorbiscodec.h"
23 #include "codebook.h"
24 #include "tremor_shared.h"
25
26 /**** pack/unpack helpers ******************************************/
27
28 /* 32 bit float (not IEEE; nonnormalized mantissa +
29 biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm
30 Why not IEEE? It's just not that important here. */
31
32 #define VQ_FEXP 10
33 #define VQ_FMAN 21
34 #define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */
35
36 static ogg_int32_t _float32_unpack(long val,int *point){
37 long mant=val&0x1fffff;
38 int sign=val&0x80000000;
39 long exp =(val&0x7fe00000L)>>VQ_FMAN;
40
41 exp-=(VQ_FMAN-1)+VQ_FEXP_BIAS;
42
43 if(mant){
44 while(!(mant&0x40000000)){
45 mant<<=1;
46 exp-=1;
47 }
48
49 if(sign)mant= -mant;
50 }else{
51 sign=0;
52 exp=-9999;
53 }
54
55 *point=exp;
56 return mant;
57 }
58
59 /* given a list of word lengths, generate a list of codewords. Works
60 for length ordered or unordered, always assigns the lowest valued
61 codewords first. Extended to handle unused entries (length 0) */
62 ogg_uint32_t *_make_words(long *l,long n,long sparsecount){
63 long i,j,count=0;
64 ogg_uint32_t marker[33];
65 ogg_uint32_t *r=(ogg_uint32_t *)_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r));
66 memset(marker,0,sizeof(marker));
67
68 for(i=0;i<n;i++){
69 long length=l[i];
70 if(length>0){
71 ogg_uint32_t entry=marker[length];
72
73 /* when we claim a node for an entry, we also claim the nodes
74 below it (pruning off the imagined tree that may have dangled
75 from it) as well as blocking the use of any nodes directly
76 above for leaves */
77
78 /* update ourself */
79 if(length<32 && (entry>>length)){
80 /* error condition; the lengths must specify an overpopulated tree */
81 _ogg_free(r);
82 return(NULL);
83 }
84 r[count++]=entry;
85
86 /* Look to see if the next shorter marker points to the node
87 above. if so, update it and repeat. */
88 {
89 for(j=length;j>0;j--){
90
91 if(marker[j]&1){
92 /* have to jump branches */
93 if(j==1)
94 marker[1]++;
95 else
96 marker[j]=marker[j-1]<<1;
97 break; /* invariant says next upper marker would already
98 have been moved if it was on the same path */
99 }
100 marker[j]++;
101 }
102 }
103
104 /* prune the tree; the implicit invariant says all the longer
105 markers were dangling from our just-taken node. Dangle them
106 from our *new* node. */
107 for(j=length+1;j<33;j++)
108 if((marker[j]>>1) == entry){
109 entry=marker[j];
110 marker[j]=marker[j-1]<<1;
111 }else
112 break;
113 }else
114 if(sparsecount==0)count++;
115 }
116
117 /* sanity check the huffman tree; an underpopulated tree must be
118 rejected. The only exception is the one-node pseudo-nil tree,
119 which appears to be underpopulated because the tree doesn't
120 really exist; there's only one possible 'codeword' or zero bits,
121 but the above tree-gen code doesn't mark that. */
122 if(sparsecount != 1){
123 for(i=1;i<33;i++)
124 if(marker[i] & (0xffffffffUL>>(32-i))){
125 _ogg_free(r);
126 return(NULL);
127 }
128 }
129
130 /* bitreverse the words because our bitwise packer/unpacker is LSb
131 endian */
132 for(i=0,count=0;i<n;i++){
133 ogg_uint32_t temp=0;
134 for(j=0;j<l[i];j++){
135 temp<<=1;
136 temp|=(r[count]>>j)&1;
137 }
138
139 if(sparsecount){
140 if(l[i])
141 r[count++]=temp;
142 }else
143 r[count++]=temp;
144 }
145
146 return(r);
147 }
148
149 /* there might be a straightforward one-line way to do the below
150 that's portable and totally safe against roundoff, but I haven't
151 thought of it. Therefore, we opt on the side of caution */
152 long _book_maptype1_quantvals(const static_codebook *b){
153 /* get us a starting hint, we'll polish it below */
154 int bits= ilog(b->entries);
155 int vals=b->entries>>((bits-1)*(b->dim-1)/b->dim);
156
157 while(1){
158 long acc=1;
159 long acc1=1;
160 int i;
161 for(i=0;i<b->dim;i++){
162 acc*=vals;
163 acc1*=vals+1;
164 }
165 if(acc<=b->entries && acc1>b->entries){
166 return(vals);
167 }else{
168 if(acc>b->entries){
169 vals--;
170 }else{
171 vals++;
172 }
173 }
174 }
175 }
176
177 /* different than what _book_unquantize does for mainline:
178 we repack the book in a fixed point format that shares the same
179 binary point. Upon first use, we can shift point if needed */
180
181 /* we need to deal with two map types: in map type 1, the values are
182 generated algorithmically (each column of the vector counts through
183 the values in the quant vector). in map type 2, all the values came
184 in in an explicit list. Both value lists must be unpacked */
185
186 ogg_int32_t *_book_unquantize(const static_codebook *b,int n,int *sparsemap,
187 int *maxpoint){
188 long j,k,count=0;
189 if(b->maptype==1 || b->maptype==2){
190 int quantvals;
191 int minpoint,delpoint;
192 ogg_int32_t mindel=_float32_unpack(b->q_min,&minpoint);
193 ogg_int32_t delta=_float32_unpack(b->q_delta,&delpoint);
194 ogg_int32_t *r=(ogg_int32_t *)_ogg_calloc(n*b->dim,sizeof(*r));
195 int *rp=(int *)_ogg_calloc(n*b->dim,sizeof(*rp));
196
197 *maxpoint=minpoint;
198
199 /* maptype 1 and 2 both use a quantized value vector, but
200 different sizes */
201 switch(b->maptype){
202 case 1:
203 /* most of the time, entries%dimensions == 0, but we need to be
204 well defined. We define that the possible vales at each
205 scalar is values == entries/dim. If entries%dim != 0, we'll
206 have 'too few' values (values*dim<entries), which means that
207 we'll have 'left over' entries; left over entries use zeroed
208 values (and are wasted). So don't generate codebooks like
209 that */
210 quantvals=_book_maptype1_quantvals(b);
211 for(j=0;j<b->entries;j++){
212 if((sparsemap && b->lengthlist[j]) || !sparsemap){
213 ogg_int32_t last=0;
214 int lastpoint=0;
215 int indexdiv=1;
216 for(k=0;k<b->dim;k++){
217 int index= (j/indexdiv)%quantvals;
218 int point=0;
219 int val=VFLOAT_MULTI(delta,delpoint,
220 abs(b->quantlist[index]),&point);
221
222 val=VFLOAT_ADD(mindel,minpoint,val,point,&point);
223 val=VFLOAT_ADD(last,lastpoint,val,point,&point);
224
225 if(b->q_sequencep){
226 last=val;
227 lastpoint=point;
228 }
229
230 if(sparsemap){
231 r[sparsemap[count]*b->dim+k]=val;
232 rp[sparsemap[count]*b->dim+k]=point;
233 }else{
234 r[count*b->dim+k]=val;
235 rp[count*b->dim+k]=point;
236 }
237 if(*maxpoint<point)*maxpoint=point;
238 indexdiv*=quantvals;
239 }
240 count++;
241 }
242
243 }
244 break;
245 case 2:
246 for(j=0;j<b->entries;j++){
247 if((sparsemap && b->lengthlist[j]) || !sparsemap){
248 ogg_int32_t last=0;
249 int lastpoint=0;
250
251 for(k=0;k<b->dim;k++){
252 int point=0;
253 int val=VFLOAT_MULTI(delta,delpoint,
254 abs(b->quantlist[j*b->dim+k]),&point);
255
256 val=VFLOAT_ADD(mindel,minpoint,val,point,&point);
257 val=VFLOAT_ADD(last,lastpoint,val,point,&point);
258
259 if(b->q_sequencep){
260 last=val;
261 lastpoint=point;
262 }
263
264 if(sparsemap){
265 r[sparsemap[count]*b->dim+k]=val;
266 rp[sparsemap[count]*b->dim+k]=point;
267 }else{
268 r[count*b->dim+k]=val;
269 rp[count*b->dim+k]=point;
270 }
271 if(*maxpoint<point)*maxpoint=point;
272 }
273 count++;
274 }
275 }
276 break;
277 }
278
279 for(j=0;j<n*b->dim;j++)
280 if(rp[j]<*maxpoint)
281 r[j]>>=*maxpoint-rp[j];
282
283 _ogg_free(rp);
284 return(r);
285 }
286 return(NULL);
287 }
288
289 void vorbis_staticbook_destroy(static_codebook *b){
290 if(b->quantlist)_ogg_free(b->quantlist);
291 if(b->lengthlist)_ogg_free(b->lengthlist);
292 memset(b,0,sizeof(*b));
293 _ogg_free(b);
294 }
295
296 void vorbis_book_clear(codebook *b){
297 /* static book is not cleared; we're likely called on the lookup and
298 the static codebook belongs to the info struct */
299 if(b->valuelist)_ogg_free(b->valuelist);
300 if(b->codelist)_ogg_free(b->codelist);
301
302 if(b->dec_index)_ogg_free(b->dec_index);
303 if(b->dec_codelengths)_ogg_free(b->dec_codelengths);
304 if(b->dec_firsttable)_ogg_free(b->dec_firsttable);
305
306 memset(b,0,sizeof(*b));
307 }
308
309 static int sort32a(const void *a,const void *b){
310 return (**(ogg_uint32_t **)a>**(ogg_uint32_t **)b)-
311 (**(ogg_uint32_t **)a<**(ogg_uint32_t **)b);
312 }
313
314 /* decode codebook arrangement is more heavily optimized than encode */
315 int vorbis_book_init_decode(codebook *c,const static_codebook *s){
316 int i,j,n=0,tabn;
317 int *sortindex;
318 memset(c,0,sizeof(*c));
319
320 /* count actually used entries */
321 for(i=0;i<s->entries;i++)
322 if(s->lengthlist[i]>0)
323 n++;
324
325 c->entries=s->entries;
326 c->used_entries=n;
327 c->dim=s->dim;
328
329 if(n>0){
330 /* two different remappings go on here.
331
332 First, we collapse the likely sparse codebook down only to
333 actually represented values/words. This collapsing needs to be
334 indexed as map-valueless books are used to encode original entry
335 positions as integers.
336
337 Second, we reorder all vectors, including the entry index above,
338 by sorted bitreversed codeword to allow treeless decode. */
339
340 /* perform sort */
341 ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries);
342 ogg_uint32_t **codep=(ogg_uint32_t **)alloca(sizeof(*codep)*n);
343
344 if(codes==NULL)goto err_out;
345
346 for(i=0;i<n;i++){
347 codes[i]=bitreverse(codes[i]);
348 codep[i]=codes+i;
349 }
350
351 qsort(codep,n,sizeof(*codep),sort32a);
352
353 sortindex=(int *)alloca(n*sizeof(*sortindex));
354 c->codelist=(ogg_uint32_t *)_ogg_malloc(n*sizeof(*c->codelist));
355 /* the index is a reverse index */
356 for(i=0;i<n;i++){
357 int position=codep[i]-codes;
358 sortindex[position]=i;
359 }
360
361 for(i=0;i<n;i++)
362 c->codelist[sortindex[i]]=codes[i];
363 _ogg_free(codes);
364
365
366
367 c->valuelist=_book_unquantize(s,n,sortindex,&c->binarypoint);
368 c->dec_index=(int *)_ogg_malloc(n*sizeof(*c->dec_index));
369
370 for(n=0,i=0;i<s->entries;i++)
371 if(s->lengthlist[i]>0)
372 c->dec_index[sortindex[n++]]=i;
373
374 c->dec_codelengths=(char *)_ogg_malloc(n*sizeof(*c->dec_codelengths));
375 for(n=0,i=0;i<s->entries;i++)
376 if(s->lengthlist[i]>0)
377 c->dec_codelengths[sortindex[n++]]=s->lengthlist[i];
378
379 c->dec_firsttablen= ilog(c->used_entries)-4; /* this is magic */
380 if(c->dec_firsttablen<5)c->dec_firsttablen=5;
381 if(c->dec_firsttablen>8)c->dec_firsttablen=8;
382
383 tabn=1<<c->dec_firsttablen;
384 c->dec_firsttable=(ogg_uint32_t *)_ogg_calloc(tabn,sizeof(*c->dec_firsttable));
385 c->dec_maxlength=0;
386
387 for(i=0;i<n;i++){
388 if(c->dec_maxlength<c->dec_codelengths[i])
389 c->dec_maxlength=c->dec_codelengths[i];
390 if(c->dec_codelengths[i]<=c->dec_firsttablen){
391 ogg_uint32_t orig=bitreverse(c->codelist[i]);
392 for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++)
393 c->dec_firsttable[orig|(j<<c->dec_codelengths[i])]=i+1;
394 }
395 }
396
397 /* now fill in 'unused' entries in the firsttable with hi/lo search
398 hints for the non-direct-hits */
399 {
400 ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen);
401 long lo=0,hi=0;
402
403 for(i=0;i<tabn;i++){
404 ogg_uint32_t word=i<<(32-c->dec_firsttablen);
405 if(c->dec_firsttable[bitreverse(word)]==0){
406 while((lo+1)<n && c->codelist[lo+1]<=word)lo++;
407 while( hi<n && word>=(c->codelist[hi]&mask))hi++;
408
409 /* we only actually have 15 bits per hint to play with here.
410 In order to overflow gracefully (nothing breaks, efficiency
411 just drops), encode as the difference from the extremes. */
412 {
413 unsigned long loval=lo;
414 unsigned long hival=n-hi;
415
416 if(loval>0x7fff)loval=0x7fff;
417 if(hival>0x7fff)hival=0x7fff;
418 c->dec_firsttable[bitreverse(word)]=
419 0x80000000UL | (loval<<15) | hival;
420 }
421 }
422 }
423 }
424 }
425
426 return(0);
427 err_out:
428 vorbis_book_clear(c);
429 return(-1);
430 }
431
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2003 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: single-block PCM synthesis
14 last mod: $Id: synthesis.c,v 1.4 2003/03/29 03:07:21 xiphmont Exp $
15
16 ********************************************************************/
17
18 #include <stdio.h>
19 #include "ogg.h"
20 #include "ivorbiscodec.h"
21 #include "codec_internal.h"
22 #include "registry.h"
23 #include "misc.h"
24 #include "block.h"
25
26 static int _vorbis_synthesis1(vorbis_block *vb,ogg_packet *op,int decodep){
27 vorbis_dsp_state *vd= vb ? vb->vd : 0;
28 private_state *b= vd ? (private_state *)vd->backend_state: 0;
29 vorbis_info *vi= vd ? vd->vi : 0;
30 codec_setup_info *ci= vi ? (codec_setup_info *)vi->codec_setup : 0;
31 oggpack_buffer *opb=vb ? &vb->opb : 0;
32 int type,mode,i;
33
34 if (!vd || !b || !vi || !ci || !opb) {
35 return OV_EBADPACKET;
36 }
37
38 /* first things first. Make sure decode is ready */
39 _vorbis_block_ripcord(vb);
40 oggpack_readinit(opb,op->packet,op->bytes);
41
42 /* Check the packet type */
43 if(oggpack_read(opb,1)!=0){
44 /* Oops. This is not an audio data packet */
45 return(OV_ENOTAUDIO);
46 }
47
48 /* read our mode and pre/post windowsize */
49 mode=oggpack_read(opb,b->modebits);
50 if(mode==-1)return(OV_EBADPACKET);
51
52 vb->mode=mode;
53 if(!ci->mode_param[mode]){
54 return(OV_EBADPACKET);
55 }
56
57 vb->W=ci->mode_param[mode]->blockflag;
58 if(vb->W){
59 vb->lW=oggpack_read(opb,1);
60 vb->nW=oggpack_read(opb,1);
61 if(vb->nW==-1) return(OV_EBADPACKET);
62 }else{
63 vb->lW=0;
64 vb->nW=0;
65 }
66
67 /* more setup */
68 vb->granulepos=op->granulepos;
69 vb->sequence=op->packetno-3; /* first block is third packet */
70 vb->eofflag=op->e_o_s;
71
72 if(decodep){
73 /* alloc pcm passback storage */
74 vb->pcmend=ci->blocksizes[vb->W];
75 vb->pcm=(ogg_int32_t **)_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels);
76 for(i=0;i<vi->channels;i++)
77 vb->pcm[i]=(ogg_int32_t *)_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i]));
78
79 /* unpack_header enforces range checking */
80 type=ci->map_type[ci->mode_param[mode]->mapping];
81
82 return(_mapping_P[type]->inverse(vb,b->mode[mode]));
83 }else{
84 /* no pcm */
85 vb->pcmend=0;
86 vb->pcm=NULL;
87
88 return(0);
89 }
90 }
91
92 int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){
93 return _vorbis_synthesis1(vb,op,1);
94 }
95
96 /* used to track pcm position without actually performing decode.
97 Useful for sequential 'fast forward' */
98 int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){
99 return _vorbis_synthesis1(vb,op,0);
100 }
101
102 long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){
103 codec_setup_info *ci=(codec_setup_info *)vi->codec_setup;
104 oggpack_buffer opb;
105 int mode;
106
107 oggpack_readinit(&opb,op->packet,op->bytes);
108
109 /* Check the packet type */
110 if(oggpack_read(&opb,1)!=0){
111 /* Oops. This is not an audio data packet */
112 return(OV_ENOTAUDIO);
113 }
114
115 {
116 int modebits=0;
117 int v=ci->modes;
118 while(v>1){
119 modebits++;
120 v>>=1;
121 }
122
123 /* read our mode and pre/post windowsize */
124 mode=oggpack_read(&opb,modebits);
125 }
126 if(mode==-1)return(OV_EBADPACKET);
127 return(ci->blocksizes[ci->mode_param[mode]->blockflag]);
128 }
129
130
0 #ifndef _TREMOR_SHARED_H_
1 #define _TREMOR_SHARED_H_
2
3 #include <stdint.h>
4 #include <stddef.h>
5 #include <retro_inline.h>
6
7 #ifdef __cplusplus
8 extern "C" {
9 #endif
10
11 static INLINE int ilog(unsigned int v)
12 {
13 int ret=0;
14 while(v)
15 {
16 ret++;
17 v>>=1;
18 }
19 return(ret);
20 }
21
22 #include "os_types.h"
23
24 static INLINE ogg_uint32_t bitreverse(ogg_uint32_t x)
25 {
26 x= ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL);
27 x= ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL);
28 x= ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL);
29 x= ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL);
30 return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL);
31 }
32
33 #ifdef __cplusplus
34 }
35 #endif
36
37 #endif
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2009 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: stdio-based convenience library for opening/seeking/decoding
14 last mod: $Id: vorbisfile.c,v 1.6 2003/03/30 23:40:56 xiphmont Exp $
15
16 ********************************************************************/
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <errno.h>
21 #include <string.h>
22 #include <math.h>
23
24 #include "ivorbiscodec.h"
25 #include "ivorbisfile.h"
26
27 #include "os.h"
28 #include "misc.h"
29
30 /* A 'chained bitstream' is a Vorbis bitstream that contains more than
31 one logical bitstream arranged end to end (the only form of Ogg
32 multiplexing allowed in a Vorbis bitstream; grouping [parallel
33 multiplexing] is not allowed in Vorbis) */
34
35 /* A Vorbis file can be played beginning to end (streamed) without
36 worrying ahead of time about chaining (see decoder_example.c). If
37 we have the whole file, however, and want random access
38 (seeking/scrubbing) or desire to know the total length/time of a
39 file, we need to account for the possibility of chaining. */
40
41 /* We can handle things a number of ways; we can determine the entire
42 bitstream structure right off the bat, or find pieces on demand.
43 This example determines and caches structure for the entire
44 bitstream, but builds a virtual decoder on the fly when moving
45 between links in the chain. */
46
47 /* There are also different ways to implement seeking. Enough
48 information exists in an Ogg bitstream to seek to
49 sample-granularity positions in the output. Or, one can seek by
50 picking some portion of the stream roughly in the desired area if
51 we only want coarse navigation through the stream. */
52
53 /*************************************************************************
54 * Many, many internal helpers. The intention is not to be confusing;
55 * rampant duplication and monolithic function implementation would be
56 * harder to understand anyway. The high level functions are last. Begin
57 * grokking near the end of the file */
58
59
60 /* read a little more data from the file/pipe into the ogg_sync framer */
61 static long _get_data(OggVorbis_File *vf){
62 errno=0;
63 if(!(vf->callbacks.read_func))return(-1);
64 if(vf->datasource){
65 char *buffer=ogg_sync_buffer(&vf->oy,CHUNKSIZE);
66 long bytes=(vf->callbacks.read_func)(buffer,1,CHUNKSIZE,vf->datasource);
67 if(bytes>0)ogg_sync_wrote(&vf->oy,bytes);
68 if(bytes==0 && errno)return(-1);
69 return(bytes);
70 }else
71 return(0);
72 }
73
74 /* save a tiny smidge of verbosity to make the code more readable */
75 static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){
76 if(vf->datasource){
77 if(!(vf->callbacks.seek_func)||
78 (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1)
79 return OV_EREAD;
80 vf->offset=offset;
81 ogg_sync_reset(&vf->oy);
82 }else{
83 /* shouldn't happen unless someone writes a broken callback */
84 return OV_EFAULT;
85 }
86 return 0;
87 }
88
89 /* The read/seek functions track absolute position within the stream */
90
91 /* from the head of the stream, get the next page. boundary specifies
92 if the function is allowed to fetch more data from the stream (and
93 how much) or only use internally buffered data.
94
95 boundary: -1) unbounded search
96 0) read no additional data; use cached only
97 n) search for a new page beginning for n bytes
98
99 return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD)
100 n) found a page at absolute offset n */
101
102 static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og,
103 ogg_int64_t boundary){
104 if(boundary>0)boundary+=vf->offset;
105 while(1){
106 long more;
107
108 if(boundary>0 && vf->offset>=boundary)return(OV_FALSE);
109 more=ogg_sync_pageseek(&vf->oy,og);
110
111 if(more<0){
112 /* skipped n bytes */
113 vf->offset-=more;
114 }else{
115 if(more==0){
116 /* send more paramedics */
117 if(!boundary)return(OV_FALSE);
118 {
119 long ret=_get_data(vf);
120 if(ret==0)return(OV_EOF);
121 if(ret<0)return(OV_EREAD);
122 }
123 }else{
124 /* got a page. Return the offset at the page beginning,
125 advance the internal offset past the page end */
126 ogg_int64_t ret=vf->offset;
127 vf->offset+=more;
128 return(ret);
129
130 }
131 }
132 }
133 }
134
135 /* find the latest page beginning before the current stream cursor
136 position. Much dirtier than the above as Ogg doesn't have any
137 backward search linkage. no 'readp' as it will certainly have to
138 read. */
139 /* returns offset or OV_EREAD, OV_FAULT */
140 static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_page *og){
141 ogg_int64_t begin=vf->offset;
142 ogg_int64_t end=begin;
143 ogg_int64_t ret;
144 ogg_int64_t offset=-1;
145
146 while(offset==-1){
147 begin-=CHUNKSIZE;
148 if(begin<0)
149 begin=0;
150
151 ret=_seek_helper(vf,begin);
152 if(ret)return(ret);
153
154 while(vf->offset<end){
155 memset(og,0,sizeof(*og));
156 ret=_get_next_page(vf,og,end-vf->offset);
157 if(ret==OV_EREAD)return(OV_EREAD);
158 if(ret<0){
159 break;
160 }else{
161 offset=ret;
162 }
163 }
164 }
165
166 /* In a fully compliant, non-multiplexed stream, we'll still be
167 holding the last page. In multiplexed (or noncompliant streams),
168 we will probably have to re-read the last page we saw */
169 if(og->header_len==0){
170 ret=_seek_helper(vf,offset);
171 if(ret)return(ret);
172
173 ret=_get_next_page(vf,og,CHUNKSIZE);
174 if(ret<0)
175 /* this shouldn't be possible */
176 return(OV_EFAULT);
177 }
178
179 return(offset);
180 }
181
182 static void _add_serialno(ogg_page *og,ogg_uint32_t **serialno_list, int *n){
183 ogg_uint32_t s = ogg_page_serialno(og);
184 (*n)++;
185
186 if(*serialno_list){
187 *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n));
188 }else{
189 *serialno_list = _ogg_malloc(sizeof(**serialno_list));
190 }
191
192 (*serialno_list)[(*n)-1] = s;
193 }
194
195 /* returns nonzero if found */
196 static int _lookup_serialno(ogg_uint32_t s, ogg_uint32_t *serialno_list, int n){
197 if(serialno_list){
198 while(n--){
199 if(*serialno_list == s) return 1;
200 serialno_list++;
201 }
202 }
203 return 0;
204 }
205
206 static int _lookup_page_serialno(ogg_page *og, ogg_uint32_t *serialno_list, int n){
207 ogg_uint32_t s = ogg_page_serialno(og);
208 return _lookup_serialno(s,serialno_list,n);
209 }
210
211 /* performs the same search as _get_prev_page, but prefers pages of
212 the specified serial number. If a page of the specified serialno is
213 spotted during the seek-back-and-read-forward, it will return the
214 info of last page of the matching serial number instead of the very
215 last page. If no page of the specified serialno is seen, it will
216 return the info of last page and alter *serialno. */
217 static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf,
218 ogg_uint32_t *serial_list, int serial_n,
219 int *serialno, ogg_int64_t *granpos){
220 ogg_page og;
221 ogg_int64_t begin=vf->offset;
222 ogg_int64_t end=begin;
223 ogg_int64_t ret;
224
225 ogg_int64_t prefoffset=-1;
226 ogg_int64_t offset=-1;
227 ogg_int64_t ret_serialno=-1;
228 ogg_int64_t ret_gran=-1;
229
230 while(offset==-1){
231 begin-=CHUNKSIZE;
232 if(begin<0)
233 begin=0;
234
235 ret=_seek_helper(vf,begin);
236 if(ret)return(ret);
237
238 while(vf->offset<end){
239 ret=_get_next_page(vf,&og,end-vf->offset);
240 if(ret==OV_EREAD)return(OV_EREAD);
241 if(ret<0){
242 break;
243 }else{
244 ret_serialno=ogg_page_serialno(&og);
245 ret_gran=ogg_page_granulepos(&og);
246 offset=ret;
247
248 if((ogg_uint32_t)ret_serialno == *serialno){
249 prefoffset=ret;
250 *granpos=ret_gran;
251 }
252
253 if(!_lookup_serialno((ogg_uint32_t)ret_serialno,serial_list,serial_n)){
254 /* we fell off the end of the link, which means we seeked
255 back too far and shouldn't have been looking in that link
256 to begin with. If we found the preferred serial number,
257 forget that we saw it. */
258 prefoffset=-1;
259 }
260 }
261 }
262 }
263
264 /* we're not interested in the page... just the serialno and granpos. */
265 if(prefoffset>=0)return(prefoffset);
266
267 *serialno = ret_serialno;
268 *granpos = ret_gran;
269 return(offset);
270
271 }
272
273 /* uses the local ogg_stream storage in vf; this is important for
274 non-streaming input sources */
275 static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc,
276 ogg_uint32_t **serialno_list, int *serialno_n,
277 ogg_page *og_ptr){
278 ogg_page og;
279 ogg_packet op;
280 int i,ret;
281 int allbos=0;
282
283 if(!og_ptr){
284 ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE);
285 if(llret==OV_EREAD)return(OV_EREAD);
286 if(llret<0)return(OV_ENOTVORBIS);
287 og_ptr=&og;
288 }
289
290 vorbis_info_init(vi);
291 vorbis_comment_init(vc);
292 vf->ready_state=OPENED;
293
294 /* extract the serialnos of all BOS pages + the first set of vorbis
295 headers we see in the link */
296
297 while(ogg_page_bos(og_ptr)){
298 if(serialno_list){
299 if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){
300 /* a dupe serialnumber in an initial header packet set == invalid stream */
301 if(*serialno_list)_ogg_free(*serialno_list);
302 *serialno_list=0;
303 *serialno_n=0;
304 ret=OV_EBADHEADER;
305 goto bail_header;
306 }
307
308 _add_serialno(og_ptr,serialno_list,serialno_n);
309 }
310
311 if(vf->ready_state<STREAMSET){
312 /* we don't have a vorbis stream in this link yet, so begin
313 prospective stream setup. We need a stream to get packets */
314 ogg_stream_reset_serialno(&vf->os,ogg_page_serialno(og_ptr));
315 ogg_stream_pagein(&vf->os,og_ptr);
316
317 if(ogg_stream_packetout(&vf->os,&op) > 0 &&
318 vorbis_synthesis_idheader(&op)){
319 /* vorbis header; continue setup */
320 vf->ready_state=STREAMSET;
321 if((ret=vorbis_synthesis_headerin(vi,vc,&op))){
322 ret=OV_EBADHEADER;
323 goto bail_header;
324 }
325 }
326 }
327
328 /* get next page */
329 {
330 ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE);
331 if(llret==OV_EREAD){
332 ret=OV_EREAD;
333 goto bail_header;
334 }
335 if(llret<0){
336 ret=OV_ENOTVORBIS;
337 goto bail_header;
338 }
339
340 /* if this page also belongs to our vorbis stream, submit it and break */
341 if(vf->ready_state==STREAMSET &&
342 vf->os.serialno == ogg_page_serialno(og_ptr)){
343 ogg_stream_pagein(&vf->os,og_ptr);
344 break;
345 }
346 }
347 }
348
349 if(vf->ready_state!=STREAMSET){
350 ret = OV_ENOTVORBIS;
351 goto bail_header;
352 }
353
354 while(1){
355
356 i=0;
357 while(i<2){ /* get a page loop */
358
359 while(i<2){ /* get a packet loop */
360
361 int result=ogg_stream_packetout(&vf->os,&op);
362 if(result==0)break;
363 if(result==-1){
364 ret=OV_EBADHEADER;
365 goto bail_header;
366 }
367
368 if((ret=vorbis_synthesis_headerin(vi,vc,&op)))
369 goto bail_header;
370
371 i++;
372 }
373
374 while(i<2){
375 if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){
376 ret=OV_EBADHEADER;
377 goto bail_header;
378 }
379
380 /* if this page belongs to the correct stream, go parse it */
381 if(vf->os.serialno == ogg_page_serialno(og_ptr)){
382 ogg_stream_pagein(&vf->os,og_ptr);
383 break;
384 }
385
386 /* if we never see the final vorbis headers before the link
387 ends, abort */
388 if(ogg_page_bos(og_ptr)){
389 if(allbos){
390 ret = OV_EBADHEADER;
391 goto bail_header;
392 }else
393 allbos=1;
394 }
395
396 /* otherwise, keep looking */
397 }
398 }
399
400 return 0;
401 }
402
403 bail_header:
404 vorbis_info_clear(vi);
405 vorbis_comment_clear(vc);
406 vf->ready_state=OPENED;
407
408 return ret;
409 }
410
411 /* Starting from current cursor position, get initial PCM offset of
412 next page. Consumes the page in the process without decoding
413 audio, however this is only called during stream parsing upon
414 seekable open. */
415 static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){
416 ogg_page og;
417 ogg_int64_t accumulated=0;
418 long lastblock=-1;
419 int result;
420 int serialno = vf->os.serialno;
421
422 while(1){
423 ogg_packet op;
424 if(_get_next_page(vf,&og,-1)<0)
425 break; /* should not be possible unless the file is truncated/mangled */
426
427 if(ogg_page_bos(&og)) break;
428 if(ogg_page_serialno(&og)!=serialno) continue;
429
430 /* count blocksizes of all frames in the page */
431 ogg_stream_pagein(&vf->os,&og);
432 while((result=ogg_stream_packetout(&vf->os,&op))){
433 if(result>0){ /* ignore holes */
434 long thisblock=vorbis_packet_blocksize(vi,&op);
435 if(lastblock!=-1)
436 accumulated+=(lastblock+thisblock)>>2;
437 lastblock=thisblock;
438 }
439 }
440
441 if(ogg_page_granulepos(&og)!=-1){
442 /* pcm offset of last packet on the first audio page */
443 accumulated= ogg_page_granulepos(&og)-accumulated;
444 break;
445 }
446 }
447
448 /* less than zero? This is a stream with samples trimmed off
449 the beginning, a normal occurrence; set the offset to zero */
450 if(accumulated<0)accumulated=0;
451
452 return accumulated;
453 }
454
455 /* finds each bitstream link one at a time using a bisection search
456 (has to begin by knowing the offset of the lb's initial page).
457 Recurses for each link so it can alloc the link storage after
458 finding them all, then unroll and fill the cache at the same time */
459 static int _bisect_forward_serialno(OggVorbis_File *vf,
460 ogg_int64_t begin,
461 ogg_int64_t searched,
462 ogg_int64_t end,
463 ogg_int64_t endgran,
464 int endserial,
465 ogg_uint32_t *currentno_list,
466 int currentnos,
467 long m){
468 ogg_int64_t pcmoffset;
469 ogg_int64_t dataoffset=searched;
470 ogg_int64_t endsearched=end;
471 ogg_int64_t next=end;
472 ogg_int64_t searchgran=-1;
473 ogg_page og;
474 ogg_int64_t ret,last;
475 int serialno = vf->os.serialno;
476
477 /* invariants:
478 we have the headers and serialnos for the link beginning at 'begin'
479 we have the offset and granpos of the last page in the file (potentially
480 not a page we care about)
481 */
482
483 /* Is the last page in our list of current serialnumbers? */
484 if(_lookup_serialno(endserial,currentno_list,currentnos)){
485
486 /* last page is in the starting serialno list, so we've bisected
487 down to (or just started with) a single link. Now we need to
488 find the last vorbis page belonging to the first vorbis stream
489 for this link. */
490
491 while(endserial != serialno){
492 endserial = serialno;
493 vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&endserial,&endgran);
494 }
495
496 vf->links=m+1;
497 if(vf->offsets)_ogg_free(vf->offsets);
498 if(vf->serialnos)_ogg_free(vf->serialnos);
499 if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
500
501 vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets));
502 vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi));
503 vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc));
504 vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos));
505 vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets));
506 vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths));
507
508 vf->offsets[m+1]=end;
509 vf->offsets[m]=begin;
510 vf->pcmlengths[m*2+1]=endgran;
511
512 }else{
513
514 ogg_uint32_t *next_serialno_list=NULL;
515 int next_serialnos=0;
516 vorbis_info vi;
517 vorbis_comment vc;
518
519 /* the below guards against garbage seperating the last and
520 first pages of two links. */
521 while(searched<endsearched){
522 ogg_int64_t bisect;
523
524 if(endsearched-searched<CHUNKSIZE){
525 bisect=searched;
526 }else{
527 bisect=(searched+endsearched)/2;
528 }
529
530 if(bisect != vf->offset){
531 ret=_seek_helper(vf,bisect);
532 if(ret)return(ret);
533 }
534
535 last=_get_next_page(vf,&og,-1);
536 if(last==OV_EREAD)return(OV_EREAD);
537 if(last<0 || !_lookup_page_serialno(&og,currentno_list,currentnos)){
538 endsearched=bisect;
539 if(last>=0)next=last;
540 }else{
541 searched=vf->offset;
542 }
543 }
544
545 /* Bisection point found */
546
547 /* for the time being, fetch end PCM offset the simple way */
548 {
549 int testserial = serialno+1;
550 vf->offset = next;
551 while(testserial != serialno){
552 testserial = serialno;
553 vf->offset=_get_prev_page_serial(vf,currentno_list,currentnos,&testserial,&searchgran);
554 }
555 }
556
557 if(vf->offset!=next){
558 ret=_seek_helper(vf,next);
559 if(ret)return(ret);
560 }
561
562 ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL);
563 if(ret)return(ret);
564 serialno = vf->os.serialno;
565 dataoffset = vf->offset;
566
567 /* this will consume a page, however the next bistection always
568 starts with a raw seek */
569 pcmoffset = _initial_pcmoffset(vf,&vi);
570
571 ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial,
572 next_serialno_list,next_serialnos,m+1);
573 if(ret)return(ret);
574
575 if(next_serialno_list)_ogg_free(next_serialno_list);
576
577 vf->offsets[m+1]=next;
578 vf->serialnos[m+1]=serialno;
579 vf->dataoffsets[m+1]=dataoffset;
580
581 vf->vi[m+1]=vi;
582 vf->vc[m+1]=vc;
583
584 vf->pcmlengths[m*2+1]=searchgran;
585 vf->pcmlengths[m*2+2]=pcmoffset;
586 vf->pcmlengths[m*2+3]-=pcmoffset;
587
588 }
589 return(0);
590 }
591
592 static int _make_decode_ready(OggVorbis_File *vf){
593 if(vf->ready_state>STREAMSET)return 0;
594 if(vf->ready_state<STREAMSET)return OV_EFAULT;
595 if(vf->seekable){
596 if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link))
597 return OV_EBADLINK;
598 }else{
599 if(vorbis_synthesis_init(&vf->vd,vf->vi))
600 return OV_EBADLINK;
601 }
602 vorbis_block_init(&vf->vd,&vf->vb);
603 vf->ready_state=INITSET;
604 vf->bittrack=0;
605 vf->samptrack=0;
606 return 0;
607 }
608
609 static int _open_seekable2(OggVorbis_File *vf){
610 ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1;
611 int endserial=vf->os.serialno;
612 int serialno=vf->os.serialno;
613
614 /* we're partially open and have a first link header state in
615 storage in vf */
616
617 /* fetch initial PCM offset */
618 ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi);
619
620 /* we can seek, so set out learning all about this file */
621 if(vf->callbacks.seek_func && vf->callbacks.tell_func){
622 (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END);
623 vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource);
624 }else{
625 vf->offset=vf->end=-1;
626 }
627
628 /* If seek_func is implemented, tell_func must also be implemented */
629 if(vf->end==-1) return(OV_EINVAL);
630
631 /* Get the offset of the last page of the physical bitstream, or, if
632 we're lucky the last vorbis page of this link as most OggVorbis
633 files will contain a single logical bitstream */
634 end=_get_prev_page_serial(vf,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran);
635 if(end<0)return(end);
636
637 /* now determine bitstream structure recursively */
638 if(_bisect_forward_serialno(vf,0,dataoffset,vf->offset,endgran,endserial,
639 vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD);
640
641 vf->offsets[0]=0;
642 vf->serialnos[0]=serialno;
643 vf->dataoffsets[0]=dataoffset;
644 vf->pcmlengths[0]=pcmoffset;
645 vf->pcmlengths[1]-=pcmoffset;
646
647 return(ov_raw_seek(vf,dataoffset));
648 }
649
650 /* clear out the current logical bitstream decoder */
651 static void _decode_clear(OggVorbis_File *vf){
652 vorbis_dsp_clear(&vf->vd);
653 vorbis_block_clear(&vf->vb);
654 vf->ready_state=OPENED;
655 }
656
657 /* fetch and process a packet. Handles the case where we're at a
658 bitstream boundary and dumps the decoding machine. If the decoding
659 machine is unloaded, it loads it. It also keeps pcm_offset up to
660 date (seek and read both use this. seek uses a special hack with
661 readp).
662
663 return: <0) error, OV_HOLE (lost packet) or OV_EOF
664 0) need more data (only if readp==0)
665 1) got a packet
666 */
667
668 static int _fetch_and_process_packet(OggVorbis_File *vf,
669 ogg_packet *op_in,
670 int readp,
671 int spanp){
672 ogg_page og;
673
674 /* handle one packet. Try to fetch it from current stream state */
675 /* extract packets from page */
676 while(1){
677
678 if(vf->ready_state==STREAMSET){
679 int ret=_make_decode_ready(vf);
680 if(ret<0)return ret;
681 }
682
683 /* process a packet if we can. If the machine isn't loaded,
684 neither is a page */
685 if(vf->ready_state==INITSET){
686 while(1) {
687 ogg_packet op;
688 ogg_packet *op_ptr=(op_in?op_in:&op);
689 int result=ogg_stream_packetout(&vf->os,op_ptr);
690 ogg_int64_t granulepos;
691
692 op_in=NULL;
693 if(result==-1)return(OV_HOLE); /* hole in the data. */
694 if(result>0){
695 /* got a packet. process it */
696 granulepos=op_ptr->granulepos;
697 if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy
698 header handling. The
699 header packets aren't
700 audio, so if/when we
701 submit them,
702 vorbis_synthesis will
703 reject them */
704
705 /* suck in the synthesis data and track bitrate */
706 {
707 int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL);
708 /* for proper use of libvorbis within libvorbisfile,
709 oldsamples will always be zero. */
710 if(oldsamples)return(OV_EFAULT);
711
712 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
713 vf->samptrack+=vorbis_synthesis_pcmout(&vf->vd,NULL)-oldsamples;
714 vf->bittrack+=op_ptr->bytes*8;
715 }
716
717 /* update the pcm offset. */
718 if(granulepos!=-1 && !op_ptr->e_o_s){
719 int link=(vf->seekable?vf->current_link:0);
720 int i,samples;
721
722 /* this packet has a pcm_offset on it (the last packet
723 completed on a page carries the offset) After processing
724 (above), we know the pcm position of the *last* sample
725 ready to be returned. Find the offset of the *first*
726
727 As an aside, this trick is inaccurate if we begin
728 reading anew right at the last page; the end-of-stream
729 granulepos declares the last frame in the stream, and the
730 last packet of the last page may be a partial frame.
731 So, we need a previous granulepos from an in-sequence page
732 to have a reference point. Thus the !op_ptr->e_o_s clause
733 above */
734
735 if(vf->seekable && link>0)
736 granulepos-=vf->pcmlengths[link*2];
737 if(granulepos<0)granulepos=0; /* actually, this
738 shouldn't be possible
739 here unless the stream
740 is very broken */
741
742 samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
743
744 granulepos-=samples;
745 for(i=0;i<link;i++)
746 granulepos+=vf->pcmlengths[i*2+1];
747 vf->pcm_offset=granulepos;
748 }
749 return(1);
750 }
751 }
752 else
753 break;
754 }
755 }
756
757 if(vf->ready_state>=OPENED){
758 ogg_int64_t ret;
759
760 while(1){
761 /* the loop is not strictly necessary, but there's no sense in
762 doing the extra checks of the larger loop for the common
763 case in a multiplexed bistream where the page is simply
764 part of a different logical bitstream; keep reading until
765 we get one with the correct serialno */
766
767 if(!readp)return(0);
768 if((ret=_get_next_page(vf,&og,-1))<0){
769 return(OV_EOF); /* eof. leave unitialized */
770 }
771
772 /* bitrate tracking; add the header's bytes here, the body bytes
773 are done by packet above */
774 vf->bittrack+=og.header_len*8;
775
776 if(vf->ready_state==INITSET){
777 if(vf->current_serialno!=ogg_page_serialno(&og)){
778
779 /* two possibilities:
780 1) our decoding just traversed a bitstream boundary
781 2) another stream is multiplexed into this logical section */
782
783 if(ogg_page_bos(&og)){
784 /* boundary case */
785 if(!spanp)
786 return(OV_EOF);
787
788 _decode_clear(vf);
789
790 if(!vf->seekable){
791 vorbis_info_clear(vf->vi);
792 vorbis_comment_clear(vf->vc);
793 }
794 break;
795
796 }else
797 continue; /* possibility #2 */
798 }
799 }
800
801 break;
802 }
803 }
804
805 /* Do we need to load a new machine before submitting the page? */
806 /* This is different in the seekable and non-seekable cases.
807
808 In the seekable case, we already have all the header
809 information loaded and cached; we just initialize the machine
810 with it and continue on our merry way.
811
812 In the non-seekable (streaming) case, we'll only be at a
813 boundary if we just left the previous logical bitstream and
814 we're now nominally at the header of the next bitstream
815 */
816
817 if(vf->ready_state!=INITSET){
818 int link;
819
820 if(vf->ready_state<STREAMSET){
821 if(vf->seekable){
822 ogg_uint32_t serialno = ogg_page_serialno(&og);
823
824 /* match the serialno to bitstream section. We use this rather than
825 offset positions to avoid problems near logical bitstream
826 boundaries */
827
828 for(link=0;link<vf->links;link++)
829 if(vf->serialnos[link]==serialno)break;
830
831 if(link==vf->links) continue; /* not the desired Vorbis
832 bitstream section; keep
833 trying */
834
835 vf->current_serialno=serialno;
836 vf->current_link=link;
837
838 ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
839 vf->ready_state=STREAMSET;
840
841 }else{
842 /* we're streaming */
843 /* fetch the three header packets, build the info struct */
844
845 int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og);
846 if(ret)return(ret);
847 vf->current_serialno=vf->os.serialno;
848 vf->current_link++;
849 link=0;
850 }
851 }
852 }
853
854 /* the buffered page is the data we want, and we're ready for it;
855 add it to the stream state */
856 ogg_stream_pagein(&vf->os,&og);
857
858 }
859 }
860
861 /* if, eg, 64 bit stdio is configured by default, this will build with
862 fseek64 */
863 static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){
864 if(f==NULL)return(-1);
865 return fseek(f,off,whence);
866 }
867
868 static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial,
869 long ibytes, ov_callbacks callbacks){
870 int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1);
871 ogg_uint32_t *serialno_list=NULL;
872 int serialno_list_size=0;
873 int ret;
874
875 memset(vf,0,sizeof(*vf));
876 vf->datasource=f;
877 vf->callbacks = callbacks;
878
879 /* init the framing state */
880 ogg_sync_init(&vf->oy);
881
882 /* perhaps some data was previously read into a buffer for testing
883 against other stream types. Allow initialization from this
884 previously read data (especially as we may be reading from a
885 non-seekable stream) */
886 if(initial){
887 char *buffer=ogg_sync_buffer(&vf->oy,ibytes);
888 memcpy(buffer,initial,ibytes);
889 ogg_sync_wrote(&vf->oy,ibytes);
890 }
891
892 /* can we seek? Stevens suggests the seek test was portable */
893 if(offsettest!=-1)vf->seekable=1;
894
895 /* No seeking yet; Set up a 'single' (current) logical bitstream
896 entry for partial open */
897 vf->links=1;
898 vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi));
899 vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc));
900 ogg_stream_init(&vf->os,-1); /* fill in the serialno later */
901
902 /* Fetch all BOS pages, store the vorbis header and all seen serial
903 numbers, load subsequent vorbis setup headers */
904 if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){
905 vf->datasource=NULL;
906 ov_clear(vf);
907 }else{
908 /* serial number list for first link needs to be held somewhere
909 for second stage of seekable stream open; this saves having to
910 seek/reread first link's serialnumber data then. */
911 vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos));
912 vf->serialnos[0]=vf->current_serialno=vf->os.serialno;
913 vf->serialnos[1]=serialno_list_size;
914 memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos));
915
916 vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets));
917 vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets));
918 vf->offsets[0]=0;
919 vf->dataoffsets[0]=vf->offset;
920
921 vf->ready_state=PARTOPEN;
922 }
923 if(serialno_list)_ogg_free(serialno_list);
924 return(ret);
925 }
926
927 static int _ov_open2(OggVorbis_File *vf){
928 if(vf->ready_state != PARTOPEN) return OV_EINVAL;
929 vf->ready_state=OPENED;
930 if(vf->seekable){
931 int ret=_open_seekable2(vf);
932 if(ret){
933 vf->datasource=NULL;
934 ov_clear(vf);
935 }
936 return(ret);
937 }else
938 vf->ready_state=STREAMSET;
939
940 return 0;
941 }
942
943
944 /* clear out the OggVorbis_File struct */
945 int ov_clear(OggVorbis_File *vf){
946 if(vf){
947 vorbis_block_clear(&vf->vb);
948 vorbis_dsp_clear(&vf->vd);
949 ogg_stream_clear(&vf->os);
950
951 if(vf->vi && vf->links){
952 int i;
953 for(i=0;i<vf->links;i++){
954 vorbis_info_clear(vf->vi+i);
955 vorbis_comment_clear(vf->vc+i);
956 }
957 _ogg_free(vf->vi);
958 _ogg_free(vf->vc);
959 }
960 if(vf->dataoffsets)_ogg_free(vf->dataoffsets);
961 if(vf->pcmlengths)_ogg_free(vf->pcmlengths);
962 if(vf->serialnos)_ogg_free(vf->serialnos);
963 if(vf->offsets)_ogg_free(vf->offsets);
964 ogg_sync_clear(&vf->oy);
965 if(vf->datasource && vf->callbacks.close_func)
966 (vf->callbacks.close_func)(vf->datasource);
967 memset(vf,0,sizeof(*vf));
968 }
969 return(0);
970 }
971
972 /* inspects the OggVorbis file and finds/documents all the logical
973 bitstreams contained in it. Tries to be tolerant of logical
974 bitstream sections that are truncated/woogie.
975
976 return: -1) error
977 0) OK
978 */
979
980 int ov_open_callbacks(void *f,OggVorbis_File *vf,
981 const char *initial,long ibytes,ov_callbacks callbacks){
982 int ret=_ov_open1(f,vf,initial,ibytes,callbacks);
983 if(ret)return ret;
984 return _ov_open2(vf);
985 }
986
987 int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){
988 ov_callbacks callbacks = {
989 (size_t (*)(void *, size_t, size_t, void *)) fread,
990 (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap,
991 (int (*)(void *)) fclose,
992 (long (*)(void *)) ftell
993 };
994
995 return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks);
996 }
997
998 /* How many logical bitstreams in this physical bitstream? */
999 long ov_streams(OggVorbis_File *vf){
1000 return vf->links;
1001 }
1002
1003 /* Is the FILE * associated with vf seekable? */
1004 long ov_seekable(OggVorbis_File *vf){
1005 return vf->seekable;
1006 }
1007
1008 /* returns the bitrate for a given logical bitstream or the entire
1009 physical bitstream. If the file is open for random access, it will
1010 find the *actual* average bitrate. If the file is streaming, it
1011 returns the nominal bitrate (if set) else the average of the
1012 upper/lower bounds (if set) else -1 (unset).
1013
1014 If you want the actual bitrate field settings, get them from the
1015 vorbis_info structs */
1016
1017 long ov_bitrate(OggVorbis_File *vf,int i){
1018 if(vf->ready_state<OPENED)return(OV_EINVAL);
1019 if(i>=vf->links)return(OV_EINVAL);
1020 if(!vf->seekable && i!=0)return(ov_bitrate(vf,0));
1021 if(i<0){
1022 ogg_int64_t bits=0;
1023 int i;
1024 for(i=0;i<vf->links;i++)
1025 bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8;
1026 /* This once read: return(rint(bits/ov_time_total(vf,-1)));
1027 * gcc 3.x on x86 miscompiled this at optimisation level 2 and above,
1028 * so this is slightly transformed to make it work.
1029 */
1030 return(bits*1000/ov_time_total(vf,-1));
1031 }else{
1032 if(vf->seekable){
1033 /* return the actual bitrate */
1034 return((vf->offsets[i+1]-vf->dataoffsets[i])*8000/ov_time_total(vf,i));
1035 }else{
1036 /* return nominal if set */
1037 if(vf->vi[i].bitrate_nominal>0){
1038 return vf->vi[i].bitrate_nominal;
1039 }else{
1040 if(vf->vi[i].bitrate_upper>0){
1041 if(vf->vi[i].bitrate_lower>0){
1042 return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2;
1043 }else{
1044 return vf->vi[i].bitrate_upper;
1045 }
1046 }
1047 return(OV_FALSE);
1048 }
1049 }
1050 }
1051 }
1052
1053 /* returns the actual bitrate since last call. returns -1 if no
1054 additional data to offer since last call (or at beginning of stream),
1055 EINVAL if stream is only partially open
1056 */
1057 long ov_bitrate_instant(OggVorbis_File *vf){
1058 int link=(vf->seekable?vf->current_link:0);
1059 long ret;
1060 if(vf->ready_state<OPENED)return(OV_EINVAL);
1061 if(vf->samptrack==0)return(OV_FALSE);
1062 ret=vf->bittrack/vf->samptrack*vf->vi[link].rate;
1063 vf->bittrack=0;
1064 vf->samptrack=0;
1065 return(ret);
1066 }
1067
1068 /* Guess */
1069 long ov_serialnumber(OggVorbis_File *vf,int i){
1070 if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1));
1071 if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1));
1072 if(i<0){
1073 return(vf->current_serialno);
1074 }else{
1075 return(vf->serialnos[i]);
1076 }
1077 }
1078
1079 /* returns: total raw (compressed) length of content if i==-1
1080 raw (compressed) length of that logical bitstream for i==0 to n
1081 OV_EINVAL if the stream is not seekable (we can't know the length)
1082 or if stream is only partially open
1083 */
1084 ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){
1085 if(vf->ready_state<OPENED)return(OV_EINVAL);
1086 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1087 if(i<0){
1088 ogg_int64_t acc=0;
1089 int i;
1090 for(i=0;i<vf->links;i++)
1091 acc+=ov_raw_total(vf,i);
1092 return(acc);
1093 }else{
1094 return(vf->offsets[i+1]-vf->offsets[i]);
1095 }
1096 }
1097
1098 /* returns: total PCM length (samples) of content if i==-1 PCM length
1099 (samples) of that logical bitstream for i==0 to n
1100 OV_EINVAL if the stream is not seekable (we can't know the
1101 length) or only partially open
1102 */
1103 ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){
1104 if(vf->ready_state<OPENED)return(OV_EINVAL);
1105 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1106 if(i<0){
1107 ogg_int64_t acc=0;
1108 int i;
1109 for(i=0;i<vf->links;i++)
1110 acc+=ov_pcm_total(vf,i);
1111 return(acc);
1112 }else{
1113 return(vf->pcmlengths[i*2+1]);
1114 }
1115 }
1116
1117 /* returns: total milliseconds of content if i==-1
1118 milliseconds in that logical bitstream for i==0 to n
1119 OV_EINVAL if the stream is not seekable (we can't know the
1120 length) or only partially open
1121 */
1122 ogg_int64_t ov_time_total(OggVorbis_File *vf,int i){
1123 if(vf->ready_state<OPENED)return(OV_EINVAL);
1124 if(!vf->seekable || i>=vf->links)return(OV_EINVAL);
1125 if(i<0){
1126 ogg_int64_t acc=0;
1127 int i;
1128 for(i=0;i<vf->links;i++)
1129 acc+=ov_time_total(vf,i);
1130 return(acc);
1131 }else{
1132 return(((ogg_int64_t)vf->pcmlengths[i*2+1])*1000/vf->vi[i].rate);
1133 }
1134 }
1135
1136 /* seek to an offset relative to the *compressed* data. This also
1137 scans packets to update the PCM cursor. It will cross a logical
1138 bitstream boundary, but only if it can't get any packets out of the
1139 tail of the bitstream we seek to (so no surprises).
1140
1141 returns zero on success, nonzero on failure */
1142
1143 int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){
1144 ogg_stream_state work_os;
1145 int ret;
1146
1147 if(vf->ready_state<OPENED)return(OV_EINVAL);
1148 if(!vf->seekable)
1149 return(OV_ENOSEEK); /* don't dump machine if we can't seek */
1150
1151 if(pos<0 || pos>vf->end)return(OV_EINVAL);
1152
1153 /* is the seek position outside our current link [if any]? */
1154 if(vf->ready_state>=STREAMSET){
1155 if(pos<vf->offsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1])
1156 _decode_clear(vf); /* clear out stream state */
1157 }
1158
1159 /* don't yet clear out decoding machine (if it's initialized), in
1160 the case we're in the same link. Restart the decode lapping, and
1161 let _fetch_and_process_packet deal with a potential bitstream
1162 boundary */
1163 vf->pcm_offset=-1;
1164 ogg_stream_reset_serialno(&vf->os,
1165 vf->current_serialno); /* must set serialno */
1166 vorbis_synthesis_restart(&vf->vd);
1167
1168 ret=_seek_helper(vf,pos);
1169 if(ret)goto seek_error;
1170
1171 /* we need to make sure the pcm_offset is set, but we don't want to
1172 advance the raw cursor past good packets just to get to the first
1173 with a granulepos. That's not equivalent behavior to beginning
1174 decoding as immediately after the seek position as possible.
1175
1176 So, a hack. We use two stream states; a local scratch state and
1177 the shared vf->os stream state. We use the local state to
1178 scan, and the shared state as a buffer for later decode.
1179
1180 Unfortuantely, on the last page we still advance to last packet
1181 because the granulepos on the last page is not necessarily on a
1182 packet boundary, and we need to make sure the granpos is
1183 correct.
1184 */
1185
1186 {
1187 ogg_page og;
1188 ogg_packet op;
1189 int lastblock=0;
1190 int accblock=0;
1191 int thisblock=0;
1192 int lastflag=0;
1193 int firstflag=0;
1194 ogg_int64_t pagepos=-1;
1195
1196 ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */
1197 ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE
1198 return from not necessarily
1199 starting from the beginning */
1200
1201 while(1){
1202 if(vf->ready_state>=STREAMSET){
1203 /* snarf/scan a packet if we can */
1204 int result=ogg_stream_packetout(&work_os,&op);
1205
1206 if(result>0){
1207
1208 if(vf->vi[vf->current_link].codec_setup){
1209 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1210 if(thisblock<0){
1211 ogg_stream_packetout(&vf->os,NULL);
1212 thisblock=0;
1213 }else{
1214
1215 /* We can't get a guaranteed correct pcm position out of the
1216 last page in a stream because it might have a 'short'
1217 granpos, which can only be detected in the presence of a
1218 preceding page. However, if the last page is also the first
1219 page, the granpos rules of a first page take precedence. Not
1220 only that, but for first==last, the EOS page must be treated
1221 as if its a normal first page for the stream to open/play. */
1222 if(lastflag && !firstflag)
1223 ogg_stream_packetout(&vf->os,NULL);
1224 else
1225 if(lastblock)accblock+=(lastblock+thisblock)>>2;
1226 }
1227
1228 if(op.granulepos!=-1){
1229 int i,link=vf->current_link;
1230 ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2];
1231 if(granulepos<0)granulepos=0;
1232
1233 for(i=0;i<link;i++)
1234 granulepos+=vf->pcmlengths[i*2+1];
1235 vf->pcm_offset=granulepos-accblock;
1236 if(vf->pcm_offset<0)vf->pcm_offset=0;
1237 break;
1238 }
1239 lastblock=thisblock;
1240 continue;
1241 }else
1242 ogg_stream_packetout(&vf->os,NULL);
1243 }
1244 }
1245
1246 if(!lastblock){
1247 pagepos=_get_next_page(vf,&og,-1);
1248 if(pagepos<0){
1249 vf->pcm_offset=ov_pcm_total(vf,-1);
1250 break;
1251 }
1252 }else{
1253 /* huh? Bogus stream with packets but no granulepos */
1254 vf->pcm_offset=-1;
1255 break;
1256 }
1257
1258 /* has our decoding just traversed a bitstream boundary? */
1259 if(vf->ready_state>=STREAMSET){
1260 if(vf->current_serialno!=ogg_page_serialno(&og)){
1261
1262 /* two possibilities:
1263 1) our decoding just traversed a bitstream boundary
1264 2) another stream is multiplexed into this logical section? */
1265
1266 if(ogg_page_bos(&og)){
1267 /* we traversed */
1268 _decode_clear(vf); /* clear out stream state */
1269 ogg_stream_clear(&work_os);
1270 } /* else, do nothing; next loop will scoop another page */
1271 }
1272 }
1273
1274 if(vf->ready_state<STREAMSET){
1275 int link;
1276 ogg_uint32_t serialno = ogg_page_serialno(&og);
1277
1278 for(link=0;link<vf->links;link++)
1279 if(vf->serialnos[link]==serialno)break;
1280
1281 if(link==vf->links) continue; /* not the desired Vorbis
1282 bitstream section; keep
1283 trying */
1284 vf->current_link=link;
1285 vf->current_serialno=serialno;
1286 ogg_stream_reset_serialno(&vf->os,serialno);
1287 ogg_stream_reset_serialno(&work_os,serialno);
1288 vf->ready_state=STREAMSET;
1289 firstflag=(pagepos<=vf->dataoffsets[link]);
1290 }
1291
1292 ogg_stream_pagein(&vf->os,&og);
1293 ogg_stream_pagein(&work_os,&og);
1294 lastflag=ogg_page_eos(&og);
1295
1296 }
1297 }
1298
1299 ogg_stream_clear(&work_os);
1300 vf->bittrack=0;
1301 vf->samptrack=0;
1302 return(0);
1303
1304 seek_error:
1305 /* dump the machine so we're in a known state */
1306 vf->pcm_offset=-1;
1307 ogg_stream_clear(&work_os);
1308 _decode_clear(vf);
1309 return OV_EBADLINK;
1310 }
1311
1312 /* rescales the number x from the range of [0,from] to [0,to]
1313 x is in the range [0,from]
1314 from, to are in the range [1, 1<<62-1] */
1315 ogg_int64_t rescale64(ogg_int64_t x, ogg_int64_t from, ogg_int64_t to){
1316 ogg_int64_t frac=0;
1317 ogg_int64_t ret=0;
1318 int i;
1319 if(x >= from) return to;
1320 if(x <= 0) return 0;
1321
1322 for(i=0;i<64;i++){
1323 if(x>=from){
1324 frac|=1;
1325 x-=from;
1326 }
1327 x<<=1;
1328 frac<<=1;
1329 }
1330
1331 for(i=0;i<64;i++){
1332 if(frac & 1){
1333 ret+=to;
1334 }
1335 frac>>=1;
1336 ret>>=1;
1337 }
1338
1339 return ret;
1340 }
1341
1342 /* Page granularity seek (faster than sample granularity because we
1343 don't do the last bit of decode to find a specific sample).
1344
1345 Seek to the last [granule marked] page preceding the specified pos
1346 location, such that decoding past the returned point will quickly
1347 arrive at the requested position. */
1348 int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){
1349 int link=-1;
1350 ogg_int64_t result=0;
1351 ogg_int64_t total=ov_pcm_total(vf,-1);
1352
1353 if(vf->ready_state<OPENED)return(OV_EINVAL);
1354 if(!vf->seekable)return(OV_ENOSEEK);
1355
1356 if(pos<0 || pos>total)return(OV_EINVAL);
1357
1358 /* which bitstream section does this pcm offset occur in? */
1359 for(link=vf->links-1;link>=0;link--){
1360 total-=vf->pcmlengths[link*2+1];
1361 if(pos>=total)break;
1362 }
1363
1364 /* search within the logical bitstream for the page with the highest
1365 pcm_pos preceding (or equal to) pos. There is a danger here;
1366 missing pages or incorrect frame number information in the
1367 bitstream could make our task impossible. Account for that (it
1368 would be an error condition) */
1369
1370 /* new search algorithm by HB (Nicholas Vinen) */
1371 {
1372 ogg_int64_t end=vf->offsets[link+1];
1373 ogg_int64_t begin=vf->offsets[link];
1374 ogg_int64_t begintime = vf->pcmlengths[link*2];
1375 ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime;
1376 ogg_int64_t target=pos-total+begintime;
1377 ogg_int64_t best=begin;
1378
1379 ogg_page og;
1380 while(begin<end){
1381 ogg_int64_t bisect;
1382
1383 if(end-begin<CHUNKSIZE){
1384 bisect=begin;
1385 }else{
1386 /* take a (pretty decent) guess. */
1387 bisect=begin + rescale64(target-begintime,
1388 endtime-begintime,
1389 end-begin) - CHUNKSIZE;
1390 if(bisect<begin+CHUNKSIZE)
1391 bisect=begin;
1392 }
1393
1394 if(bisect!=vf->offset){
1395 result=_seek_helper(vf,bisect);
1396 if(result) goto seek_error;
1397 }
1398
1399 while(begin<end){
1400 result=_get_next_page(vf,&og,end-vf->offset);
1401 if(result==OV_EREAD) goto seek_error;
1402 if(result<0){
1403 if(bisect<=begin+1)
1404 end=begin; /* found it */
1405 else{
1406 if(bisect==0) goto seek_error;
1407 bisect-=CHUNKSIZE;
1408 if(bisect<=begin)bisect=begin+1;
1409 result=_seek_helper(vf,bisect);
1410 if(result) goto seek_error;
1411 }
1412 }else{
1413 ogg_int64_t granulepos;
1414
1415 if(ogg_page_serialno(&og)!=vf->serialnos[link])
1416 continue;
1417
1418 granulepos=ogg_page_granulepos(&og);
1419 if(granulepos==-1)continue;
1420
1421 if(granulepos<target){
1422 best=result; /* raw offset of packet with granulepos */
1423 begin=vf->offset; /* raw offset of next page */
1424 begintime=granulepos;
1425
1426 if(target-begintime>44100)break;
1427 bisect=begin; /* *not* begin + 1 */
1428 }else{
1429 if(bisect<=begin+1)
1430 end=begin; /* found it */
1431 else{
1432 if(end==vf->offset){ /* we're pretty close - we'd be stuck in */
1433 end=result;
1434 bisect-=CHUNKSIZE; /* an endless loop otherwise. */
1435 if(bisect<=begin)bisect=begin+1;
1436 result=_seek_helper(vf,bisect);
1437 if(result) goto seek_error;
1438 }else{
1439 end=bisect;
1440 endtime=granulepos;
1441 break;
1442 }
1443 }
1444 }
1445 }
1446 }
1447 }
1448
1449 /* found our page. seek to it, update pcm offset. Easier case than
1450 raw_seek, don't keep packets preceding granulepos. */
1451 {
1452 ogg_page og;
1453 ogg_packet op;
1454
1455 /* seek */
1456 result=_seek_helper(vf,best);
1457 vf->pcm_offset=-1;
1458 if(result) goto seek_error;
1459 result=_get_next_page(vf,&og,-1);
1460 if(result<0) goto seek_error;
1461
1462 if(link!=vf->current_link){
1463 /* Different link; dump entire decode machine */
1464 _decode_clear(vf);
1465
1466 vf->current_link=link;
1467 vf->current_serialno=vf->serialnos[link];
1468 vf->ready_state=STREAMSET;
1469
1470 }else{
1471 vorbis_synthesis_restart(&vf->vd);
1472 }
1473
1474 ogg_stream_reset_serialno(&vf->os,vf->current_serialno);
1475 ogg_stream_pagein(&vf->os,&og);
1476
1477 /* pull out all but last packet; the one with granulepos */
1478 while(1){
1479 result=ogg_stream_packetpeek(&vf->os,&op);
1480 if(result==0){
1481 /* !!! the packet finishing this page originated on a
1482 preceding page. Keep fetching previous pages until we
1483 get one with a granulepos or without the 'continued' flag
1484 set. Then just use raw_seek for simplicity. */
1485
1486 result=_seek_helper(vf,best);
1487 if(result<0) goto seek_error;
1488
1489 while(1){
1490 result=_get_prev_page(vf,&og);
1491 if(result<0) goto seek_error;
1492 if(ogg_page_serialno(&og)==vf->current_serialno &&
1493 (ogg_page_granulepos(&og)>-1 ||
1494 !ogg_page_continued(&og))){
1495 return ov_raw_seek(vf,result);
1496 }
1497 vf->offset=result;
1498 }
1499 }
1500 if(result<0){
1501 result = OV_EBADPACKET;
1502 goto seek_error;
1503 }
1504 if(op.granulepos!=-1){
1505 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1506 if(vf->pcm_offset<0)vf->pcm_offset=0;
1507 vf->pcm_offset+=total;
1508 break;
1509 }else
1510 result=ogg_stream_packetout(&vf->os,NULL);
1511 }
1512 }
1513 }
1514
1515 /* verify result */
1516 if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){
1517 result=OV_EFAULT;
1518 goto seek_error;
1519 }
1520 vf->bittrack=0;
1521 vf->samptrack=0;
1522 return(0);
1523
1524 seek_error:
1525 /* dump machine so we're in a known state */
1526 vf->pcm_offset=-1;
1527 _decode_clear(vf);
1528 return (int)result;
1529 }
1530
1531 /* seek to a sample offset relative to the decompressed pcm stream
1532 returns zero on success, nonzero on failure */
1533
1534 int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){
1535 int thisblock,lastblock=0;
1536 int ret=ov_pcm_seek_page(vf,pos);
1537 if(ret<0)return(ret);
1538 if((ret=_make_decode_ready(vf)))return ret;
1539
1540 /* discard leading packets we don't need for the lapping of the
1541 position we want; don't decode them */
1542
1543 while(1){
1544 ogg_packet op;
1545 ogg_page og;
1546
1547 int ret=ogg_stream_packetpeek(&vf->os,&op);
1548 if(ret>0){
1549 thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op);
1550 if(thisblock<0){
1551 ogg_stream_packetout(&vf->os,NULL);
1552 continue; /* non audio packet */
1553 }
1554 if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2;
1555
1556 if(vf->pcm_offset+((thisblock+
1557 vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break;
1558
1559 /* remove the packet from packet queue and track its granulepos */
1560 ogg_stream_packetout(&vf->os,NULL);
1561 vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with
1562 only tracking, no
1563 pcm_decode */
1564 vorbis_synthesis_blockin(&vf->vd,&vf->vb);
1565
1566 /* end of logical stream case is hard, especially with exact
1567 length positioning. */
1568
1569 if(op.granulepos>-1){
1570 int i;
1571 /* always believe the stream markers */
1572 vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2];
1573 if(vf->pcm_offset<0)vf->pcm_offset=0;
1574 for(i=0;i<vf->current_link;i++)
1575 vf->pcm_offset+=vf->pcmlengths[i*2+1];
1576 }
1577
1578 lastblock=thisblock;
1579
1580 }else{
1581 if(ret<0 && ret!=OV_HOLE)break;
1582
1583 /* suck in a new page */
1584 if(_get_next_page(vf,&og,-1)<0)break;
1585 if(ogg_page_bos(&og))_decode_clear(vf);
1586
1587 if(vf->ready_state<STREAMSET){
1588 ogg_uint32_t serialno=ogg_page_serialno(&og);
1589 int link;
1590
1591 for(link=0;link<vf->links;link++)
1592 if(vf->serialnos[link]==serialno)break;
1593 if(link==vf->links) continue;
1594 vf->current_link=link;
1595
1596 vf->ready_state=STREAMSET;
1597 vf->current_serialno=ogg_page_serialno(&og);
1598 ogg_stream_reset_serialno(&vf->os,serialno);
1599 ret=_make_decode_ready(vf);
1600 if(ret)return ret;
1601 lastblock=0;
1602 }
1603
1604 ogg_stream_pagein(&vf->os,&og);
1605 }
1606 }
1607
1608 vf->bittrack=0;
1609 vf->samptrack=0;
1610 /* discard samples until we reach the desired position. Crossing a
1611 logical bitstream boundary with abandon is OK. */
1612 while(vf->pcm_offset<pos){
1613 ogg_int64_t target=pos-vf->pcm_offset;
1614 long samples=vorbis_synthesis_pcmout(&vf->vd,NULL);
1615
1616 if(samples>target)samples=target;
1617 vorbis_synthesis_read(&vf->vd,samples);
1618 vf->pcm_offset+=samples;
1619
1620 if(samples<target)
1621 if(_fetch_and_process_packet(vf,NULL,1,1)<=0)
1622 vf->pcm_offset=ov_pcm_total(vf,-1); /* eof */
1623 }
1624 return 0;
1625 }
1626
1627 /* seek to a playback time relative to the decompressed pcm stream
1628 returns zero on success, nonzero on failure */
1629 int ov_time_seek(OggVorbis_File *vf,ogg_int64_t milliseconds){
1630 /* translate time to PCM position and call ov_pcm_seek */
1631
1632 int link=-1;
1633 ogg_int64_t pcm_total=0;
1634 ogg_int64_t time_total=0;
1635
1636 if(vf->ready_state<OPENED)return(OV_EINVAL);
1637 if(!vf->seekable)return(OV_ENOSEEK);
1638 if(milliseconds<0)return(OV_EINVAL);
1639
1640 /* which bitstream section does this time offset occur in? */
1641 for(link=0;link<vf->links;link++){
1642 ogg_int64_t addsec = ov_time_total(vf,link);
1643 if(milliseconds<time_total+addsec)break;
1644 time_total+=addsec;
1645 pcm_total+=vf->pcmlengths[link*2+1];
1646 }
1647
1648 if(link==vf->links)return(OV_EINVAL);
1649
1650 /* enough information to convert time offset to pcm offset */
1651 {
1652 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
1653 return(ov_pcm_seek(vf,target));
1654 }
1655 }
1656
1657 /* page-granularity version of ov_time_seek
1658 returns zero on success, nonzero on failure */
1659 int ov_time_seek_page(OggVorbis_File *vf,ogg_int64_t milliseconds){
1660 /* translate time to PCM position and call ov_pcm_seek */
1661
1662 int link=-1;
1663 ogg_int64_t pcm_total=0;
1664 ogg_int64_t time_total=0;
1665
1666 if(vf->ready_state<OPENED)return(OV_EINVAL);
1667 if(!vf->seekable)return(OV_ENOSEEK);
1668 if(milliseconds<0)return(OV_EINVAL);
1669
1670 /* which bitstream section does this time offset occur in? */
1671 for(link=0;link<vf->links;link++){
1672 ogg_int64_t addsec = ov_time_total(vf,link);
1673 if(milliseconds<time_total+addsec)break;
1674 time_total+=addsec;
1675 pcm_total+=vf->pcmlengths[link*2+1];
1676 }
1677
1678 if(link==vf->links)return(OV_EINVAL);
1679
1680 /* enough information to convert time offset to pcm offset */
1681 {
1682 ogg_int64_t target=pcm_total+(milliseconds-time_total)*vf->vi[link].rate/1000;
1683 return(ov_pcm_seek_page(vf,target));
1684 }
1685 }
1686
1687 /* tell the current stream offset cursor. Note that seek followed by
1688 tell will likely not give the set offset due to caching */
1689 ogg_int64_t ov_raw_tell(OggVorbis_File *vf){
1690 if(vf->ready_state<OPENED)return(OV_EINVAL);
1691 return(vf->offset);
1692 }
1693
1694 /* return PCM offset (sample) of next PCM sample to be read */
1695 ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){
1696 if(vf->ready_state<OPENED)return(OV_EINVAL);
1697 return(vf->pcm_offset);
1698 }
1699
1700 /* link: -1) return the vorbis_info struct for the bitstream section
1701 currently being decoded
1702 0-n) to request information for a specific bitstream section
1703
1704 In the case of a non-seekable bitstream, any call returns the
1705 current bitstream. NULL in the case that the machine is not
1706 initialized */
1707
1708 vorbis_info *ov_info(OggVorbis_File *vf,int link){
1709 if(vf->seekable){
1710 if(link<0)
1711 if(vf->ready_state>=STREAMSET)
1712 return vf->vi+vf->current_link;
1713 else
1714 return vf->vi;
1715 else
1716 if(link>=vf->links)
1717 return NULL;
1718 else
1719 return vf->vi+link;
1720 }else{
1721 return vf->vi;
1722 }
1723 }
1724
1725 /* up to this point, everything could more or less hide the multiple
1726 logical bitstream nature of chaining from the toplevel application
1727 if the toplevel application didn't particularly care. However, at
1728 the point that we actually read audio back, the multiple-section
1729 nature must surface: Multiple bitstream sections do not necessarily
1730 have to have the same number of channels or sampling rate.
1731
1732 ov_read returns the sequential logical bitstream number currently
1733 being decoded along with the PCM data in order that the toplevel
1734 application can take action on channel/sample rate changes. This
1735 number will be incremented even for streamed (non-seekable) streams
1736 (for seekable streams, it represents the actual logical bitstream
1737 index within the physical bitstream. Note that the accessor
1738 functions above are aware of this dichotomy).
1739
1740 input values: buffer) a buffer to hold packed PCM data for return
1741 bytes_req) the byte length requested to be placed into buffer
1742
1743 return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL)
1744 0) EOF
1745 n) number of bytes of PCM actually returned. The
1746 below works on a packet-by-packet basis, so the
1747 return length is not related to the 'length' passed
1748 in, just guaranteed to fit.
1749
1750 *section) set to the logical bitstream number */
1751
1752 long ov_read(OggVorbis_File *vf,char *buffer,int bytes_req,int *bitstream)
1753 {
1754 int i,j;
1755 ogg_int32_t **pcm;
1756 long samples;
1757
1758 if(vf->ready_state<OPENED)return(OV_EINVAL);
1759
1760 while(1)
1761 {
1762 if(vf->ready_state==INITSET)
1763 {
1764 samples=vorbis_synthesis_pcmout(&vf->vd,&pcm);
1765 if(samples)
1766 break;
1767 }
1768
1769 /* suck in another packet */
1770 {
1771 int ret=_fetch_and_process_packet(vf,NULL,1,1);
1772 if(ret==OV_EOF)
1773 return(0);
1774 if(ret<=0)
1775 return(ret);
1776 }
1777
1778 }
1779
1780 if(samples>0)
1781 {
1782 /* yay! proceed to pack data into the byte buffer */
1783
1784 long channels=ov_info(vf,-1)->channels;
1785
1786 if(samples>(bytes_req/(2*channels)))
1787 samples=bytes_req/(2*channels);
1788
1789 for(i=0;i<channels;i++)
1790 { /* It's faster in this order */
1791 ogg_int32_t *src=pcm[i];
1792 short *dest=((short *)buffer)+i;
1793
1794 for(j=0;j<samples;j++)
1795 {
1796 *dest=CLIP_TO_15(src[j]>>9);
1797 dest+=channels;
1798 }
1799 }
1800
1801 vorbis_synthesis_read(&vf->vd,samples);
1802 vf->pcm_offset+=samples;
1803 if(bitstream)
1804 *bitstream=vf->current_link;
1805
1806 return(samples * 2 * channels);
1807 }
1808
1809 return(samples);
1810 }
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: window functions
14
15 ********************************************************************/
16
17 #include <stdlib.h>
18 #include <math.h>
19 #include "misc.h"
20 #include "window.h"
21 #include "window_lookup.h"
22
23 const void *_vorbis_window(int type, int left){
24
25 switch(type){
26 case 0:
27
28 switch(left){
29 case 32:
30 return vwin64;
31 case 64:
32 return vwin128;
33 case 128:
34 return vwin256;
35 case 256:
36 return vwin512;
37 case 512:
38 return vwin1024;
39 case 1024:
40 return vwin2048;
41 case 2048:
42 return vwin4096;
43 case 4096:
44 return vwin8192;
45 default:
46 return(0);
47 }
48 break;
49 default:
50 return(0);
51 }
52 }
53
54 void _vorbis_apply_window(ogg_int32_t *d,const void *window_p[2],
55 long *blocksizes,
56 int lW,int W,int nW){
57
58 LOOKUP_T *window[2]={window_p[0],window_p[1]};
59 long n=blocksizes[W];
60 long ln=blocksizes[lW];
61 long rn=blocksizes[nW];
62
63 long leftbegin=n/4-ln/4;
64 long leftend=leftbegin+ln/2;
65
66 long rightbegin=n/2+n/4-rn/4;
67 long rightend=rightbegin+rn/2;
68
69 int i,p;
70
71 for(i=0;i<leftbegin;i++)
72 d[i]=0;
73
74 for(p=0;i<leftend;i++,p++)
75 d[i]=MULT31(d[i],window[lW][p]);
76
77 for(i=rightbegin,p=rn/2-1;i<rightend;i++,p--)
78 d[i]=MULT31(d[i],window[nW][p]);
79
80 for(;i<n;i++)
81 d[i]=0;
82 }
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: window functions
14
15 ********************************************************************/
16
17 #ifndef _V_WINDOW_
18 #define _V_WINDOW_
19
20 extern const void *_vorbis_window(int type,int left);
21 extern void _vorbis_apply_window(ogg_int32_t *d,const void *window[2],
22 long *blocksizes,
23 int lW,int W,int nW);
24
25
26 #endif
0 /********************************************************************
1 * *
2 * THIS FILE IS PART OF THE OggVorbis 'TREMOR' CODEC SOURCE CODE. *
3 * *
4 * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS *
5 * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE *
6 * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
7 * *
8 * THE OggVorbis 'TREMOR' SOURCE CODE IS (C) COPYRIGHT 1994-2002 *
9 * BY THE Xiph.Org FOUNDATION http://www.xiph.org/ *
10 * *
11 ********************************************************************
12
13 function: window lookup tables
14
15 ********************************************************************/
16
17
18 #include "os_types.h"
19
20 static const LOOKUP_T vwin64[32] = {
21 X(0x001f0003), X(0x01168c98), X(0x030333c8), X(0x05dfe3a4),
22 X(0x09a49562), X(0x0e45df18), X(0x13b47ef2), X(0x19dcf676),
23 X(0x20a74d83), X(0x27f7137c), X(0x2fabb05a), X(0x37a1105a),
24 X(0x3fb0ab28), X(0x47b2dcd1), X(0x4f807bc6), X(0x56f48e70),
25 X(0x5dedfc79), X(0x64511653), X(0x6a08cfff), X(0x6f079328),
26 X(0x734796f4), X(0x76cab7f2), X(0x7999d6e8), X(0x7bc3cf9f),
27 X(0x7d5c20c1), X(0x7e7961df), X(0x7f33a567), X(0x7fa2e1d0),
28 X(0x7fdd78a5), X(0x7ff6ec6d), X(0x7ffed0e9), X(0x7ffffc3f),
29 };
30
31 static const LOOKUP_T vwin128[64] = {
32 X(0x0007c04d), X(0x0045bb89), X(0x00c18b87), X(0x017ae294),
33 X(0x02714a4e), X(0x03a4217a), X(0x05129952), X(0x06bbb24f),
34 X(0x089e38a1), X(0x0ab8c073), X(0x0d09a228), X(0x0f8ef6bd),
35 X(0x12469488), X(0x152e0c7a), X(0x1842a81c), X(0x1b81686d),
36 X(0x1ee705d9), X(0x226ff15d), X(0x26185705), X(0x29dc21cc),
37 X(0x2db700fe), X(0x31a46f08), X(0x359fb9c1), X(0x39a40c0c),
38 X(0x3dac78b6), X(0x41b40674), X(0x45b5bcb0), X(0x49acb109),
39 X(0x4d94152b), X(0x516744bd), X(0x5521d320), X(0x58bf98a5),
40 X(0x5c3cbef4), X(0x5f95cc5d), X(0x62c7add7), X(0x65cfbf64),
41 X(0x68abd2ba), X(0x6b5a3405), X(0x6dd9acab), X(0x7029840d),
42 X(0x72497e38), X(0x7439d8ac), X(0x75fb4532), X(0x778ee30a),
43 X(0x78f6367e), X(0x7a331f1a), X(0x7b47cccd), X(0x7c36b416),
44 X(0x7d028192), X(0x7dae0d18), X(0x7e3c4caa), X(0x7eb04763),
45 X(0x7f0d08a7), X(0x7f5593b7), X(0x7f8cd7d5), X(0x7fb5a513),
46 X(0x7fd2a1fc), X(0x7fe64212), X(0x7ff2bd4c), X(0x7ffa0890),
47 X(0x7ffdcf39), X(0x7fff6dac), X(0x7fffed01), X(0x7fffffc4),
48 };
49
50 static const LOOKUP_T vwin256[128] = {
51 X(0x0001f018), X(0x00117066), X(0x00306e9e), X(0x005ee5f1),
52 X(0x009ccf26), X(0x00ea208b), X(0x0146cdea), X(0x01b2c87f),
53 X(0x022dfedf), X(0x02b85ced), X(0x0351cbbd), X(0x03fa317f),
54 X(0x04b17167), X(0x05776b90), X(0x064bfcdc), X(0x072efedd),
55 X(0x082047b4), X(0x091fa9f1), X(0x0a2cf477), X(0x0b47f25d),
56 X(0x0c706ad2), X(0x0da620ff), X(0x0ee8d3ef), X(0x10383e75),
57 X(0x11941716), X(0x12fc0ff6), X(0x146fd6c8), X(0x15ef14c2),
58 X(0x17796e8e), X(0x190e844f), X(0x1aadf196), X(0x1c574d6e),
59 X(0x1e0a2a62), X(0x1fc61688), X(0x218a9b9c), X(0x23573f12),
60 X(0x252b823d), X(0x2706e269), X(0x28e8d913), X(0x2ad0dc0e),
61 X(0x2cbe5dc1), X(0x2eb0cd60), X(0x30a79733), X(0x32a224d5),
62 X(0x349fdd8b), X(0x36a02690), X(0x38a2636f), X(0x3aa5f65e),
63 X(0x3caa409e), X(0x3eaea2df), X(0x40b27da6), X(0x42b531b8),
64 X(0x44b62086), X(0x46b4ac99), X(0x48b03a05), X(0x4aa82ed5),
65 X(0x4c9bf37d), X(0x4e8af349), X(0x50749ccb), X(0x52586246),
66 X(0x5435ba1c), X(0x560c1f31), X(0x57db1152), X(0x59a21591),
67 X(0x5b60b6a3), X(0x5d168535), X(0x5ec31839), X(0x60660d36),
68 X(0x61ff0886), X(0x638db595), X(0x6511c717), X(0x668af734),
69 X(0x67f907b0), X(0x695bc207), X(0x6ab2f787), X(0x6bfe815a),
70 X(0x6d3e4090), X(0x6e721e16), X(0x6f9a0ab5), X(0x70b5fef8),
71 X(0x71c5fb16), X(0x72ca06cd), X(0x73c2313d), X(0x74ae90b2),
72 X(0x758f4275), X(0x76646a85), X(0x772e335c), X(0x77eccda0),
73 X(0x78a06fd7), X(0x79495613), X(0x79e7c19c), X(0x7a7bf894),
74 X(0x7b064596), X(0x7b86f757), X(0x7bfe6044), X(0x7c6cd615),
75 X(0x7cd2b16e), X(0x7d304d71), X(0x7d860756), X(0x7dd43e06),
76 X(0x7e1b51ad), X(0x7e5ba355), X(0x7e95947e), X(0x7ec986bb),
77 X(0x7ef7db4a), X(0x7f20f2b9), X(0x7f452c7f), X(0x7f64e6a7),
78 X(0x7f807d71), X(0x7f984aff), X(0x7faca700), X(0x7fbde662),
79 X(0x7fcc5b04), X(0x7fd85372), X(0x7fe21a99), X(0x7fe9f791),
80 X(0x7ff02d58), X(0x7ff4fa9e), X(0x7ff89990), X(0x7ffb3faa),
81 X(0x7ffd1d8b), X(0x7ffe5ecc), X(0x7fff29e0), X(0x7fff9ff3),
82 X(0x7fffdcd2), X(0x7ffff6d6), X(0x7ffffed0), X(0x7ffffffc),
83 };
84
85 static const LOOKUP_T vwin512[256] = {
86 X(0x00007c06), X(0x00045c32), X(0x000c1c62), X(0x0017bc4c),
87 X(0x00273b7a), X(0x003a9955), X(0x0051d51c), X(0x006cede7),
88 X(0x008be2a9), X(0x00aeb22a), X(0x00d55b0d), X(0x00ffdbcc),
89 X(0x012e32b6), X(0x01605df5), X(0x01965b85), X(0x01d02939),
90 X(0x020dc4ba), X(0x024f2b83), X(0x02945ae6), X(0x02dd5004),
91 X(0x032a07d3), X(0x037a7f19), X(0x03ceb26e), X(0x04269e37),
92 X(0x04823eab), X(0x04e18fcc), X(0x05448d6d), X(0x05ab3329),
93 X(0x06157c68), X(0x0683645e), X(0x06f4e607), X(0x0769fc25),
94 X(0x07e2a146), X(0x085ecfbc), X(0x08de819f), X(0x0961b0cc),
95 X(0x09e856e3), X(0x0a726d46), X(0x0affed1d), X(0x0b90cf4c),
96 X(0x0c250c79), X(0x0cbc9d0b), X(0x0d577926), X(0x0df598aa),
97 X(0x0e96f337), X(0x0f3b8026), X(0x0fe3368f), X(0x108e0d42),
98 X(0x113bfaca), X(0x11ecf56b), X(0x12a0f324), X(0x1357e9ac),
99 X(0x1411ce70), X(0x14ce9698), X(0x158e3702), X(0x1650a444),
100 X(0x1715d2aa), X(0x17ddb638), X(0x18a842aa), X(0x19756b72),
101 X(0x1a4523b9), X(0x1b175e62), X(0x1bec0e04), X(0x1cc324f0),
102 X(0x1d9c9532), X(0x1e78508a), X(0x1f564876), X(0x20366e2e),
103 X(0x2118b2a2), X(0x21fd0681), X(0x22e35a37), X(0x23cb9dee),
104 X(0x24b5c18e), X(0x25a1b4c0), X(0x268f66f1), X(0x277ec74e),
105 X(0x286fc4cc), X(0x29624e23), X(0x2a5651d7), X(0x2b4bbe34),
106 X(0x2c428150), X(0x2d3a8913), X(0x2e33c332), X(0x2f2e1d35),
107 X(0x30298478), X(0x3125e62d), X(0x32232f61), X(0x33214cfc),
108 X(0x34202bc2), X(0x351fb85a), X(0x361fdf4f), X(0x37208d10),
109 X(0x3821adf7), X(0x39232e49), X(0x3a24fa3c), X(0x3b26fdf6),
110 X(0x3c292593), X(0x3d2b5d29), X(0x3e2d90c8), X(0x3f2fac7f),
111 X(0x40319c5f), X(0x41334c81), X(0x4234a905), X(0x43359e16),
112 X(0x443617f3), X(0x453602eb), X(0x46354b65), X(0x4733dde1),
113 X(0x4831a6ff), X(0x492e937f), X(0x4a2a9045), X(0x4b258a5f),
114 X(0x4c1f6f06), X(0x4d182ba2), X(0x4e0fadce), X(0x4f05e35b),
115 X(0x4ffaba53), X(0x50ee20fd), X(0x51e005e1), X(0x52d057ca),
116 X(0x53bf05ca), X(0x54abff3b), X(0x559733c7), X(0x56809365),
117 X(0x57680e62), X(0x584d955d), X(0x59311952), X(0x5a128b96),
118 X(0x5af1dddd), X(0x5bcf023a), X(0x5ca9eb27), X(0x5d828b81),
119 X(0x5e58d68d), X(0x5f2cbffc), X(0x5ffe3be9), X(0x60cd3edf),
120 X(0x6199bdda), X(0x6263ae45), X(0x632b0602), X(0x63efbb66),
121 X(0x64b1c53f), X(0x65711ad0), X(0x662db3d7), X(0x66e7888d),
122 X(0x679e91a5), X(0x6852c84e), X(0x69042635), X(0x69b2a582),
123 X(0x6a5e40dd), X(0x6b06f36c), X(0x6bacb8d2), X(0x6c4f8d30),
124 X(0x6cef6d26), X(0x6d8c55d4), X(0x6e2644d4), X(0x6ebd3840),
125 X(0x6f512ead), X(0x6fe2272e), X(0x7070214f), X(0x70fb1d17),
126 X(0x71831b06), X(0x72081c16), X(0x728a21b5), X(0x73092dc8),
127 X(0x738542a6), X(0x73fe631b), X(0x74749261), X(0x74e7d421),
128 X(0x75582c72), X(0x75c59fd5), X(0x76303333), X(0x7697ebdd),
129 X(0x76fccf85), X(0x775ee443), X(0x77be308a), X(0x781abb2e),
130 X(0x78748b59), X(0x78cba88e), X(0x79201aa7), X(0x7971e9cd),
131 X(0x79c11e79), X(0x7a0dc170), X(0x7a57dbc2), X(0x7a9f76c1),
132 X(0x7ae49c07), X(0x7b27556b), X(0x7b67ad02), X(0x7ba5ad1b),
133 X(0x7be1603a), X(0x7c1ad118), X(0x7c520a9e), X(0x7c8717e1),
134 X(0x7cba0421), X(0x7ceadac3), X(0x7d19a74f), X(0x7d46756e),
135 X(0x7d7150e5), X(0x7d9a4592), X(0x7dc15f69), X(0x7de6aa71),
136 X(0x7e0a32c0), X(0x7e2c0479), X(0x7e4c2bc7), X(0x7e6ab4db),
137 X(0x7e87abe9), X(0x7ea31d24), X(0x7ebd14be), X(0x7ed59edd),
138 X(0x7eecc7a3), X(0x7f029b21), X(0x7f17255a), X(0x7f2a723f),
139 X(0x7f3c8daa), X(0x7f4d835d), X(0x7f5d5f00), X(0x7f6c2c1b),
140 X(0x7f79f617), X(0x7f86c83a), X(0x7f92ada2), X(0x7f9db146),
141 X(0x7fa7ddf3), X(0x7fb13e46), X(0x7fb9dcb0), X(0x7fc1c36c),
142 X(0x7fc8fc83), X(0x7fcf91c7), X(0x7fd58cd2), X(0x7fdaf702),
143 X(0x7fdfd979), X(0x7fe43d1c), X(0x7fe82a8b), X(0x7febaa29),
144 X(0x7feec412), X(0x7ff1801c), X(0x7ff3e5d6), X(0x7ff5fc86),
145 X(0x7ff7cb29), X(0x7ff9586f), X(0x7ffaaaba), X(0x7ffbc81e),
146 X(0x7ffcb660), X(0x7ffd7af3), X(0x7ffe1afa), X(0x7ffe9b42),
147 X(0x7fff0047), X(0x7fff4e2f), X(0x7fff88c9), X(0x7fffb390),
148 X(0x7fffd1a6), X(0x7fffe5d7), X(0x7ffff296), X(0x7ffff9fd),
149 X(0x7ffffdcd), X(0x7fffff6d), X(0x7fffffed), X(0x7fffffff),
150 };
151
152 static const LOOKUP_T vwin1024[512] = {
153 X(0x00001f02), X(0x0001170e), X(0x00030724), X(0x0005ef40),
154 X(0x0009cf59), X(0x000ea767), X(0x0014775e), X(0x001b3f2e),
155 X(0x0022fec8), X(0x002bb618), X(0x00356508), X(0x00400b81),
156 X(0x004ba968), X(0x00583ea0), X(0x0065cb0a), X(0x00744e84),
157 X(0x0083c8ea), X(0x00943a14), X(0x00a5a1da), X(0x00b80010),
158 X(0x00cb5488), X(0x00df9f10), X(0x00f4df76), X(0x010b1584),
159 X(0x01224101), X(0x013a61b2), X(0x01537759), X(0x016d81b6),
160 X(0x01888087), X(0x01a47385), X(0x01c15a69), X(0x01df34e6),
161 X(0x01fe02b1), X(0x021dc377), X(0x023e76e7), X(0x02601ca9),
162 X(0x0282b466), X(0x02a63dc1), X(0x02cab85d), X(0x02f023d6),
163 X(0x03167fcb), X(0x033dcbd3), X(0x03660783), X(0x038f3270),
164 X(0x03b94c29), X(0x03e4543a), X(0x04104a2e), X(0x043d2d8b),
165 X(0x046afdd5), X(0x0499ba8c), X(0x04c9632d), X(0x04f9f734),
166 X(0x052b7615), X(0x055ddf46), X(0x05913237), X(0x05c56e53),
167 X(0x05fa9306), X(0x06309fb6), X(0x066793c5), X(0x069f6e93),
168 X(0x06d82f7c), X(0x0711d5d9), X(0x074c60fe), X(0x0787d03d),
169 X(0x07c422e4), X(0x0801583e), X(0x083f6f91), X(0x087e681f),
170 X(0x08be4129), X(0x08fef9ea), X(0x0940919a), X(0x0983076d),
171 X(0x09c65a92), X(0x0a0a8a38), X(0x0a4f9585), X(0x0a957b9f),
172 X(0x0adc3ba7), X(0x0b23d4b9), X(0x0b6c45ee), X(0x0bb58e5a),
173 X(0x0bffad0f), X(0x0c4aa11a), X(0x0c966982), X(0x0ce3054d),
174 X(0x0d30737b), X(0x0d7eb308), X(0x0dcdc2eb), X(0x0e1da21a),
175 X(0x0e6e4f83), X(0x0ebfca11), X(0x0f1210ad), X(0x0f652238),
176 X(0x0fb8fd91), X(0x100da192), X(0x10630d11), X(0x10b93ee0),
177 X(0x111035cb), X(0x1167f09a), X(0x11c06e13), X(0x1219acf5),
178 X(0x1273abfb), X(0x12ce69db), X(0x1329e54a), X(0x13861cf3),
179 X(0x13e30f80), X(0x1440bb97), X(0x149f1fd8), X(0x14fe3ade),
180 X(0x155e0b40), X(0x15be8f92), X(0x161fc662), X(0x1681ae38),
181 X(0x16e4459b), X(0x17478b0b), X(0x17ab7d03), X(0x181019fb),
182 X(0x18756067), X(0x18db4eb3), X(0x1941e34a), X(0x19a91c92),
183 X(0x1a10f8ea), X(0x1a7976af), X(0x1ae29439), X(0x1b4c4fda),
184 X(0x1bb6a7e2), X(0x1c219a9a), X(0x1c8d2649), X(0x1cf9492e),
185 X(0x1d660188), X(0x1dd34d8e), X(0x1e412b74), X(0x1eaf996a),
186 X(0x1f1e959b), X(0x1f8e1e2f), X(0x1ffe3146), X(0x206ecd01),
187 X(0x20dfef78), X(0x215196c2), X(0x21c3c0f0), X(0x22366c10),
188 X(0x22a9962a), X(0x231d3d45), X(0x23915f60), X(0x2405fa7a),
189 X(0x247b0c8c), X(0x24f09389), X(0x25668d65), X(0x25dcf80c),
190 X(0x2653d167), X(0x26cb175e), X(0x2742c7d0), X(0x27bae09e),
191 X(0x28335fa2), X(0x28ac42b3), X(0x292587a5), X(0x299f2c48),
192 X(0x2a192e69), X(0x2a938bd1), X(0x2b0e4247), X(0x2b894f8d),
193 X(0x2c04b164), X(0x2c806588), X(0x2cfc69b2), X(0x2d78bb9a),
194 X(0x2df558f4), X(0x2e723f6f), X(0x2eef6cbb), X(0x2f6cde83),
195 X(0x2fea9270), X(0x30688627), X(0x30e6b74e), X(0x31652385),
196 X(0x31e3c86b), X(0x3262a39e), X(0x32e1b2b8), X(0x3360f352),
197 X(0x33e06303), X(0x345fff5e), X(0x34dfc5f8), X(0x355fb462),
198 X(0x35dfc82a), X(0x365ffee0), X(0x36e0560f), X(0x3760cb43),
199 X(0x37e15c05), X(0x386205df), X(0x38e2c657), X(0x39639af5),
200 X(0x39e4813e), X(0x3a6576b6), X(0x3ae678e3), X(0x3b678547),
201 X(0x3be89965), X(0x3c69b2c1), X(0x3ceacedc), X(0x3d6beb37),
202 X(0x3ded0557), X(0x3e6e1abb), X(0x3eef28e6), X(0x3f702d5a),
203 X(0x3ff1259a), X(0x40720f29), X(0x40f2e789), X(0x4173ac3f),
204 X(0x41f45ad0), X(0x4274f0c2), X(0x42f56b9a), X(0x4375c8e0),
205 X(0x43f6061d), X(0x447620db), X(0x44f616a5), X(0x4575e509),
206 X(0x45f58994), X(0x467501d6), X(0x46f44b62), X(0x477363cb),
207 X(0x47f248a6), X(0x4870f78e), X(0x48ef6e1a), X(0x496da9e8),
208 X(0x49eba897), X(0x4a6967c8), X(0x4ae6e521), X(0x4b641e47),
209 X(0x4be110e5), X(0x4c5dbaa7), X(0x4cda193f), X(0x4d562a5f),
210 X(0x4dd1ebbd), X(0x4e4d5b15), X(0x4ec87623), X(0x4f433aa9),
211 X(0x4fbda66c), X(0x5037b734), X(0x50b16acf), X(0x512abf0e),
212 X(0x51a3b1c5), X(0x521c40ce), X(0x52946a06), X(0x530c2b50),
213 X(0x53838292), X(0x53fa6db8), X(0x5470eab3), X(0x54e6f776),
214 X(0x555c91fc), X(0x55d1b844), X(0x56466851), X(0x56baa02f),
215 X(0x572e5deb), X(0x57a19f98), X(0x58146352), X(0x5886a737),
216 X(0x58f8696d), X(0x5969a81c), X(0x59da6177), X(0x5a4a93b4),
217 X(0x5aba3d0f), X(0x5b295bcb), X(0x5b97ee30), X(0x5c05f28d),
218 X(0x5c736738), X(0x5ce04a8d), X(0x5d4c9aed), X(0x5db856c1),
219 X(0x5e237c78), X(0x5e8e0a89), X(0x5ef7ff6f), X(0x5f6159b0),
220 X(0x5fca17d4), X(0x6032386e), X(0x6099ba15), X(0x61009b69),
221 X(0x6166db11), X(0x61cc77b9), X(0x62317017), X(0x6295c2e7),
222 X(0x62f96eec), X(0x635c72f1), X(0x63becdc8), X(0x64207e4b),
223 X(0x6481835a), X(0x64e1dbde), X(0x654186c8), X(0x65a0830e),
224 X(0x65fecfb1), X(0x665c6bb7), X(0x66b95630), X(0x67158e30),
225 X(0x677112d7), X(0x67cbe34b), X(0x6825feb9), X(0x687f6456),
226 X(0x68d81361), X(0x69300b1e), X(0x69874ada), X(0x69ddd1ea),
227 X(0x6a339fab), X(0x6a88b382), X(0x6add0cdb), X(0x6b30ab2a),
228 X(0x6b838dec), X(0x6bd5b4a6), X(0x6c271ee2), X(0x6c77cc36),
229 X(0x6cc7bc3d), X(0x6d16ee9b), X(0x6d6562fb), X(0x6db31911),
230 X(0x6e001099), X(0x6e4c4955), X(0x6e97c311), X(0x6ee27d9f),
231 X(0x6f2c78d9), X(0x6f75b4a2), X(0x6fbe30e4), X(0x7005ed91),
232 X(0x704ceaa1), X(0x70932816), X(0x70d8a5f8), X(0x711d6457),
233 X(0x7161634b), X(0x71a4a2f3), X(0x71e72375), X(0x7228e500),
234 X(0x7269e7c8), X(0x72aa2c0a), X(0x72e9b209), X(0x73287a12),
235 X(0x73668476), X(0x73a3d18f), X(0x73e061bc), X(0x741c3566),
236 X(0x74574cfa), X(0x7491a8ee), X(0x74cb49be), X(0x75042fec),
237 X(0x753c5c03), X(0x7573ce92), X(0x75aa882f), X(0x75e08979),
238 X(0x7615d313), X(0x764a65a7), X(0x767e41e5), X(0x76b16884),
239 X(0x76e3da40), X(0x771597dc), X(0x7746a221), X(0x7776f9dd),
240 X(0x77a69fe6), X(0x77d59514), X(0x7803da49), X(0x7831706a),
241 X(0x785e5861), X(0x788a9320), X(0x78b6219c), X(0x78e104cf),
242 X(0x790b3dbb), X(0x7934cd64), X(0x795db4d5), X(0x7985f51d),
243 X(0x79ad8f50), X(0x79d48486), X(0x79fad5de), X(0x7a208478),
244 X(0x7a45917b), X(0x7a69fe12), X(0x7a8dcb6c), X(0x7ab0fabb),
245 X(0x7ad38d36), X(0x7af5841a), X(0x7b16e0a3), X(0x7b37a416),
246 X(0x7b57cfb8), X(0x7b7764d4), X(0x7b9664b6), X(0x7bb4d0b0),
247 X(0x7bd2aa14), X(0x7beff23b), X(0x7c0caa7f), X(0x7c28d43c),
248 X(0x7c4470d2), X(0x7c5f81a5), X(0x7c7a081a), X(0x7c940598),
249 X(0x7cad7b8b), X(0x7cc66b5e), X(0x7cded680), X(0x7cf6be64),
250 X(0x7d0e247b), X(0x7d250a3c), X(0x7d3b711c), X(0x7d515a95),
251 X(0x7d66c822), X(0x7d7bbb3c), X(0x7d903563), X(0x7da43814),
252 X(0x7db7c4d0), X(0x7dcadd16), X(0x7ddd826a), X(0x7defb64d),
253 X(0x7e017a44), X(0x7e12cfd3), X(0x7e23b87f), X(0x7e3435cc),
254 X(0x7e444943), X(0x7e53f467), X(0x7e6338c0), X(0x7e7217d5),
255 X(0x7e80932b), X(0x7e8eac49), X(0x7e9c64b7), X(0x7ea9bdf8),
256 X(0x7eb6b994), X(0x7ec35910), X(0x7ecf9def), X(0x7edb89b6),
257 X(0x7ee71de9), X(0x7ef25c09), X(0x7efd4598), X(0x7f07dc16),
258 X(0x7f122103), X(0x7f1c15dc), X(0x7f25bc1f), X(0x7f2f1547),
259 X(0x7f3822cd), X(0x7f40e62b), X(0x7f4960d6), X(0x7f519443),
260 X(0x7f5981e7), X(0x7f612b31), X(0x7f689191), X(0x7f6fb674),
261 X(0x7f769b45), X(0x7f7d416c), X(0x7f83aa51), X(0x7f89d757),
262 X(0x7f8fc9df), X(0x7f958348), X(0x7f9b04ef), X(0x7fa0502e),
263 X(0x7fa56659), X(0x7faa48c7), X(0x7faef8c7), X(0x7fb377a7),
264 X(0x7fb7c6b3), X(0x7fbbe732), X(0x7fbfda67), X(0x7fc3a196),
265 X(0x7fc73dfa), X(0x7fcab0ce), X(0x7fcdfb4a), X(0x7fd11ea0),
266 X(0x7fd41c00), X(0x7fd6f496), X(0x7fd9a989), X(0x7fdc3bff),
267 X(0x7fdead17), X(0x7fe0fdee), X(0x7fe32f9d), X(0x7fe54337),
268 X(0x7fe739ce), X(0x7fe9146c), X(0x7fead41b), X(0x7fec79dd),
269 X(0x7fee06b2), X(0x7fef7b94), X(0x7ff0d97b), X(0x7ff22158),
270 X(0x7ff35417), X(0x7ff472a3), X(0x7ff57de0), X(0x7ff676ac),
271 X(0x7ff75de3), X(0x7ff8345a), X(0x7ff8fae4), X(0x7ff9b24b),
272 X(0x7ffa5b58), X(0x7ffaf6cd), X(0x7ffb8568), X(0x7ffc07e2),
273 X(0x7ffc7eed), X(0x7ffceb38), X(0x7ffd4d6d), X(0x7ffda631),
274 X(0x7ffdf621), X(0x7ffe3dd8), X(0x7ffe7dea), X(0x7ffeb6e7),
275 X(0x7ffee959), X(0x7fff15c4), X(0x7fff3ca9), X(0x7fff5e80),
276 X(0x7fff7bc0), X(0x7fff94d6), X(0x7fffaa2d), X(0x7fffbc29),
277 X(0x7fffcb29), X(0x7fffd786), X(0x7fffe195), X(0x7fffe9a3),
278 X(0x7fffeffa), X(0x7ffff4dd), X(0x7ffff889), X(0x7ffffb37),
279 X(0x7ffffd1a), X(0x7ffffe5d), X(0x7fffff29), X(0x7fffffa0),
280 X(0x7fffffdd), X(0x7ffffff7), X(0x7fffffff), X(0x7fffffff),
281 };
282
283 static const LOOKUP_T vwin2048[1024] = {
284 X(0x000007c0), X(0x000045c4), X(0x0000c1ca), X(0x00017bd3),
285 X(0x000273de), X(0x0003a9eb), X(0x00051df9), X(0x0006d007),
286 X(0x0008c014), X(0x000aee1e), X(0x000d5a25), X(0x00100428),
287 X(0x0012ec23), X(0x00161216), X(0x001975fe), X(0x001d17da),
288 X(0x0020f7a8), X(0x00251564), X(0x0029710c), X(0x002e0a9e),
289 X(0x0032e217), X(0x0037f773), X(0x003d4ab0), X(0x0042dbca),
290 X(0x0048aabe), X(0x004eb788), X(0x00550224), X(0x005b8a8f),
291 X(0x006250c5), X(0x006954c1), X(0x0070967e), X(0x007815f9),
292 X(0x007fd32c), X(0x0087ce13), X(0x009006a9), X(0x00987ce9),
293 X(0x00a130cc), X(0x00aa224f), X(0x00b3516b), X(0x00bcbe1a),
294 X(0x00c66856), X(0x00d0501a), X(0x00da755f), X(0x00e4d81f),
295 X(0x00ef7853), X(0x00fa55f4), X(0x010570fc), X(0x0110c963),
296 X(0x011c5f22), X(0x01283232), X(0x0134428c), X(0x01409027),
297 X(0x014d1afb), X(0x0159e302), X(0x0166e831), X(0x01742a82),
298 X(0x0181a9ec), X(0x018f6665), X(0x019d5fe5), X(0x01ab9663),
299 X(0x01ba09d6), X(0x01c8ba34), X(0x01d7a775), X(0x01e6d18d),
300 X(0x01f63873), X(0x0205dc1e), X(0x0215bc82), X(0x0225d997),
301 X(0x02363350), X(0x0246c9a3), X(0x02579c86), X(0x0268abed),
302 X(0x0279f7cc), X(0x028b801a), X(0x029d44c9), X(0x02af45ce),
303 X(0x02c1831d), X(0x02d3fcaa), X(0x02e6b269), X(0x02f9a44c),
304 X(0x030cd248), X(0x03203c4f), X(0x0333e255), X(0x0347c44b),
305 X(0x035be225), X(0x03703bd5), X(0x0384d14d), X(0x0399a280),
306 X(0x03aeaf5e), X(0x03c3f7d9), X(0x03d97be4), X(0x03ef3b6e),
307 X(0x0405366a), X(0x041b6cc8), X(0x0431de78), X(0x04488b6c),
308 X(0x045f7393), X(0x047696dd), X(0x048df53b), X(0x04a58e9b),
309 X(0x04bd62ee), X(0x04d57223), X(0x04edbc28), X(0x050640ed),
310 X(0x051f0060), X(0x0537fa70), X(0x05512f0a), X(0x056a9e1e),
311 X(0x05844798), X(0x059e2b67), X(0x05b84978), X(0x05d2a1b8),
312 X(0x05ed3414), X(0x06080079), X(0x062306d3), X(0x063e470f),
313 X(0x0659c119), X(0x067574dd), X(0x06916247), X(0x06ad8941),
314 X(0x06c9e9b8), X(0x06e68397), X(0x070356c8), X(0x07206336),
315 X(0x073da8cb), X(0x075b2772), X(0x0778df15), X(0x0796cf9c),
316 X(0x07b4f8f3), X(0x07d35b01), X(0x07f1f5b1), X(0x0810c8eb),
317 X(0x082fd497), X(0x084f189e), X(0x086e94e9), X(0x088e495e),
318 X(0x08ae35e6), X(0x08ce5a68), X(0x08eeb6cc), X(0x090f4af8),
319 X(0x093016d3), X(0x09511a44), X(0x09725530), X(0x0993c77f),
320 X(0x09b57115), X(0x09d751d8), X(0x09f969ae), X(0x0a1bb87c),
321 X(0x0a3e3e26), X(0x0a60fa91), X(0x0a83eda2), X(0x0aa7173c),
322 X(0x0aca7743), X(0x0aee0d9b), X(0x0b11da28), X(0x0b35dccc),
323 X(0x0b5a156a), X(0x0b7e83e5), X(0x0ba3281f), X(0x0bc801fa),
324 X(0x0bed1159), X(0x0c12561c), X(0x0c37d025), X(0x0c5d7f55),
325 X(0x0c83638d), X(0x0ca97cae), X(0x0ccfca97), X(0x0cf64d2a),
326 X(0x0d1d0444), X(0x0d43efc7), X(0x0d6b0f92), X(0x0d926383),
327 X(0x0db9eb79), X(0x0de1a752), X(0x0e0996ee), X(0x0e31ba29),
328 X(0x0e5a10e2), X(0x0e829af6), X(0x0eab5841), X(0x0ed448a2),
329 X(0x0efd6bf4), X(0x0f26c214), X(0x0f504ade), X(0x0f7a062e),
330 X(0x0fa3f3df), X(0x0fce13cd), X(0x0ff865d2), X(0x1022e9ca),
331 X(0x104d9f8e), X(0x107886f9), X(0x10a39fe5), X(0x10ceea2c),
332 X(0x10fa65a6), X(0x1126122d), X(0x1151ef9a), X(0x117dfdc5),
333 X(0x11aa3c87), X(0x11d6abb6), X(0x12034b2c), X(0x12301ac0),
334 X(0x125d1a48), X(0x128a499b), X(0x12b7a891), X(0x12e536ff),
335 X(0x1312f4bb), X(0x1340e19c), X(0x136efd75), X(0x139d481e),
336 X(0x13cbc16a), X(0x13fa692f), X(0x14293f40), X(0x14584371),
337 X(0x14877597), X(0x14b6d585), X(0x14e6630d), X(0x15161e04),
338 X(0x1546063b), X(0x15761b85), X(0x15a65db3), X(0x15d6cc99),
339 X(0x16076806), X(0x16382fcd), X(0x166923bf), X(0x169a43ab),
340 X(0x16cb8f62), X(0x16fd06b5), X(0x172ea973), X(0x1760776b),
341 X(0x1792706e), X(0x17c49449), X(0x17f6e2cb), X(0x18295bc3),
342 X(0x185bfeff), X(0x188ecc4c), X(0x18c1c379), X(0x18f4e452),
343 X(0x19282ea4), X(0x195ba23c), X(0x198f3ee6), X(0x19c3046e),
344 X(0x19f6f2a1), X(0x1a2b094a), X(0x1a5f4833), X(0x1a93af28),
345 X(0x1ac83df3), X(0x1afcf460), X(0x1b31d237), X(0x1b66d744),
346 X(0x1b9c034e), X(0x1bd15621), X(0x1c06cf84), X(0x1c3c6f40),
347 X(0x1c72351e), X(0x1ca820e6), X(0x1cde3260), X(0x1d146953),
348 X(0x1d4ac587), X(0x1d8146c3), X(0x1db7eccd), X(0x1deeb76c),
349 X(0x1e25a667), X(0x1e5cb982), X(0x1e93f085), X(0x1ecb4b33),
350 X(0x1f02c953), X(0x1f3a6aaa), X(0x1f722efb), X(0x1faa160b),
351 X(0x1fe21f9e), X(0x201a4b79), X(0x2052995d), X(0x208b0910),
352 X(0x20c39a53), X(0x20fc4cea), X(0x21352097), X(0x216e151c),
353 X(0x21a72a3a), X(0x21e05fb5), X(0x2219b54d), X(0x22532ac3),
354 X(0x228cbfd8), X(0x22c6744d), X(0x230047e2), X(0x233a3a58),
355 X(0x23744b6d), X(0x23ae7ae3), X(0x23e8c878), X(0x242333ec),
356 X(0x245dbcfd), X(0x24986369), X(0x24d326f1), X(0x250e0750),
357 X(0x25490446), X(0x25841d90), X(0x25bf52ec), X(0x25faa417),
358 X(0x263610cd), X(0x267198cc), X(0x26ad3bcf), X(0x26e8f994),
359 X(0x2724d1d6), X(0x2760c451), X(0x279cd0c0), X(0x27d8f6e0),
360 X(0x2815366a), X(0x28518f1b), X(0x288e00ac), X(0x28ca8ad8),
361 X(0x29072d5a), X(0x2943e7eb), X(0x2980ba45), X(0x29bda422),
362 X(0x29faa53c), X(0x2a37bd4a), X(0x2a74ec07), X(0x2ab2312b),
363 X(0x2aef8c6f), X(0x2b2cfd8b), X(0x2b6a8437), X(0x2ba8202c),
364 X(0x2be5d120), X(0x2c2396cc), X(0x2c6170e7), X(0x2c9f5f29),
365 X(0x2cdd6147), X(0x2d1b76fa), X(0x2d599ff7), X(0x2d97dbf5),
366 X(0x2dd62aab), X(0x2e148bcf), X(0x2e52ff16), X(0x2e918436),
367 X(0x2ed01ae5), X(0x2f0ec2d9), X(0x2f4d7bc6), X(0x2f8c4562),
368 X(0x2fcb1f62), X(0x300a097a), X(0x3049035f), X(0x30880cc6),
369 X(0x30c72563), X(0x31064cea), X(0x3145830f), X(0x3184c786),
370 X(0x31c41a03), X(0x32037a39), X(0x3242e7dc), X(0x3282629f),
371 X(0x32c1ea36), X(0x33017e53), X(0x33411ea9), X(0x3380caec),
372 X(0x33c082ce), X(0x34004602), X(0x34401439), X(0x347fed27),
373 X(0x34bfd07e), X(0x34ffbdf0), X(0x353fb52e), X(0x357fb5ec),
374 X(0x35bfbfda), X(0x35ffd2aa), X(0x363fee0f), X(0x368011b9),
375 X(0x36c03d5a), X(0x370070a4), X(0x3740ab48), X(0x3780ecf7),
376 X(0x37c13562), X(0x3801843a), X(0x3841d931), X(0x388233f7),
377 X(0x38c2943d), X(0x3902f9b4), X(0x3943640d), X(0x3983d2f8),
378 X(0x39c44626), X(0x3a04bd48), X(0x3a45380e), X(0x3a85b62a),
379 X(0x3ac6374a), X(0x3b06bb20), X(0x3b47415c), X(0x3b87c9ae),
380 X(0x3bc853c7), X(0x3c08df57), X(0x3c496c0f), X(0x3c89f99f),
381 X(0x3cca87b6), X(0x3d0b1605), X(0x3d4ba43d), X(0x3d8c320e),
382 X(0x3dccbf27), X(0x3e0d4b3a), X(0x3e4dd5f6), X(0x3e8e5f0c),
383 X(0x3ecee62b), X(0x3f0f6b05), X(0x3f4fed49), X(0x3f906ca8),
384 X(0x3fd0e8d2), X(0x40116177), X(0x4051d648), X(0x409246f6),
385 X(0x40d2b330), X(0x41131aa7), X(0x41537d0c), X(0x4193da10),
386 X(0x41d43162), X(0x421482b4), X(0x4254cdb7), X(0x4295121b),
387 X(0x42d54f91), X(0x431585ca), X(0x4355b477), X(0x4395db49),
388 X(0x43d5f9f1), X(0x44161021), X(0x44561d8a), X(0x449621dd),
389 X(0x44d61ccc), X(0x45160e08), X(0x4555f544), X(0x4595d230),
390 X(0x45d5a47f), X(0x46156be3), X(0x4655280e), X(0x4694d8b2),
391 X(0x46d47d82), X(0x4714162f), X(0x4753a26d), X(0x479321ef),
392 X(0x47d29466), X(0x4811f987), X(0x48515104), X(0x48909a91),
393 X(0x48cfd5e1), X(0x490f02a7), X(0x494e2098), X(0x498d2f66),
394 X(0x49cc2ec7), X(0x4a0b1e6f), X(0x4a49fe11), X(0x4a88cd62),
395 X(0x4ac78c18), X(0x4b0639e6), X(0x4b44d683), X(0x4b8361a2),
396 X(0x4bc1dafa), X(0x4c004241), X(0x4c3e972c), X(0x4c7cd970),
397 X(0x4cbb08c5), X(0x4cf924e1), X(0x4d372d7a), X(0x4d752247),
398 X(0x4db30300), X(0x4df0cf5a), X(0x4e2e870f), X(0x4e6c29d6),
399 X(0x4ea9b766), X(0x4ee72f78), X(0x4f2491c4), X(0x4f61de02),
400 X(0x4f9f13ec), X(0x4fdc333b), X(0x50193ba8), X(0x50562ced),
401 X(0x509306c3), X(0x50cfc8e5), X(0x510c730d), X(0x514904f6),
402 X(0x51857e5a), X(0x51c1def5), X(0x51fe2682), X(0x523a54bc),
403 X(0x52766961), X(0x52b2642c), X(0x52ee44d9), X(0x532a0b26),
404 X(0x5365b6d0), X(0x53a14793), X(0x53dcbd2f), X(0x54181760),
405 X(0x545355e5), X(0x548e787d), X(0x54c97ee6), X(0x550468e1),
406 X(0x553f362c), X(0x5579e687), X(0x55b479b3), X(0x55eeef70),
407 X(0x5629477f), X(0x566381a1), X(0x569d9d97), X(0x56d79b24),
408 X(0x57117a0a), X(0x574b3a0a), X(0x5784dae9), X(0x57be5c69),
409 X(0x57f7be4d), X(0x5831005a), X(0x586a2254), X(0x58a32400),
410 X(0x58dc0522), X(0x5914c57f), X(0x594d64de), X(0x5985e305),
411 X(0x59be3fba), X(0x59f67ac3), X(0x5a2e93e9), X(0x5a668af2),
412 X(0x5a9e5fa6), X(0x5ad611ce), X(0x5b0da133), X(0x5b450d9d),
413 X(0x5b7c56d7), X(0x5bb37ca9), X(0x5bea7ede), X(0x5c215d41),
414 X(0x5c58179d), X(0x5c8eadbe), X(0x5cc51f6f), X(0x5cfb6c7c),
415 X(0x5d3194b2), X(0x5d6797de), X(0x5d9d75cf), X(0x5dd32e51),
416 X(0x5e08c132), X(0x5e3e2e43), X(0x5e737551), X(0x5ea8962d),
417 X(0x5edd90a7), X(0x5f12648e), X(0x5f4711b4), X(0x5f7b97ea),
418 X(0x5faff702), X(0x5fe42ece), X(0x60183f20), X(0x604c27cc),
419 X(0x607fe8a6), X(0x60b38180), X(0x60e6f22f), X(0x611a3a89),
420 X(0x614d5a62), X(0x61805190), X(0x61b31fe9), X(0x61e5c545),
421 X(0x62184179), X(0x624a945d), X(0x627cbdca), X(0x62aebd98),
422 X(0x62e0939f), X(0x63123fba), X(0x6343c1c1), X(0x6375198f),
423 X(0x63a646ff), X(0x63d749ec), X(0x64082232), X(0x6438cfad),
424 X(0x64695238), X(0x6499a9b3), X(0x64c9d5f9), X(0x64f9d6ea),
425 X(0x6529ac63), X(0x65595643), X(0x6588d46a), X(0x65b826b8),
426 X(0x65e74d0e), X(0x6616474b), X(0x66451552), X(0x6673b704),
427 X(0x66a22c44), X(0x66d074f4), X(0x66fe90f8), X(0x672c8033),
428 X(0x675a428a), X(0x6787d7e1), X(0x67b5401f), X(0x67e27b27),
429 X(0x680f88e1), X(0x683c6934), X(0x68691c05), X(0x6895a13e),
430 X(0x68c1f8c7), X(0x68ee2287), X(0x691a1e68), X(0x6945ec54),
431 X(0x69718c35), X(0x699cfdf5), X(0x69c8417f), X(0x69f356c0),
432 X(0x6a1e3da3), X(0x6a48f615), X(0x6a738002), X(0x6a9ddb5a),
433 X(0x6ac80808), X(0x6af205fd), X(0x6b1bd526), X(0x6b457575),
434 X(0x6b6ee6d8), X(0x6b982940), X(0x6bc13c9f), X(0x6bea20e5),
435 X(0x6c12d605), X(0x6c3b5bf1), X(0x6c63b29c), X(0x6c8bd9fb),
436 X(0x6cb3d200), X(0x6cdb9aa0), X(0x6d0333d0), X(0x6d2a9d86),
437 X(0x6d51d7b7), X(0x6d78e25a), X(0x6d9fbd67), X(0x6dc668d3),
438 X(0x6dece498), X(0x6e1330ad), X(0x6e394d0c), X(0x6e5f39ae),
439 X(0x6e84f68d), X(0x6eaa83a2), X(0x6ecfe0ea), X(0x6ef50e5e),
440 X(0x6f1a0bfc), X(0x6f3ed9bf), X(0x6f6377a4), X(0x6f87e5a8),
441 X(0x6fac23c9), X(0x6fd03206), X(0x6ff4105c), X(0x7017becc),
442 X(0x703b3d54), X(0x705e8bf5), X(0x7081aaaf), X(0x70a49984),
443 X(0x70c75874), X(0x70e9e783), X(0x710c46b2), X(0x712e7605),
444 X(0x7150757f), X(0x71724523), X(0x7193e4f6), X(0x71b554fd),
445 X(0x71d6953e), X(0x71f7a5bd), X(0x72188681), X(0x72393792),
446 X(0x7259b8f5), X(0x727a0ab2), X(0x729a2cd2), X(0x72ba1f5d),
447 X(0x72d9e25c), X(0x72f975d8), X(0x7318d9db), X(0x73380e6f),
448 X(0x735713a0), X(0x7375e978), X(0x73949003), X(0x73b3074c),
449 X(0x73d14f61), X(0x73ef684f), X(0x740d5222), X(0x742b0ce9),
450 X(0x744898b1), X(0x7465f589), X(0x74832381), X(0x74a022a8),
451 X(0x74bcf30e), X(0x74d994c3), X(0x74f607d8), X(0x75124c5f),
452 X(0x752e6268), X(0x754a4a05), X(0x7566034b), X(0x75818e4a),
453 X(0x759ceb16), X(0x75b819c4), X(0x75d31a66), X(0x75eded12),
454 X(0x760891dc), X(0x762308da), X(0x763d5221), X(0x76576dc8),
455 X(0x76715be4), X(0x768b1c8c), X(0x76a4afd9), X(0x76be15e0),
456 X(0x76d74ebb), X(0x76f05a82), X(0x7709394d), X(0x7721eb35),
457 X(0x773a7054), X(0x7752c8c4), X(0x776af49f), X(0x7782f400),
458 X(0x779ac701), X(0x77b26dbd), X(0x77c9e851), X(0x77e136d8),
459 X(0x77f8596f), X(0x780f5032), X(0x78261b3f), X(0x783cbab2),
460 X(0x78532eaa), X(0x78697745), X(0x787f94a0), X(0x789586db),
461 X(0x78ab4e15), X(0x78c0ea6d), X(0x78d65c03), X(0x78eba2f7),
462 X(0x7900bf68), X(0x7915b179), X(0x792a7949), X(0x793f16fb),
463 X(0x79538aaf), X(0x7967d488), X(0x797bf4a8), X(0x798feb31),
464 X(0x79a3b846), X(0x79b75c0a), X(0x79cad6a1), X(0x79de282e),
465 X(0x79f150d5), X(0x7a0450bb), X(0x7a172803), X(0x7a29d6d3),
466 X(0x7a3c5d50), X(0x7a4ebb9f), X(0x7a60f1e6), X(0x7a73004a),
467 X(0x7a84e6f2), X(0x7a96a604), X(0x7aa83da7), X(0x7ab9ae01),
468 X(0x7acaf73a), X(0x7adc1979), X(0x7aed14e6), X(0x7afde9a8),
469 X(0x7b0e97e8), X(0x7b1f1fcd), X(0x7b2f8182), X(0x7b3fbd2d),
470 X(0x7b4fd2f9), X(0x7b5fc30f), X(0x7b6f8d98), X(0x7b7f32bd),
471 X(0x7b8eb2a9), X(0x7b9e0d85), X(0x7bad437d), X(0x7bbc54b9),
472 X(0x7bcb4166), X(0x7bda09ae), X(0x7be8adbc), X(0x7bf72dbc),
473 X(0x7c0589d8), X(0x7c13c23d), X(0x7c21d716), X(0x7c2fc88f),
474 X(0x7c3d96d5), X(0x7c4b4214), X(0x7c58ca78), X(0x7c66302d),
475 X(0x7c737362), X(0x7c809443), X(0x7c8d92fc), X(0x7c9a6fbc),
476 X(0x7ca72aaf), X(0x7cb3c404), X(0x7cc03be8), X(0x7ccc9288),
477 X(0x7cd8c814), X(0x7ce4dcb9), X(0x7cf0d0a5), X(0x7cfca406),
478 X(0x7d08570c), X(0x7d13e9e5), X(0x7d1f5cbf), X(0x7d2aafca),
479 X(0x7d35e335), X(0x7d40f72e), X(0x7d4bebe4), X(0x7d56c188),
480 X(0x7d617848), X(0x7d6c1054), X(0x7d7689db), X(0x7d80e50e),
481 X(0x7d8b221b), X(0x7d954133), X(0x7d9f4286), X(0x7da92643),
482 X(0x7db2ec9b), X(0x7dbc95bd), X(0x7dc621da), X(0x7dcf9123),
483 X(0x7dd8e3c6), X(0x7de219f6), X(0x7deb33e2), X(0x7df431ba),
484 X(0x7dfd13af), X(0x7e05d9f2), X(0x7e0e84b4), X(0x7e171424),
485 X(0x7e1f8874), X(0x7e27e1d4), X(0x7e302074), X(0x7e384487),
486 X(0x7e404e3c), X(0x7e483dc4), X(0x7e501350), X(0x7e57cf11),
487 X(0x7e5f7138), X(0x7e66f9f4), X(0x7e6e6979), X(0x7e75bff5),
488 X(0x7e7cfd9a), X(0x7e842298), X(0x7e8b2f22), X(0x7e922366),
489 X(0x7e98ff97), X(0x7e9fc3e4), X(0x7ea6707f), X(0x7ead0598),
490 X(0x7eb38360), X(0x7eb9ea07), X(0x7ec039bf), X(0x7ec672b7),
491 X(0x7ecc9521), X(0x7ed2a12c), X(0x7ed8970a), X(0x7ede76ea),
492 X(0x7ee440fd), X(0x7ee9f573), X(0x7eef947d), X(0x7ef51e4b),
493 X(0x7efa930d), X(0x7efff2f2), X(0x7f053e2b), X(0x7f0a74e8),
494 X(0x7f0f9758), X(0x7f14a5ac), X(0x7f19a013), X(0x7f1e86bc),
495 X(0x7f2359d8), X(0x7f281995), X(0x7f2cc623), X(0x7f315fb1),
496 X(0x7f35e66e), X(0x7f3a5a8a), X(0x7f3ebc33), X(0x7f430b98),
497 X(0x7f4748e7), X(0x7f4b7450), X(0x7f4f8e01), X(0x7f539629),
498 X(0x7f578cf5), X(0x7f5b7293), X(0x7f5f4732), X(0x7f630b00),
499 X(0x7f66be2b), X(0x7f6a60df), X(0x7f6df34b), X(0x7f71759b),
500 X(0x7f74e7fe), X(0x7f784aa0), X(0x7f7b9daf), X(0x7f7ee156),
501 X(0x7f8215c3), X(0x7f853b22), X(0x7f88519f), X(0x7f8b5967),
502 X(0x7f8e52a6), X(0x7f913d87), X(0x7f941a36), X(0x7f96e8df),
503 X(0x7f99a9ad), X(0x7f9c5ccb), X(0x7f9f0265), X(0x7fa19aa5),
504 X(0x7fa425b5), X(0x7fa6a3c1), X(0x7fa914f3), X(0x7fab7974),
505 X(0x7fadd16f), X(0x7fb01d0d), X(0x7fb25c78), X(0x7fb48fd9),
506 X(0x7fb6b75a), X(0x7fb8d323), X(0x7fbae35d), X(0x7fbce831),
507 X(0x7fbee1c7), X(0x7fc0d047), X(0x7fc2b3d9), X(0x7fc48ca5),
508 X(0x7fc65ad3), X(0x7fc81e88), X(0x7fc9d7ee), X(0x7fcb872a),
509 X(0x7fcd2c63), X(0x7fcec7bf), X(0x7fd05966), X(0x7fd1e17c),
510 X(0x7fd36027), X(0x7fd4d58d), X(0x7fd641d3), X(0x7fd7a51e),
511 X(0x7fd8ff94), X(0x7fda5157), X(0x7fdb9a8e), X(0x7fdcdb5b),
512 X(0x7fde13e2), X(0x7fdf4448), X(0x7fe06caf), X(0x7fe18d3b),
513 X(0x7fe2a60e), X(0x7fe3b74b), X(0x7fe4c114), X(0x7fe5c38b),
514 X(0x7fe6bed2), X(0x7fe7b30a), X(0x7fe8a055), X(0x7fe986d4),
515 X(0x7fea66a7), X(0x7feb3ff0), X(0x7fec12cd), X(0x7fecdf5f),
516 X(0x7feda5c5), X(0x7fee6620), X(0x7fef208d), X(0x7fefd52c),
517 X(0x7ff0841c), X(0x7ff12d7a), X(0x7ff1d164), X(0x7ff26ff9),
518 X(0x7ff30955), X(0x7ff39d96), X(0x7ff42cd9), X(0x7ff4b739),
519 X(0x7ff53cd4), X(0x7ff5bdc5), X(0x7ff63a28), X(0x7ff6b217),
520 X(0x7ff725af), X(0x7ff7950a), X(0x7ff80043), X(0x7ff86773),
521 X(0x7ff8cab4), X(0x7ff92a21), X(0x7ff985d1), X(0x7ff9dddf),
522 X(0x7ffa3262), X(0x7ffa8374), X(0x7ffad12c), X(0x7ffb1ba1),
523 X(0x7ffb62ec), X(0x7ffba723), X(0x7ffbe85c), X(0x7ffc26b0),
524 X(0x7ffc6233), X(0x7ffc9afb), X(0x7ffcd11e), X(0x7ffd04b1),
525 X(0x7ffd35c9), X(0x7ffd647b), X(0x7ffd90da), X(0x7ffdbafa),
526 X(0x7ffde2f0), X(0x7ffe08ce), X(0x7ffe2ca7), X(0x7ffe4e8e),
527 X(0x7ffe6e95), X(0x7ffe8cce), X(0x7ffea94a), X(0x7ffec41b),
528 X(0x7ffedd52), X(0x7ffef4ff), X(0x7fff0b33), X(0x7fff1ffd),
529 X(0x7fff336e), X(0x7fff4593), X(0x7fff567d), X(0x7fff663a),
530 X(0x7fff74d8), X(0x7fff8265), X(0x7fff8eee), X(0x7fff9a81),
531 X(0x7fffa52b), X(0x7fffaef8), X(0x7fffb7f5), X(0x7fffc02d),
532 X(0x7fffc7ab), X(0x7fffce7c), X(0x7fffd4a9), X(0x7fffda3e),
533 X(0x7fffdf44), X(0x7fffe3c6), X(0x7fffe7cc), X(0x7fffeb60),
534 X(0x7fffee8a), X(0x7ffff153), X(0x7ffff3c4), X(0x7ffff5e3),
535 X(0x7ffff7b8), X(0x7ffff94b), X(0x7ffffaa1), X(0x7ffffbc1),
536 X(0x7ffffcb2), X(0x7ffffd78), X(0x7ffffe19), X(0x7ffffe9a),
537 X(0x7ffffeff), X(0x7fffff4e), X(0x7fffff89), X(0x7fffffb3),
538 X(0x7fffffd2), X(0x7fffffe6), X(0x7ffffff3), X(0x7ffffffa),
539 X(0x7ffffffe), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff),
540 };
541
542 static const LOOKUP_T vwin4096[2048] = {
543 X(0x000001f0), X(0x00001171), X(0x00003072), X(0x00005ef5),
544 X(0x00009cf8), X(0x0000ea7c), X(0x00014780), X(0x0001b405),
545 X(0x0002300b), X(0x0002bb91), X(0x00035698), X(0x0004011e),
546 X(0x0004bb25), X(0x000584ac), X(0x00065db3), X(0x0007463a),
547 X(0x00083e41), X(0x000945c7), X(0x000a5ccc), X(0x000b8350),
548 X(0x000cb954), X(0x000dfed7), X(0x000f53d8), X(0x0010b857),
549 X(0x00122c55), X(0x0013afd1), X(0x001542ca), X(0x0016e541),
550 X(0x00189735), X(0x001a58a7), X(0x001c2995), X(0x001e09ff),
551 X(0x001ff9e6), X(0x0021f948), X(0x00240826), X(0x00262680),
552 X(0x00285454), X(0x002a91a3), X(0x002cde6c), X(0x002f3aaf),
553 X(0x0031a66b), X(0x003421a0), X(0x0036ac4f), X(0x00394675),
554 X(0x003bf014), X(0x003ea92a), X(0x004171b7), X(0x004449bb),
555 X(0x00473135), X(0x004a2824), X(0x004d2e8a), X(0x00504463),
556 X(0x005369b2), X(0x00569e74), X(0x0059e2aa), X(0x005d3652),
557 X(0x0060996d), X(0x00640bf9), X(0x00678df7), X(0x006b1f66),
558 X(0x006ec045), X(0x00727093), X(0x00763051), X(0x0079ff7d),
559 X(0x007dde16), X(0x0081cc1d), X(0x0085c991), X(0x0089d671),
560 X(0x008df2bc), X(0x00921e71), X(0x00965991), X(0x009aa41a),
561 X(0x009efe0c), X(0x00a36766), X(0x00a7e028), X(0x00ac6850),
562 X(0x00b0ffde), X(0x00b5a6d1), X(0x00ba5d28), X(0x00bf22e4),
563 X(0x00c3f802), X(0x00c8dc83), X(0x00cdd065), X(0x00d2d3a8),
564 X(0x00d7e64a), X(0x00dd084c), X(0x00e239ac), X(0x00e77a69),
565 X(0x00ecca83), X(0x00f229f9), X(0x00f798ca), X(0x00fd16f5),
566 X(0x0102a479), X(0x01084155), X(0x010ded89), X(0x0113a913),
567 X(0x011973f3), X(0x011f4e27), X(0x012537af), X(0x012b308a),
568 X(0x013138b7), X(0x01375035), X(0x013d7702), X(0x0143ad1f),
569 X(0x0149f289), X(0x01504741), X(0x0156ab44), X(0x015d1e92),
570 X(0x0163a12a), X(0x016a330b), X(0x0170d433), X(0x017784a3),
571 X(0x017e4458), X(0x01851351), X(0x018bf18e), X(0x0192df0d),
572 X(0x0199dbcd), X(0x01a0e7cd), X(0x01a8030c), X(0x01af2d89),
573 X(0x01b66743), X(0x01bdb038), X(0x01c50867), X(0x01cc6fd0),
574 X(0x01d3e670), X(0x01db6c47), X(0x01e30153), X(0x01eaa593),
575 X(0x01f25907), X(0x01fa1bac), X(0x0201ed81), X(0x0209ce86),
576 X(0x0211beb8), X(0x0219be17), X(0x0221cca2), X(0x0229ea56),
577 X(0x02321733), X(0x023a5337), X(0x02429e60), X(0x024af8af),
578 X(0x02536220), X(0x025bdab3), X(0x02646267), X(0x026cf93a),
579 X(0x02759f2a), X(0x027e5436), X(0x0287185d), X(0x028feb9d),
580 X(0x0298cdf4), X(0x02a1bf62), X(0x02aabfe5), X(0x02b3cf7b),
581 X(0x02bcee23), X(0x02c61bdb), X(0x02cf58a2), X(0x02d8a475),
582 X(0x02e1ff55), X(0x02eb693e), X(0x02f4e230), X(0x02fe6a29),
583 X(0x03080127), X(0x0311a729), X(0x031b5c2d), X(0x03252031),
584 X(0x032ef334), X(0x0338d534), X(0x0342c630), X(0x034cc625),
585 X(0x0356d512), X(0x0360f2f6), X(0x036b1fce), X(0x03755b99),
586 X(0x037fa655), X(0x038a0001), X(0x0394689a), X(0x039ee020),
587 X(0x03a9668f), X(0x03b3fbe6), X(0x03bea024), X(0x03c95347),
588 X(0x03d4154d), X(0x03dee633), X(0x03e9c5f9), X(0x03f4b49b),
589 X(0x03ffb219), X(0x040abe71), X(0x0415d9a0), X(0x042103a5),
590 X(0x042c3c7d), X(0x04378428), X(0x0442daa2), X(0x044e3fea),
591 X(0x0459b3fd), X(0x046536db), X(0x0470c880), X(0x047c68eb),
592 X(0x0488181a), X(0x0493d60b), X(0x049fa2bc), X(0x04ab7e2a),
593 X(0x04b76854), X(0x04c36137), X(0x04cf68d1), X(0x04db7f21),
594 X(0x04e7a424), X(0x04f3d7d8), X(0x05001a3b), X(0x050c6b4a),
595 X(0x0518cb04), X(0x05253966), X(0x0531b66e), X(0x053e421a),
596 X(0x054adc68), X(0x05578555), X(0x05643cdf), X(0x05710304),
597 X(0x057dd7c1), X(0x058abb15), X(0x0597acfd), X(0x05a4ad76),
598 X(0x05b1bc7f), X(0x05beda14), X(0x05cc0635), X(0x05d940dd),
599 X(0x05e68a0b), X(0x05f3e1bd), X(0x060147f0), X(0x060ebca1),
600 X(0x061c3fcf), X(0x0629d176), X(0x06377194), X(0x06452027),
601 X(0x0652dd2c), X(0x0660a8a2), X(0x066e8284), X(0x067c6ad1),
602 X(0x068a6186), X(0x069866a1), X(0x06a67a1e), X(0x06b49bfc),
603 X(0x06c2cc38), X(0x06d10acf), X(0x06df57bf), X(0x06edb304),
604 X(0x06fc1c9d), X(0x070a9487), X(0x07191abe), X(0x0727af40),
605 X(0x0736520b), X(0x0745031c), X(0x0753c270), X(0x07629004),
606 X(0x07716bd6), X(0x078055e2), X(0x078f4e26), X(0x079e549f),
607 X(0x07ad694b), X(0x07bc8c26), X(0x07cbbd2e), X(0x07dafc5f),
608 X(0x07ea49b7), X(0x07f9a533), X(0x08090ed1), X(0x0818868c),
609 X(0x08280c62), X(0x0837a051), X(0x08474255), X(0x0856f26b),
610 X(0x0866b091), X(0x08767cc3), X(0x088656fe), X(0x08963f3f),
611 X(0x08a63584), X(0x08b639c8), X(0x08c64c0a), X(0x08d66c45),
612 X(0x08e69a77), X(0x08f6d69d), X(0x090720b3), X(0x091778b7),
613 X(0x0927dea5), X(0x0938527a), X(0x0948d433), X(0x095963cc),
614 X(0x096a0143), X(0x097aac94), X(0x098b65bb), X(0x099c2cb6),
615 X(0x09ad0182), X(0x09bde41a), X(0x09ced47d), X(0x09dfd2a5),
616 X(0x09f0de90), X(0x0a01f83b), X(0x0a131fa3), X(0x0a2454c3),
617 X(0x0a359798), X(0x0a46e820), X(0x0a584656), X(0x0a69b237),
618 X(0x0a7b2bc0), X(0x0a8cb2ec), X(0x0a9e47ba), X(0x0aafea24),
619 X(0x0ac19a29), X(0x0ad357c3), X(0x0ae522ef), X(0x0af6fbab),
620 X(0x0b08e1f1), X(0x0b1ad5c0), X(0x0b2cd712), X(0x0b3ee5e5),
621 X(0x0b510234), X(0x0b632bfd), X(0x0b75633b), X(0x0b87a7eb),
622 X(0x0b99fa08), X(0x0bac5990), X(0x0bbec67e), X(0x0bd140cf),
623 X(0x0be3c87e), X(0x0bf65d89), X(0x0c08ffeb), X(0x0c1bafa1),
624 X(0x0c2e6ca6), X(0x0c4136f6), X(0x0c540e8f), X(0x0c66f36c),
625 X(0x0c79e588), X(0x0c8ce4e1), X(0x0c9ff172), X(0x0cb30b37),
626 X(0x0cc6322c), X(0x0cd9664d), X(0x0ceca797), X(0x0cfff605),
627 X(0x0d135193), X(0x0d26ba3d), X(0x0d3a2fff), X(0x0d4db2d5),
628 X(0x0d6142ba), X(0x0d74dfac), X(0x0d8889a5), X(0x0d9c40a1),
629 X(0x0db0049d), X(0x0dc3d593), X(0x0dd7b380), X(0x0deb9e60),
630 X(0x0dff962f), X(0x0e139ae7), X(0x0e27ac85), X(0x0e3bcb05),
631 X(0x0e4ff662), X(0x0e642e98), X(0x0e7873a2), X(0x0e8cc57d),
632 X(0x0ea12423), X(0x0eb58f91), X(0x0eca07c2), X(0x0ede8cb1),
633 X(0x0ef31e5b), X(0x0f07bcba), X(0x0f1c67cb), X(0x0f311f88),
634 X(0x0f45e3ee), X(0x0f5ab4f7), X(0x0f6f92a0), X(0x0f847ce3),
635 X(0x0f9973bc), X(0x0fae7726), X(0x0fc3871e), X(0x0fd8a39d),
636 X(0x0fedcca1), X(0x10030223), X(0x1018441f), X(0x102d9291),
637 X(0x1042ed74), X(0x105854c3), X(0x106dc879), X(0x10834892),
638 X(0x1098d508), X(0x10ae6dd8), X(0x10c412fc), X(0x10d9c46f),
639 X(0x10ef822d), X(0x11054c30), X(0x111b2274), X(0x113104f5),
640 X(0x1146f3ac), X(0x115cee95), X(0x1172f5ab), X(0x118908e9),
641 X(0x119f284a), X(0x11b553ca), X(0x11cb8b62), X(0x11e1cf0f),
642 X(0x11f81ecb), X(0x120e7a90), X(0x1224e25a), X(0x123b5624),
643 X(0x1251d5e9), X(0x126861a3), X(0x127ef94e), X(0x12959ce3),
644 X(0x12ac4c5f), X(0x12c307bb), X(0x12d9cef2), X(0x12f0a200),
645 X(0x130780df), X(0x131e6b8a), X(0x133561fa), X(0x134c642c),
646 X(0x1363721a), X(0x137a8bbe), X(0x1391b113), X(0x13a8e214),
647 X(0x13c01eba), X(0x13d76702), X(0x13eebae5), X(0x14061a5e),
648 X(0x141d8567), X(0x1434fbfb), X(0x144c7e14), X(0x14640bae),
649 X(0x147ba4c1), X(0x14934949), X(0x14aaf941), X(0x14c2b4a2),
650 X(0x14da7b67), X(0x14f24d8a), X(0x150a2b06), X(0x152213d5),
651 X(0x153a07f1), X(0x15520755), X(0x156a11fb), X(0x158227dd),
652 X(0x159a48f5), X(0x15b2753d), X(0x15caacb1), X(0x15e2ef49),
653 X(0x15fb3d01), X(0x161395d2), X(0x162bf9b6), X(0x164468a8),
654 X(0x165ce2a1), X(0x1675679c), X(0x168df793), X(0x16a69280),
655 X(0x16bf385c), X(0x16d7e922), X(0x16f0a4cc), X(0x17096b54),
656 X(0x17223cb4), X(0x173b18e5), X(0x1753ffe2), X(0x176cf1a5),
657 X(0x1785ee27), X(0x179ef562), X(0x17b80750), X(0x17d123eb),
658 X(0x17ea4b2d), X(0x18037d10), X(0x181cb98d), X(0x1836009e),
659 X(0x184f523c), X(0x1868ae63), X(0x1882150a), X(0x189b862c),
660 X(0x18b501c4), X(0x18ce87c9), X(0x18e81836), X(0x1901b305),
661 X(0x191b582f), X(0x193507ad), X(0x194ec17a), X(0x1968858f),
662 X(0x198253e5), X(0x199c2c75), X(0x19b60f3a), X(0x19cffc2d),
663 X(0x19e9f347), X(0x1a03f482), X(0x1a1dffd7), X(0x1a381540),
664 X(0x1a5234b5), X(0x1a6c5e31), X(0x1a8691ac), X(0x1aa0cf21),
665 X(0x1abb1687), X(0x1ad567da), X(0x1aefc311), X(0x1b0a2826),
666 X(0x1b249712), X(0x1b3f0fd0), X(0x1b599257), X(0x1b741ea1),
667 X(0x1b8eb4a7), X(0x1ba95462), X(0x1bc3fdcd), X(0x1bdeb0de),
668 X(0x1bf96d91), X(0x1c1433dd), X(0x1c2f03bc), X(0x1c49dd27),
669 X(0x1c64c017), X(0x1c7fac85), X(0x1c9aa269), X(0x1cb5a1be),
670 X(0x1cd0aa7c), X(0x1cebbc9c), X(0x1d06d816), X(0x1d21fce4),
671 X(0x1d3d2aff), X(0x1d586260), X(0x1d73a2fe), X(0x1d8eecd4),
672 X(0x1daa3fda), X(0x1dc59c09), X(0x1de1015a), X(0x1dfc6fc5),
673 X(0x1e17e743), X(0x1e3367cd), X(0x1e4ef15b), X(0x1e6a83e7),
674 X(0x1e861f6a), X(0x1ea1c3da), X(0x1ebd7133), X(0x1ed9276b),
675 X(0x1ef4e67c), X(0x1f10ae5e), X(0x1f2c7f0a), X(0x1f485879),
676 X(0x1f643aa2), X(0x1f80257f), X(0x1f9c1908), X(0x1fb81536),
677 X(0x1fd41a00), X(0x1ff02761), X(0x200c3d4f), X(0x20285bc3),
678 X(0x204482b7), X(0x2060b221), X(0x207ce9fb), X(0x20992a3e),
679 X(0x20b572e0), X(0x20d1c3dc), X(0x20ee1d28), X(0x210a7ebe),
680 X(0x2126e895), X(0x21435aa6), X(0x215fd4ea), X(0x217c5757),
681 X(0x2198e1e8), X(0x21b57493), X(0x21d20f51), X(0x21eeb21b),
682 X(0x220b5ce7), X(0x22280fb0), X(0x2244ca6c), X(0x22618d13),
683 X(0x227e579f), X(0x229b2a06), X(0x22b80442), X(0x22d4e649),
684 X(0x22f1d015), X(0x230ec19d), X(0x232bbad9), X(0x2348bbc1),
685 X(0x2365c44c), X(0x2382d474), X(0x239fec30), X(0x23bd0b78),
686 X(0x23da3244), X(0x23f7608b), X(0x24149646), X(0x2431d36c),
687 X(0x244f17f5), X(0x246c63da), X(0x2489b711), X(0x24a71193),
688 X(0x24c47358), X(0x24e1dc57), X(0x24ff4c88), X(0x251cc3e2),
689 X(0x253a425e), X(0x2557c7f4), X(0x2575549a), X(0x2592e848),
690 X(0x25b082f7), X(0x25ce249e), X(0x25ebcd34), X(0x26097cb2),
691 X(0x2627330e), X(0x2644f040), X(0x2662b441), X(0x26807f07),
692 X(0x269e5089), X(0x26bc28c1), X(0x26da07a4), X(0x26f7ed2b),
693 X(0x2715d94d), X(0x2733cc02), X(0x2751c540), X(0x276fc500),
694 X(0x278dcb39), X(0x27abd7e2), X(0x27c9eaf3), X(0x27e80463),
695 X(0x28062429), X(0x28244a3e), X(0x28427697), X(0x2860a92d),
696 X(0x287ee1f7), X(0x289d20eb), X(0x28bb6603), X(0x28d9b134),
697 X(0x28f80275), X(0x291659c0), X(0x2934b709), X(0x29531a49),
698 X(0x29718378), X(0x298ff28b), X(0x29ae677b), X(0x29cce23e),
699 X(0x29eb62cb), X(0x2a09e91b), X(0x2a287523), X(0x2a4706dc),
700 X(0x2a659e3c), X(0x2a843b39), X(0x2aa2ddcd), X(0x2ac185ec),
701 X(0x2ae0338f), X(0x2afee6ad), X(0x2b1d9f3c), X(0x2b3c5d33),
702 X(0x2b5b208b), X(0x2b79e939), X(0x2b98b734), X(0x2bb78a74),
703 X(0x2bd662ef), X(0x2bf5409d), X(0x2c142374), X(0x2c330b6b),
704 X(0x2c51f87a), X(0x2c70ea97), X(0x2c8fe1b9), X(0x2caeddd6),
705 X(0x2ccddee7), X(0x2cece4e1), X(0x2d0befbb), X(0x2d2aff6d),
706 X(0x2d4a13ec), X(0x2d692d31), X(0x2d884b32), X(0x2da76de4),
707 X(0x2dc69540), X(0x2de5c13d), X(0x2e04f1d0), X(0x2e2426f0),
708 X(0x2e436095), X(0x2e629eb4), X(0x2e81e146), X(0x2ea1283f),
709 X(0x2ec07398), X(0x2edfc347), X(0x2eff1742), X(0x2f1e6f80),
710 X(0x2f3dcbf8), X(0x2f5d2ca0), X(0x2f7c916f), X(0x2f9bfa5c),
711 X(0x2fbb675d), X(0x2fdad869), X(0x2ffa4d76), X(0x3019c67b),
712 X(0x3039436f), X(0x3058c448), X(0x307848fc), X(0x3097d183),
713 X(0x30b75dd3), X(0x30d6ede2), X(0x30f681a6), X(0x31161917),
714 X(0x3135b42b), X(0x315552d8), X(0x3174f514), X(0x31949ad7),
715 X(0x31b44417), X(0x31d3f0ca), X(0x31f3a0e6), X(0x32135462),
716 X(0x32330b35), X(0x3252c555), X(0x327282b7), X(0x32924354),
717 X(0x32b20720), X(0x32d1ce13), X(0x32f19823), X(0x33116546),
718 X(0x33313573), X(0x3351089f), X(0x3370dec2), X(0x3390b7d1),
719 X(0x33b093c3), X(0x33d0728f), X(0x33f05429), X(0x3410388a),
720 X(0x34301fa7), X(0x34500977), X(0x346ff5ef), X(0x348fe506),
721 X(0x34afd6b3), X(0x34cfcaeb), X(0x34efc1a5), X(0x350fbad7),
722 X(0x352fb678), X(0x354fb47d), X(0x356fb4dd), X(0x358fb78e),
723 X(0x35afbc86), X(0x35cfc3bc), X(0x35efcd25), X(0x360fd8b8),
724 X(0x362fe66c), X(0x364ff636), X(0x3670080c), X(0x36901be5),
725 X(0x36b031b7), X(0x36d04978), X(0x36f0631e), X(0x37107ea0),
726 X(0x37309bf3), X(0x3750bb0e), X(0x3770dbe6), X(0x3790fe73),
727 X(0x37b122aa), X(0x37d14881), X(0x37f16fee), X(0x381198e8),
728 X(0x3831c365), X(0x3851ef5a), X(0x38721cbe), X(0x38924b87),
729 X(0x38b27bac), X(0x38d2ad21), X(0x38f2dfde), X(0x391313d8),
730 X(0x39334906), X(0x39537f5d), X(0x3973b6d4), X(0x3993ef60),
731 X(0x39b428f9), X(0x39d46393), X(0x39f49f25), X(0x3a14dba6),
732 X(0x3a35190a), X(0x3a555748), X(0x3a759657), X(0x3a95d62c),
733 X(0x3ab616be), X(0x3ad65801), X(0x3af699ed), X(0x3b16dc78),
734 X(0x3b371f97), X(0x3b576341), X(0x3b77a76c), X(0x3b97ec0d),
735 X(0x3bb8311b), X(0x3bd8768b), X(0x3bf8bc55), X(0x3c19026d),
736 X(0x3c3948ca), X(0x3c598f62), X(0x3c79d62b), X(0x3c9a1d1b),
737 X(0x3cba6428), X(0x3cdaab48), X(0x3cfaf271), X(0x3d1b3999),
738 X(0x3d3b80b6), X(0x3d5bc7be), X(0x3d7c0ea8), X(0x3d9c5569),
739 X(0x3dbc9bf7), X(0x3ddce248), X(0x3dfd2852), X(0x3e1d6e0c),
740 X(0x3e3db36c), X(0x3e5df866), X(0x3e7e3cf2), X(0x3e9e8106),
741 X(0x3ebec497), X(0x3edf079b), X(0x3eff4a09), X(0x3f1f8bd7),
742 X(0x3f3fccfa), X(0x3f600d69), X(0x3f804d1a), X(0x3fa08c02),
743 X(0x3fc0ca19), X(0x3fe10753), X(0x400143a7), X(0x40217f0a),
744 X(0x4041b974), X(0x4061f2da), X(0x40822b32), X(0x40a26272),
745 X(0x40c29891), X(0x40e2cd83), X(0x41030140), X(0x412333bd),
746 X(0x414364f1), X(0x416394d2), X(0x4183c355), X(0x41a3f070),
747 X(0x41c41c1b), X(0x41e4464a), X(0x42046ef4), X(0x42249610),
748 X(0x4244bb92), X(0x4264df72), X(0x428501a5), X(0x42a52222),
749 X(0x42c540de), X(0x42e55dd0), X(0x430578ed), X(0x4325922d),
750 X(0x4345a985), X(0x4365beeb), X(0x4385d255), X(0x43a5e3ba),
751 X(0x43c5f30f), X(0x43e6004b), X(0x44060b65), X(0x44261451),
752 X(0x44461b07), X(0x44661f7c), X(0x448621a7), X(0x44a6217d),
753 X(0x44c61ef6), X(0x44e61a07), X(0x450612a6), X(0x452608ca),
754 X(0x4545fc69), X(0x4565ed79), X(0x4585dbf1), X(0x45a5c7c6),
755 X(0x45c5b0ef), X(0x45e59761), X(0x46057b15), X(0x46255bfe),
756 X(0x46453a15), X(0x4665154f), X(0x4684eda2), X(0x46a4c305),
757 X(0x46c4956e), X(0x46e464d3), X(0x4704312b), X(0x4723fa6c),
758 X(0x4743c08d), X(0x47638382), X(0x47834344), X(0x47a2ffc9),
759 X(0x47c2b906), X(0x47e26ef2), X(0x48022183), X(0x4821d0b1),
760 X(0x48417c71), X(0x486124b9), X(0x4880c981), X(0x48a06abe),
761 X(0x48c00867), X(0x48dfa272), X(0x48ff38d6), X(0x491ecb8a),
762 X(0x493e5a84), X(0x495de5b9), X(0x497d6d22), X(0x499cf0b4),
763 X(0x49bc7066), X(0x49dbec2e), X(0x49fb6402), X(0x4a1ad7db),
764 X(0x4a3a47ad), X(0x4a59b370), X(0x4a791b1a), X(0x4a987ea1),
765 X(0x4ab7ddfd), X(0x4ad73924), X(0x4af6900c), X(0x4b15e2ad),
766 X(0x4b3530fc), X(0x4b547af1), X(0x4b73c082), X(0x4b9301a6),
767 X(0x4bb23e53), X(0x4bd17681), X(0x4bf0aa25), X(0x4c0fd937),
768 X(0x4c2f03ae), X(0x4c4e297f), X(0x4c6d4aa3), X(0x4c8c670f),
769 X(0x4cab7eba), X(0x4cca919c), X(0x4ce99fab), X(0x4d08a8de),
770 X(0x4d27ad2c), X(0x4d46ac8b), X(0x4d65a6f3), X(0x4d849c5a),
771 X(0x4da38cb7), X(0x4dc27802), X(0x4de15e31), X(0x4e003f3a),
772 X(0x4e1f1b16), X(0x4e3df1ba), X(0x4e5cc31e), X(0x4e7b8f3a),
773 X(0x4e9a5603), X(0x4eb91771), X(0x4ed7d37b), X(0x4ef68a18),
774 X(0x4f153b3f), X(0x4f33e6e7), X(0x4f528d08), X(0x4f712d97),
775 X(0x4f8fc88e), X(0x4fae5de1), X(0x4fcced8a), X(0x4feb777f),
776 X(0x5009fbb6), X(0x50287a28), X(0x5046f2cc), X(0x50656598),
777 X(0x5083d284), X(0x50a23988), X(0x50c09a9a), X(0x50def5b1),
778 X(0x50fd4ac7), X(0x511b99d0), X(0x5139e2c5), X(0x5158259e),
779 X(0x51766251), X(0x519498d6), X(0x51b2c925), X(0x51d0f334),
780 X(0x51ef16fb), X(0x520d3473), X(0x522b4b91), X(0x52495c4e),
781 X(0x526766a2), X(0x52856a83), X(0x52a367e9), X(0x52c15ecd),
782 X(0x52df4f24), X(0x52fd38e8), X(0x531b1c10), X(0x5338f892),
783 X(0x5356ce68), X(0x53749d89), X(0x539265eb), X(0x53b02788),
784 X(0x53cde257), X(0x53eb964f), X(0x54094369), X(0x5426e99c),
785 X(0x544488df), X(0x5462212c), X(0x547fb279), X(0x549d3cbe),
786 X(0x54babff4), X(0x54d83c12), X(0x54f5b110), X(0x55131ee7),
787 X(0x5530858d), X(0x554de4fc), X(0x556b3d2a), X(0x55888e11),
788 X(0x55a5d7a8), X(0x55c319e7), X(0x55e054c7), X(0x55fd883f),
789 X(0x561ab447), X(0x5637d8d8), X(0x5654f5ea), X(0x56720b75),
790 X(0x568f1971), X(0x56ac1fd7), X(0x56c91e9e), X(0x56e615c0),
791 X(0x57030534), X(0x571fecf2), X(0x573cccf3), X(0x5759a530),
792 X(0x577675a0), X(0x57933e3c), X(0x57affefd), X(0x57ccb7db),
793 X(0x57e968ce), X(0x580611cf), X(0x5822b2d6), X(0x583f4bdd),
794 X(0x585bdcdb), X(0x587865c9), X(0x5894e69f), X(0x58b15f57),
795 X(0x58cdcfe9), X(0x58ea384e), X(0x5906987d), X(0x5922f071),
796 X(0x593f4022), X(0x595b8788), X(0x5977c69c), X(0x5993fd57),
797 X(0x59b02bb2), X(0x59cc51a6), X(0x59e86f2c), X(0x5a04843c),
798 X(0x5a2090d0), X(0x5a3c94e0), X(0x5a589065), X(0x5a748359),
799 X(0x5a906db4), X(0x5aac4f70), X(0x5ac82884), X(0x5ae3f8ec),
800 X(0x5affc09f), X(0x5b1b7f97), X(0x5b3735cd), X(0x5b52e33a),
801 X(0x5b6e87d8), X(0x5b8a239f), X(0x5ba5b689), X(0x5bc1408f),
802 X(0x5bdcc1aa), X(0x5bf839d5), X(0x5c13a907), X(0x5c2f0f3b),
803 X(0x5c4a6c6a), X(0x5c65c08d), X(0x5c810b9e), X(0x5c9c4d97),
804 X(0x5cb78670), X(0x5cd2b623), X(0x5ceddcaa), X(0x5d08f9ff),
805 X(0x5d240e1b), X(0x5d3f18f8), X(0x5d5a1a8f), X(0x5d7512da),
806 X(0x5d9001d3), X(0x5daae773), X(0x5dc5c3b5), X(0x5de09692),
807 X(0x5dfb6004), X(0x5e162004), X(0x5e30d68d), X(0x5e4b8399),
808 X(0x5e662721), X(0x5e80c11f), X(0x5e9b518e), X(0x5eb5d867),
809 X(0x5ed055a4), X(0x5eeac940), X(0x5f053334), X(0x5f1f937b),
810 X(0x5f39ea0f), X(0x5f5436ea), X(0x5f6e7a06), X(0x5f88b35d),
811 X(0x5fa2e2e9), X(0x5fbd08a6), X(0x5fd7248d), X(0x5ff13698),
812 X(0x600b3ec2), X(0x60253d05), X(0x603f315b), X(0x60591bc0),
813 X(0x6072fc2d), X(0x608cd29e), X(0x60a69f0b), X(0x60c06171),
814 X(0x60da19ca), X(0x60f3c80f), X(0x610d6c3d), X(0x6127064d),
815 X(0x6140963a), X(0x615a1bff), X(0x61739797), X(0x618d08fc),
816 X(0x61a67029), X(0x61bfcd1a), X(0x61d91fc8), X(0x61f2682f),
817 X(0x620ba64a), X(0x6224da13), X(0x623e0386), X(0x6257229d),
818 X(0x62703754), X(0x628941a6), X(0x62a2418e), X(0x62bb3706),
819 X(0x62d4220a), X(0x62ed0296), X(0x6305d8a3), X(0x631ea42f),
820 X(0x63376533), X(0x63501bab), X(0x6368c793), X(0x638168e5),
821 X(0x6399ff9e), X(0x63b28bb8), X(0x63cb0d2f), X(0x63e383ff),
822 X(0x63fbf022), X(0x64145195), X(0x642ca853), X(0x6444f457),
823 X(0x645d359e), X(0x64756c22), X(0x648d97e0), X(0x64a5b8d3),
824 X(0x64bdcef6), X(0x64d5da47), X(0x64eddabf), X(0x6505d05c),
825 X(0x651dbb19), X(0x65359af2), X(0x654d6fe3), X(0x656539e7),
826 X(0x657cf8fb), X(0x6594ad1b), X(0x65ac5643), X(0x65c3f46e),
827 X(0x65db8799), X(0x65f30fc0), X(0x660a8ce0), X(0x6621fef3),
828 X(0x663965f7), X(0x6650c1e7), X(0x666812c1), X(0x667f5880),
829 X(0x66969320), X(0x66adc29e), X(0x66c4e6f7), X(0x66dc0026),
830 X(0x66f30e28), X(0x670a10fa), X(0x67210898), X(0x6737f4ff),
831 X(0x674ed62b), X(0x6765ac19), X(0x677c76c5), X(0x6793362c),
832 X(0x67a9ea4b), X(0x67c0931f), X(0x67d730a3), X(0x67edc2d6),
833 X(0x680449b3), X(0x681ac538), X(0x68313562), X(0x68479a2d),
834 X(0x685df396), X(0x6874419b), X(0x688a8438), X(0x68a0bb6a),
835 X(0x68b6e72e), X(0x68cd0782), X(0x68e31c63), X(0x68f925cd),
836 X(0x690f23be), X(0x69251633), X(0x693afd29), X(0x6950d89e),
837 X(0x6966a88f), X(0x697c6cf8), X(0x699225d9), X(0x69a7d32d),
838 X(0x69bd74f3), X(0x69d30b27), X(0x69e895c8), X(0x69fe14d2),
839 X(0x6a138844), X(0x6a28f01b), X(0x6a3e4c54), X(0x6a539ced),
840 X(0x6a68e1e4), X(0x6a7e1b37), X(0x6a9348e3), X(0x6aa86ae6),
841 X(0x6abd813d), X(0x6ad28be7), X(0x6ae78ae2), X(0x6afc7e2b),
842 X(0x6b1165c0), X(0x6b26419f), X(0x6b3b11c7), X(0x6b4fd634),
843 X(0x6b648ee6), X(0x6b793bda), X(0x6b8ddd0e), X(0x6ba27281),
844 X(0x6bb6fc31), X(0x6bcb7a1b), X(0x6bdfec3e), X(0x6bf45299),
845 X(0x6c08ad29), X(0x6c1cfbed), X(0x6c313ee4), X(0x6c45760a),
846 X(0x6c59a160), X(0x6c6dc0e4), X(0x6c81d493), X(0x6c95dc6d),
847 X(0x6ca9d86f), X(0x6cbdc899), X(0x6cd1acea), X(0x6ce5855f),
848 X(0x6cf951f7), X(0x6d0d12b1), X(0x6d20c78c), X(0x6d347087),
849 X(0x6d480da0), X(0x6d5b9ed6), X(0x6d6f2427), X(0x6d829d94),
850 X(0x6d960b1a), X(0x6da96cb9), X(0x6dbcc270), X(0x6dd00c3c),
851 X(0x6de34a1f), X(0x6df67c16), X(0x6e09a221), X(0x6e1cbc3f),
852 X(0x6e2fca6e), X(0x6e42ccaf), X(0x6e55c300), X(0x6e68ad60),
853 X(0x6e7b8bd0), X(0x6e8e5e4d), X(0x6ea124d8), X(0x6eb3df70),
854 X(0x6ec68e13), X(0x6ed930c3), X(0x6eebc77d), X(0x6efe5242),
855 X(0x6f10d111), X(0x6f2343e9), X(0x6f35aacb), X(0x6f4805b5),
856 X(0x6f5a54a8), X(0x6f6c97a2), X(0x6f7ecea4), X(0x6f90f9ae),
857 X(0x6fa318be), X(0x6fb52bd6), X(0x6fc732f4), X(0x6fd92e19),
858 X(0x6feb1d44), X(0x6ffd0076), X(0x700ed7ad), X(0x7020a2eb),
859 X(0x7032622f), X(0x7044157a), X(0x7055bcca), X(0x70675821),
860 X(0x7078e77e), X(0x708a6ae2), X(0x709be24c), X(0x70ad4dbd),
861 X(0x70bead36), X(0x70d000b5), X(0x70e1483d), X(0x70f283cc),
862 X(0x7103b363), X(0x7114d704), X(0x7125eead), X(0x7136fa60),
863 X(0x7147fa1c), X(0x7158ede4), X(0x7169d5b6), X(0x717ab193),
864 X(0x718b817d), X(0x719c4573), X(0x71acfd76), X(0x71bda988),
865 X(0x71ce49a8), X(0x71deddd7), X(0x71ef6617), X(0x71ffe267),
866 X(0x721052ca), X(0x7220b73e), X(0x72310fc6), X(0x72415c62),
867 X(0x72519d14), X(0x7261d1db), X(0x7271faba), X(0x728217b1),
868 X(0x729228c0), X(0x72a22dea), X(0x72b22730), X(0x72c21491),
869 X(0x72d1f611), X(0x72e1cbaf), X(0x72f1956c), X(0x7301534c),
870 X(0x7311054d), X(0x7320ab72), X(0x733045bc), X(0x733fd42d),
871 X(0x734f56c5), X(0x735ecd86), X(0x736e3872), X(0x737d9789),
872 X(0x738ceacf), X(0x739c3243), X(0x73ab6de7), X(0x73ba9dbe),
873 X(0x73c9c1c8), X(0x73d8da08), X(0x73e7e67f), X(0x73f6e72e),
874 X(0x7405dc17), X(0x7414c53c), X(0x7423a29f), X(0x74327442),
875 X(0x74413a26), X(0x744ff44d), X(0x745ea2b9), X(0x746d456c),
876 X(0x747bdc68), X(0x748a67ae), X(0x7498e741), X(0x74a75b23),
877 X(0x74b5c356), X(0x74c41fdb), X(0x74d270b6), X(0x74e0b5e7),
878 X(0x74eeef71), X(0x74fd1d57), X(0x750b3f9a), X(0x7519563c),
879 X(0x75276140), X(0x753560a8), X(0x75435477), X(0x75513cae),
880 X(0x755f1951), X(0x756cea60), X(0x757aafdf), X(0x758869d1),
881 X(0x75961837), X(0x75a3bb14), X(0x75b1526a), X(0x75bede3c),
882 X(0x75cc5e8d), X(0x75d9d35f), X(0x75e73cb5), X(0x75f49a91),
883 X(0x7601ecf6), X(0x760f33e6), X(0x761c6f65), X(0x76299f74),
884 X(0x7636c417), X(0x7643dd51), X(0x7650eb24), X(0x765ded93),
885 X(0x766ae4a0), X(0x7677d050), X(0x7684b0a4), X(0x7691859f),
886 X(0x769e4f45), X(0x76ab0d98), X(0x76b7c09c), X(0x76c46852),
887 X(0x76d104bf), X(0x76dd95e6), X(0x76ea1bc9), X(0x76f6966b),
888 X(0x770305d0), X(0x770f69fb), X(0x771bc2ef), X(0x772810af),
889 X(0x7734533e), X(0x77408aa0), X(0x774cb6d7), X(0x7758d7e8),
890 X(0x7764edd5), X(0x7770f8a2), X(0x777cf852), X(0x7788ece8),
891 X(0x7794d668), X(0x77a0b4d5), X(0x77ac8833), X(0x77b85085),
892 X(0x77c40dce), X(0x77cfc013), X(0x77db6756), X(0x77e7039b),
893 X(0x77f294e6), X(0x77fe1b3b), X(0x7809969c), X(0x7815070e),
894 X(0x78206c93), X(0x782bc731), X(0x783716ea), X(0x78425bc3),
895 X(0x784d95be), X(0x7858c4e1), X(0x7863e92d), X(0x786f02a8),
896 X(0x787a1156), X(0x78851539), X(0x78900e56), X(0x789afcb1),
897 X(0x78a5e04d), X(0x78b0b92f), X(0x78bb875b), X(0x78c64ad4),
898 X(0x78d1039e), X(0x78dbb1be), X(0x78e65537), X(0x78f0ee0e),
899 X(0x78fb7c46), X(0x7905ffe4), X(0x791078ec), X(0x791ae762),
900 X(0x79254b4a), X(0x792fa4a7), X(0x7939f380), X(0x794437d7),
901 X(0x794e71b0), X(0x7958a111), X(0x7962c5fd), X(0x796ce078),
902 X(0x7976f087), X(0x7980f62f), X(0x798af173), X(0x7994e258),
903 X(0x799ec8e2), X(0x79a8a515), X(0x79b276f7), X(0x79bc3e8b),
904 X(0x79c5fbd6), X(0x79cfaedc), X(0x79d957a2), X(0x79e2f62c),
905 X(0x79ec8a7f), X(0x79f6149f), X(0x79ff9492), X(0x7a090a5a),
906 X(0x7a1275fe), X(0x7a1bd781), X(0x7a252ee9), X(0x7a2e7c39),
907 X(0x7a37bf77), X(0x7a40f8a7), X(0x7a4a27ce), X(0x7a534cf0),
908 X(0x7a5c6813), X(0x7a65793b), X(0x7a6e806d), X(0x7a777dad),
909 X(0x7a807100), X(0x7a895a6b), X(0x7a9239f4), X(0x7a9b0f9e),
910 X(0x7aa3db6f), X(0x7aac9d6b), X(0x7ab55597), X(0x7abe03f9),
911 X(0x7ac6a895), X(0x7acf4370), X(0x7ad7d48f), X(0x7ae05bf6),
912 X(0x7ae8d9ac), X(0x7af14db5), X(0x7af9b815), X(0x7b0218d2),
913 X(0x7b0a6ff2), X(0x7b12bd78), X(0x7b1b016a), X(0x7b233bce),
914 X(0x7b2b6ca7), X(0x7b3393fc), X(0x7b3bb1d1), X(0x7b43c62c),
915 X(0x7b4bd111), X(0x7b53d286), X(0x7b5bca90), X(0x7b63b935),
916 X(0x7b6b9e78), X(0x7b737a61), X(0x7b7b4cf3), X(0x7b831634),
917 X(0x7b8ad629), X(0x7b928cd8), X(0x7b9a3a45), X(0x7ba1de77),
918 X(0x7ba97972), X(0x7bb10b3c), X(0x7bb893d9), X(0x7bc01350),
919 X(0x7bc789a6), X(0x7bcef6e0), X(0x7bd65b03), X(0x7bddb616),
920 X(0x7be5081c), X(0x7bec511c), X(0x7bf3911b), X(0x7bfac81f),
921 X(0x7c01f62c), X(0x7c091b49), X(0x7c10377b), X(0x7c174ac7),
922 X(0x7c1e5532), X(0x7c2556c4), X(0x7c2c4f80), X(0x7c333f6c),
923 X(0x7c3a268e), X(0x7c4104ec), X(0x7c47da8a), X(0x7c4ea76f),
924 X(0x7c556ba1), X(0x7c5c2724), X(0x7c62d9fe), X(0x7c698435),
925 X(0x7c7025cf), X(0x7c76bed0), X(0x7c7d4f40), X(0x7c83d723),
926 X(0x7c8a567f), X(0x7c90cd5a), X(0x7c973bb9), X(0x7c9da1a2),
927 X(0x7ca3ff1b), X(0x7caa542a), X(0x7cb0a0d3), X(0x7cb6e51e),
928 X(0x7cbd210f), X(0x7cc354ac), X(0x7cc97ffc), X(0x7ccfa304),
929 X(0x7cd5bdc9), X(0x7cdbd051), X(0x7ce1daa3), X(0x7ce7dcc3),
930 X(0x7cedd6b8), X(0x7cf3c888), X(0x7cf9b238), X(0x7cff93cf),
931 X(0x7d056d51), X(0x7d0b3ec5), X(0x7d110830), X(0x7d16c99a),
932 X(0x7d1c8306), X(0x7d22347c), X(0x7d27de00), X(0x7d2d7f9a),
933 X(0x7d33194f), X(0x7d38ab24), X(0x7d3e351f), X(0x7d43b748),
934 X(0x7d4931a2), X(0x7d4ea435), X(0x7d540f06), X(0x7d59721b),
935 X(0x7d5ecd7b), X(0x7d64212a), X(0x7d696d2f), X(0x7d6eb190),
936 X(0x7d73ee53), X(0x7d79237e), X(0x7d7e5117), X(0x7d837723),
937 X(0x7d8895a9), X(0x7d8dacae), X(0x7d92bc3a), X(0x7d97c451),
938 X(0x7d9cc4f9), X(0x7da1be39), X(0x7da6b017), X(0x7dab9a99),
939 X(0x7db07dc4), X(0x7db5599e), X(0x7dba2e2f), X(0x7dbefb7b),
940 X(0x7dc3c189), X(0x7dc8805e), X(0x7dcd3802), X(0x7dd1e879),
941 X(0x7dd691ca), X(0x7ddb33fb), X(0x7ddfcf12), X(0x7de46315),
942 X(0x7de8f00a), X(0x7ded75f8), X(0x7df1f4e3), X(0x7df66cd3),
943 X(0x7dfaddcd), X(0x7dff47d7), X(0x7e03aaf8), X(0x7e080735),
944 X(0x7e0c5c95), X(0x7e10ab1e), X(0x7e14f2d5), X(0x7e1933c1),
945 X(0x7e1d6de8), X(0x7e21a150), X(0x7e25cdff), X(0x7e29f3fc),
946 X(0x7e2e134c), X(0x7e322bf5), X(0x7e363dfd), X(0x7e3a496b),
947 X(0x7e3e4e45), X(0x7e424c90), X(0x7e464454), X(0x7e4a3595),
948 X(0x7e4e205a), X(0x7e5204aa), X(0x7e55e289), X(0x7e59b9ff),
949 X(0x7e5d8b12), X(0x7e6155c7), X(0x7e651a24), X(0x7e68d831),
950 X(0x7e6c8ff2), X(0x7e70416e), X(0x7e73ecac), X(0x7e7791b0),
951 X(0x7e7b3082), X(0x7e7ec927), X(0x7e825ba6), X(0x7e85e804),
952 X(0x7e896e48), X(0x7e8cee77), X(0x7e906899), X(0x7e93dcb2),
953 X(0x7e974aca), X(0x7e9ab2e5), X(0x7e9e150b), X(0x7ea17141),
954 X(0x7ea4c78e), X(0x7ea817f7), X(0x7eab6283), X(0x7eaea737),
955 X(0x7eb1e61a), X(0x7eb51f33), X(0x7eb85285), X(0x7ebb8019),
956 X(0x7ebea7f4), X(0x7ec1ca1d), X(0x7ec4e698), X(0x7ec7fd6d),
957 X(0x7ecb0ea1), X(0x7ece1a3a), X(0x7ed1203f), X(0x7ed420b6),
958 X(0x7ed71ba4), X(0x7eda110f), X(0x7edd00ff), X(0x7edfeb78),
959 X(0x7ee2d081), X(0x7ee5b01f), X(0x7ee88a5a), X(0x7eeb5f36),
960 X(0x7eee2eba), X(0x7ef0f8ed), X(0x7ef3bdd3), X(0x7ef67d73),
961 X(0x7ef937d3), X(0x7efbecf9), X(0x7efe9ceb), X(0x7f0147ae),
962 X(0x7f03ed4a), X(0x7f068dc4), X(0x7f092922), X(0x7f0bbf69),
963 X(0x7f0e50a1), X(0x7f10dcce), X(0x7f1363f7), X(0x7f15e622),
964 X(0x7f186355), X(0x7f1adb95), X(0x7f1d4ee9), X(0x7f1fbd57),
965 X(0x7f2226e4), X(0x7f248b96), X(0x7f26eb74), X(0x7f294683),
966 X(0x7f2b9cc9), X(0x7f2dee4d), X(0x7f303b13), X(0x7f328322),
967 X(0x7f34c680), X(0x7f370533), X(0x7f393f40), X(0x7f3b74ad),
968 X(0x7f3da581), X(0x7f3fd1c1), X(0x7f41f972), X(0x7f441c9c),
969 X(0x7f463b43), X(0x7f48556d), X(0x7f4a6b21), X(0x7f4c7c64),
970 X(0x7f4e893c), X(0x7f5091ae), X(0x7f5295c1), X(0x7f54957a),
971 X(0x7f5690e0), X(0x7f5887f7), X(0x7f5a7ac5), X(0x7f5c6951),
972 X(0x7f5e53a0), X(0x7f6039b8), X(0x7f621b9e), X(0x7f63f958),
973 X(0x7f65d2ed), X(0x7f67a861), X(0x7f6979ba), X(0x7f6b46ff),
974 X(0x7f6d1034), X(0x7f6ed560), X(0x7f709687), X(0x7f7253b1),
975 X(0x7f740ce1), X(0x7f75c21f), X(0x7f777370), X(0x7f7920d8),
976 X(0x7f7aca5f), X(0x7f7c7008), X(0x7f7e11db), X(0x7f7fafdd),
977 X(0x7f814a13), X(0x7f82e082), X(0x7f847331), X(0x7f860224),
978 X(0x7f878d62), X(0x7f8914f0), X(0x7f8a98d4), X(0x7f8c1912),
979 X(0x7f8d95b0), X(0x7f8f0eb5), X(0x7f908425), X(0x7f91f605),
980 X(0x7f93645c), X(0x7f94cf2f), X(0x7f963683), X(0x7f979a5d),
981 X(0x7f98fac4), X(0x7f9a57bb), X(0x7f9bb14a), X(0x7f9d0775),
982 X(0x7f9e5a41), X(0x7f9fa9b4), X(0x7fa0f5d3), X(0x7fa23ea4),
983 X(0x7fa3842b), X(0x7fa4c66f), X(0x7fa60575), X(0x7fa74141),
984 X(0x7fa879d9), X(0x7fa9af42), X(0x7faae182), X(0x7fac109e),
985 X(0x7fad3c9a), X(0x7fae657d), X(0x7faf8b4c), X(0x7fb0ae0b),
986 X(0x7fb1cdc0), X(0x7fb2ea70), X(0x7fb40420), X(0x7fb51ad5),
987 X(0x7fb62e95), X(0x7fb73f64), X(0x7fb84d48), X(0x7fb95846),
988 X(0x7fba6062), X(0x7fbb65a2), X(0x7fbc680c), X(0x7fbd67a3),
989 X(0x7fbe646d), X(0x7fbf5e70), X(0x7fc055af), X(0x7fc14a31),
990 X(0x7fc23bf9), X(0x7fc32b0d), X(0x7fc41773), X(0x7fc5012e),
991 X(0x7fc5e844), X(0x7fc6ccba), X(0x7fc7ae94), X(0x7fc88dd8),
992 X(0x7fc96a8a), X(0x7fca44af), X(0x7fcb1c4c), X(0x7fcbf167),
993 X(0x7fccc403), X(0x7fcd9425), X(0x7fce61d3), X(0x7fcf2d11),
994 X(0x7fcff5e3), X(0x7fd0bc4f), X(0x7fd1805a), X(0x7fd24207),
995 X(0x7fd3015c), X(0x7fd3be5d), X(0x7fd47910), X(0x7fd53178),
996 X(0x7fd5e79b), X(0x7fd69b7c), X(0x7fd74d21), X(0x7fd7fc8e),
997 X(0x7fd8a9c8), X(0x7fd954d4), X(0x7fd9fdb5), X(0x7fdaa471),
998 X(0x7fdb490b), X(0x7fdbeb89), X(0x7fdc8bef), X(0x7fdd2a42),
999 X(0x7fddc685), X(0x7fde60be), X(0x7fdef8f0), X(0x7fdf8f20),
1000 X(0x7fe02353), X(0x7fe0b58d), X(0x7fe145d3), X(0x7fe1d428),
1001 X(0x7fe26091), X(0x7fe2eb12), X(0x7fe373b0), X(0x7fe3fa6f),
1002 X(0x7fe47f53), X(0x7fe50260), X(0x7fe5839b), X(0x7fe60308),
1003 X(0x7fe680ab), X(0x7fe6fc88), X(0x7fe776a4), X(0x7fe7ef02),
1004 X(0x7fe865a7), X(0x7fe8da97), X(0x7fe94dd6), X(0x7fe9bf68),
1005 X(0x7fea2f51), X(0x7fea9d95), X(0x7feb0a39), X(0x7feb7540),
1006 X(0x7febdeae), X(0x7fec4687), X(0x7fecaccf), X(0x7fed118b),
1007 X(0x7fed74be), X(0x7fedd66c), X(0x7fee3698), X(0x7fee9548),
1008 X(0x7feef27e), X(0x7fef4e3f), X(0x7fefa88e), X(0x7ff0016f),
1009 X(0x7ff058e7), X(0x7ff0aef8), X(0x7ff103a6), X(0x7ff156f6),
1010 X(0x7ff1a8eb), X(0x7ff1f988), X(0x7ff248d2), X(0x7ff296cc),
1011 X(0x7ff2e37a), X(0x7ff32edf), X(0x7ff378ff), X(0x7ff3c1de),
1012 X(0x7ff4097e), X(0x7ff44fe5), X(0x7ff49515), X(0x7ff4d911),
1013 X(0x7ff51bde), X(0x7ff55d7f), X(0x7ff59df7), X(0x7ff5dd4a),
1014 X(0x7ff61b7b), X(0x7ff6588d), X(0x7ff69485), X(0x7ff6cf65),
1015 X(0x7ff70930), X(0x7ff741eb), X(0x7ff77998), X(0x7ff7b03b),
1016 X(0x7ff7e5d7), X(0x7ff81a6f), X(0x7ff84e06), X(0x7ff880a1),
1017 X(0x7ff8b241), X(0x7ff8e2ea), X(0x7ff912a0), X(0x7ff94165),
1018 X(0x7ff96f3d), X(0x7ff99c2b), X(0x7ff9c831), X(0x7ff9f354),
1019 X(0x7ffa1d95), X(0x7ffa46f9), X(0x7ffa6f81), X(0x7ffa9731),
1020 X(0x7ffabe0d), X(0x7ffae416), X(0x7ffb0951), X(0x7ffb2dbf),
1021 X(0x7ffb5164), X(0x7ffb7442), X(0x7ffb965d), X(0x7ffbb7b8),
1022 X(0x7ffbd854), X(0x7ffbf836), X(0x7ffc175f), X(0x7ffc35d3),
1023 X(0x7ffc5394), X(0x7ffc70a5), X(0x7ffc8d09), X(0x7ffca8c2),
1024 X(0x7ffcc3d4), X(0x7ffcde3f), X(0x7ffcf809), X(0x7ffd1132),
1025 X(0x7ffd29be), X(0x7ffd41ae), X(0x7ffd5907), X(0x7ffd6fc9),
1026 X(0x7ffd85f9), X(0x7ffd9b97), X(0x7ffdb0a7), X(0x7ffdc52b),
1027 X(0x7ffdd926), X(0x7ffdec99), X(0x7ffdff88), X(0x7ffe11f4),
1028 X(0x7ffe23e0), X(0x7ffe354f), X(0x7ffe4642), X(0x7ffe56bc),
1029 X(0x7ffe66bf), X(0x7ffe764e), X(0x7ffe856a), X(0x7ffe9416),
1030 X(0x7ffea254), X(0x7ffeb026), X(0x7ffebd8e), X(0x7ffeca8f),
1031 X(0x7ffed72a), X(0x7ffee362), X(0x7ffeef38), X(0x7ffefaaf),
1032 X(0x7fff05c9), X(0x7fff1087), X(0x7fff1aec), X(0x7fff24f9),
1033 X(0x7fff2eb1), X(0x7fff3816), X(0x7fff4128), X(0x7fff49eb),
1034 X(0x7fff5260), X(0x7fff5a88), X(0x7fff6266), X(0x7fff69fc),
1035 X(0x7fff714b), X(0x7fff7854), X(0x7fff7f1a), X(0x7fff859f),
1036 X(0x7fff8be3), X(0x7fff91ea), X(0x7fff97b3), X(0x7fff9d41),
1037 X(0x7fffa296), X(0x7fffa7b3), X(0x7fffac99), X(0x7fffb14b),
1038 X(0x7fffb5c9), X(0x7fffba15), X(0x7fffbe31), X(0x7fffc21d),
1039 X(0x7fffc5dc), X(0x7fffc96f), X(0x7fffccd8), X(0x7fffd016),
1040 X(0x7fffd32d), X(0x7fffd61c), X(0x7fffd8e7), X(0x7fffdb8d),
1041 X(0x7fffde0f), X(0x7fffe071), X(0x7fffe2b1), X(0x7fffe4d2),
1042 X(0x7fffe6d5), X(0x7fffe8bb), X(0x7fffea85), X(0x7fffec34),
1043 X(0x7fffedc9), X(0x7fffef45), X(0x7ffff0aa), X(0x7ffff1f7),
1044 X(0x7ffff330), X(0x7ffff453), X(0x7ffff562), X(0x7ffff65f),
1045 X(0x7ffff749), X(0x7ffff823), X(0x7ffff8ec), X(0x7ffff9a6),
1046 X(0x7ffffa51), X(0x7ffffaee), X(0x7ffffb7e), X(0x7ffffc02),
1047 X(0x7ffffc7a), X(0x7ffffce7), X(0x7ffffd4a), X(0x7ffffda3),
1048 X(0x7ffffdf4), X(0x7ffffe3c), X(0x7ffffe7c), X(0x7ffffeb6),
1049 X(0x7ffffee8), X(0x7fffff15), X(0x7fffff3c), X(0x7fffff5e),
1050 X(0x7fffff7b), X(0x7fffff95), X(0x7fffffaa), X(0x7fffffbc),
1051 X(0x7fffffcb), X(0x7fffffd7), X(0x7fffffe2), X(0x7fffffea),
1052 X(0x7ffffff0), X(0x7ffffff5), X(0x7ffffff9), X(0x7ffffffb),
1053 X(0x7ffffffd), X(0x7ffffffe), X(0x7fffffff), X(0x7fffffff),
1054 X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff),
1055 };
1056
1057 static const LOOKUP_T vwin8192[4096] = {
1058 X(0x0000007c), X(0x0000045c), X(0x00000c1d), X(0x000017bd),
1059 X(0x0000273e), X(0x00003a9f), X(0x000051e0), X(0x00006d02),
1060 X(0x00008c03), X(0x0000aee5), X(0x0000d5a7), X(0x00010049),
1061 X(0x00012ecb), X(0x0001612d), X(0x00019770), X(0x0001d193),
1062 X(0x00020f96), X(0x00025178), X(0x0002973c), X(0x0002e0df),
1063 X(0x00032e62), X(0x00037fc5), X(0x0003d509), X(0x00042e2c),
1064 X(0x00048b30), X(0x0004ec13), X(0x000550d7), X(0x0005b97a),
1065 X(0x000625fe), X(0x00069661), X(0x00070aa4), X(0x000782c8),
1066 X(0x0007fecb), X(0x00087eae), X(0x00090271), X(0x00098a14),
1067 X(0x000a1597), X(0x000aa4f9), X(0x000b383b), X(0x000bcf5d),
1068 X(0x000c6a5f), X(0x000d0941), X(0x000dac02), X(0x000e52a3),
1069 X(0x000efd23), X(0x000fab84), X(0x00105dc3), X(0x001113e3),
1070 X(0x0011cde2), X(0x00128bc0), X(0x00134d7e), X(0x0014131b),
1071 X(0x0014dc98), X(0x0015a9f4), X(0x00167b30), X(0x0017504a),
1072 X(0x00182945), X(0x0019061e), X(0x0019e6d7), X(0x001acb6f),
1073 X(0x001bb3e6), X(0x001ca03c), X(0x001d9071), X(0x001e8485),
1074 X(0x001f7c79), X(0x0020784b), X(0x002177fc), X(0x00227b8c),
1075 X(0x002382fb), X(0x00248e49), X(0x00259d76), X(0x0026b081),
1076 X(0x0027c76b), X(0x0028e234), X(0x002a00dc), X(0x002b2361),
1077 X(0x002c49c6), X(0x002d7409), X(0x002ea22a), X(0x002fd42a),
1078 X(0x00310a08), X(0x003243c5), X(0x00338160), X(0x0034c2d9),
1079 X(0x00360830), X(0x00375165), X(0x00389e78), X(0x0039ef6a),
1080 X(0x003b4439), X(0x003c9ce6), X(0x003df971), X(0x003f59da),
1081 X(0x0040be20), X(0x00422645), X(0x00439247), X(0x00450226),
1082 X(0x004675e3), X(0x0047ed7e), X(0x004968f5), X(0x004ae84b),
1083 X(0x004c6b7d), X(0x004df28d), X(0x004f7d7a), X(0x00510c44),
1084 X(0x00529eeb), X(0x00543570), X(0x0055cfd1), X(0x00576e0f),
1085 X(0x00591029), X(0x005ab621), X(0x005c5ff5), X(0x005e0da6),
1086 X(0x005fbf33), X(0x0061749d), X(0x00632de4), X(0x0064eb06),
1087 X(0x0066ac05), X(0x006870e0), X(0x006a3998), X(0x006c062b),
1088 X(0x006dd69b), X(0x006faae6), X(0x0071830d), X(0x00735f10),
1089 X(0x00753eef), X(0x007722a9), X(0x00790a3f), X(0x007af5b1),
1090 X(0x007ce4fe), X(0x007ed826), X(0x0080cf29), X(0x0082ca08),
1091 X(0x0084c8c2), X(0x0086cb57), X(0x0088d1c7), X(0x008adc11),
1092 X(0x008cea37), X(0x008efc37), X(0x00911212), X(0x00932bc7),
1093 X(0x00954957), X(0x00976ac2), X(0x00999006), X(0x009bb925),
1094 X(0x009de61e), X(0x00a016f1), X(0x00a24b9e), X(0x00a48425),
1095 X(0x00a6c086), X(0x00a900c0), X(0x00ab44d4), X(0x00ad8cc2),
1096 X(0x00afd889), X(0x00b22829), X(0x00b47ba2), X(0x00b6d2f5),
1097 X(0x00b92e21), X(0x00bb8d26), X(0x00bdf004), X(0x00c056ba),
1098 X(0x00c2c149), X(0x00c52fb1), X(0x00c7a1f1), X(0x00ca180a),
1099 X(0x00cc91fb), X(0x00cf0fc5), X(0x00d19166), X(0x00d416df),
1100 X(0x00d6a031), X(0x00d92d5a), X(0x00dbbe5b), X(0x00de5333),
1101 X(0x00e0ebe3), X(0x00e3886b), X(0x00e628c9), X(0x00e8ccff),
1102 X(0x00eb750c), X(0x00ee20f0), X(0x00f0d0ab), X(0x00f3843d),
1103 X(0x00f63ba5), X(0x00f8f6e4), X(0x00fbb5fa), X(0x00fe78e5),
1104 X(0x01013fa7), X(0x01040a3f), X(0x0106d8ae), X(0x0109aaf2),
1105 X(0x010c810c), X(0x010f5afb), X(0x011238c0), X(0x01151a5b),
1106 X(0x0117ffcb), X(0x011ae910), X(0x011dd62a), X(0x0120c719),
1107 X(0x0123bbdd), X(0x0126b476), X(0x0129b0e4), X(0x012cb126),
1108 X(0x012fb53c), X(0x0132bd27), X(0x0135c8e6), X(0x0138d879),
1109 X(0x013bebdf), X(0x013f031a), X(0x01421e28), X(0x01453d0a),
1110 X(0x01485fbf), X(0x014b8648), X(0x014eb0a4), X(0x0151ded2),
1111 X(0x015510d4), X(0x015846a8), X(0x015b8050), X(0x015ebdc9),
1112 X(0x0161ff15), X(0x01654434), X(0x01688d24), X(0x016bd9e6),
1113 X(0x016f2a7b), X(0x01727ee1), X(0x0175d718), X(0x01793321),
1114 X(0x017c92fc), X(0x017ff6a7), X(0x01835e24), X(0x0186c972),
1115 X(0x018a3890), X(0x018dab7f), X(0x0191223f), X(0x01949ccf),
1116 X(0x01981b2f), X(0x019b9d5f), X(0x019f235f), X(0x01a2ad2f),
1117 X(0x01a63acf), X(0x01a9cc3e), X(0x01ad617c), X(0x01b0fa8a),
1118 X(0x01b49767), X(0x01b83813), X(0x01bbdc8d), X(0x01bf84d6),
1119 X(0x01c330ee), X(0x01c6e0d4), X(0x01ca9488), X(0x01ce4c0b),
1120 X(0x01d2075b), X(0x01d5c679), X(0x01d98964), X(0x01dd501d),
1121 X(0x01e11aa3), X(0x01e4e8f6), X(0x01e8bb17), X(0x01ec9104),
1122 X(0x01f06abd), X(0x01f44844), X(0x01f82996), X(0x01fc0eb5),
1123 X(0x01fff7a0), X(0x0203e456), X(0x0207d4d9), X(0x020bc926),
1124 X(0x020fc140), X(0x0213bd24), X(0x0217bcd4), X(0x021bc04e),
1125 X(0x021fc793), X(0x0223d2a3), X(0x0227e17d), X(0x022bf421),
1126 X(0x02300a90), X(0x023424c8), X(0x023842ca), X(0x023c6495),
1127 X(0x02408a2a), X(0x0244b389), X(0x0248e0b0), X(0x024d11a0),
1128 X(0x02514659), X(0x02557eda), X(0x0259bb24), X(0x025dfb35),
1129 X(0x02623f0f), X(0x026686b1), X(0x026ad21a), X(0x026f214b),
1130 X(0x02737443), X(0x0277cb02), X(0x027c2588), X(0x028083d5),
1131 X(0x0284e5e9), X(0x02894bc2), X(0x028db562), X(0x029222c8),
1132 X(0x029693f4), X(0x029b08e6), X(0x029f819d), X(0x02a3fe19),
1133 X(0x02a87e5b), X(0x02ad0261), X(0x02b18a2c), X(0x02b615bb),
1134 X(0x02baa50f), X(0x02bf3827), X(0x02c3cf03), X(0x02c869a3),
1135 X(0x02cd0807), X(0x02d1aa2d), X(0x02d65017), X(0x02daf9c4),
1136 X(0x02dfa734), X(0x02e45866), X(0x02e90d5b), X(0x02edc612),
1137 X(0x02f2828b), X(0x02f742c6), X(0x02fc06c3), X(0x0300ce80),
1138 X(0x030599ff), X(0x030a6940), X(0x030f3c40), X(0x03141302),
1139 X(0x0318ed84), X(0x031dcbc6), X(0x0322adc8), X(0x0327938a),
1140 X(0x032c7d0c), X(0x03316a4c), X(0x03365b4d), X(0x033b500c),
1141 X(0x03404889), X(0x034544c6), X(0x034a44c0), X(0x034f4879),
1142 X(0x03544ff0), X(0x03595b24), X(0x035e6a16), X(0x03637cc5),
1143 X(0x03689331), X(0x036dad5a), X(0x0372cb40), X(0x0377ece2),
1144 X(0x037d1240), X(0x03823b5a), X(0x03876830), X(0x038c98c1),
1145 X(0x0391cd0e), X(0x03970516), X(0x039c40d8), X(0x03a18055),
1146 X(0x03a6c38d), X(0x03ac0a7f), X(0x03b1552b), X(0x03b6a390),
1147 X(0x03bbf5af), X(0x03c14b88), X(0x03c6a519), X(0x03cc0263),
1148 X(0x03d16366), X(0x03d6c821), X(0x03dc3094), X(0x03e19cc0),
1149 X(0x03e70ca2), X(0x03ec803d), X(0x03f1f78e), X(0x03f77296),
1150 X(0x03fcf155), X(0x040273cb), X(0x0407f9f7), X(0x040d83d9),
1151 X(0x04131170), X(0x0418a2bd), X(0x041e37c0), X(0x0423d077),
1152 X(0x04296ce4), X(0x042f0d04), X(0x0434b0da), X(0x043a5863),
1153 X(0x044003a0), X(0x0445b290), X(0x044b6534), X(0x04511b8b),
1154 X(0x0456d595), X(0x045c9352), X(0x046254c1), X(0x046819e1),
1155 X(0x046de2b4), X(0x0473af39), X(0x04797f6e), X(0x047f5355),
1156 X(0x04852aec), X(0x048b0635), X(0x0490e52d), X(0x0496c7d6),
1157 X(0x049cae2e), X(0x04a29836), X(0x04a885ed), X(0x04ae7753),
1158 X(0x04b46c68), X(0x04ba652b), X(0x04c0619d), X(0x04c661bc),
1159 X(0x04cc658a), X(0x04d26d04), X(0x04d8782c), X(0x04de8701),
1160 X(0x04e49983), X(0x04eaafb0), X(0x04f0c98a), X(0x04f6e710),
1161 X(0x04fd0842), X(0x05032d1e), X(0x050955a6), X(0x050f81d8),
1162 X(0x0515b1b5), X(0x051be53d), X(0x05221c6e), X(0x05285748),
1163 X(0x052e95cd), X(0x0534d7fa), X(0x053b1dd0), X(0x0541674e),
1164 X(0x0547b475), X(0x054e0544), X(0x055459bb), X(0x055ab1d9),
1165 X(0x05610d9e), X(0x05676d0a), X(0x056dd01c), X(0x057436d5),
1166 X(0x057aa134), X(0x05810f38), X(0x058780e2), X(0x058df631),
1167 X(0x05946f25), X(0x059aebbe), X(0x05a16bfa), X(0x05a7efdb),
1168 X(0x05ae775f), X(0x05b50287), X(0x05bb9152), X(0x05c223c0),
1169 X(0x05c8b9d0), X(0x05cf5382), X(0x05d5f0d6), X(0x05dc91cc),
1170 X(0x05e33663), X(0x05e9de9c), X(0x05f08a75), X(0x05f739ee),
1171 X(0x05fded07), X(0x0604a3c0), X(0x060b5e19), X(0x06121c11),
1172 X(0x0618dda8), X(0x061fa2dd), X(0x06266bb1), X(0x062d3822),
1173 X(0x06340831), X(0x063adbde), X(0x0641b328), X(0x06488e0e),
1174 X(0x064f6c91), X(0x06564eaf), X(0x065d346a), X(0x06641dc0),
1175 X(0x066b0ab1), X(0x0671fb3d), X(0x0678ef64), X(0x067fe724),
1176 X(0x0686e27f), X(0x068de173), X(0x0694e400), X(0x069bea27),
1177 X(0x06a2f3e6), X(0x06aa013d), X(0x06b1122c), X(0x06b826b3),
1178 X(0x06bf3ed1), X(0x06c65a86), X(0x06cd79d1), X(0x06d49cb3),
1179 X(0x06dbc32b), X(0x06e2ed38), X(0x06ea1adb), X(0x06f14c13),
1180 X(0x06f880df), X(0x06ffb940), X(0x0706f535), X(0x070e34bd),
1181 X(0x071577d9), X(0x071cbe88), X(0x072408c9), X(0x072b569d),
1182 X(0x0732a802), X(0x0739fcf9), X(0x07415582), X(0x0748b19b),
1183 X(0x07501145), X(0x0757747f), X(0x075edb49), X(0x076645a3),
1184 X(0x076db38c), X(0x07752503), X(0x077c9a09), X(0x0784129e),
1185 X(0x078b8ec0), X(0x07930e70), X(0x079a91ac), X(0x07a21876),
1186 X(0x07a9a2cc), X(0x07b130ad), X(0x07b8c21b), X(0x07c05714),
1187 X(0x07c7ef98), X(0x07cf8ba6), X(0x07d72b3f), X(0x07dece62),
1188 X(0x07e6750e), X(0x07ee1f43), X(0x07f5cd01), X(0x07fd7e48),
1189 X(0x08053316), X(0x080ceb6d), X(0x0814a74a), X(0x081c66af),
1190 X(0x0824299a), X(0x082bf00c), X(0x0833ba03), X(0x083b8780),
1191 X(0x08435882), X(0x084b2d09), X(0x08530514), X(0x085ae0a3),
1192 X(0x0862bfb6), X(0x086aa24c), X(0x08728865), X(0x087a7201),
1193 X(0x08825f1e), X(0x088a4fbe), X(0x089243de), X(0x089a3b80),
1194 X(0x08a236a2), X(0x08aa3545), X(0x08b23767), X(0x08ba3d09),
1195 X(0x08c2462a), X(0x08ca52c9), X(0x08d262e7), X(0x08da7682),
1196 X(0x08e28d9c), X(0x08eaa832), X(0x08f2c645), X(0x08fae7d4),
1197 X(0x09030cdf), X(0x090b3566), X(0x09136168), X(0x091b90e5),
1198 X(0x0923c3dc), X(0x092bfa4d), X(0x09343437), X(0x093c719b),
1199 X(0x0944b277), X(0x094cf6cc), X(0x09553e99), X(0x095d89dd),
1200 X(0x0965d899), X(0x096e2acb), X(0x09768073), X(0x097ed991),
1201 X(0x09873625), X(0x098f962e), X(0x0997f9ac), X(0x09a0609e),
1202 X(0x09a8cb04), X(0x09b138dd), X(0x09b9aa29), X(0x09c21ee8),
1203 X(0x09ca9719), X(0x09d312bc), X(0x09db91d0), X(0x09e41456),
1204 X(0x09ec9a4b), X(0x09f523b1), X(0x09fdb087), X(0x0a0640cc),
1205 X(0x0a0ed47f), X(0x0a176ba2), X(0x0a200632), X(0x0a28a42f),
1206 X(0x0a31459a), X(0x0a39ea72), X(0x0a4292b5), X(0x0a4b3e65),
1207 X(0x0a53ed80), X(0x0a5ca006), X(0x0a6555f7), X(0x0a6e0f51),
1208 X(0x0a76cc16), X(0x0a7f8c44), X(0x0a884fda), X(0x0a9116d9),
1209 X(0x0a99e140), X(0x0aa2af0e), X(0x0aab8043), X(0x0ab454df),
1210 X(0x0abd2ce1), X(0x0ac60849), X(0x0acee716), X(0x0ad7c948),
1211 X(0x0ae0aedf), X(0x0ae997d9), X(0x0af28437), X(0x0afb73f7),
1212 X(0x0b04671b), X(0x0b0d5da0), X(0x0b165788), X(0x0b1f54d0),
1213 X(0x0b285579), X(0x0b315983), X(0x0b3a60ec), X(0x0b436bb5),
1214 X(0x0b4c79dd), X(0x0b558b63), X(0x0b5ea048), X(0x0b67b88a),
1215 X(0x0b70d429), X(0x0b79f324), X(0x0b83157c), X(0x0b8c3b30),
1216 X(0x0b95643f), X(0x0b9e90a8), X(0x0ba7c06c), X(0x0bb0f38a),
1217 X(0x0bba2a01), X(0x0bc363d1), X(0x0bcca0f9), X(0x0bd5e17a),
1218 X(0x0bdf2552), X(0x0be86c81), X(0x0bf1b706), X(0x0bfb04e2),
1219 X(0x0c045613), X(0x0c0daa99), X(0x0c170274), X(0x0c205da3),
1220 X(0x0c29bc25), X(0x0c331dfb), X(0x0c3c8323), X(0x0c45eb9e),
1221 X(0x0c4f576a), X(0x0c58c688), X(0x0c6238f6), X(0x0c6baeb5),
1222 X(0x0c7527c3), X(0x0c7ea421), X(0x0c8823cd), X(0x0c91a6c8),
1223 X(0x0c9b2d10), X(0x0ca4b6a6), X(0x0cae4389), X(0x0cb7d3b8),
1224 X(0x0cc16732), X(0x0ccafdf8), X(0x0cd49809), X(0x0cde3564),
1225 X(0x0ce7d609), X(0x0cf179f7), X(0x0cfb212e), X(0x0d04cbad),
1226 X(0x0d0e7974), X(0x0d182a83), X(0x0d21ded8), X(0x0d2b9673),
1227 X(0x0d355154), X(0x0d3f0f7b), X(0x0d48d0e6), X(0x0d529595),
1228 X(0x0d5c5d88), X(0x0d6628be), X(0x0d6ff737), X(0x0d79c8f2),
1229 X(0x0d839dee), X(0x0d8d762c), X(0x0d9751aa), X(0x0da13068),
1230 X(0x0dab1266), X(0x0db4f7a3), X(0x0dbee01e), X(0x0dc8cbd8),
1231 X(0x0dd2bace), X(0x0ddcad02), X(0x0de6a272), X(0x0df09b1e),
1232 X(0x0dfa9705), X(0x0e049627), X(0x0e0e9883), X(0x0e189e19),
1233 X(0x0e22a6e8), X(0x0e2cb2f0), X(0x0e36c230), X(0x0e40d4a8),
1234 X(0x0e4aea56), X(0x0e55033b), X(0x0e5f1f56), X(0x0e693ea7),
1235 X(0x0e73612c), X(0x0e7d86e5), X(0x0e87afd3), X(0x0e91dbf3),
1236 X(0x0e9c0b47), X(0x0ea63dcc), X(0x0eb07383), X(0x0ebaac6b),
1237 X(0x0ec4e883), X(0x0ecf27cc), X(0x0ed96a44), X(0x0ee3afea),
1238 X(0x0eedf8bf), X(0x0ef844c2), X(0x0f0293f2), X(0x0f0ce64e),
1239 X(0x0f173bd6), X(0x0f21948a), X(0x0f2bf069), X(0x0f364f72),
1240 X(0x0f40b1a5), X(0x0f4b1701), X(0x0f557f86), X(0x0f5feb32),
1241 X(0x0f6a5a07), X(0x0f74cc02), X(0x0f7f4124), X(0x0f89b96b),
1242 X(0x0f9434d8), X(0x0f9eb369), X(0x0fa9351e), X(0x0fb3b9f7),
1243 X(0x0fbe41f3), X(0x0fc8cd11), X(0x0fd35b51), X(0x0fddecb2),
1244 X(0x0fe88134), X(0x0ff318d6), X(0x0ffdb397), X(0x10085177),
1245 X(0x1012f275), X(0x101d9691), X(0x10283dca), X(0x1032e81f),
1246 X(0x103d9591), X(0x1048461e), X(0x1052f9c5), X(0x105db087),
1247 X(0x10686a62), X(0x10732756), X(0x107de763), X(0x1088aa87),
1248 X(0x109370c2), X(0x109e3a14), X(0x10a9067c), X(0x10b3d5f9),
1249 X(0x10bea88b), X(0x10c97e31), X(0x10d456eb), X(0x10df32b8),
1250 X(0x10ea1197), X(0x10f4f387), X(0x10ffd889), X(0x110ac09b),
1251 X(0x1115abbe), X(0x112099ef), X(0x112b8b2f), X(0x11367f7d),
1252 X(0x114176d9), X(0x114c7141), X(0x11576eb6), X(0x11626f36),
1253 X(0x116d72c1), X(0x11787957), X(0x118382f6), X(0x118e8f9e),
1254 X(0x11999f4f), X(0x11a4b208), X(0x11afc7c7), X(0x11bae08e),
1255 X(0x11c5fc5a), X(0x11d11b2c), X(0x11dc3d02), X(0x11e761dd),
1256 X(0x11f289ba), X(0x11fdb49b), X(0x1208e27e), X(0x12141362),
1257 X(0x121f4748), X(0x122a7e2d), X(0x1235b812), X(0x1240f4f6),
1258 X(0x124c34d9), X(0x125777b9), X(0x1262bd96), X(0x126e0670),
1259 X(0x12795245), X(0x1284a115), X(0x128ff2e0), X(0x129b47a5),
1260 X(0x12a69f63), X(0x12b1fa19), X(0x12bd57c7), X(0x12c8b86c),
1261 X(0x12d41c08), X(0x12df829a), X(0x12eaec21), X(0x12f6589d),
1262 X(0x1301c80c), X(0x130d3a6f), X(0x1318afc4), X(0x1324280b),
1263 X(0x132fa344), X(0x133b216d), X(0x1346a286), X(0x1352268e),
1264 X(0x135dad85), X(0x1369376a), X(0x1374c43c), X(0x138053fb),
1265 X(0x138be6a5), X(0x13977c3b), X(0x13a314bc), X(0x13aeb026),
1266 X(0x13ba4e79), X(0x13c5efb5), X(0x13d193d9), X(0x13dd3ae4),
1267 X(0x13e8e4d6), X(0x13f491ad), X(0x1400416a), X(0x140bf40b),
1268 X(0x1417a98f), X(0x142361f7), X(0x142f1d41), X(0x143adb6d),
1269 X(0x14469c7a), X(0x14526067), X(0x145e2734), X(0x1469f0df),
1270 X(0x1475bd69), X(0x14818cd0), X(0x148d5f15), X(0x14993435),
1271 X(0x14a50c31), X(0x14b0e708), X(0x14bcc4b8), X(0x14c8a542),
1272 X(0x14d488a5), X(0x14e06edf), X(0x14ec57f1), X(0x14f843d9),
1273 X(0x15043297), X(0x1510242b), X(0x151c1892), X(0x15280fcd),
1274 X(0x153409dc), X(0x154006bc), X(0x154c066e), X(0x155808f1),
1275 X(0x15640e44), X(0x15701666), X(0x157c2157), X(0x15882f16),
1276 X(0x15943fa2), X(0x15a052fb), X(0x15ac691f), X(0x15b8820f),
1277 X(0x15c49dc8), X(0x15d0bc4c), X(0x15dcdd98), X(0x15e901ad),
1278 X(0x15f52888), X(0x1601522b), X(0x160d7e93), X(0x1619adc1),
1279 X(0x1625dfb3), X(0x16321469), X(0x163e4be2), X(0x164a861d),
1280 X(0x1656c31a), X(0x166302d8), X(0x166f4555), X(0x167b8a92),
1281 X(0x1687d28e), X(0x16941d47), X(0x16a06abe), X(0x16acbaf0),
1282 X(0x16b90ddf), X(0x16c56388), X(0x16d1bbeb), X(0x16de1708),
1283 X(0x16ea74dd), X(0x16f6d56a), X(0x170338ae), X(0x170f9ea8),
1284 X(0x171c0758), X(0x172872bd), X(0x1734e0d6), X(0x174151a2),
1285 X(0x174dc520), X(0x175a3b51), X(0x1766b432), X(0x17732fc4),
1286 X(0x177fae05), X(0x178c2ef4), X(0x1798b292), X(0x17a538dd),
1287 X(0x17b1c1d4), X(0x17be4d77), X(0x17cadbc5), X(0x17d76cbc),
1288 X(0x17e4005e), X(0x17f096a7), X(0x17fd2f98), X(0x1809cb31),
1289 X(0x1816696f), X(0x18230a53), X(0x182faddc), X(0x183c5408),
1290 X(0x1848fcd8), X(0x1855a849), X(0x1862565d), X(0x186f0711),
1291 X(0x187bba64), X(0x18887057), X(0x189528e9), X(0x18a1e418),
1292 X(0x18aea1e3), X(0x18bb624b), X(0x18c8254e), X(0x18d4eaeb),
1293 X(0x18e1b321), X(0x18ee7df1), X(0x18fb4b58), X(0x19081b57),
1294 X(0x1914edec), X(0x1921c317), X(0x192e9ad6), X(0x193b7529),
1295 X(0x19485210), X(0x19553189), X(0x19621393), X(0x196ef82e),
1296 X(0x197bdf59), X(0x1988c913), X(0x1995b55c), X(0x19a2a432),
1297 X(0x19af9595), X(0x19bc8983), X(0x19c97ffd), X(0x19d67900),
1298 X(0x19e3748e), X(0x19f072a3), X(0x19fd7341), X(0x1a0a7665),
1299 X(0x1a177c10), X(0x1a248440), X(0x1a318ef4), X(0x1a3e9c2c),
1300 X(0x1a4babe7), X(0x1a58be24), X(0x1a65d2e2), X(0x1a72ea20),
1301 X(0x1a8003de), X(0x1a8d201a), X(0x1a9a3ed5), X(0x1aa7600c),
1302 X(0x1ab483bf), X(0x1ac1a9ee), X(0x1aced297), X(0x1adbfdba),
1303 X(0x1ae92b56), X(0x1af65b69), X(0x1b038df4), X(0x1b10c2f5),
1304 X(0x1b1dfa6b), X(0x1b2b3456), X(0x1b3870b5), X(0x1b45af87),
1305 X(0x1b52f0ca), X(0x1b60347f), X(0x1b6d7aa4), X(0x1b7ac339),
1306 X(0x1b880e3c), X(0x1b955bad), X(0x1ba2ab8b), X(0x1baffdd5),
1307 X(0x1bbd528a), X(0x1bcaa9a9), X(0x1bd80332), X(0x1be55f24),
1308 X(0x1bf2bd7d), X(0x1c001e3d), X(0x1c0d8164), X(0x1c1ae6ef),
1309 X(0x1c284edf), X(0x1c35b932), X(0x1c4325e7), X(0x1c5094fe),
1310 X(0x1c5e0677), X(0x1c6b7a4f), X(0x1c78f086), X(0x1c86691b),
1311 X(0x1c93e40d), X(0x1ca1615c), X(0x1caee107), X(0x1cbc630c),
1312 X(0x1cc9e76b), X(0x1cd76e23), X(0x1ce4f733), X(0x1cf2829a),
1313 X(0x1d001057), X(0x1d0da06a), X(0x1d1b32d1), X(0x1d28c78c),
1314 X(0x1d365e9a), X(0x1d43f7f9), X(0x1d5193a9), X(0x1d5f31aa),
1315 X(0x1d6cd1f9), X(0x1d7a7497), X(0x1d881982), X(0x1d95c0ba),
1316 X(0x1da36a3d), X(0x1db1160a), X(0x1dbec422), X(0x1dcc7482),
1317 X(0x1dda272b), X(0x1de7dc1a), X(0x1df59350), X(0x1e034ccb),
1318 X(0x1e11088a), X(0x1e1ec68c), X(0x1e2c86d1), X(0x1e3a4958),
1319 X(0x1e480e20), X(0x1e55d527), X(0x1e639e6d), X(0x1e7169f1),
1320 X(0x1e7f37b2), X(0x1e8d07b0), X(0x1e9ad9e8), X(0x1ea8ae5b),
1321 X(0x1eb68507), X(0x1ec45dec), X(0x1ed23908), X(0x1ee0165b),
1322 X(0x1eedf5e4), X(0x1efbd7a1), X(0x1f09bb92), X(0x1f17a1b6),
1323 X(0x1f258a0d), X(0x1f337494), X(0x1f41614b), X(0x1f4f5032),
1324 X(0x1f5d4147), X(0x1f6b3489), X(0x1f7929f7), X(0x1f872192),
1325 X(0x1f951b56), X(0x1fa31744), X(0x1fb1155b), X(0x1fbf159a),
1326 X(0x1fcd17ff), X(0x1fdb1c8b), X(0x1fe9233b), X(0x1ff72c0f),
1327 X(0x20053706), X(0x20134420), X(0x2021535a), X(0x202f64b4),
1328 X(0x203d782e), X(0x204b8dc6), X(0x2059a57c), X(0x2067bf4e),
1329 X(0x2075db3b), X(0x2083f943), X(0x20921964), X(0x20a03b9e),
1330 X(0x20ae5fef), X(0x20bc8657), X(0x20caaed5), X(0x20d8d967),
1331 X(0x20e7060e), X(0x20f534c7), X(0x21036592), X(0x2111986e),
1332 X(0x211fcd59), X(0x212e0454), X(0x213c3d5d), X(0x214a7873),
1333 X(0x2158b594), X(0x2166f4c1), X(0x217535f8), X(0x21837938),
1334 X(0x2191be81), X(0x21a005d0), X(0x21ae4f26), X(0x21bc9a81),
1335 X(0x21cae7e0), X(0x21d93743), X(0x21e788a8), X(0x21f5dc0e),
1336 X(0x22043174), X(0x221288da), X(0x2220e23e), X(0x222f3da0),
1337 X(0x223d9afe), X(0x224bfa58), X(0x225a5bac), X(0x2268bef9),
1338 X(0x2277243f), X(0x22858b7d), X(0x2293f4b0), X(0x22a25fda),
1339 X(0x22b0ccf8), X(0x22bf3c09), X(0x22cdad0d), X(0x22dc2002),
1340 X(0x22ea94e8), X(0x22f90bbe), X(0x23078482), X(0x2315ff33),
1341 X(0x23247bd1), X(0x2332fa5b), X(0x23417acf), X(0x234ffd2c),
1342 X(0x235e8173), X(0x236d07a0), X(0x237b8fb4), X(0x238a19ae),
1343 X(0x2398a58c), X(0x23a7334d), X(0x23b5c2f1), X(0x23c45477),
1344 X(0x23d2e7dd), X(0x23e17d22), X(0x23f01446), X(0x23fead47),
1345 X(0x240d4825), X(0x241be4dd), X(0x242a8371), X(0x243923dd),
1346 X(0x2447c622), X(0x24566a3e), X(0x24651031), X(0x2473b7f8),
1347 X(0x24826194), X(0x24910d03), X(0x249fba44), X(0x24ae6957),
1348 X(0x24bd1a39), X(0x24cbccea), X(0x24da816a), X(0x24e937b7),
1349 X(0x24f7efcf), X(0x2506a9b3), X(0x25156560), X(0x252422d6),
1350 X(0x2532e215), X(0x2541a31a), X(0x255065e4), X(0x255f2a74),
1351 X(0x256df0c7), X(0x257cb8dd), X(0x258b82b4), X(0x259a4e4c),
1352 X(0x25a91ba4), X(0x25b7eaba), X(0x25c6bb8e), X(0x25d58e1e),
1353 X(0x25e46269), X(0x25f3386e), X(0x2602102d), X(0x2610e9a4),
1354 X(0x261fc4d3), X(0x262ea1b7), X(0x263d8050), X(0x264c609e),
1355 X(0x265b429e), X(0x266a2650), X(0x26790bb3), X(0x2687f2c6),
1356 X(0x2696db88), X(0x26a5c5f7), X(0x26b4b213), X(0x26c39fda),
1357 X(0x26d28f4c), X(0x26e18067), X(0x26f0732b), X(0x26ff6796),
1358 X(0x270e5da7), X(0x271d555d), X(0x272c4eb7), X(0x273b49b5),
1359 X(0x274a4654), X(0x27594495), X(0x27684475), X(0x277745f4),
1360 X(0x27864910), X(0x27954dc9), X(0x27a4541e), X(0x27b35c0d),
1361 X(0x27c26596), X(0x27d170b7), X(0x27e07d6f), X(0x27ef8bbd),
1362 X(0x27fe9ba0), X(0x280dad18), X(0x281cc022), X(0x282bd4be),
1363 X(0x283aeaeb), X(0x284a02a7), X(0x28591bf2), X(0x286836cb),
1364 X(0x28775330), X(0x28867120), X(0x2895909b), X(0x28a4b19e),
1365 X(0x28b3d42a), X(0x28c2f83d), X(0x28d21dd5), X(0x28e144f3),
1366 X(0x28f06d94), X(0x28ff97b8), X(0x290ec35d), X(0x291df082),
1367 X(0x292d1f27), X(0x293c4f4a), X(0x294b80eb), X(0x295ab407),
1368 X(0x2969e89e), X(0x29791eaf), X(0x29885639), X(0x29978f3b),
1369 X(0x29a6c9b3), X(0x29b605a0), X(0x29c54302), X(0x29d481d7),
1370 X(0x29e3c21e), X(0x29f303d6), X(0x2a0246fd), X(0x2a118b94),
1371 X(0x2a20d198), X(0x2a301909), X(0x2a3f61e6), X(0x2a4eac2c),
1372 X(0x2a5df7dc), X(0x2a6d44f4), X(0x2a7c9374), X(0x2a8be359),
1373 X(0x2a9b34a2), X(0x2aaa8750), X(0x2ab9db60), X(0x2ac930d1),
1374 X(0x2ad887a3), X(0x2ae7dfd3), X(0x2af73962), X(0x2b06944e),
1375 X(0x2b15f096), X(0x2b254e38), X(0x2b34ad34), X(0x2b440d89),
1376 X(0x2b536f34), X(0x2b62d236), X(0x2b72368d), X(0x2b819c38),
1377 X(0x2b910336), X(0x2ba06b86), X(0x2bafd526), X(0x2bbf4015),
1378 X(0x2bceac53), X(0x2bde19de), X(0x2bed88b5), X(0x2bfcf8d7),
1379 X(0x2c0c6a43), X(0x2c1bdcf7), X(0x2c2b50f3), X(0x2c3ac635),
1380 X(0x2c4a3cbd), X(0x2c59b488), X(0x2c692d97), X(0x2c78a7e7),
1381 X(0x2c882378), X(0x2c97a049), X(0x2ca71e58), X(0x2cb69da4),
1382 X(0x2cc61e2c), X(0x2cd59ff0), X(0x2ce522ed), X(0x2cf4a723),
1383 X(0x2d042c90), X(0x2d13b334), X(0x2d233b0d), X(0x2d32c41a),
1384 X(0x2d424e5a), X(0x2d51d9cc), X(0x2d61666e), X(0x2d70f440),
1385 X(0x2d808340), X(0x2d90136e), X(0x2d9fa4c7), X(0x2daf374c),
1386 X(0x2dbecafa), X(0x2dce5fd1), X(0x2dddf5cf), X(0x2ded8cf4),
1387 X(0x2dfd253d), X(0x2e0cbeab), X(0x2e1c593b), X(0x2e2bf4ed),
1388 X(0x2e3b91c0), X(0x2e4b2fb1), X(0x2e5acec1), X(0x2e6a6eee),
1389 X(0x2e7a1037), X(0x2e89b29b), X(0x2e995618), X(0x2ea8faad),
1390 X(0x2eb8a05a), X(0x2ec8471c), X(0x2ed7eef4), X(0x2ee797df),
1391 X(0x2ef741dc), X(0x2f06eceb), X(0x2f16990a), X(0x2f264639),
1392 X(0x2f35f475), X(0x2f45a3bd), X(0x2f555412), X(0x2f650570),
1393 X(0x2f74b7d8), X(0x2f846b48), X(0x2f941fbe), X(0x2fa3d53a),
1394 X(0x2fb38bbb), X(0x2fc3433f), X(0x2fd2fbc5), X(0x2fe2b54c),
1395 X(0x2ff26fd3), X(0x30022b58), X(0x3011e7db), X(0x3021a55a),
1396 X(0x303163d4), X(0x30412348), X(0x3050e3b5), X(0x3060a519),
1397 X(0x30706773), X(0x30802ac3), X(0x308fef06), X(0x309fb43d),
1398 X(0x30af7a65), X(0x30bf417d), X(0x30cf0985), X(0x30ded27a),
1399 X(0x30ee9c5d), X(0x30fe672b), X(0x310e32e3), X(0x311dff85),
1400 X(0x312dcd0f), X(0x313d9b80), X(0x314d6ad7), X(0x315d3b12),
1401 X(0x316d0c30), X(0x317cde31), X(0x318cb113), X(0x319c84d4),
1402 X(0x31ac5974), X(0x31bc2ef1), X(0x31cc054b), X(0x31dbdc7f),
1403 X(0x31ebb48e), X(0x31fb8d74), X(0x320b6733), X(0x321b41c7),
1404 X(0x322b1d31), X(0x323af96e), X(0x324ad67e), X(0x325ab45f),
1405 X(0x326a9311), X(0x327a7291), X(0x328a52e0), X(0x329a33fb),
1406 X(0x32aa15e1), X(0x32b9f892), X(0x32c9dc0c), X(0x32d9c04d),
1407 X(0x32e9a555), X(0x32f98b22), X(0x330971b4), X(0x33195909),
1408 X(0x3329411f), X(0x333929f6), X(0x3349138c), X(0x3358fde1),
1409 X(0x3368e8f2), X(0x3378d4c0), X(0x3388c147), X(0x3398ae89),
1410 X(0x33a89c82), X(0x33b88b32), X(0x33c87a98), X(0x33d86ab2),
1411 X(0x33e85b80), X(0x33f84d00), X(0x34083f30), X(0x34183210),
1412 X(0x3428259f), X(0x343819db), X(0x34480ec3), X(0x34580455),
1413 X(0x3467fa92), X(0x3477f176), X(0x3487e902), X(0x3497e134),
1414 X(0x34a7da0a), X(0x34b7d384), X(0x34c7cda0), X(0x34d7c85e),
1415 X(0x34e7c3bb), X(0x34f7bfb7), X(0x3507bc50), X(0x3517b985),
1416 X(0x3527b756), X(0x3537b5c0), X(0x3547b4c3), X(0x3557b45d),
1417 X(0x3567b48d), X(0x3577b552), X(0x3587b6aa), X(0x3597b895),
1418 X(0x35a7bb12), X(0x35b7be1e), X(0x35c7c1b9), X(0x35d7c5e1),
1419 X(0x35e7ca96), X(0x35f7cfd6), X(0x3607d5a0), X(0x3617dbf3),
1420 X(0x3627e2cd), X(0x3637ea2d), X(0x3647f212), X(0x3657fa7b),
1421 X(0x36680366), X(0x36780cd2), X(0x368816bf), X(0x3698212b),
1422 X(0x36a82c14), X(0x36b83779), X(0x36c8435a), X(0x36d84fb4),
1423 X(0x36e85c88), X(0x36f869d2), X(0x37087793), X(0x371885c9),
1424 X(0x37289473), X(0x3738a38f), X(0x3748b31d), X(0x3758c31a),
1425 X(0x3768d387), X(0x3778e461), X(0x3788f5a7), X(0x37990759),
1426 X(0x37a91975), X(0x37b92bf9), X(0x37c93ee4), X(0x37d95236),
1427 X(0x37e965ed), X(0x37f97a08), X(0x38098e85), X(0x3819a363),
1428 X(0x3829b8a2), X(0x3839ce3f), X(0x3849e43a), X(0x3859fa91),
1429 X(0x386a1143), X(0x387a284f), X(0x388a3fb4), X(0x389a5770),
1430 X(0x38aa6f83), X(0x38ba87ea), X(0x38caa0a5), X(0x38dab9b2),
1431 X(0x38ead311), X(0x38faecbf), X(0x390b06bc), X(0x391b2107),
1432 X(0x392b3b9e), X(0x393b5680), X(0x394b71ac), X(0x395b8d20),
1433 X(0x396ba8dc), X(0x397bc4dd), X(0x398be124), X(0x399bfdae),
1434 X(0x39ac1a7a), X(0x39bc3788), X(0x39cc54d5), X(0x39dc7261),
1435 X(0x39ec902a), X(0x39fcae2f), X(0x3a0ccc70), X(0x3a1ceaea),
1436 X(0x3a2d099c), X(0x3a3d2885), X(0x3a4d47a5), X(0x3a5d66f9),
1437 X(0x3a6d8680), X(0x3a7da63a), X(0x3a8dc625), X(0x3a9de63f),
1438 X(0x3aae0688), X(0x3abe26fe), X(0x3ace47a0), X(0x3ade686d),
1439 X(0x3aee8963), X(0x3afeaa82), X(0x3b0ecbc7), X(0x3b1eed32),
1440 X(0x3b2f0ec2), X(0x3b3f3075), X(0x3b4f524a), X(0x3b5f7440),
1441 X(0x3b6f9656), X(0x3b7fb889), X(0x3b8fdada), X(0x3b9ffd46),
1442 X(0x3bb01fce), X(0x3bc0426e), X(0x3bd06526), X(0x3be087f6),
1443 X(0x3bf0aada), X(0x3c00cdd4), X(0x3c10f0e0), X(0x3c2113fe),
1444 X(0x3c31372d), X(0x3c415a6b), X(0x3c517db7), X(0x3c61a110),
1445 X(0x3c71c475), X(0x3c81e7e4), X(0x3c920b5c), X(0x3ca22edc),
1446 X(0x3cb25262), X(0x3cc275ee), X(0x3cd2997e), X(0x3ce2bd11),
1447 X(0x3cf2e0a6), X(0x3d03043b), X(0x3d1327cf), X(0x3d234b61),
1448 X(0x3d336ef0), X(0x3d43927a), X(0x3d53b5ff), X(0x3d63d97c),
1449 X(0x3d73fcf1), X(0x3d84205c), X(0x3d9443bd), X(0x3da46711),
1450 X(0x3db48a58), X(0x3dc4ad91), X(0x3dd4d0ba), X(0x3de4f3d1),
1451 X(0x3df516d7), X(0x3e0539c9), X(0x3e155ca6), X(0x3e257f6d),
1452 X(0x3e35a21d), X(0x3e45c4b4), X(0x3e55e731), X(0x3e660994),
1453 X(0x3e762bda), X(0x3e864e03), X(0x3e96700d), X(0x3ea691f7),
1454 X(0x3eb6b3bf), X(0x3ec6d565), X(0x3ed6f6e8), X(0x3ee71845),
1455 X(0x3ef7397c), X(0x3f075a8c), X(0x3f177b73), X(0x3f279c30),
1456 X(0x3f37bcc2), X(0x3f47dd27), X(0x3f57fd5f), X(0x3f681d68),
1457 X(0x3f783d40), X(0x3f885ce7), X(0x3f987c5c), X(0x3fa89b9c),
1458 X(0x3fb8baa7), X(0x3fc8d97c), X(0x3fd8f819), X(0x3fe9167e),
1459 X(0x3ff934a8), X(0x40095296), X(0x40197049), X(0x40298dbd),
1460 X(0x4039aaf2), X(0x4049c7e7), X(0x4059e49a), X(0x406a010a),
1461 X(0x407a1d36), X(0x408a391d), X(0x409a54bd), X(0x40aa7015),
1462 X(0x40ba8b25), X(0x40caa5ea), X(0x40dac063), X(0x40eada90),
1463 X(0x40faf46e), X(0x410b0dfe), X(0x411b273d), X(0x412b402a),
1464 X(0x413b58c4), X(0x414b710a), X(0x415b88fa), X(0x416ba093),
1465 X(0x417bb7d5), X(0x418bcebe), X(0x419be54c), X(0x41abfb7e),
1466 X(0x41bc1153), X(0x41cc26ca), X(0x41dc3be2), X(0x41ec5099),
1467 X(0x41fc64ef), X(0x420c78e1), X(0x421c8c6f), X(0x422c9f97),
1468 X(0x423cb258), X(0x424cc4b2), X(0x425cd6a2), X(0x426ce827),
1469 X(0x427cf941), X(0x428d09ee), X(0x429d1a2c), X(0x42ad29fb),
1470 X(0x42bd3959), X(0x42cd4846), X(0x42dd56bf), X(0x42ed64c3),
1471 X(0x42fd7252), X(0x430d7f6a), X(0x431d8c0a), X(0x432d9831),
1472 X(0x433da3dd), X(0x434daf0d), X(0x435db9c0), X(0x436dc3f5),
1473 X(0x437dcdab), X(0x438dd6df), X(0x439ddf92), X(0x43ade7c1),
1474 X(0x43bdef6c), X(0x43cdf691), X(0x43ddfd2f), X(0x43ee0345),
1475 X(0x43fe08d2), X(0x440e0dd4), X(0x441e124b), X(0x442e1634),
1476 X(0x443e198f), X(0x444e1c5a), X(0x445e1e95), X(0x446e203e),
1477 X(0x447e2153), X(0x448e21d5), X(0x449e21c0), X(0x44ae2115),
1478 X(0x44be1fd1), X(0x44ce1df4), X(0x44de1b7d), X(0x44ee186a),
1479 X(0x44fe14ba), X(0x450e106b), X(0x451e0b7e), X(0x452e05ef),
1480 X(0x453dffbf), X(0x454df8eb), X(0x455df173), X(0x456de956),
1481 X(0x457de092), X(0x458dd726), X(0x459dcd10), X(0x45adc251),
1482 X(0x45bdb6e5), X(0x45cdaacd), X(0x45dd9e06), X(0x45ed9091),
1483 X(0x45fd826a), X(0x460d7392), X(0x461d6407), X(0x462d53c8),
1484 X(0x463d42d4), X(0x464d3129), X(0x465d1ec6), X(0x466d0baa),
1485 X(0x467cf7d3), X(0x468ce342), X(0x469ccdf3), X(0x46acb7e7),
1486 X(0x46bca11c), X(0x46cc8990), X(0x46dc7143), X(0x46ec5833),
1487 X(0x46fc3e5f), X(0x470c23c6), X(0x471c0867), X(0x472bec40),
1488 X(0x473bcf50), X(0x474bb196), X(0x475b9311), X(0x476b73c0),
1489 X(0x477b53a1), X(0x478b32b4), X(0x479b10f6), X(0x47aaee67),
1490 X(0x47bacb06), X(0x47caa6d1), X(0x47da81c7), X(0x47ea5be7),
1491 X(0x47fa3530), X(0x480a0da1), X(0x4819e537), X(0x4829bbf3),
1492 X(0x483991d3), X(0x484966d6), X(0x48593afb), X(0x48690e3f),
1493 X(0x4878e0a3), X(0x4888b225), X(0x489882c4), X(0x48a8527e),
1494 X(0x48b82153), X(0x48c7ef41), X(0x48d7bc47), X(0x48e78863),
1495 X(0x48f75396), X(0x49071ddc), X(0x4916e736), X(0x4926afa2),
1496 X(0x4936771f), X(0x49463dac), X(0x49560347), X(0x4965c7ef),
1497 X(0x49758ba4), X(0x49854e63), X(0x4995102c), X(0x49a4d0fe),
1498 X(0x49b490d7), X(0x49c44fb6), X(0x49d40d9a), X(0x49e3ca82),
1499 X(0x49f3866c), X(0x4a034159), X(0x4a12fb45), X(0x4a22b430),
1500 X(0x4a326c19), X(0x4a4222ff), X(0x4a51d8e1), X(0x4a618dbd),
1501 X(0x4a714192), X(0x4a80f45f), X(0x4a90a623), X(0x4aa056dd),
1502 X(0x4ab0068b), X(0x4abfb52c), X(0x4acf62c0), X(0x4adf0f44),
1503 X(0x4aeebab9), X(0x4afe651c), X(0x4b0e0e6c), X(0x4b1db6a9),
1504 X(0x4b2d5dd1), X(0x4b3d03e2), X(0x4b4ca8dd), X(0x4b5c4cbf),
1505 X(0x4b6bef88), X(0x4b7b9136), X(0x4b8b31c8), X(0x4b9ad13d),
1506 X(0x4baa6f93), X(0x4bba0ccb), X(0x4bc9a8e2), X(0x4bd943d7),
1507 X(0x4be8dda9), X(0x4bf87658), X(0x4c080de1), X(0x4c17a444),
1508 X(0x4c27397f), X(0x4c36cd92), X(0x4c46607b), X(0x4c55f239),
1509 X(0x4c6582cb), X(0x4c75122f), X(0x4c84a065), X(0x4c942d6c),
1510 X(0x4ca3b942), X(0x4cb343e6), X(0x4cc2cd57), X(0x4cd25594),
1511 X(0x4ce1dc9c), X(0x4cf1626d), X(0x4d00e707), X(0x4d106a68),
1512 X(0x4d1fec8f), X(0x4d2f6d7a), X(0x4d3eed2a), X(0x4d4e6b9d),
1513 X(0x4d5de8d1), X(0x4d6d64c5), X(0x4d7cdf79), X(0x4d8c58eb),
1514 X(0x4d9bd11a), X(0x4dab4804), X(0x4dbabdaa), X(0x4dca3209),
1515 X(0x4dd9a520), X(0x4de916ef), X(0x4df88774), X(0x4e07f6ae),
1516 X(0x4e17649c), X(0x4e26d13c), X(0x4e363c8f), X(0x4e45a692),
1517 X(0x4e550f44), X(0x4e6476a4), X(0x4e73dcb2), X(0x4e83416c),
1518 X(0x4e92a4d1), X(0x4ea206df), X(0x4eb16796), X(0x4ec0c6f5),
1519 X(0x4ed024fa), X(0x4edf81a5), X(0x4eeedcf3), X(0x4efe36e5),
1520 X(0x4f0d8f79), X(0x4f1ce6ad), X(0x4f2c3c82), X(0x4f3b90f4),
1521 X(0x4f4ae405), X(0x4f5a35b1), X(0x4f6985fa), X(0x4f78d4dc),
1522 X(0x4f882257), X(0x4f976e6a), X(0x4fa6b914), X(0x4fb60254),
1523 X(0x4fc54a28), X(0x4fd49090), X(0x4fe3d58b), X(0x4ff31917),
1524 X(0x50025b33), X(0x50119bde), X(0x5020db17), X(0x503018dd),
1525 X(0x503f552f), X(0x504e900b), X(0x505dc971), X(0x506d0160),
1526 X(0x507c37d7), X(0x508b6cd3), X(0x509aa055), X(0x50a9d25b),
1527 X(0x50b902e4), X(0x50c831ef), X(0x50d75f7b), X(0x50e68b87),
1528 X(0x50f5b612), X(0x5104df1a), X(0x5114069f), X(0x51232ca0),
1529 X(0x5132511a), X(0x5141740f), X(0x5150957b), X(0x515fb55f),
1530 X(0x516ed3b8), X(0x517df087), X(0x518d0bca), X(0x519c257f),
1531 X(0x51ab3da7), X(0x51ba543f), X(0x51c96947), X(0x51d87cbd),
1532 X(0x51e78ea1), X(0x51f69ef1), X(0x5205adad), X(0x5214bad3),
1533 X(0x5223c662), X(0x5232d05a), X(0x5241d8b9), X(0x5250df7d),
1534 X(0x525fe4a7), X(0x526ee835), X(0x527dea26), X(0x528cea78),
1535 X(0x529be92c), X(0x52aae63f), X(0x52b9e1b0), X(0x52c8db80),
1536 X(0x52d7d3ac), X(0x52e6ca33), X(0x52f5bf15), X(0x5304b251),
1537 X(0x5313a3e5), X(0x532293d0), X(0x53318212), X(0x53406ea8),
1538 X(0x534f5993), X(0x535e42d2), X(0x536d2a62), X(0x537c1043),
1539 X(0x538af475), X(0x5399d6f6), X(0x53a8b7c4), X(0x53b796e0),
1540 X(0x53c67447), X(0x53d54ffa), X(0x53e429f6), X(0x53f3023b),
1541 X(0x5401d8c8), X(0x5410ad9c), X(0x541f80b5), X(0x542e5213),
1542 X(0x543d21b5), X(0x544bef9a), X(0x545abbc0), X(0x54698627),
1543 X(0x54784ece), X(0x548715b3), X(0x5495dad6), X(0x54a49e35),
1544 X(0x54b35fd0), X(0x54c21fa6), X(0x54d0ddb5), X(0x54df99fd),
1545 X(0x54ee547c), X(0x54fd0d32), X(0x550bc41d), X(0x551a793d),
1546 X(0x55292c91), X(0x5537de16), X(0x55468dce), X(0x55553bb6),
1547 X(0x5563e7cd), X(0x55729213), X(0x55813a87), X(0x558fe127),
1548 X(0x559e85f2), X(0x55ad28e9), X(0x55bbca08), X(0x55ca6950),
1549 X(0x55d906c0), X(0x55e7a257), X(0x55f63c13), X(0x5604d3f4),
1550 X(0x561369f8), X(0x5621fe1f), X(0x56309067), X(0x563f20d1),
1551 X(0x564daf5a), X(0x565c3c02), X(0x566ac6c7), X(0x56794faa),
1552 X(0x5687d6a8), X(0x56965bc1), X(0x56a4def4), X(0x56b36040),
1553 X(0x56c1dfa4), X(0x56d05d1f), X(0x56ded8af), X(0x56ed5255),
1554 X(0x56fbca0f), X(0x570a3fdc), X(0x5718b3bc), X(0x572725ac),
1555 X(0x573595ad), X(0x574403bd), X(0x57526fdb), X(0x5760da07),
1556 X(0x576f423f), X(0x577da883), X(0x578c0cd1), X(0x579a6f29),
1557 X(0x57a8cf8a), X(0x57b72df2), X(0x57c58a61), X(0x57d3e4d6),
1558 X(0x57e23d50), X(0x57f093cd), X(0x57fee84e), X(0x580d3ad1),
1559 X(0x581b8b54), X(0x5829d9d8), X(0x5838265c), X(0x584670dd),
1560 X(0x5854b95c), X(0x5862ffd8), X(0x5871444f), X(0x587f86c1),
1561 X(0x588dc72c), X(0x589c0591), X(0x58aa41ed), X(0x58b87c40),
1562 X(0x58c6b489), X(0x58d4eac7), X(0x58e31ef9), X(0x58f1511f),
1563 X(0x58ff8137), X(0x590daf40), X(0x591bdb3a), X(0x592a0524),
1564 X(0x59382cfc), X(0x594652c2), X(0x59547675), X(0x59629815),
1565 X(0x5970b79f), X(0x597ed513), X(0x598cf071), X(0x599b09b7),
1566 X(0x59a920e5), X(0x59b735f9), X(0x59c548f4), X(0x59d359d2),
1567 X(0x59e16895), X(0x59ef753b), X(0x59fd7fc4), X(0x5a0b882d),
1568 X(0x5a198e77), X(0x5a2792a0), X(0x5a3594a9), X(0x5a43948e),
1569 X(0x5a519251), X(0x5a5f8df0), X(0x5a6d876a), X(0x5a7b7ebe),
1570 X(0x5a8973ec), X(0x5a9766f2), X(0x5aa557d0), X(0x5ab34685),
1571 X(0x5ac1330f), X(0x5acf1d6f), X(0x5add05a3), X(0x5aeaebaa),
1572 X(0x5af8cf84), X(0x5b06b12f), X(0x5b1490ab), X(0x5b226df7),
1573 X(0x5b304912), X(0x5b3e21fc), X(0x5b4bf8b2), X(0x5b59cd35),
1574 X(0x5b679f84), X(0x5b756f9e), X(0x5b833d82), X(0x5b91092e),
1575 X(0x5b9ed2a3), X(0x5bac99e0), X(0x5bba5ee3), X(0x5bc821ac),
1576 X(0x5bd5e23a), X(0x5be3a08c), X(0x5bf15ca1), X(0x5bff1679),
1577 X(0x5c0cce12), X(0x5c1a836c), X(0x5c283686), X(0x5c35e760),
1578 X(0x5c4395f7), X(0x5c51424c), X(0x5c5eec5e), X(0x5c6c942b),
1579 X(0x5c7a39b4), X(0x5c87dcf7), X(0x5c957df3), X(0x5ca31ca8),
1580 X(0x5cb0b915), X(0x5cbe5338), X(0x5ccbeb12), X(0x5cd980a1),
1581 X(0x5ce713e5), X(0x5cf4a4dd), X(0x5d023387), X(0x5d0fbfe4),
1582 X(0x5d1d49f2), X(0x5d2ad1b1), X(0x5d38571f), X(0x5d45da3c),
1583 X(0x5d535b08), X(0x5d60d981), X(0x5d6e55a7), X(0x5d7bcf78),
1584 X(0x5d8946f5), X(0x5d96bc1c), X(0x5da42eec), X(0x5db19f65),
1585 X(0x5dbf0d86), X(0x5dcc794e), X(0x5dd9e2bd), X(0x5de749d1),
1586 X(0x5df4ae8a), X(0x5e0210e7), X(0x5e0f70e7), X(0x5e1cce8a),
1587 X(0x5e2a29ce), X(0x5e3782b4), X(0x5e44d93a), X(0x5e522d5f),
1588 X(0x5e5f7f23), X(0x5e6cce85), X(0x5e7a1b85), X(0x5e876620),
1589 X(0x5e94ae58), X(0x5ea1f42a), X(0x5eaf3797), X(0x5ebc789d),
1590 X(0x5ec9b73c), X(0x5ed6f372), X(0x5ee42d41), X(0x5ef164a5),
1591 X(0x5efe999f), X(0x5f0bcc2f), X(0x5f18fc52), X(0x5f262a09),
1592 X(0x5f335553), X(0x5f407e2f), X(0x5f4da49d), X(0x5f5ac89b),
1593 X(0x5f67ea29), X(0x5f750946), X(0x5f8225f2), X(0x5f8f402b),
1594 X(0x5f9c57f2), X(0x5fa96d44), X(0x5fb68023), X(0x5fc3908c),
1595 X(0x5fd09e7f), X(0x5fdda9fc), X(0x5feab302), X(0x5ff7b990),
1596 X(0x6004bda5), X(0x6011bf40), X(0x601ebe62), X(0x602bbb09),
1597 X(0x6038b534), X(0x6045ace4), X(0x6052a216), X(0x605f94cb),
1598 X(0x606c8502), X(0x607972b9), X(0x60865df2), X(0x609346aa),
1599 X(0x60a02ce1), X(0x60ad1096), X(0x60b9f1c9), X(0x60c6d079),
1600 X(0x60d3aca5), X(0x60e0864d), X(0x60ed5d70), X(0x60fa320d),
1601 X(0x61070424), X(0x6113d3b4), X(0x6120a0bc), X(0x612d6b3c),
1602 X(0x613a3332), X(0x6146f89f), X(0x6153bb82), X(0x61607bd9),
1603 X(0x616d39a5), X(0x6179f4e5), X(0x6186ad98), X(0x619363bd),
1604 X(0x61a01753), X(0x61acc85b), X(0x61b976d3), X(0x61c622bc),
1605 X(0x61d2cc13), X(0x61df72d8), X(0x61ec170c), X(0x61f8b8ad),
1606 X(0x620557ba), X(0x6211f434), X(0x621e8e18), X(0x622b2568),
1607 X(0x6237ba21), X(0x62444c44), X(0x6250dbd0), X(0x625d68c4),
1608 X(0x6269f320), X(0x62767ae2), X(0x6283000b), X(0x628f829a),
1609 X(0x629c028e), X(0x62a87fe6), X(0x62b4faa2), X(0x62c172c2),
1610 X(0x62cde844), X(0x62da5b29), X(0x62e6cb6e), X(0x62f33915),
1611 X(0x62ffa41c), X(0x630c0c83), X(0x63187248), X(0x6324d56d),
1612 X(0x633135ef), X(0x633d93ce), X(0x6349ef0b), X(0x635647a3),
1613 X(0x63629d97), X(0x636ef0e6), X(0x637b418f), X(0x63878f92),
1614 X(0x6393daef), X(0x63a023a4), X(0x63ac69b1), X(0x63b8ad15),
1615 X(0x63c4edd1), X(0x63d12be3), X(0x63dd674b), X(0x63e9a008),
1616 X(0x63f5d61a), X(0x64020980), X(0x640e3a39), X(0x641a6846),
1617 X(0x642693a5), X(0x6432bc56), X(0x643ee258), X(0x644b05ab),
1618 X(0x6457264e), X(0x64634441), X(0x646f5f83), X(0x647b7814),
1619 X(0x64878df3), X(0x6493a120), X(0x649fb199), X(0x64abbf5f),
1620 X(0x64b7ca71), X(0x64c3d2ce), X(0x64cfd877), X(0x64dbdb69),
1621 X(0x64e7dba6), X(0x64f3d92b), X(0x64ffd3fa), X(0x650bcc11),
1622 X(0x6517c16f), X(0x6523b415), X(0x652fa402), X(0x653b9134),
1623 X(0x65477bad), X(0x6553636a), X(0x655f486d), X(0x656b2ab3),
1624 X(0x65770a3d), X(0x6582e70a), X(0x658ec11a), X(0x659a986d),
1625 X(0x65a66d00), X(0x65b23ed5), X(0x65be0deb), X(0x65c9da41),
1626 X(0x65d5a3d7), X(0x65e16aac), X(0x65ed2ebf), X(0x65f8f011),
1627 X(0x6604aea1), X(0x66106a6e), X(0x661c2377), X(0x6627d9be),
1628 X(0x66338d40), X(0x663f3dfd), X(0x664aebf5), X(0x66569728),
1629 X(0x66623f95), X(0x666de53b), X(0x6679881b), X(0x66852833),
1630 X(0x6690c583), X(0x669c600b), X(0x66a7f7ca), X(0x66b38cc0),
1631 X(0x66bf1eec), X(0x66caae4f), X(0x66d63ae6), X(0x66e1c4b3),
1632 X(0x66ed4bb4), X(0x66f8cfea), X(0x67045153), X(0x670fcfef),
1633 X(0x671b4bbe), X(0x6726c4bf), X(0x67323af3), X(0x673dae58),
1634 X(0x67491eee), X(0x67548cb5), X(0x675ff7ab), X(0x676b5fd2),
1635 X(0x6776c528), X(0x678227ad), X(0x678d8761), X(0x6798e443),
1636 X(0x67a43e52), X(0x67af958f), X(0x67bae9f9), X(0x67c63b8f),
1637 X(0x67d18a52), X(0x67dcd640), X(0x67e81f59), X(0x67f3659d),
1638 X(0x67fea90c), X(0x6809e9a5), X(0x68152768), X(0x68206254),
1639 X(0x682b9a68), X(0x6836cfa6), X(0x6842020b), X(0x684d3199),
1640 X(0x68585e4d), X(0x68638829), X(0x686eaf2b), X(0x6879d354),
1641 X(0x6884f4a2), X(0x68901316), X(0x689b2eb0), X(0x68a6476d),
1642 X(0x68b15d50), X(0x68bc7056), X(0x68c78080), X(0x68d28dcd),
1643 X(0x68dd983e), X(0x68e89fd0), X(0x68f3a486), X(0x68fea65d),
1644 X(0x6909a555), X(0x6914a16f), X(0x691f9aa9), X(0x692a9104),
1645 X(0x69358480), X(0x6940751b), X(0x694b62d5), X(0x69564daf),
1646 X(0x696135a7), X(0x696c1abe), X(0x6976fcf3), X(0x6981dc46),
1647 X(0x698cb8b6), X(0x69979243), X(0x69a268ed), X(0x69ad3cb4),
1648 X(0x69b80d97), X(0x69c2db96), X(0x69cda6b0), X(0x69d86ee5),
1649 X(0x69e33436), X(0x69edf6a1), X(0x69f8b626), X(0x6a0372c5),
1650 X(0x6a0e2c7e), X(0x6a18e350), X(0x6a23973c), X(0x6a2e4840),
1651 X(0x6a38f65d), X(0x6a43a191), X(0x6a4e49de), X(0x6a58ef42),
1652 X(0x6a6391be), X(0x6a6e3151), X(0x6a78cdfa), X(0x6a8367ba),
1653 X(0x6a8dfe90), X(0x6a98927c), X(0x6aa3237d), X(0x6aadb194),
1654 X(0x6ab83cc0), X(0x6ac2c500), X(0x6acd4a55), X(0x6ad7ccbf),
1655 X(0x6ae24c3c), X(0x6aecc8cd), X(0x6af74271), X(0x6b01b929),
1656 X(0x6b0c2cf4), X(0x6b169dd1), X(0x6b210bc1), X(0x6b2b76c2),
1657 X(0x6b35ded6), X(0x6b4043fc), X(0x6b4aa632), X(0x6b55057a),
1658 X(0x6b5f61d3), X(0x6b69bb3d), X(0x6b7411b7), X(0x6b7e6541),
1659 X(0x6b88b5db), X(0x6b930385), X(0x6b9d4e3f), X(0x6ba79607),
1660 X(0x6bb1dadf), X(0x6bbc1cc6), X(0x6bc65bbb), X(0x6bd097bf),
1661 X(0x6bdad0d0), X(0x6be506f0), X(0x6bef3a1d), X(0x6bf96a58),
1662 X(0x6c0397a0), X(0x6c0dc1f5), X(0x6c17e957), X(0x6c220dc6),
1663 X(0x6c2c2f41), X(0x6c364dc9), X(0x6c40695c), X(0x6c4a81fc),
1664 X(0x6c5497a7), X(0x6c5eaa5d), X(0x6c68ba1f), X(0x6c72c6eb),
1665 X(0x6c7cd0c3), X(0x6c86d7a6), X(0x6c90db92), X(0x6c9adc8a),
1666 X(0x6ca4da8b), X(0x6caed596), X(0x6cb8cdab), X(0x6cc2c2ca),
1667 X(0x6cccb4f2), X(0x6cd6a424), X(0x6ce0905e), X(0x6cea79a1),
1668 X(0x6cf45fee), X(0x6cfe4342), X(0x6d0823a0), X(0x6d120105),
1669 X(0x6d1bdb73), X(0x6d25b2e8), X(0x6d2f8765), X(0x6d3958ea),
1670 X(0x6d432777), X(0x6d4cf30a), X(0x6d56bba5), X(0x6d608147),
1671 X(0x6d6a43f0), X(0x6d7403a0), X(0x6d7dc056), X(0x6d877a13),
1672 X(0x6d9130d6), X(0x6d9ae4a0), X(0x6da4956f), X(0x6dae4345),
1673 X(0x6db7ee20), X(0x6dc19601), X(0x6dcb3ae7), X(0x6dd4dcd3),
1674 X(0x6dde7bc4), X(0x6de817bb), X(0x6df1b0b6), X(0x6dfb46b7),
1675 X(0x6e04d9bc), X(0x6e0e69c7), X(0x6e17f6d5), X(0x6e2180e9),
1676 X(0x6e2b0801), X(0x6e348c1d), X(0x6e3e0d3d), X(0x6e478b62),
1677 X(0x6e51068a), X(0x6e5a7eb7), X(0x6e63f3e7), X(0x6e6d661b),
1678 X(0x6e76d552), X(0x6e80418e), X(0x6e89aacc), X(0x6e93110f),
1679 X(0x6e9c7454), X(0x6ea5d49d), X(0x6eaf31e9), X(0x6eb88c37),
1680 X(0x6ec1e389), X(0x6ecb37de), X(0x6ed48936), X(0x6eddd790),
1681 X(0x6ee722ee), X(0x6ef06b4d), X(0x6ef9b0b0), X(0x6f02f315),
1682 X(0x6f0c327c), X(0x6f156ee6), X(0x6f1ea852), X(0x6f27dec1),
1683 X(0x6f311232), X(0x6f3a42a5), X(0x6f43701a), X(0x6f4c9a91),
1684 X(0x6f55c20a), X(0x6f5ee686), X(0x6f680803), X(0x6f712682),
1685 X(0x6f7a4203), X(0x6f835a86), X(0x6f8c700b), X(0x6f958291),
1686 X(0x6f9e921a), X(0x6fa79ea4), X(0x6fb0a830), X(0x6fb9aebd),
1687 X(0x6fc2b24c), X(0x6fcbb2dd), X(0x6fd4b06f), X(0x6fddab03),
1688 X(0x6fe6a299), X(0x6fef9730), X(0x6ff888c9), X(0x70017763),
1689 X(0x700a62ff), X(0x70134b9c), X(0x701c313b), X(0x702513dc),
1690 X(0x702df37e), X(0x7036d021), X(0x703fa9c6), X(0x7048806d),
1691 X(0x70515415), X(0x705a24bf), X(0x7062f26b), X(0x706bbd17),
1692 X(0x707484c6), X(0x707d4976), X(0x70860b28), X(0x708ec9dc),
1693 X(0x70978591), X(0x70a03e48), X(0x70a8f400), X(0x70b1a6bb),
1694 X(0x70ba5677), X(0x70c30335), X(0x70cbacf5), X(0x70d453b6),
1695 X(0x70dcf77a), X(0x70e59840), X(0x70ee3607), X(0x70f6d0d1),
1696 X(0x70ff689d), X(0x7107fd6b), X(0x71108f3b), X(0x71191e0d),
1697 X(0x7121a9e2), X(0x712a32b9), X(0x7132b892), X(0x713b3b6e),
1698 X(0x7143bb4c), X(0x714c382d), X(0x7154b211), X(0x715d28f7),
1699 X(0x71659ce0), X(0x716e0dcc), X(0x71767bbb), X(0x717ee6ac),
1700 X(0x71874ea1), X(0x718fb399), X(0x71981594), X(0x71a07493),
1701 X(0x71a8d094), X(0x71b1299a), X(0x71b97fa2), X(0x71c1d2af),
1702 X(0x71ca22bf), X(0x71d26fd2), X(0x71dab9ea), X(0x71e30106),
1703 X(0x71eb4526), X(0x71f3864a), X(0x71fbc472), X(0x7203ff9e),
1704 X(0x720c37cf), X(0x72146d05), X(0x721c9f3f), X(0x7224ce7e),
1705 X(0x722cfac2), X(0x7235240b), X(0x723d4a59), X(0x72456dad),
1706 X(0x724d8e05), X(0x7255ab63), X(0x725dc5c7), X(0x7265dd31),
1707 X(0x726df1a0), X(0x72760315), X(0x727e1191), X(0x72861d12),
1708 X(0x728e259a), X(0x72962b28), X(0x729e2dbd), X(0x72a62d59),
1709 X(0x72ae29fc), X(0x72b623a5), X(0x72be1a56), X(0x72c60e0e),
1710 X(0x72cdfece), X(0x72d5ec95), X(0x72ddd764), X(0x72e5bf3b),
1711 X(0x72eda41a), X(0x72f58601), X(0x72fd64f1), X(0x730540e9),
1712 X(0x730d19e9), X(0x7314eff3), X(0x731cc305), X(0x73249321),
1713 X(0x732c6046), X(0x73342a75), X(0x733bf1ad), X(0x7343b5ef),
1714 X(0x734b773b), X(0x73533591), X(0x735af0f2), X(0x7362a95d),
1715 X(0x736a5ed3), X(0x73721153), X(0x7379c0df), X(0x73816d76),
1716 X(0x73891719), X(0x7390bdc7), X(0x73986181), X(0x73a00247),
1717 X(0x73a7a01a), X(0x73af3af8), X(0x73b6d2e4), X(0x73be67dc),
1718 X(0x73c5f9e1), X(0x73cd88f3), X(0x73d51513), X(0x73dc9e40),
1719 X(0x73e4247c), X(0x73eba7c5), X(0x73f3281c), X(0x73faa582),
1720 X(0x74021ff7), X(0x7409977b), X(0x74110c0d), X(0x74187daf),
1721 X(0x741fec61), X(0x74275822), X(0x742ec0f3), X(0x743626d5),
1722 X(0x743d89c7), X(0x7444e9c9), X(0x744c46dd), X(0x7453a101),
1723 X(0x745af837), X(0x74624c7f), X(0x74699dd8), X(0x7470ec44),
1724 X(0x747837c2), X(0x747f8052), X(0x7486c5f5), X(0x748e08ac),
1725 X(0x74954875), X(0x749c8552), X(0x74a3bf43), X(0x74aaf648),
1726 X(0x74b22a62), X(0x74b95b90), X(0x74c089d2), X(0x74c7b52a),
1727 X(0x74cedd97), X(0x74d6031a), X(0x74dd25b2), X(0x74e44561),
1728 X(0x74eb6226), X(0x74f27c02), X(0x74f992f5), X(0x7500a6ff),
1729 X(0x7507b820), X(0x750ec659), X(0x7515d1aa), X(0x751cda14),
1730 X(0x7523df96), X(0x752ae231), X(0x7531e1e5), X(0x7538deb2),
1731 X(0x753fd89a), X(0x7546cf9b), X(0x754dc3b7), X(0x7554b4ed),
1732 X(0x755ba33e), X(0x75628eaa), X(0x75697732), X(0x75705cd5),
1733 X(0x75773f95), X(0x757e1f71), X(0x7584fc6a), X(0x758bd67f),
1734 X(0x7592adb2), X(0x75998203), X(0x75a05371), X(0x75a721fe),
1735 X(0x75adeda9), X(0x75b4b673), X(0x75bb7c5c), X(0x75c23f65),
1736 X(0x75c8ff8d), X(0x75cfbcd6), X(0x75d6773f), X(0x75dd2ec8),
1737 X(0x75e3e373), X(0x75ea953f), X(0x75f1442d), X(0x75f7f03d),
1738 X(0x75fe996f), X(0x76053fc5), X(0x760be33d), X(0x761283d8),
1739 X(0x76192197), X(0x761fbc7b), X(0x76265482), X(0x762ce9af),
1740 X(0x76337c01), X(0x763a0b78), X(0x76409814), X(0x764721d7),
1741 X(0x764da8c1), X(0x76542cd1), X(0x765aae08), X(0x76612c67),
1742 X(0x7667a7ee), X(0x766e209d), X(0x76749675), X(0x767b0975),
1743 X(0x7681799f), X(0x7687e6f3), X(0x768e5170), X(0x7694b918),
1744 X(0x769b1deb), X(0x76a17fe9), X(0x76a7df13), X(0x76ae3b68),
1745 X(0x76b494ea), X(0x76baeb98), X(0x76c13f74), X(0x76c7907c),
1746 X(0x76cddeb3), X(0x76d42a18), X(0x76da72ab), X(0x76e0b86d),
1747 X(0x76e6fb5e), X(0x76ed3b7f), X(0x76f378d0), X(0x76f9b352),
1748 X(0x76ffeb05), X(0x77061fe8), X(0x770c51fe), X(0x77128145),
1749 X(0x7718adbf), X(0x771ed76c), X(0x7724fe4c), X(0x772b225f),
1750 X(0x773143a7), X(0x77376223), X(0x773d7dd3), X(0x774396ba),
1751 X(0x7749acd5), X(0x774fc027), X(0x7755d0af), X(0x775bde6f),
1752 X(0x7761e965), X(0x7767f193), X(0x776df6fa), X(0x7773f998),
1753 X(0x7779f970), X(0x777ff681), X(0x7785f0cd), X(0x778be852),
1754 X(0x7791dd12), X(0x7797cf0d), X(0x779dbe43), X(0x77a3aab6),
1755 X(0x77a99465), X(0x77af7b50), X(0x77b55f79), X(0x77bb40e0),
1756 X(0x77c11f85), X(0x77c6fb68), X(0x77ccd48a), X(0x77d2aaec),
1757 X(0x77d87e8d), X(0x77de4f6f), X(0x77e41d92), X(0x77e9e8f5),
1758 X(0x77efb19b), X(0x77f57782), X(0x77fb3aad), X(0x7800fb1a),
1759 X(0x7806b8ca), X(0x780c73bf), X(0x78122bf7), X(0x7817e175),
1760 X(0x781d9438), X(0x78234440), X(0x7828f18f), X(0x782e9c25),
1761 X(0x78344401), X(0x7839e925), X(0x783f8b92), X(0x78452b46),
1762 X(0x784ac844), X(0x7850628b), X(0x7855fa1c), X(0x785b8ef8),
1763 X(0x7861211e), X(0x7866b090), X(0x786c3d4d), X(0x7871c757),
1764 X(0x78774ead), X(0x787cd351), X(0x78825543), X(0x7887d483),
1765 X(0x788d5111), X(0x7892caef), X(0x7898421c), X(0x789db69a),
1766 X(0x78a32868), X(0x78a89787), X(0x78ae03f8), X(0x78b36dbb),
1767 X(0x78b8d4d1), X(0x78be393a), X(0x78c39af6), X(0x78c8fa06),
1768 X(0x78ce566c), X(0x78d3b026), X(0x78d90736), X(0x78de5b9c),
1769 X(0x78e3ad58), X(0x78e8fc6c), X(0x78ee48d7), X(0x78f3929b),
1770 X(0x78f8d9b7), X(0x78fe1e2c), X(0x79035ffb), X(0x79089f24),
1771 X(0x790ddba8), X(0x79131587), X(0x79184cc2), X(0x791d8159),
1772 X(0x7922b34d), X(0x7927e29e), X(0x792d0f4d), X(0x7932395a),
1773 X(0x793760c6), X(0x793c8591), X(0x7941a7bd), X(0x7946c749),
1774 X(0x794be435), X(0x7950fe84), X(0x79561634), X(0x795b2b47),
1775 X(0x79603dbc), X(0x79654d96), X(0x796a5ad4), X(0x796f6576),
1776 X(0x79746d7e), X(0x797972eb), X(0x797e75bf), X(0x798375f9),
1777 X(0x7988739b), X(0x798d6ea5), X(0x79926717), X(0x79975cf2),
1778 X(0x799c5037), X(0x79a140e6), X(0x79a62f00), X(0x79ab1a85),
1779 X(0x79b00376), X(0x79b4e9d3), X(0x79b9cd9d), X(0x79beaed4),
1780 X(0x79c38d79), X(0x79c8698d), X(0x79cd4310), X(0x79d21a03),
1781 X(0x79d6ee66), X(0x79dbc03a), X(0x79e08f7f), X(0x79e55c36),
1782 X(0x79ea265f), X(0x79eeedfc), X(0x79f3b30c), X(0x79f87590),
1783 X(0x79fd3589), X(0x7a01f2f7), X(0x7a06addc), X(0x7a0b6636),
1784 X(0x7a101c08), X(0x7a14cf52), X(0x7a198013), X(0x7a1e2e4d),
1785 X(0x7a22da01), X(0x7a27832f), X(0x7a2c29d7), X(0x7a30cdfa),
1786 X(0x7a356f99), X(0x7a3a0eb4), X(0x7a3eab4c), X(0x7a434561),
1787 X(0x7a47dcf5), X(0x7a4c7207), X(0x7a510498), X(0x7a5594a9),
1788 X(0x7a5a223a), X(0x7a5ead4d), X(0x7a6335e0), X(0x7a67bbf6),
1789 X(0x7a6c3f8f), X(0x7a70c0ab), X(0x7a753f4b), X(0x7a79bb6f),
1790 X(0x7a7e3519), X(0x7a82ac48), X(0x7a8720fe), X(0x7a8b933b),
1791 X(0x7a9002ff), X(0x7a94704b), X(0x7a98db20), X(0x7a9d437e),
1792 X(0x7aa1a967), X(0x7aa60cd9), X(0x7aaa6dd7), X(0x7aaecc61),
1793 X(0x7ab32877), X(0x7ab7821b), X(0x7abbd94b), X(0x7ac02e0a),
1794 X(0x7ac48058), X(0x7ac8d035), X(0x7acd1da3), X(0x7ad168a1),
1795 X(0x7ad5b130), X(0x7ad9f751), X(0x7ade3b05), X(0x7ae27c4c),
1796 X(0x7ae6bb27), X(0x7aeaf796), X(0x7aef319a), X(0x7af36934),
1797 X(0x7af79e64), X(0x7afbd12c), X(0x7b00018a), X(0x7b042f81),
1798 X(0x7b085b10), X(0x7b0c8439), X(0x7b10aafc), X(0x7b14cf5a),
1799 X(0x7b18f153), X(0x7b1d10e8), X(0x7b212e1a), X(0x7b2548e9),
1800 X(0x7b296155), X(0x7b2d7761), X(0x7b318b0b), X(0x7b359c55),
1801 X(0x7b39ab3f), X(0x7b3db7cb), X(0x7b41c1f8), X(0x7b45c9c8),
1802 X(0x7b49cf3b), X(0x7b4dd251), X(0x7b51d30b), X(0x7b55d16b),
1803 X(0x7b59cd70), X(0x7b5dc71b), X(0x7b61be6d), X(0x7b65b366),
1804 X(0x7b69a608), X(0x7b6d9653), X(0x7b718447), X(0x7b756fe5),
1805 X(0x7b79592e), X(0x7b7d4022), X(0x7b8124c3), X(0x7b850710),
1806 X(0x7b88e70a), X(0x7b8cc4b3), X(0x7b90a00a), X(0x7b947911),
1807 X(0x7b984fc8), X(0x7b9c242f), X(0x7b9ff648), X(0x7ba3c612),
1808 X(0x7ba79390), X(0x7bab5ec1), X(0x7baf27a5), X(0x7bb2ee3f),
1809 X(0x7bb6b28e), X(0x7bba7493), X(0x7bbe344e), X(0x7bc1f1c1),
1810 X(0x7bc5acec), X(0x7bc965cf), X(0x7bcd1c6c), X(0x7bd0d0c3),
1811 X(0x7bd482d4), X(0x7bd832a1), X(0x7bdbe02a), X(0x7bdf8b70),
1812 X(0x7be33473), X(0x7be6db34), X(0x7bea7fb4), X(0x7bee21f4),
1813 X(0x7bf1c1f3), X(0x7bf55fb3), X(0x7bf8fb35), X(0x7bfc9479),
1814 X(0x7c002b7f), X(0x7c03c04a), X(0x7c0752d8), X(0x7c0ae32b),
1815 X(0x7c0e7144), X(0x7c11fd23), X(0x7c1586c9), X(0x7c190e36),
1816 X(0x7c1c936c), X(0x7c20166b), X(0x7c239733), X(0x7c2715c6),
1817 X(0x7c2a9224), X(0x7c2e0c4e), X(0x7c318444), X(0x7c34fa07),
1818 X(0x7c386d98), X(0x7c3bdef8), X(0x7c3f4e26), X(0x7c42bb25),
1819 X(0x7c4625f4), X(0x7c498e95), X(0x7c4cf507), X(0x7c50594c),
1820 X(0x7c53bb65), X(0x7c571b51), X(0x7c5a7913), X(0x7c5dd4aa),
1821 X(0x7c612e17), X(0x7c64855b), X(0x7c67da76), X(0x7c6b2d6a),
1822 X(0x7c6e7e37), X(0x7c71ccdd), X(0x7c75195e), X(0x7c7863ba),
1823 X(0x7c7babf1), X(0x7c7ef206), X(0x7c8235f7), X(0x7c8577c6),
1824 X(0x7c88b774), X(0x7c8bf502), X(0x7c8f306f), X(0x7c9269bd),
1825 X(0x7c95a0ec), X(0x7c98d5fe), X(0x7c9c08f2), X(0x7c9f39cb),
1826 X(0x7ca26887), X(0x7ca59528), X(0x7ca8bfb0), X(0x7cabe81d),
1827 X(0x7caf0e72), X(0x7cb232af), X(0x7cb554d4), X(0x7cb874e2),
1828 X(0x7cbb92db), X(0x7cbeaebe), X(0x7cc1c88d), X(0x7cc4e047),
1829 X(0x7cc7f5ef), X(0x7ccb0984), X(0x7cce1b08), X(0x7cd12a7b),
1830 X(0x7cd437dd), X(0x7cd74330), X(0x7cda4c74), X(0x7cdd53aa),
1831 X(0x7ce058d3), X(0x7ce35bef), X(0x7ce65cff), X(0x7ce95c04),
1832 X(0x7cec58ff), X(0x7cef53f0), X(0x7cf24cd7), X(0x7cf543b7),
1833 X(0x7cf8388f), X(0x7cfb2b60), X(0x7cfe1c2b), X(0x7d010af1),
1834 X(0x7d03f7b2), X(0x7d06e26f), X(0x7d09cb29), X(0x7d0cb1e0),
1835 X(0x7d0f9696), X(0x7d12794b), X(0x7d1559ff), X(0x7d1838b4),
1836 X(0x7d1b156a), X(0x7d1df022), X(0x7d20c8dd), X(0x7d239f9b),
1837 X(0x7d26745e), X(0x7d294725), X(0x7d2c17f1), X(0x7d2ee6c4),
1838 X(0x7d31b39f), X(0x7d347e81), X(0x7d37476b), X(0x7d3a0e5f),
1839 X(0x7d3cd35d), X(0x7d3f9665), X(0x7d425779), X(0x7d451699),
1840 X(0x7d47d3c6), X(0x7d4a8f01), X(0x7d4d484b), X(0x7d4fffa3),
1841 X(0x7d52b50c), X(0x7d556885), X(0x7d581a0f), X(0x7d5ac9ac),
1842 X(0x7d5d775c), X(0x7d60231f), X(0x7d62ccf6), X(0x7d6574e3),
1843 X(0x7d681ae6), X(0x7d6abeff), X(0x7d6d612f), X(0x7d700178),
1844 X(0x7d729fd9), X(0x7d753c54), X(0x7d77d6e9), X(0x7d7a6f9a),
1845 X(0x7d7d0666), X(0x7d7f9b4f), X(0x7d822e55), X(0x7d84bf79),
1846 X(0x7d874ebc), X(0x7d89dc1e), X(0x7d8c67a1), X(0x7d8ef144),
1847 X(0x7d91790a), X(0x7d93fef2), X(0x7d9682fd), X(0x7d99052d),
1848 X(0x7d9b8581), X(0x7d9e03fb), X(0x7da0809b), X(0x7da2fb62),
1849 X(0x7da57451), X(0x7da7eb68), X(0x7daa60a8), X(0x7dacd413),
1850 X(0x7daf45a9), X(0x7db1b56a), X(0x7db42357), X(0x7db68f71),
1851 X(0x7db8f9b9), X(0x7dbb6230), X(0x7dbdc8d6), X(0x7dc02dac),
1852 X(0x7dc290b3), X(0x7dc4f1eb), X(0x7dc75156), X(0x7dc9aef4),
1853 X(0x7dcc0ac5), X(0x7dce64cc), X(0x7dd0bd07), X(0x7dd31379),
1854 X(0x7dd56821), X(0x7dd7bb01), X(0x7dda0c1a), X(0x7ddc5b6b),
1855 X(0x7ddea8f7), X(0x7de0f4bd), X(0x7de33ebe), X(0x7de586fc),
1856 X(0x7de7cd76), X(0x7dea122e), X(0x7dec5525), X(0x7dee965a),
1857 X(0x7df0d5d0), X(0x7df31386), X(0x7df54f7e), X(0x7df789b8),
1858 X(0x7df9c235), X(0x7dfbf8f5), X(0x7dfe2dfa), X(0x7e006145),
1859 X(0x7e0292d5), X(0x7e04c2ac), X(0x7e06f0cb), X(0x7e091d32),
1860 X(0x7e0b47e1), X(0x7e0d70db), X(0x7e0f981f), X(0x7e11bdaf),
1861 X(0x7e13e18a), X(0x7e1603b3), X(0x7e182429), X(0x7e1a42ed),
1862 X(0x7e1c6001), X(0x7e1e7b64), X(0x7e209518), X(0x7e22ad1d),
1863 X(0x7e24c375), X(0x7e26d81f), X(0x7e28eb1d), X(0x7e2afc70),
1864 X(0x7e2d0c17), X(0x7e2f1a15), X(0x7e31266a), X(0x7e333115),
1865 X(0x7e353a1a), X(0x7e374177), X(0x7e39472e), X(0x7e3b4b3f),
1866 X(0x7e3d4dac), X(0x7e3f4e75), X(0x7e414d9a), X(0x7e434b1e),
1867 X(0x7e4546ff), X(0x7e474140), X(0x7e4939e0), X(0x7e4b30e2),
1868 X(0x7e4d2644), X(0x7e4f1a09), X(0x7e510c30), X(0x7e52fcbc),
1869 X(0x7e54ebab), X(0x7e56d900), X(0x7e58c4bb), X(0x7e5aaedd),
1870 X(0x7e5c9766), X(0x7e5e7e57), X(0x7e6063b2), X(0x7e624776),
1871 X(0x7e6429a5), X(0x7e660a3f), X(0x7e67e945), X(0x7e69c6b8),
1872 X(0x7e6ba299), X(0x7e6d7ce7), X(0x7e6f55a5), X(0x7e712cd3),
1873 X(0x7e730272), X(0x7e74d682), X(0x7e76a904), X(0x7e7879f9),
1874 X(0x7e7a4962), X(0x7e7c173f), X(0x7e7de392), X(0x7e7fae5a),
1875 X(0x7e817799), X(0x7e833f50), X(0x7e85057f), X(0x7e86ca27),
1876 X(0x7e888d49), X(0x7e8a4ee5), X(0x7e8c0efd), X(0x7e8dcd91),
1877 X(0x7e8f8aa1), X(0x7e914630), X(0x7e93003c), X(0x7e94b8c8),
1878 X(0x7e966fd4), X(0x7e982560), X(0x7e99d96e), X(0x7e9b8bfe),
1879 X(0x7e9d3d10), X(0x7e9eeca7), X(0x7ea09ac2), X(0x7ea24762),
1880 X(0x7ea3f288), X(0x7ea59c35), X(0x7ea7446a), X(0x7ea8eb27),
1881 X(0x7eaa906c), X(0x7eac343c), X(0x7eadd696), X(0x7eaf777b),
1882 X(0x7eb116ed), X(0x7eb2b4eb), X(0x7eb45177), X(0x7eb5ec91),
1883 X(0x7eb7863b), X(0x7eb91e74), X(0x7ebab53e), X(0x7ebc4a99),
1884 X(0x7ebdde87), X(0x7ebf7107), X(0x7ec1021b), X(0x7ec291c3),
1885 X(0x7ec42001), X(0x7ec5acd5), X(0x7ec7383f), X(0x7ec8c241),
1886 X(0x7eca4adb), X(0x7ecbd20d), X(0x7ecd57da), X(0x7ecedc41),
1887 X(0x7ed05f44), X(0x7ed1e0e2), X(0x7ed3611d), X(0x7ed4dff6),
1888 X(0x7ed65d6d), X(0x7ed7d983), X(0x7ed95438), X(0x7edacd8f),
1889 X(0x7edc4586), X(0x7eddbc20), X(0x7edf315c), X(0x7ee0a53c),
1890 X(0x7ee217c1), X(0x7ee388ea), X(0x7ee4f8b9), X(0x7ee6672f),
1891 X(0x7ee7d44c), X(0x7ee94012), X(0x7eeaaa80), X(0x7eec1397),
1892 X(0x7eed7b59), X(0x7eeee1c6), X(0x7ef046df), X(0x7ef1aaa5),
1893 X(0x7ef30d18), X(0x7ef46e39), X(0x7ef5ce09), X(0x7ef72c88),
1894 X(0x7ef889b8), X(0x7ef9e599), X(0x7efb402c), X(0x7efc9972),
1895 X(0x7efdf16b), X(0x7eff4818), X(0x7f009d79), X(0x7f01f191),
1896 X(0x7f03445f), X(0x7f0495e4), X(0x7f05e620), X(0x7f073516),
1897 X(0x7f0882c5), X(0x7f09cf2d), X(0x7f0b1a51), X(0x7f0c6430),
1898 X(0x7f0daccc), X(0x7f0ef425), X(0x7f103a3b), X(0x7f117f11),
1899 X(0x7f12c2a5), X(0x7f1404fa), X(0x7f15460f), X(0x7f1685e6),
1900 X(0x7f17c47f), X(0x7f1901db), X(0x7f1a3dfb), X(0x7f1b78e0),
1901 X(0x7f1cb28a), X(0x7f1deafa), X(0x7f1f2231), X(0x7f20582f),
1902 X(0x7f218cf5), X(0x7f22c085), X(0x7f23f2de), X(0x7f252401),
1903 X(0x7f2653f0), X(0x7f2782ab), X(0x7f28b032), X(0x7f29dc87),
1904 X(0x7f2b07aa), X(0x7f2c319c), X(0x7f2d5a5e), X(0x7f2e81f0),
1905 X(0x7f2fa853), X(0x7f30cd88), X(0x7f31f18f), X(0x7f33146a),
1906 X(0x7f343619), X(0x7f35569c), X(0x7f3675f6), X(0x7f379425),
1907 X(0x7f38b12c), X(0x7f39cd0a), X(0x7f3ae7c0), X(0x7f3c0150),
1908 X(0x7f3d19ba), X(0x7f3e30fe), X(0x7f3f471e), X(0x7f405c1a),
1909 X(0x7f416ff3), X(0x7f4282a9), X(0x7f43943e), X(0x7f44a4b2),
1910 X(0x7f45b405), X(0x7f46c239), X(0x7f47cf4e), X(0x7f48db45),
1911 X(0x7f49e61f), X(0x7f4aefdc), X(0x7f4bf87e), X(0x7f4d0004),
1912 X(0x7f4e0670), X(0x7f4f0bc2), X(0x7f500ffb), X(0x7f51131c),
1913 X(0x7f521525), X(0x7f531618), X(0x7f5415f4), X(0x7f5514bb),
1914 X(0x7f56126e), X(0x7f570f0c), X(0x7f580a98), X(0x7f590511),
1915 X(0x7f59fe78), X(0x7f5af6ce), X(0x7f5bee14), X(0x7f5ce44a),
1916 X(0x7f5dd972), X(0x7f5ecd8b), X(0x7f5fc097), X(0x7f60b296),
1917 X(0x7f61a389), X(0x7f629370), X(0x7f63824e), X(0x7f647021),
1918 X(0x7f655ceb), X(0x7f6648ad), X(0x7f673367), X(0x7f681d19),
1919 X(0x7f6905c6), X(0x7f69ed6d), X(0x7f6ad40f), X(0x7f6bb9ad),
1920 X(0x7f6c9e48), X(0x7f6d81e0), X(0x7f6e6475), X(0x7f6f460a),
1921 X(0x7f70269d), X(0x7f710631), X(0x7f71e4c6), X(0x7f72c25c),
1922 X(0x7f739ef4), X(0x7f747a8f), X(0x7f75552e), X(0x7f762ed1),
1923 X(0x7f770779), X(0x7f77df27), X(0x7f78b5db), X(0x7f798b97),
1924 X(0x7f7a605a), X(0x7f7b3425), X(0x7f7c06fa), X(0x7f7cd8d9),
1925 X(0x7f7da9c2), X(0x7f7e79b7), X(0x7f7f48b8), X(0x7f8016c5),
1926 X(0x7f80e3e0), X(0x7f81b009), X(0x7f827b40), X(0x7f834588),
1927 X(0x7f840edf), X(0x7f84d747), X(0x7f859ec1), X(0x7f86654d),
1928 X(0x7f872aec), X(0x7f87ef9e), X(0x7f88b365), X(0x7f897641),
1929 X(0x7f8a3832), X(0x7f8af93a), X(0x7f8bb959), X(0x7f8c7890),
1930 X(0x7f8d36df), X(0x7f8df448), X(0x7f8eb0ca), X(0x7f8f6c67),
1931 X(0x7f90271e), X(0x7f90e0f2), X(0x7f9199e2), X(0x7f9251f0),
1932 X(0x7f93091b), X(0x7f93bf65), X(0x7f9474ce), X(0x7f952958),
1933 X(0x7f95dd01), X(0x7f968fcd), X(0x7f9741ba), X(0x7f97f2ca),
1934 X(0x7f98a2fd), X(0x7f995254), X(0x7f9a00d0), X(0x7f9aae71),
1935 X(0x7f9b5b38), X(0x7f9c0726), X(0x7f9cb23b), X(0x7f9d5c78),
1936 X(0x7f9e05de), X(0x7f9eae6e), X(0x7f9f5627), X(0x7f9ffd0b),
1937 X(0x7fa0a31b), X(0x7fa14856), X(0x7fa1ecbf), X(0x7fa29054),
1938 X(0x7fa33318), X(0x7fa3d50b), X(0x7fa4762c), X(0x7fa5167e),
1939 X(0x7fa5b601), X(0x7fa654b5), X(0x7fa6f29b), X(0x7fa78fb3),
1940 X(0x7fa82bff), X(0x7fa8c77f), X(0x7fa96234), X(0x7fa9fc1e),
1941 X(0x7faa953e), X(0x7fab2d94), X(0x7fabc522), X(0x7fac5be8),
1942 X(0x7facf1e6), X(0x7fad871d), X(0x7fae1b8f), X(0x7faeaf3b),
1943 X(0x7faf4222), X(0x7fafd445), X(0x7fb065a4), X(0x7fb0f641),
1944 X(0x7fb1861b), X(0x7fb21534), X(0x7fb2a38c), X(0x7fb33124),
1945 X(0x7fb3bdfb), X(0x7fb44a14), X(0x7fb4d56f), X(0x7fb5600c),
1946 X(0x7fb5e9ec), X(0x7fb6730f), X(0x7fb6fb76), X(0x7fb78323),
1947 X(0x7fb80a15), X(0x7fb8904d), X(0x7fb915cc), X(0x7fb99a92),
1948 X(0x7fba1ea0), X(0x7fbaa1f7), X(0x7fbb2497), X(0x7fbba681),
1949 X(0x7fbc27b5), X(0x7fbca835), X(0x7fbd2801), X(0x7fbda719),
1950 X(0x7fbe257e), X(0x7fbea331), X(0x7fbf2032), X(0x7fbf9c82),
1951 X(0x7fc01821), X(0x7fc09311), X(0x7fc10d52), X(0x7fc186e4),
1952 X(0x7fc1ffc8), X(0x7fc277ff), X(0x7fc2ef89), X(0x7fc36667),
1953 X(0x7fc3dc9a), X(0x7fc45221), X(0x7fc4c6ff), X(0x7fc53b33),
1954 X(0x7fc5aebe), X(0x7fc621a0), X(0x7fc693db), X(0x7fc7056f),
1955 X(0x7fc7765c), X(0x7fc7e6a3), X(0x7fc85645), X(0x7fc8c542),
1956 X(0x7fc9339b), X(0x7fc9a150), X(0x7fca0e63), X(0x7fca7ad3),
1957 X(0x7fcae6a2), X(0x7fcb51cf), X(0x7fcbbc5c), X(0x7fcc2649),
1958 X(0x7fcc8f97), X(0x7fccf846), X(0x7fcd6058), X(0x7fcdc7cb),
1959 X(0x7fce2ea2), X(0x7fce94dd), X(0x7fcefa7b), X(0x7fcf5f7f),
1960 X(0x7fcfc3e8), X(0x7fd027b7), X(0x7fd08aed), X(0x7fd0ed8b),
1961 X(0x7fd14f90), X(0x7fd1b0fd), X(0x7fd211d4), X(0x7fd27214),
1962 X(0x7fd2d1bf), X(0x7fd330d4), X(0x7fd38f55), X(0x7fd3ed41),
1963 X(0x7fd44a9a), X(0x7fd4a761), X(0x7fd50395), X(0x7fd55f37),
1964 X(0x7fd5ba48), X(0x7fd614c9), X(0x7fd66eba), X(0x7fd6c81b),
1965 X(0x7fd720ed), X(0x7fd77932), X(0x7fd7d0e8), X(0x7fd82812),
1966 X(0x7fd87eae), X(0x7fd8d4bf), X(0x7fd92a45), X(0x7fd97f40),
1967 X(0x7fd9d3b0), X(0x7fda2797), X(0x7fda7af5), X(0x7fdacdca),
1968 X(0x7fdb2018), X(0x7fdb71dd), X(0x7fdbc31c), X(0x7fdc13d5),
1969 X(0x7fdc6408), X(0x7fdcb3b6), X(0x7fdd02df), X(0x7fdd5184),
1970 X(0x7fdd9fa5), X(0x7fdded44), X(0x7fde3a60), X(0x7fde86fb),
1971 X(0x7fded314), X(0x7fdf1eac), X(0x7fdf69c4), X(0x7fdfb45d),
1972 X(0x7fdffe76), X(0x7fe04811), X(0x7fe0912e), X(0x7fe0d9ce),
1973 X(0x7fe121f0), X(0x7fe16996), X(0x7fe1b0c1), X(0x7fe1f770),
1974 X(0x7fe23da4), X(0x7fe2835f), X(0x7fe2c89f), X(0x7fe30d67),
1975 X(0x7fe351b5), X(0x7fe3958c), X(0x7fe3d8ec), X(0x7fe41bd4),
1976 X(0x7fe45e46), X(0x7fe4a042), X(0x7fe4e1c8), X(0x7fe522da),
1977 X(0x7fe56378), X(0x7fe5a3a1), X(0x7fe5e358), X(0x7fe6229b),
1978 X(0x7fe6616d), X(0x7fe69fcc), X(0x7fe6ddbb), X(0x7fe71b39),
1979 X(0x7fe75847), X(0x7fe794e5), X(0x7fe7d114), X(0x7fe80cd5),
1980 X(0x7fe84827), X(0x7fe8830c), X(0x7fe8bd84), X(0x7fe8f78f),
1981 X(0x7fe9312f), X(0x7fe96a62), X(0x7fe9a32b), X(0x7fe9db8a),
1982 X(0x7fea137e), X(0x7fea4b09), X(0x7fea822b), X(0x7feab8e5),
1983 X(0x7feaef37), X(0x7feb2521), X(0x7feb5aa4), X(0x7feb8fc1),
1984 X(0x7febc478), X(0x7febf8ca), X(0x7fec2cb6), X(0x7fec603e),
1985 X(0x7fec9363), X(0x7fecc623), X(0x7fecf881), X(0x7fed2a7c),
1986 X(0x7fed5c16), X(0x7fed8d4e), X(0x7fedbe24), X(0x7fedee9b),
1987 X(0x7fee1eb1), X(0x7fee4e68), X(0x7fee7dc0), X(0x7feeacb9),
1988 X(0x7feedb54), X(0x7fef0991), X(0x7fef3771), X(0x7fef64f5),
1989 X(0x7fef921d), X(0x7fefbee8), X(0x7fefeb59), X(0x7ff0176f),
1990 X(0x7ff0432a), X(0x7ff06e8c), X(0x7ff09995), X(0x7ff0c444),
1991 X(0x7ff0ee9c), X(0x7ff1189b), X(0x7ff14243), X(0x7ff16b94),
1992 X(0x7ff1948e), X(0x7ff1bd32), X(0x7ff1e581), X(0x7ff20d7b),
1993 X(0x7ff2351f), X(0x7ff25c70), X(0x7ff2836d), X(0x7ff2aa17),
1994 X(0x7ff2d06d), X(0x7ff2f672), X(0x7ff31c24), X(0x7ff34185),
1995 X(0x7ff36695), X(0x7ff38b55), X(0x7ff3afc4), X(0x7ff3d3e4),
1996 X(0x7ff3f7b4), X(0x7ff41b35), X(0x7ff43e69), X(0x7ff4614e),
1997 X(0x7ff483e6), X(0x7ff4a631), X(0x7ff4c82f), X(0x7ff4e9e1),
1998 X(0x7ff50b47), X(0x7ff52c62), X(0x7ff54d33), X(0x7ff56db9),
1999 X(0x7ff58df5), X(0x7ff5ade7), X(0x7ff5cd90), X(0x7ff5ecf1),
2000 X(0x7ff60c09), X(0x7ff62ada), X(0x7ff64963), X(0x7ff667a5),
2001 X(0x7ff685a1), X(0x7ff6a357), X(0x7ff6c0c7), X(0x7ff6ddf1),
2002 X(0x7ff6fad7), X(0x7ff71778), X(0x7ff733d6), X(0x7ff74fef),
2003 X(0x7ff76bc6), X(0x7ff78759), X(0x7ff7a2ab), X(0x7ff7bdba),
2004 X(0x7ff7d888), X(0x7ff7f315), X(0x7ff80d61), X(0x7ff8276c),
2005 X(0x7ff84138), X(0x7ff85ac4), X(0x7ff87412), X(0x7ff88d20),
2006 X(0x7ff8a5f0), X(0x7ff8be82), X(0x7ff8d6d7), X(0x7ff8eeef),
2007 X(0x7ff906c9), X(0x7ff91e68), X(0x7ff935cb), X(0x7ff94cf2),
2008 X(0x7ff963dd), X(0x7ff97a8f), X(0x7ff99105), X(0x7ff9a742),
2009 X(0x7ff9bd45), X(0x7ff9d30f), X(0x7ff9e8a0), X(0x7ff9fdf9),
2010 X(0x7ffa131a), X(0x7ffa2803), X(0x7ffa3cb4), X(0x7ffa512f),
2011 X(0x7ffa6573), X(0x7ffa7981), X(0x7ffa8d59), X(0x7ffaa0fc),
2012 X(0x7ffab46a), X(0x7ffac7a3), X(0x7ffadaa8), X(0x7ffaed78),
2013 X(0x7ffb0015), X(0x7ffb127f), X(0x7ffb24b6), X(0x7ffb36bb),
2014 X(0x7ffb488d), X(0x7ffb5a2e), X(0x7ffb6b9d), X(0x7ffb7cdb),
2015 X(0x7ffb8de9), X(0x7ffb9ec6), X(0x7ffbaf73), X(0x7ffbbff1),
2016 X(0x7ffbd03f), X(0x7ffbe05e), X(0x7ffbf04f), X(0x7ffc0012),
2017 X(0x7ffc0fa6), X(0x7ffc1f0d), X(0x7ffc2e47), X(0x7ffc3d54),
2018 X(0x7ffc4c35), X(0x7ffc5ae9), X(0x7ffc6971), X(0x7ffc77ce),
2019 X(0x7ffc8600), X(0x7ffc9407), X(0x7ffca1e4), X(0x7ffcaf96),
2020 X(0x7ffcbd1f), X(0x7ffcca7e), X(0x7ffcd7b4), X(0x7ffce4c1),
2021 X(0x7ffcf1a5), X(0x7ffcfe62), X(0x7ffd0af6), X(0x7ffd1763),
2022 X(0x7ffd23a9), X(0x7ffd2fc8), X(0x7ffd3bc1), X(0x7ffd4793),
2023 X(0x7ffd533f), X(0x7ffd5ec5), X(0x7ffd6a27), X(0x7ffd7563),
2024 X(0x7ffd807a), X(0x7ffd8b6e), X(0x7ffd963d), X(0x7ffda0e8),
2025 X(0x7ffdab70), X(0x7ffdb5d5), X(0x7ffdc017), X(0x7ffdca36),
2026 X(0x7ffdd434), X(0x7ffdde0f), X(0x7ffde7c9), X(0x7ffdf161),
2027 X(0x7ffdfad8), X(0x7ffe042f), X(0x7ffe0d65), X(0x7ffe167b),
2028 X(0x7ffe1f71), X(0x7ffe2848), X(0x7ffe30ff), X(0x7ffe3997),
2029 X(0x7ffe4211), X(0x7ffe4a6c), X(0x7ffe52a9), X(0x7ffe5ac8),
2030 X(0x7ffe62c9), X(0x7ffe6aae), X(0x7ffe7275), X(0x7ffe7a1f),
2031 X(0x7ffe81ad), X(0x7ffe891f), X(0x7ffe9075), X(0x7ffe97b0),
2032 X(0x7ffe9ece), X(0x7ffea5d2), X(0x7ffeacbb), X(0x7ffeb38a),
2033 X(0x7ffeba3e), X(0x7ffec0d8), X(0x7ffec758), X(0x7ffecdbf),
2034 X(0x7ffed40d), X(0x7ffeda41), X(0x7ffee05d), X(0x7ffee660),
2035 X(0x7ffeec4b), X(0x7ffef21f), X(0x7ffef7da), X(0x7ffefd7e),
2036 X(0x7fff030b), X(0x7fff0881), X(0x7fff0de0), X(0x7fff1328),
2037 X(0x7fff185b), X(0x7fff1d77), X(0x7fff227e), X(0x7fff276f),
2038 X(0x7fff2c4b), X(0x7fff3112), X(0x7fff35c4), X(0x7fff3a62),
2039 X(0x7fff3eeb), X(0x7fff4360), X(0x7fff47c2), X(0x7fff4c0f),
2040 X(0x7fff504a), X(0x7fff5471), X(0x7fff5885), X(0x7fff5c87),
2041 X(0x7fff6076), X(0x7fff6452), X(0x7fff681d), X(0x7fff6bd6),
2042 X(0x7fff6f7d), X(0x7fff7313), X(0x7fff7698), X(0x7fff7a0c),
2043 X(0x7fff7d6f), X(0x7fff80c2), X(0x7fff8404), X(0x7fff8736),
2044 X(0x7fff8a58), X(0x7fff8d6b), X(0x7fff906e), X(0x7fff9362),
2045 X(0x7fff9646), X(0x7fff991c), X(0x7fff9be3), X(0x7fff9e9c),
2046 X(0x7fffa146), X(0x7fffa3e2), X(0x7fffa671), X(0x7fffa8f1),
2047 X(0x7fffab65), X(0x7fffadca), X(0x7fffb023), X(0x7fffb26f),
2048 X(0x7fffb4ae), X(0x7fffb6e0), X(0x7fffb906), X(0x7fffbb20),
2049 X(0x7fffbd2e), X(0x7fffbf30), X(0x7fffc126), X(0x7fffc311),
2050 X(0x7fffc4f1), X(0x7fffc6c5), X(0x7fffc88f), X(0x7fffca4d),
2051 X(0x7fffcc01), X(0x7fffcdab), X(0x7fffcf4a), X(0x7fffd0e0),
2052 X(0x7fffd26b), X(0x7fffd3ec), X(0x7fffd564), X(0x7fffd6d2),
2053 X(0x7fffd838), X(0x7fffd993), X(0x7fffdae6), X(0x7fffdc31),
2054 X(0x7fffdd72), X(0x7fffdeab), X(0x7fffdfdb), X(0x7fffe104),
2055 X(0x7fffe224), X(0x7fffe33c), X(0x7fffe44d), X(0x7fffe556),
2056 X(0x7fffe657), X(0x7fffe751), X(0x7fffe844), X(0x7fffe930),
2057 X(0x7fffea15), X(0x7fffeaf3), X(0x7fffebca), X(0x7fffec9b),
2058 X(0x7fffed66), X(0x7fffee2a), X(0x7fffeee8), X(0x7fffefa0),
2059 X(0x7ffff053), X(0x7ffff0ff), X(0x7ffff1a6), X(0x7ffff247),
2060 X(0x7ffff2e4), X(0x7ffff37a), X(0x7ffff40c), X(0x7ffff499),
2061 X(0x7ffff520), X(0x7ffff5a3), X(0x7ffff621), X(0x7ffff69b),
2062 X(0x7ffff710), X(0x7ffff781), X(0x7ffff7ee), X(0x7ffff857),
2063 X(0x7ffff8bb), X(0x7ffff91c), X(0x7ffff979), X(0x7ffff9d2),
2064 X(0x7ffffa27), X(0x7ffffa79), X(0x7ffffac8), X(0x7ffffb13),
2065 X(0x7ffffb5b), X(0x7ffffba0), X(0x7ffffbe2), X(0x7ffffc21),
2066 X(0x7ffffc5d), X(0x7ffffc96), X(0x7ffffccd), X(0x7ffffd01),
2067 X(0x7ffffd32), X(0x7ffffd61), X(0x7ffffd8e), X(0x7ffffdb8),
2068 X(0x7ffffde0), X(0x7ffffe07), X(0x7ffffe2b), X(0x7ffffe4d),
2069 X(0x7ffffe6d), X(0x7ffffe8b), X(0x7ffffea8), X(0x7ffffec3),
2070 X(0x7ffffedc), X(0x7ffffef4), X(0x7fffff0a), X(0x7fffff1f),
2071 X(0x7fffff33), X(0x7fffff45), X(0x7fffff56), X(0x7fffff66),
2072 X(0x7fffff75), X(0x7fffff82), X(0x7fffff8f), X(0x7fffff9a),
2073 X(0x7fffffa5), X(0x7fffffaf), X(0x7fffffb8), X(0x7fffffc0),
2074 X(0x7fffffc8), X(0x7fffffce), X(0x7fffffd5), X(0x7fffffda),
2075 X(0x7fffffdf), X(0x7fffffe4), X(0x7fffffe8), X(0x7fffffeb),
2076 X(0x7fffffef), X(0x7ffffff1), X(0x7ffffff4), X(0x7ffffff6),
2077 X(0x7ffffff8), X(0x7ffffff9), X(0x7ffffffb), X(0x7ffffffc),
2078 X(0x7ffffffd), X(0x7ffffffd), X(0x7ffffffe), X(0x7fffffff),
2079 X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff),
2080 X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff),
2081 X(0x7fffffff), X(0x7fffffff), X(0x7fffffff), X(0x7fffffff),
2082 };
2083
0 /*************************************************************************
1 *
2 * $Id: trio.c,v 1.129 2009/09/20 11:37:15 breese Exp $
3 *
4 * Copyright (C) 1998, 2009 Bjorn Reese and Daniel Stenberg.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
14 *
15 *************************************************************************
16 *
17 * A note to trio contributors:
18 *
19 * Avoid heap allocation at all costs to ensure that the trio functions
20 * are async-safe. The exceptions are the printf/fprintf functions, which
21 * uses fputc, and the asprintf functions and the <alloc> modifier, which
22 * by design are required to allocate form the heap.
23 *
24 ************************************************************************/
25
26 /*
27 * TODO:
28 * - Scan is probably too permissive about its modifiers.
29 * - C escapes in %#[] ?
30 * - Multibyte characters (done for format parsing, except scan groups)
31 * - Complex numbers? (C99 _Complex)
32 * - Boolean values? (C99 _Bool)
33 * - C99 NaN(n-char-sequence) missing. The n-char-sequence can be used
34 * to print the mantissa, e.g. NaN(0xc000000000000000)
35 * - Should we support the GNU %a alloc modifier? GNU has an ugly hack
36 * for %a, because C99 used %a for other purposes. If specified as
37 * %as or %a[ it is interpreted as the alloc modifier, otherwise as
38 * the C99 hex-float. This means that you cannot scan %as as a hex-float
39 * immediately followed by an 's'.
40 * - Scanning of collating symbols.
41 */
42
43 /*************************************************************************
44 * Trio include files
45 */
46 #include "../include/trio/triodef.h"
47 #include "../include/trio/trio.h"
48 #include "../include/trio/triop.h"
49
50 #ifdef _WIN32
51 #include <direct.h>
52 #else
53 #include <unistd.h>
54 #endif
55
56 #if defined(TRIO_EMBED_NAN)
57 # define TRIO_PUBLIC_NAN static
58 #endif
59 #include "../include/trio/trionan.h"
60
61 #if defined(TRIO_EMBED_STRING)
62 # define TRIO_PUBLIC_STRING static
63 # define TRIO_FUNC_LENGTH
64 # define TRIO_FUNC_LENGTH_MAX
65 # define TRIO_FUNC_TO_LONG
66 # if TRIO_FEATURE_DYNAMICSTRING
67 # define TRIO_FUNC_XSTRING_DUPLICATE
68 # endif
69 # if TRIO_FEATURE_ERRNO
70 # define TRIO_FUNC_ERROR
71 # endif
72 # if TRIO_FEATURE_DYNAMICSTRING
73 # define TRIO_FUNC_STRING_EXTRACT
74 # endif
75 # if TRIO_FEATURE_DYNAMICSTRING
76 # define TRIO_FUNC_STRING_TERMINATE
77 # endif
78 # if TRIO_FEATURE_USER_DEFINED
79 # define TRIO_FUNC_DUPLICATE
80 # endif
81 # if TRIO_FEATURE_DYNAMICSTRING
82 # define TRIO_FUNC_STRING_DESTROY
83 # endif
84 # if TRIO_FEATURE_USER_DEFINED
85 # define TRIO_FUNC_DESTROY
86 # endif
87 # if TRIO_FEATURE_USER_DEFINED
88 # define TRIO_FUNC_EQUAL
89 # endif
90 # if TRIO_FEATURE_USER_DEFINED || TRIO_FEATURE_SCANF
91 # define TRIO_FUNC_EQUAL_CASE
92 # endif
93 # if TRIO_FEATURE_SCANF
94 # define TRIO_FUNC_TO_UPPER
95 # endif
96 # if TRIO_FEATURE_DYNAMICSTRING
97 # define TRIO_FUNC_XSTRING_APPEND_CHAR
98 # endif
99 #endif
100 #include "../include/trio/triostr.h"
101
102 /**************************************************************************
103 *
104 * Definitions
105 *
106 *************************************************************************/
107
108 #include <limits.h>
109
110 #if defined(__STDC_ISO_10646__) || defined(MB_LEN_MAX) || defined(USE_MULTIBYTE) || TRIO_FEATURE_WIDECHAR
111 # if !defined(TRIO_PLATFORM_WINCE) && !defined(ANDROID)
112 # define TRIO_COMPILER_SUPPORTS_MULTIBYTE
113 # if !defined(MB_LEN_MAX)
114 # define MB_LEN_MAX 6
115 # endif
116 # endif
117 #endif
118
119 #if (TRIO_COMPILER_VISUALC - 0 >= 1100) || defined(TRIO_COMPILER_BORLAND)
120 # define TRIO_COMPILER_SUPPORTS_VISUALC_INT
121 #endif
122
123 /*************************************************************************
124 * Generic definitions
125 */
126
127 #if !(defined(DEBUG) || defined(NDEBUG))
128 # define NDEBUG
129 #endif
130
131 #include <assert.h>
132 #include <ctype.h>
133 #if defined(PREDEF_STANDARD_C99) && !defined(isascii)
134 # define isascii(x) ((x) & 0x7F)
135 #endif
136 #if defined(TRIO_COMPILER_ANCIENT)
137 # include <varargs.h>
138 #else
139 # include <stdarg.h>
140 #endif
141 #include <stddef.h>
142 #if defined(TRIO_PLATFORM_WINCE)
143 extern int errno;
144 #else
145 # include <errno.h>
146 #endif
147
148 #ifndef NULL
149 # define NULL 0
150 #endif
151 #define NIL ((char)0)
152 #ifndef FALSE
153 # define FALSE (1 == 0)
154 # define TRUE (! FALSE)
155 #endif
156 #define BOOLEAN_T int
157
158 /* mincore() can be used for debugging purposes */
159 #define VALID(x) (NULL != (x))
160
161 #if TRIO_FEATURE_ERRORCODE
162 /*
163 * Encode the error code and the position. This is decoded
164 * with TRIO_ERROR_CODE and TRIO_ERROR_POSITION.
165 */
166 # define TRIO_ERROR_RETURN(x,y) (- ((x) + ((y) << 8)))
167 #else
168 # define TRIO_ERROR_RETURN(x,y) (-1)
169 #endif
170
171 typedef unsigned long trio_flags_t;
172
173
174 /*************************************************************************
175 * Platform specific definitions
176 */
177 #if defined(TRIO_PLATFORM_WIN32)
178 # if defined(TRIO_PLATFORM_WINCE)
179 int read(int handle, char *buffer, unsigned int length);
180 int write(int handle, const char *buffer, unsigned int length);
181 # else
182 # include <io.h>
183 # define read _read
184 # define write _write
185 # endif
186 #endif /* TRIO_PLATFORM_WIN32 */
187
188 #if TRIO_FEATURE_WIDECHAR
189 # if defined(PREDEF_STANDARD_C94)
190 # include <wchar.h>
191 # include <wctype.h>
192 typedef wchar_t trio_wchar_t;
193 typedef wint_t trio_wint_t;
194 # else
195 typedef char trio_wchar_t;
196 typedef int trio_wint_t;
197 # define WCONST(x) L ## x
198 # define WEOF EOF
199 # define iswalnum(x) isalnum(x)
200 # define iswalpha(x) isalpha(x)
201 # define iswcntrl(x) iscntrl(x)
202 # define iswdigit(x) isdigit(x)
203 # define iswgraph(x) isgraph(x)
204 # define iswlower(x) islower(x)
205 # define iswprint(x) isprint(x)
206 # define iswpunct(x) ispunct(x)
207 # define iswspace(x) isspace(x)
208 # define iswupper(x) isupper(x)
209 # define iswxdigit(x) isxdigit(x)
210 # endif
211 #endif
212
213
214 /*************************************************************************
215 * Compiler dependent definitions
216 */
217
218 /* Support for long long */
219 #ifndef __cplusplus
220 # if !defined(USE_LONGLONG)
221 # if defined(TRIO_COMPILER_GCC) && !defined(__STRICT_ANSI__)
222 # define USE_LONGLONG
223 # else
224 # if defined(TRIO_COMPILER_SUNPRO)
225 # define USE_LONGLONG
226 # else
227 # if defined(TRIO_COMPILER_MSVC) && (_MSC_VER >= 1400)
228 # define USE_LONGLONG
229 # else
230 # if defined(_LONG_LONG) || defined(_LONGLONG)
231 # define USE_LONGLONG
232 # endif
233 # endif
234 # endif
235 # endif
236 # endif
237 #endif
238
239 /* The extra long numbers */
240 #if defined(USE_LONGLONG)
241 typedef signed long long int trio_longlong_t;
242 typedef unsigned long long int trio_ulonglong_t;
243 #else
244 # if defined(TRIO_COMPILER_SUPPORTS_VISUALC_INT)
245 typedef signed __int64 trio_longlong_t;
246 typedef unsigned __int64 trio_ulonglong_t;
247 # else
248 typedef TRIO_SIGNED long int trio_longlong_t;
249 typedef unsigned long int trio_ulonglong_t;
250 # endif
251 #endif
252
253 /* Maximal and fixed integer types */
254 #if defined(PREDEF_STANDARD_C99)
255 # include <stdint.h>
256 typedef intmax_t trio_intmax_t;
257 typedef uintmax_t trio_uintmax_t;
258 typedef int8_t trio_int8_t;
259 typedef int16_t trio_int16_t;
260 typedef int32_t trio_int32_t;
261 typedef int64_t trio_int64_t;
262 #else
263 # if defined(PREDEF_STANDARD_UNIX98)
264 # include <inttypes.h>
265 typedef intmax_t trio_intmax_t;
266 typedef uintmax_t trio_uintmax_t;
267 typedef int8_t trio_int8_t;
268 typedef int16_t trio_int16_t;
269 typedef int32_t trio_int32_t;
270 typedef int64_t trio_int64_t;
271 # else
272 # if defined(TRIO_COMPILER_SUPPORTS_VISUALC_INT)
273 typedef trio_longlong_t trio_intmax_t;
274 typedef trio_ulonglong_t trio_uintmax_t;
275 typedef __int8 trio_int8_t;
276 typedef __int16 trio_int16_t;
277 typedef __int32 trio_int32_t;
278 typedef __int64 trio_int64_t;
279 # else
280 typedef trio_longlong_t trio_intmax_t;
281 typedef trio_ulonglong_t trio_uintmax_t;
282 # if defined(TRIO_INT8_T)
283 typedef TRIO_INT8_T trio_int8_t;
284 # else
285 typedef TRIO_SIGNED char trio_int8_t;
286 # endif
287 # if defined(TRIO_INT16_T)
288 typedef TRIO_INT16_T trio_int16_t;
289 # else
290 typedef TRIO_SIGNED short trio_int16_t;
291 # endif
292 # if defined(TRIO_INT32_T)
293 typedef TRIO_INT32_T trio_int32_t;
294 # else
295 typedef TRIO_SIGNED int trio_int32_t;
296 # endif
297 # if defined(TRIO_INT64_T)
298 typedef TRIO_INT64_T trio_int64_t;
299 # else
300 typedef trio_longlong_t trio_int64_t;
301 # endif
302 # endif
303 # endif
304 #endif
305
306 #if defined(HAVE_FLOORL)
307 # define trio_floor(x) floorl((x))
308 #else
309 # define trio_floor(x) floor((double)(x))
310 #endif
311
312 #if defined(HAVE_CEILL)
313 # define trio_ceil(x) ceill((x))
314 #else
315 # define trio_ceil(x) ceil((double)(x))
316 #endif
317
318 #if defined(HAVE_FMODL)
319 # define trio_fmod(x,y) fmodl((x),(y))
320 #else
321 # define trio_fmod(x,y) fmod((double)(x),(double)(y))
322 #endif
323
324 #if defined(HAVE_POWL)
325 # define trio_pow(x,y) powl((x),(y))
326 #else
327 # define trio_pow(x,y) pow((double)(x),(double)(y))
328 #endif
329
330 #if defined(HAVE_LOG10L)
331 # define trio_log10(x) log10l((x))
332 #else
333 # define trio_log10(x) log10((double)(x))
334 #endif
335
336
337 /*************************************************************************
338 * Internal Definitions
339 */
340
341 /* The maximal number of digits is for base 2 */
342 #define MAX_CHARS_IN(x) (sizeof(x) * CHAR_BIT)
343 /* The width of a pointer. The number of bits in a hex digit is 4 */
344 #define POINTER_WIDTH ((sizeof("0x") - 1) + sizeof(trio_pointer_t) * CHAR_BIT / 4)
345
346 /* Various constants */
347 enum {
348 TYPE_PRINT = 1,
349 #if TRIO_FEATURE_SCANF
350 TYPE_SCAN = 2,
351 #endif
352
353 /* Flags. FLAGS_LAST must be less than ULONG_MAX */
354 FLAGS_NEW = 0,
355 FLAGS_STICKY = 1,
356 FLAGS_SPACE = 2 * FLAGS_STICKY,
357 FLAGS_SHOWSIGN = 2 * FLAGS_SPACE,
358 FLAGS_LEFTADJUST = 2 * FLAGS_SHOWSIGN,
359 FLAGS_ALTERNATIVE = 2 * FLAGS_LEFTADJUST,
360 FLAGS_SHORT = 2 * FLAGS_ALTERNATIVE,
361 FLAGS_SHORTSHORT = 2 * FLAGS_SHORT,
362 FLAGS_LONG = 2 * FLAGS_SHORTSHORT,
363 FLAGS_QUAD = 2 * FLAGS_LONG,
364 FLAGS_LONGDOUBLE = 2 * FLAGS_QUAD,
365 FLAGS_SIZE_T = 2 * FLAGS_LONGDOUBLE,
366 FLAGS_PTRDIFF_T = 2 * FLAGS_SIZE_T,
367 FLAGS_INTMAX_T = 2 * FLAGS_PTRDIFF_T,
368 FLAGS_NILPADDING = 2 * FLAGS_INTMAX_T,
369 FLAGS_UNSIGNED = 2 * FLAGS_NILPADDING,
370 FLAGS_UPPER = 2 * FLAGS_UNSIGNED,
371 FLAGS_WIDTH = 2 * FLAGS_UPPER,
372 FLAGS_WIDTH_PARAMETER = 2 * FLAGS_WIDTH,
373 FLAGS_PRECISION = 2 * FLAGS_WIDTH_PARAMETER,
374 FLAGS_PRECISION_PARAMETER = 2 * FLAGS_PRECISION,
375 FLAGS_BASE = 2 * FLAGS_PRECISION_PARAMETER,
376 FLAGS_BASE_PARAMETER = 2 * FLAGS_BASE,
377 FLAGS_FLOAT_E = 2 * FLAGS_BASE_PARAMETER,
378 FLAGS_FLOAT_G = 2 * FLAGS_FLOAT_E,
379 FLAGS_QUOTE = 2 * FLAGS_FLOAT_G,
380 FLAGS_WIDECHAR = 2 * FLAGS_QUOTE,
381 FLAGS_IGNORE = 2 * FLAGS_WIDECHAR,
382 FLAGS_IGNORE_PARAMETER = 2 * FLAGS_IGNORE,
383 FLAGS_VARSIZE_PARAMETER = 2 * FLAGS_IGNORE_PARAMETER,
384 FLAGS_FIXED_SIZE = 2 * FLAGS_VARSIZE_PARAMETER,
385 FLAGS_LAST = FLAGS_FIXED_SIZE,
386 /* Reused flags */
387 FLAGS_EXCLUDE = FLAGS_SHORT,
388 FLAGS_USER_DEFINED = FLAGS_IGNORE,
389 FLAGS_USER_DEFINED_PARAMETER = FLAGS_IGNORE_PARAMETER,
390 FLAGS_ROUNDING = FLAGS_INTMAX_T,
391 /* Compounded flags */
392 FLAGS_ALL_VARSIZES = FLAGS_LONG | FLAGS_QUAD | FLAGS_INTMAX_T | FLAGS_PTRDIFF_T | FLAGS_SIZE_T,
393 FLAGS_ALL_SIZES = FLAGS_ALL_VARSIZES | FLAGS_SHORTSHORT | FLAGS_SHORT,
394
395 NO_POSITION = -1,
396 NO_WIDTH = 0,
397 NO_PRECISION = -1,
398 NO_SIZE = -1,
399
400 /* Do not change these */
401 NO_BASE = -1,
402 MIN_BASE = 2,
403 MAX_BASE = 36,
404 BASE_BINARY = 2,
405 BASE_OCTAL = 8,
406 BASE_DECIMAL = 10,
407 BASE_HEX = 16,
408
409 /* Maximal number of allowed parameters */
410 MAX_PARAMETERS = 64,
411 /* Maximal number of characters in class */
412 MAX_CHARACTER_CLASS = UCHAR_MAX + 1,
413
414 #if TRIO_FEATURE_USER_DEFINED
415 /* Maximal string lengths for user-defined specifiers */
416 MAX_USER_NAME = 64,
417 MAX_USER_DATA = 256,
418 #endif
419
420 /* Maximal length of locale separator strings */
421 MAX_LOCALE_SEPARATOR_LENGTH = MB_LEN_MAX,
422 /* Maximal number of integers in grouping */
423 MAX_LOCALE_GROUPS = 64
424 };
425
426 #define NO_GROUPING ((int)CHAR_MAX)
427
428 /* Fundamental formatting parameter types */
429 #define FORMAT_SENTINEL -1 /* marks end of parameters array */
430 #define FORMAT_UNKNOWN 0
431 #define FORMAT_INT 1
432 #define FORMAT_DOUBLE 2
433 #define FORMAT_CHAR 3
434 #define FORMAT_STRING 4
435 #define FORMAT_POINTER 5
436 #define FORMAT_COUNT 6
437 #define FORMAT_PARAMETER 7
438 #define FORMAT_GROUP 8
439 #define FORMAT_ERRNO 9
440 #define FORMAT_USER_DEFINED 10
441
442 /* Character constants */
443 #define CHAR_IDENTIFIER '%'
444 #define CHAR_ALT_IDENTIFIER '$'
445 #define CHAR_BACKSLASH '\\'
446 #define CHAR_QUOTE '\"'
447 #define CHAR_ADJUST ' '
448
449 /*
450 * SPECIFIERS:
451 *
452 *
453 * a Hex-float
454 * A Hex-float
455 * c Character
456 * C Widechar character (wint_t)
457 * d Decimal
458 * e Float
459 * E Float
460 * F Float
461 * F Float
462 * g Float
463 * G Float
464 * i Integer
465 * m Error message
466 * n Count
467 * o Octal
468 * p Pointer
469 * s String
470 * S Widechar string (wchar_t *)
471 * u Unsigned
472 * x Hex
473 * X Hex
474 * [] Group
475 * <> User-defined
476 *
477 * Reserved:
478 *
479 * D Binary Coded Decimal %D(length,precision) (OS/390)
480 */
481 #define SPECIFIER_CHAR 'c'
482 #define SPECIFIER_STRING 's'
483 #define SPECIFIER_DECIMAL 'd'
484 #define SPECIFIER_INTEGER 'i'
485 #define SPECIFIER_UNSIGNED 'u'
486 #define SPECIFIER_OCTAL 'o'
487 #define SPECIFIER_HEX 'x'
488 #define SPECIFIER_HEX_UPPER 'X'
489 #define SPECIFIER_POINTER 'p'
490 #if TRIO_FEATURE_SCANF
491 # define SPECIFIER_GROUP '['
492 # define SPECIFIER_UNGROUP ']'
493 #endif
494 #define SPECIFIER_COUNT 'n'
495 #if TRIO_UNIX98
496 # define SPECIFIER_CHAR_UPPER 'C'
497 # define SPECIFIER_STRING_UPPER 'S'
498 #endif
499 #define SPECIFIER_HEXFLOAT 'a'
500 #define SPECIFIER_HEXFLOAT_UPPER 'A'
501 #define SPECIFIER_ERRNO 'm'
502 #if TRIO_FEATURE_BINARY
503 # define SPECIFIER_BINARY 'b'
504 # define SPECIFIER_BINARY_UPPER 'B'
505 #endif
506
507 /*
508 * QUALIFIERS:
509 *
510 *
511 * Numbers = d,i,o,u,x,X
512 * Float = a,A,e,E,f,F,g,G
513 * String = s
514 * Char = c
515 *
516 *
517 * 9$ Position
518 * Use the 9th parameter. 9 can be any number between 1 and
519 * the maximal argument
520 *
521 * 9 Width
522 * Set width to 9. 9 can be any number, but must not be postfixed
523 * by '$'
524 *
525 * h Short
526 * Numbers:
527 * (unsigned) short int
528 *
529 * hh Short short
530 * Numbers:
531 * (unsigned) char
532 *
533 * l Long
534 * Numbers:
535 * (unsigned) long int
536 * String:
537 * as the S specifier
538 * Char:
539 * as the C specifier
540 *
541 * ll Long Long
542 * Numbers:
543 * (unsigned) long long int
544 *
545 * L Long Double
546 * Float
547 * long double
548 *
549 * # Alternative
550 * Float:
551 * Decimal-point is always present
552 * String:
553 * non-printable characters are handled as \number
554 *
555 * Spacing
556 *
557 * + Sign
558 *
559 * - Alignment
560 *
561 * . Precision
562 *
563 * * Parameter
564 * print: use parameter
565 * scan: no parameter (ignore)
566 *
567 * q Quad
568 *
569 * Z size_t
570 *
571 * w Widechar
572 *
573 * ' Thousands/quote
574 * Numbers:
575 * Integer part grouped in thousands
576 * Binary numbers:
577 * Number grouped in nibbles (4 bits)
578 * String:
579 * Quoted string
580 *
581 * j intmax_t
582 * t prtdiff_t
583 * z size_t
584 *
585 * ! Sticky
586 * @ Parameter (for both print and scan)
587 *
588 * I n-bit Integer
589 * Numbers:
590 * The following options exists
591 * I8 = 8-bit integer
592 * I16 = 16-bit integer
593 * I32 = 32-bit integer
594 * I64 = 64-bit integer
595 */
596 #define QUALIFIER_POSITION '$'
597 #define QUALIFIER_SHORT 'h'
598 #define QUALIFIER_LONG 'l'
599 #define QUALIFIER_LONG_UPPER 'L'
600 #define QUALIFIER_ALTERNATIVE '#'
601 #define QUALIFIER_SPACE ' '
602 #define QUALIFIER_PLUS '+'
603 #define QUALIFIER_MINUS '-'
604 #define QUALIFIER_DOT '.'
605 #define QUALIFIER_STAR '*'
606 #define QUALIFIER_CIRCUMFLEX '^' /* For scanlists */
607 #define QUALIFIER_SIZE_T 'z'
608 #define QUALIFIER_PTRDIFF_T 't'
609 #define QUALIFIER_INTMAX_T 'j'
610 #define QUALIFIER_QUAD 'q'
611 #define QUALIFIER_SIZE_T_UPPER 'Z'
612 #if TRIO_MISC
613 # define QUALIFIER_WIDECHAR 'w'
614 #endif
615 #define QUALIFIER_FIXED_SIZE 'I'
616 #define QUALIFIER_QUOTE '\''
617 #define QUALIFIER_STICKY '!'
618 #define QUALIFIER_VARSIZE '&' /* This should remain undocumented */
619 #define QUALIFIER_ROUNDING_UPPER 'R'
620
621
622 /*************************************************************************
623 *
624 * Internal Structures
625 *
626 *************************************************************************/
627
628 /* Parameters */
629 typedef struct {
630 /* An indication of which entry in the data union is used */
631 int type;
632 /* The flags */
633 trio_flags_t flags;
634 /* The width qualifier */
635 int width;
636 /* The precision qualifier */
637 int precision;
638 /* The base qualifier */
639 int base;
640 /* Base from specifier */
641 int baseSpecifier;
642 /* The size for the variable size qualifier */
643 int varsize;
644 /* Offset of the first character of the specifier */
645 int beginOffset;
646 /* Offset of the first character after the specifier */
647 int endOffset;
648 /* Position in the argument list that this parameter refers to */
649 int position;
650 /* The data from the argument list */
651 union {
652 char *string;
653 #if TRIO_FEATURE_WIDECHAR
654 trio_wchar_t *wstring;
655 #endif
656 trio_pointer_t pointer;
657 union {
658 trio_intmax_t as_signed;
659 trio_uintmax_t as_unsigned;
660 } number;
661 int errorNumber;
662 } data;
663 } trio_parameter_t;
664
665 /* Container for customized functions */
666 typedef struct {
667 union {
668 trio_outstream_t out;
669 trio_instream_t in;
670 } stream;
671 trio_pointer_t closure;
672 } trio_custom_t;
673
674 /* General trio "class" */
675 typedef struct _trio_class_t {
676 /*
677 * The function to write characters to a stream.
678 */
679 void (*OutStream) TRIO_PROTO((struct _trio_class_t *, int));
680 /*
681 * The function to read characters from a stream.
682 */
683 void (*InStream) TRIO_PROTO((struct _trio_class_t *, int *));
684 /*
685 * The function to undo read characters from a stream.
686 */
687 void (*UndoStream) TRIO_PROTO((struct _trio_class_t *));
688 /*
689 * The current location in the stream.
690 */
691 trio_pointer_t location;
692 /*
693 * The character currently being processed.
694 */
695 int current;
696 /*
697 * The number of characters that would have been written/read
698 * if there had been sufficient space.
699 */
700 int processed;
701 union {
702 /*
703 * The number of characters that are actually written. Processed and
704 * committed will only differ for the *nprintf functions.
705 */
706 int committed;
707 /*
708 * The number of look-ahead characters read.
709 */
710 int cached;
711 } actually;
712 /*
713 * The upper limit of characters that may be written/read.
714 */
715 int max;
716 /*
717 * The last output error that was detected.
718 */
719 int error;
720 } trio_class_t;
721
722 /* References (for user-defined callbacks) */
723 typedef struct _trio_reference_t {
724 trio_class_t *data;
725 trio_parameter_t *parameter;
726 } trio_reference_t;
727
728 /*************************************************************************
729 *
730 * Internal Variables
731 *
732 *************************************************************************/
733
734 //static TRIO_CONST char rcsid[] = "@(#)$Id: trio.c,v 1.129 2009/09/20 11:37:15 breese Exp $";
735
736 static TRIO_CONST char internalNullString[] = "(nil)";
737
738 #if defined(USE_LOCALE)
739 static struct lconv *internalLocaleValues = NULL;
740 #endif
741
742 /*
743 * UNIX98 says "in a locale where the radix character is not defined,
744 * the radix character defaults to a period (.)"
745 */
746 #if TRIO_FEATURE_QUOTE
747 static int internalThousandSeparatorLength = 1;
748 static char internalThousandSeparator[MAX_LOCALE_SEPARATOR_LENGTH + 1] = ",";
749 static char internalGrouping[MAX_LOCALE_GROUPS] = { (char)NO_GROUPING };
750 #endif
751
752 static TRIO_CONST char internalDigitsLower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
753 static TRIO_CONST char internalDigitsUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
754 #if TRIO_FEATURE_SCANF
755 static BOOLEAN_T internalDigitsUnconverted = TRUE;
756 static int internalDigitArray[128];
757 #endif
758
759 /*************************************************************************
760 *
761 * Internal Functions
762 *
763 ************************************************************************/
764
765 #if defined(TRIO_EMBED_NAN)
766 # include "trionan.c"
767 #endif
768
769 #if defined(TRIO_EMBED_STRING)
770 # include "triostr.c"
771 #endif
772
773 /*************************************************************************
774 * TrioInitializeParameter
775 *
776 * Description:
777 * Initialize a trio_parameter_t struct.
778 */
779 TRIO_PRIVATE void
780 TrioInitializeParameter
781 TRIO_ARGS1((parameter),
782 trio_parameter_t *parameter)
783 {
784 parameter->type = FORMAT_UNKNOWN;
785 parameter->flags = 0;
786 parameter->width = 0;
787 parameter->precision = 0;
788 parameter->base = 0;
789 parameter->baseSpecifier = 0;
790 parameter->varsize = 0;
791 parameter->beginOffset = 0;
792 parameter->endOffset = 0;
793 parameter->position = 0;
794 parameter->data.pointer = 0;
795 }
796
797 /*************************************************************************
798 * TrioCopyParameter
799 *
800 * Description:
801 * Copies one trio_parameter_t struct to another.
802 */
803 TRIO_PRIVATE void
804 TrioCopyParameter
805 TRIO_ARGS2((target, source),
806 trio_parameter_t *target,
807 TRIO_CONST trio_parameter_t *source)
808 {
809
810 target->type = source->type;
811 target->flags = source->flags;
812 target->width = source->width;
813 target->precision = source->precision;
814 target->base = source->base;
815 target->baseSpecifier = source->baseSpecifier;
816 target->varsize = source->varsize;
817 target->beginOffset = source->beginOffset;
818 target->endOffset = source->endOffset;
819 target->position = source->position;
820 target->data = source->data;
821 }
822
823 /*************************************************************************
824 * TrioIsQualifier
825 *
826 * Description:
827 * Remember to add all new qualifiers to this function.
828 * QUALIFIER_POSITION must not be added.
829 */
830 TRIO_PRIVATE BOOLEAN_T
831 TrioIsQualifier
832 TRIO_ARGS1((character),
833 TRIO_CONST char character)
834 {
835 /* QUALIFIER_POSITION is not included */
836 switch (character)
837 {
838 case '0': case '1': case '2': case '3': case '4':
839 case '5': case '6': case '7': case '8': case '9':
840 case QUALIFIER_PLUS:
841 case QUALIFIER_MINUS:
842 case QUALIFIER_SPACE:
843 case QUALIFIER_DOT:
844 case QUALIFIER_STAR:
845 case QUALIFIER_ALTERNATIVE:
846 case QUALIFIER_SHORT:
847 case QUALIFIER_LONG:
848 case QUALIFIER_CIRCUMFLEX:
849 case QUALIFIER_LONG_UPPER:
850 case QUALIFIER_SIZE_T:
851 case QUALIFIER_PTRDIFF_T:
852 case QUALIFIER_INTMAX_T:
853 case QUALIFIER_QUAD:
854 case QUALIFIER_SIZE_T_UPPER:
855 #if defined(QUALIFIER_WIDECHAR)
856 case QUALIFIER_WIDECHAR:
857 #endif
858 case QUALIFIER_QUOTE:
859 case QUALIFIER_STICKY:
860 case QUALIFIER_VARSIZE:
861 #if defined(QUALIFIER_PARAM)
862 case QUALIFIER_PARAM:
863 #endif
864 case QUALIFIER_FIXED_SIZE:
865 case QUALIFIER_ROUNDING_UPPER:
866 return TRUE;
867 default:
868 return FALSE;
869 }
870 }
871
872 /*************************************************************************
873 * TrioSetLocale
874 */
875 #if defined(USE_LOCALE)
876 TRIO_PRIVATE void
877 TrioSetLocale(TRIO_NOARGS)
878 {
879 internalLocaleValues = (struct lconv *)localeconv();
880 if (internalLocaleValues)
881 {
882 if ((internalLocaleValues->decimal_point) &&
883 (internalLocaleValues->decimal_point[0] != NIL))
884 {
885 internalDecimalPointLength = trio_length(internalLocaleValues->decimal_point);
886 if (internalDecimalPointLength == 1)
887 {
888 internalDecimalPoint = internalLocaleValues->decimal_point[0];
889 }
890 else
891 {
892 internalDecimalPoint = NIL;
893 trio_copy_max(internalDecimalPointString,
894 sizeof(internalDecimalPointString),
895 internalLocaleValues->decimal_point);
896 }
897 }
898 }
899 }
900 #endif /* defined(USE_LOCALE) */
901
902 #if TRIO_FEATURE_QUOTE
903 TRIO_PRIVATE BOOLEAN_T
904 TrioFollowedBySeparator
905 TRIO_ARGS1((position),
906 int position)
907 {
908 int step = 0;
909 char *groupingPointer = internalGrouping;
910
911 position--;
912 if (position == 0)
913 return FALSE;
914 while (position > 0)
915 {
916 if (*groupingPointer == CHAR_MAX)
917 {
918 /* Disable grouping */
919 break; /* while */
920 }
921 else if (*groupingPointer != 0)
922 {
923 step = *groupingPointer++;
924 }
925 if (step == 0)
926 break;
927 position -= step;
928 }
929 return (position == 0);
930 }
931 #endif /* TRIO_FEATURE_QUOTE */
932
933 /*************************************************************************
934 * TrioGetPosition
935 *
936 * Get the %n$ position.
937 */
938 TRIO_PRIVATE int
939 TrioGetPosition
940 TRIO_ARGS2((format, offsetPointer),
941 TRIO_CONST char *format,
942 int *offsetPointer)
943 {
944 #if TRIO_FEATURE_POSITIONAL
945 char *tmpformat;
946 int number = 0;
947 int offset = *offsetPointer;
948
949 number = (int)trio_to_long(&format[offset], &tmpformat, BASE_DECIMAL);
950 offset = (int)(tmpformat - format);
951 if ((number != 0) && (QUALIFIER_POSITION == format[offset++]))
952 {
953 *offsetPointer = offset;
954 /*
955 * number is decreased by 1, because n$ starts from 1, whereas
956 * the array it is indexing starts from 0.
957 */
958 return number - 1;
959 }
960 #endif
961 return NO_POSITION;
962 }
963
964 /*************************************************************************
965 * TrioParseQualifiers
966 *
967 * Description:
968 * Parse the qualifiers of a potential conversion specifier
969 */
970 TRIO_PRIVATE int
971 TrioParseQualifiers
972 TRIO_ARGS4((type, format, offset, parameter),
973 int type,
974 TRIO_CONST char *format,
975 int offset,
976 trio_parameter_t *parameter)
977 {
978 char ch;
979 int dots = 0; /* Count number of dots in modifier part */
980 char *tmpformat;
981
982 parameter->beginOffset = offset - 1;
983 parameter->flags = FLAGS_NEW;
984 parameter->position = TrioGetPosition(format, &offset);
985
986 /* Default values */
987 parameter->width = NO_WIDTH;
988 parameter->precision = NO_PRECISION;
989 parameter->base = NO_BASE;
990 parameter->varsize = NO_SIZE;
991
992 while (TrioIsQualifier(format[offset]))
993 {
994 ch = format[offset++];
995
996 switch (ch)
997 {
998 case QUALIFIER_SPACE:
999 parameter->flags |= FLAGS_SPACE;
1000 break;
1001
1002 case QUALIFIER_PLUS:
1003 parameter->flags |= FLAGS_SHOWSIGN;
1004 break;
1005
1006 case QUALIFIER_MINUS:
1007 parameter->flags |= FLAGS_LEFTADJUST;
1008 parameter->flags &= ~FLAGS_NILPADDING;
1009 break;
1010
1011 case QUALIFIER_ALTERNATIVE:
1012 parameter->flags |= FLAGS_ALTERNATIVE;
1013 break;
1014
1015 case QUALIFIER_DOT:
1016 if (dots == 0) /* Precision */
1017 {
1018 dots++;
1019
1020 /* Skip if no precision */
1021 if (QUALIFIER_DOT == format[offset])
1022 break;
1023
1024 /* After the first dot we have the precision */
1025 parameter->flags |= FLAGS_PRECISION;
1026 if ((QUALIFIER_STAR == format[offset])
1027 #if defined(QUALIFIER_PARAM)
1028 || (QUALIFIER_PARAM == format[offset])
1029 #endif
1030 )
1031 {
1032 offset++;
1033 parameter->flags |= FLAGS_PRECISION_PARAMETER;
1034 parameter->precision = TrioGetPosition(format, &offset);
1035 }
1036 else
1037 {
1038 parameter->precision = trio_to_long(&format[offset],
1039 &tmpformat,
1040 BASE_DECIMAL);
1041 offset = (int)(tmpformat - format);
1042 }
1043 }
1044 else if (dots == 1) /* Base */
1045 {
1046 dots++;
1047
1048 /* After the second dot we have the base */
1049 parameter->flags |= FLAGS_BASE;
1050 if ((QUALIFIER_STAR == format[offset])
1051 #if defined(QUALIFIER_PARAM)
1052 || (QUALIFIER_PARAM == format[offset])
1053 #endif
1054 )
1055 {
1056 offset++;
1057 parameter->flags |= FLAGS_BASE_PARAMETER;
1058 parameter->base = TrioGetPosition(format, &offset);
1059 }
1060 else
1061 {
1062 parameter->base = trio_to_long(&format[offset],
1063 &tmpformat,
1064 BASE_DECIMAL);
1065 if (parameter->base > MAX_BASE)
1066 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1067 offset = (int)(tmpformat - format);
1068 }
1069 }
1070 else
1071 {
1072 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1073 }
1074 break; /* QUALIFIER_DOT */
1075
1076 #if defined(QUALIFIER_PARAM)
1077 case QUALIFIER_PARAM:
1078 parameter->type = TYPE_PRINT;
1079 /* FALLTHROUGH */
1080 #endif
1081 case QUALIFIER_STAR:
1082 /* This has different meanings for print and scan */
1083 if (TYPE_PRINT == type)
1084 {
1085 /* Read with from parameter */
1086 int width = TrioGetPosition(format, &offset);
1087 parameter->flags |= (FLAGS_WIDTH | FLAGS_WIDTH_PARAMETER);
1088 if (NO_POSITION != width)
1089 parameter->width = width;
1090 /* else keep parameter->width = NO_WIDTH which != NO_POSITION */
1091 }
1092 #if TRIO_FEATURE_SCANF
1093 else
1094 {
1095 /* Scan, but do not store result */
1096 parameter->flags |= FLAGS_IGNORE;
1097 }
1098 #endif
1099 break; /* QUALIFIER_STAR */
1100
1101 case '0':
1102 if (! (parameter->flags & FLAGS_LEFTADJUST))
1103 parameter->flags |= FLAGS_NILPADDING;
1104 /* FALLTHROUGH */
1105 case '1': case '2': case '3': case '4':
1106 case '5': case '6': case '7': case '8': case '9':
1107 parameter->flags |= FLAGS_WIDTH;
1108 /*
1109 * &format[offset - 1] is used to "rewind" the read
1110 * character from format
1111 */
1112 parameter->width = trio_to_long(&format[offset - 1],
1113 &tmpformat,
1114 BASE_DECIMAL);
1115 offset = (int)(tmpformat - format);
1116 break;
1117
1118 case QUALIFIER_SHORT:
1119 if (parameter->flags & FLAGS_SHORTSHORT)
1120 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1121 else if (parameter->flags & FLAGS_SHORT)
1122 parameter->flags |= FLAGS_SHORTSHORT;
1123 else
1124 parameter->flags |= FLAGS_SHORT;
1125 break;
1126
1127 case QUALIFIER_LONG:
1128 if (parameter->flags & FLAGS_QUAD)
1129 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1130 else if (parameter->flags & FLAGS_LONG)
1131 parameter->flags |= FLAGS_QUAD;
1132 else
1133 parameter->flags |= FLAGS_LONG;
1134 break;
1135
1136 #if TRIO_FEATURE_LONGDOUBLE
1137 case QUALIFIER_LONG_UPPER:
1138 parameter->flags |= FLAGS_LONGDOUBLE;
1139 break;
1140 #endif
1141
1142 #if TRIO_FEATURE_SIZE_T
1143 case QUALIFIER_SIZE_T:
1144 parameter->flags |= FLAGS_SIZE_T;
1145 /* Modify flags for later truncation of number */
1146 if (sizeof(size_t) == sizeof(trio_ulonglong_t))
1147 parameter->flags |= FLAGS_QUAD;
1148 else if (sizeof(size_t) == sizeof(long))
1149 parameter->flags |= FLAGS_LONG;
1150 break;
1151 #endif
1152
1153 #if TRIO_FEATURE_PTRDIFF_T
1154 case QUALIFIER_PTRDIFF_T:
1155 parameter->flags |= FLAGS_PTRDIFF_T;
1156 if (sizeof(ptrdiff_t) == sizeof(trio_ulonglong_t))
1157 parameter->flags |= FLAGS_QUAD;
1158 else if (sizeof(ptrdiff_t) == sizeof(long))
1159 parameter->flags |= FLAGS_LONG;
1160 break;
1161 #endif
1162
1163 #if TRIO_FEATURE_INTMAX_T
1164 case QUALIFIER_INTMAX_T:
1165 parameter->flags |= FLAGS_INTMAX_T;
1166 if (sizeof(trio_intmax_t) == sizeof(trio_ulonglong_t))
1167 parameter->flags |= FLAGS_QUAD;
1168 else if (sizeof(trio_intmax_t) == sizeof(long))
1169 parameter->flags |= FLAGS_LONG;
1170 break;
1171 #endif
1172
1173 #if TRIO_FEATURE_QUAD
1174 case QUALIFIER_QUAD:
1175 parameter->flags |= FLAGS_QUAD;
1176 break;
1177 #endif
1178
1179 #if TRIO_FEATURE_FIXED_SIZE
1180 case QUALIFIER_FIXED_SIZE:
1181 if (parameter->flags & FLAGS_FIXED_SIZE)
1182 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1183
1184 if (parameter->flags & (FLAGS_ALL_SIZES |
1185 FLAGS_LONGDOUBLE |
1186 FLAGS_WIDECHAR |
1187 FLAGS_VARSIZE_PARAMETER))
1188 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1189
1190 if ((format[offset] == '6') &&
1191 (format[offset + 1] == '4'))
1192 {
1193 parameter->varsize = sizeof(trio_int64_t);
1194 offset += 2;
1195 }
1196 else if ((format[offset] == '3') &&
1197 (format[offset + 1] == '2'))
1198 {
1199 parameter->varsize = sizeof(trio_int32_t);
1200 offset += 2;
1201 }
1202 else if ((format[offset] == '1') &&
1203 (format[offset + 1] == '6'))
1204 {
1205 parameter->varsize = sizeof(trio_int16_t);
1206 offset += 2;
1207 }
1208 else if (format[offset] == '8')
1209 {
1210 parameter->varsize = sizeof(trio_int8_t);
1211 offset++;
1212 }
1213 else
1214 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1215
1216 parameter->flags |= FLAGS_FIXED_SIZE;
1217 break;
1218 #endif /* TRIO_FEATURE_FIXED_SIZE */
1219
1220 #if defined(QUALIFIER_WIDECHAR)
1221 case QUALIFIER_WIDECHAR:
1222 parameter->flags |= FLAGS_WIDECHAR;
1223 break;
1224 #endif
1225
1226 #if TRIO_FEATURE_SIZE_T_UPPER
1227 case QUALIFIER_SIZE_T_UPPER:
1228 break;
1229 #endif
1230
1231 #if TRIO_FEATURE_QUOTE
1232 case QUALIFIER_QUOTE:
1233 parameter->flags |= FLAGS_QUOTE;
1234 break;
1235 #endif
1236
1237 #if TRIO_FEATURE_STICKY
1238 case QUALIFIER_STICKY:
1239 parameter->flags |= FLAGS_STICKY;
1240 break;
1241 #endif
1242
1243 #if TRIO_FEATURE_VARSIZE
1244 case QUALIFIER_VARSIZE:
1245 parameter->flags |= FLAGS_VARSIZE_PARAMETER;
1246 break;
1247 #endif
1248
1249 #if TRIO_FEATURE_ROUNDING
1250 case QUALIFIER_ROUNDING_UPPER:
1251 parameter->flags |= FLAGS_ROUNDING;
1252 break;
1253 #endif
1254
1255 default:
1256 /* Bail out completely to make the error more obvious */
1257 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1258 }
1259 } /* while qualifier */
1260
1261 parameter->endOffset = offset;
1262
1263 return 0;
1264 }
1265
1266 /*************************************************************************
1267 * TrioParseSpecifier
1268 *
1269 * Description:
1270 * Parse the specifier part of a potential conversion specifier
1271 */
1272 TRIO_PRIVATE int
1273 TrioParseSpecifier
1274 TRIO_ARGS4((type, format, offset, parameter),
1275 int type,
1276 TRIO_CONST char *format,
1277 int offset,
1278 trio_parameter_t *parameter)
1279 {
1280 parameter->baseSpecifier = NO_BASE;
1281
1282 switch (format[offset++])
1283 {
1284 #if defined(SPECIFIER_CHAR_UPPER)
1285 case SPECIFIER_CHAR_UPPER:
1286 parameter->flags |= FLAGS_WIDECHAR;
1287 /* FALLTHROUGH */
1288 #endif
1289 case SPECIFIER_CHAR:
1290 if (parameter->flags & FLAGS_LONG)
1291 parameter->flags |= FLAGS_WIDECHAR;
1292 else if (parameter->flags & FLAGS_SHORT)
1293 parameter->flags &= ~FLAGS_WIDECHAR;
1294 parameter->type = FORMAT_CHAR;
1295 break;
1296
1297 #if defined(SPECIFIER_STRING_UPPER)
1298 case SPECIFIER_STRING_UPPER:
1299 parameter->flags |= FLAGS_WIDECHAR;
1300 /* FALLTHROUGH */
1301 #endif
1302 case SPECIFIER_STRING:
1303 if (parameter->flags & FLAGS_LONG)
1304 parameter->flags |= FLAGS_WIDECHAR;
1305 else if (parameter->flags & FLAGS_SHORT)
1306 parameter->flags &= ~FLAGS_WIDECHAR;
1307 parameter->type = FORMAT_STRING;
1308 break;
1309
1310 #if defined(SPECIFIER_GROUP)
1311 case SPECIFIER_GROUP:
1312 if (TYPE_SCAN == type)
1313 {
1314 int depth = 1;
1315 parameter->type = FORMAT_GROUP;
1316 if (format[offset] == QUALIFIER_CIRCUMFLEX)
1317 offset++;
1318 if (format[offset] == SPECIFIER_UNGROUP)
1319 offset++;
1320 if (format[offset] == QUALIFIER_MINUS)
1321 offset++;
1322 /* Skip nested brackets */
1323 while (format[offset] != NIL)
1324 {
1325 if (format[offset] == SPECIFIER_GROUP)
1326 {
1327 depth++;
1328 }
1329 else if (format[offset] == SPECIFIER_UNGROUP)
1330 {
1331 if (--depth <= 0)
1332 {
1333 offset++;
1334 break;
1335 }
1336 }
1337 offset++;
1338 }
1339 }
1340 break;
1341 #endif /* defined(SPECIFIER_GROUP) */
1342
1343 case SPECIFIER_INTEGER:
1344 parameter->type = FORMAT_INT;
1345 break;
1346
1347 case SPECIFIER_UNSIGNED:
1348 parameter->flags |= FLAGS_UNSIGNED;
1349 parameter->type = FORMAT_INT;
1350 break;
1351
1352 case SPECIFIER_DECIMAL:
1353 parameter->baseSpecifier = BASE_DECIMAL;
1354 parameter->type = FORMAT_INT;
1355 break;
1356
1357 case SPECIFIER_OCTAL:
1358 parameter->flags |= FLAGS_UNSIGNED;
1359 parameter->baseSpecifier = BASE_OCTAL;
1360 parameter->type = FORMAT_INT;
1361 break;
1362
1363 #if TRIO_FEATURE_BINARY
1364 case SPECIFIER_BINARY_UPPER:
1365 parameter->flags |= FLAGS_UPPER;
1366 /* FALLTHROUGH */
1367 case SPECIFIER_BINARY:
1368 parameter->flags |= FLAGS_NILPADDING;
1369 parameter->baseSpecifier = BASE_BINARY;
1370 parameter->type = FORMAT_INT;
1371 break;
1372 #endif
1373
1374 case SPECIFIER_HEX_UPPER:
1375 parameter->flags |= FLAGS_UPPER;
1376 /* FALLTHROUGH */
1377 case SPECIFIER_HEX:
1378 parameter->flags |= FLAGS_UNSIGNED;
1379 parameter->baseSpecifier = BASE_HEX;
1380 parameter->type = FORMAT_INT;
1381 break;
1382
1383 #if defined(SPECIFIER_FLOAT_E)
1384 # if defined(SPECIFIER_FLOAT_E_UPPER)
1385 case SPECIFIER_FLOAT_E_UPPER:
1386 parameter->flags |= FLAGS_UPPER;
1387 /* FALLTHROUGH */
1388 # endif
1389 case SPECIFIER_FLOAT_E:
1390 parameter->flags |= FLAGS_FLOAT_E;
1391 parameter->type = FORMAT_DOUBLE;
1392 break;
1393 #endif
1394
1395 #if defined(SPECIFIER_FLOAT_G)
1396 # if defined(SPECIFIER_FLOAT_G_UPPER)
1397 case SPECIFIER_FLOAT_G_UPPER:
1398 parameter->flags |= FLAGS_UPPER;
1399 /* FALLTHROUGH */
1400 # endif
1401 case SPECIFIER_FLOAT_G:
1402 parameter->flags |= FLAGS_FLOAT_G;
1403 parameter->type = FORMAT_DOUBLE;
1404 break;
1405 #endif
1406
1407 #if defined(SPECIFIER_FLOAT_F)
1408 # if defined(SPECIFIER_FLOAT_F_UPPER)
1409 case SPECIFIER_FLOAT_F_UPPER:
1410 parameter->flags |= FLAGS_UPPER;
1411 /* FALLTHROUGH */
1412 # endif
1413 case SPECIFIER_FLOAT_F:
1414 parameter->type = FORMAT_DOUBLE;
1415 break;
1416 #endif
1417
1418 #if defined(TRIO_COMPILER_VISUALC)
1419 # pragma warning( push )
1420 # pragma warning( disable : 4127 ) /* Conditional expression is constant */
1421 #endif
1422 case SPECIFIER_POINTER:
1423 if (sizeof(trio_pointer_t) == sizeof(trio_ulonglong_t))
1424 parameter->flags |= FLAGS_QUAD;
1425 else if (sizeof(trio_pointer_t) == sizeof(long))
1426 parameter->flags |= FLAGS_LONG;
1427 parameter->type = FORMAT_POINTER;
1428 break;
1429 #if defined(TRIO_COMPILER_VISUALC)
1430 # pragma warning( pop )
1431 #endif
1432
1433 case SPECIFIER_COUNT:
1434 parameter->type = FORMAT_COUNT;
1435 break;
1436
1437 #if TRIO_FEATURE_HEXFLOAT
1438 case SPECIFIER_HEXFLOAT_UPPER:
1439 parameter->flags |= FLAGS_UPPER;
1440 /* FALLTHROUGH */
1441 case SPECIFIER_HEXFLOAT:
1442 parameter->baseSpecifier = BASE_HEX;
1443 parameter->type = FORMAT_DOUBLE;
1444 break;
1445 #endif
1446
1447 #if TRIO_FEATURE_ERRNO
1448 case SPECIFIER_ERRNO:
1449 parameter->type = FORMAT_ERRNO;
1450 break;
1451 #endif
1452
1453 default:
1454 /* Bail out completely to make the error more obvious */
1455 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
1456 }
1457
1458 parameter->endOffset = offset;
1459
1460 return 0;
1461 }
1462
1463 /*************************************************************************
1464 * TrioParse
1465 *
1466 * Description:
1467 * Parse the format string
1468 */
1469 TRIO_PRIVATE int
1470 TrioParse
1471 TRIO_ARGS5((type, format, parameters, arglist, argarray),
1472 int type,
1473 TRIO_CONST char *format,
1474 trio_parameter_t *parameters,
1475 va_list arglist,
1476 trio_pointer_t *argarray)
1477 {
1478 /* Count the number of times a parameter is referenced */
1479 unsigned short usedEntries[MAX_PARAMETERS];
1480 /* Parameter counters */
1481 int parameterPosition;
1482 int maxParam = -1;
1483 /* Utility variables */
1484 int offset; /* Offset into formatting string */
1485 BOOLEAN_T positional; /* Does the specifier have a positional? */
1486 #if TRIO_FEATURE_STICKY
1487 BOOLEAN_T gotSticky = FALSE; /* Are there any sticky modifiers at all? */
1488 #endif
1489 /*
1490 * indices specifies the order in which the parameters must be
1491 * read from the va_args (this is necessary to handle positionals)
1492 */
1493 int indices[MAX_PARAMETERS];
1494 int pos = 0;
1495 /* Various variables */
1496 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1497 int charlen;
1498 #endif
1499 int save_errno;
1500 int i = -1;
1501 int num;
1502 trio_parameter_t workParameter;
1503 int status;
1504
1505 /*
1506 * The 'parameters' array is not initialized, but we need to
1507 * know which entries we have used.
1508 */
1509 memset(usedEntries, 0, sizeof(usedEntries));
1510
1511 save_errno = errno;
1512 offset = 0;
1513 parameterPosition = 0;
1514 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1515 (void)mblen(NULL, 0);
1516 #endif
1517
1518 while (format[offset])
1519 {
1520 TrioInitializeParameter(&workParameter);
1521
1522 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
1523 if (! isascii(format[offset]))
1524 {
1525 /*
1526 * Multibyte characters cannot be legal specifiers or
1527 * modifiers, so we skip over them.
1528 */
1529 charlen = mblen(&format[offset], MB_LEN_MAX);
1530 offset += (charlen > 0) ? charlen : 1;
1531 continue; /* while */
1532 }
1533 #endif /* TRIO_COMPILER_SUPPORTS_MULTIBYTE */
1534
1535 switch(format[offset++]) {
1536
1537 case CHAR_IDENTIFIER:
1538 {
1539 if (CHAR_IDENTIFIER == format[offset])
1540 {
1541 /* skip double "%" */
1542 offset++;
1543 continue; /* while */
1544 }
1545
1546 status = TrioParseQualifiers(type, format, offset, &workParameter);
1547 if (status < 0)
1548 return status; /* Return qualifier syntax error */
1549
1550 status = TrioParseSpecifier(type, format, workParameter.endOffset, &workParameter);
1551 if (status < 0)
1552 return status; /* Return specifier syntax error */
1553 }
1554 break;
1555
1556 default:
1557 continue; /* while */
1558 }
1559
1560 /* now handle the parsed conversion specification */
1561 positional = (NO_POSITION != workParameter.position);
1562
1563 /*
1564 * Parameters only need the type and value. The value is
1565 * read later.
1566 */
1567 if (workParameter.flags & FLAGS_WIDTH_PARAMETER)
1568 {
1569 if (workParameter.width == NO_WIDTH)
1570 {
1571 workParameter.width = parameterPosition++;
1572 }
1573 else
1574 {
1575 if (! positional)
1576 workParameter.position = workParameter.width + 1;
1577 }
1578
1579 usedEntries[workParameter.width] += 1;
1580 if (workParameter.width > maxParam)
1581 maxParam = workParameter.width;
1582 parameters[pos].type = FORMAT_PARAMETER;
1583 parameters[pos].flags = 0;
1584 indices[workParameter.width] = pos;
1585 workParameter.width = pos++;
1586 }
1587 if (workParameter.flags & FLAGS_PRECISION_PARAMETER)
1588 {
1589 if (workParameter.precision == NO_PRECISION)
1590 {
1591 workParameter.precision = parameterPosition++;
1592 }
1593 else
1594 {
1595 if (! positional)
1596 workParameter.position = workParameter.precision + 1;
1597 }
1598
1599 usedEntries[workParameter.precision] += 1;
1600 if (workParameter.precision > maxParam)
1601 maxParam = workParameter.precision;
1602 parameters[pos].type = FORMAT_PARAMETER;
1603 parameters[pos].flags = 0;
1604 indices[workParameter.precision] = pos;
1605 workParameter.precision = pos++;
1606 }
1607 if (workParameter.flags & FLAGS_BASE_PARAMETER)
1608 {
1609 if (workParameter.base == NO_BASE)
1610 {
1611 workParameter.base = parameterPosition++;
1612 }
1613 else
1614 {
1615 if (! positional)
1616 workParameter.position = workParameter.base + 1;
1617 }
1618
1619 usedEntries[workParameter.base] += 1;
1620 if (workParameter.base > maxParam)
1621 maxParam = workParameter.base;
1622 parameters[pos].type = FORMAT_PARAMETER;
1623 parameters[pos].flags = 0;
1624 indices[workParameter.base] = pos;
1625 workParameter.base = pos++;
1626 }
1627 #if TRIO_FEATURE_VARSIZE
1628 if (workParameter.flags & FLAGS_VARSIZE_PARAMETER)
1629 {
1630 workParameter.varsize = parameterPosition++;
1631
1632 usedEntries[workParameter.varsize] += 1;
1633 if (workParameter.varsize > maxParam)
1634 maxParam = workParameter.varsize;
1635 parameters[pos].type = FORMAT_PARAMETER;
1636 parameters[pos].flags = 0;
1637 indices[workParameter.varsize] = pos;
1638 workParameter.varsize = pos++;
1639 }
1640 #endif
1641
1642 if (NO_POSITION == workParameter.position)
1643 {
1644 workParameter.position = parameterPosition++;
1645 }
1646
1647 if (workParameter.position > maxParam)
1648 maxParam = workParameter.position;
1649
1650 if (workParameter.position >= MAX_PARAMETERS)
1651 {
1652 /* Bail out completely to make the error more obvious */
1653 return TRIO_ERROR_RETURN(TRIO_ETOOMANY, offset);
1654 }
1655
1656 indices[workParameter.position] = pos;
1657
1658 /* Count the number of times this entry has been used */
1659 usedEntries[workParameter.position] += 1;
1660
1661 /* Find last sticky parameters */
1662 #if TRIO_FEATURE_STICKY
1663 if (workParameter.flags & FLAGS_STICKY)
1664 {
1665 gotSticky = TRUE;
1666 }
1667 else if (gotSticky)
1668 {
1669 for (i = pos - 1; i >= 0; i--)
1670 {
1671 if (parameters[i].type == FORMAT_PARAMETER)
1672 continue;
1673 if ((parameters[i].flags & FLAGS_STICKY) &&
1674 (parameters[i].type == workParameter.type))
1675 {
1676 /* Do not overwrite current qualifiers */
1677 workParameter.flags |= (parameters[i].flags & (unsigned long)~FLAGS_STICKY);
1678 if (workParameter.width == NO_WIDTH)
1679 workParameter.width = parameters[i].width;
1680 if (workParameter.precision == NO_PRECISION)
1681 workParameter.precision = parameters[i].precision;
1682 if (workParameter.base == NO_BASE)
1683 workParameter.base = parameters[i].base;
1684 break;
1685 }
1686 }
1687 }
1688 #endif
1689
1690 if (workParameter.base == NO_BASE)
1691 workParameter.base = BASE_DECIMAL;
1692
1693 offset = workParameter.endOffset;
1694
1695 TrioCopyParameter(&parameters[pos++], &workParameter);
1696 } /* while format characters left */
1697
1698 parameters[pos].type = FORMAT_SENTINEL; /* end parameter array with sentinel */
1699 parameters[pos].beginOffset = offset;
1700
1701 for (num = 0; num <= maxParam; num++)
1702 {
1703 if (usedEntries[num] != 1)
1704 {
1705 if (usedEntries[num] == 0) /* gap detected */
1706 return TRIO_ERROR_RETURN(TRIO_EGAP, num);
1707 else /* double references detected */
1708 return TRIO_ERROR_RETURN(TRIO_EDBLREF, num);
1709 }
1710
1711 i = indices[num];
1712
1713 /*
1714 * FORMAT_PARAMETERS are only present if they must be read,
1715 * so it makes no sense to check the ignore flag (besides,
1716 * the flags variable is not set for that particular type)
1717 */
1718 if ((parameters[i].type != FORMAT_PARAMETER) &&
1719 (parameters[i].flags & FLAGS_IGNORE))
1720 continue; /* for all arguments */
1721
1722 /*
1723 * The stack arguments are read according to ANSI C89
1724 * default argument promotions:
1725 *
1726 * char = int
1727 * short = int
1728 * unsigned char = unsigned int
1729 * unsigned short = unsigned int
1730 * float = double
1731 *
1732 * In addition to the ANSI C89 these types are read (the
1733 * default argument promotions of C99 has not been
1734 * considered yet)
1735 *
1736 * long long
1737 * long double
1738 * size_t
1739 * ptrdiff_t
1740 * intmax_t
1741 */
1742 switch (parameters[i].type)
1743 {
1744 case FORMAT_GROUP:
1745 case FORMAT_STRING:
1746 #if TRIO_FEATURE_WIDECHAR
1747 if (parameters[i].flags & FLAGS_WIDECHAR)
1748 {
1749 parameters[i].data.wstring = (argarray == NULL)
1750 ? va_arg(arglist, trio_wchar_t *)
1751 : (trio_wchar_t *)(argarray[num]);
1752 }
1753 else
1754 #endif
1755 {
1756 parameters[i].data.string = (argarray == NULL)
1757 ? va_arg(arglist, char *)
1758 : (char *)(argarray[num]);
1759 }
1760 break;
1761
1762 case FORMAT_POINTER:
1763 case FORMAT_COUNT:
1764 case FORMAT_UNKNOWN:
1765 parameters[i].data.pointer = (argarray == NULL)
1766 ? va_arg(arglist, trio_pointer_t )
1767 : argarray[num];
1768 break;
1769
1770 case FORMAT_CHAR:
1771 case FORMAT_INT:
1772 #if TRIO_FEATURE_SCANF
1773 if (TYPE_SCAN == type)
1774 {
1775 if (argarray == NULL)
1776 parameters[i].data.pointer =
1777 (trio_pointer_t)va_arg(arglist, trio_pointer_t);
1778 else
1779 {
1780 if (parameters[i].type == FORMAT_CHAR)
1781 parameters[i].data.pointer =
1782 (trio_pointer_t)((char *)argarray[num]);
1783 else if (parameters[i].flags & FLAGS_SHORT)
1784 parameters[i].data.pointer =
1785 (trio_pointer_t)((short *)argarray[num]);
1786 else
1787 parameters[i].data.pointer =
1788 (trio_pointer_t)((int *)argarray[num]);
1789 }
1790 }
1791 else
1792 #endif /* TRIO_FEATURE_SCANF */
1793 {
1794 #if TRIO_FEATURE_VARSIZE || TRIO_FEATURE_FIXED_SIZE
1795 if (parameters[i].flags
1796 & (FLAGS_VARSIZE_PARAMETER | FLAGS_FIXED_SIZE))
1797 {
1798 int varsize;
1799 if (parameters[i].flags & FLAGS_VARSIZE_PARAMETER)
1800 {
1801 /*
1802 * Variable sizes are mapped onto the fixed sizes, in
1803 * accordance with integer promotion.
1804 *
1805 * Please note that this may not be portable, as we
1806 * only guess the size, not the layout of the numbers.
1807 * For example, if int is little-endian, and long is
1808 * big-endian, then this will fail.
1809 */
1810 varsize = (int)parameters[parameters[i].varsize].data.number.as_unsigned;
1811 }
1812 else
1813 {
1814 /* Used for the I<bits> modifiers */
1815 varsize = parameters[i].varsize;
1816 }
1817 parameters[i].flags &= ~FLAGS_ALL_VARSIZES;
1818
1819 if (varsize <= (int)sizeof(int))
1820 ;
1821 else if (varsize <= (int)sizeof(long))
1822 parameters[i].flags |= FLAGS_LONG;
1823 #if TRIO_FEATURE_INTMAX_T
1824 else if (varsize <= (int)sizeof(trio_longlong_t))
1825 parameters[i].flags |= FLAGS_QUAD;
1826 else
1827 parameters[i].flags |= FLAGS_INTMAX_T;
1828 #else
1829 else
1830 parameters[i].flags |= FLAGS_QUAD;
1831 #endif
1832 }
1833 #endif /* TRIO_FEATURE_VARSIZE */
1834 #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
1835 if (parameters[i].flags & FLAGS_SIZE_T)
1836 parameters[i].data.number.as_unsigned = (argarray == NULL)
1837 ? (trio_uintmax_t)va_arg(arglist, size_t)
1838 : (trio_uintmax_t)(*((size_t *)argarray[num]));
1839 else
1840 #endif
1841 #if TRIO_FEATURE_PTRDIFF_T
1842 if (parameters[i].flags & FLAGS_PTRDIFF_T)
1843 parameters[i].data.number.as_unsigned = (argarray == NULL)
1844 ? (trio_uintmax_t)va_arg(arglist, ptrdiff_t)
1845 : (trio_uintmax_t)(*((ptrdiff_t *)argarray[num]));
1846 else
1847 #endif
1848 #if TRIO_FEATURE_INTMAX_T
1849 if (parameters[i].flags & FLAGS_INTMAX_T)
1850 parameters[i].data.number.as_unsigned = (argarray == NULL)
1851 ? (trio_uintmax_t)va_arg(arglist, trio_intmax_t)
1852 : (trio_uintmax_t)(*((trio_intmax_t *)argarray[num]));
1853 else
1854 #endif
1855 if (parameters[i].flags & FLAGS_QUAD)
1856 parameters[i].data.number.as_unsigned = (argarray == NULL)
1857 ? (trio_uintmax_t)va_arg(arglist, trio_ulonglong_t)
1858 : (trio_uintmax_t)(*((trio_ulonglong_t *)argarray[num]));
1859 else if (parameters[i].flags & FLAGS_LONG)
1860 parameters[i].data.number.as_unsigned = (argarray == NULL)
1861 ? (trio_uintmax_t)va_arg(arglist, long)
1862 : (trio_uintmax_t)(*((long *)argarray[num]));
1863 else
1864 {
1865 if (argarray == NULL)
1866 parameters[i].data.number.as_unsigned = (trio_uintmax_t)va_arg(arglist, int);
1867 else
1868 {
1869 if (parameters[i].type == FORMAT_CHAR)
1870 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((char *)argarray[num]));
1871 else if (parameters[i].flags & FLAGS_SHORT)
1872 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((short *)argarray[num]));
1873 else
1874 parameters[i].data.number.as_unsigned = (trio_uintmax_t)(*((int *)argarray[num]));
1875 }
1876 }
1877 }
1878 break;
1879
1880 case FORMAT_PARAMETER:
1881 /*
1882 * The parameter for the user-defined specifier is a pointer,
1883 * whereas the rest (width, precision, base) uses an integer.
1884 */
1885 if (parameters[i].flags & FLAGS_USER_DEFINED)
1886 parameters[i].data.pointer = (argarray == NULL)
1887 ? va_arg(arglist, trio_pointer_t )
1888 : argarray[num];
1889 else
1890 parameters[i].data.number.as_unsigned = (argarray == NULL)
1891 ? (trio_uintmax_t)va_arg(arglist, int)
1892 : (trio_uintmax_t)(*((int *)argarray[num]));
1893 break;
1894
1895 #if TRIO_FEATURE_ERRNO
1896 case FORMAT_ERRNO:
1897 parameters[i].data.errorNumber = save_errno;
1898 break;
1899 #endif
1900
1901 default:
1902 break;
1903 }
1904 } /* for all specifiers */
1905 return num;
1906 }
1907
1908
1909 /*************************************************************************
1910 *
1911 * FORMATTING
1912 *
1913 ************************************************************************/
1914
1915
1916 /*************************************************************************
1917 * TrioWriteNumber
1918 *
1919 * Description:
1920 * Output a number.
1921 * The complexity of this function is a result of the complexity
1922 * of the dependencies of the flags.
1923 */
1924 TRIO_PRIVATE void
1925 TrioWriteNumber
1926 TRIO_ARGS6((self, number, flags, width, precision, base),
1927 trio_class_t *self,
1928 trio_uintmax_t number,
1929 trio_flags_t flags,
1930 int width,
1931 int precision,
1932 int base)
1933 {
1934 BOOLEAN_T isNegative;
1935 BOOLEAN_T isNumberZero;
1936 BOOLEAN_T isPrecisionZero;
1937 BOOLEAN_T ignoreNumber;
1938 char buffer[MAX_CHARS_IN(trio_uintmax_t) * (1 + MAX_LOCALE_SEPARATOR_LENGTH) + 1];
1939 char *bufferend;
1940 char *pointer;
1941 TRIO_CONST char *digits;
1942 int i;
1943 #if TRIO_FEATURE_QUOTE
1944 int length;
1945 char *p;
1946 #endif
1947 int count;
1948 int digitOffset;
1949
1950 assert(VALID(self));
1951 assert(VALID(self->OutStream));
1952 assert(((base >= MIN_BASE) && (base <= MAX_BASE)) || (base == NO_BASE));
1953
1954 digits = (flags & FLAGS_UPPER) ? internalDigitsUpper : internalDigitsLower;
1955 if (base == NO_BASE)
1956 base = BASE_DECIMAL;
1957
1958 isNumberZero = (number == 0);
1959 isPrecisionZero = (precision == 0);
1960 ignoreNumber = (isNumberZero
1961 && isPrecisionZero
1962 && !((flags & FLAGS_ALTERNATIVE) && (base == BASE_OCTAL)));
1963
1964 if (flags & FLAGS_UNSIGNED)
1965 {
1966 isNegative = FALSE;
1967 flags &= ~FLAGS_SHOWSIGN;
1968 }
1969 else
1970 {
1971 isNegative = ((trio_intmax_t)number < 0);
1972 if (isNegative)
1973 number = -((trio_intmax_t)number);
1974 }
1975
1976 if (flags & FLAGS_QUAD)
1977 number &= (trio_ulonglong_t)-1;
1978 else if (flags & FLAGS_LONG)
1979 number &= (unsigned long)-1;
1980 else
1981 number &= (unsigned int)-1;
1982
1983 /* Build number */
1984 pointer = bufferend = &buffer[sizeof(buffer) - 1];
1985 *pointer-- = NIL;
1986 for (i = 1; i < (int)sizeof(buffer); i++)
1987 {
1988 digitOffset = number % base;
1989 *pointer-- = digits[digitOffset];
1990 number /= base;
1991 if (number == 0)
1992 break;
1993
1994 #if TRIO_FEATURE_QUOTE
1995 if ((flags & FLAGS_QUOTE) && TrioFollowedBySeparator(i + 1))
1996 {
1997 /*
1998 * We are building the number from the least significant
1999 * to the most significant digit, so we have to copy the
2000 * thousand separator backwards
2001 */
2002 length = internalThousandSeparatorLength;
2003 if (((int)(pointer - buffer) - length) > 0)
2004 {
2005 p = &internalThousandSeparator[length - 1];
2006 while (length-- > 0)
2007 *pointer-- = *p--;
2008 }
2009 }
2010 #endif
2011 }
2012
2013 if (! ignoreNumber)
2014 {
2015 /* Adjust width */
2016 width -= (bufferend - pointer) - 1;
2017 }
2018
2019 /* Adjust precision */
2020 if (NO_PRECISION != precision)
2021 {
2022 precision -= (bufferend - pointer) - 1;
2023 if (precision < 0)
2024 precision = 0;
2025 flags |= FLAGS_NILPADDING;
2026 }
2027
2028 /* Calculate padding */
2029 count = (! ((flags & FLAGS_LEFTADJUST) || (precision == NO_PRECISION)))
2030 ? precision
2031 : 0;
2032
2033 /* Adjust width further */
2034 if (isNegative || (flags & FLAGS_SHOWSIGN) || (flags & FLAGS_SPACE))
2035 width--;
2036 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2037 {
2038 switch (base)
2039 {
2040 case BASE_BINARY:
2041 case BASE_HEX:
2042 width -= 2;
2043 break;
2044 case BASE_OCTAL:
2045 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2046 width--;
2047 break;
2048 default:
2049 break;
2050 }
2051 }
2052
2053 /* Output prefixes spaces if needed */
2054 if (! ((flags & FLAGS_LEFTADJUST) ||
2055 ((flags & FLAGS_NILPADDING) && (precision == NO_PRECISION))))
2056 {
2057 while (width-- > count)
2058 self->OutStream(self, CHAR_ADJUST);
2059 }
2060
2061 /* width has been adjusted for signs and alternatives */
2062 if (isNegative)
2063 self->OutStream(self, '-');
2064 else if (flags & FLAGS_SHOWSIGN)
2065 self->OutStream(self, '+');
2066 else if (flags & FLAGS_SPACE)
2067 self->OutStream(self, ' ');
2068
2069 /* Prefix is not written when the value is zero */
2070 if ((flags & FLAGS_ALTERNATIVE) && !isNumberZero)
2071 {
2072 switch (base)
2073 {
2074 case BASE_BINARY:
2075 self->OutStream(self, '0');
2076 self->OutStream(self, (flags & FLAGS_UPPER) ? 'B' : 'b');
2077 break;
2078
2079 case BASE_OCTAL:
2080 if (!(flags & FLAGS_NILPADDING) || (count == 0))
2081 self->OutStream(self, '0');
2082 break;
2083
2084 case BASE_HEX:
2085 self->OutStream(self, '0');
2086 self->OutStream(self, (flags & FLAGS_UPPER) ? 'X' : 'x');
2087 break;
2088
2089 default:
2090 break;
2091 } /* switch base */
2092 }
2093
2094 /* Output prefixed zero padding if needed */
2095 if (flags & FLAGS_NILPADDING)
2096 {
2097 if (precision == NO_PRECISION)
2098 precision = width;
2099 while (precision-- > 0)
2100 {
2101 self->OutStream(self, '0');
2102 width--;
2103 }
2104 }
2105
2106 if (! ignoreNumber)
2107 {
2108 /* Output the number itself */
2109 while (*(++pointer))
2110 {
2111 self->OutStream(self, *pointer);
2112 }
2113 }
2114
2115 /* Output trailing spaces if needed */
2116 if (flags & FLAGS_LEFTADJUST)
2117 {
2118 while (width-- > 0)
2119 self->OutStream(self, CHAR_ADJUST);
2120 }
2121 }
2122
2123 /*************************************************************************
2124 * TrioWriteStringCharacter
2125 *
2126 * Description:
2127 * Output a single character of a string
2128 */
2129 TRIO_PRIVATE void
2130 TrioWriteStringCharacter
2131 TRIO_ARGS3((self, ch, flags),
2132 trio_class_t *self,
2133 int ch,
2134 trio_flags_t flags)
2135 {
2136 if (flags & FLAGS_ALTERNATIVE)
2137 {
2138 if (! isprint(ch))
2139 {
2140 /*
2141 * Non-printable characters are converted to C escapes or
2142 * \number, if no C escape exists.
2143 */
2144 self->OutStream(self, CHAR_BACKSLASH);
2145 switch (ch)
2146 {
2147 case '\007': self->OutStream(self, 'a'); break;
2148 case '\b': self->OutStream(self, 'b'); break;
2149 case '\f': self->OutStream(self, 'f'); break;
2150 case '\n': self->OutStream(self, 'n'); break;
2151 case '\r': self->OutStream(self, 'r'); break;
2152 case '\t': self->OutStream(self, 't'); break;
2153 case '\v': self->OutStream(self, 'v'); break;
2154 case '\\': self->OutStream(self, '\\'); break;
2155 default:
2156 self->OutStream(self, 'x');
2157 TrioWriteNumber(self, (trio_uintmax_t)ch,
2158 FLAGS_UNSIGNED | FLAGS_NILPADDING,
2159 2, 2, BASE_HEX);
2160 break;
2161 }
2162 }
2163 else if (ch == CHAR_BACKSLASH)
2164 {
2165 self->OutStream(self, CHAR_BACKSLASH);
2166 self->OutStream(self, CHAR_BACKSLASH);
2167 }
2168 else
2169 {
2170 self->OutStream(self, ch);
2171 }
2172 }
2173 else
2174 {
2175 self->OutStream(self, ch);
2176 }
2177 }
2178
2179 /*************************************************************************
2180 * TrioWriteString
2181 *
2182 * Description:
2183 * Output a string
2184 */
2185 TRIO_PRIVATE void
2186 TrioWriteString
2187 TRIO_ARGS5((self, string, flags, width, precision),
2188 trio_class_t *self,
2189 TRIO_CONST char *string,
2190 trio_flags_t flags,
2191 int width,
2192 int precision)
2193 {
2194 int length;
2195 int ch;
2196
2197 assert(VALID(self));
2198 assert(VALID(self->OutStream));
2199
2200 if (string == NULL)
2201 {
2202 string = internalNullString;
2203 length = sizeof(internalNullString) - 1;
2204 #if TRIO_FEATURE_QUOTE
2205 /* Disable quoting for the null pointer */
2206 flags &= (~FLAGS_QUOTE);
2207 #endif
2208 width = 0;
2209 }
2210 else
2211 {
2212 if (precision == 0)
2213 {
2214 length = trio_length(string);
2215 }
2216 else
2217 {
2218 length = trio_length_max(string, precision);
2219 }
2220 }
2221 if ((NO_PRECISION != precision) &&
2222 (precision < length))
2223 {
2224 length = precision;
2225 }
2226 width -= length;
2227
2228 #if TRIO_FEATURE_QUOTE
2229 if (flags & FLAGS_QUOTE)
2230 self->OutStream(self, CHAR_QUOTE);
2231 #endif
2232
2233 if (! (flags & FLAGS_LEFTADJUST))
2234 {
2235 while (width-- > 0)
2236 self->OutStream(self, CHAR_ADJUST);
2237 }
2238
2239 while (length-- > 0)
2240 {
2241 /* The ctype parameters must be an unsigned char (or EOF) */
2242 ch = (int)((unsigned char)(*string++));
2243 TrioWriteStringCharacter(self, ch, flags);
2244 }
2245
2246 if (flags & FLAGS_LEFTADJUST)
2247 {
2248 while (width-- > 0)
2249 self->OutStream(self, CHAR_ADJUST);
2250 }
2251 #if TRIO_FEATURE_QUOTE
2252 if (flags & FLAGS_QUOTE)
2253 self->OutStream(self, CHAR_QUOTE);
2254 #endif
2255 }
2256
2257 /*************************************************************************
2258 * TrioWriteWideStringCharacter
2259 *
2260 * Description:
2261 * Output a wide string as a multi-byte sequence
2262 */
2263 #if TRIO_FEATURE_WIDECHAR
2264 TRIO_PRIVATE int
2265 TrioWriteWideStringCharacter
2266 TRIO_ARGS4((self, wch, flags, width),
2267 trio_class_t *self,
2268 trio_wchar_t wch,
2269 trio_flags_t flags,
2270 int width)
2271 {
2272 int size;
2273 int i;
2274 int ch;
2275 char *string;
2276 char buffer[MB_LEN_MAX + 1];
2277
2278 if (width == NO_WIDTH)
2279 width = sizeof(buffer);
2280
2281 size = wctomb(buffer, wch);
2282 if ((size <= 0) || (size > width) || (buffer[0] == NIL))
2283 return 0;
2284
2285 string = buffer;
2286 i = size;
2287 while ((width >= i) && (width-- > 0) && (i-- > 0))
2288 {
2289 /* The ctype parameters must be an unsigned char (or EOF) */
2290 ch = (int)((unsigned char)(*string++));
2291 TrioWriteStringCharacter(self, ch, flags);
2292 }
2293 return size;
2294 }
2295 #endif /* TRIO_FEATURE_WIDECHAR */
2296
2297 /*************************************************************************
2298 * TrioWriteWideString
2299 *
2300 * Description:
2301 * Output a wide character string as a multi-byte string
2302 */
2303 #if TRIO_FEATURE_WIDECHAR
2304 TRIO_PRIVATE void
2305 TrioWriteWideString
2306 TRIO_ARGS5((self, wstring, flags, width, precision),
2307 trio_class_t *self,
2308 TRIO_CONST trio_wchar_t *wstring,
2309 trio_flags_t flags,
2310 int width,
2311 int precision)
2312 {
2313 int length;
2314 int size;
2315
2316 assert(VALID(self));
2317 assert(VALID(self->OutStream));
2318
2319 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
2320 /* Required by TrioWriteWideStringCharacter */
2321 (void)mblen(NULL, 0);
2322 #endif
2323
2324 if (wstring == NULL)
2325 {
2326 TrioWriteString(self, NULL, flags, width, precision);
2327 return;
2328 }
2329
2330 if (NO_PRECISION == precision)
2331 {
2332 length = INT_MAX;
2333 }
2334 else
2335 {
2336 length = precision;
2337 width -= length;
2338 }
2339
2340 #if TRIO_FEATURE_QUOTE
2341 if (flags & FLAGS_QUOTE)
2342 self->OutStream(self, CHAR_QUOTE);
2343 #endif
2344
2345 if (! (flags & FLAGS_LEFTADJUST))
2346 {
2347 while (width-- > 0)
2348 self->OutStream(self, CHAR_ADJUST);
2349 }
2350
2351 while (length > 0)
2352 {
2353 size = TrioWriteWideStringCharacter(self, *wstring++, flags, length);
2354 if (size == 0)
2355 break; /* while */
2356 length -= size;
2357 }
2358
2359 if (flags & FLAGS_LEFTADJUST)
2360 {
2361 while (width-- > 0)
2362 self->OutStream(self, CHAR_ADJUST);
2363 }
2364 #if TRIO_FEATURE_QUOTE
2365 if (flags & FLAGS_QUOTE)
2366 self->OutStream(self, CHAR_QUOTE);
2367 #endif
2368 }
2369 #endif /* TRIO_FEATURE_WIDECHAR */
2370
2371 /*************************************************************************
2372 * TrioFormatProcess
2373 *
2374 * Description:
2375 * This is the main engine for formatting output
2376 */
2377 TRIO_PRIVATE int
2378 TrioFormatProcess
2379 TRIO_ARGS3((data, format, parameters),
2380 trio_class_t *data,
2381 TRIO_CONST char *format,
2382 trio_parameter_t *parameters)
2383 {
2384 int i;
2385 #if TRIO_FEATURE_ERRNO
2386 TRIO_CONST char *string;
2387 #endif
2388 trio_pointer_t pointer;
2389 trio_flags_t flags;
2390 int width;
2391 int precision;
2392 int base;
2393 int offset;
2394
2395 offset = 0;
2396 i = 0;
2397
2398 for (;;)
2399 {
2400 /* Skip the parameter entries */
2401 while (parameters[i].type == FORMAT_PARAMETER)
2402 i++;
2403
2404 /* Copy non conversion-specifier part of format string */
2405 while (offset < parameters[i].beginOffset)
2406 {
2407 if (CHAR_IDENTIFIER == format[offset] && CHAR_IDENTIFIER == format[offset + 1])
2408 {
2409 data->OutStream(data, CHAR_IDENTIFIER);
2410 offset += 2;
2411 }
2412 else
2413 {
2414 data->OutStream(data, format[offset++]);
2415 }
2416 }
2417
2418 /* Abort if we reached end of format string */
2419 if (parameters[i].type == FORMAT_SENTINEL)
2420 break;
2421
2422 /* Ouput parameter */
2423 flags = parameters[i].flags;
2424
2425 /* Find width */
2426 width = parameters[i].width;
2427 if (flags & FLAGS_WIDTH_PARAMETER)
2428 {
2429 /* Get width from parameter list */
2430 width = (int)parameters[width].data.number.as_signed;
2431 if (width < 0)
2432 {
2433 /*
2434 * A negative width is the same as the - flag and
2435 * a positive width.
2436 */
2437 flags |= FLAGS_LEFTADJUST;
2438 flags &= ~FLAGS_NILPADDING;
2439 width = -width;
2440 }
2441 }
2442
2443 /* Find precision */
2444 if (flags & FLAGS_PRECISION)
2445 {
2446 precision = parameters[i].precision;
2447 if (flags & FLAGS_PRECISION_PARAMETER)
2448 {
2449 /* Get precision from parameter list */
2450 precision = (int)parameters[precision].data.number.as_signed;
2451 if (precision < 0)
2452 {
2453 /*
2454 * A negative precision is the same as no
2455 * precision
2456 */
2457 precision = NO_PRECISION;
2458 }
2459 }
2460 }
2461 else
2462 {
2463 precision = NO_PRECISION;
2464 }
2465
2466 /* Find base */
2467 if (NO_BASE != parameters[i].baseSpecifier)
2468 {
2469 /* Base from specifier has priority */
2470 base = parameters[i].baseSpecifier;
2471 }
2472 else if (flags & FLAGS_BASE_PARAMETER)
2473 {
2474 /* Get base from parameter list */
2475 base = parameters[i].base;
2476 base = (int)parameters[base].data.number.as_signed;
2477 }
2478 else
2479 {
2480 /* Use base from format string */
2481 base = parameters[i].base;
2482 }
2483
2484 switch (parameters[i].type)
2485 {
2486 case FORMAT_CHAR:
2487 #if TRIO_FEATURE_QUOTE
2488 if (flags & FLAGS_QUOTE)
2489 data->OutStream(data, CHAR_QUOTE);
2490 #endif
2491 if (! (flags & FLAGS_LEFTADJUST))
2492 {
2493 while (--width > 0)
2494 data->OutStream(data, CHAR_ADJUST);
2495 }
2496 #if TRIO_FEATURE_WIDECHAR
2497 if (flags & FLAGS_WIDECHAR)
2498 {
2499 TrioWriteWideStringCharacter(data,
2500 (trio_wchar_t)parameters[i].data.number.as_signed,
2501 flags,
2502 NO_WIDTH);
2503 }
2504 else
2505 #endif
2506 {
2507 TrioWriteStringCharacter(data,
2508 (int)parameters[i].data.number.as_signed,
2509 flags);
2510 }
2511
2512 if (flags & FLAGS_LEFTADJUST)
2513 {
2514 while(--width > 0)
2515 data->OutStream(data, CHAR_ADJUST);
2516 }
2517 #if TRIO_FEATURE_QUOTE
2518 if (flags & FLAGS_QUOTE)
2519 data->OutStream(data, CHAR_QUOTE);
2520 #endif
2521
2522 break; /* FORMAT_CHAR */
2523
2524 case FORMAT_INT:
2525 TrioWriteNumber(data,
2526 parameters[i].data.number.as_unsigned,
2527 flags,
2528 width,
2529 precision,
2530 base);
2531
2532 break; /* FORMAT_INT */
2533 case FORMAT_STRING:
2534 #if TRIO_FEATURE_WIDECHAR
2535 if (flags & FLAGS_WIDECHAR)
2536 {
2537 TrioWriteWideString(data,
2538 parameters[i].data.wstring,
2539 flags,
2540 width,
2541 precision);
2542 }
2543 else
2544 #endif
2545 {
2546 TrioWriteString(data,
2547 parameters[i].data.string,
2548 flags,
2549 width,
2550 precision);
2551 }
2552 break; /* FORMAT_STRING */
2553
2554 case FORMAT_POINTER:
2555 {
2556 trio_reference_t reference;
2557
2558 reference.data = data;
2559 reference.parameter = &parameters[i];
2560 trio_print_pointer(&reference, parameters[i].data.pointer);
2561 }
2562 break; /* FORMAT_POINTER */
2563
2564 case FORMAT_COUNT:
2565 pointer = parameters[i].data.pointer;
2566 if (NULL != pointer)
2567 {
2568 /*
2569 * C99 paragraph 7.19.6.1.8 says "the number of
2570 * characters written to the output stream so far by
2571 * this call", which is data->actually.committed
2572 */
2573 #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
2574 if (flags & FLAGS_SIZE_T)
2575 *(size_t *)pointer = (size_t)data->actually.committed;
2576 else
2577 #endif
2578 #if TRIO_FEATURE_PTRDIFF_T
2579 if (flags & FLAGS_PTRDIFF_T)
2580 *(ptrdiff_t *)pointer = (ptrdiff_t)data->actually.committed;
2581 else
2582 #endif
2583 #if TRIO_FEATURE_INTMAX_T
2584 if (flags & FLAGS_INTMAX_T)
2585 *(trio_intmax_t *)pointer = (trio_intmax_t)data->actually.committed;
2586 else
2587 #endif
2588 if (flags & FLAGS_QUAD)
2589 {
2590 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)data->actually.committed;
2591 }
2592 else if (flags & FLAGS_LONG)
2593 {
2594 *(long int *)pointer = (long int)data->actually.committed;
2595 }
2596 else if (flags & FLAGS_SHORT)
2597 {
2598 *(short int *)pointer = (short int)data->actually.committed;
2599 }
2600 else
2601 {
2602 *(int *)pointer = (int)data->actually.committed;
2603 }
2604 }
2605 break; /* FORMAT_COUNT */
2606
2607 case FORMAT_PARAMETER:
2608 break; /* FORMAT_PARAMETER */
2609
2610 #if TRIO_FEATURE_ERRNO
2611 case FORMAT_ERRNO:
2612 string = trio_error(parameters[i].data.errorNumber);
2613 if (string)
2614 {
2615 TrioWriteString(data,
2616 string,
2617 flags,
2618 width,
2619 precision);
2620 }
2621 else
2622 {
2623 data->OutStream(data, '#');
2624 TrioWriteNumber(data,
2625 (trio_uintmax_t)parameters[i].data.errorNumber,
2626 flags,
2627 width,
2628 precision,
2629 BASE_DECIMAL);
2630 }
2631 break; /* FORMAT_ERRNO */
2632 #endif /* TRIO_FEATURE_ERRNO */
2633
2634 default:
2635 break;
2636 } /* switch parameter type */
2637
2638 /* Prepare for next */
2639 offset = parameters[i].endOffset;
2640 i++;
2641 }
2642
2643 return data->processed;
2644 }
2645
2646 /*************************************************************************
2647 * TrioFormat
2648 */
2649 TRIO_PRIVATE int
2650 TrioFormat
2651 TRIO_ARGS6((destination, destinationSize, OutStream, format, arglist, argarray),
2652 trio_pointer_t destination,
2653 size_t destinationSize,
2654 void (*OutStream) TRIO_PROTO((trio_class_t *, int)),
2655 TRIO_CONST char *format,
2656 va_list arglist,
2657 trio_pointer_t *argarray)
2658 {
2659 int status;
2660 trio_class_t data;
2661 trio_parameter_t parameters[MAX_PARAMETERS];
2662
2663 assert(VALID(OutStream));
2664 assert(VALID(format));
2665
2666 memset(&data, 0, sizeof(data));
2667 data.OutStream = OutStream;
2668 data.location = destination;
2669 data.max = destinationSize;
2670 data.error = 0;
2671
2672 #if defined(USE_LOCALE)
2673 if (NULL == internalLocaleValues)
2674 {
2675 TrioSetLocale();
2676 }
2677 #endif
2678
2679 status = TrioParse(TYPE_PRINT, format, parameters, arglist, argarray);
2680 if (status < 0)
2681 return status;
2682
2683 status = TrioFormatProcess(&data, format, parameters);
2684 if (data.error != 0)
2685 {
2686 status = data.error;
2687 }
2688 return status;
2689 }
2690
2691 /*************************************************************************
2692 * TrioOutStreamFile
2693 */
2694
2695 /*************************************************************************
2696 * TrioOutStreamCustom
2697 */
2698
2699 /*************************************************************************
2700 * TrioOutStreamString
2701 */
2702 TRIO_PRIVATE void
2703 TrioOutStreamString
2704 TRIO_ARGS2((self, output),
2705 trio_class_t *self,
2706 int output)
2707 {
2708 char **buffer;
2709
2710 assert(VALID(self));
2711 assert(VALID(self->location));
2712
2713 buffer = (char **)self->location;
2714 **buffer = (char)output;
2715 (*buffer)++;
2716 self->processed++;
2717 self->actually.committed++;
2718 }
2719
2720 /*************************************************************************
2721 * TrioOutStreamStringMax
2722 */
2723 TRIO_PRIVATE void
2724 TrioOutStreamStringMax
2725 TRIO_ARGS2((self, output),
2726 trio_class_t *self,
2727 int output)
2728 {
2729 char **buffer;
2730
2731 assert(VALID(self));
2732 assert(VALID(self->location));
2733
2734 buffer = (char **)self->location;
2735
2736 if (self->processed < self->max)
2737 {
2738 **buffer = (char)output;
2739 (*buffer)++;
2740 self->actually.committed++;
2741 }
2742 self->processed++;
2743 }
2744
2745 /*************************************************************************
2746 * TrioOutStreamStringDynamic
2747 */
2748 #if TRIO_FEATURE_DYNAMICSTRING
2749 TRIO_PRIVATE void
2750 TrioOutStreamStringDynamic
2751 TRIO_ARGS2((self, output),
2752 trio_class_t *self,
2753 int output)
2754 {
2755 assert(VALID(self));
2756 assert(VALID(self->location));
2757
2758 if (self->error == 0)
2759 {
2760 trio_xstring_append_char((trio_string_t *)self->location,
2761 (char)output);
2762 self->actually.committed++;
2763 }
2764 /* The processed variable must always be increased */
2765 self->processed++;
2766 }
2767 #endif /* TRIO_FEATURE_DYNAMICSTRING */
2768
2769 /*************************************************************************
2770 *
2771 * Formatted printing functions
2772 *
2773 ************************************************************************/
2774
2775 #if defined(TRIO_DOCUMENTATION)
2776 # include "doc/doc_printf.h"
2777 #endif
2778
2779 /*************************************************************************
2780 * dprintf
2781 */
2782
2783 /*************************************************************************
2784 * cprintf
2785 */
2786
2787 /*************************************************************************
2788 * sprintf
2789 */
2790
2791 /**
2792 Print to string.
2793
2794 @param buffer Output string.
2795 @param format Formatting string.
2796 @param ... Arguments.
2797 @return Number of printed characters.
2798 */
2799 TRIO_PUBLIC int
2800 trio_sprintf
2801 TRIO_VARGS3((buffer, format, va_alist),
2802 char *buffer,
2803 TRIO_CONST char *format,
2804 TRIO_VA_DECL)
2805 {
2806 int status;
2807 va_list args;
2808
2809 assert(VALID(buffer));
2810 assert(VALID(format));
2811
2812 TRIO_VA_START(args, format);
2813 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, args, NULL);
2814 *buffer = NIL; /* Terminate with NIL character */
2815 TRIO_VA_END(args);
2816 return status;
2817 }
2818
2819 /**
2820 Print to string.
2821
2822 @param buffer Output string.
2823 @param format Formatting string.
2824 @param args Arguments.
2825 @return Number of printed characters.
2826 */
2827 TRIO_PUBLIC int
2828 trio_sprintfv
2829 TRIO_ARGS3((buffer, format, args),
2830 char *buffer,
2831 TRIO_CONST char *format,
2832 trio_pointer_t *args)
2833 {
2834 static va_list unused;
2835 int status;
2836
2837 assert(VALID(buffer));
2838 assert(VALID(format));
2839
2840 status = TrioFormat(&buffer, 0, TrioOutStreamString, format, unused, args);
2841 *buffer = NIL;
2842 return status;
2843 }
2844
2845 /*************************************************************************
2846 * snprintf
2847 */
2848
2849 /**
2850 Print at most @p max characters to string.
2851
2852 @param buffer Output string.
2853 @param max Maximum number of characters to print.
2854 @param format Formatting string.
2855 @param ... Arguments.
2856 @return Number of printed characters.
2857 */
2858 TRIO_PUBLIC int
2859 trio_snprintf
2860 TRIO_VARGS4((buffer, max, format, va_alist),
2861 char *buffer,
2862 size_t max,
2863 TRIO_CONST char *format,
2864 TRIO_VA_DECL)
2865 {
2866 int status;
2867 va_list args;
2868
2869 assert(VALID(buffer) || (max == 0));
2870 assert(VALID(format));
2871
2872 TRIO_VA_START(args, format);
2873 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
2874 TrioOutStreamStringMax, format, args, NULL);
2875 if (max > 0)
2876 *buffer = NIL;
2877 TRIO_VA_END(args);
2878 return status;
2879 }
2880
2881 /**
2882 Print at most @p max characters to string.
2883
2884 @param buffer Output string.
2885 @param max Maximum number of characters to print.
2886 @param format Formatting string.
2887 @param args Arguments.
2888 @return Number of printed characters.
2889 */
2890 TRIO_PUBLIC int
2891 trio_snprintfv
2892 TRIO_ARGS4((buffer, max, format, args),
2893 char *buffer,
2894 size_t max,
2895 TRIO_CONST char *format,
2896 trio_pointer_t *args)
2897 {
2898 static va_list unused;
2899 int status;
2900
2901 assert(VALID(buffer) || (max == 0));
2902 assert(VALID(format));
2903
2904 status = TrioFormat(&buffer, max > 0 ? max - 1 : 0,
2905 TrioOutStreamStringMax, format, unused, args);
2906 if (max > 0)
2907 *buffer = NIL;
2908 return status;
2909 }
2910
2911 /*************************************************************************
2912 * trio_aprintf
2913 */
2914
2915 #if TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING
2916 TRIO_PUBLIC char *
2917 trio_aprintf
2918 TRIO_VARGS2((format, va_alist),
2919 TRIO_CONST char *format,
2920 TRIO_VA_DECL)
2921 {
2922 va_list args;
2923 trio_string_t *info;
2924 char *result = NULL;
2925
2926 assert(VALID(format));
2927
2928 info = trio_xstring_duplicate("");
2929 if (info)
2930 {
2931 TRIO_VA_START(args, format);
2932 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
2933 format, args, NULL);
2934 TRIO_VA_END(args);
2935
2936 trio_string_terminate(info);
2937 result = trio_string_extract(info);
2938 trio_string_destroy(info);
2939 }
2940 return result;
2941 }
2942 #endif /* TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING */
2943
2944 #if TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING
2945 TRIO_PUBLIC char *
2946 trio_vaprintf
2947 TRIO_ARGS2((format, args),
2948 TRIO_CONST char *format,
2949 va_list args)
2950 {
2951 trio_string_t *info;
2952 char *result = NULL;
2953
2954 assert(VALID(format));
2955
2956 info = trio_xstring_duplicate("");
2957 if (info)
2958 {
2959 (void)TrioFormat(info, 0, TrioOutStreamStringDynamic,
2960 format, args, NULL);
2961 trio_string_terminate(info);
2962 result = trio_string_extract(info);
2963 trio_string_destroy(info);
2964 }
2965 return result;
2966 }
2967 #endif /* TRIO_DEPRECATED && TRIO_FEATURE_DYNAMICSTRING */
2968
2969 /**
2970 Allocate and print to string.
2971 The memory allocated and returned by @p result must be freed by the
2972 calling application.
2973
2974 @param result Output string.
2975 @param format Formatting string.
2976 @param ... Arguments.
2977 @return Number of printed characters.
2978 */
2979 #if TRIO_FEATURE_DYNAMICSTRING
2980 TRIO_PUBLIC int
2981 trio_asprintf
2982 TRIO_VARGS3((result, format, va_alist),
2983 char **result,
2984 TRIO_CONST char *format,
2985 TRIO_VA_DECL)
2986 {
2987 va_list args;
2988 int status;
2989 trio_string_t *info;
2990
2991 assert(VALID(format));
2992
2993 *result = NULL;
2994
2995 info = trio_xstring_duplicate("");
2996 if (info == NULL)
2997 {
2998 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
2999 }
3000 else
3001 {
3002 TRIO_VA_START(args, format);
3003 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
3004 format, args, NULL);
3005 TRIO_VA_END(args);
3006 if (status >= 0)
3007 {
3008 trio_string_terminate(info);
3009 *result = trio_string_extract(info);
3010 }
3011 trio_string_destroy(info);
3012 }
3013 return status;
3014 }
3015 #endif /* TRIO_FEATURE_DYNAMICSTRING */
3016
3017 /**
3018 Allocate and print to string.
3019 The memory allocated and returned by @p result must be freed by the
3020 calling application.
3021
3022 @param result Output string.
3023 @param format Formatting string.
3024 @param args Arguments.
3025 @return Number of printed characters.
3026 */
3027 #if TRIO_FEATURE_DYNAMICSTRING
3028 TRIO_PUBLIC int
3029 trio_vasprintf
3030 TRIO_ARGS3((result, format, args),
3031 char **result,
3032 TRIO_CONST char *format,
3033 va_list args)
3034 {
3035 int status;
3036 trio_string_t *info;
3037
3038 assert(VALID(format));
3039
3040 *result = NULL;
3041
3042 info = trio_xstring_duplicate("");
3043 if (info == NULL)
3044 {
3045 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3046 }
3047 else
3048 {
3049 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
3050 format, args, NULL);
3051 if (status >= 0)
3052 {
3053 trio_string_terminate(info);
3054 *result = trio_string_extract(info);
3055 }
3056 trio_string_destroy(info);
3057 }
3058 return status;
3059 }
3060 #endif /* TRIO_FEATURE_DYNAMICSTRING */
3061
3062 /**
3063 Allocate and print to string.
3064 The memory allocated and returned by @p result must be freed by the
3065 calling application.
3066
3067 @param result Output string.
3068 @param format Formatting string.
3069 @param args Arguments.
3070 @return Number of printed characters.
3071 */
3072 #if TRIO_FEATURE_DYNAMICSTRING
3073 TRIO_PUBLIC int
3074 trio_asprintfv
3075 TRIO_ARGS3((result, format, args),
3076 char **result,
3077 TRIO_CONST char *format,
3078 trio_pointer_t * args)
3079 {
3080 static va_list unused;
3081 int status;
3082 trio_string_t *info;
3083
3084 assert(VALID(format));
3085
3086 *result = NULL;
3087
3088 info = trio_xstring_duplicate("");
3089 if (info == NULL)
3090 {
3091 status = TRIO_ERROR_RETURN(TRIO_ENOMEM, 0);
3092 }
3093 else
3094 {
3095 status = TrioFormat(info, 0, TrioOutStreamStringDynamic,
3096 format, unused, args);
3097 if (status >= 0)
3098 {
3099 trio_string_terminate(info);
3100 *result = trio_string_extract(info);
3101 }
3102 trio_string_destroy(info);
3103 }
3104 return status;
3105 }
3106 #endif /* TRIO_FEATURE_DYNAMICSTRING */
3107
3108 /** @} End of Printf documentation module */
3109
3110 /*************************************************************************
3111 *
3112 * CALLBACK
3113 *
3114 ************************************************************************/
3115
3116 #if defined(TRIO_DOCUMENTATION)
3117 # include "doc/doc_register.h"
3118 #endif
3119 /**
3120 @addtogroup UserDefined
3121 @{
3122 */
3123
3124 /*************************************************************************
3125 * trio_print_pointer [public]
3126 */
3127 void
3128 trio_print_pointer
3129 TRIO_ARGS2((ref, pointer),
3130 trio_pointer_t ref,
3131 trio_pointer_t pointer)
3132 {
3133 trio_reference_t *self = (trio_reference_t *)ref;
3134 trio_flags_t flags;
3135 trio_uintmax_t number;
3136
3137 if (NULL == pointer)
3138 {
3139 TRIO_CONST char *string = internalNullString;
3140 while (*string)
3141 self->data->OutStream(self->data, *string++);
3142 }
3143 else
3144 {
3145 /*
3146 * The subtraction of the null pointer is a workaround
3147 * to avoid a compiler warning. The performance overhead
3148 * is negligible (and likely to be removed by an
3149 * optimizing compiler). The (char *) casting is done
3150 * to please ANSI C++.
3151 */
3152 number = (trio_uintmax_t)((char *)pointer - (char *)0);
3153 /* Shrink to size of pointer */
3154 number &= (trio_uintmax_t)-1;
3155 flags = self->parameter->flags;
3156 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE |
3157 FLAGS_NILPADDING);
3158 TrioWriteNumber(self->data,
3159 number,
3160 flags,
3161 POINTER_WIDTH,
3162 NO_PRECISION,
3163 BASE_HEX);
3164 }
3165 }
3166
3167 /** @} End of UserDefined documentation module */
3168
3169 /*************************************************************************
3170 *
3171 * LOCALES
3172 *
3173 ************************************************************************/
3174
3175 /*************************************************************************
3176 * trio_locale_set_decimal_point
3177 *
3178 * Decimal point can only be one character. The input argument is a
3179 * string to enable multibyte characters. At most MB_LEN_MAX characters
3180 * will be used.
3181 */
3182
3183 /*************************************************************************
3184 * trio_locale_set_thousand_separator
3185 *
3186 * See trio_locale_set_decimal_point
3187 */
3188
3189 /*************************************************************************
3190 * trio_locale_set_grouping
3191 *
3192 * Array of bytes. Reversed order.
3193 *
3194 * CHAR_MAX : No further grouping
3195 * 0 : Repeat last group for the remaining digits (not necessary
3196 * as C strings are zero-terminated)
3197 * n : Set current group to n
3198 *
3199 * Same order as the grouping attribute in LC_NUMERIC.
3200 */
3201
3202
3203 /*************************************************************************
3204 *
3205 * SCANNING
3206 *
3207 ************************************************************************/
3208
3209 #if TRIO_FEATURE_SCANF
3210
3211 /*************************************************************************
3212 * TrioSkipWhitespaces
3213 */
3214 TRIO_PRIVATE int
3215 TrioSkipWhitespaces
3216 TRIO_ARGS1((self),
3217 trio_class_t *self)
3218 {
3219 int ch;
3220
3221 ch = self->current;
3222 while (isspace(ch))
3223 {
3224 self->InStream(self, &ch);
3225 }
3226 return ch;
3227 }
3228
3229 /*************************************************************************
3230 * TrioGetCharacterClass
3231 *
3232 * FIXME:
3233 * multibyte
3234 */
3235 TRIO_PRIVATE int
3236 TrioGetCharacterClass
3237 TRIO_ARGS4((format, offsetPointer, flagsPointer, characterclass),
3238 TRIO_CONST char *format,
3239 int *offsetPointer,
3240 trio_flags_t *flagsPointer,
3241 int *characterclass)
3242 {
3243 int offset = *offsetPointer;
3244 int i;
3245 char ch;
3246 char range_begin;
3247 char range_end;
3248
3249 *flagsPointer &= ~FLAGS_EXCLUDE;
3250
3251 if (format[offset] == QUALIFIER_CIRCUMFLEX)
3252 {
3253 *flagsPointer |= FLAGS_EXCLUDE;
3254 offset++;
3255 }
3256 /*
3257 * If the ungroup character is at the beginning of the scanlist,
3258 * it will be part of the class, and a second ungroup character
3259 * must follow to end the group.
3260 */
3261 if (format[offset] == SPECIFIER_UNGROUP)
3262 {
3263 characterclass[(int)SPECIFIER_UNGROUP]++;
3264 offset++;
3265 }
3266 /*
3267 * Minus is used to specify ranges. To include minus in the class,
3268 * it must be at the beginning of the list
3269 */
3270 if (format[offset] == QUALIFIER_MINUS)
3271 {
3272 characterclass[(int)QUALIFIER_MINUS]++;
3273 offset++;
3274 }
3275 /* Collect characters */
3276 for (ch = format[offset];
3277 (ch != SPECIFIER_UNGROUP) && (ch != NIL);
3278 ch = format[++offset])
3279 {
3280 switch (ch)
3281 {
3282 case QUALIFIER_MINUS: /* Scanlist ranges */
3283
3284 /*
3285 * Both C99 and UNIX98 describes ranges as implementation-
3286 * defined.
3287 *
3288 * We support the following behaviour (although this may
3289 * change as we become wiser)
3290 * - only increasing ranges, ie. [a-b] but not [b-a]
3291 * - transitive ranges, ie. [a-b-c] == [a-c]
3292 * - trailing minus, ie. [a-] is interpreted as an 'a'
3293 * and a '-'
3294 * - duplicates (although we can easily convert these
3295 * into errors)
3296 */
3297 range_begin = format[offset - 1];
3298 range_end = format[++offset];
3299 if (range_end == SPECIFIER_UNGROUP)
3300 {
3301 /* Trailing minus is included */
3302 characterclass[(int)ch]++;
3303 ch = range_end;
3304 break; /* for */
3305 }
3306 if (range_end == NIL)
3307 return TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
3308 if (range_begin > range_end)
3309 return TRIO_ERROR_RETURN(TRIO_ERANGE, offset);
3310
3311 for (i = (int)range_begin; i <= (int)range_end; i++)
3312 characterclass[i]++;
3313
3314 ch = range_end;
3315 break;
3316
3317
3318 default:
3319 characterclass[(int)ch]++;
3320 break;
3321 }
3322 }
3323 return 0;
3324 }
3325
3326 /*************************************************************************
3327 * TrioReadNumber
3328 *
3329 * We implement our own number conversion in preference of strtol and
3330 * strtoul, because we must handle 'long long' and thousand separators.
3331 */
3332 TRIO_PRIVATE BOOLEAN_T
3333 TrioReadNumber
3334 TRIO_ARGS5((self, target, flags, width, base),
3335 trio_class_t *self,
3336 trio_uintmax_t *target,
3337 trio_flags_t flags,
3338 int width,
3339 int base)
3340 {
3341 trio_uintmax_t number = 0;
3342 int digit;
3343 int count;
3344 BOOLEAN_T isNegative = FALSE;
3345 BOOLEAN_T gotNumber = FALSE;
3346 int j;
3347
3348 assert(VALID(self));
3349 assert(VALID(self->InStream));
3350 assert((base >= MIN_BASE && base <= MAX_BASE) || (base == NO_BASE));
3351
3352 if (internalDigitsUnconverted)
3353 {
3354 /* Lazy evaluation of digits array */
3355 memset(internalDigitArray, -1, sizeof(internalDigitArray));
3356 for (j = 0; j < (int)sizeof(internalDigitsLower) - 1; j++)
3357 {
3358 internalDigitArray[(int)internalDigitsLower[j]] = j;
3359 internalDigitArray[(int)internalDigitsUpper[j]] = j;
3360 }
3361 internalDigitsUnconverted = FALSE;
3362 }
3363
3364 TrioSkipWhitespaces(self);
3365
3366 /* Leading sign */
3367 if (self->current == '+')
3368 {
3369 self->InStream(self, NULL);
3370 }
3371 else if (self->current == '-')
3372 {
3373 self->InStream(self, NULL);
3374 isNegative = TRUE;
3375 }
3376
3377 count = self->processed;
3378
3379 if (flags & FLAGS_ALTERNATIVE)
3380 {
3381 switch (base)
3382 {
3383 case NO_BASE:
3384 case BASE_OCTAL:
3385 case BASE_HEX:
3386 case BASE_BINARY:
3387 if (self->current == '0')
3388 {
3389 self->InStream(self, NULL);
3390 if (self->current)
3391 {
3392 if ((base == BASE_HEX) &&
3393 (trio_to_upper(self->current) == 'X'))
3394 {
3395 self->InStream(self, NULL);
3396 }
3397 else if ((base == BASE_BINARY) &&
3398 (trio_to_upper(self->current) == 'B'))
3399 {
3400 self->InStream(self, NULL);
3401 }
3402 }
3403 }
3404 else
3405 return FALSE;
3406 break;
3407 default:
3408 break;
3409 }
3410 }
3411
3412 while (((width == NO_WIDTH) || (self->processed - count < width)) &&
3413 (! ((self->current == EOF) || isspace(self->current))))
3414 {
3415 if (isascii(self->current))
3416 {
3417 digit = internalDigitArray[self->current];
3418 /* Abort if digit is not allowed in the specified base */
3419 if ((digit == -1) || (digit >= base))
3420 break;
3421 }
3422 #if TRIO_FEATURE_QUOTE
3423 else if (flags & FLAGS_QUOTE)
3424 {
3425 /* Compare with thousands separator */
3426 for (j = 0; internalThousandSeparator[j] && self->current; j++)
3427 {
3428 if (internalThousandSeparator[j] != self->current)
3429 break;
3430
3431 self->InStream(self, NULL);
3432 }
3433 if (internalThousandSeparator[j])
3434 break; /* Mismatch */
3435 else
3436 continue; /* Match */
3437 }
3438 #endif
3439 else
3440 break;
3441
3442 number *= base;
3443 number += digit;
3444 gotNumber = TRUE; /* we need at least one digit */
3445
3446 self->InStream(self, NULL);
3447 }
3448
3449 /* Was anything read at all? */
3450 if (!gotNumber)
3451 return FALSE;
3452
3453 if (target)
3454 *target = (isNegative) ? (trio_uintmax_t)(-((trio_intmax_t)number)) : number;
3455 return TRUE;
3456 }
3457
3458 /*************************************************************************
3459 * TrioReadChar
3460 */
3461 TRIO_PRIVATE int
3462 TrioReadChar
3463 TRIO_ARGS4((self, target, flags, width),
3464 trio_class_t *self,
3465 char *target,
3466 trio_flags_t flags,
3467 int width)
3468 {
3469 int i;
3470 char ch;
3471 trio_uintmax_t number;
3472
3473 assert(VALID(self));
3474 assert(VALID(self->InStream));
3475
3476 for (i = 0;
3477 (self->current != EOF) && (i < width);
3478 i++)
3479 {
3480 ch = (char)self->current;
3481 self->InStream(self, NULL);
3482 if ((flags & FLAGS_ALTERNATIVE) && (ch == CHAR_BACKSLASH))
3483 {
3484 switch (self->current)
3485 {
3486 case '\\': ch = '\\'; break;
3487 case 'a': ch = '\007'; break;
3488 case 'b': ch = '\b'; break;
3489 case 'f': ch = '\f'; break;
3490 case 'n': ch = '\n'; break;
3491 case 'r': ch = '\r'; break;
3492 case 't': ch = '\t'; break;
3493 case 'v': ch = '\v'; break;
3494 default:
3495 if (isdigit(self->current))
3496 {
3497 /* Read octal number */
3498 if (!TrioReadNumber(self, &number, 0, 3, BASE_OCTAL))
3499 return 0;
3500 ch = (char)number;
3501 }
3502 else if (trio_to_upper(self->current) == 'X')
3503 {
3504 /* Read hexadecimal number */
3505 self->InStream(self, NULL);
3506 if (!TrioReadNumber(self, &number, 0, 2, BASE_HEX))
3507 return 0;
3508 ch = (char)number;
3509 }
3510 else
3511 {
3512 ch = (char)self->current;
3513 }
3514 break;
3515 }
3516 }
3517
3518 if (target)
3519 target[i] = ch;
3520 }
3521 return i + 1;
3522 }
3523
3524 /*************************************************************************
3525 * TrioReadString
3526 */
3527 TRIO_PRIVATE BOOLEAN_T
3528 TrioReadString
3529 TRIO_ARGS4((self, target, flags, width),
3530 trio_class_t *self,
3531 char *target,
3532 trio_flags_t flags,
3533 int width)
3534 {
3535 int i;
3536
3537 assert(VALID(self));
3538 assert(VALID(self->InStream));
3539
3540 TrioSkipWhitespaces(self);
3541
3542 /*
3543 * Continue until end of string is reached, a whitespace is encountered,
3544 * or width is exceeded
3545 */
3546 for (i = 0;
3547 ((width == NO_WIDTH) || (i < width)) &&
3548 (! ((self->current == EOF) || isspace(self->current)));
3549 i++)
3550 {
3551 if (TrioReadChar(self, (target ? &target[i] : 0), flags, 1) == 0)
3552 break; /* for */
3553 }
3554 if (target)
3555 target[i] = NIL;
3556 return TRUE;
3557 }
3558
3559 /*************************************************************************
3560 * TrioReadWideChar
3561 */
3562 #if TRIO_FEATURE_WIDECHAR
3563 TRIO_PRIVATE int
3564 TrioReadWideChar
3565 TRIO_ARGS4((self, target, flags, width),
3566 trio_class_t *self,
3567 trio_wchar_t *target,
3568 trio_flags_t flags,
3569 int width)
3570 {
3571 int i;
3572 int j;
3573 int size;
3574 int amount = 0;
3575 trio_wchar_t wch;
3576 char buffer[MB_LEN_MAX + 1];
3577
3578 assert(VALID(self));
3579 assert(VALID(self->InStream));
3580
3581 for (i = 0;
3582 (self->current != EOF) && (i < width);
3583 i++)
3584 {
3585 if (isascii(self->current))
3586 {
3587 if (TrioReadChar(self, buffer, flags, 1) == 0)
3588 return 0;
3589 buffer[1] = NIL;
3590 }
3591 else
3592 {
3593 /*
3594 * Collect a multibyte character, by enlarging buffer until
3595 * it contains a fully legal multibyte character, or the
3596 * buffer is full.
3597 */
3598 j = 0;
3599 do
3600 {
3601 buffer[j++] = (char)self->current;
3602 buffer[j] = NIL;
3603 self->InStream(self, NULL);
3604 }
3605 while ((j < (int)sizeof(buffer)) && (mblen(buffer, (size_t)j) != j));
3606 }
3607 if (target)
3608 {
3609 size = mbtowc(&wch, buffer, sizeof(buffer));
3610 if (size > 0)
3611 target[i] = wch;
3612 }
3613 amount += size;
3614 self->InStream(self, NULL);
3615 }
3616 return amount;
3617 }
3618 #endif /* TRIO_FEATURE_WIDECHAR */
3619
3620 /*************************************************************************
3621 * TrioReadWideString
3622 */
3623 #if TRIO_FEATURE_WIDECHAR
3624 TRIO_PRIVATE BOOLEAN_T
3625 TrioReadWideString
3626 TRIO_ARGS4((self, target, flags, width),
3627 trio_class_t *self,
3628 trio_wchar_t *target,
3629 trio_flags_t flags,
3630 int width)
3631 {
3632 int i;
3633 int size;
3634
3635 assert(VALID(self));
3636 assert(VALID(self->InStream));
3637
3638 TrioSkipWhitespaces(self);
3639
3640 #if defined(TRIO_COMPILER_SUPPORTS_MULTIBYTE)
3641 /* Required by TrioReadWideChar */
3642 (void)mblen(NULL, 0);
3643 #endif
3644
3645 /*
3646 * Continue until end of string is reached, a whitespace is encountered,
3647 * or width is exceeded
3648 */
3649 for (i = 0;
3650 ((width == NO_WIDTH) || (i < width)) &&
3651 (! ((self->current == EOF) || isspace(self->current)));
3652 )
3653 {
3654 size = TrioReadWideChar(self, &target[i], flags, 1);
3655 if (size == 0)
3656 break; /* for */
3657
3658 i += size;
3659 }
3660 if (target)
3661 target[i] = WCONST('\0');
3662 return TRUE;
3663 }
3664 #endif /* TRIO_FEATURE_WIDECHAR */
3665
3666 /*************************************************************************
3667 * TrioReadGroup
3668 *
3669 * Reads non-empty character groups.
3670 *
3671 * FIXME: characterclass does not work with multibyte characters
3672 */
3673 TRIO_PRIVATE BOOLEAN_T
3674 TrioReadGroup
3675 TRIO_ARGS5((self, target, characterclass, flags, width),
3676 trio_class_t *self,
3677 char *target,
3678 int *characterclass,
3679 trio_flags_t flags,
3680 int width)
3681 {
3682 int ch;
3683 int i;
3684
3685 assert(VALID(self));
3686 assert(VALID(self->InStream));
3687
3688 ch = self->current;
3689 for (i = 0;
3690 ((width == NO_WIDTH) || (i < width)) &&
3691 (! ((ch == EOF) ||
3692 (((flags & FLAGS_EXCLUDE) != 0) ^ (characterclass[ch] == 0))));
3693 i++)
3694 {
3695 if (target)
3696 target[i] = (char)ch;
3697 self->InStream(self, &ch);
3698 }
3699
3700 if (i == 0)
3701 return FALSE;
3702
3703 /* Terminate the string if input saved */
3704 if (target)
3705 target[i] = NIL;
3706 return TRUE;
3707 }
3708
3709 /*************************************************************************
3710 * TrioReadPointer
3711 */
3712 TRIO_PRIVATE BOOLEAN_T
3713 TrioReadPointer
3714 TRIO_ARGS3((self, target, flags),
3715 trio_class_t *self,
3716 trio_pointer_t *target,
3717 trio_flags_t flags)
3718 {
3719 trio_uintmax_t number;
3720 char buffer[sizeof(internalNullString)];
3721
3722 flags |= (FLAGS_UNSIGNED | FLAGS_ALTERNATIVE | FLAGS_NILPADDING);
3723
3724 if (TrioReadNumber(self,
3725 &number,
3726 flags,
3727 POINTER_WIDTH,
3728 BASE_HEX))
3729 {
3730 if (target)
3731 {
3732 #if defined(TRIO_COMPILER_GCC) || defined(TRIO_COMPILER_MIPSPRO)
3733 /*
3734 * The strange assignment of number is a workaround for a compiler
3735 * warning
3736 */
3737 *target = &((char *)0)[number];
3738 #else
3739 *target = (trio_pointer_t)number;
3740 #endif
3741 }
3742 return TRUE;
3743 }
3744 else if (TrioReadString(self,
3745 (flags & FLAGS_IGNORE)
3746 ? NULL
3747 : buffer,
3748 0,
3749 sizeof(internalNullString) - 1))
3750 {
3751 if (trio_equal_case(buffer, internalNullString))
3752 {
3753 if (target)
3754 *target = NULL;
3755 return TRUE;
3756 }
3757 }
3758 return FALSE;
3759 }
3760
3761 /*************************************************************************
3762 * TrioScanProcess
3763 */
3764 TRIO_PRIVATE int
3765 TrioScanProcess
3766 TRIO_ARGS3((data, format, parameters),
3767 trio_class_t *data,
3768 TRIO_CONST char *format,
3769 trio_parameter_t *parameters)
3770 {
3771 int status;
3772 int assignment;
3773 int ch;
3774 int offset; /* Offset of format string */
3775 int i; /* Offset of current parameter */
3776 trio_flags_t flags;
3777 int width;
3778 int base;
3779 trio_pointer_t pointer;
3780
3781 /* Return on empty format string */
3782 if (format[0] == NIL)
3783 return 0;
3784
3785 status = 0;
3786 assignment = 0;
3787 i = 0;
3788 offset = 0;
3789 data->InStream(data, &ch);
3790
3791 for (;;)
3792 {
3793 /* Skip the parameter entries */
3794 while (parameters[i].type == FORMAT_PARAMETER)
3795 {
3796 assert(i <= MAX_PARAMETERS);
3797 i++;
3798 }
3799
3800 /* Compare non conversion-specifier part of format string */
3801 while (offset < parameters[i].beginOffset)
3802 {
3803 if ((CHAR_IDENTIFIER == format[offset]) &&
3804 (CHAR_IDENTIFIER == format[offset + 1]))
3805 {
3806 /* Two % in format matches one % in input stream */
3807 if (CHAR_IDENTIFIER == ch)
3808 {
3809 data->InStream(data, &ch);
3810 offset += 2;
3811 continue; /* while format chars left */
3812 }
3813 else
3814 {
3815 status = TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
3816 goto end;
3817 }
3818 }
3819 else /* Not an % identifier */
3820 {
3821 if (isspace((int)format[offset]))
3822 {
3823 /* Whitespaces may match any amount of whitespaces */
3824 ch = TrioSkipWhitespaces(data);
3825 }
3826 else if (ch == format[offset])
3827 {
3828 data->InStream(data, &ch);
3829 }
3830 else
3831 {
3832 status = assignment;
3833 goto end;
3834 }
3835
3836 offset++;
3837 }
3838 }
3839
3840 if (parameters[i].type == FORMAT_SENTINEL)
3841 break;
3842
3843 if ((EOF == ch) && (parameters[i].type != FORMAT_COUNT))
3844 {
3845 status = (assignment > 0) ? assignment : EOF;
3846 goto end;
3847 }
3848
3849 flags = parameters[i].flags;
3850
3851 /* Find width */
3852 width = parameters[i].width;
3853 if (flags & FLAGS_WIDTH_PARAMETER)
3854 {
3855 /* Get width from parameter list */
3856 width = (int)parameters[width].data.number.as_signed;
3857 }
3858
3859 /* Find base */
3860 if (NO_BASE != parameters[i].baseSpecifier)
3861 {
3862 /* Base from specifier has priority */
3863 base = parameters[i].baseSpecifier;
3864 }
3865 else if (flags & FLAGS_BASE_PARAMETER)
3866 {
3867 /* Get base from parameter list */
3868 base = parameters[i].base;
3869 base = (int)parameters[base].data.number.as_signed;
3870 }
3871 else
3872 {
3873 /* Use base from format string */
3874 base = parameters[i].base;
3875 }
3876
3877 switch (parameters[i].type)
3878 {
3879 case FORMAT_INT:
3880 {
3881 trio_uintmax_t number;
3882
3883 if (0 == base)
3884 base = BASE_DECIMAL;
3885
3886 if (!TrioReadNumber(data,
3887 &number,
3888 flags,
3889 width,
3890 base))
3891 {
3892 status = assignment;
3893 goto end;
3894 }
3895
3896 if (!(flags & FLAGS_IGNORE))
3897 {
3898 assignment++;
3899
3900 pointer = parameters[i].data.pointer;
3901 #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
3902 if (flags & FLAGS_SIZE_T)
3903 *(size_t *)pointer = (size_t)number;
3904 else
3905 #endif
3906 #if TRIO_FEATURE_PTRDIFF_T
3907 if (flags & FLAGS_PTRDIFF_T)
3908 *(ptrdiff_t *)pointer = (ptrdiff_t)number;
3909 else
3910 #endif
3911 #if TRIO_FEATURE_INTMAX_T
3912 if (flags & FLAGS_INTMAX_T)
3913 *(trio_intmax_t *)pointer = (trio_intmax_t)number;
3914 else
3915 #endif
3916 if (flags & FLAGS_QUAD)
3917 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)number;
3918 else if (flags & FLAGS_LONG)
3919 *(long int *)pointer = (long int)number;
3920 else if (flags & FLAGS_SHORT)
3921 *(short int *)pointer = (short int)number;
3922 else
3923 *(int *)pointer = (int)number;
3924 }
3925 }
3926 break; /* FORMAT_INT */
3927
3928 case FORMAT_STRING:
3929 #if TRIO_FEATURE_WIDECHAR
3930 if (flags & FLAGS_WIDECHAR)
3931 {
3932 if (!TrioReadWideString(data,
3933 (flags & FLAGS_IGNORE)
3934 ? NULL
3935 : parameters[i].data.wstring,
3936 flags,
3937 width))
3938 {
3939 status = assignment;
3940 goto end;
3941 }
3942 }
3943 else
3944 #endif
3945 {
3946 if (!TrioReadString(data,
3947 (flags & FLAGS_IGNORE)
3948 ? NULL
3949 : parameters[i].data.string,
3950 flags,
3951 width))
3952 {
3953 status = assignment;
3954 goto end;
3955 }
3956 }
3957 if (!(flags & FLAGS_IGNORE))
3958 assignment++;
3959 break; /* FORMAT_STRING */
3960
3961 case FORMAT_GROUP:
3962 {
3963 int characterclass[MAX_CHARACTER_CLASS + 1];
3964
3965 /* Skip over modifiers */
3966 while (format[offset] != SPECIFIER_GROUP)
3967 {
3968 offset++;
3969 }
3970 /* Skip over group specifier */
3971 offset++;
3972
3973 memset(characterclass, 0, sizeof(characterclass));
3974 status = TrioGetCharacterClass(format,
3975 &offset,
3976 &flags,
3977 characterclass);
3978 if (status < 0)
3979 goto end;
3980
3981 if (!TrioReadGroup(data,
3982 (flags & FLAGS_IGNORE)
3983 ? NULL
3984 : parameters[i].data.string,
3985 characterclass,
3986 flags,
3987 parameters[i].width))
3988 {
3989 status = assignment;
3990 goto end;
3991 }
3992 if (!(flags & FLAGS_IGNORE))
3993 assignment++;
3994 }
3995 break; /* FORMAT_GROUP */
3996
3997 case FORMAT_COUNT:
3998 pointer = parameters[i].data.pointer;
3999 if (NULL != pointer)
4000 {
4001 int count = data->processed;
4002 if (ch != EOF)
4003 count--; /* a character is read, but is not consumed yet */
4004 #if TRIO_FEATURE_SIZE_T || TRIO_FEATURE_SIZE_T_UPPER
4005 if (flags & FLAGS_SIZE_T)
4006 *(size_t *)pointer = (size_t)count;
4007 else
4008 #endif
4009 #if TRIO_FEATURE_PTRDIFF_T
4010 if (flags & FLAGS_PTRDIFF_T)
4011 *(ptrdiff_t *)pointer = (ptrdiff_t)count;
4012 else
4013 #endif
4014 #if TRIO_FEATURE_INTMAX_T
4015 if (flags & FLAGS_INTMAX_T)
4016 *(trio_intmax_t *)pointer = (trio_intmax_t)count;
4017 else
4018 #endif
4019 if (flags & FLAGS_QUAD)
4020 {
4021 *(trio_ulonglong_t *)pointer = (trio_ulonglong_t)count;
4022 }
4023 else if (flags & FLAGS_LONG)
4024 {
4025 *(long int *)pointer = (long int)count;
4026 }
4027 else if (flags & FLAGS_SHORT)
4028 {
4029 *(short int *)pointer = (short int)count;
4030 }
4031 else
4032 {
4033 *(int *)pointer = (int)count;
4034 }
4035 }
4036 break; /* FORMAT_COUNT */
4037
4038 case FORMAT_CHAR:
4039 #if TRIO_FEATURE_WIDECHAR
4040 if (flags & FLAGS_WIDECHAR)
4041 {
4042 if (TrioReadWideChar(data,
4043 (flags & FLAGS_IGNORE)
4044 ? NULL
4045 : parameters[i].data.wstring,
4046 flags,
4047 (width == NO_WIDTH) ? 1 : width) == 0)
4048 {
4049 status = assignment;
4050 goto end;
4051 }
4052 }
4053 else
4054 #endif
4055 {
4056 if (TrioReadChar(data,
4057 (flags & FLAGS_IGNORE)
4058 ? NULL
4059 : parameters[i].data.string,
4060 flags,
4061 (width == NO_WIDTH) ? 1 : width) == 0)
4062 {
4063 status = assignment;
4064 goto end;
4065 }
4066 }
4067 if (!(flags & FLAGS_IGNORE))
4068 assignment++;
4069 break; /* FORMAT_CHAR */
4070
4071 case FORMAT_POINTER:
4072 if (!TrioReadPointer(data,
4073 (flags & FLAGS_IGNORE)
4074 ? NULL
4075 : (trio_pointer_t *)parameters[i].data.pointer,
4076 flags))
4077 {
4078 status = assignment;
4079 goto end;
4080 }
4081 if (!(flags & FLAGS_IGNORE))
4082 assignment++;
4083 break; /* FORMAT_POINTER */
4084
4085 case FORMAT_PARAMETER:
4086 break; /* FORMAT_PARAMETER */
4087
4088 default:
4089 status = TRIO_ERROR_RETURN(TRIO_EINVAL, offset);
4090 goto end;
4091 }
4092
4093 ch = data->current;
4094 offset = parameters[i].endOffset;
4095 i++;
4096 }
4097
4098 status = assignment;
4099 end:
4100 if (data->UndoStream)
4101 data->UndoStream(data);
4102 return status;
4103 }
4104
4105 /*************************************************************************
4106 * TrioScan
4107 */
4108 TRIO_PRIVATE int
4109 TrioScan
4110 TRIO_ARGS7((source, sourceSize, InStream, UndoStream, format, arglist, argarray),
4111 trio_pointer_t source,
4112 size_t sourceSize,
4113 void (*InStream) TRIO_PROTO((trio_class_t *, int *)),
4114 void (*UndoStream) TRIO_PROTO((trio_class_t *)),
4115 TRIO_CONST char *format,
4116 va_list arglist,
4117 trio_pointer_t *argarray)
4118 {
4119 int status;
4120 trio_parameter_t parameters[MAX_PARAMETERS];
4121 trio_class_t data;
4122
4123 assert(VALID(InStream));
4124 assert(VALID(format));
4125
4126 memset(&data, 0, sizeof(data));
4127 data.InStream = InStream;
4128 data.UndoStream = UndoStream;
4129 data.location = (trio_pointer_t)source;
4130 data.max = sourceSize;
4131 data.error = 0;
4132
4133 #if defined(USE_LOCALE)
4134 if (NULL == internalLocaleValues)
4135 {
4136 TrioSetLocale();
4137 }
4138 #endif
4139
4140 status = TrioParse(TYPE_SCAN, format, parameters, arglist, argarray);
4141 if (status < 0)
4142 return status;
4143
4144 status = TrioScanProcess(&data, format, parameters);
4145 if (data.error != 0)
4146 {
4147 status = data.error;
4148 }
4149 return status;
4150 }
4151
4152 /*************************************************************************
4153 * TrioInStreamCustom
4154 */
4155
4156 /*************************************************************************
4157 * TrioInStreamString
4158 */
4159 TRIO_PRIVATE void
4160 TrioInStreamString
4161 TRIO_ARGS2((self, intPointer),
4162 trio_class_t *self,
4163 int *intPointer)
4164 {
4165 unsigned char **buffer;
4166
4167 assert(VALID(self));
4168 assert(VALID(self->location));
4169
4170 self->actually.cached = 0;
4171
4172 buffer = (unsigned char **)self->location;
4173 self->current = (*buffer)[0];
4174 if (self->current == NIL)
4175 {
4176 self->current = EOF;
4177 }
4178 else
4179 {
4180 (*buffer)++;
4181 self->processed++;
4182 self->actually.cached++;
4183 }
4184
4185 if (VALID(intPointer))
4186 {
4187 *intPointer = self->current;
4188 }
4189 }
4190
4191 /*************************************************************************
4192 *
4193 * Formatted scanning functions
4194 *
4195 ************************************************************************/
4196
4197 #if defined(TRIO_DOCUMENTATION)
4198 # include "doc/doc_scanf.h"
4199 #endif
4200 /** @addtogroup Scanf
4201 @{
4202 */
4203
4204 /*************************************************************************
4205 * scanf
4206 */
4207
4208 /*************************************************************************
4209 * sscanf
4210 */
4211
4212 /**
4213 Scan characters from string.
4214
4215 @param buffer Input string.
4216 @param format Formatting string.
4217 @param ... Arguments.
4218 @return Number of scanned characters.
4219 */
4220 TRIO_PUBLIC int
4221 trio_sscanf
4222 TRIO_VARGS3((buffer, format, va_alist),
4223 TRIO_CONST char *buffer,
4224 TRIO_CONST char *format,
4225 TRIO_VA_DECL)
4226 {
4227 int status;
4228 va_list args;
4229
4230 assert(VALID(buffer));
4231 assert(VALID(format));
4232
4233 TRIO_VA_START(args, format);
4234 status = TrioScan((trio_pointer_t)&buffer, 0,
4235 TrioInStreamString,
4236 NULL,
4237 format, args, NULL);
4238 TRIO_VA_END(args);
4239 return status;
4240 }
4241
4242 /**
4243 Scan characters from string.
4244
4245 @param buffer Input string.
4246 @param format Formatting string.
4247 @param args Arguments.
4248 @return Number of scanned characters.
4249 */
4250 TRIO_PUBLIC int
4251 trio_sscanfv
4252 TRIO_ARGS3((buffer, format, args),
4253 TRIO_CONST char *buffer,
4254 TRIO_CONST char *format,
4255 trio_pointer_t *args)
4256 {
4257 static va_list unused;
4258
4259 assert(VALID(buffer));
4260 assert(VALID(format));
4261
4262 return TrioScan((trio_pointer_t)&buffer, 0,
4263 TrioInStreamString,
4264 NULL,
4265 format, unused, args);
4266 }
4267
4268 #endif /* TRIO_FEATURE_SCANF */
0 /*************************************************************************
1 *
2 * $Id: triostr.c,v 1.36 2010/01/26 13:02:02 breese Exp $
3 *
4 * Copyright (C) 2001 Bjorn Reese and Daniel Stenberg.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
11 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
12 * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
13 * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
14 *
15 ************************************************************************/
16
17 /*************************************************************************
18 * Include files
19 */
20
21 #if defined(HAVE_CONFIG_H)
22 # include <config.h>
23 #endif
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <ctype.h>
28 #include "../include/trio/triodef.h"
29 #include "../include/trio/triostr.h"
30 #if defined(TRIO_FUNC_TO_LONG_DOUBLE)
31 # define USE_MATH
32 #endif
33 #if defined(USE_MATH)
34 # include <math.h>
35 #endif
36
37 /*************************************************************************
38 * Definitions
39 */
40
41 #if !defined(TRIO_PUBLIC_STRING)
42 # define TRIO_PUBLIC_STRING TRIO_PUBLIC
43 #endif
44 #if !defined(TRIO_PRIVATE_STRING)
45 # define TRIO_PRIVATE_STRING TRIO_PRIVATE
46 #endif
47
48 #if !defined(NULL)
49 # define NULL 0
50 #endif
51 #if !defined(NIL)
52 # define NIL ((char)0)
53 #endif
54 #if !defined(FALSE)
55 # define FALSE (1 == 0)
56 # define TRUE (! FALSE)
57 #endif
58 #if !defined(BOOLEAN_T)
59 # define BOOLEAN_T int
60 #endif
61
62 #if defined(USE_MATH)
63 # if defined(PREDEF_STANDARD_C99)
64 # if defined(TRIO_COMPILER_DECC)
65 # if (TRIO_COMPILER_DECC - 0 > 80000000)
66 /*
67 * The OSF/1 runtime that comes with the DECC compiler does not support
68 * hexfloats conversion.
69 */
70 # define USE_STRTOD
71 # define USE_STRTOF
72 # endif
73 # else
74 # define USE_STRTOD
75 # define USE_STRTOF
76 # endif
77 # else
78 # if defined(TRIO_COMPILER_VISUALC)
79 # define USE_STRTOD
80 # endif
81 #endif
82 #endif
83
84 #if defined(TRIO_PLATFORM_UNIX)
85 # if defined(PREDEF_STANDARD_UNIX95)
86 # define USE_STRCASECMP
87 # define USE_STRNCASECMP
88 # endif
89 # if defined(TRIO_PLATFORM_SUNOS)
90 # define USE_SYS_ERRLIST
91 # else
92 # define USE_STRERROR
93 # endif
94 # if defined(TRIO_PLATFORM_QNX)
95 # define strcasecmp(x,y) stricmp(x,y)
96 # define strncasecmp(x,y,n) strnicmp(x,y,n)
97 # endif
98 #endif
99
100 #if defined(TRIO_PLATFORM_WIN32)
101 # define USE_STRCASECMP
102 # if defined(TRIO_PLATFORM_WINCE)
103 # define strcasecmp(x,y) _stricmp(x,y)
104 # else
105 # define strcasecmp(x,y) strcmpi(x,y)
106 # endif
107 #endif
108
109 #if !defined(HAVE_CONFIG_H)
110 # if !(defined(TRIO_PLATFORM_SUNOS))
111 # define HAVE_TOLOWER
112 # define HAVE_TOUPPER
113 # endif
114 #endif
115
116 #if defined(USE_MATH) && !defined(TRIO_NO_POWL)
117 # if !defined(HAVE_POWL)
118 # if defined(PREDEF_STANDARD_C99) \
119 || defined(PREDEF_STANDARD_UNIX03)
120 # define HAVE_POWL
121 # else
122 # if defined(TRIO_COMPILER_VISUALC)
123 # if defined(powl)
124 # define HAVE_POWL
125 # endif
126 # endif
127 # endif
128 # endif
129 #endif
130
131 #if defined(HAVE_POWL)
132 # define trio_powl(x,y) powl((x),(y))
133 #else
134 # define trio_powl(x,y) pow((double)(x),(double)(y))
135 #endif
136
137 #if defined(TRIO_FUNC_TO_UPPER) \
138 || (defined(TRIO_FUNC_EQUAL) && !defined(USE_STRCASECMP)) \
139 || (defined(TRIO_FUNC_EQUAL_MAX) && !defined(USE_STRNCASECMP)) \
140 || defined(TRIO_FUNC_MATCH) \
141 || defined(TRIO_FUNC_TO_LONG_DOUBLE) \
142 || defined(TRIO_FUNC_UPPER)
143 # define TRIO_FUNC_INTERNAL_TO_UPPER
144 #endif
145
146 /*************************************************************************
147 * Structures
148 */
149
150 struct _trio_string_t
151 {
152 char *content;
153 size_t length;
154 size_t allocated;
155 };
156
157 /*************************************************************************
158 * Constants
159 */
160
161 #if !defined(TRIO_EMBED_STRING)
162 static TRIO_CONST char rcsid[] = "@(#)$Id: triostr.c,v 1.36 2010/01/26 13:02:02 breese Exp $";
163 #endif
164
165 /*************************************************************************
166 * Static String Functions
167 */
168
169 #if defined(TRIO_DOCUMENTATION)
170 # include "doc/doc_static.h"
171 #endif
172 /** @addtogroup StaticStrings
173 @{
174 */
175
176 /*
177 * internal_duplicate_max
178 */
179 #if defined(TRIO_FUNC_DUPLICATE) \
180 || defined(TRIO_FUNC_DUPLICATE_MAX) \
181 || defined(TRIO_FUNC_STRING_DUPLICATE) \
182 || defined(TRIO_FUNC_XSTRING_DUPLICATE)
183
184 TRIO_PRIVATE_STRING char *
185 internal_duplicate_max
186 TRIO_ARGS2((source, size),
187 TRIO_CONST char *source,
188 size_t size)
189 {
190 char *target;
191
192 assert(source);
193
194 /* Make room for string plus a terminating zero */
195 size++;
196 target = trio_create(size);
197 if (target)
198 {
199 trio_copy_max(target, size, source);
200 }
201 return target;
202 }
203
204 #endif
205
206 /*
207 * internal_string_alloc
208 */
209 #if defined(TRIO_FUNC_STRING_CREATE) \
210 || defined(TRIO_FUNC_STRING_DUPLICATE) \
211 || defined(TRIO_FUNC_XSTRING_DUPLICATE)
212
213 TRIO_PRIVATE_STRING trio_string_t *
214 internal_string_alloc(TRIO_NOARGS)
215 {
216 trio_string_t *self;
217
218 self = (trio_string_t *)TRIO_MALLOC(sizeof(trio_string_t));
219 if (self)
220 {
221 self->content = NULL;
222 self->length = 0;
223 self->allocated = 0;
224 }
225 return self;
226 }
227
228 #endif
229
230 /*
231 * internal_string_grow
232 *
233 * The size of the string will be increased by 'delta' characters. If
234 * 'delta' is zero, the size will be doubled.
235 */
236 #if defined(TRIO_FUNC_STRING_CREATE) \
237 || defined(TRIO_FUNC_STRING_APPEND) \
238 || defined(TRIO_FUNC_XSTRING_APPEND) \
239 || defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
240
241 TRIO_PRIVATE_STRING BOOLEAN_T
242 internal_string_grow
243 TRIO_ARGS2((self, delta),
244 trio_string_t *self,
245 size_t delta)
246 {
247 BOOLEAN_T status = FALSE;
248 char *new_content;
249 size_t new_size;
250
251 new_size = (delta == 0)
252 ? ( (self->allocated == 0) ? 1 : self->allocated * 2 )
253 : self->allocated + delta;
254
255 new_content = (char *)TRIO_REALLOC(self->content, new_size);
256 if (new_content)
257 {
258 self->content = new_content;
259 self->allocated = new_size;
260 status = TRUE;
261 }
262 return status;
263 }
264
265 #endif
266
267 /*
268 * internal_string_grow_to
269 *
270 * The size of the string will be increased to 'length' plus one characters.
271 * If 'length' is less than the original size, the original size will be
272 * used (that is, the size of the string is never decreased).
273 */
274 #if defined(TRIO_FUNC_STRING_APPEND) \
275 || defined(TRIO_FUNC_XSTRING_APPEND) \
276 || defined(TRIO_FUNC_XSTRING_APPEND_MAX)
277
278 TRIO_PRIVATE_STRING BOOLEAN_T
279 internal_string_grow_to
280 TRIO_ARGS2((self, length),
281 trio_string_t *self,
282 size_t length)
283 {
284 length++; /* Room for terminating zero */
285 return (self->allocated < length)
286 ? internal_string_grow(self, length - self->allocated)
287 : TRUE;
288 }
289
290 #endif
291
292 #if defined(TRIO_FUNC_INTERNAL_TO_UPPER)
293
294 TRIO_PRIVATE_STRING TRIO_INLINE int
295 internal_to_upper
296 TRIO_ARGS1((source),
297 int source)
298 {
299 # if defined(HAVE_TOUPPER)
300
301 return toupper(source);
302
303 # else
304
305 /* Does not handle locales or non-contiguous alphabetic characters */
306 return ((source >= (int)'a') && (source <= (int)'z'))
307 ? source - 'a' + 'A'
308 : source;
309
310 # endif
311 }
312
313 #endif
314
315
316 /**
317 Create new string.
318
319 @param size Size of new string.
320 @return Pointer to string, or NULL if allocation failed.
321 */
322 #if defined(TRIO_FUNC_CREATE)
323
324 TRIO_PUBLIC_STRING char *
325 trio_create
326 TRIO_ARGS1((size),
327 size_t size)
328 {
329 return (char *)TRIO_MALLOC(size);
330 }
331
332 #endif
333
334 /**
335 Destroy string.
336
337 @param string String to be freed.
338 */
339 #if defined(TRIO_FUNC_DESTROY)
340
341 TRIO_PUBLIC_STRING void
342 trio_destroy
343 TRIO_ARGS1((string),
344 char *string)
345 {
346 if (string)
347 {
348 TRIO_FREE(string);
349 }
350 }
351
352 #endif
353
354 /**
355 Count the number of characters in a string.
356
357 @param string String to measure.
358 @return Number of characters in @p string.
359 */
360 #if defined(TRIO_FUNC_LENGTH)
361
362 TRIO_PUBLIC_STRING size_t
363 trio_length
364 TRIO_ARGS1((string),
365 TRIO_CONST char *string)
366 {
367 return strlen(string);
368 }
369
370 #endif
371
372 /**
373 Count at most @p max characters in a string.
374
375 @param string String to measure.
376 @param max Maximum number of characters to count.
377 @return The maximum value of @p max and number of characters in @p string.
378 */
379 #if defined(TRIO_FUNC_LENGTH_MAX)
380
381 TRIO_PUBLIC_STRING size_t
382 trio_length_max
383 TRIO_ARGS2((string, max),
384 TRIO_CONST char *string,
385 size_t max)
386 {
387 size_t i;
388
389 for (i = 0; i < max; ++i)
390 {
391 if (string[i] == 0)
392 break;
393 }
394 return i;
395 }
396
397 #endif
398
399 /**
400 Append @p source at the end of @p target.
401
402 @param target Target string.
403 @param source Source string.
404 @return Boolean value indicating success or failure.
405
406 @pre @p target must point to a memory chunk with sufficient room to
407 contain the @p target string and @p source string.
408 @pre No boundary checking is performed, so insufficient memory will
409 result in a buffer overrun.
410 @post @p target will be zero terminated.
411 */
412 #if defined(TRIO_FUNC_APPEND)
413
414 TRIO_PUBLIC_STRING int
415 trio_append
416 TRIO_ARGS2((target, source),
417 char *target,
418 TRIO_CONST char *source)
419 {
420 assert(target);
421 assert(source);
422
423 return (strcat(target, source) != NULL);
424 }
425
426 #endif
427
428 /**
429 Append at most @p max characters from @p source to @p target.
430
431 @param target Target string.
432 @param max Maximum number of characters to append.
433 @param source Source string.
434 @return Boolean value indicating success or failure.
435
436 @pre @p target must point to a memory chuck with sufficient room to
437 contain the @p target string and the @p source string (at most @p max
438 characters).
439 @pre No boundary checking is performed, so insufficient memory will
440 result in a buffer overrun.
441 @post @p target will be zero terminated.
442 */
443 #if defined(TRIO_FUNC_APPEND_MAX)
444
445 TRIO_PUBLIC_STRING int
446 trio_append_max
447 TRIO_ARGS3((target, max, source),
448 char *target,
449 size_t max,
450 TRIO_CONST char *source)
451 {
452 size_t length;
453
454 assert(target);
455 assert(source);
456
457 length = trio_length(target);
458
459 if (max > length)
460 {
461 strncat(target, source, max - length - 1);
462 }
463 return TRUE;
464 }
465
466 #endif
467
468 /**
469 Determine if a string contains a substring.
470
471 @param string String to be searched.
472 @param substring String to be found.
473 @return Boolean value indicating success or failure.
474 */
475 #if defined(TRIO_FUNC_CONTAINS)
476
477 TRIO_PUBLIC_STRING int
478 trio_contains
479 TRIO_ARGS2((string, substring),
480 TRIO_CONST char *string,
481 TRIO_CONST char *substring)
482 {
483 assert(string);
484 assert(substring);
485
486 return (0 != strstr(string, substring));
487 }
488
489 #endif
490
491 /**
492 Copy @p source to @p target.
493
494 @param target Target string.
495 @param source Source string.
496 @return Boolean value indicating success or failure.
497
498 @pre @p target must point to a memory chunk with sufficient room to
499 contain the @p source string.
500 @pre No boundary checking is performed, so insufficient memory will
501 result in a buffer overrun.
502 @post @p target will be zero terminated.
503 */
504 #if defined(TRIO_FUNC_COPY)
505
506 TRIO_PUBLIC_STRING int
507 trio_copy
508 TRIO_ARGS2((target, source),
509 char *target,
510 TRIO_CONST char *source)
511 {
512 assert(target);
513 assert(source);
514
515 (void)strcpy(target, source);
516 return TRUE;
517 }
518
519 #endif
520
521 /**
522 Copy at most @p max - 1 characters from @p source to @p target.
523
524 @param target Target string.
525 @param max Maximum number of characters to append (one of which is
526 a NUL terminator). In other words @p source must point to at least
527 @p max - 1 bytes, but @p target must point to at least @p max
528 bytes.
529 @param source Source string.
530 @return Boolean value indicating success or failure.
531
532 @pre @p target must point to a memory chunk with sufficient room to
533 contain the @p source string and a NUL terminator (at most @p max
534 bytes total).
535 @pre No boundary checking is performed, so insufficient memory will
536 result in a buffer overrun.
537 @post @p target will be zero terminated.
538 */
539 #if defined(TRIO_FUNC_COPY_MAX)
540
541 TRIO_PUBLIC_STRING int
542 trio_copy_max
543 TRIO_ARGS3((target, max, source),
544 char *target,
545 size_t max,
546 TRIO_CONST char *source)
547 {
548 assert(target);
549 assert(source);
550 assert(max > 0); /* Includes != 0 */
551
552 (void)strncpy(target, source, max - 1);
553 target[max - 1] = (char)0;
554 return TRUE;
555 }
556
557 #endif
558
559 /**
560 Duplicate @p source.
561
562 @param source Source string.
563 @return A copy of the @p source string.
564
565 @post @p target will be zero terminated.
566 */
567 #if defined(TRIO_FUNC_DUPLICATE)
568
569 TRIO_PUBLIC_STRING char *
570 trio_duplicate
571 TRIO_ARGS1((source),
572 TRIO_CONST char *source)
573 {
574 return internal_duplicate_max(source, trio_length(source));
575 }
576
577 #endif
578
579 /**
580 Duplicate at most @p max characters of @p source.
581
582 @param source Source string.
583 @param max Maximum number of characters to duplicate.
584 @return A copy of the @p source string.
585
586 @post @p target will be zero terminated.
587 */
588 #if defined(TRIO_FUNC_DUPLICATE_MAX)
589
590 TRIO_PUBLIC_STRING char *
591 trio_duplicate_max
592 TRIO_ARGS2((source, max),
593 TRIO_CONST char *source,
594 size_t max)
595 {
596 size_t length;
597
598 assert(source);
599 assert(max > 0);
600
601 length = trio_length(source);
602 if (length > max)
603 {
604 length = max;
605 }
606 return internal_duplicate_max(source, length);
607 }
608
609 #endif
610
611 /**
612 Compare if two strings are equal.
613
614 @param first First string.
615 @param second Second string.
616 @return Boolean indicating whether the two strings are equal or not.
617
618 Case-insensitive comparison.
619 */
620 #if defined(TRIO_FUNC_EQUAL)
621
622 TRIO_PUBLIC_STRING int
623 trio_equal
624 TRIO_ARGS2((first, second),
625 TRIO_CONST char *first,
626 TRIO_CONST char *second)
627 {
628 assert(first);
629 assert(second);
630
631 if ((first != NULL) && (second != NULL))
632 {
633 # if defined(USE_STRCASECMP)
634 return (0 == strcasecmp(first, second));
635 # else
636 while ((*first != NIL) && (*second != NIL))
637 {
638 if (internal_to_upper(*first) != internal_to_upper(*second))
639 {
640 break;
641 }
642 first++;
643 second++;
644 }
645 return ((*first == NIL) && (*second == NIL));
646 # endif
647 }
648 return FALSE;
649 }
650
651 #endif
652
653 /**
654 Compare if two strings are equal.
655
656 @param first First string.
657 @param second Second string.
658 @return Boolean indicating whether the two strings are equal or not.
659
660 Case-sensitive comparison.
661 */
662 #if defined(TRIO_FUNC_EQUAL_CASE)
663
664 TRIO_PUBLIC_STRING int
665 trio_equal_case
666 TRIO_ARGS2((first, second),
667 TRIO_CONST char *first,
668 TRIO_CONST char *second)
669 {
670 assert(first);
671 assert(second);
672
673 if ((first != NULL) && (second != NULL))
674 {
675 return (0 == strcmp(first, second));
676 }
677 return FALSE;
678 }
679
680 #endif
681
682 /**
683 Compare if two strings up until the first @p max characters are equal.
684
685 @param first First string.
686 @param max Maximum number of characters to compare.
687 @param second Second string.
688 @return Boolean indicating whether the two strings are equal or not.
689
690 Case-sensitive comparison.
691 */
692 #if defined(TRIO_FUNC_EQUAL_CASE_MAX)
693
694 TRIO_PUBLIC_STRING int
695 trio_equal_case_max
696 TRIO_ARGS3((first, max, second),
697 TRIO_CONST char *first,
698 size_t max,
699 TRIO_CONST char *second)
700 {
701 assert(first);
702 assert(second);
703
704 if ((first != NULL) && (second != NULL))
705 {
706 return (0 == strncmp(first, second, max));
707 }
708 return FALSE;
709 }
710
711 #endif
712
713 /**
714 Compare if two strings are equal.
715
716 @param first First string.
717 @param second Second string.
718 @return Boolean indicating whether the two strings are equal or not.
719
720 Collating characters are considered equal.
721 */
722 #if defined(TRIO_FUNC_EQUAL_LOCALE)
723
724 TRIO_PUBLIC_STRING int
725 trio_equal_locale
726 TRIO_ARGS2((first, second),
727 TRIO_CONST char *first,
728 TRIO_CONST char *second)
729 {
730 assert(first);
731 assert(second);
732
733 # if defined(LC_COLLATE)
734 return (strcoll(first, second) == 0);
735 # else
736 return trio_equal(first, second);
737 # endif
738 }
739
740 #endif
741
742 /**
743 Compare if two strings up until the first @p max characters are equal.
744
745 @param first First string.
746 @param max Maximum number of characters to compare.
747 @param second Second string.
748 @return Boolean indicating whether the two strings are equal or not.
749
750 Case-insensitive comparison.
751 */
752 #if defined(TRIO_FUNC_EQUAL_MAX)
753
754 TRIO_PUBLIC_STRING int
755 trio_equal_max
756 TRIO_ARGS3((first, max, second),
757 TRIO_CONST char *first,
758 size_t max,
759 TRIO_CONST char *second)
760 {
761 assert(first);
762 assert(second);
763
764 if ((first != NULL) && (second != NULL))
765 {
766 # if defined(USE_STRNCASECMP)
767 return (0 == strncasecmp(first, second, max));
768 # else
769 /* Not adequately tested yet */
770 size_t cnt = 0;
771 while ((*first != NIL) && (*second != NIL) && (cnt <= max))
772 {
773 if (internal_to_upper(*first) != internal_to_upper(*second))
774 {
775 break;
776 }
777 first++;
778 second++;
779 cnt++;
780 }
781 return ((cnt == max) || ((*first == NIL) && (*second == NIL)));
782 # endif
783 }
784 return FALSE;
785 }
786
787 #endif
788
789 /**
790 Provide a textual description of an error code (errno).
791
792 @param error_number Error number.
793 @return Textual description of @p error_number.
794 */
795 #if defined(TRIO_FUNC_ERROR)
796
797 TRIO_PUBLIC_STRING TRIO_CONST char *
798 trio_error
799 TRIO_ARGS1((error_number),
800 int error_number)
801 {
802 # if defined(USE_STRERROR)
803
804 return strerror(error_number);
805
806 # else
807 # if defined(USE_SYS_ERRLIST)
808
809 extern char *sys_errlist[];
810 extern int sys_nerr;
811
812 return ((error_number < 0) || (error_number >= sys_nerr))
813 ? "unknown"
814 : sys_errlist[error_number];
815
816 # else
817
818 return "unknown";
819
820 # endif
821 # endif
822 }
823
824 #endif
825
826 /**
827 Format the date/time according to @p format.
828
829 @param target Target string.
830 @param max Maximum number of characters to format.
831 @param format Formatting string.
832 @param datetime Date/time structure.
833 @return Number of formatted characters.
834
835 The formatting string accepts the same specifiers as the standard C
836 function strftime.
837 */
838 #if defined(TRIO_FUNC_FORMAT_DATE_MAX)
839
840 TRIO_PUBLIC_STRING size_t
841 trio_format_date_max
842 TRIO_ARGS4((target, max, format, datetime),
843 char *target,
844 size_t max,
845 TRIO_CONST char *format,
846 TRIO_CONST struct tm *datetime)
847 {
848 assert(target);
849 assert(format);
850 assert(datetime);
851 assert(max > 0);
852
853 return strftime(target, max, format, datetime);
854 }
855
856 #endif
857
858 /**
859 Calculate a hash value for a string.
860
861 @param string String to be calculated on.
862 @param type Hash function.
863 @return Calculated hash value.
864
865 @p type can be one of the following
866 @li @c TRIO_HASH_PLAIN Plain hash function.
867 */
868 #if defined(TRIO_FUNC_HASH)
869
870 TRIO_PUBLIC_STRING unsigned long
871 trio_hash
872 TRIO_ARGS2((string, type),
873 TRIO_CONST char *string,
874 int type)
875 {
876 unsigned long value = 0L;
877 char ch;
878
879 assert(string);
880
881 switch (type)
882 {
883 case TRIO_HASH_PLAIN:
884 while ( (ch = *string++) != NIL )
885 {
886 value *= 31;
887 value += (unsigned long)ch;
888 }
889 break;
890 default:
891 assert(FALSE);
892 break;
893 }
894 return value;
895 }
896
897 #endif
898
899 /**
900 Find first occurrence of a character in a string.
901
902 @param string String to be searched.
903 @param character Character to be found.
904 @return A pointer to the found character, or NULL if character was not found.
905 */
906 #if defined(TRIO_FUNC_INDEX)
907
908 TRIO_PUBLIC_STRING char *
909 trio_index
910 TRIO_ARGS2((string, character),
911 TRIO_CONST char *string,
912 int character)
913 {
914 assert(string);
915
916 return strchr(string, character);
917 }
918
919 #endif
920
921 /**
922 Find last occurrence of a character in a string.
923
924 @param string String to be searched.
925 @param character Character to be found.
926 @return A pointer to the found character, or NULL if character was not found.
927 */
928 #if defined(TRIO_FUNC_INDEX_LAST)
929
930 TRIO_PUBLIC_STRING char *
931 trio_index_last
932 TRIO_ARGS2((string, character),
933 TRIO_CONST char *string,
934 int character)
935 {
936 assert(string);
937
938 return strchr(string, character);
939 }
940
941 #endif
942
943 /**
944 Convert the alphabetic letters in the string to lower-case.
945
946 @param target String to be converted.
947 @return Number of processed characters (converted or not).
948 */
949 #if defined(TRIO_FUNC_LOWER)
950
951 TRIO_PUBLIC_STRING int
952 trio_lower
953 TRIO_ARGS1((target),
954 char *target)
955 {
956 assert(target);
957
958 return trio_span_function(target, target, trio_to_lower);
959 }
960
961 #endif
962
963 /**
964 Compare two strings using wildcards.
965
966 @param string String to be searched.
967 @param pattern Pattern, including wildcards, to search for.
968 @return Boolean value indicating success or failure.
969
970 Case-insensitive comparison.
971
972 The following wildcards can be used
973 @li @c * Match any number of characters.
974 @li @c ? Match a single character.
975 */
976 #if defined(TRIO_FUNC_MATCH)
977
978 TRIO_PUBLIC_STRING int
979 trio_match
980 TRIO_ARGS2((string, pattern),
981 TRIO_CONST char *string,
982 TRIO_CONST char *pattern)
983 {
984 assert(string);
985 assert(pattern);
986
987 for (; ('*' != *pattern); ++pattern, ++string)
988 {
989 if (NIL == *string)
990 {
991 return (NIL == *pattern);
992 }
993 if ((internal_to_upper((int)*string) != internal_to_upper((int)*pattern))
994 && ('?' != *pattern))
995 {
996 return FALSE;
997 }
998 }
999 /* two-line patch to prevent *too* much recursiveness: */
1000 while ('*' == pattern[1])
1001 pattern++;
1002
1003 do
1004 {
1005 if ( trio_match(string, &pattern[1]) )
1006 {
1007 return TRUE;
1008 }
1009 }
1010 while (*string++);
1011
1012 return FALSE;
1013 }
1014
1015 #endif
1016
1017 /**
1018 Compare two strings using wildcards.
1019
1020 @param string String to be searched.
1021 @param pattern Pattern, including wildcards, to search for.
1022 @return Boolean value indicating success or failure.
1023
1024 Case-sensitive comparison.
1025
1026 The following wildcards can be used
1027 @li @c * Match any number of characters.
1028 @li @c ? Match a single character.
1029 */
1030 #if defined(TRIO_FUNC_MATCH_CASE)
1031
1032 TRIO_PUBLIC_STRING int
1033 trio_match_case
1034 TRIO_ARGS2((string, pattern),
1035 TRIO_CONST char *string,
1036 TRIO_CONST char *pattern)
1037 {
1038 assert(string);
1039 assert(pattern);
1040
1041 for (; ('*' != *pattern); ++pattern, ++string)
1042 {
1043 if (NIL == *string)
1044 {
1045 return (NIL == *pattern);
1046 }
1047 if ((*string != *pattern)
1048 && ('?' != *pattern))
1049 {
1050 return FALSE;
1051 }
1052 }
1053 /* two-line patch to prevent *too* much recursiveness: */
1054 while ('*' == pattern[1])
1055 pattern++;
1056
1057 do
1058 {
1059 if ( trio_match_case(string, &pattern[1]) )
1060 {
1061 return TRUE;
1062 }
1063 }
1064 while (*string++);
1065
1066 return FALSE;
1067 }
1068
1069 #endif
1070
1071 /**
1072 Execute a function on each character in string.
1073
1074 @param target Target string.
1075 @param source Source string.
1076 @param Function Function to be executed.
1077 @return Number of processed characters.
1078 */
1079 #if defined(TRIO_FUNC_SPAN_FUNCTION)
1080
1081 TRIO_PUBLIC_STRING size_t
1082 trio_span_function
1083 TRIO_ARGS3((target, source, Function),
1084 char *target,
1085 TRIO_CONST char *source,
1086 int (*Function) TRIO_PROTO((int)))
1087 {
1088 size_t count = 0;
1089
1090 assert(target);
1091 assert(source);
1092 assert(Function);
1093
1094 while (*source != NIL)
1095 {
1096 *target++ = Function(*source++);
1097 count++;
1098 }
1099 return count;
1100 }
1101
1102 #endif
1103
1104 /**
1105 Convert string to signed integer.
1106
1107 @param string String to be converted.
1108 @param endp Pointer to end of converted string.
1109 @param base Radix number of number.
1110 */
1111 #if defined(TRIO_FUNC_TO_LONG)
1112
1113 TRIO_PUBLIC_STRING long
1114 trio_to_long
1115 TRIO_ARGS3((string, endp, base),
1116 TRIO_CONST char *string,
1117 char **endp,
1118 int base)
1119 {
1120 assert(string);
1121 assert((base >= 2) && (base <= 36));
1122
1123 return strtol(string, endp, base);
1124 }
1125
1126 #endif
1127
1128 /**
1129 Convert one alphabetic letter to lower-case.
1130
1131 @param source The letter to be converted.
1132 @return The converted letter.
1133 */
1134 #if defined(TRIO_FUNC_TO_LOWER)
1135
1136 TRIO_PUBLIC_STRING int
1137 trio_to_lower
1138 TRIO_ARGS1((source),
1139 int source)
1140 {
1141 # if defined(HAVE_TOLOWER)
1142
1143 return tolower(source);
1144
1145 # else
1146
1147 /* Does not handle locales or non-contiguous alphabetic characters */
1148 return ((source >= (int)'A') && (source <= (int)'Z'))
1149 ? source - 'A' + 'a'
1150 : source;
1151
1152 # endif
1153 }
1154
1155 #endif
1156
1157 /**
1158 Convert one alphabetic letter to upper-case.
1159
1160 @param source The letter to be converted.
1161 @return The converted letter.
1162 */
1163 #if defined(TRIO_FUNC_TO_UPPER)
1164
1165 TRIO_PUBLIC_STRING int
1166 trio_to_upper
1167 TRIO_ARGS1((source),
1168 int source)
1169 {
1170 return internal_to_upper(source);
1171 }
1172
1173 #endif
1174
1175 /** @} End of StaticStrings */
1176
1177
1178 /*************************************************************************
1179 * Dynamic String Functions
1180 */
1181
1182 #if defined(TRIO_DOCUMENTATION)
1183 # include "doc/doc_dynamic.h"
1184 #endif
1185 /** @addtogroup DynamicStrings
1186 @{
1187 */
1188
1189 /**
1190 Deallocate the dynamic string and its contents.
1191
1192 @param self Dynamic string
1193 */
1194 #if defined(TRIO_FUNC_STRING_DESTROY)
1195
1196 TRIO_PUBLIC_STRING void
1197 trio_string_destroy
1198 TRIO_ARGS1((self),
1199 trio_string_t *self)
1200 {
1201 assert(self);
1202
1203 if (self)
1204 {
1205 trio_destroy(self->content);
1206 TRIO_FREE(self);
1207 }
1208 }
1209
1210 #endif
1211
1212 /**
1213 Extract the content.
1214
1215 @param self Dynamic String
1216 @return Content of dynamic string.
1217
1218 The content is removed from the dynamic string. This enables destruction
1219 of the dynamic string without deallocation of the content.
1220 */
1221 #if defined(TRIO_FUNC_STRING_EXTRACT)
1222
1223 TRIO_PUBLIC_STRING char *
1224 trio_string_extract
1225 TRIO_ARGS1((self),
1226 trio_string_t *self)
1227 {
1228 char *result;
1229
1230 assert(self);
1231
1232 result = self->content;
1233 /* FIXME: Allocate new empty buffer? */
1234 self->content = NULL;
1235 self->length = self->allocated = 0;
1236 return result;
1237 }
1238
1239 #endif
1240
1241 /*
1242 * trio_string_size
1243 */
1244 #if defined(TRIO_FUNC_STRING_SIZE)
1245
1246 TRIO_PUBLIC_STRING int
1247 trio_string_size
1248 TRIO_ARGS1((self),
1249 trio_string_t *self)
1250 {
1251 assert(self);
1252
1253 return self->allocated;
1254 }
1255
1256 #endif
1257
1258 /*
1259 * trio_string_terminate
1260 */
1261 #if defined(TRIO_FUNC_STRING_TERMINATE)
1262
1263 TRIO_PUBLIC_STRING void
1264 trio_string_terminate
1265 TRIO_ARGS1((self),
1266 trio_string_t *self)
1267 {
1268 trio_xstring_append_char(self, 0);
1269 }
1270
1271 #endif
1272
1273 /*
1274 * trio_xstring_append_char
1275 */
1276 #if defined(TRIO_FUNC_XSTRING_APPEND_CHAR)
1277
1278 TRIO_PUBLIC_STRING int
1279 trio_xstring_append_char
1280 TRIO_ARGS2((self, character),
1281 trio_string_t *self,
1282 char character)
1283 {
1284 assert(self);
1285
1286 if ((int)self->length >= trio_string_size(self))
1287 {
1288 if (!internal_string_grow(self, 0))
1289 goto error;
1290 }
1291 self->content[self->length] = character;
1292 self->length++;
1293 return TRUE;
1294
1295 error:
1296 return FALSE;
1297 }
1298
1299 #endif
1300
1301 /*
1302 * trio_xstring_duplicate
1303 */
1304 #if defined(TRIO_FUNC_XSTRING_DUPLICATE)
1305
1306 TRIO_PUBLIC_STRING trio_string_t *
1307 trio_xstring_duplicate
1308 TRIO_ARGS1((other),
1309 TRIO_CONST char *other)
1310 {
1311 trio_string_t *self;
1312
1313 assert(other);
1314
1315 self = internal_string_alloc();
1316 if (self)
1317 {
1318 self->content = internal_duplicate_max(other, trio_length(other));
1319 if (self->content)
1320 {
1321 self->length = trio_length(self->content);
1322 self->allocated = self->length + 1;
1323 }
1324 else
1325 {
1326 self->length = self->allocated = 0;
1327 }
1328 }
1329 return self;
1330 }
1331
1332 #endif
0 #include "../mednafen.h"
1 #include "../video.h"
2 #include "../general.h"
3 #include "../state.h"
4 #include "../driver.h"
5
6 #include "Deinterlacer.h"
7 Deinterlacer::Deinterlacer() : FieldBuffer(NULL), StateValid(false), DeintType(DEINT_WEAVE)
8 {
9 PrevDRect.x = 0;
10 PrevDRect.y = 0;
11
12 PrevDRect.w = 0;
13 PrevDRect.h = 0;
14 }
15
16 Deinterlacer::~Deinterlacer()
17 {
18 if(FieldBuffer)
19 {
20 delete FieldBuffer;
21 FieldBuffer = NULL;
22 }
23 }
24
25 void Deinterlacer::SetType(unsigned dt)
26 {
27 if(DeintType != dt)
28 {
29 DeintType = dt;
30
31 LWBuffer.resize(0);
32 if(FieldBuffer)
33 {
34 delete FieldBuffer;
35 FieldBuffer = NULL;
36 }
37 StateValid = false;
38 }
39 }
40
41 template<typename T>
42 void Deinterlacer::InternalProcess(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field)
43 {
44 //
45 // We need to output with LineWidths as always being valid to handle the case of horizontal resolution change between fields
46 // while in interlace mode, so clear the first LineWidths entry if it's == ~0, and
47 // [...]
48 const bool LineWidths_In_Valid = (LineWidths[0] != ~0);
49 const bool WeaveGood = (StateValid && PrevDRect.h == DisplayRect.h && DeintType == DEINT_WEAVE);
50 //
51 // XReposition stuff is to prevent exceeding the dimensions of the video surface under certain conditions(weave deinterlacer, previous field has higher
52 // horizontal resolution than current field, and current field's rectangle has an x offset that's too large when taking into consideration the previous field's
53 // width; for simplicity, we don't check widths, but just assume that the previous field's maximum width is >= than the current field's maximum width).
54 //
55 const int32 XReposition = ((WeaveGood && DisplayRect.x > PrevDRect.x) ? DisplayRect.x : 0);
56
57 //printf("%2d %2d, %d\n", DisplayRect.x, PrevDRect.x, XReposition);
58
59 if(XReposition)
60 DisplayRect.x = 0;
61
62 if(surface->h && !LineWidths_In_Valid)
63 {
64 LineWidths[0] = 0;
65 }
66
67 for(int y = 0; y < DisplayRect.h / 2; y++)
68 {
69 // [...]
70 // set all relevant source line widths to the contents of DisplayRect(also simplifies the src_lw and related pointer calculation code
71 // farther below.
72 if(!LineWidths_In_Valid)
73 LineWidths[(y * 2) + field + DisplayRect.y] = DisplayRect.w;
74
75 if(XReposition)
76 {
77 memmove(surface->pixels + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix,
78 surface->pixels + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + XReposition,
79 LineWidths[(y * 2) + field + DisplayRect.y] * sizeof(T));
80 }
81
82 if(WeaveGood)
83 {
84 const T* src = FieldBuffer->pixels + y * FieldBuffer->pitchinpix;
85 T* dest = surface->pixels + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
86 int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
87
88 *dest_lw = LWBuffer[y];
89
90 memcpy(dest, src, LWBuffer[y] * sizeof(T));
91 }
92 else if(DeintType == DEINT_BOB)
93 {
94 const T* src = surface->pixels + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
95 T* dest = surface->pixels + ((y * 2) + (field ^ 1) + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
96 const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
97 int32 *dest_lw = &LineWidths[(y * 2) + (field ^ 1) + DisplayRect.y];
98
99 *dest_lw = *src_lw;
100
101 memcpy(dest, src, *src_lw * sizeof(T));
102 }
103 else
104 {
105 const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
106 const T* src = surface->pixels + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
107 const int32 dly = ((y * 2) + (field + 1) + DisplayRect.y);
108 T* dest = surface->pixels + dly * surface->pitchinpix + DisplayRect.x;
109
110 if(y == 0 && field)
111 {
112 T black = MAKECOLOR(0, 0, 0, 0);
113 T* dm2 = surface->pixels + (dly - 2) * surface->pitchinpix;
114
115 LineWidths[dly - 2] = *src_lw;
116
117 for(int x = 0; x < *src_lw; x++)
118 dm2[x] = black;
119 }
120
121 if(dly < (DisplayRect.y + DisplayRect.h))
122 {
123 LineWidths[dly] = *src_lw;
124 memcpy(dest, src, *src_lw * sizeof(T));
125 }
126 }
127
128 //
129 //
130 //
131 //
132 //
133 //
134 if(DeintType == DEINT_WEAVE)
135 {
136 const int32 *src_lw = &LineWidths[(y * 2) + field + DisplayRect.y];
137 const T* src = surface->pixels + ((y * 2) + field + DisplayRect.y) * surface->pitchinpix + DisplayRect.x;
138 T* dest = FieldBuffer->pixels + y * FieldBuffer->pitchinpix;
139
140 memcpy(dest, src, *src_lw * sizeof(uint32));
141 LWBuffer[y] = *src_lw;
142
143 StateValid = true;
144 }
145 }
146 }
147
148 void Deinterlacer::Process(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field)
149 {
150 const MDFN_Rect DisplayRect_Original = DisplayRect;
151
152 if(DeintType == DEINT_WEAVE)
153 {
154 if(!FieldBuffer || FieldBuffer->w < surface->w || FieldBuffer->h < (surface->h / 2))
155 {
156 if(FieldBuffer)
157 delete FieldBuffer;
158
159 FieldBuffer = new MDFN_Surface(NULL, surface->w, surface->h / 2, surface->w, surface->format);
160 LWBuffer.resize(FieldBuffer->h);
161 }
162 else if(memcmp(&surface->format, &FieldBuffer->format, sizeof(MDFN_PixelFormat)))
163 {
164 FieldBuffer->SetFormat(surface->format, StateValid && PrevDRect.h == DisplayRect.h);
165 }
166 }
167
168 #if defined(WANT_32BPP)
169 InternalProcess<uint32>(surface, DisplayRect, LineWidths, field);
170 #elif defined(WANT_16BPP)
171 InternalProcess<uint16>(surface, DisplayRect, LineWidths, field);
172 #endif
173
174 PrevDRect = DisplayRect_Original;
175 }
176
177 void Deinterlacer::ClearState(void)
178 {
179 StateValid = false;
180
181 PrevDRect.x = 0;
182 PrevDRect.y = 0;
183
184 PrevDRect.w = 0;
185 PrevDRect.h = 0;
186 }
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #ifndef __MDFN_DEINTERLACER_H
18 #define __MDFN_DEINTERLACER_H
19
20 #include <vector>
21
22 class Deinterlacer
23 {
24 public:
25
26 Deinterlacer();
27 ~Deinterlacer();
28
29 enum
30 {
31 DEINT_BOB_OFFSET = 0, // Code will fall-through to this case under certain conditions, too.
32 DEINT_BOB,
33 DEINT_WEAVE,
34 };
35
36 void SetType(unsigned t);
37 inline unsigned GetType(void)
38 {
39 return(DeintType);
40 }
41
42 void Process(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field);
43
44 void ClearState(void);
45
46 private:
47
48 template<typename T>
49 void InternalProcess(MDFN_Surface *surface, MDFN_Rect &DisplayRect, int32 *LineWidths, const bool field);
50
51 MDFN_Surface *FieldBuffer;
52 std::vector<int32> LWBuffer;
53 bool StateValid;
54 MDFN_Rect PrevDRect;
55 unsigned DeintType;
56 };
57
58 #endif
0 /* Mednafen - Multi-system Emulator
1 *
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15 */
16
17 #include "../mednafen.h"
18 #include "surface.h"
19
20 MDFN_PixelFormat::MDFN_PixelFormat()
21 {
22 bpp = 0;
23 colorspace = 0;
24
25 Rshift = 0;
26 Gshift = 0;
27 Bshift = 0;
28 Ashift = 0;
29 }
30
31 MDFN_PixelFormat::MDFN_PixelFormat(const unsigned int p_colorspace, const uint8 p_rs, const uint8 p_gs, const uint8 p_bs, const uint8 p_as)
32 {
33 bpp = 32;
34 colorspace = p_colorspace;
35
36 Rshift = p_rs;
37 Gshift = p_gs;
38 Bshift = p_bs;
39 Ashift = p_as;
40 }
41
42 MDFN_Surface::MDFN_Surface()
43 {
44 memset(&format, 0, sizeof(format));
45
46 pixels = NULL;
47 pitchinpix = 0;
48 w = 0;
49 h = 0;
50 }
51
52 MDFN_Surface::MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf)
53 {
54 Init(p_pixels, p_width, p_height, p_pitchinpix, nf);
55 }
56
57 void MDFN_Surface::Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf)
58 {
59 void *rpix = NULL;
60 assert(nf.bpp == 16 || nf.bpp == 32);
61
62 format = nf;
63
64 pixels = NULL;
65
66 if(!(rpix = calloc(1, p_pitchinpix * p_height * (nf.bpp / 8))))
67 throw(1);
68
69 pixels = (uint32 *)rpix;
70
71 w = p_width;
72 h = p_height;
73
74 pitchinpix = p_pitchinpix;
75 }
76
77 // When we're converting, only convert the w*h area(AKA leave the last part of the line, pitch32 - w, alone),
78 // for places where we store auxillary information there(graphics viewer in the debugger), and it'll be faster
79 // to boot.
80 void MDFN_Surface::SetFormat(const MDFN_PixelFormat &nf, bool convert)
81 {
82 format = nf;
83 }
84
85 MDFN_Surface::~MDFN_Surface()
86 {
87 if(pixels)
88 free(pixels);
89 }
90
0 #ifndef __MDFN_SURFACE_H
1 #define __MDFN_SURFACE_H
2
3 #define RED_SHIFT 16
4 #define GREEN_SHIFT 8
5 #define BLUE_SHIFT 0
6 #define ALPHA_SHIFT 24
7 #define MAKECOLOR(r, g, b, a) ((r << RED_SHIFT) | (g << GREEN_SHIFT) | (b << BLUE_SHIFT) | (a << ALPHA_SHIFT))
8
9 struct MDFN_PaletteEntry
10 {
11 uint8 r, g, b;
12 };
13
14 typedef struct
15 {
16 int32 x, y, w, h;
17 } MDFN_Rect;
18
19 enum
20 {
21 MDFN_COLORSPACE_RGB = 0,
22 MDFN_COLORSPACE_YCbCr = 1,
23 MDFN_COLORSPACE_YUV = 2, // TODO, maybe.
24 };
25
26 class MDFN_PixelFormat
27 {
28 public:
29
30 MDFN_PixelFormat();
31 MDFN_PixelFormat(const unsigned int p_colorspace, const uint8 p_rs, const uint8 p_gs, const uint8 p_bs, const uint8 p_as);
32
33 unsigned int bpp;
34 unsigned int colorspace;
35
36 union
37 {
38 uint8 Rshift; // Bit position of the lowest bit of the red component
39 uint8 Yshift;
40 };
41
42 union
43 {
44 uint8 Gshift; // [...] green component
45 uint8 Ushift;
46 uint8 Cbshift;
47 };
48
49 union
50 {
51 uint8 Bshift; // [...] blue component
52 uint8 Vshift;
53 uint8 Crshift;
54 };
55
56 uint8 Ashift; // [...] alpha component.
57
58 // Gets the R/G/B/A values for the passed 32-bit surface pixel value
59 INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
60 {
61 r = (value >> RED_SHIFT) & 0xFF;
62 g = (value >> GREEN_SHIFT) & 0xFF;
63 b = (value >> BLUE_SHIFT) & 0xFF;
64 a = (value >> ALPHA_SHIFT) & 0xFF;
65 }
66
67 }; // MDFN_PixelFormat;
68
69 // Supports 32-bit RGBA
70 // 16-bit is WIP
71 class MDFN_Surface //typedef struct
72 {
73 public:
74
75 MDFN_Surface();
76 MDFN_Surface(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf);
77
78 ~MDFN_Surface();
79
80 uint32 *pixels;
81
82 // w, h, and pitch32 should always be > 0
83 int32 w;
84 int32 h;
85
86 union
87 {
88 int32 pitch32; // In pixels, not in bytes.
89 int32 pitchinpix; // New name, new code should use this.
90 };
91
92 MDFN_PaletteEntry *palette;
93
94 MDFN_PixelFormat format;
95
96 void SetFormat(const MDFN_PixelFormat &new_format, bool convert);
97
98 // Gets the R/G/B/A values for the passed 32-bit surface pixel value
99 INLINE void DecodeColor(uint32 value, int &r, int &g, int &b, int &a) const
100 {
101 r = (value >> RED_SHIFT) & 0xFF;
102 g = (value >> GREEN_SHIFT) & 0xFF;
103 b = (value >> BLUE_SHIFT) & 0xFF;
104 a = (value >> ALPHA_SHIFT) & 0xFF;
105 }
106
107 INLINE void DecodeColor(uint32 value, int &r, int &g, int &b) const
108 {
109 r = (value >> RED_SHIFT) & 0xFF;
110 g = (value >> GREEN_SHIFT) & 0xFF;
111 b = (value >> BLUE_SHIFT) & 0xFF;
112 }
113 private:
114 void Init(void *const p_pixels, const uint32 p_width, const uint32 p_height, const uint32 p_pitchinpix, const MDFN_PixelFormat &nf);
115 };
116
117 #endif
0 #ifndef __MDFN_VIDEO_H
1 #define __MDFN_VIDEO_H
2
3 #include "video/surface.h"
4
5 void MDFN_DispMessage(const char *format, ...);
6
7 #endif
0 LIBRARY "msvc-2003"
1 EXPORTS
2 retro_set_environment
3 retro_set_video_refresh
4 retro_set_audio_sample
5 retro_set_audio_sample_batch
6 retro_set_input_poll
7 retro_set_input_state
8 retro_init
9 retro_deinit
10 retro_api_version
11 retro_get_system_info
12 retro_get_system_av_info
13 retro_set_controller_port_device
14 retro_reset
15 retro_run
16 retro_serialize_size
17 retro_serialize
18 retro_unserialize
19 retro_cheat_reset
20 retro_cheat_set
21 retro_load_game
22 retro_load_game_special
23 retro_unload_game
24 retro_get_region
25 retro_get_memory_data
26 retro_get_memory_size
0 <?xml version="1.0" encoding="windows-1250"?>
1 <VisualStudioProject
2 ProjectType="Visual C++"
3 Version="7.10"
4 Name="libretro-psx"
5 ProjectGUID="{A9C675CC-DDF4-4BC5-A212-25AE2465D253}"
6 RootNamespace="libretro-psx"
7 Keyword="Win32Proj">
8 <Platforms>
9 <Platform
10 Name="Win32"/>
11 </Platforms>
12 <Configurations>
13 <Configuration
14 Name="Debug|Win32"
15 OutputDirectory="Debug"
16 IntermediateDirectory="Debug"
17 ConfigurationType="2"
18 CharacterSet="2">
19 <Tool
20 Name="VCCLCompilerTool"
21 Optimization="0"
22 AdditionalIncludeDirectories="&quot;$(SolutionDir)\msvc-2003&quot;"
23 PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBRETROPSX_EXPORTS;WANT_THREADING;WANT_32BPP;__LIBRETRO__;WANT_NEW_API;NEED_TREMOR;NEED_DEINTERLACER;NEED_CD;MEDNAFEN_VERSION_NUMERIC=9361"
24 MinimalRebuild="TRUE"
25 BasicRuntimeChecks="3"
26 RuntimeLibrary="1"
27 UsePrecompiledHeader="0"
28 WarningLevel="3"
29 Detect64BitPortabilityProblems="TRUE"
30 DebugInformationFormat="4"/>
31 <Tool
32 Name="VCCustomBuildTool"/>
33 <Tool
34 Name="VCLinkerTool"
35 OutputFile="$(OutDir)/libretro-psx.dll"
36 LinkIncremental="2"
37 ModuleDefinitionFile="libretro.def"
38 GenerateDebugInformation="TRUE"
39 ProgramDatabaseFile="$(OutDir)/libretro-psx.pdb"
40 SubSystem="2"
41 ImportLibrary="$(OutDir)/libretro-psx.lib"
42 TargetMachine="1"/>
43 <Tool
44 Name="VCMIDLTool"/>
45 <Tool
46 Name="VCPostBuildEventTool"/>
47 <Tool
48 Name="VCPreBuildEventTool"/>
49 <Tool
50 Name="VCPreLinkEventTool"/>
51 <Tool
52 Name="VCResourceCompilerTool"/>
53 <Tool
54 Name="VCWebServiceProxyGeneratorTool"/>
55 <Tool
56 Name="VCXMLDataGeneratorTool"/>
57 <Tool
58 Name="VCWebDeploymentTool"/>
59 <Tool
60 Name="VCManagedWrapperGeneratorTool"/>
61 <Tool
62 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
63 </Configuration>
64 <Configuration
65 Name="Release|Win32"
66 OutputDirectory="Release"
67 IntermediateDirectory="Release"
68 ConfigurationType="2"
69 CharacterSet="2">
70 <Tool
71 Name="VCCLCompilerTool"
72 AdditionalIncludeDirectories="&quot;$(SolutionDir)\msvc-2003&quot;"
73 PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBRETROPSX_EXPORTS;WANT_THREADING;WANT_32BPP;__LIBRETRO__;WANT_NEW_API;NEED_TREMOR;NEED_DEINTERLACER;NEED_CD;MEDNAFEN_VERSION_NUMERIC=9361"
74 RuntimeLibrary="0"
75 UsePrecompiledHeader="0"
76 WarningLevel="3"
77 Detect64BitPortabilityProblems="TRUE"
78 DebugInformationFormat="3"/>
79 <Tool
80 Name="VCCustomBuildTool"/>
81 <Tool
82 Name="VCLinkerTool"
83 OutputFile="$(OutDir)/libretro-psx.dll"
84 LinkIncremental="1"
85 ModuleDefinitionFile="libretro.def"
86 GenerateDebugInformation="TRUE"
87 SubSystem="2"
88 OptimizeReferences="2"
89 EnableCOMDATFolding="2"
90 ImportLibrary="$(OutDir)/libretro-psx.lib"
91 TargetMachine="1"/>
92 <Tool
93 Name="VCMIDLTool"/>
94 <Tool
95 Name="VCPostBuildEventTool"/>
96 <Tool
97 Name="VCPreBuildEventTool"/>
98 <Tool
99 Name="VCPreLinkEventTool"/>
100 <Tool
101 Name="VCResourceCompilerTool"/>
102 <Tool
103 Name="VCWebServiceProxyGeneratorTool"/>
104 <Tool
105 Name="VCXMLDataGeneratorTool"/>
106 <Tool
107 Name="VCWebDeploymentTool"/>
108 <Tool
109 Name="VCManagedWrapperGeneratorTool"/>
110 <Tool
111 Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
112 </Configuration>
113 </Configurations>
114 <References>
115 </References>
116 <Files>
117 <Filter
118 Name="Source Files"
119 Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
120 UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
121 <File
122 RelativePath="..\..\libretro.cpp">
123 </File>
124 <File
125 RelativePath="..\..\scrc32.c">
126 </File>
127 <File
128 RelativePath="..\..\threads.c">
129 <FileConfiguration
130 Name="Debug|Win32">
131 <Tool
132 Name="VCCLCompilerTool"
133 CompileAs="2"/>
134 </FileConfiguration>
135 <FileConfiguration
136 Name="Release|Win32">
137 <Tool
138 Name="VCCLCompilerTool"
139 CompileAs="2"/>
140 </FileConfiguration>
141 </File>
142 <Filter
143 Name="mednafen"
144 Filter="">
145 <File
146 RelativePath="..\..\mednafen\endian.cpp">
147 </File>
148 <File
149 RelativePath="..\..\mednafen\error.cpp">
150 </File>
151 <File
152 RelativePath="..\..\mednafen\file.cpp">
153 </File>
154 <File
155 RelativePath="..\..\mednafen\FileStream.cpp">
156 </File>
157 <File
158 RelativePath="..\..\mednafen\FileWrapper.cpp">
159 </File>
160 <File
161 RelativePath="..\..\mednafen\general.cpp">
162 </File>
163 <File
164 RelativePath="..\..\mednafen\md5.cpp">
165 </File>
166 <File
167 RelativePath="..\..\mednafen\MemoryStream.cpp">
168 </File>
169 <File
170 RelativePath="..\..\mednafen\mempatcher.cpp">
171 </File>
172 <File
173 RelativePath="..\..\mednafen\settings.cpp">
174 </File>
175 <File
176 RelativePath="..\..\mednafen\state.cpp">
177 </File>
178 <File
179 RelativePath="..\..\mednafen\Stream.cpp">
180 </File>
181 <Filter
182 Name="psx"
183 Filter="">
184 <File
185 RelativePath="..\..\mednafen\psx\cdc.cpp">
186 </File>
187 <File
188 RelativePath="..\..\mednafen\psx\cpu.cpp">
189 </File>
190 <File
191 RelativePath="..\..\mednafen\psx\dma.cpp">
192 </File>
193 <File
194 RelativePath="..\..\mednafen\psx\frontio.cpp">
195 </File>
196 <File
197 RelativePath="..\..\mednafen\psx\gpu.cpp">
198 </File>
199 <File
200 RelativePath="..\..\mednafen\psx\gte.cpp">
201 </File>
202 <File
203 RelativePath="..\..\mednafen\psx\irq.cpp">
204 </File>
205 <File
206 RelativePath="..\..\mednafen\psx\mdec.cpp">
207 </File>
208 <File
209 RelativePath="..\..\mednafen\psx\sio.cpp">
210 </File>
211 <File
212 RelativePath="..\..\mednafen\psx\spu.cpp">
213 </File>
214 <File
215 RelativePath="..\..\mednafen\psx\timer.cpp">
216 </File>
217 <Filter
218 Name="input"
219 Filter="">
220 <File
221 RelativePath="..\..\mednafen\psx\input\dualanalog.cpp">
222 </File>
223 <File
224 RelativePath="..\..\mednafen\psx\input\dualshock.cpp">
225 </File>
226 <File
227 RelativePath="..\..\mednafen\psx\input\gamepad.cpp">
228 </File>
229 <File
230 RelativePath="..\..\mednafen\psx\input\guncon.cpp">
231 </File>
232 <File
233 RelativePath="..\..\mednafen\psx\input\justifier.cpp">
234 </File>
235 <File
236 RelativePath="..\..\mednafen\psx\input\memcard.cpp">
237 </File>
238 <File
239 RelativePath="..\..\mednafen\psx\input\mouse.cpp">
240 </File>
241 <File
242 RelativePath="..\..\mednafen\psx\input\multitap.cpp">
243 </File>
244 <File
245 RelativePath="..\..\mednafen\psx\input\negcon.cpp">
246 </File>
247 </Filter>
248 </Filter>
249 <Filter
250 Name="video"
251 Filter="">
252 <File
253 RelativePath="..\..\mednafen\video\Deinterlacer.cpp">
254 </File>
255 <File
256 RelativePath="..\..\mednafen\video\surface.cpp">
257 </File>
258 </Filter>
259 <Filter
260 Name="trio"
261 Filter="">
262 <File
263 RelativePath="..\..\mednafen\trio\trio.c">
264 <FileConfiguration
265 Name="Debug|Win32">
266 <Tool
267 Name="VCCLCompilerTool"
268 CompileAs="2"/>
269 </FileConfiguration>
270 <FileConfiguration
271 Name="Release|Win32">
272 <Tool
273 Name="VCCLCompilerTool"
274 CompileAs="2"/>
275 </FileConfiguration>
276 </File>
277 <File
278 RelativePath="..\..\mednafen\trio\triostr.c">
279 <FileConfiguration
280 Name="Debug|Win32">
281 <Tool
282 Name="VCCLCompilerTool"
283 CompileAs="2"/>
284 </FileConfiguration>
285 <FileConfiguration
286 Name="Release|Win32">
287 <Tool
288 Name="VCCLCompilerTool"
289 CompileAs="2"/>
290 </FileConfiguration>
291 </File>
292 </Filter>
293 <Filter
294 Name="cdrom"
295 Filter="">
296 <File
297 RelativePath="..\..\mednafen\cdrom\audioreader.cpp">
298 </File>
299 <File
300 RelativePath="..\..\mednafen\cdrom\CDAccess.cpp">
301 </File>
302 <File
303 RelativePath="..\..\mednafen\cdrom\CDAccess_CCD.cpp">
304 </File>
305 <File
306 RelativePath="..\..\mednafen\cdrom\CDAccess_Image.cpp">
307 </File>
308 <File
309 RelativePath="..\..\mednafen\cdrom\cdromif.cpp">
310 </File>
311 <File
312 RelativePath="..\..\mednafen\cdrom\CDUtility.cpp">
313 </File>
314 <File
315 RelativePath="..\..\mednafen\cdrom\crc32.cpp">
316 </File>
317 <File
318 RelativePath="..\..\mednafen\cdrom\galois.cpp">
319 </File>
320 <File
321 RelativePath="..\..\mednafen\cdrom\l-ec.cpp">
322 </File>
323 <File
324 RelativePath="..\..\mednafen\cdrom\lec.cpp">
325 </File>
326 <File
327 RelativePath="..\..\mednafen\cdrom\recover-raw.cpp">
328 </File>
329 <File
330 RelativePath="..\..\mednafen\cdrom\SimpleFIFO.cpp">
331 </File>
332 </Filter>
333 <Filter
334 Name="tremor"
335 Filter="">
336 <File
337 RelativePath="..\..\mednafen\tremor\bitwise.c">
338 <FileConfiguration
339 Name="Debug|Win32">
340 <Tool
341 Name="VCCLCompilerTool"
342 CompileAs="1"/>
343 </FileConfiguration>
344 <FileConfiguration
345 Name="Release|Win32">
346 <Tool
347 Name="VCCLCompilerTool"
348 CompileAs="1"/>
349 </FileConfiguration>
350 </File>
351 <File
352 RelativePath="..\..\mednafen\tremor\block.c">
353 <FileConfiguration
354 Name="Debug|Win32">
355 <Tool
356 Name="VCCLCompilerTool"
357 CompileAs="1"/>
358 </FileConfiguration>
359 <FileConfiguration
360 Name="Release|Win32">
361 <Tool
362 Name="VCCLCompilerTool"
363 CompileAs="1"/>
364 </FileConfiguration>
365 </File>
366 <File
367 RelativePath="..\..\mednafen\tremor\codebook.c">
368 <FileConfiguration
369 Name="Debug|Win32">
370 <Tool
371 Name="VCCLCompilerTool"
372 CompileAs="1"/>
373 </FileConfiguration>
374 <FileConfiguration
375 Name="Release|Win32">
376 <Tool
377 Name="VCCLCompilerTool"
378 CompileAs="1"/>
379 </FileConfiguration>
380 </File>
381 <File
382 RelativePath="..\..\mednafen\tremor\floor0.c">
383 <FileConfiguration
384 Name="Debug|Win32">
385 <Tool
386 Name="VCCLCompilerTool"
387 CompileAs="1"/>
388 </FileConfiguration>
389 <FileConfiguration
390 Name="Release|Win32">
391 <Tool
392 Name="VCCLCompilerTool"
393 CompileAs="1"/>
394 </FileConfiguration>
395 </File>
396 <File
397 RelativePath="..\..\mednafen\tremor\floor1.c">
398 <FileConfiguration
399 Name="Debug|Win32">
400 <Tool
401 Name="VCCLCompilerTool"
402 CompileAs="1"/>
403 </FileConfiguration>
404 <FileConfiguration
405 Name="Release|Win32">
406 <Tool
407 Name="VCCLCompilerTool"
408 CompileAs="1"/>
409 </FileConfiguration>
410 </File>
411 <File
412 RelativePath="..\..\mednafen\tremor\framing.c">
413 <FileConfiguration
414 Name="Debug|Win32">
415 <Tool
416 Name="VCCLCompilerTool"
417 CompileAs="1"/>
418 </FileConfiguration>
419 <FileConfiguration
420 Name="Release|Win32">
421 <Tool
422 Name="VCCLCompilerTool"
423 CompileAs="1"/>
424 </FileConfiguration>
425 </File>
426 <File
427 RelativePath="..\..\mednafen\tremor\info.c">
428 <FileConfiguration
429 Name="Debug|Win32">
430 <Tool
431 Name="VCCLCompilerTool"
432 CompileAs="1"/>
433 </FileConfiguration>
434 <FileConfiguration
435 Name="Release|Win32">
436 <Tool
437 Name="VCCLCompilerTool"
438 CompileAs="1"/>
439 </FileConfiguration>
440 </File>
441 <File
442 RelativePath="..\..\mednafen\tremor\ivorbisfile_example.c">
443 <FileConfiguration
444 Name="Debug|Win32">
445 <Tool
446 Name="VCCLCompilerTool"
447 CompileAs="1"/>
448 </FileConfiguration>
449 <FileConfiguration
450 Name="Release|Win32">
451 <Tool
452 Name="VCCLCompilerTool"
453 CompileAs="1"/>
454 </FileConfiguration>
455 </File>
456 <File
457 RelativePath="..\..\mednafen\tremor\mapping0.c">
458 <FileConfiguration
459 Name="Debug|Win32">
460 <Tool
461 Name="VCCLCompilerTool"
462 CompileAs="1"/>
463 </FileConfiguration>
464 <FileConfiguration
465 Name="Release|Win32">
466 <Tool
467 Name="VCCLCompilerTool"
468 CompileAs="1"/>
469 </FileConfiguration>
470 </File>
471 <File
472 RelativePath="..\..\mednafen\tremor\mdct.c">
473 <FileConfiguration
474 Name="Debug|Win32">
475 <Tool
476 Name="VCCLCompilerTool"
477 CompileAs="1"/>
478 </FileConfiguration>
479 <FileConfiguration
480 Name="Release|Win32">
481 <Tool
482 Name="VCCLCompilerTool"
483 CompileAs="1"/>
484 </FileConfiguration>
485 </File>
486 <File
487 RelativePath="..\..\mednafen\tremor\registry.c">
488 <FileConfiguration
489 Name="Debug|Win32">
490 <Tool
491 Name="VCCLCompilerTool"
492 CompileAs="1"/>
493 </FileConfiguration>
494 <FileConfiguration
495 Name="Release|Win32">
496 <Tool
497 Name="VCCLCompilerTool"
498 CompileAs="1"/>
499 </FileConfiguration>
500 </File>
501 <File
502 RelativePath="..\..\mednafen\tremor\res012.c">
503 <FileConfiguration
504 Name="Debug|Win32">
505 <Tool
506 Name="VCCLCompilerTool"
507 CompileAs="1"/>
508 </FileConfiguration>
509 <FileConfiguration
510 Name="Release|Win32">
511 <Tool
512 Name="VCCLCompilerTool"
513 CompileAs="1"/>
514 </FileConfiguration>
515 </File>
516 <File
517 RelativePath="..\..\mednafen\tremor\sharedbook.c">
518 <FileConfiguration
519 Name="Debug|Win32">
520 <Tool
521 Name="VCCLCompilerTool"
522 CompileAs="1"/>
523 </FileConfiguration>
524 <FileConfiguration
525 Name="Release|Win32">
526 <Tool
527 Name="VCCLCompilerTool"
528 CompileAs="1"/>
529 </FileConfiguration>
530 </File>
531 <File
532 RelativePath="..\..\mednafen\tremor\synthesis.c">
533 <FileConfiguration
534 Name="Debug|Win32">
535 <Tool
536 Name="VCCLCompilerTool"
537 CompileAs="1"/>
538 </FileConfiguration>
539 <FileConfiguration
540 Name="Release|Win32">
541 <Tool
542 Name="VCCLCompilerTool"
543 CompileAs="1"/>
544 </FileConfiguration>
545 </File>
546 <File
547 RelativePath="..\..\mednafen\tremor\vorbisfile.c">
548 <FileConfiguration
549 Name="Debug|Win32">
550 <Tool
551 Name="VCCLCompilerTool"
552 CompileAs="1"/>
553 </FileConfiguration>
554 <FileConfiguration
555 Name="Release|Win32">
556 <Tool
557 Name="VCCLCompilerTool"
558 CompileAs="1"/>
559 </FileConfiguration>
560 </File>
561 <File
562 RelativePath="..\..\mednafen\tremor\window.c">
563 <FileConfiguration
564 Name="Debug|Win32">
565 <Tool
566 Name="VCCLCompilerTool"
567 CompileAs="1"/>
568 </FileConfiguration>
569 <FileConfiguration
570 Name="Release|Win32">
571 <Tool
572 Name="VCCLCompilerTool"
573 CompileAs="1"/>
574 </FileConfiguration>
575 </File>
576 </Filter>
577 </Filter>
578 </Filter>
579 <Filter
580 Name="Header Files"
581 Filter="h;hpp;hxx;hm;inl;inc;xsd"
582 UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
583 </Filter>
584 <Filter
585 Name="Resource Files"
586 Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
587 UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
588 </Filter>
589 </Files>
590 <Globals>
591 </Globals>
592 </VisualStudioProject>
0 // ISO C9x compliant stdint.h for Microsoft Visual Studio
1 // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
2 //
3 // Copyright (c) 2006-2008 Alexander Chemeris
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // 3. The name of the author may be used to endorse or promote products
16 // derived from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
19 // WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
21 // EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 ///////////////////////////////////////////////////////////////////////////////
30 #ifndef __RARCH_STDINT_H
31 #define __RARCH_STDINT_H
32
33 #if _MSC_VER && (_MSC_VER < 1600)
34 //pre-MSVC 2010 needs an implementation of stdint.h
35
36 #if _MSC_VER > 1000
37 #pragma once
38 #endif
39
40 #include <limits.h>
41
42 // For Visual Studio 6 in C++ mode and for many Visual Studio versions when
43 // compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
44 // or compiler give many errors like this:
45 // error C2733: second C linkage of overloaded function 'wmemchr' not allowed
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49 # include <wchar.h>
50 #ifdef __cplusplus
51 }
52 #endif
53
54 // Define _W64 macros to mark types changing their size, like intptr_t.
55 #ifndef _W64
56 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
57 # define _W64 __w64
58 # else
59 # define _W64
60 # endif
61 #endif
62
63
64 // 7.18.1 Integer types
65
66 // 7.18.1.1 Exact-width integer types
67
68 // Visual Studio 6 and Embedded Visual C++ 4 doesn't
69 // realize that, e.g. char has the same size as __int8
70 // so we give up on __intX for them.
71 #if (_MSC_VER < 1300)
72 typedef signed char int8_t;
73 typedef signed short int16_t;
74 typedef signed int int32_t;
75 typedef unsigned char uint8_t;
76 typedef unsigned short uint16_t;
77 typedef unsigned int uint32_t;
78 #else
79 typedef signed __int8 int8_t;
80 typedef signed __int16 int16_t;
81 typedef signed __int32 int32_t;
82 typedef unsigned __int8 uint8_t;
83 typedef unsigned __int16 uint16_t;
84 typedef unsigned __int32 uint32_t;
85 #endif
86 typedef signed __int64 int64_t;
87 typedef unsigned __int64 uint64_t;
88
89
90 // 7.18.1.2 Minimum-width integer types
91 typedef int8_t int_least8_t;
92 typedef int16_t int_least16_t;
93 typedef int32_t int_least32_t;
94 typedef int64_t int_least64_t;
95 typedef uint8_t uint_least8_t;
96 typedef uint16_t uint_least16_t;
97 typedef uint32_t uint_least32_t;
98 typedef uint64_t uint_least64_t;
99
100 // 7.18.1.3 Fastest minimum-width integer types
101 typedef int8_t int_fast8_t;
102 typedef int16_t int_fast16_t;
103 typedef int32_t int_fast32_t;
104 typedef int64_t int_fast64_t;
105 typedef uint8_t uint_fast8_t;
106 typedef uint16_t uint_fast16_t;
107 typedef uint32_t uint_fast32_t;
108 typedef uint64_t uint_fast64_t;
109
110 // 7.18.1.4 Integer types capable of holding object pointers
111 #ifdef _WIN64 // [
112 typedef signed __int64 intptr_t;
113 typedef unsigned __int64 uintptr_t;
114 #else // _WIN64 ][
115 typedef _W64 signed int intptr_t;
116 typedef _W64 unsigned int uintptr_t;
117 #endif // _WIN64 ]
118
119 // 7.18.1.5 Greatest-width integer types
120 typedef int64_t intmax_t;
121 typedef uint64_t uintmax_t;
122
123
124 // 7.18.2 Limits of specified-width integer types
125
126 #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
127
128 // 7.18.2.1 Limits of exact-width integer types
129 #define INT8_MIN ((int8_t)_I8_MIN)
130 #define INT8_MAX _I8_MAX
131 #define INT16_MIN ((int16_t)_I16_MIN)
132 #define INT16_MAX _I16_MAX
133 #define INT32_MIN ((int32_t)_I32_MIN)
134 #define INT32_MAX _I32_MAX
135 #define INT64_MIN ((int64_t)_I64_MIN)
136 #define INT64_MAX _I64_MAX
137 #define UINT8_MAX _UI8_MAX
138 #define UINT16_MAX _UI16_MAX
139 #define UINT32_MAX _UI32_MAX
140 #define UINT64_MAX _UI64_MAX
141
142 // 7.18.2.2 Limits of minimum-width integer types
143 #define INT_LEAST8_MIN INT8_MIN
144 #define INT_LEAST8_MAX INT8_MAX
145 #define INT_LEAST16_MIN INT16_MIN
146 #define INT_LEAST16_MAX INT16_MAX
147 #define INT_LEAST32_MIN INT32_MIN
148 #define INT_LEAST32_MAX INT32_MAX
149 #define INT_LEAST64_MIN INT64_MIN
150 #define INT_LEAST64_MAX INT64_MAX
151 #define UINT_LEAST8_MAX UINT8_MAX
152 #define UINT_LEAST16_MAX UINT16_MAX
153 #define UINT_LEAST32_MAX UINT32_MAX
154 #define UINT_LEAST64_MAX UINT64_MAX
155
156 // 7.18.2.3 Limits of fastest minimum-width integer types
157 #define INT_FAST8_MIN INT8_MIN
158 #define INT_FAST8_MAX INT8_MAX
159 #define INT_FAST16_MIN INT16_MIN
160 #define INT_FAST16_MAX INT16_MAX
161 #define INT_FAST32_MIN INT32_MIN
162 #define INT_FAST32_MAX INT32_MAX
163 #define INT_FAST64_MIN INT64_MIN
164 #define INT_FAST64_MAX INT64_MAX
165 #define UINT_FAST8_MAX UINT8_MAX
166 #define UINT_FAST16_MAX UINT16_MAX
167 #define UINT_FAST32_MAX UINT32_MAX
168 #define UINT_FAST64_MAX UINT64_MAX
169
170 // 7.18.2.4 Limits of integer types capable of holding object pointers
171 #ifdef _WIN64 // [
172 # define INTPTR_MIN INT64_MIN
173 # define INTPTR_MAX INT64_MAX
174 # define UINTPTR_MAX UINT64_MAX
175 #else // _WIN64 ][
176 # define INTPTR_MIN INT32_MIN
177 # define INTPTR_MAX INT32_MAX
178 # define UINTPTR_MAX UINT32_MAX
179 #endif // _WIN64 ]
180
181 // 7.18.2.5 Limits of greatest-width integer types
182 #define INTMAX_MIN INT64_MIN
183 #define INTMAX_MAX INT64_MAX
184 #define UINTMAX_MAX UINT64_MAX
185
186 // 7.18.3 Limits of other integer types
187
188 #ifdef _WIN64 // [
189 # define PTRDIFF_MIN _I64_MIN
190 # define PTRDIFF_MAX _I64_MAX
191 #else // _WIN64 ][
192 # define PTRDIFF_MIN _I32_MIN
193 # define PTRDIFF_MAX _I32_MAX
194 #endif // _WIN64 ]
195
196 #define SIG_ATOMIC_MIN INT_MIN
197 #define SIG_ATOMIC_MAX INT_MAX
198
199 #ifndef SIZE_MAX // [
200 # ifdef _WIN64 // [
201 # define SIZE_MAX _UI64_MAX
202 # else // _WIN64 ][
203 # define SIZE_MAX _UI32_MAX
204 # endif // _WIN64 ]
205 #endif // SIZE_MAX ]
206
207 // WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
208 #ifndef WCHAR_MIN // [
209 # define WCHAR_MIN 0
210 #endif // WCHAR_MIN ]
211 #ifndef WCHAR_MAX // [
212 # define WCHAR_MAX _UI16_MAX
213 #endif // WCHAR_MAX ]
214
215 #define WINT_MIN 0
216 #define WINT_MAX _UI16_MAX
217
218 #endif // __STDC_LIMIT_MACROS ]
219
220
221 // 7.18.4 Limits of other integer types
222
223 #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
224
225 // 7.18.4.1 Macros for minimum-width integer constants
226
227 #define INT8_C(val) val##i8
228 #define INT16_C(val) val##i16
229 #define INT32_C(val) val##i32
230 #define INT64_C(val) val##i64
231
232 #define UINT8_C(val) val##ui8
233 #define UINT16_C(val) val##ui16
234 #define UINT32_C(val) val##ui32
235 #define UINT64_C(val) val##ui64
236
237 // 7.18.4.2 Macros for greatest-width integer constants
238 #define INTMAX_C INT64_C
239 #define UINTMAX_C UINT64_C
240
241 #endif // __STDC_CONSTANT_MACROS ]
242
243 #else
244 //sanity for everything else
245 #include <stdint.h>
246 #endif
247
248 #endif
0 Microsoft Visual Studio Solution File, Format Version 8.00
1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "msvc-2003", "msvc-2003/msvc-2003.vcproj", "{A9C675CC-DDF4-4BC5-A212-25AE2465D253}"
2 ProjectSection(ProjectDependencies) = postProject
3 EndProjectSection
4 EndProject
5 Global
6 GlobalSection(SolutionConfiguration) = preSolution
7 Debug = Debug
8 Release = Release
9 EndGlobalSection
10 GlobalSection(ProjectConfiguration) = postSolution
11 {A9C675CC-DDF4-4BC5-A212-25AE2465D253}.Debug.ActiveCfg = Debug|Win32
12 {A9C675CC-DDF4-4BC5-A212-25AE2465D253}.Debug.Build.0 = Debug|Win32
13 {A9C675CC-DDF4-4BC5-A212-25AE2465D253}.Release.ActiveCfg = Release|Win32
14 {A9C675CC-DDF4-4BC5-A212-25AE2465D253}.Release.Build.0 = Release|Win32
15 EndGlobalSection
16 GlobalSection(ExtensibilityGlobals) = postSolution
17 EndGlobalSection
18 GlobalSection(ExtensibilityAddIns) = postSolution
19 EndGlobalSection
20 EndGlobal
0 #ifdef __cplusplus
1 extern "C" {
2 #endif
3
4 #ifdef WANT_CRC32
5
6 static const unsigned long crc_table[256] = {
7 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
8 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
9 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
10 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
11 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
12 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
13 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
14 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
15 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
16 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
17 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
18 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
19 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
20 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
21 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
22 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
23 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
24 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
25 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
26 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
27 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
28 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
29 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
30 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
31 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
32 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
33 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
34 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
35 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
36 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
37 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
38 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
39 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
40 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
41 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
42 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
43 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
44 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
45 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
46 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
47 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
48 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
49 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
50 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
51 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
52 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
53 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
54 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
55 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
56 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
57 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
58 0x2d02ef8dL
59 };
60
61 #define DO1_CRC32(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8);
62 #define DO2_CRC32(buf) DO1_CRC32(buf); DO1_CRC32(buf);
63 #define DO4_CRC32(buf) DO2_CRC32(buf); DO2_CRC32(buf);
64 #define DO8_CRC32(buf) DO4_CRC32(buf); DO4_CRC32(buf);
65
66 unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len)
67 {
68 if (buf == 0) return 0L;
69 crc = crc ^ 0xffffffffL;
70 while (len >= 8)
71 {
72 DO8_CRC32(buf);
73 len -= 8;
74 }
75 if (len) do {
76 DO1_CRC32(buf);
77 } while (--len);
78 return crc ^ 0xffffffffL;
79 }
80
81 #endif
82
83 #ifdef __cplusplus
84 }
85 #endif
0 #ifndef _S_CRC32_H
1 #define _S_CRC32_H
2
3 #ifdef __cplusplus
4 extern "C" {
5 #endif
6
7 unsigned long crc32(unsigned long crc, const unsigned char *buf, unsigned int len);
8
9 #ifdef __cplusplus
10 }
11 #endif
12
13 #endif