mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2025-01-11 18:59:07 +01:00
This commit is contained in:
parent
cf5e1dda45
commit
217ca8de3f
174
Makefile
Normal file
174
Makefile
Normal file
@ -0,0 +1,174 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# Generic makefile for Gamecube projects
|
||||
#
|
||||
# Tab stops set to 4
|
||||
# | | | |
|
||||
# 0 1 2 3
|
||||
#---------------------------------------------------------------------------------
|
||||
# Clear the implicit built in rules
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
# TARGET is the name of the output
|
||||
# BUILD is the directory where object files & intermediate files will be placed
|
||||
# SOURCES is a list of directories containing source code
|
||||
# INCLUDES is a list of directories containing extra header files
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := genplus
|
||||
BUILD := build
|
||||
SOURCES := source source/m68k source/cpu source/sound \
|
||||
source/ngc source/ngc/gui
|
||||
INCLUDES := source source/m68k source/cpu source/sound \
|
||||
source/ngc source/ngc/gui
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float
|
||||
CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) \
|
||||
-DGENESIS_HACKS="1" \
|
||||
|
||||
LDFLAGS = $(MACHDEP) -mogc -Wl,-Map,$(notdir $@).map -Wl,--cref
|
||||
|
||||
PREFIX := powerpc-gekko-
|
||||
|
||||
#export PATH:=/c/devkitPPC_r11/bin:/bin
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
# include and lib
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := /c/devkitPro/devkitPPC
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# any extra libraries we wish to link with
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBS := -logc -lm -lz -logcsys -lsdcard
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# no real need to edit anything past this point unless you need to add additional
|
||||
# rules for different file extensions
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
|
||||
|
||||
export CC := $(PREFIX)gcc
|
||||
export CXX := $(PREFIX)g++
|
||||
export AR := $(PREFIX)ar
|
||||
export OBJCOPY := $(PREFIX)objcopy
|
||||
#---------------------------------------------------------------------------------
|
||||
# automatically build a list of object files for our project
|
||||
#---------------------------------------------------------------------------------
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
sFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.S)))
|
||||
#---------------------------------------------------------------------------------
|
||||
# use CXX for linking C++ projects, CC for standard C
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
export LD := $(CC)
|
||||
else
|
||||
export LD := $(CXX)
|
||||
endif
|
||||
|
||||
export OFILES := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(sFILES:.s=.o) $(SFILES:.S=.o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# build a list of include paths
|
||||
#---------------------------------------------------------------------------------
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# build a list of library paths
|
||||
#---------------------------------------------------------------------------------
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
.PHONY: $(BUILD) clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(BUILD):
|
||||
@[ -d $@ ] || mkdir $@
|
||||
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) *.elf
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
run:
|
||||
psoload $(TARGET).dol
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
reload:
|
||||
psoload -r $(TARGET).dol
|
||||
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# main targets
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT).dol: $(OUTPUT).elf
|
||||
@echo output ... $(notdir $@)
|
||||
@$(OBJCOPY) -O binary $< $@
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
$(OUTPUT).elf: $(OFILES)
|
||||
@echo linking ... $(notdir $@)
|
||||
@$(LD) $^ $(LDFLAGS) $(LIBPATHS) $(LIBS) -o $@
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# Compile Targets for C/C++
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.o : %.cpp
|
||||
@echo Compiling ... $(notdir $<)
|
||||
@$(CXX) -MMD $(CFLAGS) -o $@ -c $<
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.o : %.c
|
||||
@echo Compiling ... $(notdir $<)
|
||||
@$(CC) -MMD $(CFLAGS) -o $@ -c $<
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.o : %.S
|
||||
@echo Compiling ... $(notdir $<)
|
||||
@$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.o : %.s
|
||||
@echo Compiling ... $(notdir $<)
|
||||
@$(CC) -MMD $(CFLAGS) -D_LANGUAGE_ASSEMBLY -c $< -o $@
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# canned command sequence for binary data
|
||||
#---------------------------------------------------------------------------------
|
||||
define bin2o
|
||||
cp $(<) $(*).tmp
|
||||
$(OBJCOPY) -I binary -O elf32-powerpc -B powerpc \
|
||||
--rename-section .data=.rodata,readonly,data,contents,alloc \
|
||||
--redefine-sym _binary_$*_tmp_start=$*\
|
||||
--redefine-sym _binary_$*_tmp_end=$*_end\
|
||||
--redefine-sym _binary_$*_tmp_size=$*_size\
|
||||
$(*).tmp $(@)
|
||||
echo "extern const u8" $(*)"[];" > $(*).h
|
||||
echo "extern const u32" $(*)_size[]";" >> $(*).h
|
||||
rm $(*).tmp
|
||||
endef
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
131
changelog.txt
Normal file
131
changelog.txt
Normal file
@ -0,0 +1,131 @@
|
||||
The Genesis Plus Project
|
||||
------------------------------
|
||||
|
||||
CHANGELOG:
|
||||
|
||||
- completely rewrote EEPROM emulation: support for all known serial EEPROM types (24C01-24C65) and mappers (Sega, Acclaim, EA, COdemasters)
|
||||
used in few games (now use game database) as backup RAM. This should fix SRAM load/save support in the following games:
|
||||
|
||||
|
||||
|
||||
20/07/2007:
|
||||
[Genesis]
|
||||
- corrected TeamPlayer support: fix multiplayer in Gauntlet 4 (Sept. version), Pengo and a lot of others
|
||||
- added J-Cart support: enable multiplayer in Codemasters games (Pete Sampras, Micromachines games, Super Skidmarks)
|
||||
- added serial EEPROM autodetection: fix games with bad SRAM informations in header (NBA Jam TE)
|
||||
- added SVP faking: display 2D graphics in Virtua Racing (the game is however still unplayable)
|
||||
- added support for more internal IO registers: fixe some unlicensed games (Wisdom Tree games...)
|
||||
- added preliminary support for unmapped protection device: fix some unlicensed games with special built-in hardware (Squirell King, Lion King 2...)
|
||||
- added "Soft Reset" combo (in game, use L+Z triggers): this should be like pressing the RESET button on a real Genesis and this is required
|
||||
in some games to enable special features or even complete the game (ex: X-Men).
|
||||
|
||||
[NGC]
|
||||
- added separate configuration for PortA/PortB inputs (GAMEPAD, MULTITAP or NONE, see Joypad Config): this let you setting
|
||||
PORTB as unplugged, which is needed in some games to access special modes or enable cheat codes (Alien Storm, X-Men...)
|
||||
- Freezestate & SRAM files are now compressed (using zlib)
|
||||
- FreezeState & SRAM files can now be saved/loaded to/from SDCARD: located in /genplus/saves/ from the root of your SDCARD
|
||||
- changed initial ROMS directory for SDCARD user: now looking for /genplus/roms/ from the root of your SDCARD
|
||||
- added user-transparent SRAM autoload (detection order is MCARD then SDCARD, SLOTA then SLOTB)
|
||||
- "System reboot" is now used for console reboot and SD/PSO reload (if detected)
|
||||
- added new font: now use original IPL font, extracted from Bootrom
|
||||
- modified controls when going into the rom selection menu (DVD or SDCARD):
|
||||
. use B button to go up one directory
|
||||
. use Z button to quit the file selection menu
|
||||
. use L/R triggers to go down/up one full page
|
||||
. use Left/Right buttons or Analog stick to scroll the selected entry's filename when it can't be full displayed
|
||||
- various menu rearrangment, minor bugfixes & sourcecode cleanup
|
||||
|
||||
21/06/2007:
|
||||
- added 4.7GB DVD support for WII drives (the maximal allowed size for Gamecube DVD is still 1.35GB)
|
||||
- removed MPAL video timings, always use 60Hz NTSC: fix display problems for PAL wii users (no more PAL50 version needed)
|
||||
- added Console Reboot option in main menu (IPL Reboot)
|
||||
- added Multitap support (EA 4-Way Play and Sega Teamplayer): allowed up to four players in games supporting those peripherals
|
||||
- added partial Sega Menacer lightgun support (use Analog Stick): automatically set when detecting the 6-in-1 Menacer game
|
||||
|
||||
18/05/2007:
|
||||
- you can now switch between FM cores without reseting the game. FM registers value are automatically restored when switching.
|
||||
- modified PAL framesync a little bit: the 20ms period is now applied between the start of 2 consecutive frames,
|
||||
no more between the end of the previous and the start of the next one, which seems more correct to me
|
||||
- removed the previous VINT timings modification because it brokes some games (Rocket Knight, Thunderforce III,...)
|
||||
- added automatic Timing configuration (VDP latency, VINT timing & alternate Line Timing) at game loading, based upon specific romname detection.
|
||||
This means you can still modify some of these options afterwards but they are now automatically set/unset when loading a game which need
|
||||
special timing fixes. These fixes are also automatically desactivated when the current game doesn't need them.
|
||||
|
||||
For your information, games that are actually detected and need special timings to run properly are:
|
||||
.Legend of Galahad & Road Rash series (single line not rendered properly)
|
||||
.Sesame Street Counting Cafe (don't boot)
|
||||
.Chaos Engine/Soldiers of Fortune (graphic glitches on scrolling)
|
||||
|
||||
|
||||
08/05/2007:
|
||||
- corrected L & R buttons assignment: fixes Genesis X & Z buttons being inverted
|
||||
- VINT timings are now a little more accurate: fixes Sesame's Street Counting Cafe
|
||||
- SN76496 MAX_OUTPUT back to normal
|
||||
- modified FB_WNOISE value in SN76496 core according to John Kortink's last informations
|
||||
- added support for Maxim's PSG core, same as used in SMSPLUS (it becomes the default PSG core)
|
||||
- updated FM core to the latest MAME version
|
||||
- corrected DAC output level (fixes voices and some special FX being too low)
|
||||
- added support for Gens YM2612 (FM) core (MAME's one still remains default FM core)
|
||||
- added configurable preamplification for each sound cores (see Emulator Options)
|
||||
- added some other configurable sound options (boost overall volume, FM improvment for Gens YM2612)
|
||||
|
||||
11/04/2007:
|
||||
- corrected MAX_OUTPUT value in SN76496 core: fix PSG sound (SFX) volume
|
||||
- removed unused sound buffer allocation
|
||||
|
||||
26/03/2007:
|
||||
- added DVD automount: automatically call libogc DVD_Mount function if ISO PVD reading failed (idea taken from softdev's last neocdredux release). This may be useful for loading roms from a DVD after booting from SDLOAD or after stopping DVD motor.
|
||||
- added "DVD motor off" feature, like in others emulators
|
||||
- corrected Memory Card mounting function: EXI_ProbeReset() function was never called if the first mounting attempt failed. Should fix some of the "Unable to mount memory card" errors.
|
||||
|
||||
22/03/2007:
|
||||
- added SDCARD subdirectory browsing and LFN (255 char. max) support
|
||||
|
||||
17/03/2007:
|
||||
- remove some rendering unused code (only used by DOS version of genesis plus) for little speedup
|
||||
- added an option to enable alternate line rendering timing (fix single line error in Road Rash series and Legend of Galahad's Intro)
|
||||
- Color RAM update now always reset color 0 to border color (fix color glitches in Mortal Kombat,...) (thanks to Noop's for the idea)
|
||||
- added last Softdev's modifications (normalised memory access and ASM GU functions used intead of 'C' ones) for some speedup
|
||||
- updated gcaram.c to be compatible with last libogc version
|
||||
|
||||
09/03/2007:
|
||||
- little rendering code speedups
|
||||
- modified HV counter tables (fix graphic glitches in Skitchin's sky, Lotus 2 Recs, Panorama Cotton, Dashin Desperados & maybe more)
|
||||
- completely rewrote DMA timings emulation so that it works for all games (no more cpu freezing)
|
||||
- added all DMA tranfer rates handling for each three DMA modes and added dma busy flag emulation
|
||||
- modified interrupts handling on VDP register #0 and #1 writes (fix Lemmings status bar)
|
||||
- added VDP RAM write latency (fix Chaos Engine/Soldier of Fortune gfx glitches)
|
||||
- modified FM timers handling a bit (fix Vectorman2 music)
|
||||
- corrected Sprite Limit rendering (fix Sonic 1 & Micromachines 2 title screens)
|
||||
- corrected IO Registers writes (fix Decap' Attack controls, no more need for alternate input)
|
||||
- corrected 6 Buttons Pad emulation (fix 6buttons detection in Mortal Kombat 3, Comix Zone and other 6-buttons compatible games)
|
||||
- modified sound mixing a bit according to Generator sourcecode (FM and PSG ratios seems more correct)
|
||||
- added separate CPU Region (USA, Europe, Japan,...) & Speed (PAL or NTSC) choice in menu options
|
||||
- modified main frame synchro in PAL mode (fix sound glitch in this mode), thanks to Softdev for the solution
|
||||
- added savestates support (go to SRAM menu, memory card supports only)
|
||||
|
||||
07/02/2007: (Eke-Eke)
|
||||
- fm timers fixed (fix missing music in Castle of Illusion, Quackshot, Undead Line, Wonderboy in Monster Lair, Cal 50, Turbo Outrun, Thundeforce 4 and maybe more)
|
||||
- added complete EEPROM emulation (save support now works fine in Wonderboy5, Megaman Willy Wars, NBA Jam...) (credits to Notaz, adapted from Picodrive code)
|
||||
- added preliminar dma timing emulation (fix bottom screen in Legend of Galahad) (credits to Notaz, adapted from Picodrive code)
|
||||
- hack: clear Vint pending after Hint (INT level 4) acknowledge (fix Fatal Rewind)
|
||||
- hack: modify read_bus16 to return a random value (fake fetch) (fix Time Killers)
|
||||
- modified cpu execution timings, with more correct hblank and interrupts timing (fix ISS Deluxe, Double Dragon 2 and certainly more) (Based on Gens code)
|
||||
- modified busreq mechanism: better synchro between z80 & 68k (no need to dejitter anymore) (Based on Gens code)
|
||||
- added sprite collision detection (fix Strider 2)
|
||||
- modified dma fill operation according to correct endianness (fix Contra Hardcorps gfx garbage)
|
||||
|
||||
|
||||
???
|
||||
|
||||
|
||||
WIP1.2 unzip.c
|
||||
Added partial zip support
|
||||
|
||||
WIP1.1 sio.c added
|
||||
Added six button pad support from x86 Gens
|
||||
Additional changes based on Charles MacDonald's gen-hw.txt
|
||||
|
||||
WIP1 07 March 2006
|
||||
Updated SN76496 driver
|
||||
Added GX Hardware Scaling
|
356
genplus.txt
Normal file
356
genplus.txt
Normal file
@ -0,0 +1,356 @@
|
||||
×××-–—————————————————————————————————-———————————————————————————————————-×××
|
||||
|
||||
·gGGgø
|
||||
—————— ·gg• gGee• gGGg ×× ———————————
|
||||
þg þ¨ þ¨ g ×
|
||||
——— þg øg þEeeø þgggg gge·e• ggg•· þ ggg•· ———
|
||||
þgG gg þe þ¨ Ng þ· g¨ þi gg¨
|
||||
— ·gG ggg þg· þ gg þg g××Sg þg gSggg —
|
||||
—————— ¨þggg¨ ¨gggg• þ g ¨g×××× ¨g þ× ¨gg ———
|
||||
·•ggg ·•gg
|
||||
————————P —— L — U S ———————
|
||||
softdev.tehskeen.com
|
||||
ø°º–––————————————————————————————————————————————————————————————————————×·.
|
||||
°Ø¨–; -×× description ××-
|
||||
·/ –––––———— –––––––––– ––—————––––––—— ——–––––– –––––—————
|
||||
|
||||
Genesis Plus emulates the Sega's Genesis/Mega Drive system. It was
|
||||
originally created by Charles MacDonald and ported to the Nintendo GameCube
|
||||
by The "Genesis Plus" Team. It is an open source emulator and a community
|
||||
project which aims to bring you blast processing into the past.
|
||||
|
||||
Using this "emulator" you will be able to enjoy all of your classic 16bit
|
||||
games in all of their glory. GenesisPlus has been converted from a PC
|
||||
based platform to run on the GameCube's proprietary PPC Gekko processor
|
||||
and features customized code to give you the best gaming experience
|
||||
possible.
|
||||
|
||||
This port is based on Genesis Plus 1.2 sourcecode but it's also featuring a lot of
|
||||
modifications & additions to improve games compatibility, emulation accuracy
|
||||
and various peripheral supports. See changelog.txt for the whole history.
|
||||
|
||||
... Features ...
|
||||
|
||||
. accurate & full speed Sega Genesis emulation
|
||||
. Stereo Sound (@48 kHz)
|
||||
. PAL Megadrive (50Hz) timings support
|
||||
. 1~4 Players support
|
||||
. 6-Buttons gamepad support
|
||||
. Sega TeamPlayer & EA 4-Way Play support
|
||||
. J-Cart support (autodetected)
|
||||
. partial Sega Menacer support (autodetected for Menacer 6-in-1 game)
|
||||
. Freeze State support
|
||||
. SRAM support
|
||||
. serial EEPROM support (used by a few games as backup RAM)
|
||||
. ROM banking support (Super Street Fighter 2)
|
||||
. External RAM banking support (Phantasy Star 4, Legend of Thor,…)
|
||||
. Game Genie codes support
|
||||
. ROM Information Screen
|
||||
. Zipped roms support
|
||||
. Interleaved roms support (.smd)
|
||||
. Load roms from SDCARD or DVD (4.7GB DVD support for Wii users)
|
||||
. Load/Save SRAM and FreezeState files (compressed) from/to Memory Card & SDCARD
|
||||
. SRAM autoload feature
|
||||
. SDLOAD or IPL reboot feature
|
||||
|
||||
|
||||
ø°º–––————————————————————————————————————————————————————————————————————×·.
|
||||
°Ø¨–; ×-× installation ×-×
|
||||
·/ –––––———— –––––––––– ––—————––––––—— ——–––––– –––––—————
|
||||
|
||||
The emulator is provided as a .dol which is a Gamecube Executable. You only need to load and run
|
||||
the DOL on your GC or WII (Gamecube controller is needed) using various methods (Bootable DVD, SDLOAD,...)
|
||||
If you have no idea on how to load&run a DOL, please go here on follow the available guides:
|
||||
http://modyawii.tehskeen.com/ (Booting Homebrew Section)
|
||||
|
||||
SDCARD users should create a directory named "genplus" at the root of the SDCARD.
|
||||
Inside this directory, you have to create then a subdirectory named "roms" to put all your roms.
|
||||
You should also create a subdirectory named "saves" where SRAM and FreezeState files will be saved.
|
||||
|
||||
If using a DVD to load the roms, the format of the image you burned must be ISO9960
|
||||
or you won't be able to read from it. The maximal readable size is 1.35GB for Gamecube users
|
||||
and 4.7GB for Wii users.
|
||||
|
||||
IMPORTANT: When putting roms either on DVD or SDCARD, it is recommended to use subdirectories as there is
|
||||
a limit of 1000 files per directory.
|
||||
|
||||
|
||||
|
||||
ø°º–––————————————————————————————————————————————————————————————————————×·.
|
||||
°Ø¨–; -×× usage -××
|
||||
·/ –––––———— –––––––––– ––—————––––––—— ——–––––– –––––—————
|
||||
|
||||
You'll start off with the main introduction screen and after pressing "A"
|
||||
you will be at the main menu. Note that at anytime during gameplay you can
|
||||
return to the main menu by tapping on that little Z button (you know, the
|
||||
one on your controller).
|
||||
|
||||
Pressing 'L + Z' Triggers during Gameplay will execute a "Soft Reset".
|
||||
This should be like pressing the RESET button on a real Genesis.
|
||||
This is needed by some games to unlock special features and by the X-Men
|
||||
game to complete the "Mojo's Crunch" level.
|
||||
|
||||
Pressing 'B' in any menu will get you back to the previous screen.
|
||||
|
||||
Of course it's a menu so you have yourself a few things to choose from.
|
||||
So here's a list and what they do.
|
||||
|
||||
|
||||
PLAY GAME: Takes you into or back to the game.
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
GAME INFOS: Shows basic ROM information
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
This screen shows some basic information for the loaded ROM.
|
||||
Of note is the supports area at the bottom of the list.
|
||||
Use Up/Down buttons or Analog Stick to scrolldown the screen.
|
||||
If the ROM supports 6-button gamepads, they are automatically selected for you.
|
||||
Otherwise, the standard 3-button pad is used. (This can also be forced in Joypad Config menu)
|
||||
|
||||
|
||||
RESET GAME: Performs a soft-reset on the genesis virtual console
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
LOAD NEW GAME: Let you load a new game from DVD or SDCARD
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
When entering the rom selection menu (DVD or SDCARD), following controls are used:
|
||||
|
||||
. A button : load the selected file
|
||||
. B button : go up one directory
|
||||
. Z button : quit the file selection menu
|
||||
. L/R triggers : go down/up one full page
|
||||
. Left/Right buttons or Analog stick : scroll the selected entry's filename when it can't be full displayed
|
||||
. Up/Down buttons or Analog stick : select previous/next file
|
||||
|
||||
* Load from DVD:
|
||||
****************
|
||||
|
||||
A DVD browser is displayed. Navigate and select your ROM from here.
|
||||
IMPORTANT: Your DVD must be in ISO9660 format
|
||||
|
||||
* Load from SDCARD:
|
||||
*******************
|
||||
|
||||
A SDCARD browser is displayed. Navigate and select your ROM from here.
|
||||
IMPORTANT: To load roms from SDCARD, you have to use a SDCARD adapter in MC SlotA
|
||||
On the SDCARD, roms must be initially placed in /genplus/roms subdirectory
|
||||
|
||||
In both cases, the maximum number of files per directory (DVD or SDCARD) is 1000.
|
||||
It is *recommended* to use subdirectories.
|
||||
|
||||
|
||||
EMULATOR OPTIONS: Let you configure various options
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
Misc Options:
|
||||
*************
|
||||
|
||||
X and Y are to try to compensate for TVs with high overscan, or if
|
||||
you just want to play on a smaller area.
|
||||
|
||||
VDP Latency is used to be more accurate in term of VRAM write timing,
|
||||
it is required by some games (Chaos Engine...) to be displayed properly
|
||||
(OFF by default, automatically set when specific roms are detected)
|
||||
|
||||
DMA Timing is used to be more accurate in term of DMA copy to V-RAM timing,
|
||||
it is required by some games (Legend of Galahad...) to be displayed properly
|
||||
(ON by default)
|
||||
|
||||
ALT. timing let you modify the line rendering timing. This is used in some games
|
||||
(Road Rash series, Legend of Galahad) which have single line display glitch
|
||||
(OFF by default, automatically set when specific roms are detected)
|
||||
|
||||
NOTE: These options are now automatically set when loading a game which need special timing fixes.
|
||||
These fixes are also now automatically desactivated when the current game doesn't need them.
|
||||
For your information, games that actually need special timings to run properly are:
|
||||
.Legend of Galahad & Road Rash series (single line not rendered properly)
|
||||
.Sesame Street Counting Cafe (don't boot)
|
||||
.Chaos Engine/Soldiers of Fortune (graphic glitches when scrolling)
|
||||
|
||||
CPU Mode let you force the CPU speed for the game:
|
||||
* AUTO: orignal CPU speed is automatically detected
|
||||
* NTSC: 60hz Genesis display
|
||||
* PAL: 50Hz Genesis display
|
||||
The game will automatically be be reloaded after you change this setting.
|
||||
|
||||
REGION let you force the region setting for the game:
|
||||
when changing region setting, some games may display different things but also may not load
|
||||
if they have some internal region detection code.
|
||||
* AUTO: orignal game region is automatically detected
|
||||
* EUR (europe 50Hz), USA (usa 60Hz), JAPAN (japan 60Hz) or JAPAN_PAL (japan 50Hz)
|
||||
The game will automatically be be reloaded after you change this setting.
|
||||
|
||||
SRAM AUTOLOAD let you enable/disable automatic SRAM loading when starting a new game.
|
||||
The detection order is: MCARD (SLOTA) > MCARD (SLOTB) > SDCARD (SLOTA) > SDCARD (SLOTB)
|
||||
|
||||
|
||||
Sound Options:
|
||||
**************
|
||||
|
||||
PSG VOLUME let you adjust the global volume level for the PSG output (0~200%)
|
||||
FM Volume let you adjust the global volume level for the FM output (0~200%)
|
||||
Default values depends on the current FM & PSG core and are automatically set when switching between cores.
|
||||
|
||||
BOOST VOLUME let you modify the overall sound level (0~4x).
|
||||
This could be useful when adjusting FM and PSG relative levels.
|
||||
Setting those values too high may produce some bad effects.
|
||||
|
||||
HQ YM2612 is only useful when selecting Gens FM core, in order to have the most accurate YM2612 emulation.
|
||||
|
||||
FM CORE let you choose which YM2612 emulation core to use, both have specific issues with some games:
|
||||
* GENS is the core used in Gens, a famous Genesis emulator for PC platforms
|
||||
* MAME is the one used in MAME (DEFAULT)
|
||||
|
||||
PSG CORE let you choose which PSG emulation core to use:
|
||||
* MAME is the one used in MAME
|
||||
* SMSP is the one developped by Maxim from smspower.org (DEFAULT)
|
||||
|
||||
|
||||
|
||||
Configure Joypads:
|
||||
******************
|
||||
|
||||
Allows you to configure the joypads.
|
||||
Here you can remap all 6 buttons, and adjust the Analog stick
|
||||
sensitivity. A lower value is more sensitive.
|
||||
|
||||
IMPORTANT: the Analog Stick is also used when emulating the Sega Menacer lightgun,
|
||||
so you may want to reduce the sensibility when playing the Menacer 6-in-1 game
|
||||
|
||||
|
||||
TYPE let you choose the type of the emulated Genesis gamepads (3-Buttons or 6-Buttons)
|
||||
Genesis Plus automatically detects and set this option if the current game supports 6-Buttons but
|
||||
you can also force use of 3-Buttons gamepads if you prefer.
|
||||
|
||||
* 3BUTTONS: use classic Genesis controllers
|
||||
* 6BUTTONS: use 6-Buttons Genesis controllers
|
||||
|
||||
|
||||
PORTA and PORTB let you choose which type of device to be plugged in each two Genesis input ports:
|
||||
|
||||
* GAMEPAD: single gamepad (3 or 6-buttons, see above)
|
||||
* MULTITAP: multiplayer adapter (Sega Teamplayer or EA 4-Way Play)
|
||||
* NONE: unplugged
|
||||
|
||||
IMPORTANT:
|
||||
|
||||
1/ MULTITAP should only be plugged if the game is supporting one of the multiplayer adapter.
|
||||
Actually, both Sega Teamplayer and EA 4-Way Play adapters are supported.
|
||||
Games are usually supporting only one of the above adapters but Genesis Plus automatically detect
|
||||
which one should be used.
|
||||
|
||||
3/ Most multiplayer games will work with MULTITAP plugged in PORTA but some of them require
|
||||
a GAMEPAD to be plugged in PORTA and the MULTITAP to be plugged in PORTB.
|
||||
|
||||
4/ MULTITAP shouldn't be plugged in both ports since only games supporting more than 4 players
|
||||
can take advantage of this configuration. As we only have 4 controllers max. on the Gamecube,
|
||||
only the 4 first gamepads will effectively been seen as plugged.
|
||||
|
||||
5/ J-Cart games (Micromachines games, Pete Sampras games, Super Skidmarks) use a built-in adapter
|
||||
to enable 2 additional gamepads to be plugged and are not compatible with any of the above adapters.
|
||||
So, do not activate MULTITAP with those games, they are automatically detected by the system which
|
||||
configure itself to enable up to 4 players support.
|
||||
|
||||
6/ Be sure that all controllers are correctly plugged when you switch on the console, otherwise,
|
||||
they won't be detected. Also don't unplug any controllers or you will need to reboot the system.
|
||||
|
||||
7/ Changing Controller Type or Port settings will reset the current game.
|
||||
|
||||
8/ When the 6-in-1 Menacer game is detected, PORTA is forced to NONE and PORTB forced to MENACER, you
|
||||
can not change those settings as long as you don't load another rom (previous settings will be restored)
|
||||
|
||||
|
||||
|
||||
Game Genie Cheats:
|
||||
******************
|
||||
|
||||
Code entry for those of you into cheating :)
|
||||
This screen lets you enter up to eight Game Genie codes.
|
||||
Use the A key to select/release an entry
|
||||
Use the B key to exit.
|
||||
|
||||
|
||||
|
||||
MEMORY MANAGER: Let you managed SRAM and FreezeState files
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
. SRAM Manager: Let you load/save SRAM data from/to the selected device
|
||||
. STATE Manager: Let you load/save FreezeState data from/to the selected device
|
||||
|
||||
For each submenu, you can now choose the device type and location.
|
||||
Be sure to set this according to your system configuration before saving/loading files.
|
||||
|
||||
. Device: Let you choose the device to use: SDCARD or MCARD
|
||||
. SLOT: Let you choose which MC slot to use for the device
|
||||
|
||||
IMPORTANT:
|
||||
|
||||
1/ when using NGC Memory Card in SLOTA, some mounting errors may occur. In this case,
|
||||
remove and insert the Memory Card again before trying to save/load anything.
|
||||
|
||||
2/ when using SDCARD, the directory /genplus/saves must exist
|
||||
|
||||
3/ for Wii users, please note that the SD slot can *NOT* be acceeded so use a SD-Adapter in a MC SLot
|
||||
|
||||
|
||||
|
||||
STOP DVD MOTOR: Stop the DVD motor and the disc from spinning during playtime
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
|
||||
SYSTEM REBOOT:
|
||||
-----------------------------------------------------------------------------------
|
||||
|
||||
For users of SDLoad or PSOLoad, you can call this to go back.
|
||||
For others, this will reboot the system
|
||||
|
||||
|
||||
|
||||
ø°º–––————————————————————————————————————————————————————————————————————×·.
|
||||
°Ø¨–; ××- develloper notes ××-
|
||||
·/ –––––———— –––––––––– ––—————––––––—— ——–––––– –––––—————
|
||||
|
||||
According to the GNU status of this project, the sourcecode MUST be included in any binary releases you made.
|
||||
To recompile the sourcecode, you will need to have installed:
|
||||
. DevkitPPC environment
|
||||
. libOGC last sources
|
||||
|
||||
You also need to replace the gu_psasm.S file which is located in the /LIBBOGC directory (from the root of libogc source directory)
|
||||
with the one included in this release and then recompile/reinstall libogc.
|
||||
|
||||
If you have no idea on how to compile DOLs , please refer to this thread:
|
||||
http://www.tehskeen.com/forums/showthread.php?t=2968.
|
||||
|
||||
|
||||
ø°º–––————————————————————————————————————————————————————————————————————×·.
|
||||
°Ø¨–; ××- credits ××-
|
||||
·/ –––––———— –––––––––– ––—————––––––—— ——–––––– –––––—————
|
||||
|
||||
coding - the "genesis plus team"
|
||||
softdev
|
||||
honkeykong
|
||||
markcube
|
||||
|
||||
additionnal code and support - eke-eke
|
||||
|
||||
graphics - brakken
|
||||
|
||||
documentation - softdev (chm)
|
||||
brakken (user d0x)
|
||||
eke-eke (rewrite and changelog updates)
|
||||
|
||||
additional credits:
|
||||
|
||||
• Stephane Dallongeville for the YM2612 core from his GENS project (http://gens.consolemul.com/) and
|
||||
for making Gens opensource, which has been an unvaluable help while upgrading this emulator
|
||||
• Maxim for his SN76489 core (http://www.smspower.org), already use ins SMSPlus
|
||||
• People at SMSPower's and SpritesMind's forums (http://www.spritesmind.net) for their technical help
|
||||
|
||||
(see /doc for original credits)
|
||||
|
||||
|
||||
×××-–—————————————————————————————————-———————————————————————————————————-×××
|
3
pcutil/Makefile
Normal file
3
pcutil/Makefile
Normal file
@ -0,0 +1,3 @@
|
||||
inject: inject.c
|
||||
@gcc -O2 -Wall inject.c -o inject
|
||||
@strip inject
|
154
pcutil/inject.c
Normal file
154
pcutil/inject.c
Normal file
@ -0,0 +1,154 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.04
|
||||
*
|
||||
* Developer ROM injector.
|
||||
*
|
||||
* You should set ROMOFFSET to match ngc.c, as this will change as the
|
||||
* binary expands and/or contracts.
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DOLHEADERLENGTH 256 // GC DOL Header Length
|
||||
#define MAXTEXT 7 // Maximum 7 Text Sections
|
||||
#define MAXDATA 11 // Maximum 11 Data Sections
|
||||
|
||||
struct DOLHEADER{
|
||||
unsigned int textOffsets[MAXTEXT];
|
||||
unsigned int dataOffsets[MAXDATA];
|
||||
|
||||
unsigned int textAddress[MAXTEXT];
|
||||
unsigned int dataAddress[MAXDATA];
|
||||
|
||||
unsigned int textLength[MAXTEXT];
|
||||
unsigned int dataLength[MAXDATA];
|
||||
|
||||
unsigned int bssAddress;
|
||||
unsigned int bssLength;
|
||||
|
||||
unsigned int entryPoint;
|
||||
unsigned int unused[MAXTEXT];
|
||||
} dolheader;
|
||||
|
||||
unsigned int FLIP32(unsigned int b)
|
||||
{
|
||||
unsigned int c;
|
||||
|
||||
c = ( b & 0xff000000 ) >> 24;
|
||||
c |= ( b & 0xff0000 ) >> 8;
|
||||
c |= ( b & 0xff00 ) << 8;
|
||||
c |= ( b & 0xff ) << 24;
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
#define ROMOFFSET 0x80600000
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
FILE *infile, *outfile;
|
||||
char *dol;
|
||||
char *rom;
|
||||
int dollen, romlen, outlen;
|
||||
char *sig = "GENPLUSR";
|
||||
|
||||
if ( argc != 4 )
|
||||
{
|
||||
printf("Usage : %s genplus.dol genesisrom.smd output.dol\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*** Try to open all three handles ***/
|
||||
infile = fopen(argv[1], "rb");
|
||||
if ( infile == NULL )
|
||||
{
|
||||
printf("Unable to open %s for reading\n", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*** Allocate and load ***/
|
||||
fseek(infile, 0, SEEK_END);
|
||||
dollen=ftell(infile);
|
||||
fseek(infile, 0, SEEK_SET);
|
||||
|
||||
dol = calloc(sizeof(char), dollen + 32);
|
||||
|
||||
if ( fread(dol, 1, dollen, infile ) != dollen )
|
||||
{
|
||||
free(dol);
|
||||
printf("Error reading %s\n", argv[1]);
|
||||
fclose(infile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
|
||||
infile = fopen(argv[2], "rb");
|
||||
if ( infile == NULL )
|
||||
{
|
||||
printf("Unable to open %s for reading\n", argv[2]);
|
||||
free(dol);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*** Allocate and load ***/
|
||||
fseek( infile, 0, SEEK_END);
|
||||
romlen = ftell(infile);
|
||||
fseek( infile, 0, SEEK_SET);
|
||||
rom = calloc( sizeof(char), romlen + 48 );
|
||||
|
||||
if ( fread(rom, 1, romlen, infile) != romlen )
|
||||
{
|
||||
printf("Error reading %s\n", argv[2]);
|
||||
fclose(infile);
|
||||
free(rom);
|
||||
free(dol);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
|
||||
/*** Ok, now have both in memory - so update the dol header and get this file done -;) ***/
|
||||
memcpy(&dolheader, dol, DOLHEADERLENGTH);
|
||||
|
||||
/*** Align to 32 bytes - no real reason, I just like it -;) ***/
|
||||
if ( dollen & 0x1f )
|
||||
dollen = ( dollen & ~0x1f ) + 0x20;
|
||||
|
||||
dolheader.dataOffsets[1] = FLIP32(dollen);
|
||||
dolheader.dataAddress[1] = FLIP32(ROMOFFSET);
|
||||
dolheader.dataLength[1] = FLIP32(romlen + 32);
|
||||
|
||||
/*** Move the updated header back ***/
|
||||
memcpy(dol, &dolheader, DOLHEADERLENGTH);
|
||||
|
||||
outfile = fopen(argv[3], "wb");
|
||||
if ( outfile == NULL )
|
||||
{
|
||||
printf("Unable to open %s for writing!\n", argv[3]);
|
||||
free(rom);
|
||||
free(dol);
|
||||
}
|
||||
|
||||
/*** Now simply update the files ***/
|
||||
fwrite(dol, 1, dollen, outfile);
|
||||
fwrite(sig, 1, 8, outfile);
|
||||
|
||||
outlen = FLIP32(romlen);
|
||||
fwrite(&outlen, 1, 4, outfile);
|
||||
|
||||
char align[32];
|
||||
memset(align, 0, 32);
|
||||
fwrite(align, 1, 20, outfile);
|
||||
fwrite(rom, 1, romlen, outfile);
|
||||
fclose(outfile);
|
||||
|
||||
free(dol);
|
||||
free(rom);
|
||||
|
||||
printf("Output file %s created successfully\n", argv[3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
BIN
pcutil/injectlnx
Normal file
BIN
pcutil/injectlnx
Normal file
Binary file not shown.
30
source/cpu/cpuintrf.h
Normal file
30
source/cpu/cpuintrf.h
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
#ifndef CPUINTRF_H
|
||||
#define CPUINTRF_H
|
||||
|
||||
#include "osd_cpu.h"
|
||||
|
||||
#define CPU_16BIT_PORT 0x4000
|
||||
#define CPU_FLAGS_MASK 0xff00
|
||||
#define CLEAR_LINE 0
|
||||
#define ASSERT_LINE 1
|
||||
#define REG_PREVIOUSPC -1
|
||||
#define REG_SP_CONTENTS -2
|
||||
|
||||
/* daisy-chain link */
|
||||
typedef struct {
|
||||
void (*reset)(int); /* reset callback */
|
||||
int (*interrupt_entry)(int); /* entry callback */
|
||||
void (*interrupt_reti)(int); /* reti callback */
|
||||
int irq_param; /* callback paramater */
|
||||
} Z80_DaisyChain;
|
||||
|
||||
#define Z80_MAXDAISY 4 /* maximum of daisy chan device */
|
||||
|
||||
#define Z80_INT_REQ 0x01 /* interrupt request mask */
|
||||
#define Z80_INT_IEO 0x02 /* interrupt disable mask(IEO) */
|
||||
|
||||
#define Z80_VECTOR(device,state) (((device)<<8)|(state))
|
||||
|
||||
|
||||
#endif /* CPUINTRF_H */
|
342
source/cpu/m68k.h
Normal file
342
source/cpu/m68k.h
Normal file
@ -0,0 +1,342 @@
|
||||
#ifndef M68K__HEADER
|
||||
#define M68K__HEADER
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ========================= LICENSING & COPYRIGHT ======================== */
|
||||
/* ======================================================================== */
|
||||
/*
|
||||
* MUSASHI
|
||||
* Version 3.3
|
||||
*
|
||||
* A portable Motorola M680x0 processor emulation engine.
|
||||
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
|
||||
*
|
||||
* This code may be freely used for non-commercial purposes as long as this
|
||||
* copyright notice remains unaltered in the source code and any binary files
|
||||
* containing this code in compiled form.
|
||||
*
|
||||
* All other lisencing terms must be negotiated with the author
|
||||
* (Karl Stenerud).
|
||||
*
|
||||
* The latest version of this code can be obtained at:
|
||||
* http://kstenerud.cjb.net
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================ GENERAL DEFINES =========================== */
|
||||
|
||||
/* ======================================================================== */
|
||||
|
||||
/* There are 7 levels of interrupt to the 68K.
|
||||
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
|
||||
*/
|
||||
#define M68K_IRQ_NONE 0
|
||||
#define M68K_IRQ_1 1
|
||||
#define M68K_IRQ_2 2
|
||||
#define M68K_IRQ_3 3
|
||||
#define M68K_IRQ_4 4
|
||||
#define M68K_IRQ_5 5
|
||||
#define M68K_IRQ_6 6
|
||||
#define M68K_IRQ_7 7
|
||||
|
||||
|
||||
/* Special interrupt acknowledge values.
|
||||
* Use these as special returns from the interrupt acknowledge callback
|
||||
* (specified later in this header).
|
||||
*/
|
||||
|
||||
/* Causes an interrupt autovector (0x18 + interrupt level) to be taken.
|
||||
* This happens in a real 68K if VPA or AVEC is asserted during an interrupt
|
||||
* acknowledge cycle instead of DTACK.
|
||||
*/
|
||||
#define M68K_INT_ACK_AUTOVECTOR 0xffffffff
|
||||
|
||||
/* Causes the spurious interrupt vector (0x18) to be taken
|
||||
* This happens in a real 68K if BERR is asserted during the interrupt
|
||||
* acknowledge cycle (i.e. no devices responded to the acknowledge).
|
||||
*/
|
||||
#define M68K_INT_ACK_SPURIOUS 0xfffffffe
|
||||
|
||||
|
||||
/* CPU types for use in m68k_set_cpu_type() */
|
||||
enum
|
||||
{
|
||||
M68K_CPU_TYPE_INVALID,
|
||||
M68K_CPU_TYPE_68000,
|
||||
M68K_CPU_TYPE_68010,
|
||||
M68K_CPU_TYPE_68EC020,
|
||||
M68K_CPU_TYPE_68020,
|
||||
M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */
|
||||
M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */
|
||||
};
|
||||
|
||||
/* Registers used by m68k_get_reg() and m68k_set_reg() */
|
||||
typedef enum
|
||||
{
|
||||
/* Real registers */
|
||||
M68K_REG_D0, /* Data registers */
|
||||
M68K_REG_D1,
|
||||
M68K_REG_D2,
|
||||
M68K_REG_D3,
|
||||
M68K_REG_D4,
|
||||
M68K_REG_D5,
|
||||
M68K_REG_D6,
|
||||
M68K_REG_D7,
|
||||
M68K_REG_A0, /* Address registers */
|
||||
M68K_REG_A1,
|
||||
M68K_REG_A2,
|
||||
M68K_REG_A3,
|
||||
M68K_REG_A4,
|
||||
M68K_REG_A5,
|
||||
M68K_REG_A6,
|
||||
M68K_REG_A7,
|
||||
M68K_REG_PC, /* Program Counter */
|
||||
M68K_REG_SR, /* Status Register */
|
||||
M68K_REG_SP, /* The current Stack Pointer (located in A7) */
|
||||
M68K_REG_USP, /* User Stack Pointer */
|
||||
M68K_REG_ISP, /* Interrupt Stack Pointer */
|
||||
M68K_REG_MSP, /* Master Stack Pointer */
|
||||
M68K_REG_SFC, /* Source Function Code */
|
||||
M68K_REG_DFC, /* Destination Function Code */
|
||||
M68K_REG_VBR, /* Vector Base Register */
|
||||
M68K_REG_CACR, /* Cache Control Register */
|
||||
M68K_REG_CAAR, /* Cache Address Register */
|
||||
|
||||
/* Assumed registers */
|
||||
/* These are cheat registers which emulate the 1-longword prefetch
|
||||
* present in the 68000 and 68010.
|
||||
*/
|
||||
M68K_REG_PREF_ADDR, /* Last prefetch address */
|
||||
M68K_REG_PREF_DATA, /* Last prefetch data */
|
||||
|
||||
/* Convenience registers */
|
||||
M68K_REG_PPC, /* Previous value in the program counter */
|
||||
M68K_REG_IR, /* Instruction register */
|
||||
M68K_REG_CPU_TYPE /* Type of CPU being run */
|
||||
} m68k_register_t;
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* You will have to implement these functions */
|
||||
|
||||
/* read/write functions called by the CPU to access memory.
|
||||
* while values used are 32 bits, only the appropriate number
|
||||
* of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
|
||||
* of value should be written to memory).
|
||||
*
|
||||
* NOTE: I have separated the immediate and PC-relative memory fetches
|
||||
* from the other memory fetches because some systems require
|
||||
* differentiation between PROGRAM and DATA fetches (usually
|
||||
* for security setups such as encryption).
|
||||
* This separation can either be achieved by setting
|
||||
* M68K_SEPARATE_READS in m68kconf.h and defining
|
||||
* the read functions, or by setting M68K_EMULATE_FC and
|
||||
* making a function code callback function.
|
||||
* Using the callback offers better emulation coverage
|
||||
* because you can also monitor whether the CPU is in SYSTEM or
|
||||
* USER mode, but it is also slower.
|
||||
*/
|
||||
|
||||
/* Read from anywhere */
|
||||
unsigned int m68k_read_memory_8(unsigned int address);
|
||||
unsigned int m68k_read_memory_16(unsigned int address);
|
||||
unsigned int m68k_read_memory_32(unsigned int address);
|
||||
|
||||
/* Read data immediately following the PC */
|
||||
unsigned int m68k_read_immediate_16(unsigned int address);
|
||||
unsigned int m68k_read_immediate_32(unsigned int address);
|
||||
|
||||
/* Read data relative to the PC */
|
||||
unsigned int m68k_read_pcrelative_8(unsigned int address);
|
||||
unsigned int m68k_read_pcrelative_16(unsigned int address);
|
||||
unsigned int m68k_read_pcrelative_32(unsigned int address);
|
||||
|
||||
/* Memory access for the disassembler */
|
||||
unsigned int m68k_read_disassembler_8 (unsigned int address);
|
||||
unsigned int m68k_read_disassembler_16 (unsigned int address);
|
||||
unsigned int m68k_read_disassembler_32 (unsigned int address);
|
||||
|
||||
/* Write to anywhere */
|
||||
void m68k_write_memory_8(unsigned int address, unsigned int value);
|
||||
void m68k_write_memory_16(unsigned int address, unsigned int value);
|
||||
void m68k_write_memory_32(unsigned int address, unsigned int value);
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================== CALLBACKS =============================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* These functions allow you to set callbacks to the host when specific events
|
||||
* occur. Note that you must enable the corresponding value in m68kconf.h
|
||||
* in order for these to do anything useful.
|
||||
* Note: I have defined default callbacks which are used if you have enabled
|
||||
* the corresponding #define in m68kconf.h but either haven't assigned a
|
||||
* callback or have assigned a callback of NULL.
|
||||
*/
|
||||
|
||||
/* Set the callback for an interrupt acknowledge.
|
||||
* You must enable M68K_EMULATE_INT_ACK in m68kconf.h.
|
||||
* The CPU will call the callback with the interrupt level being acknowledged.
|
||||
* The host program must return either a vector from 0x02-0xff, or one of the
|
||||
* special interrupt acknowledge values specified earlier in this header.
|
||||
* If this is not implemented, the CPU will always assume an autovectored
|
||||
* interrupt, and will automatically clear the interrupt request when it
|
||||
* services the interrupt.
|
||||
* Default behavior: return M68K_INT_ACK_AUTOVECTOR.
|
||||
*/
|
||||
void m68k_set_int_ack_callback(int (*callback)(int int_level));
|
||||
|
||||
|
||||
/* Set the callback for a breakpoint acknowledge (68010+).
|
||||
* You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h.
|
||||
* The CPU will call the callback with whatever was in the data field of the
|
||||
* BKPT instruction for 68020+, or 0 for 68010.
|
||||
* Default behavior: do nothing.
|
||||
*/
|
||||
void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data));
|
||||
|
||||
|
||||
/* Set the callback for the RESET instruction.
|
||||
* You must enable M68K_EMULATE_RESET in m68kconf.h.
|
||||
* The CPU calls this callback every time it encounters a RESET instruction.
|
||||
* Default behavior: do nothing.
|
||||
*/
|
||||
void m68k_set_reset_instr_callback(void (*callback)(void));
|
||||
|
||||
|
||||
/* Set the callback for informing of a large PC change.
|
||||
* You must enable M68K_MONITOR_PC in m68kconf.h.
|
||||
* The CPU calls this callback with the new PC value every time the PC changes
|
||||
* by a large value (currently set for changes by longwords).
|
||||
* Default behavior: do nothing.
|
||||
*/
|
||||
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc));
|
||||
|
||||
|
||||
/* Set the callback for CPU function code changes.
|
||||
* You must enable M68K_EMULATE_FC in m68kconf.h.
|
||||
* The CPU calls this callback with the function code before every memory
|
||||
* access to set the CPU's function code according to what kind of memory
|
||||
* access it is (supervisor/user, program/data and such).
|
||||
* Default behavior: do nothing.
|
||||
*/
|
||||
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc));
|
||||
|
||||
|
||||
/* Set a callback for the instruction cycle of the CPU.
|
||||
* You must enable M68K_INSTRUCTION_HOOK in m68kconf.h.
|
||||
* The CPU calls this callback just before fetching the opcode in the
|
||||
* instruction cycle.
|
||||
* Default behavior: do nothing.
|
||||
*/
|
||||
void m68k_set_instr_hook_callback(void (*callback)(void));
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* Use this function to set the CPU type you want to emulate.
|
||||
* Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68010,
|
||||
* M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020.
|
||||
*/
|
||||
void m68k_set_cpu_type(unsigned int cpu_type);
|
||||
|
||||
/* Pulse the RESET pin on the CPU.
|
||||
* You *MUST* reset the CPU at least once to initialize the emulation
|
||||
* Note: If you didn't call m68k_set_cpu_type() before resetting
|
||||
* the CPU for the first time, the CPU will be set to
|
||||
* M68K_CPU_TYPE_68000.
|
||||
*/
|
||||
void m68k_pulse_reset(void);
|
||||
|
||||
/* execute num_cycles worth of instructions. returns number of cycles used */
|
||||
int m68k_execute(int num_cycles);
|
||||
|
||||
/* These functions let you read/write/modify the number of cycles left to run
|
||||
* while m68k_execute() is running.
|
||||
* These are useful if the 68k accesses a memory-mapped port on another device
|
||||
* that requires immediate processing by another CPU.
|
||||
*/
|
||||
int m68k_cycles_run(void); /* Number of cycles run so far */
|
||||
int m68k_cycles_remaining(void); /* Number of cycles left */
|
||||
void m68k_modify_timeslice(int cycles); /* Modify cycles left */
|
||||
void m68k_end_timeslice(void); /* End timeslice now */
|
||||
|
||||
/* Set the IPL0-IPL2 pins on the CPU (IRQ).
|
||||
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
|
||||
* Setting IRQ to 0 will clear an interrupt request.
|
||||
*/
|
||||
void m68k_set_irq(unsigned int int_level);
|
||||
|
||||
|
||||
/* Halt the CPU as if you pulsed the HALT pin. */
|
||||
void m68k_pulse_halt(void);
|
||||
|
||||
|
||||
/* Context switching to allow multiple CPUs */
|
||||
|
||||
/* Get the size of the cpu context in bytes */
|
||||
unsigned int m68k_context_size(void);
|
||||
|
||||
/* Get a cpu context */
|
||||
unsigned int m68k_get_context(void* dst);
|
||||
|
||||
/* set the current cpu context */
|
||||
void m68k_set_context(void* dst);
|
||||
|
||||
/* Save the current cpu context to disk.
|
||||
* You must provide a function pointer of the form:
|
||||
* void save_value(char* identifier, unsigned int value)
|
||||
*/
|
||||
void m68k_save_context( void (*save_value)(char* identifier, unsigned int value));
|
||||
|
||||
/* Load a cpu context from disk.
|
||||
* You must provide a function pointer of the form:
|
||||
* unsigned int load_value(char* identifier)
|
||||
*/
|
||||
void m68k_load_context(unsigned int (*load_value)(char* identifier));
|
||||
|
||||
|
||||
|
||||
/* Peek at the internals of a CPU context. This can either be a context
|
||||
* retrieved using m68k_get_context() or the currently running context.
|
||||
* If context is NULL, the currently running CPU context will be used.
|
||||
*/
|
||||
unsigned int m68k_get_reg(void* context, m68k_register_t reg);
|
||||
|
||||
/* Poke values into the internals of the currently running CPU context */
|
||||
void m68k_set_reg(m68k_register_t reg, unsigned int value);
|
||||
|
||||
/* Check if an instruction is valid for the specified CPU type */
|
||||
unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type);
|
||||
|
||||
/* Disassemble 1 instruction using the epecified CPU type at pc. Stores
|
||||
* disassembly in str_buff and returns the size of the instruction in bytes.
|
||||
*/
|
||||
unsigned int m68k_disassemble(char* str_buff, unsigned int pc, unsigned int cpu_type);
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================= CONFIGURATION ============================ */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* Import the configuration for this build */
|
||||
#include "m68kconf.h"
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================== END OF FILE ============================= */
|
||||
/* ======================================================================== */
|
||||
|
||||
#endif /* M68K__HEADER */
|
||||
|
||||
/*** Not really required, but makes for clean compile under DevkitPPC ***/
|
||||
extern int vdp_int_ack_callback(int int_level);
|
183
source/cpu/m68kconf.h
Normal file
183
source/cpu/m68kconf.h
Normal file
@ -0,0 +1,183 @@
|
||||
/* ======================================================================== */
|
||||
/* ========================= LICENSING & COPYRIGHT ======================== */
|
||||
/* ======================================================================== */
|
||||
/*
|
||||
* MUSASHI
|
||||
* Version 3.3
|
||||
*
|
||||
* A portable Motorola M680x0 processor emulation engine.
|
||||
* Copyright 1998-2001 Karl Stenerud. All rights reserved.
|
||||
*
|
||||
* This code may be freely used for non-commercial purposes as long as this
|
||||
* copyright notice remains unaltered in the source code and any binary files
|
||||
* containing this code in compiled form.
|
||||
*
|
||||
* All other lisencing terms must be negotiated with the author
|
||||
* (Karl Stenerud).
|
||||
*
|
||||
* The latest version of this code can be obtained at:
|
||||
* http://kstenerud.cjb.net
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef M68KCONF__HEADER
|
||||
#define M68KCONF__HEADER
|
||||
|
||||
|
||||
/* Configuration switches.
|
||||
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
|
||||
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
|
||||
* or macro you specify, rather than using callback functions whose pointer
|
||||
* must be passed in using m68k_set_xxx_callback().
|
||||
*/
|
||||
#define OPT_OFF 0
|
||||
#define OPT_ON 1
|
||||
#define OPT_SPECIFY_HANDLER 2
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================== MAME STUFF ============================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* If you're compiling this for MAME, only change M68K_COMPILE_FOR_MAME
|
||||
* to OPT_ON and use m68kmame.h to configure the 68k core.
|
||||
*/
|
||||
#ifndef M68K_COMPILE_FOR_MAME
|
||||
#define M68K_COMPILE_FOR_MAME OPT_OFF
|
||||
#endif /* M68K_COMPILE_FOR_MAME */
|
||||
|
||||
#if M68K_COMPILE_FOR_MAME == OPT_ON
|
||||
#include "m68kmame.h"
|
||||
#else
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================= CONFIGURATION ============================ */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* Turn on if you want to use the following M68K variants */
|
||||
#define M68K_EMULATE_010 OPT_ON
|
||||
#define M68K_EMULATE_EC020 OPT_ON
|
||||
#define M68K_EMULATE_020 OPT_ON
|
||||
|
||||
|
||||
/* If on, the CPU will call m68k_read_immediate_xx() for immediate addressing
|
||||
* and m68k_read_pcrelative_xx() for PC-relative addressing.
|
||||
* If off, all read requests from the CPU will be redirected to m68k_read_xx()
|
||||
*/
|
||||
#define M68K_SEPARATE_READS OPT_OFF
|
||||
|
||||
|
||||
/* If on, CPU will call the interrupt acknowledge callback when it services an
|
||||
* interrupt.
|
||||
* If off, all interrupts will be autovectored and all interrupt requests will
|
||||
* auto-clear when the interrupt is serviced.
|
||||
*/
|
||||
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
|
||||
#define M68K_INT_ACK_CALLBACK(A) vdp_int_ack_callback(A)
|
||||
|
||||
|
||||
/* If on, CPU will call the breakpoint acknowledge callback when it encounters
|
||||
* a breakpoint instruction and it is running a 68010+.
|
||||
*/
|
||||
#define M68K_EMULATE_BKPT_ACK OPT_OFF
|
||||
#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
|
||||
|
||||
|
||||
/* If on, the CPU will monitor the trace flags and take trace exceptions
|
||||
*/
|
||||
#define M68K_EMULATE_TRACE OPT_OFF
|
||||
|
||||
|
||||
/* If on, CPU will call the output reset callback when it encounters a reset
|
||||
* instruction.
|
||||
*/
|
||||
#define M68K_EMULATE_RESET OPT_OFF
|
||||
#define M68K_RESET_CALLBACK() your_reset_handler_function()
|
||||
|
||||
|
||||
/* If on, CPU will call the set fc callback on every memory access to
|
||||
* differentiate between user/supervisor, program/data access like a real
|
||||
* 68000 would. This should be enabled and the callback should be set if you
|
||||
* want to properly emulate the m68010 or higher. (moves uses function codes
|
||||
* to read/write data from different address spaces)
|
||||
*/
|
||||
#define M68K_EMULATE_FC OPT_OFF
|
||||
#define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(A)
|
||||
|
||||
|
||||
/* If on, CPU will call the pc changed callback when it changes the PC by a
|
||||
* large value. This allows host programs to be nicer when it comes to
|
||||
* fetching immediate data and instructions on a banked memory system.
|
||||
*/
|
||||
#define M68K_MONITOR_PC OPT_OFF
|
||||
#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
|
||||
|
||||
|
||||
/* If on, CPU will call the instruction hook callback before every
|
||||
* instruction.
|
||||
*/
|
||||
#define M68K_INSTRUCTION_HOOK OPT_OFF
|
||||
#define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function()
|
||||
|
||||
|
||||
/* If on, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
|
||||
#define M68K_EMULATE_PREFETCH OPT_OFF
|
||||
|
||||
|
||||
/* If on, the CPU will generate address error exceptions if it tries to
|
||||
* access a word or longword at an odd address.
|
||||
* NOTE: Do not enable this! It is not working!
|
||||
*/
|
||||
#define M68K_EMULATE_ADDRESS_ERROR OPT_OFF
|
||||
|
||||
|
||||
/* Turn on to enable logging of illegal instruction calls.
|
||||
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
|
||||
* Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
|
||||
*/
|
||||
#define M68K_LOG_ENABLE OPT_OFF
|
||||
#define M68K_LOG_1010_1111 OPT_OFF
|
||||
#define M68K_LOG_FILEHANDLE some_file_handle
|
||||
|
||||
|
||||
/* ----------------------------- COMPATIBILITY ---------------------------- */
|
||||
|
||||
/* The following options set optimizations that violate the current ANSI
|
||||
* standard, but will be compliant under the forthcoming C9X standard.
|
||||
*/
|
||||
|
||||
|
||||
/* If on, the enulation core will use 64-bit integers to speed up some
|
||||
* operations.
|
||||
*/
|
||||
#define M68K_USE_64_BIT OPT_OFF
|
||||
|
||||
|
||||
/* Set to your compiler's static inline keyword to enable it, or
|
||||
* set it to blank to disable it.
|
||||
* If you define INLINE in the makefile, it will override this value.
|
||||
* NOTE: not enabling inline functions will SEVERELY slow down emulation.
|
||||
*/
|
||||
#ifndef INLINE
|
||||
#define INLINE static __inline__
|
||||
#endif /* INLINE */
|
||||
|
||||
|
||||
/* If your environment requires special prefixes for system callback functions
|
||||
* such as the argument to qsort(), then set them here or in the makefile.
|
||||
*/
|
||||
#ifndef DECL_SPEC
|
||||
#define DECL_SPEC
|
||||
#endif
|
||||
|
||||
#endif /* M68K_COMPILE_FOR_MAME */
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================== END OF FILE ============================= */
|
||||
/* ======================================================================== */
|
||||
|
||||
#endif /* M68KCONF__HEADER */
|
77
source/cpu/osd_cpu.h
Normal file
77
source/cpu/osd_cpu.h
Normal file
@ -0,0 +1,77 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Define size independent data types and operations. *
|
||||
* *
|
||||
* The following types must be supported by all platforms: *
|
||||
* *
|
||||
* UINT8 - Unsigned 8-bit Integer INT8 - Signed 8-bit integer *
|
||||
* UINT16 - Unsigned 16-bit Integer INT16 - Signed 16-bit integer *
|
||||
* UINT32 - Unsigned 32-bit Integer INT32 - Signed 32-bit integer *
|
||||
* UINT64 - Unsigned 64-bit Integer INT64 - Signed 64-bit integer *
|
||||
* *
|
||||
* *
|
||||
* The macro names for the artithmatic operations are composed as follows: *
|
||||
* *
|
||||
* XXX_R_A_B, where XXX - 3 letter operation code (ADD, SUB, etc.) *
|
||||
* R - The type of the result *
|
||||
* A - The type of operand 1 *
|
||||
* B - The type of operand 2 (if binary operation) *
|
||||
* *
|
||||
* Each type is one of: U8,8,U16,16,U32,32,U64,64 *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
|
||||
#ifndef OSD_CPU_H
|
||||
#define OSD_CPU_H
|
||||
|
||||
typedef unsigned char UINT8;
|
||||
typedef unsigned short UINT16;
|
||||
typedef unsigned int UINT32;
|
||||
__extension__ typedef unsigned long long UINT64;
|
||||
typedef signed char INT8;
|
||||
typedef signed short INT16;
|
||||
typedef signed int INT32;
|
||||
__extension__ typedef signed long long INT64;
|
||||
|
||||
/* Combine two 32-bit integers into a 64-bit integer */
|
||||
#define COMBINE_64_32_32(A,B) ((((UINT64)(A))<<32) | (UINT32)(B))
|
||||
#define COMBINE_U64_U32_U32(A,B) COMBINE_64_32_32(A,B)
|
||||
|
||||
/* Return upper 32 bits of a 64-bit integer */
|
||||
#define HI32_32_64(A) (((UINT64)(A)) >> 32)
|
||||
#define HI32_U32_U64(A) HI32_32_64(A)
|
||||
|
||||
/* Return lower 32 bits of a 64-bit integer */
|
||||
#define LO32_32_64(A) ((A) & 0xffffffff)
|
||||
#define LO32_U32_U64(A) LO32_32_64(A)
|
||||
|
||||
#define DIV_64_64_32(A,B) ((A)/(B))
|
||||
#define DIV_U64_U64_U32(A,B) ((A)/(UINT32)(B))
|
||||
|
||||
#define MOD_32_64_32(A,B) ((A)%(B))
|
||||
#define MOD_U32_U64_U32(A,B) ((A)%(UINT32)(B))
|
||||
|
||||
#define MUL_64_32_32(A,B) ((A)*(INT64)(B))
|
||||
#define MUL_U64_U32_U32(A,B) ((A)*(UINT64)(UINT32)(B))
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* Union of UINT8, UINT16 and UINT32 in native endianess of the target
|
||||
* This is used to access bytes and words in a machine independent manner.
|
||||
* The upper bytes h2 and h3 normally contain zero (16 bit CPU cores)
|
||||
* thus PAIR.d can be used to pass arguments to the memory system
|
||||
* which expects 'int' really.
|
||||
******************************************************************************/
|
||||
typedef union {
|
||||
#ifdef LSB_FIRST
|
||||
struct { UINT8 l,h,h2,h3; } b;
|
||||
struct { UINT16 l,h; } w;
|
||||
#else
|
||||
struct { UINT8 h3,h2,h,l; } b;
|
||||
struct { UINT16 h,l; } w;
|
||||
#endif
|
||||
UINT32 d;
|
||||
} PAIR;
|
||||
|
||||
#endif /* defined OSD_CPU_H */
|
4511
source/cpu/z80.c
Normal file
4511
source/cpu/z80.c
Normal file
File diff suppressed because it is too large
Load Diff
62
source/cpu/z80.h
Normal file
62
source/cpu/z80.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef Z80_H
|
||||
#define Z80_H
|
||||
|
||||
#include "cpuintrf.h"
|
||||
#include "osd_cpu.h"
|
||||
|
||||
enum {
|
||||
Z80_PC=1, Z80_SP, Z80_AF, Z80_BC, Z80_DE, Z80_HL,
|
||||
Z80_IX, Z80_IY, Z80_AF2, Z80_BC2, Z80_DE2, Z80_HL2,
|
||||
Z80_R, Z80_I, Z80_IM, Z80_IFF1, Z80_IFF2, Z80_HALT,
|
||||
Z80_NMI_STATE, Z80_IRQ_STATE, Z80_DC0, Z80_DC1, Z80_DC2, Z80_DC3
|
||||
};
|
||||
|
||||
enum {
|
||||
Z80_TABLE_op,
|
||||
Z80_TABLE_cb,
|
||||
Z80_TABLE_ed,
|
||||
Z80_TABLE_xy,
|
||||
Z80_TABLE_xycb,
|
||||
Z80_TABLE_ex /* cycles counts for taken jr/jp/call and interrupt latency (rst opcodes) */
|
||||
};
|
||||
|
||||
extern int z80_ICount; /* T-state count */
|
||||
|
||||
#define Z80_IGNORE_INT -1 /* Ignore interrupt */
|
||||
#define Z80_NMI_INT -2 /* Execute NMI */
|
||||
#define Z80_IRQ_INT -1000 /* Execute IRQ */
|
||||
|
||||
extern void z80_reset (void *param);
|
||||
extern void z80_exit (void);
|
||||
extern void z80_end_timeslice(void);
|
||||
extern int z80_execute(int cycles);
|
||||
extern void z80_burn(int cycles);
|
||||
extern unsigned z80_get_context (void *dst);
|
||||
extern void z80_set_context (void *src);
|
||||
extern void *z80_get_cycle_table (int which);
|
||||
extern void z80_set_cycle_table (int which, void *new_tbl);
|
||||
extern unsigned z80_get_pc (void);
|
||||
extern void z80_set_pc (unsigned val);
|
||||
extern unsigned z80_get_sp (void);
|
||||
extern void z80_set_sp (unsigned val);
|
||||
extern unsigned z80_get_reg (int regnum);
|
||||
extern void z80_set_reg (int regnum, unsigned val);
|
||||
extern void z80_set_nmi_line(int state);
|
||||
extern void z80_set_irq_line(int irqline, int state);
|
||||
extern void z80_set_irq_callback(int (*irq_callback)(int));
|
||||
extern void z80_state_save(void *file);
|
||||
extern void z80_state_load(void *file);
|
||||
extern const char *z80_info(void *context, int regnum);
|
||||
extern unsigned z80_dasm(char *buffer, unsigned pc);
|
||||
|
||||
#ifdef MAME_DEBUG
|
||||
extern unsigned DasmZ80(char *buffer, unsigned pc);
|
||||
#endif
|
||||
|
||||
unsigned int cpu_readport16(unsigned int port);
|
||||
void cpu_writeport16(unsigned int port, unsigned int data);
|
||||
unsigned int cpu_readmem16(unsigned int address);
|
||||
void cpu_writemem16(unsigned int address, unsigned int data);
|
||||
|
||||
#endif
|
||||
|
2051
source/cpu/z80daa.h
Normal file
2051
source/cpu/z80daa.h
Normal file
File diff suppressed because it is too large
Load Diff
0
source/docs/Genesis_ROM_Format.txt
Normal file
0
source/docs/Genesis_ROM_Format.txt
Normal file
22
source/docs/changelog
Normal file
22
source/docs/changelog
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
[04/20/03]
|
||||
- Modified 68000 emulator to prevent 'tas.b $mem' from writing data back
|
||||
after a read (fixes Gargoyles).
|
||||
- Fixed bug in 68000 emulator to swap order of words written for address
|
||||
register indirect pre-decremented writes (fixes Jim Power graphics).
|
||||
- Added support for 240-line displays (for Super Skidmarks).
|
||||
- Rewrote part of the interrupt handling (fixes some raster effects).
|
||||
- Removed sprite collision detection code (never really worked).
|
||||
- Optimized sprite rendering inner loop.
|
||||
|
||||
[04/13/03]
|
||||
- Finished up memory map for VDP DMA V-bus reads.
|
||||
- Fixed handling of 68000 writes to I/O chip at even addresses.
|
||||
- Fixed bit 7 handling of control register in I/O chip.
|
||||
- Finished up Z80 memory map.
|
||||
- Added code to handle Genesis hardware lock-ups.
|
||||
- Removed some faulty code from the 68000 memory map handlers.
|
||||
|
||||
[03/22/03]
|
||||
- Completed implementation of Z80 banked memory handlers.
|
||||
|
235
source/docs/gamegenie.htm
Normal file
235
source/docs/gamegenie.htm
Normal file
@ -0,0 +1,235 @@
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>GameGenie patches</TITLE>
|
||||
</HEAD>
|
||||
<BODY TEXT="#000000" BGCOLOR="#FEFEF4">
|
||||
<BASEFONT FACE="MS Sans Serif" SIZE="-1">
|
||||
|
||||
<BR>
|
||||
<CENTER><H1>GameGenie Patching</H1></CENTER>
|
||||
<BR>
|
||||
<P> GameGenie was a device created by codemasters and galoob that
|
||||
let you make cheats for games. It was plugged in the console like a normal
|
||||
cartridge, and in its top the desired cartridge was plugged. These cheats are
|
||||
possible because what GameGenie do is edit the RAM that stores values used by
|
||||
the ROMs, setting these values to a constant that can be, for example, the
|
||||
number of lifes you have!</P>
|
||||
<P> Genecyst was the first Genesis emulator to have support
|
||||
for GameGenie then, with Kgen98, Steve Snake started to use this neat feature
|
||||
in his great emulator. No ROM image of a GameGenie is necessary, as some may
|
||||
imagine, to use them with console emulators, these programs themselves have a
|
||||
built-in feature that acts like a GameGenie, writing the codes in the emulated
|
||||
RAM.</P>
|
||||
<P> The GameGenie code consists of a eight-bytes long string, and
|
||||
the valid characters are A, B, C, D, E, F, G, H, J, K, L, M, N, P, R, S, T, V,
|
||||
W, X, Y, Z, 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9, all in uppercase. Each character
|
||||
have a binary repressentation, which is 5-bits long.</P>
|
||||
|
||||
<TABLE WIDTH="70%" BORDER="0" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TH>Char</TH>
|
||||
<TH>Value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">A</TD><TD>00000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">B</TD><TD>00001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">C</TD><TD>00010</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">D</TD><TD>00011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">E</TD><TD>00100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">F</TD><TD>00101</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">G</TD><TD>00110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">H</TD><TD>00111</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">J</TD><TD>01000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">K</TD><TD>01001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">L</TD><TD>01010</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD VALIGN="TOP">
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TH>Char</TH>
|
||||
<TH>Value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">M</TD><TD>01011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">N</TD><TD>01100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">P</TD><TD>01101</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">R</TD><TD>01110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">S</TD><TD>01111</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">T</TD><TD>10000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">V</TD><TD>10001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">W</TD><TD>10010</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">X</TD><TD>10011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">Y</TD><TD>10100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">Z</TD><TD>10101</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD VALIGN="TOP">
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TH>Char</TH>
|
||||
<TH>Value</TH>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">0</TD><TD>10110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">1</TD><TD>10111</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">2</TD><TD>11000</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">3</TD><TD>11001</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">4</TD><TD>11010</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">5</TD><TD>11011</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">6</TD><TD>11100</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">7</TD><TD>11101</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">8</TD><TD>11110</TD>
|
||||
</TR>
|
||||
<TR>
|
||||
<TD ALIGN="CENTER">9</TD><TD>11111</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
<BR>
|
||||
<P> The cheat code should be firstly converted directly using the
|
||||
table above, and then the bits should be reordered. For example, the GameGenie
|
||||
code SCRA-BJX0 is translated to:</P>
|
||||
<FONT FACE="Courier">
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Code:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Bits:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Id:</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>S</TD><TD>C</TD><TD>R</TD><TD>A</TD>
|
||||
</TR>
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>01111</TD><TD>00010</TD><TD>01110</TD><TD>00000</TD>
|
||||
</TR>
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>ijklm</TD><TD>nopIJ</TD><TD>KLMNO</TD><TD>PABCD</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">-</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">-</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">-</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR ALIGN="CENTER"><TD>B</TD><TD>J</TD><TD>X</TD><TD>0</TD></TR>
|
||||
<TR ALIGN="CENTER"><TD>00001</TD><TD>01000</TD><TD>10011</TD><TD>10110</TD></TR>
|
||||
<TR ALIGN="CENTER"><TD>EFGHd</TD><TD>efgha</TD><TD>bcQRS</TD><TD>TUVWX</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</FONT>
|
||||
<P> Then rearrange (using the id) as...</P>
|
||||
<FONT FACE="Courier">
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Bits:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">Id:</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1" ALIGN="CENTER">
|
||||
<TR>
|
||||
<TD>00000000</TD><TD>10011100</TD><TD>01110110</TD>
|
||||
</TR>
|
||||
<TR ALIGN="CENTER">
|
||||
<TD>ABCDEFGH</TD><TD>IJKLMNOP</TD><TD>QRSTUVWX</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="0" ALIGN="CENTER">
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">:</TD></TR>
|
||||
<TR><TD ALIGN="RIGHT" VALIGN="MIDDLE">:</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
<TD>
|
||||
<TABLE BORDER="1">
|
||||
<TR ALIGN="CENTER"><TD>01010100</TD> <TD>01111000</TD></TR>
|
||||
<TR ALIGN="CENTER"><TD>abcdefgh</TD><TD>ijklmnop</TD></TR>
|
||||
</TABLE>
|
||||
</TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</FONT>
|
||||
<BR>
|
||||
<P> Which give us, in hexa, <B>009C76:5478</B>. This means that
|
||||
<B>H5478</B> will be written at <B>H009C76</B> memory offset.</P>
|
||||
</BODY>
|
||||
</HTML>
|
0
source/docs/gen-hw.txt
Normal file
0
source/docs/gen-hw.txt
Normal file
0
source/docs/genvdp.txt
Normal file
0
source/docs/genvdp.txt
Normal file
933
source/docs/io.htm
Normal file
933
source/docs/io.htm
Normal file
@ -0,0 +1,933 @@
|
||||
<html><head><title>Sega Genesis I/O Chip and Peripherals</title></head><body>
|
||||
|
||||
<h2>Sega Genesis I/O Chip and Peripherals</h2>
|
||||
By Charles MacDonald<br>
|
||||
<a href="http://cgfm2.emuviews.com/">http://cgfm2.emuviews.com</a>
|
||||
<hr>
|
||||
|
||||
<h4>Contents</h4>
|
||||
<ul>
|
||||
<li><a href="#ovr">Overview</a>
|
||||
</li><li><a href="#con">Connector details</a>
|
||||
</li><li><a href="#cpu">CPU interface</a>
|
||||
</li><li><a href="#reg">Register list</a>
|
||||
</li><li><a href="#ver">Version register</a>
|
||||
</li><li><a href="#dat">Data register</a>
|
||||
</li><li><a href="#dir">Control register</a>
|
||||
</li><li><a href="#scr">Serial control register</a>
|
||||
</li><li><a href="#txd">TxData register</a>
|
||||
</li><li><a href="#rxd">RxData register</a>
|
||||
</li><li><a href="#ser">Using serial communication</a>
|
||||
</li><li><a href="#per">Peripheral devices</a>
|
||||
<ul>
|
||||
<li><a href="#md2">2-button Mark-III gamepad</a>
|
||||
</li><li><a href="#md3">3-button standard gamepad</a>
|
||||
</li><li><a href="#md6">Fighting Pad 6B</a><i>(incomplete)</i>
|
||||
</li><li><a href="#gun">Lightguns (Sega Menacer, Konami Justifier)</a><i>(incomplete)</i>
|
||||
</li><li><a href="#eat">EA 4-Way Play</a>
|
||||
</li><li><a href="#mul">Sega Team Player</a><i>(incomplete)</i>
|
||||
</li><li><a href="#mmo">Sega Mega Mouse</a>
|
||||
</li></ul>
|
||||
</li><li><a href="#msc">Miscellaneous</a>
|
||||
</li><li><a href="#dis">Disclaimer</a>
|
||||
</li></ul>
|
||||
|
||||
<a name="ovr">
|
||||
</a><h4><a name="ovr">Overview</a></h4>
|
||||
<p>
|
||||
<a name="ovr"> The I/O chip manages three 7-bit I/O ports. It also
|
||||
provides an way for the CPU to read the state of several jumpers in the
|
||||
system. Later versions of the Genesis hardware have the I/O chip
|
||||
integrated into some of the other custom hardware, but they all
|
||||
function identically.
|
||||
</a></p>
|
||||
|
||||
<a name="con">
|
||||
</a><h4><a name="con">Connector details</a></h4>
|
||||
<p>
|
||||
<a name="con"> Ports A and B are male DB-9 connectors, while port C is
|
||||
female. In the Genesis 2 and 3, there is no physical connector for port
|
||||
C, but it can still be programmed and will respond like any other port.
|
||||
(as if no gamepad was connected) Here are the pin assignments:
|
||||
</a></p>
|
||||
|
||||
<pre><a name="con"> Pin 1 : D0
|
||||
Pin 2 : D1
|
||||
Pin 3 : D2
|
||||
Pin 4 : D3
|
||||
Pin 5 : +5V
|
||||
Pin 6 : TL
|
||||
Pin 7 : TH
|
||||
Pin 8 : Ground
|
||||
Pin 9 : TR
|
||||
</a></pre>
|
||||
|
||||
<a name="cpu">
|
||||
</a><h4><a name="cpu">CPU interface</a></h4>
|
||||
|
||||
<p>
|
||||
<a name="cpu"> The I/O chip is connected to the 68000 and Z80. When in
|
||||
Mark-III compatibility mode, the I/O chip has a different set of
|
||||
registers which mimic those of the SMS, which will not be discussed
|
||||
here.
|
||||
<br><br>
|
||||
The I/O chip is mapped to $A10000-$A1001F in the 68000/VDP/Z80 banked address space.
|
||||
It is normally read and written in byte units at odd addresses.
|
||||
The chip gets /LWR only, so writing to even addresses has no effect.
|
||||
|
||||
Reading even addresses returns the same data you'd get from an odd address.
|
||||
If a word-sized write is done, the LSB is sent to the I/O chip and the MSB is ignored.
|
||||
Here are some examples to illustrate these points:
|
||||
</a></p><pre><a name="cpu"> ; Does nothing, byte writes to even addresses are ignored
|
||||
move.b #$40, $A10002
|
||||
|
||||
; Returns contents of version register, reading even addresses is the same as reading odd ones
|
||||
move.b $A10000, d0
|
||||
|
||||
; Same as writing #$40 to $A10007, the MSB is ignored
|
||||
move.w #$C040, $A10006
|
||||
</a></pre>
|
||||
<p></p>
|
||||
|
||||
<a name="reg">
|
||||
</a><h4><a name="reg">Register list</a></h4>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>Address</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10001</td>
|
||||
<td>Version</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10003</td>
|
||||
<td>Port A data</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10005</td>
|
||||
<td>Port B data</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10007</td>
|
||||
<td>Port C data</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10009</td>
|
||||
<td>Port A control</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1000B</td>
|
||||
<td>Port B control</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1000D</td>
|
||||
<td>Port C control</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1000F</td>
|
||||
<td>Port A TxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10011</td>
|
||||
<td>Port A RxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10013</td>
|
||||
<td>Port A serial control</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10015</td>
|
||||
<td>Port B TxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10017</td>
|
||||
<td>Port B RxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A10019</td>
|
||||
<td>Port B serial control</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1001B</td>
|
||||
<td>Port C TxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1001D</td>
|
||||
<td>Port C RxData</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$A1001F</td>
|
||||
<td>Port C serial control</td>
|
||||
</tr>
|
||||
|
||||
</tbody></table>
|
||||
|
||||
<a name="ver">
|
||||
</a><h4><a name="ver">Version register</a></h4>
|
||||
<p>
|
||||
<a name="ver"> The version register returns several types of
|
||||
information, such as a hard-coded version number, settings of the
|
||||
domestic/export and PAL/NTSC jumpers, and the state of a sense pin
|
||||
which the Sega CD uses. </a></p><pre><a name="ver"> D7 : Console is 1= Export (USA, Europe, etc.) 0= Domestic (Japan)
|
||||
D6 : Video type is 1= PAL, 0= NTSC
|
||||
D5 : Sega CD unit is 1= not present, 0= connected.
|
||||
D4 : Unused (always returns zero)
|
||||
D3 : Bit 3 of version number
|
||||
D2 : Bit 2 of version number
|
||||
D1 : Bit 1 of version number
|
||||
D0 : Bit 0 of version number
|
||||
</a></pre>
|
||||
|
||||
<a name="ver"> Bit 5 is used by the Sega CD, returning '0' when it is attached and '1' when it is not.
|
||||
|
||||
<br><br>
|
||||
The version number is zero for the original model Genesis and MegaDrive.
|
||||
All later versions of the hardware are version 1, and have additional security hardware.
|
||||
|
||||
<br><br>
|
||||
Bits 7,6 are used in country protection checks. Some early games used
|
||||
them to display English or Japanese text, so the same game program could
|
||||
be used in both regions. Here's a list of settings:
|
||||
</a><p></p>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>Bit 7</td>
|
||||
<td>Bit 6</td>
|
||||
<td>TV type</td>
|
||||
<td>Region</td>
|
||||
<td>Comments</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>NTSC</td>
|
||||
<td>Japan, Korea, Taiwan</td>
|
||||
<td>262 lines, 60 FPS</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>PAL</td>
|
||||
<td>Japan</td>
|
||||
<td>No hardware actually uses this setting</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>NTSC</td>
|
||||
<td>USA, Canada</td>
|
||||
<td>262 lines, 60 FPS</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>PAL-M</td>
|
||||
<td>Brazil</td>
|
||||
<td>262 lines, 60 FPS</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>PAL</td>
|
||||
<td>Europe, Hong Kong</td>
|
||||
<td>313 lines, 50 FPS</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="ver"> Early games stored a region compatibility code in their
|
||||
header at offset $0001F1. This value could be the ASCII text J, U, or E
|
||||
for Japan, USA or Europe. During game initialization, bits 7,6 could be
|
||||
sampled and compared to the region type stored in the header. If there
|
||||
is a mismatch, many games will fill the screen with a single color lock
|
||||
up intentionally, or sometimes display an error message. <br><br>
|
||||
Later games have a slightly more complex code.
|
||||
Here's the table Sega uses to determine valid codes to use:
|
||||
</a></p>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td colspan="2">$A10001</td>
|
||||
<td> </td>
|
||||
<td rowspan="2">Main Sales Territories</td>
|
||||
<td colspan="16">Hardware Enable Code (numbers from 0 to F below)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#cccccc">
|
||||
<td>Bit 7</td>
|
||||
<td>Bit 6</td>
|
||||
<td>Hardware Type</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2</td>
|
||||
<td>3</td>
|
||||
<td>4</td>
|
||||
<td>5</td>
|
||||
<td>6</td>
|
||||
<td>7</td>
|
||||
<td>8</td>
|
||||
<td>9</td>
|
||||
<td>A</td>
|
||||
<td>B</td>
|
||||
<td>C</td>
|
||||
<td>D</td>
|
||||
<td>E</td>
|
||||
<td>F</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>Japan, NTSC</td>
|
||||
<td>Japan, S. Korea, Taiwan</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>Japan, PAL</td>
|
||||
<td> </td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>Overseas, NTSC</td>
|
||||
<td>N. America, Brazil</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>Overseas, PAL</td>
|
||||
<td>Europe, Hong Kong</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>X</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
<td>O</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="ver"> Common uses of the new code type are ASCII values '4' for N.America, 'A' for UK, and 'B' for UK and Japan.
|
||||
</a></p>
|
||||
|
||||
|
||||
<a name="dat">
|
||||
</a><h4><a name="dat">Data register</a></h4>
|
||||
<p>
|
||||
<a name="dat"> Writing to the data register sets the logic level of
|
||||
pins configured as outputs (0= 0V, 1= +5V), and does nothing to pins
|
||||
configured as inputs. Reading from the data register returns the state
|
||||
of each pin. Here's a list of which bits in the data register
|
||||
correspond to pins on the I/O port.
|
||||
</a></p><pre><a name="dat"> D7 : Unused. This bit will return any value written to it
|
||||
D6 : TH pin
|
||||
D5 : TR pin
|
||||
D4 : TL pin
|
||||
D3 : D3 pin
|
||||
D2 : D2 pin
|
||||
D1 : D1 pin
|
||||
D0 : D0 pin
|
||||
</a></pre>
|
||||
|
||||
<a name="dat"> If a pin is configured as an input, reading it returns
|
||||
the true logic state of whatever the pin is connected to (e.g. 0 for
|
||||
ground, 1 for +5V). If nothing is connected to it, the pin returns '1',
|
||||
maybe due to internal pull-up resistors.
|
||||
<br><br>
|
||||
If a pin is configured as an output, reading it returns the last value written to this register.
|
||||
</a><p></p>
|
||||
|
||||
<a name="dir">
|
||||
</a><h4><a name="dir">Control register</a></h4>
|
||||
<p>
|
||||
<a name="dir"> The control register determines which pins are inputs and outputs.
|
||||
|
||||
</a></p><pre><a name="dir"> D7 : /HL output control (see description)
|
||||
D6 : TH pin is 1=output, 0=input
|
||||
D5 : TR pin is 1=output, 0=input
|
||||
D4 : TL pin is 1=output, 0=input
|
||||
D3 : D3 pin is 1=output, 0=input
|
||||
D2 : D2 pin is 1=output, 0=input
|
||||
D1 : D1 pin is 1=output, 0=input
|
||||
D0 : D0 pin is 1=output, 0=input
|
||||
</a></pre>
|
||||
|
||||
<a name="dir"> If bit 7 of this register is set, and TH is configured as an input,
|
||||
then whenever external hardware makes high to low transition on TH
|
||||
the I/O chip will strobe it's /HL output pin low. This pin connects to
|
||||
the VDP, which can be set up to latch the HV counter and/or cause a level 2
|
||||
interrupt upon /HL going low.
|
||||
</a><p></p>
|
||||
|
||||
<a name="scr">
|
||||
</a><h4><a name="scr">Serial control register</a></h4>
|
||||
<p>
|
||||
<a name="scr"> The serial control register defines how a port is used for serial
|
||||
communications and provides status flags to indicate the current state
|
||||
of sending or receiving data.
|
||||
|
||||
</a></p><pre><a name="scr"> D7 : Serial baud rate bit 1
|
||||
D6 : Serial baud rate bit 0
|
||||
D5 : TR pin functions as 1= serial input pin, 0= normal
|
||||
D4 : TL pin functions as 1= serial output pin, 0= normal
|
||||
D3 : 1= Make I/O chip strobe /HL low when a byte has been received, 0= Do nothing
|
||||
D2 : 1= Error receiving current byte, 0= No error
|
||||
D1 : 1= Rxd buffer is ready to read, 0= Rxd buffer isn't ready
|
||||
D0 : 1= Txd buffer is full, 0= Can write to Txd buffer
|
||||
</a></pre>
|
||||
|
||||
<a name="scr"> The available baud rates are:
|
||||
</a><p></p>
|
||||
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>D7</td>
|
||||
<td>D6</td>
|
||||
<td>Baud rate</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>4800 bps</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>2400 bps</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>1200 bps</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>300 bps</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="scr"> When doing serial communication, TL and/or TR can be used for sending
|
||||
and receiving data. During this time the data and control registers
|
||||
have no effect for whichever pin(s) are in serial mode. The rest of the
|
||||
pins in the same port function normally.
|
||||
|
||||
<br><br> The intended use of bit 3 is to also have the VDP set up to
|
||||
enable level 2 interrupts when /HL goes low. This way, when the I/O
|
||||
chip receives a byte through the TR pin, if this bit is set then it
|
||||
will strobe /HL low and cause an interrupt. So receiving data serially
|
||||
can either be accomplished through manual polling or be interrupt
|
||||
driven.
|
||||
<br><br>
|
||||
Bits 2-0 are read-only status flags, the rest of the bits in this register can be read and written.
|
||||
</a></p>
|
||||
|
||||
|
||||
<a name="txd">
|
||||
</a><h4><a name="txd">TxData register</a></h4>
|
||||
<p>
|
||||
<a name="txd"> Writing a byte to this register will make the I/O chip
|
||||
output the data serially through the TL pin, providing it was
|
||||
configured for serial mode. You should poll bit 0 of the serial control
|
||||
register until the bit returns 0 to ensure the previously written byte
|
||||
has been sent and the TxData buffer is empty.
|
||||
</a></p>
|
||||
|
||||
<a name="rxd">
|
||||
</a><h4><a name="rxd">RxData register</a></h4>
|
||||
<p>
|
||||
<a name="rxd"> Reading from this register returns the last byte
|
||||
received serially through the TR pin. You should check bits 3,2 of the
|
||||
serial control register to ensure that the RxData input buffer is full
|
||||
and that there were no errors in receiving the byte (which would then
|
||||
be invalid).
|
||||
</a></p>
|
||||
|
||||
<a name="ser">
|
||||
</a><h4><a name="ser">Using serial communication</a></h4>
|
||||
<p>
|
||||
<a name="ser"> When in serial mode, the I/O ports output TTL-level
|
||||
signals. You need something like a MAX232 line driver to convert these
|
||||
to RS-232 compatible signals for interfacing with (for example) a PC.
|
||||
<br><br> If you just want to do experiments on the serial ports
|
||||
themselves, you can use a null modem cable with the TL/TR wires
|
||||
switched around to connect port A to B. I used this for testing the
|
||||
serial capabilities while writing this document. Be sure to disconnect
|
||||
the +5V line as well.
|
||||
</a></p>
|
||||
|
||||
<a name="per">
|
||||
</a><h2><a name="per">Peripheral devices</a><hr></h2>
|
||||
|
||||
<ul>
|
||||
<li><a href="#md2">2-button Mark-III gamepad</a>
|
||||
</li><li><a href="#md3">3-button standard gamepad</a>
|
||||
</li><li><a href="#md6">Fighting Pad 6B</a>
|
||||
</li><li><a href="#gun">Lightguns (Sega Menacer, Konami Justifier)</a>
|
||||
</li><li><a href="#eat">EA 4-Way Play</a>
|
||||
</li><li><a href="#mul">Sega Team Player</a>
|
||||
</li><li><a href="#mmo">Sega Mega Mouse</a>
|
||||
</li></ul>
|
||||
|
||||
<a name="md2">
|
||||
</a><h4><a name="md2">2-button Mark-III gamepad</a></h4>
|
||||
<p>
|
||||
<a name="md2"> This controller has a 4-way direction pad, and two buttons (2 and 1).
|
||||
Here's a description of how the controller interfaces with an I/O port:
|
||||
|
||||
</a></p><pre><a name="md2"> D6 : (TH) Not used
|
||||
D5 : (TR) Button 2
|
||||
D4 : (TL) Button 1
|
||||
D3 : (D3) D-pad Right
|
||||
D2 : (D2) D-pad Left
|
||||
D1 : (D1) D-pad Down
|
||||
D0 : (D0) D-pad Up
|
||||
</a></pre>
|
||||
|
||||
<a name="md2"> All buttons are active-low logic, so they return '0' when pressed and '1' when released.
|
||||
</a><p></p>
|
||||
|
||||
<a name="md3">
|
||||
</a><h4><a name="md3">3-button standard gamepad</a></h4>
|
||||
<p>
|
||||
<a name="md3"> This controller has a 4-way direction pad, and four buttons (Start, A, B, C).
|
||||
It uses a multiplexer that selects 1 of 2 inputs using TH, and routes buttons Start or C to TR, and B or A to TL.
|
||||
|
||||
<br><br>
|
||||
Here's a description of how the controller interfaces with an I/O port:
|
||||
|
||||
</a></p><pre><a name="md3"> When TH=0 When TH=1
|
||||
D6 : (TH) 0 1
|
||||
D5 : (TR) Start button Button C
|
||||
D4 : (TL) Button A Button B
|
||||
D3 : (D3) 0 D-pad Right
|
||||
D2 : (D2) 0 D-pad Left
|
||||
D1 : (D1) D-pad Down D-pad Down
|
||||
D0 : (D0) D-pad Up D-pad Up
|
||||
</a></pre>
|
||||
|
||||
<a name="md3"> All buttons are active-low logic, so they return '0' when pressed and '1' when released.
|
||||
|
||||
<br><br> You need a small delay between changing TH and reading the
|
||||
button state back, as the multiplexer takes some time in switching
|
||||
inputs. I've found about four NOPs provides a reasonable delay.
|
||||
<br><br>
|
||||
Here's some example code to read a 3-button gamepad:
|
||||
</a><p></p>
|
||||
|
||||
<table bgcolor="#e0e0e0" width="70%"><tbody><tr><td><pre>; Returns D0 with the button states: 'SACBRLDU'
|
||||
_read_joypad:
|
||||
move.l d1, -(a7)
|
||||
move.b #$40, $A10003
|
||||
nop
|
||||
nop
|
||||
move.b $A10003, d0
|
||||
andi.b #$3F, d0
|
||||
move.b #$00, $A10003
|
||||
nop
|
||||
nop
|
||||
move.b $A10003, d1
|
||||
lsl.b #2, d1
|
||||
andi.b #$C0, d1
|
||||
or.b d1, d0
|
||||
eori.b #$FF, d0
|
||||
move.l (a7)+, d1
|
||||
rts
|
||||
</pre></td></tr></tbody></table>
|
||||
|
||||
<a name="md6">
|
||||
</a><h4><a name="md6">Fighting Pad 6B</a></h4>
|
||||
<p>
|
||||
<a name="md6"> Information coming soon.
|
||||
</a></p>
|
||||
|
||||
<a name="gun">
|
||||
</a><h4><a name="gun">Lightguns (Sega Menacer, Konami Justifier)</a></h4>
|
||||
<p>
|
||||
<a name="gun"> Information coming soon.
|
||||
</a></p>
|
||||
|
||||
<a name="eat">
|
||||
</a><h4><a name="eat">EA 4-Way Play</a></h4>
|
||||
<p>
|
||||
<a name="eat"> The EA 4-Way Play plugs into ports A and B, and allows up to four standard Genesis controllers to be connected at once.
|
||||
|
||||
<br><br> I've determined how the multitap works by examining the
|
||||
joystick reading code from NHL '95 and trying the same routine on a
|
||||
new-style Sega Team Player in 'EXTRA' mode. That said, the actual EA
|
||||
4-Way Play could have some differences that Sega's compatibility mode
|
||||
doesn't take care of.
|
||||
<br><br> To detect the multitap, set CTRL1 to 0x40, CTRL2 to 0x7F and
|
||||
DATA2 to $7C. Reading the lower 2 bits of DATA1 will return zero if the
|
||||
multitap is present. Usually these bits return 0x03 if there is no tap,
|
||||
no controller, or the Sega Team Player isn't in EXTRA mode, but this
|
||||
could be a behavior specific to the Team Player.
|
||||
<br><br>
|
||||
To read the pads, write 0x0C, 0x1C, 0x2C, or 0x3C to DATA2 to select the controller in port A, B, C, or D.
|
||||
You can then use DATA1/CTRL1 to read the pad state just like polling a regular 3-button pad in port A.
|
||||
|
||||
<br><br>
|
||||
Here's some example code to use the EA 4-Way Play:
|
||||
</a></p>
|
||||
|
||||
<table bgcolor="#e0e0e0" width="70%"><tbody><tr><td><pre>; Returns D0 == 0 if the multitap is present, or D0 != 0 if it isn't
|
||||
_detect_4wayplay:
|
||||
move.b #$40, $A10009
|
||||
nop
|
||||
move.b #$7F, $A1000B
|
||||
nop
|
||||
move.b #$7C, $A10005
|
||||
nop
|
||||
moveq #0, d0
|
||||
move.b $A10003, d0
|
||||
andi.b #$03, d0
|
||||
rts
|
||||
|
||||
; Returns the state of all four 3-button gamepads in D0
|
||||
_read_4wayplay:
|
||||
move.l d1-d3/a0, -(a7)
|
||||
lea $A10000, a0
|
||||
move.l #$0C1C2C3C, d2
|
||||
moveq #$03, d3
|
||||
poll: move.b d2, $05(a0)
|
||||
nop
|
||||
nop
|
||||
move.b #$40, $03(a0)
|
||||
nop
|
||||
nop
|
||||
move.b $A10003, d0
|
||||
andi.b #$3F, d0
|
||||
move.b #$00, $03(a0)
|
||||
nop
|
||||
nop
|
||||
move.b $03(a0), d1
|
||||
lsl.b #2, d1
|
||||
andi.b #$C0, d1
|
||||
or.b d1, d0
|
||||
lsl.l #8, d0
|
||||
lsr.l #8, d2
|
||||
dbra d3, poll
|
||||
eori.l #-1, d0
|
||||
move.l (a7)+, d2-d3/a0
|
||||
rts
|
||||
</pre></td></tr></tbody></table>
|
||||
|
||||
|
||||
<a name="mul">
|
||||
</a><h4><a name="mul">Sega Team Player</a></h4>
|
||||
<p>
|
||||
<a name="mul"> The Team Player is a multitap device that allows four peripherals to be connected to the Genesis at one time.
|
||||
It has a mode select switch with several settings:
|
||||
</a></p><pre><a name="mul"> EXTRA - All four ports are enabled. This is the setting used by
|
||||
EA 4-Way Play compatible games.
|
||||
A - Routes the peripheral in port A to port A of the Genesis.
|
||||
B - Routes the peripheral in port B to port A of the Genesis.
|
||||
C - Routes the peripheral in port C to port A of the Genesis.
|
||||
D - Routes the peripheral in port D to port A of the Genesis.
|
||||
MULTI - All four ports are enabled. This is the setting used by
|
||||
Team Player compatible games.
|
||||
</a></pre>
|
||||
<a name="mul"> Sega made two versions of the Team Player. The first one
|
||||
was not compatible with the EA 4-Way Play and only had one cable to
|
||||
connect it to port A. The second one added the "EXTRA" setting for EA
|
||||
4-Way Play compatibility and provides a second cable to connect it to
|
||||
port B as well. Both seem to function identically with the exception of
|
||||
EXTRA mode.
|
||||
<br><br>
|
||||
I don't have any programming information for this device.
|
||||
</a><p></p>
|
||||
|
||||
<a name="mmo">
|
||||
</a><h4><a name="mmo">Sega Mega Mouse</a></h4>
|
||||
<p>
|
||||
<a name="mmo"> This is a three button mouse (left, middle, right) with an extra button
|
||||
(Start) located near the thumb position. It uses a PIC16C54 microcontroller
|
||||
which manages the buttons and position tracking.
|
||||
|
||||
<br><br>
|
||||
The Sega Mega Mouse that is distributed in North America is incompatible with the European version of Populous 2.
|
||||
The mouse functions normally but has Y axis inverted so up is down and vice-versa.
|
||||
It may have been designed for the Japanese Mega Drive mouse, which is a <b>different</b> product with 2 buttons and unique physical appearance.
|
||||
|
||||
<br><br>
|
||||
The protocol works as follows:
|
||||
TH and TR are outputs which tell the microcontroller to stop or start a data transfer, and to acknowledge received data.
|
||||
TL is an input which returns a busy flag for the microcontroller.
|
||||
D3-D0 are inputs that return the data.
|
||||
Here's a table showing the communication process:
|
||||
</a></p>
|
||||
<table bgcolor="#f0f0f0" border="0" cellpadding="4">
|
||||
<tbody><tr bgcolor="#cccccc">
|
||||
<td>Write</td>
|
||||
<td>TH</td>
|
||||
<td>TR</td>
|
||||
<td>TL</td>
|
||||
<td>D3</td>
|
||||
<td>D2</td>
|
||||
<td>D1</td>
|
||||
<td>D0</td>
|
||||
<td>Description</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$60</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>Request data</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>0</td>
|
||||
<td>ID #0 ($0)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>ID #1 ($B)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>ID #2 ($F)</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>1</td>
|
||||
<td>ID #3 ($F)</td>
|
||||
</tr>
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>Y Over</td>
|
||||
<td>X Over</td>
|
||||
<td>Y Sign</td>
|
||||
<td>X Sign</td>
|
||||
<td>Axis sign and overflow</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>Start</td>
|
||||
<td>Middle</td>
|
||||
<td>Right</td>
|
||||
<td>Left</td>
|
||||
<td>Button state</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>X7</td>
|
||||
<td>X6</td>
|
||||
<td>X5</td>
|
||||
<td>X4</td>
|
||||
<td>X axis MSN</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>X3</td>
|
||||
<td>X2</td>
|
||||
<td>X1</td>
|
||||
<td>X0</td>
|
||||
<td>X axis LSN</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$20</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">1</td>
|
||||
<td>0</td>
|
||||
<td>Y7</td>
|
||||
<td>Y6</td>
|
||||
<td>Y5</td>
|
||||
<td>Y4</td>
|
||||
<td>Y axis MSN</td>
|
||||
</tr>
|
||||
|
||||
<tr bgcolor="#dddddd">
|
||||
<td>$00</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td bgcolor="#bbbbbb">0</td>
|
||||
<td>1</td>
|
||||
<td>Y3</td>
|
||||
<td>Y2</td>
|
||||
<td>Y1</td>
|
||||
<td>Y0</td>
|
||||
<td>Y axis LSN</td>
|
||||
</tr>
|
||||
</tbody></table>
|
||||
|
||||
<p>
|
||||
<a name="mmo"> Write #$60 when you are done polling to stop the data
|
||||
transfer. If you continue to poll the mouse after collecting all the
|
||||
data by writing $20 / $00, the Y axis LSN will always be returned. Sega
|
||||
advises polling beyond this point will make the mouse behave
|
||||
abnormally. It's possible that the PIC code in some versions of the
|
||||
Mega Mouse may have problems if the poll sequence is too long.
|
||||
<br><br>
|
||||
The X/Y overflow flags are supposed to be set if the mouse is moved over a distance greater than can be measured.
|
||||
I can't get them to become set, maybe the mouse supports a fairly wide range of movement.
|
||||
|
||||
|
||||
<br><br> You need a considerable delay between writing new values to
|
||||
TH/TR. I think the intention is to poll TL until the microcontroller
|
||||
returns 'not busy', but I can't get this to work reliably. Sega's mouse
|
||||
reading code also has a timeout when checking TL which would indicate
|
||||
it may get stuck in a certain state.
|
||||
<br><br>
|
||||
All buttons (start, left, middle, right) are active-high logic, so they return '1' when pressed and '0' when released.
|
||||
</a></p>
|
||||
|
||||
<a name="msc">
|
||||
</a><h4><a name="msc">Miscellaneous</a></h4>
|
||||
<p>
|
||||
<a name="msc"> After power-up, the default state of the I/O chip are as follows:
|
||||
</a></p><pre><a name="msc"> $A10001 = $80 (Bits 7,6,5 depend on the domestic/export, PAL/NTSC jumpers and having a Sega CD or not)
|
||||
$A10003 = $7F
|
||||
$A10005 = $7F
|
||||
$A10007 = $7F
|
||||
$A10009 = $00
|
||||
$A1000B = $00
|
||||
$A1000D = $00
|
||||
$A1000F = $FF
|
||||
$A10011 = $00
|
||||
$A10013 = $00
|
||||
$A10015 = $FF
|
||||
$A10017 = $00
|
||||
$A10019 = $00
|
||||
$A1001B = $FB
|
||||
$A1001D = $00
|
||||
$A1001F = $00
|
||||
</a></pre>
|
||||
<p></p>
|
||||
|
||||
<a name="dis">
|
||||
</a><h4><a name="dis">Disclaimer</a></h4>
|
||||
<pre><a name="dis"> If you use any information from this document, please credit me
|
||||
(Charles MacDonald) and optionally provide a link to my webpage
|
||||
(http://cgfm2.emuviews.com/) so interested parties can access it.
|
||||
|
||||
The credit text should be present in the accompanying documentation of
|
||||
whatever project which used the information, or even in the program
|
||||
itself (e.g. an about box)
|
||||
|
||||
Regarding distribution, you cannot put this document on another
|
||||
website, nor link directly to it.
|
||||
</a></pre>
|
||||
|
||||
<hr>
|
||||
|
||||
</body></html>
|
340
source/docs/license
Normal file
340
source/docs/license
Normal file
@ -0,0 +1,340 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Library General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) 19yy <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) 19yy name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Library General
|
||||
Public License instead of this License.
|
0
source/docs/m5hvc.txt
Normal file
0
source/docs/m5hvc.txt
Normal file
0
source/docs/porting.txt
Normal file
0
source/docs/porting.txt
Normal file
0
source/docs/readme.txt
Normal file
0
source/docs/readme.txt
Normal file
0
source/docs/ssf2tnc.txt
Normal file
0
source/docs/ssf2tnc.txt
Normal file
0
source/docs/todo.txt
Normal file
0
source/docs/todo.txt
Normal file
445
source/eeprom.c
Normal file
445
source/eeprom.c
Normal file
@ -0,0 +1,445 @@
|
||||
#include "shared.h"
|
||||
#include "rominfo.h"
|
||||
|
||||
#define GAME_COUNT 21
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char game_id[14];
|
||||
uint16 chk;
|
||||
T_EEPROM_TYPE type;
|
||||
} T_GAME_ENTRY;
|
||||
|
||||
T_GAME_ENTRY database[GAME_COUNT] =
|
||||
{
|
||||
/* ACCLAIM mappers */
|
||||
/* 24C02 (old mapper) */
|
||||
{{"T-081326" }, 0, {8, 0xFF, 0xFF, 0x200000, 0x200000, 0x200000, 0, 1, 1}}, /* NBA Jam (UE) */
|
||||
{{"T-81033" }, 0, {8, 0xFF, 0xFF, 0x200000, 0x200000, 0x200000, 0, 1, 1}}, /* NBA Jam (J) */
|
||||
/* 24C02 */
|
||||
{{"T-81406" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NBA Jam TE */
|
||||
{{"T-081276" }, 0, {8, 0xFF, 0xFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club */
|
||||
/* 24C16 */
|
||||
{{"T-081586" }, 0, {8, 0x7FF, 0x7FF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* NFL Quarterback Club '96 */
|
||||
/* 24C65 */
|
||||
{{"T-81576" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* College Slam */
|
||||
{{"T-81476" }, 0, {16, 0x1FFF, 0x1FFF, 0x200001, 0x200001, 0x200000, 0, 0, 0}}, /* Frank Thomas Big Hurt Baseball */
|
||||
|
||||
/* EA mapper (24C01 only) */
|
||||
{{"T-50396" }, 0, {7, 0x7F, 0x7F, 0x200000, 0x200000, 0x200000, 7, 7, 6}}, /* NHLPA Hockey 93 (UE) */
|
||||
{{"T-50176" }, 0, {7, 0x7F, 0x7F, 0x200000, 0x200000, 0x200000, 7, 7, 6}}, /* Rings of Power */
|
||||
|
||||
/* SEGA mapper (24C01 only) */
|
||||
{{"T-12046" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Megaman - The Wily Wars */
|
||||
{{"T-12053" }, 0xEA80, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Rockman Mega World (J) [A] */
|
||||
{{"MK-1215" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Evander 'Real Deal' Holyfield's Boxing */
|
||||
{{"MK-1228" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (U) */
|
||||
{{"G-5538" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (J) */
|
||||
{{"PR-1993" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Greatest Heavyweights of the Ring (E) */
|
||||
{{"G-4060" }, 0, {7, 0x7F, 0x7F, 0x200001, 0x200001, 0x200001, 0, 0, 1}}, /* Wonderboy in Monster World */
|
||||
|
||||
/* CODEMASTERS mapper */
|
||||
/* 24C08 */
|
||||
{{"T-120096" }, 0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines 2 - Turbo Tournament (E) */
|
||||
{{"00000000-00"}, 0x168B, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military */
|
||||
{{"00000000-00"}, 0xCEE0, {8, 0x3FF, 0x3FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Military (Bad)*/
|
||||
/* 24C16 */
|
||||
{{"00000000-00"}, 0x165E, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}}, /* Micro Machines Turbo Tournament 96 */
|
||||
{{"00000000-00"}, 0x2C41, {8, 0x7FF, 0x7FF, 0x300000, 0x380001, 0x300000, 0, 7, 1}} /* Micro Machines Turbo Tournament 96 (Bad)*/
|
||||
};
|
||||
|
||||
|
||||
T_EEPROM eeprom;
|
||||
|
||||
void EEPROM_Init()
|
||||
{
|
||||
uint8 i = 0;
|
||||
|
||||
/* initialize eeprom */
|
||||
memset(&eeprom, 0, sizeof(T_EEPROM));
|
||||
eeprom.sda = eeprom.old_sda = 1;
|
||||
eeprom.scl = eeprom.old_scl = 1;
|
||||
eeprom.state = STAND_BY;
|
||||
|
||||
sram.custom = 0;
|
||||
|
||||
/* look into game database */
|
||||
while ((i<GAME_COUNT) && (!sram.custom))
|
||||
{
|
||||
if (strstr(rominfo.product,database[i].game_id) != NULL)
|
||||
{
|
||||
/* additional check (Micro Machines, Rockman Mega World) */
|
||||
if ((database[i].chk == 0) || (database[i].chk == rominfo.checksum))
|
||||
{
|
||||
sram.custom = 1;
|
||||
sram.on = 1;
|
||||
sram.write = 1;
|
||||
memcpy(&eeprom.type, &database[i].type, sizeof(T_EEPROM_TYPE));
|
||||
|
||||
/* Micromachines II need initialized values in RAM */
|
||||
if (i == 16)
|
||||
{
|
||||
int j=0;
|
||||
while (j<0x400)
|
||||
{
|
||||
/* memory array is filled with "PETETEST01234567" */
|
||||
sram.sram[j++] = 0x50;
|
||||
sram.sram[j++] = 0x45;
|
||||
sram.sram[j++] = 0x54;
|
||||
sram.sram[j++] = 0x45;
|
||||
sram.sram[j++] = 0x54;
|
||||
sram.sram[j++] = 0x45;
|
||||
sram.sram[j++] = 0x53;
|
||||
sram.sram[j++] = 0x54;
|
||||
sram.sram[j++] = 0x30;
|
||||
sram.sram[j++] = 0x31;
|
||||
sram.sram[j++] = 0x32;
|
||||
sram.sram[j++] = 0x33;
|
||||
sram.sram[j++] = 0x34;
|
||||
sram.sram[j++] = 0x35;
|
||||
sram.sram[j++] = 0x36;
|
||||
sram.sram[j++] = 0x37;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (sram.custom)
|
||||
{
|
||||
/* set SRAM start & end address */
|
||||
sram.start = sram.end = eeprom.type.sda_in_adr;
|
||||
if (sram.end < eeprom.type.sda_out_adr) sram.end = eeprom.type.sda_out_adr;
|
||||
if (sram.end < eeprom.type.scl_adr) sram.end = eeprom.type.scl_adr;
|
||||
if (sram.start > eeprom.type.sda_out_adr) sram.start = eeprom.type.sda_out_adr;
|
||||
if (sram.start > eeprom.type.scl_adr) sram.start = eeprom.type.scl_adr;
|
||||
}
|
||||
else if ((sram.end - sram.start) < 2)
|
||||
{
|
||||
/* Game not found in database but header indicates it uses EEPROM */
|
||||
sram.custom = 1;
|
||||
sram.on = 1;
|
||||
sram.write = 1;
|
||||
|
||||
/* set SEGA mapper as default */
|
||||
memcpy(&eeprom.type, &database[9].type, sizeof(T_EEPROM_TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
static void Detect_START()
|
||||
{
|
||||
if (eeprom.old_scl && eeprom.scl)
|
||||
{
|
||||
if (eeprom.old_sda && !eeprom.sda)
|
||||
{
|
||||
eeprom.cycles = 0;
|
||||
eeprom.slave_mask = 0;
|
||||
if (eeprom.type.address_bits == 7)
|
||||
{
|
||||
eeprom.word_address = 0;
|
||||
eeprom.state = GET_WORD_ADR_7BITS;
|
||||
}
|
||||
else eeprom.state = GET_SLAVE_ADR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void Detect_STOP()
|
||||
{
|
||||
if (eeprom.old_scl && eeprom.scl)
|
||||
{
|
||||
if (!eeprom.old_sda && eeprom.sda)
|
||||
{
|
||||
eeprom.state = STAND_BY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EEPROM_Write(unsigned int address, unsigned int value)
|
||||
{
|
||||
uint16 sram_address = 0;
|
||||
|
||||
/* decode SCL and SDA value */
|
||||
if (eeprom.type.sda_in_adr == address) eeprom.sda = (value >> eeprom.type.sda_in_bit) & 1;
|
||||
else eeprom.sda = eeprom.old_sda;
|
||||
if (eeprom.type.scl_adr == address) eeprom.scl = (value >> eeprom.type.scl_bit) & 1;
|
||||
else eeprom.scl = eeprom.old_scl;
|
||||
|
||||
/* EEPROM current state */
|
||||
switch (eeprom.state)
|
||||
{
|
||||
/* Standby Mode */
|
||||
case STAND_BY:
|
||||
Detect_START();
|
||||
Detect_STOP();
|
||||
break;
|
||||
|
||||
|
||||
/* Suspended Mode */
|
||||
case WAIT_STOP:
|
||||
Detect_STOP();
|
||||
break;
|
||||
|
||||
|
||||
/* Get Word Address 7 bits: MODE-1 only (24C01)
|
||||
* and R/W bit
|
||||
*/
|
||||
case GET_WORD_ADR_7BITS:
|
||||
Detect_START();
|
||||
Detect_STOP();
|
||||
|
||||
/* look for SCL LOW to HIGH transition */
|
||||
if (!eeprom.old_scl && eeprom.scl)
|
||||
{
|
||||
if (eeprom.cycles == 0) eeprom.cycles ++;
|
||||
}
|
||||
|
||||
|
||||
/* look for SCL HIGH to LOW transition */
|
||||
if (eeprom.old_scl && !eeprom.scl && (eeprom.cycles > 0))
|
||||
{
|
||||
if (eeprom.cycles < 8) eeprom.word_address |= (eeprom.old_sda << (7 - eeprom.cycles));
|
||||
else if (eeprom.cycles == 8) eeprom.rw = eeprom.old_sda;
|
||||
else
|
||||
{ /* ACK CYCLE */
|
||||
eeprom.cycles = 0;
|
||||
eeprom.word_address &= eeprom.type.size_mask;
|
||||
eeprom.state = eeprom.rw ? READ_DATA : WRITE_DATA;
|
||||
}
|
||||
|
||||
eeprom.cycles ++;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/* Get Slave Address (3bits) : MODE-2 & MODE-3 only (24C01 - 24C512) (0-3bits, depending on the array size)
|
||||
* or/and Word Address MSB: MODE-2 only (24C04 - 24C16) (0-3bits, depending on the array size)
|
||||
* and R/W bit
|
||||
*/
|
||||
case GET_SLAVE_ADR:
|
||||
|
||||
Detect_START();
|
||||
Detect_STOP();
|
||||
|
||||
/* look for SCL LOW to HIGH transition */
|
||||
if (!eeprom.old_scl && eeprom.scl)
|
||||
{
|
||||
if (eeprom.cycles == 0) eeprom.cycles ++;
|
||||
}
|
||||
|
||||
/* look for SCL HIGH to LOW transition */
|
||||
if (eeprom.old_scl && !eeprom.scl && (eeprom.cycles > 0))
|
||||
{
|
||||
if ((eeprom.cycles > 4) && (eeprom.cycles <8))
|
||||
{
|
||||
if ((eeprom.type.address_bits == 16) ||
|
||||
(eeprom.type.size_mask < (1 << (15 - eeprom.cycles))))
|
||||
{
|
||||
/* this is a SLAVE ADDRESS bit */
|
||||
eeprom.slave_mask |= (eeprom.old_sda << (7 - eeprom.cycles));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this is a WORD ADDRESS high bit */
|
||||
if (eeprom.old_sda) eeprom.word_address |= (1 << (15 - eeprom.cycles));
|
||||
else eeprom.word_address &= ~(1 << (15 - eeprom.cycles));
|
||||
}
|
||||
}
|
||||
else if (eeprom.cycles == 8) eeprom.rw = eeprom.old_sda;
|
||||
else if (eeprom.cycles > 8)
|
||||
{
|
||||
/* ACK CYCLE */
|
||||
eeprom.cycles = 0;
|
||||
if (eeprom.type.address_bits == 16)
|
||||
{
|
||||
/* two ADDRESS bytes */
|
||||
eeprom.state = eeprom.rw ? READ_DATA : GET_WORD_ADR_HIGH;
|
||||
eeprom.slave_mask <<= 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* one ADDRESS byte */
|
||||
eeprom.state = eeprom.rw ? READ_DATA : GET_WORD_ADR_LOW;
|
||||
eeprom.slave_mask <<= 8;
|
||||
}
|
||||
}
|
||||
|
||||
eeprom.cycles ++;
|
||||
}
|
||||
break;
|
||||
|
||||
/* Get Word Address MSB (4-8bits depending on the array size)
|
||||
* MODE-3 only (24C32 - 24C512)
|
||||
*/
|
||||
case GET_WORD_ADR_HIGH:
|
||||
|
||||
Detect_START();
|
||||
Detect_STOP();
|
||||
|
||||
/* look for SCL HIGH to LOW transition */
|
||||
if (eeprom.old_scl && !eeprom.scl)
|
||||
{
|
||||
if (eeprom.cycles < 9)
|
||||
{
|
||||
if ((eeprom.type.size_mask + 1) < (1 << (17 - eeprom.cycles)))
|
||||
{
|
||||
/* ignored bit: slave mask should be right-shifted by one */
|
||||
eeprom.slave_mask >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this is a WORD ADDRESS high bit */
|
||||
if (eeprom.old_sda) eeprom.word_address |= (1 << (16 - eeprom.cycles));
|
||||
else eeprom.word_address &= ~(1 << (16 - eeprom.cycles));
|
||||
}
|
||||
|
||||
eeprom.cycles ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ACK CYCLE */
|
||||
eeprom.cycles = 1;
|
||||
eeprom.state = GET_WORD_ADR_LOW;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/* Get Word Address LSB: 7bits (24C01) or 8bits (24C02-24C512)
|
||||
* MODE-2 and MODE-3 only (24C01 - 24C512)
|
||||
*/
|
||||
case GET_WORD_ADR_LOW:
|
||||
|
||||
Detect_START();
|
||||
Detect_STOP();
|
||||
|
||||
/* look for SCL HIGH to LOW transition */
|
||||
if (eeprom.old_scl && !eeprom.scl)
|
||||
{
|
||||
if (eeprom.cycles < 9)
|
||||
{
|
||||
if ((eeprom.type.size_mask + 1) < (1 << (9 - eeprom.cycles)))
|
||||
{
|
||||
/* ignored bit (X24C01): slave mask should be right-shifted by one */
|
||||
eeprom.slave_mask >>= 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* this is a WORD ADDRESS high bit */
|
||||
if (eeprom.old_sda) eeprom.word_address |= (1 << (8 - eeprom.cycles));
|
||||
else eeprom.word_address &= ~(1 << (8 - eeprom.cycles));
|
||||
}
|
||||
|
||||
eeprom.cycles ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* ACK CYCLE */
|
||||
eeprom.cycles = 1;
|
||||
eeprom.word_address &= eeprom.type.size_mask;
|
||||
eeprom.state = WRITE_DATA;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/*
|
||||
* Read Cycle
|
||||
*/
|
||||
case READ_DATA:
|
||||
|
||||
Detect_START();
|
||||
Detect_STOP();
|
||||
|
||||
/* look for SCL HIGH to LOW transition */
|
||||
if (eeprom.old_scl && !eeprom.scl)
|
||||
{
|
||||
if (eeprom.cycles < 9) eeprom.cycles ++;
|
||||
else
|
||||
{
|
||||
eeprom.cycles = 1;
|
||||
|
||||
/* ACK not received */
|
||||
if (eeprom.old_sda) eeprom.state = WAIT_STOP;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
/*
|
||||
* Write Cycle
|
||||
*/
|
||||
case WRITE_DATA:
|
||||
|
||||
Detect_START();
|
||||
Detect_STOP();
|
||||
|
||||
/* look for SCL HIGH to LOW transition */
|
||||
if (eeprom.old_scl && !eeprom.scl)
|
||||
{
|
||||
if (eeprom.cycles < 9)
|
||||
{
|
||||
/* Write DATA bits (max 64kBytes) */
|
||||
sram_address = (eeprom.slave_mask | eeprom.word_address) & 0xFFFF;
|
||||
if (eeprom.old_sda) sram.sram[sram_address] |= (1 << (8 - eeprom.cycles));
|
||||
else sram.sram[sram_address] &= ~(1 << (8 - eeprom.cycles));
|
||||
|
||||
if (eeprom.cycles == 8)
|
||||
{
|
||||
/* WORD ADDRESS is incremented (roll up at maximum pagesize) */
|
||||
eeprom.word_address = (eeprom.word_address & (0xFFFF - eeprom.type.pagewrite_mask)) |
|
||||
((eeprom.word_address + 1) & eeprom.type.pagewrite_mask);
|
||||
}
|
||||
|
||||
eeprom.cycles ++;
|
||||
}
|
||||
else eeprom.cycles = 1; /* ACK cycle */
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
eeprom.old_scl = eeprom.scl;
|
||||
eeprom.old_sda = eeprom.sda;
|
||||
}
|
||||
|
||||
|
||||
unsigned int EEPROM_Read(unsigned int address)
|
||||
{
|
||||
uint16 sram_address;
|
||||
uint8 sda_out = eeprom.sda;
|
||||
|
||||
/* EEPROM state */
|
||||
switch (eeprom.state)
|
||||
{
|
||||
case READ_DATA:
|
||||
if (eeprom.cycles < 9)
|
||||
{
|
||||
/* Return DATA bits (max 64kBytes) */
|
||||
sram_address = (eeprom.slave_mask | eeprom.word_address) & 0xFFFF;
|
||||
sda_out = (sram.sram[sram_address] >> (8 - eeprom.cycles)) & 1;
|
||||
|
||||
if (eeprom.cycles == 8)
|
||||
{
|
||||
/* WORD ADDRESS is incremented (roll up at maximum array size) */
|
||||
eeprom.word_address ++;
|
||||
eeprom.word_address &= eeprom.type.size_mask;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GET_WORD_ADR_7BITS:
|
||||
case GET_SLAVE_ADR:
|
||||
case GET_WORD_ADR_HIGH:
|
||||
case GET_WORD_ADR_LOW:
|
||||
case WRITE_DATA:
|
||||
if (eeprom.cycles == 9) sda_out = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (address == eeprom.type.sda_out_adr) return (sda_out << eeprom.type.sda_out_bit);
|
||||
else return 0;
|
||||
}
|
64
source/eeprom.h
Normal file
64
source/eeprom.h
Normal file
@ -0,0 +1,64 @@
|
||||
/* this defines the type of EEPROM inside the game cartridge as Backup RAM
|
||||
* Here are some notes from 8BitWizard (http://www.spritesmind.net/_GenDev/forum):
|
||||
*
|
||||
* Mode 1 (7-bit) - the chip takes a single byte with a 7-bit memory address and a R/W bit (24C01)
|
||||
* Mode 2 (8-bit) - the chip takes a 7-bit device address and R/W bit followed by an 8-bit memory address;
|
||||
* the device address may contain up to three more memory address bits (24C01 - 24C16).
|
||||
* You can also string eight 24C01, four 24C02, two 24C08, or various combinations, set their address config lines correctly,
|
||||
* and the result appears exactly the same as a 24C16
|
||||
* Mode 3 (16-bit) - the chip takes a 7-bit device address and R/W bit followed by a 16-bit memory address (24C32 and larger)
|
||||
*
|
||||
* Also, while most 24Cxx are addressed at 200000-2FFFFF, I have found two different ways of mapping the control lines.
|
||||
* EA uses SDA on D7 (read/write) and SCL on D6 (write only), and I have found boards using different mapping (I think Accolade)
|
||||
* which uses D1-read=SDA, D0-write=SDA, D1-write=SCL. Accolade also has a custom-chip mapper which may even use a third method.
|
||||
*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 address_bits; /* number of bits needed to address the array: 7, 8 or 16 */
|
||||
uint16 size_mask; /* size of the array (in bytes) - 1 */
|
||||
uint16 pagewrite_mask; /* maximal number of bytes that can be written in a single write cycle - 1*/
|
||||
uint32 sda_in_adr; /* 68k address used by SDA_IN signal */
|
||||
uint32 sda_out_adr; /* 68k address used by SDA_OUT signal */
|
||||
uint32 scl_adr; /* address used by SCL signal */
|
||||
uint8 sda_in_bit; /* position of the SDA_IN bit */
|
||||
uint8 sda_out_bit; /* position of the SDA_OUT bit */
|
||||
uint8 scl_bit; /* position of the SCL bit */
|
||||
|
||||
} T_EEPROM_TYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STAND_BY = 0,
|
||||
WAIT_STOP,
|
||||
GET_SLAVE_ADR,
|
||||
GET_WORD_ADR_7BITS,
|
||||
GET_WORD_ADR_HIGH,
|
||||
GET_WORD_ADR_LOW,
|
||||
WRITE_DATA,
|
||||
READ_DATA,
|
||||
|
||||
} T_EEPROM_STATE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 sda;
|
||||
uint8 scl;
|
||||
uint8 old_sda;
|
||||
uint8 old_scl;
|
||||
uint8 cycles;
|
||||
uint8 rw;
|
||||
uint16 slave_mask;
|
||||
uint16 word_address;
|
||||
T_EEPROM_STATE state;
|
||||
T_EEPROM_TYPE type;
|
||||
} T_EEPROM;
|
||||
|
||||
/* global variables */
|
||||
extern T_EEPROM eeprom;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void EEPROM_Init();
|
||||
extern void EEPROM_Write(unsigned int address, unsigned int value);
|
||||
extern unsigned int EEPROM_Read(unsigned int address);
|
||||
|
184
source/genesis.c
Normal file
184
source/genesis.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
uint8 *cart_rom; /* cart_rom NEED to be previously dynamically allocated */
|
||||
uint8 work_ram[0x10000]; /* 68K work RAM */
|
||||
uint8 zram[0x2000]; /* Z80 work RAM */
|
||||
uint8 zbusreq; /* /BUSREQ from Z80 */
|
||||
uint8 zreset; /* /RESET to Z80 */
|
||||
uint8 zbusack; /* /BUSACK to Z80 */
|
||||
uint8 zirq; /* /IRQ to Z80 */
|
||||
uint32 zbank; /* Address of Z80 bank window */
|
||||
uint8 gen_running;
|
||||
uint32 lastbusreqcnt;
|
||||
uint8 lastbusack;
|
||||
uint32 genromsize;
|
||||
|
||||
static int cpu_sync[512]; /* Z80-68K cycles synchronization table */
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
void bswap(uint8 *mem, int length)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < length; i += 2)
|
||||
{
|
||||
uint8 temp = mem[i+0];
|
||||
mem[i+0] = mem[i+1];
|
||||
mem[i+1] = temp;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* Init, reset, shutdown functions */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
void gen_init (void)
|
||||
{
|
||||
int i;
|
||||
#ifdef LSB_FIRST
|
||||
bswap(cart_rom, genromsize);
|
||||
#endif
|
||||
#ifdef NGC
|
||||
ShadowROM ();
|
||||
#else
|
||||
memcpy(shadow_rom,cart_rom,genromsize);
|
||||
#endif
|
||||
m68k_set_cpu_type (M68K_CPU_TYPE_68000);
|
||||
m68k_pulse_reset ();
|
||||
gen_running = 1;
|
||||
for (i=0; i<512; i++) cpu_sync[i] = (int)(((double)i * 7.0) / 15.0);
|
||||
}
|
||||
|
||||
void gen_reset (void)
|
||||
{
|
||||
/* Clear RAM */
|
||||
memset (work_ram, 0, sizeof (work_ram));
|
||||
memset (zram, 0, sizeof (zram));
|
||||
gen_running = 1;
|
||||
zreset = 0; /* Z80 is reset */
|
||||
zbusreq = 0; /* Z80 has control of the Z bus */
|
||||
zbusack = 1; /* Z80 is busy using the Z bus */
|
||||
zbank = 0; /* Assume default bank is 000000-007FFF */
|
||||
zirq = 0; /* No interrupts occuring */
|
||||
lastbusreqcnt = 0;
|
||||
lastbusack = 1;
|
||||
|
||||
/* Reset the 68000 emulator */
|
||||
m68k_pulse_reset ();
|
||||
z80_reset (0);
|
||||
z80_set_irq_callback (z80_irq_callback);
|
||||
}
|
||||
|
||||
void gen_shutdown (void)
|
||||
{
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------
|
||||
Bus controller chip functions
|
||||
-----------------------------------------------------------------------*/
|
||||
int gen_busack_r (void)
|
||||
{
|
||||
if (zbusack == 0)
|
||||
{
|
||||
if ((count_m68k + m68k_cycles_run() - lastbusreqcnt) > 16)
|
||||
return 0; /* bus taken */
|
||||
else return (lastbusack&1);
|
||||
}
|
||||
else return 1;
|
||||
}
|
||||
|
||||
void gen_busreq_w (int state)
|
||||
{
|
||||
int z80_cycles_to_run;
|
||||
|
||||
input_raz ();
|
||||
|
||||
if (state == 1)
|
||||
{
|
||||
/* Bus Request */
|
||||
lastbusreqcnt = count_m68k + m68k_cycles_run();
|
||||
lastbusack = zbusack;
|
||||
if (zbusreq == 0)
|
||||
{
|
||||
/* Z80 stopped */
|
||||
/* z80 was ON during the last 68k cycles */
|
||||
/* we execute the appropriate number of z80 cycles */
|
||||
z80_cycles_to_run = aim_z80 - cpu_sync[aim_m68k - count_m68k -m68k_cycles_run()];
|
||||
if (z80_cycles_to_run > 0) z80_run(z80_cycles_to_run);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Bus released */
|
||||
if (zbusreq == 1)
|
||||
{
|
||||
/* Z80 started */
|
||||
/* z80 was OFF during the last 68k cycles */
|
||||
/* we burn the appropriate number of z80 cycles */
|
||||
z80_cycles_to_run = aim_z80 - cpu_sync[aim_m68k - count_m68k - m68k_cycles_run()];
|
||||
if (z80_cycles_to_run > 0) count_z80 = z80_cycles_to_run;
|
||||
}
|
||||
}
|
||||
zbusreq = (state & 1);
|
||||
zbusack = 1 ^ (zbusreq & zreset);
|
||||
}
|
||||
|
||||
void gen_reset_w (int state)
|
||||
{
|
||||
zreset = (state & 1);
|
||||
zbusack = 1 ^ (zbusreq & zreset);
|
||||
|
||||
if (zreset == 0)
|
||||
{
|
||||
lastbusreqcnt = 0;
|
||||
lastbusack = 1;
|
||||
fm_reset();
|
||||
z80_reset (0);
|
||||
z80_set_irq_callback (z80_irq_callback);
|
||||
}
|
||||
}
|
||||
|
||||
void gen_bank_w (int state)
|
||||
{
|
||||
zbank = ((zbank >> 1) | ((state & 1) << 23)) & 0xFF8000;
|
||||
}
|
||||
|
||||
int z80_irq_callback (int param)
|
||||
{
|
||||
zirq = 0;
|
||||
z80_set_irq_line (0, CLEAR_LINE);
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
int vdp_int_ack_callback (int int_level)
|
||||
{
|
||||
switch (int_level)
|
||||
{
|
||||
case 4:
|
||||
hint_pending = 0;
|
||||
vint_pending = 0;
|
||||
break;
|
||||
case 6:
|
||||
vint_pending = 0;
|
||||
break;
|
||||
}
|
||||
return M68K_INT_ACK_AUTOVECTOR;
|
||||
}
|
32
source/genesis.h
Normal file
32
source/genesis.h
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
#ifndef _GENESIS_H_
|
||||
#define _GENESIS_H_
|
||||
|
||||
/* Global variables */
|
||||
extern uint8 *cart_rom;
|
||||
extern uint8 work_ram[0x10000];
|
||||
extern uint8 zram[0x2000];
|
||||
extern uint8 zbusreq;
|
||||
extern uint8 zbusack;
|
||||
extern uint8 zreset;
|
||||
extern uint8 zirq;
|
||||
extern uint32 zbank;
|
||||
extern uint8 gen_running;
|
||||
extern uint32 lastbusreqcnt;
|
||||
extern uint8 lastbusack;
|
||||
extern uint32 genromsize;
|
||||
|
||||
/* Function prototypes */
|
||||
void gen_init(void);
|
||||
void gen_reset(void);
|
||||
void gen_shutdown(void);
|
||||
int gen_busack_r(void);
|
||||
void gen_busreq_w(int state);
|
||||
void gen_reset_w(int state);
|
||||
void gen_bank_w(int state);
|
||||
void bswap(uint8 *mem, int length);
|
||||
int z80_irq_callback(int param);
|
||||
void m68k_irq_ack_callback(int int_level);
|
||||
|
||||
#endif /* _GEN_H_ */
|
||||
|
440
source/hvc.h
Normal file
440
source/hvc.h
Normal file
@ -0,0 +1,440 @@
|
||||
|
||||
#ifndef _HVC_H_
|
||||
#define _HVC_H_
|
||||
|
||||
/* V counter values for NTSC 192-line display */
|
||||
uint8 vc_ntsc_192[262] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
|
||||
0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
/* V counter values for NTSC 224-line display */
|
||||
uint16 vc_ntsc_224[262] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
|
||||
0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
/* V counter values for NTSC 240-line display */
|
||||
uint8 vc_ntsc_240[262] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05
|
||||
};
|
||||
|
||||
/* V counter values for PAL 192-line display */
|
||||
uint8 vc_pal_192[313] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2,
|
||||
0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
/* V counter values for PAL 224-line display */
|
||||
uint16 vc_pal_224[313] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
|
||||
0x100, 0x101, 0x102,
|
||||
0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};
|
||||
|
||||
/* V counter values for PAL 240-line display */
|
||||
uint16 vc_pal_240[313] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
|
||||
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
|
||||
0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
|
||||
0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, 0x109, 0x10A,
|
||||
0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
|
||||
0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
|
||||
};
|
||||
|
||||
/*
|
||||
VDP timing for an NTSC Genesis in display mode 5.
|
||||
Version 0.4 (11/29/00)
|
||||
|
||||
by Charles MacDonald
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Unpublished work Copyright 2000 Charles MacDonald
|
||||
|
||||
Description 32-cell 40-cell
|
||||
----------------------------------------------------------------------------
|
||||
Range 00-93, E9-FF 00-B6, E4-FF
|
||||
Display area 00-7F 00-9F
|
||||
V counter increment 84, 85 A4, A5
|
||||
V-blanking in 86, 87 A7, A8
|
||||
V-blanking out 86, 87 A7, A8
|
||||
H-blanking in 93, E9 B2, E4
|
||||
H-blanking out 06, 07 06, 07
|
||||
|
||||
Comma seperated values show the H counter value before an event occurs,
|
||||
and then the H counter value immediately after.
|
||||
|
||||
These values shouldn't be considered 100% accurate, they are probably
|
||||
off by one or two.
|
||||
|
||||
Each H counter unit is equivalent to two pixels.
|
||||
|
||||
The gaps at 93-E9 and B6-E4 are where the H counter 'jumps' ahead.
|
||||
The H counter will never actually be set to the values 94-E8 or B7-E3.
|
||||
Perhaps this is the horizontal retrace period.
|
||||
|
||||
Interestingly enough, the timing values for the 32-cell display mode
|
||||
are identical to that of the SMS.
|
||||
|
||||
It would appear that in 40-cell mode, the horizontal blanking period
|
||||
is shorter as the active display period takes more time.
|
||||
|
||||
The V-blanking flag can also be forcibly set by disabling the display
|
||||
through bit 6 of register #1.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
uint8 cycle2hc32[488] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x05,
|
||||
0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A,
|
||||
0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x10, 0x10,
|
||||
0x10, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x15, 0x16,
|
||||
0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, 0x1B,
|
||||
0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21,
|
||||
0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26, 0x26,
|
||||
0x27, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2A, 0x2A, 0x2A, 0x2B, 0x2B, 0x2B, 0x2C, 0x2C,
|
||||
0x2C, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x2F, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32,
|
||||
0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x36, 0x37, 0x37, 0x37,
|
||||
0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3A, 0x3B, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D,
|
||||
0x3D, 0x3E, 0x3E, 0x3E, 0x3F, 0x3F, 0x3F, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41, 0x42, 0x42, 0x42,
|
||||
0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x47, 0x48, 0x48,
|
||||
0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B, 0x4B, 0x4C, 0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4E,
|
||||
0x4E, 0x4E, 0x4F, 0x4F, 0x4F, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53,
|
||||
0x54, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59,
|
||||
0x59, 0x5A, 0x5A, 0x5A, 0x5B, 0x5B, 0x5B, 0x5C, 0x5C, 0x5C, 0x5D, 0x5D, 0x5E, 0x5E, 0x5E, 0x5F,
|
||||
0x5F, 0x5F, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x63, 0x64, 0x64,
|
||||
0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6A,
|
||||
0x6A, 0x6A, 0x6B, 0x6B, 0x6C, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, 0x6E, 0x6E, 0x6E, 0x6F, 0x6F, 0x6F,
|
||||
0x70, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75,
|
||||
0x75, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7B,
|
||||
0x7B, 0x7B, 0x7C, 0x7C, 0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7E, 0x7F, 0x7F, 0x80, 0x80, 0x80,
|
||||
0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x83, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86,
|
||||
0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8A, 0x8A, 0x8A, 0x8B, 0x8B, 0x8B,
|
||||
0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8E, 0x8F, 0x8F, 0x8F, 0x90, 0x90, 0x90, 0x91, 0x91,
|
||||
0x91, 0x92, 0x92, 0x92, 0x93, 0x93,
|
||||
0xE9, 0xE9, 0xE9, 0xEA, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEC,
|
||||
0xEC, 0xEC, 0xED, 0xED, 0xED, 0xEE, 0xEE, 0xEE, 0xEF, 0xEF, 0xF0, 0xF0, 0xF0, 0xF1, 0xF1, 0xF1,
|
||||
0xF2, 0xF2, 0xF2, 0xF3, 0xF3, 0xF3, 0xF4, 0xF4, 0xF4, 0xF5, 0xF5, 0xF6, 0xF6, 0xF6, 0xF7, 0xF7,
|
||||
0xF7, 0xF8, 0xF8, 0xF8, 0xF9, 0xF9, 0xF9, 0xFA, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC, 0xFC, 0xFD,
|
||||
0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF
|
||||
};
|
||||
*/
|
||||
|
||||
uint8 cycle2hc32[489] = {
|
||||
0xe8, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xed,
|
||||
0xed, 0xed, 0xee, 0xee, 0xee, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2,
|
||||
0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf8, 0xf8,
|
||||
0xf8, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd,
|
||||
0xfe, 0xfe, 0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03,
|
||||
0x03, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09,
|
||||
0x09, 0x09, 0x0a, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e,
|
||||
0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14,
|
||||
0x14, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19,
|
||||
0x1a, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f,
|
||||
0x1f, 0x20, 0x20, 0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24,
|
||||
0x25, 0x25, 0x26, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a,
|
||||
0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30,
|
||||
0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35,
|
||||
0x36, 0x36, 0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b,
|
||||
0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40,
|
||||
0x41, 0x41, 0x41, 0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46, 0x46,
|
||||
0x46, 0x47, 0x47, 0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b,
|
||||
0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x51, 0x51,
|
||||
0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57,
|
||||
0x57, 0x57, 0x58, 0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c,
|
||||
0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62,
|
||||
0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67,
|
||||
0x68, 0x68, 0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d,
|
||||
0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72,
|
||||
0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78,
|
||||
0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e,
|
||||
0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x83,
|
||||
0x84, 0x84, 0x84, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89,
|
||||
0x89, 0x89, 0x8a, 0x8a, 0x8b, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e,
|
||||
0x8f, 0x8f, 0x8f, 0x90, 0x90, 0x90, 0x91, 0x91, 0x92
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
uint8 cycle2hc32[489] = {
|
||||
0xe9, 0xe9, 0xe9, 0xea, 0xea, 0xea, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xec, 0xed, 0xed, 0xed, 0xee,
|
||||
0xee, 0xee, 0xef, 0xef, 0xef, 0xf0, 0xf0, 0xf1, 0xf1, 0xf1, 0xf2, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3,
|
||||
0xf4, 0xf4, 0xf4, 0xf5, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf8, 0xf8, 0xf9, 0xf9,
|
||||
0xf9, 0xfa, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfe, 0xfe, 0xfe,
|
||||
0xff, 0xff, 0xff, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04,
|
||||
0x04, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a,
|
||||
0x0a, 0x0a, 0x0b, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c, 0x0d, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f,
|
||||
0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14, 0x14, 0x14, 0x15,
|
||||
0x15, 0x15, 0x16, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1a, 0x1a, 0x1a,
|
||||
0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x20, 0x20,
|
||||
0x20, 0x21, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x25,
|
||||
0x26, 0x26, 0x27, 0x27, 0x27, 0x28, 0x28, 0x28, 0x29, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b,
|
||||
0x2b, 0x2c, 0x2c, 0x2c, 0x2d, 0x2d, 0x2d, 0x2e, 0x2e, 0x2f, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x31,
|
||||
0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x35, 0x36, 0x36,
|
||||
0x37, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3b, 0x3c,
|
||||
0x3c, 0x3c, 0x3d, 0x3d, 0x3e, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x41,
|
||||
0x42, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47,
|
||||
0x47, 0x48, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4b, 0x4c, 0x4c, 0x4c,
|
||||
0x4d, 0x4d, 0x4e, 0x4e, 0x4e, 0x4f, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x51, 0x51, 0x51, 0x52, 0x52,
|
||||
0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x57, 0x58,
|
||||
0x58, 0x58, 0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, 0x5d, 0x5d, 0x5d,
|
||||
0x5e, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x60, 0x61, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63,
|
||||
0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x68,
|
||||
0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6d, 0x6d, 0x6d, 0x6e, 0x6e,
|
||||
0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70, 0x70, 0x71, 0x71, 0x71, 0x72, 0x72, 0x72, 0x73, 0x73, 0x73,
|
||||
0x74, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79,
|
||||
0x79, 0x7a, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f,
|
||||
0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x83, 0x83, 0x84, 0x84, 0x84,
|
||||
0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a,
|
||||
0x8a, 0x8a, 0x8b, 0x8b, 0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x8f,
|
||||
0x90, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92, 0x92, 0x93
|
||||
};*/
|
||||
|
||||
|
||||
/*
|
||||
uint8 cycle2hc40[488] = {
|
||||
0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x06,
|
||||
0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0D,
|
||||
0x0D, 0x0E, 0x0E, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x13, 0x13, 0x13, 0x14,
|
||||
0x14, 0x15, 0x15, 0x16, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x19, 0x1A, 0x1A, 0x1B,
|
||||
0x1B, 0x1C, 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, 0x20, 0x20, 0x20, 0x21, 0x21, 0x22,
|
||||
0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29,
|
||||
0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30,
|
||||
0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x33, 0x34, 0x34, 0x35, 0x35, 0x36, 0x36, 0x36,
|
||||
0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x39, 0x3A, 0x3A, 0x3B, 0x3B, 0x3C, 0x3C, 0x3D, 0x3D, 0x3D,
|
||||
0x3E, 0x3E, 0x3F, 0x3F, 0x40, 0x40, 0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43, 0x44, 0x44,
|
||||
0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49, 0x4A, 0x4A, 0x4A, 0x4B, 0x4B,
|
||||
0x4C, 0x4C, 0x4D, 0x4D, 0x4D, 0x4E, 0x4E, 0x4F, 0x4F, 0x50, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52,
|
||||
0x53, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58, 0x59, 0x59,
|
||||
0x5A, 0x5A, 0x5A, 0x5B, 0x5B, 0x5C, 0x5C, 0x5D, 0x5D, 0x5D, 0x5E, 0x5E, 0x5F, 0x5F, 0x60, 0x60,
|
||||
0x60, 0x61, 0x61, 0x62, 0x62, 0x63, 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67,
|
||||
0x67, 0x68, 0x68, 0x69, 0x69, 0x6A, 0x6A, 0x6A, 0x6B, 0x6B, 0x6C, 0x6C, 0x6D, 0x6D, 0x6D, 0x6E,
|
||||
0x6E, 0x6F, 0x6F, 0x70, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x73, 0x74, 0x74, 0x75,
|
||||
0x75, 0x76, 0x76, 0x77, 0x77, 0x77, 0x78, 0x78, 0x79, 0x79, 0x7A, 0x7A, 0x7A, 0x7B, 0x7B, 0x7C,
|
||||
0x7C, 0x7D, 0x7D, 0x7D, 0x7E, 0x7E, 0x7F, 0x7F, 0x80, 0x80, 0x80, 0x81, 0x81, 0x82, 0x82, 0x83,
|
||||
0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89, 0x8A,
|
||||
0x8A, 0x8A, 0x8B, 0x8B, 0x8C, 0x8C, 0x8D, 0x8D, 0x8D, 0x8E, 0x8E, 0x8F, 0x8F, 0x90, 0x90, 0x90,
|
||||
0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x94, 0x94, 0x94, 0x95, 0x95, 0x96, 0x96, 0x97, 0x97, 0x97,
|
||||
0x98, 0x98, 0x99, 0x99, 0x9A, 0x9A, 0x9A, 0x9B, 0x9B, 0x9C, 0x9C, 0x9D, 0x9D, 0x9D, 0x9E, 0x9E,
|
||||
0x9F, 0x9F, 0xA0, 0xA0, 0xA1, 0xA1, 0xA1, 0xA2, 0xA2, 0xA3, 0xA3, 0xA4, 0xA4, 0xA4, 0xA5, 0xA5,
|
||||
0xA6, 0xA6, 0xA7, 0xA7, 0xA7, 0xA8, 0xA8, 0xA9, 0xA9, 0xAA, 0xAA, 0xAA, 0xAB, 0xAB, 0xAC, 0xAC,
|
||||
0xAD, 0xAD, 0xAD, 0xAE, 0xAE, 0xAF, 0xAF, 0xB0, 0xB0, 0xB1, 0xB1, 0xB1, 0xB2, 0xB2, 0xB3, 0xB3,
|
||||
0xB4, 0xB4, 0xB4, 0xB5, 0xB5, 0xB6, 0xB6,
|
||||
0xE4, 0xE4, 0xE4, 0xE5, 0xE5, 0xE6, 0xE6, 0xE7, 0xE7,
|
||||
0xE7, 0xE8, 0xE8, 0xE9, 0xE9, 0xEA, 0xEA, 0xEB, 0xEB, 0xEB, 0xEC, 0xEC, 0xED, 0xED, 0xEE, 0xEE,
|
||||
0xEE, 0xEF, 0xEF, 0xF0, 0xF0, 0xF1, 0xF1, 0xF1, 0xF2, 0xF2, 0xF3, 0xF3, 0xF4, 0xF4, 0xF4, 0xF5,
|
||||
0xF5, 0xF6, 0xF6, 0xF7, 0xF7, 0xF7, 0xF8, 0xF8, 0xF9, 0xF9, 0xFA, 0xFA, 0xFB, 0xFB, 0xFB, 0xFC,
|
||||
0xFC, 0xFD, 0xFD, 0xFE, 0xFE, 0xFE, 0xFF, 0xFF
|
||||
};*/
|
||||
|
||||
uint8 cycle2hc40[489] = {
|
||||
0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe6, 0xe6, 0xe7, 0xe7, 0xe7, 0xe8, 0xe8, 0xe9, 0xe9, 0xea, 0xea,
|
||||
0xea, 0xeb, 0xeb, 0xec, 0xec, 0xed, 0xed, 0xed, 0xee, 0xee, 0xef, 0xef, 0xf0, 0xf0, 0xf0, 0xf1,
|
||||
0xf1, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7, 0xf8,
|
||||
0xf8, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfb, 0xfb, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe, 0xff,
|
||||
0xff, 0xff, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x05,
|
||||
0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x09, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, 0x0c,
|
||||
0x0d, 0x0d, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13,
|
||||
0x14, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19, 0x19, 0x1a, 0x1a,
|
||||
0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x20, 0x20, 0x21, 0x21,
|
||||
0x21, 0x22, 0x22, 0x23, 0x23, 0x24, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, 0x27, 0x28,
|
||||
0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2b, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d, 0x2e, 0x2e, 0x2e, 0x2f,
|
||||
0x2f, 0x30, 0x30, 0x31, 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x34, 0x34, 0x35, 0x35, 0x36,
|
||||
0x36, 0x37, 0x37, 0x37, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x3a, 0x3b, 0x3b, 0x3c, 0x3c, 0x3d,
|
||||
0x3d, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x40, 0x40, 0x40, 0x41, 0x41, 0x42, 0x42, 0x43, 0x43, 0x43,
|
||||
0x44, 0x44, 0x45, 0x45, 0x46, 0x46, 0x46, 0x47, 0x47, 0x48, 0x48, 0x49, 0x49, 0x49, 0x4a, 0x4a,
|
||||
0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f, 0x4f, 0x50, 0x50, 0x50, 0x51, 0x51,
|
||||
0x52, 0x52, 0x53, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, 0x56, 0x56, 0x57, 0x57, 0x58, 0x58,
|
||||
0x59, 0x59, 0x59, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c, 0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f,
|
||||
0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63, 0x63, 0x64, 0x64, 0x65, 0x65, 0x65, 0x66,
|
||||
0x66, 0x67, 0x67, 0x68, 0x68, 0x68, 0x69, 0x69, 0x6a, 0x6a, 0x6b, 0x6b, 0x6b, 0x6c, 0x6c, 0x6d,
|
||||
0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x6f, 0x70, 0x70, 0x71, 0x71, 0x72, 0x72, 0x72, 0x73, 0x73, 0x74,
|
||||
0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77, 0x78, 0x78, 0x78, 0x79, 0x79, 0x7a, 0x7a, 0x7b,
|
||||
0x7b, 0x7b, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81,
|
||||
0x82, 0x82, 0x83, 0x83, 0x84, 0x84, 0x84, 0x85, 0x85, 0x86, 0x86, 0x87, 0x87, 0x87, 0x88, 0x88,
|
||||
0x89, 0x89, 0x8a, 0x8a, 0x8a, 0x8b, 0x8b, 0x8c, 0x8c, 0x8d, 0x8d, 0x8d, 0x8e, 0x8e, 0x8f, 0x8f,
|
||||
0x90, 0x90, 0x90, 0x91, 0x91, 0x92, 0x92, 0x93, 0x93, 0x94, 0x94, 0x94, 0x95, 0x95, 0x96, 0x96,
|
||||
0x97, 0x97, 0x97, 0x98, 0x98, 0x99, 0x99, 0x9a, 0x9a, 0x9a, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d,
|
||||
0x9d, 0x9e, 0x9e, 0x9f, 0x9f, 0xa0, 0xa0, 0xa0, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4,
|
||||
0xa4, 0xa5, 0xa5, 0xa6, 0xa6, 0xa6, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xab,
|
||||
0xab, 0xac, 0xac, 0xac, 0xad, 0xad, 0xae, 0xae, 0xaf, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1, 0xb1, 0xb2,
|
||||
0xb2, 0xb2, 0xb3, 0xb3, 0xb4, 0xb4, 0xb5, 0xb5, 0xb6
|
||||
};
|
||||
|
||||
/*
|
||||
uint8 cycle2hc40[489] = {
|
||||
0xe4, 0xe4, 0xe4, 0xe5, 0xe5, 0xe6, 0xe6, 0xe6, 0xe7, 0xe7, 0xe8, 0xe8, 0xe9, 0xe9, 0xe9, 0xea,
|
||||
0xea, 0xeb, 0xeb, 0xeb, 0xec, 0xec, 0xed, 0xed, 0xee, 0xee, 0xee, 0xef, 0xef, 0xf0, 0xf0, 0xf1,
|
||||
0xf1, 0xf1, 0xf2, 0xf2, 0xf3, 0xf3, 0xf3, 0xf4, 0xf4, 0xf5, 0xf5, 0xf6, 0xf6, 0xf6, 0xf7, 0xf7,
|
||||
0xf8, 0xf8, 0xf9, 0xf9, 0xf9, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfc, 0xfc, 0xfd, 0xfd, 0xfe, 0xfe,
|
||||
0xfe, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x04, 0x04, 0x05,
|
||||
0x05, 0x06, 0x06, 0x06, 0x07, 0x07, 0x08, 0x08, 0x08, 0x09, 0x09, 0x0a, 0x0a, 0x0b, 0x0b, 0x0b,
|
||||
0x0c, 0x0c, 0x0d, 0x0d, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x10, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12,
|
||||
0x13, 0x13, 0x13, 0x14, 0x14, 0x15, 0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x18, 0x19,
|
||||
0x19, 0x1a, 0x1a, 0x1b, 0x1b, 0x1b, 0x1c, 0x1c, 0x1d, 0x1d, 0x1d, 0x1e, 0x1e, 0x1f, 0x1f, 0x20,
|
||||
0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x25, 0x26, 0x26,
|
||||
0x27, 0x27, 0x28, 0x28, 0x28, 0x29, 0x29, 0x2a, 0x2a, 0x2a, 0x2b, 0x2b, 0x2c, 0x2c, 0x2d, 0x2d,
|
||||
0x2d, 0x2e, 0x2e, 0x2f, 0x2f, 0x30, 0x30, 0x30, 0x31, 0x31, 0x32, 0x32, 0x32, 0x33, 0x33, 0x34,
|
||||
0x34, 0x35, 0x35, 0x35, 0x36, 0x36, 0x37, 0x37, 0x38, 0x38, 0x38, 0x39, 0x39, 0x3a, 0x3a, 0x3a,
|
||||
0x3b, 0x3b, 0x3c, 0x3c, 0x3d, 0x3d, 0x3d, 0x3e, 0x3e, 0x3f, 0x3f, 0x3f, 0x40, 0x40, 0x41, 0x41,
|
||||
0x42, 0x42, 0x42, 0x43, 0x43, 0x44, 0x44, 0x45, 0x45, 0x45, 0x46, 0x46, 0x47, 0x47, 0x47, 0x48,
|
||||
0x48, 0x49, 0x49, 0x4a, 0x4a, 0x4a, 0x4b, 0x4b, 0x4c, 0x4c, 0x4d, 0x4d, 0x4d, 0x4e, 0x4e, 0x4f,
|
||||
0x4f, 0x4f, 0x50, 0x50, 0x51, 0x51, 0x52, 0x52, 0x52, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x55,
|
||||
0x56, 0x56, 0x57, 0x57, 0x57, 0x58, 0x58, 0x59, 0x59, 0x5a, 0x5a, 0x5a, 0x5b, 0x5b, 0x5c, 0x5c,
|
||||
0x5c, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f, 0x5f, 0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x62, 0x63,
|
||||
0x63, 0x64, 0x64, 0x64, 0x65, 0x65, 0x66, 0x66, 0x67, 0x67, 0x67, 0x68, 0x68, 0x69, 0x69, 0x6a,
|
||||
0x6a, 0x6a, 0x6b, 0x6b, 0x6c, 0x6c, 0x6c, 0x6d, 0x6d, 0x6e, 0x6e, 0x6f, 0x6f, 0x6f, 0x70, 0x70,
|
||||
0x71, 0x71, 0x71, 0x72, 0x72, 0x73, 0x73, 0x74, 0x74, 0x74, 0x75, 0x75, 0x76, 0x76, 0x77, 0x77,
|
||||
0x77, 0x78, 0x78, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b, 0x7b, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7e,
|
||||
0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x82, 0x82, 0x83, 0x83, 0x84, 0x84, 0x84,
|
||||
0x85, 0x85, 0x86, 0x86, 0x86, 0x87, 0x87, 0x88, 0x88, 0x89, 0x89, 0x89, 0x8a, 0x8a, 0x8b, 0x8b,
|
||||
0x8c, 0x8c, 0x8c, 0x8d, 0x8d, 0x8e, 0x8e, 0x8e, 0x8f, 0x8f, 0x90, 0x90, 0x91, 0x91, 0x91, 0x92,
|
||||
0x92, 0x93, 0x93, 0x94, 0x94, 0x94, 0x95, 0x95, 0x96, 0x96, 0x96, 0x97, 0x97, 0x98, 0x98, 0x99,
|
||||
0x99, 0x99, 0x9a, 0x9a, 0x9b, 0x9b, 0x9b, 0x9c, 0x9c, 0x9d, 0x9d, 0x9e, 0x9e, 0x9e, 0x9f, 0x9f,
|
||||
0xa0, 0xa0, 0xa1, 0xa1, 0xa1, 0xa2, 0xa2, 0xa3, 0xa3, 0xa3, 0xa4, 0xa4, 0xa5, 0xa5, 0xa6, 0xa6,
|
||||
0xa6, 0xa7, 0xa7, 0xa8, 0xa8, 0xa9, 0xa9, 0xa9, 0xaa, 0xaa, 0xab, 0xab, 0xab, 0xac, 0xac, 0xad,
|
||||
0xad, 0xae, 0xae, 0xae, 0xaf, 0xaf, 0xb0, 0xb0, 0xb1
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/* H counter values for a 256-pixel wide display (342 pixel max.) */
|
||||
/*uint8 hc_256[171] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93,
|
||||
0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};*/
|
||||
|
||||
/* H counter values for a 320-pixel wide display (422 pixels max.) */
|
||||
/*uint8 hc_320[211] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
|
||||
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
|
||||
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
|
||||
0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
|
||||
0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
|
||||
};*/
|
||||
|
||||
/*uint8 *hc_table[2] = {
|
||||
hc_256,
|
||||
hc_320,
|
||||
};*/
|
||||
|
||||
#endif /* _HVC_H_ */
|
||||
|
508
source/input.c
Normal file
508
source/input.c
Normal file
@ -0,0 +1,508 @@
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
/*
|
||||
NGC port (June 2007): Added various Peripherals emulation (Eke-Eke)
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
t_input input;
|
||||
uint8 current_pad = 0;
|
||||
uint8 j_cart = 0;
|
||||
|
||||
void gamepad_reset(uint8 num);
|
||||
void gamepad_update(uint8 num);
|
||||
void gamepad_raz(uint8 num);
|
||||
void lightgun_update(void);
|
||||
void lightgun_reset(void);
|
||||
void teamplayer_reset(uint8 port);
|
||||
|
||||
/*****************************************************************************
|
||||
* Generic INPUTS Control
|
||||
*
|
||||
*****************************************************************************/
|
||||
void input_reset (int padtype)
|
||||
{
|
||||
uint8 i;
|
||||
|
||||
input.max = 0;
|
||||
for (i=0; i<MAX_DEVICES; i++)
|
||||
{
|
||||
input.dev[i] = NO_DEVICE;
|
||||
input.pad[i] = 0;
|
||||
}
|
||||
|
||||
switch (input.system[0])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
if (input.max++ < MAX_INPUTS) input.dev[0] = padtype;
|
||||
gamepad_reset(0);
|
||||
break;
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (input.max++ < MAX_INPUTS) input.dev[i] = padtype;
|
||||
gamepad_reset(i);
|
||||
}
|
||||
current_pad = 0;
|
||||
break;
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (input.max++ < MAX_INPUTS) input.dev[i] = padtype;
|
||||
}
|
||||
teamplayer_reset(0);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (input.system[1])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
if (input.max++ < MAX_INPUTS) input.dev[4] = padtype;
|
||||
gamepad_reset(4);
|
||||
break;
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
for (i=4; i<8; i++)
|
||||
{
|
||||
if (input.max++ < MAX_INPUTS) input.dev[i] = padtype;
|
||||
}
|
||||
teamplayer_reset(1);
|
||||
break;
|
||||
|
||||
case SYSTEM_MENACER:
|
||||
if (input.max++ < MAX_INPUTS) input.dev[4] = DEVICE_LIGHTGUN;
|
||||
lightgun_reset();
|
||||
break;
|
||||
}
|
||||
|
||||
if (input.max > MAX_INPUTS) input.max = MAX_INPUTS;
|
||||
|
||||
/* J-CART: add two gamepad inputs */
|
||||
if (j_cart)
|
||||
{
|
||||
input.dev[5] = padtype;
|
||||
input.dev[6] = padtype;
|
||||
gamepad_reset(5);
|
||||
gamepad_reset(6);
|
||||
input.max+=2;
|
||||
}
|
||||
}
|
||||
|
||||
void input_update()
|
||||
{
|
||||
uint8 i;
|
||||
switch (input.system[0])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
if (input.dev[0] == DEVICE_6BUTTON) gamepad_update(0);
|
||||
break;
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (input.dev[i] == DEVICE_6BUTTON) gamepad_update(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (input.system[1])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
if (input.dev[4] == DEVICE_6BUTTON) gamepad_update(4);
|
||||
break;
|
||||
|
||||
case SYSTEM_MENACER:
|
||||
lightgun_update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void input_raz()
|
||||
{
|
||||
uint8 i;
|
||||
switch (input.system[0])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
if (input.dev[0] == DEVICE_6BUTTON) gamepad_raz(0);
|
||||
break;
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (input.dev[i] == DEVICE_6BUTTON) gamepad_raz(i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (input.system[1])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
if (input.dev[4] == DEVICE_6BUTTON) gamepad_raz(4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* LIGHTGUN specific functions
|
||||
*
|
||||
*****************************************************************************/
|
||||
struct gun
|
||||
{
|
||||
int16 x;
|
||||
int16 y;
|
||||
} lightgun;
|
||||
|
||||
void lightgun_reset(void)
|
||||
{
|
||||
lightgun.x = bitmap.viewport.w >> 1;
|
||||
lightgun.y = bitmap.viewport.h >> 1;
|
||||
}
|
||||
|
||||
void lightgun_update(void)
|
||||
{
|
||||
if ((v_counter == lightgun.y))
|
||||
{
|
||||
if (reg[0x0B] & 8) m68k_set_irq(2);
|
||||
if (reg[0x00] & 2)
|
||||
{
|
||||
hc_latch = lightgun.x + 166;
|
||||
if (hc_latch >= bitmap.viewport.w + 52) hc_latch -= (bitmap.viewport.w + 52 + 48);
|
||||
hc_latch >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void lightgun_set ()
|
||||
{
|
||||
if ((input.pad[4] & INPUT_RIGHT)) lightgun.x ++;
|
||||
if ((input.pad[4] & INPUT_LEFT)) lightgun.x --;
|
||||
if ((input.pad[4] & INPUT_UP)) lightgun.y --;
|
||||
if ((input.pad[4] & INPUT_DOWN)) lightgun.y ++;
|
||||
|
||||
if (lightgun.x < 0) lightgun.x = 0;
|
||||
else if (lightgun.x > bitmap.viewport.w-34) lightgun.x = bitmap.viewport.w-34;
|
||||
|
||||
if (lightgun.y < 0) lightgun.y = 0;
|
||||
else if (lightgun.y > bitmap.viewport.h-8) lightgun.y = bitmap.viewport.h-8;
|
||||
}
|
||||
|
||||
uint8 lightgun_read (void)
|
||||
{
|
||||
uint8 retval = 0x00;
|
||||
if ((input.pad[4] & INPUT_B)) retval |= 0x01;
|
||||
if ((input.pad[4] & INPUT_A)) retval |= 0x02;
|
||||
if ((input.pad[4] & INPUT_C)) retval |= 0x04;
|
||||
if ((input.pad[4] & INPUT_START)) retval |= 0x08;
|
||||
return (retval & 0x7F);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* GAMEPAD specific functions (2PLAYERS/4WAYPLAY)
|
||||
*
|
||||
*****************************************************************************/
|
||||
struct pad
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
uint8 Delay;
|
||||
} gamepad[MAX_DEVICES];
|
||||
|
||||
void gamepad_reset(uint8 i)
|
||||
{
|
||||
gamepad[i].State = 0x40;
|
||||
if (input.dev[i] == DEVICE_6BUTTON) gamepad_raz(i);
|
||||
}
|
||||
|
||||
void gamepad_raz(uint8 i)
|
||||
{
|
||||
gamepad[i].Counter = 0;
|
||||
gamepad[i].Delay = 0;
|
||||
}
|
||||
|
||||
void gamepad_update(uint8 i)
|
||||
{
|
||||
if (gamepad[i].Delay++ > 25) gamepad_raz(i);
|
||||
}
|
||||
|
||||
uint8 gamepad_read (uint8 i)
|
||||
{
|
||||
int control;
|
||||
unsigned char retval = 0xFF;
|
||||
|
||||
if (input.dev[i] == NO_DEVICE) return 0x7F;
|
||||
|
||||
control = (gamepad[i].State & 0x40) >> 6; /* current TH state */
|
||||
|
||||
if (input.dev[i] == DEVICE_6BUTTON)
|
||||
{
|
||||
control += (gamepad[i].Counter & 3) << 1; /* TH transitions counter */
|
||||
}
|
||||
|
||||
switch (control)
|
||||
{
|
||||
case 1: /*** First High ***/
|
||||
case 3: /*** Second High ***/
|
||||
case 5: /*** Third High ***/
|
||||
|
||||
/* TH = 1 : ?1CBRLDU */
|
||||
if (input.pad[i] & INPUT_C) retval &= ~0x20;
|
||||
if (input.pad[i] & INPUT_B) retval &= ~0x10;
|
||||
if (input.pad[i] & INPUT_UP) retval &= ~0x01;
|
||||
if (input.pad[i] & INPUT_DOWN) retval &= ~0x02;
|
||||
if (input.pad[i] & INPUT_LEFT) retval &= ~0x04;
|
||||
if (input.pad[i] & INPUT_RIGHT) retval &= ~0x08;
|
||||
break;
|
||||
|
||||
case 0: /*** First low ***/
|
||||
case 2: /*** Second low ***/
|
||||
|
||||
/* TH = 0 : ?0SA00DU */
|
||||
if (input.pad[i] & INPUT_A) retval &= ~0x10;
|
||||
if (input.pad[i] & INPUT_START) retval &= ~0x20;
|
||||
if (input.pad[i] & INPUT_UP) retval &= ~0x01;
|
||||
if (input.pad[i] & INPUT_DOWN) retval &= ~0x02;
|
||||
retval &= 0xB3;
|
||||
break;
|
||||
|
||||
/* 6buttons specific (taken from gen-hw.txt) */
|
||||
/* A 6-button gamepad allows the extra buttons to be read based on how */
|
||||
/* many times TH is switched from 1 to 0 (and not 0 to 1). Observe the */
|
||||
/* following sequence */
|
||||
/*
|
||||
TH = 1 : ?1CBRLDU 3-button pad return value
|
||||
TH = 0 : ?0SA00DU 3-button pad return value
|
||||
TH = 1 : ?1CBRLDU 3-button pad return value
|
||||
TH = 0 : ?0SA0000 D3-0 are forced to '0'
|
||||
TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0
|
||||
TH = 0 : ?0SA1111 D3-0 are forced to '1'
|
||||
*/
|
||||
case 4: /*** Third Low ***/
|
||||
|
||||
/* TH = 0 : ?0SA0000 D3-0 are forced to '0'*/
|
||||
if (input.pad[i] & INPUT_A) retval &= ~0x10;
|
||||
if (input.pad[i] & INPUT_START) retval &= ~0x20;
|
||||
retval &= 0xB0;
|
||||
break;
|
||||
|
||||
case 6: /*** Fourth Low ***/
|
||||
|
||||
/* TH = 0 : ?0SA1111 D3-0 are forced to '1'*/
|
||||
if (input.pad[i] & INPUT_A) retval &= ~0x10;
|
||||
if (input.pad[i] & INPUT_START) retval &= ~0x20;
|
||||
retval &= 0xBF;
|
||||
break;
|
||||
|
||||
case 7: /*** Fourth High ***/
|
||||
|
||||
/* TH = 1 : ?1CBMXYZ Extra buttons returned in D3-0*/
|
||||
if (input.pad[i] & INPUT_X) retval &= ~0x04;
|
||||
if (input.pad[i] & INPUT_Y) retval &= ~0x02;
|
||||
if (input.pad[i] & INPUT_Z) retval &= ~0x01;
|
||||
if (input.pad[i] & INPUT_B) retval &= ~0x10;
|
||||
if (input.pad[i] & INPUT_C) retval &= ~0x20;
|
||||
if (input.pad[i] & INPUT_MODE) retval &= ~0x08;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* bit7 is latched*/
|
||||
return (retval&0x7f);
|
||||
}
|
||||
|
||||
void gamepad_write (uint8 i, uint8 data)
|
||||
{
|
||||
if (input.dev[i] == DEVICE_6BUTTON)
|
||||
{
|
||||
/* TH=0 to TH=1 transition */
|
||||
if (!(gamepad[i].State & 0x40) && (data & 0x40))
|
||||
{
|
||||
gamepad[i].Counter++;
|
||||
gamepad[i].Delay = 0;
|
||||
}
|
||||
}
|
||||
|
||||
gamepad[i].State = data;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
* TEAMPLAYER specific functions
|
||||
*
|
||||
*****************************************************************************/
|
||||
struct teamplayer
|
||||
{
|
||||
uint8 State;
|
||||
uint8 Counter;
|
||||
uint8 Table[12];
|
||||
} teamplayer[2];
|
||||
|
||||
void teamplayer_reset(uint8 port)
|
||||
{
|
||||
uint8 i;
|
||||
uint8 index = 0;
|
||||
uint8 pad_input = 0;
|
||||
|
||||
teamplayer[port].State = 0x60; /* TH = 1, TR = 1 */
|
||||
teamplayer[port].Counter = 0;
|
||||
|
||||
/* this table determines which gamepad input should be returned during acquisition sequence
|
||||
index = teamplayer read table index: 0=1st read, 1=2nd read, ...
|
||||
pad_input = gamepad input 0-14: 0=P1_DIR, 1=P1_SABC, 2=P1_MXYZ, 4=P2_DIR, 5=P2_SABC, ...
|
||||
*/
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (input.dev[(4*port) + i] == DEVICE_3BUTTON)
|
||||
{
|
||||
teamplayer[port].Table[index++] = pad_input;
|
||||
teamplayer[port].Table[index++] = pad_input + 1;
|
||||
}
|
||||
else if (input.dev[(4*port) + i] == DEVICE_6BUTTON)
|
||||
{
|
||||
teamplayer[port].Table[index++] = pad_input;
|
||||
teamplayer[port].Table[index++] = pad_input + 1;
|
||||
teamplayer[port].Table[index++] = pad_input + 2;
|
||||
}
|
||||
pad_input += 4;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* SEGA teamplayer returns successively:
|
||||
- PAD1 inputs
|
||||
- PAD2 inputs
|
||||
- PAD3 inputs
|
||||
- PAD4 inputs
|
||||
|
||||
Each PAD inputs is obtained through 2 or 3 sequential reads:
|
||||
1/ DIR buttons
|
||||
2/ START,A,C,B buttons
|
||||
3/ MODE, X,Y,Z buttons (6Button only !)
|
||||
*/
|
||||
uint8 teamplayer_read(uint8 port, uint8 index)
|
||||
{
|
||||
uint8 retval = 0x7F;
|
||||
uint8 pad_input = teamplayer[port].Table[index] & 0x03;
|
||||
uint8 pad_num = (4 * port) + ((teamplayer[port].Table[index] >> 2) & 0x03);
|
||||
|
||||
switch (pad_input)
|
||||
{
|
||||
case 0:
|
||||
/* Directions Buttons */
|
||||
if (input.pad[pad_num] & INPUT_UP) retval &= ~0x01;
|
||||
if (input.pad[pad_num] & INPUT_DOWN) retval &= ~0x02;
|
||||
if (input.pad[pad_num] & INPUT_LEFT) retval &= ~0x04;
|
||||
if (input.pad[pad_num] & INPUT_RIGHT) retval &= ~0x08;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
/* S,A,C,B Buttons */
|
||||
if (input.pad[pad_num] & INPUT_B) retval &= ~0x01;
|
||||
if (input.pad[pad_num] & INPUT_C) retval &= ~0x02;
|
||||
if (input.pad[pad_num] & INPUT_A) retval &= ~0x04;
|
||||
if (input.pad[pad_num] & INPUT_START) retval &= ~0x08;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
/* M,X,Y,Z Buttons (6-Buttons only)*/
|
||||
if (input.pad[pad_num] & INPUT_Z) retval &= ~0x01;
|
||||
if (input.pad[pad_num] & INPUT_Y) retval &= ~0x02;
|
||||
if (input.pad[pad_num] & INPUT_X) retval &= ~0x04;
|
||||
if (input.pad[pad_num] & INPUT_MODE) retval &= ~0x08;
|
||||
break;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* MULTITAP generic functions (TEAMPLAYER/4WAYPLAY)
|
||||
*
|
||||
*****************************************************************************/
|
||||
void multitap_write (uint8 port, uint8 data)
|
||||
{
|
||||
uint8 old_state;
|
||||
switch (input.system[port])
|
||||
{
|
||||
case SYSTEM_WAYPLAY:
|
||||
if (!port) gamepad_write(current_pad, data);
|
||||
else current_pad = (data >> 4) & 0x07;
|
||||
break;
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
old_state = teamplayer[port].State;
|
||||
teamplayer[port].State = (data & io_reg[port+4]) | (teamplayer[port].State & ~io_reg[port+4]);
|
||||
if (old_state != teamplayer[port].State) teamplayer[port].Counter ++;
|
||||
if ((data&0x60) == 0x60) teamplayer[port].Counter = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 multitap_read (uint8 port)
|
||||
{
|
||||
uint8 retval = 0x7F;
|
||||
uint8 padnum;
|
||||
|
||||
switch (input.system[port])
|
||||
{
|
||||
case SYSTEM_WAYPLAY:
|
||||
if (port == 1) return 0x7F;
|
||||
if (current_pad >= 4) return 0x70; /* multitap detection (TH2 = 1) */
|
||||
return gamepad_read(current_pad); /* 0x0C = Pad1, 0x1C = Pad2, ... */
|
||||
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
switch (teamplayer[port].Counter) /* acquisition sequence steps */
|
||||
{
|
||||
case 0: /* initial state: TH = 1, TR = 1 */
|
||||
retval = 0x73;
|
||||
break;
|
||||
|
||||
case 1: /* start request: TH = 0, TR = 1 */
|
||||
retval = 0x3F;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3: /* ack request: TH=0, TR handshake */
|
||||
retval = 0x00;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7: /* gamepads type */
|
||||
padnum = (4 * port) + teamplayer[port].Counter - 4;
|
||||
retval = input.dev[padnum];
|
||||
break;
|
||||
|
||||
default: /* gamepads inputs acquisition */
|
||||
retval = teamplayer_read(port, teamplayer[port].Counter - 8);
|
||||
break;
|
||||
}
|
||||
|
||||
/* TL must match TR state */
|
||||
retval &= ~0x10;
|
||||
if (teamplayer[port].State & 0x20) retval |= 0x10;
|
||||
return retval;
|
||||
}
|
||||
return retval;
|
||||
}
|
63
source/input.h
Normal file
63
source/input.h
Normal file
@ -0,0 +1,63 @@
|
||||
#ifndef _INPUT_H_
|
||||
#define _INPUT_H_
|
||||
#include "types.h"
|
||||
|
||||
/* Input devices */
|
||||
#ifdef NGC
|
||||
#define MAX_INPUTS (4)
|
||||
#else
|
||||
#define MAX_INPUTS (8)
|
||||
#endif
|
||||
#define MAX_DEVICES (8)
|
||||
#define DEVICE_3BUTTON (0x00) /* 3-button gamepad */
|
||||
#define DEVICE_6BUTTON (0x01) /* 6-button gamepad */
|
||||
#define DEVICE_MOUSE (0x02) /* Sega Mouse (not supported) */
|
||||
#define DEVICE_LIGHTGUN (0x03) /* Sega Menacer */
|
||||
#define DEVICE_2BUTTON (0x04) /* 2-button gamepad (not supported) */
|
||||
#define NO_DEVICE (0x0F) /* unconnected */
|
||||
|
||||
/* Input bitmasks */
|
||||
#define INPUT_MODE (0x00000800)
|
||||
#define INPUT_Z (0x00000400)
|
||||
#define INPUT_Y (0x00000200)
|
||||
#define INPUT_X (0x00000100)
|
||||
#define INPUT_START (0x00000080)
|
||||
#define INPUT_C (0x00000040)
|
||||
#define INPUT_B (0x00000020)
|
||||
#define INPUT_A (0x00000010)
|
||||
#define INPUT_LEFT (0x00000008)
|
||||
#define INPUT_RIGHT (0x00000004)
|
||||
#define INPUT_DOWN (0x00000002)
|
||||
#define INPUT_UP (0x00000001)
|
||||
|
||||
/* System bitmasks */
|
||||
#define SYSTEM_GAMEPAD (0) /* Single Gamepad */
|
||||
#define SYSTEM_TEAMPLAYER (1) /* Sega TeamPlayer (1~8 players) */
|
||||
#define SYSTEM_WAYPLAY (2) /* EA 4-Way Play (1~4 players) */
|
||||
#define SYSTEM_MENACER (3) /* SEGA Menacer Lightgun */
|
||||
#define NO_SYSTEM (4) /* Unconnected Port*/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 dev[MAX_DEVICES]; /* Can be any of the DEVICE_* values */
|
||||
uint32 pad[MAX_DEVICES]; /* Can be any of the INPUT_* bitmasks */
|
||||
uint8 system[2]; /* Can be any of the SYSTEM_* bitmasks (PORTA & PORTB) */
|
||||
uint8 max; /* maximum number of connected devices */
|
||||
} t_input;
|
||||
|
||||
/* global variables */
|
||||
extern t_input input;
|
||||
extern uint8 j_cart;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void input_reset (int padtype);
|
||||
extern void input_update(void);
|
||||
extern void input_raz(void);
|
||||
extern void lightgun_set (void);
|
||||
extern uint8 lightgun_read (void);
|
||||
extern uint8 gamepad_read (uint8 i);
|
||||
extern void gamepad_write (uint8 i, uint8 data);
|
||||
extern uint8 multitap_read (uint8 port);
|
||||
extern void multitap_write (uint8 port, uint8 data);
|
||||
|
||||
#endif
|
215
source/io.c
Normal file
215
source/io.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
|
||||
I/O controller chip emulation
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
uint8 io_reg[0x10];
|
||||
uint8 region_code = REGION_USA;
|
||||
uint8 pad_type = DEVICE_3BUTTON;
|
||||
|
||||
/*****************************************************************************
|
||||
* IO Read/Write wrappers
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
unsigned char Player1_Read (void)
|
||||
{
|
||||
return gamepad_read(0);
|
||||
}
|
||||
|
||||
unsigned char Player2_Read (void)
|
||||
{
|
||||
return gamepad_read(4);
|
||||
}
|
||||
|
||||
void Player1_Write (unsigned char data)
|
||||
{
|
||||
gamepad_write(0, data);
|
||||
}
|
||||
|
||||
void Player2_Write (unsigned char data)
|
||||
{
|
||||
gamepad_write(4, data);
|
||||
}
|
||||
|
||||
unsigned char MultiTap1_Read (void)
|
||||
{
|
||||
return multitap_read(0);
|
||||
}
|
||||
|
||||
unsigned char MultiTap2_Read (void)
|
||||
{
|
||||
return multitap_read(1);
|
||||
}
|
||||
|
||||
void MultiTap1_Write (unsigned char data)
|
||||
{
|
||||
multitap_write(0, data);
|
||||
}
|
||||
|
||||
void MultiTap2_Write (unsigned char data)
|
||||
{
|
||||
multitap_write(1, data);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* I/O chip functions *
|
||||
* *
|
||||
*****************************************************************************
|
||||
*/
|
||||
struct port_t
|
||||
{
|
||||
void (*data_w)(uint8 data);
|
||||
uint8 (*data_r)(void);
|
||||
} port[3];
|
||||
|
||||
void io_reset(void)
|
||||
{
|
||||
/* I/O register default settings */
|
||||
uint8 io_def[0x10] =
|
||||
{
|
||||
0xA0,
|
||||
0x7F, 0x7F, 0x7F,
|
||||
0x00, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00,
|
||||
0xFF, 0x00, 0x00,
|
||||
0xFB, 0x00, 0x00,
|
||||
};
|
||||
|
||||
/* Initialize I/O registers */
|
||||
memcpy (io_reg, io_def, 0x10);
|
||||
|
||||
switch (input.system[0])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
port[0].data_w = Player1_Write;
|
||||
port[0].data_r = Player1_Read;
|
||||
break;
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
port[0].data_w = MultiTap1_Write;
|
||||
port[0].data_r = MultiTap1_Read;
|
||||
break;
|
||||
|
||||
default:
|
||||
port[0].data_w = NULL;
|
||||
port[0].data_r = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (input.system[1])
|
||||
{
|
||||
case SYSTEM_GAMEPAD:
|
||||
port[1].data_w = Player2_Write;
|
||||
port[1].data_r = Player2_Read;
|
||||
break;
|
||||
|
||||
case SYSTEM_WAYPLAY:
|
||||
case SYSTEM_TEAMPLAYER:
|
||||
port[1].data_w = MultiTap2_Write;
|
||||
port[1].data_r = MultiTap2_Read;
|
||||
break;
|
||||
|
||||
case SYSTEM_MENACER:
|
||||
port[1].data_w = NULL;
|
||||
port[1].data_r = lightgun_read;
|
||||
break;
|
||||
|
||||
default:
|
||||
port[1].data_w = NULL;
|
||||
port[1].data_r = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
port[2].data_w = NULL;
|
||||
port[2].data_r = NULL;
|
||||
|
||||
j_cart = 0;
|
||||
input_reset(pad_type);
|
||||
}
|
||||
|
||||
void io_write(int offset, int value)
|
||||
{
|
||||
switch (offset)
|
||||
{
|
||||
case 0x01: /* Port A Data */
|
||||
case 0x02: /* Port B Data */
|
||||
case 0x03: /* Port C Data */
|
||||
io_reg[offset] = ((value & 0x80) | (value & io_reg[offset+3]));
|
||||
if(port[offset-1].data_w) port[offset-1].data_w(value);
|
||||
return;
|
||||
|
||||
case 0x05: /* Port B Ctrl */
|
||||
if (((value & 0x7F) == 0x7F) &&
|
||||
((input.system[0] == SYSTEM_TEAMPLAYER) ||
|
||||
(input.system[1] == SYSTEM_TEAMPLAYER)))
|
||||
{
|
||||
/* autodetect 4-Way play ! */
|
||||
input.system[0] = SYSTEM_WAYPLAY;
|
||||
input.system[1] = SYSTEM_WAYPLAY;
|
||||
port[0].data_w = MultiTap1_Write;
|
||||
port[0].data_r = MultiTap1_Read;
|
||||
port[1].data_w = MultiTap2_Write;
|
||||
port[1].data_r = MultiTap2_Read;
|
||||
input_reset(pad_type);
|
||||
}
|
||||
|
||||
case 0x04: /* Port A Ctrl */
|
||||
case 0x06: /* Port C Ctrl */
|
||||
io_reg[offset] = value & 0xFF;
|
||||
io_reg[offset-3] = ((io_reg[offset-3] & 0x80) | (io_reg[offset-3] & io_reg[offset]));
|
||||
break;
|
||||
|
||||
case 0x07: /* Port A TxData */
|
||||
case 0x0A: /* Port B TxData */
|
||||
case 0x0D: /* Port C TxData */
|
||||
io_reg[offset] = value;
|
||||
break;
|
||||
|
||||
case 0x09: /* Port A S-Ctrl */
|
||||
case 0x0C: /* Port B S-Ctrl */
|
||||
case 0x0F: /* Port C S-Ctrl */
|
||||
io_reg[offset] = (value & 0xF8);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int io_read(int offset)
|
||||
{
|
||||
uint8 has_scd = 0x20; /* No Sega CD unit attached */
|
||||
uint8 gen_ver = 0x00; /* Version 0 hardware */
|
||||
uint8 input = 0x7F; /* default input state */
|
||||
|
||||
switch(offset)
|
||||
{
|
||||
case 0x00: /* Version */
|
||||
return (region_code | has_scd | gen_ver);
|
||||
|
||||
case 0x01: /* Port A Data */
|
||||
case 0x02: /* Port B Data */
|
||||
case 0x03: /* Port C Data */
|
||||
if(port[offset-1].data_r) input = port[offset-1].data_r();
|
||||
return (io_reg[offset] | ((~io_reg[offset+3]) & input));
|
||||
}
|
||||
|
||||
return (io_reg[offset]);
|
||||
}
|
20
source/io.h
Normal file
20
source/io.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef _IO_H_
|
||||
#define _IO_H_
|
||||
|
||||
#define REGION_USA 0x80
|
||||
#define REGION_JAPAN_NTSC 0x00
|
||||
#define REGION_EUROPE 0xC0
|
||||
#define REGION_JAPAN_PAL 0x40
|
||||
|
||||
/* Global variables */
|
||||
extern uint8 io_reg[0x10];
|
||||
extern uint8 region_code;
|
||||
extern uint8 pad_type;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void io_reset(void);
|
||||
extern void io_write(int offset, int value);
|
||||
extern int io_read(int offset);
|
||||
|
||||
#endif /* _IO_H_ */
|
||||
|
894
source/m68k/m68kcpu.c
Normal file
894
source/m68k/m68kcpu.c
Normal file
@ -0,0 +1,894 @@
|
||||
/* ======================================================================== */
|
||||
/* ========================= LICENSING & COPYRIGHT ======================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
#if 0
|
||||
static const char* copyright_notice =
|
||||
"MUSASHI\n"
|
||||
"Version 3.3 (2001-01-29)\n"
|
||||
"A portable Motorola M680x0 processor emulation engine.\n"
|
||||
"Copyright 1998-2001 Karl Stenerud. All rights reserved.\n"
|
||||
"\n"
|
||||
"This code may be freely used for non-commercial purpooses as long as this\n"
|
||||
"copyright notice remains unaltered in the source code and any binary files\n"
|
||||
"containing this code in compiled form.\n"
|
||||
"\n"
|
||||
"All other lisencing terms must be negotiated with the author\n"
|
||||
"(Karl Stenerud).\n"
|
||||
"\n"
|
||||
"The latest version of this code can be obtained at:\n"
|
||||
"http://kstenerud.cjb.net\n"
|
||||
;
|
||||
#endif
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ================================= NOTES ================================ */
|
||||
/* ======================================================================== */
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ================================ INCLUDES ============================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
#include "m68kops.h"
|
||||
#include "m68kcpu.h"
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ================================= DATA ================================= */
|
||||
/* ======================================================================== */
|
||||
|
||||
int m68ki_initial_cycles;
|
||||
int m68ki_remaining_cycles = 0; /* Number of clocks remaining */
|
||||
uint m68ki_tracing = 0;
|
||||
uint m68ki_address_space;
|
||||
|
||||
#ifdef M68K_LOG_ENABLE
|
||||
char* m68ki_cpu_names[9] =
|
||||
{
|
||||
"Invalid CPU",
|
||||
"M68000",
|
||||
"M68010",
|
||||
"Invalid CPU",
|
||||
"M68EC020"
|
||||
"Invalid CPU",
|
||||
"Invalid CPU",
|
||||
"Invalid CPU",
|
||||
"M68020"
|
||||
};
|
||||
#endif /* M68K_LOG_ENABLE */
|
||||
|
||||
/* The CPU core */
|
||||
m68ki_cpu_core m68ki_cpu = {0};
|
||||
|
||||
#if M68K_EMULATE_ADDRESS_ERROR
|
||||
jmp_buf m68ki_address_error_trap;
|
||||
#endif /* M68K_EMULATE_ADDRESS_ERROR */
|
||||
|
||||
/* Used by shift & rotate instructions */
|
||||
uint8 m68ki_shift_8_table[65] =
|
||||
{
|
||||
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
uint16 m68ki_shift_16_table[65] =
|
||||
{
|
||||
0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
|
||||
0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
|
||||
0xffff, 0xffff
|
||||
};
|
||||
uint m68ki_shift_32_table[65] =
|
||||
{
|
||||
0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
|
||||
0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
|
||||
0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
|
||||
0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
|
||||
0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
|
||||
0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
|
||||
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
|
||||
};
|
||||
|
||||
|
||||
/* Number of clock cycles to use for exception processing.
|
||||
* I used 4 for any vectors that are undocumented for processing times.
|
||||
*/
|
||||
uint8 m68ki_exception_cycle_table[3][256] =
|
||||
{
|
||||
{ /* 000 */
|
||||
4, /* 0: Reset - Initial Stack Pointer */
|
||||
4, /* 1: Reset - Initial Program Counter */
|
||||
50, /* 2: Bus Error (unemulated) */
|
||||
50, /* 3: Address Error (unemulated) */
|
||||
34, /* 4: Illegal Instruction */
|
||||
38, /* 5: Divide by Zero -- ASG: changed from 42 */
|
||||
40, /* 6: CHK -- ASG: chanaged from 44 */
|
||||
34, /* 7: TRAPV */
|
||||
34, /* 8: Privilege Violation */
|
||||
34, /* 9: Trace */
|
||||
4, /* 10: 1010 */
|
||||
4, /* 11: 1111 */
|
||||
4, /* 12: RESERVED */
|
||||
4, /* 13: Coprocessor Protocol Violation (unemulated) */
|
||||
4, /* 14: Format Error */
|
||||
44, /* 15: Uninitialized Interrupt */
|
||||
4, /* 16: RESERVED */
|
||||
4, /* 17: RESERVED */
|
||||
4, /* 18: RESERVED */
|
||||
4, /* 19: RESERVED */
|
||||
4, /* 20: RESERVED */
|
||||
4, /* 21: RESERVED */
|
||||
4, /* 22: RESERVED */
|
||||
4, /* 23: RESERVED */
|
||||
44, /* 24: Spurious Interrupt */
|
||||
44, /* 25: Level 1 Interrupt Autovector */
|
||||
44, /* 26: Level 2 Interrupt Autovector */
|
||||
44, /* 27: Level 3 Interrupt Autovector */
|
||||
44, /* 28: Level 4 Interrupt Autovector */
|
||||
44, /* 29: Level 5 Interrupt Autovector */
|
||||
44, /* 30: Level 6 Interrupt Autovector */
|
||||
44, /* 31: Level 7 Interrupt Autovector */
|
||||
34, /* 32: TRAP #0 -- ASG: chanaged from 38 */
|
||||
34, /* 33: TRAP #1 */
|
||||
34, /* 34: TRAP #2 */
|
||||
34, /* 35: TRAP #3 */
|
||||
34, /* 36: TRAP #4 */
|
||||
34, /* 37: TRAP #5 */
|
||||
34, /* 38: TRAP #6 */
|
||||
34, /* 39: TRAP #7 */
|
||||
34, /* 40: TRAP #8 */
|
||||
34, /* 41: TRAP #9 */
|
||||
34, /* 42: TRAP #10 */
|
||||
34, /* 43: TRAP #11 */
|
||||
34, /* 44: TRAP #12 */
|
||||
34, /* 45: TRAP #13 */
|
||||
34, /* 46: TRAP #14 */
|
||||
34, /* 47: TRAP #15 */
|
||||
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
|
||||
4, /* 49: FP Inexact Result (unemulated) */
|
||||
4, /* 50: FP Divide by Zero (unemulated) */
|
||||
4, /* 51: FP Underflow (unemulated) */
|
||||
4, /* 52: FP Operand Error (unemulated) */
|
||||
4, /* 53: FP Overflow (unemulated) */
|
||||
4, /* 54: FP Signaling NAN (unemulated) */
|
||||
4, /* 55: FP Unimplemented Data Type (unemulated) */
|
||||
4, /* 56: MMU Configuration Error (unemulated) */
|
||||
4, /* 57: MMU Illegal Operation Error (unemulated) */
|
||||
4, /* 58: MMU Access Level Violation Error (unemulated) */
|
||||
4, /* 59: RESERVED */
|
||||
4, /* 60: RESERVED */
|
||||
4, /* 61: RESERVED */
|
||||
4, /* 62: RESERVED */
|
||||
4, /* 63: RESERVED */
|
||||
/* 64-255: User Defined */
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
},
|
||||
{ /* 010 */
|
||||
4, /* 0: Reset - Initial Stack Pointer */
|
||||
4, /* 1: Reset - Initial Program Counter */
|
||||
126, /* 2: Bus Error (unemulated) */
|
||||
126, /* 3: Address Error (unemulated) */
|
||||
38, /* 4: Illegal Instruction */
|
||||
44, /* 5: Divide by Zero */
|
||||
44, /* 6: CHK */
|
||||
34, /* 7: TRAPV */
|
||||
38, /* 8: Privilege Violation */
|
||||
38, /* 9: Trace */
|
||||
4, /* 10: 1010 */
|
||||
4, /* 11: 1111 */
|
||||
4, /* 12: RESERVED */
|
||||
4, /* 13: Coprocessor Protocol Violation (unemulated) */
|
||||
4, /* 14: Format Error */
|
||||
44, /* 15: Uninitialized Interrupt */
|
||||
4, /* 16: RESERVED */
|
||||
4, /* 17: RESERVED */
|
||||
4, /* 18: RESERVED */
|
||||
4, /* 19: RESERVED */
|
||||
4, /* 20: RESERVED */
|
||||
4, /* 21: RESERVED */
|
||||
4, /* 22: RESERVED */
|
||||
4, /* 23: RESERVED */
|
||||
46, /* 24: Spurious Interrupt */
|
||||
46, /* 25: Level 1 Interrupt Autovector */
|
||||
46, /* 26: Level 2 Interrupt Autovector */
|
||||
46, /* 27: Level 3 Interrupt Autovector */
|
||||
46, /* 28: Level 4 Interrupt Autovector */
|
||||
46, /* 29: Level 5 Interrupt Autovector */
|
||||
46, /* 30: Level 6 Interrupt Autovector */
|
||||
46, /* 31: Level 7 Interrupt Autovector */
|
||||
38, /* 32: TRAP #0 */
|
||||
38, /* 33: TRAP #1 */
|
||||
38, /* 34: TRAP #2 */
|
||||
38, /* 35: TRAP #3 */
|
||||
38, /* 36: TRAP #4 */
|
||||
38, /* 37: TRAP #5 */
|
||||
38, /* 38: TRAP #6 */
|
||||
38, /* 39: TRAP #7 */
|
||||
38, /* 40: TRAP #8 */
|
||||
38, /* 41: TRAP #9 */
|
||||
38, /* 42: TRAP #10 */
|
||||
38, /* 43: TRAP #11 */
|
||||
38, /* 44: TRAP #12 */
|
||||
38, /* 45: TRAP #13 */
|
||||
38, /* 46: TRAP #14 */
|
||||
38, /* 47: TRAP #15 */
|
||||
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
|
||||
4, /* 49: FP Inexact Result (unemulated) */
|
||||
4, /* 50: FP Divide by Zero (unemulated) */
|
||||
4, /* 51: FP Underflow (unemulated) */
|
||||
4, /* 52: FP Operand Error (unemulated) */
|
||||
4, /* 53: FP Overflow (unemulated) */
|
||||
4, /* 54: FP Signaling NAN (unemulated) */
|
||||
4, /* 55: FP Unimplemented Data Type (unemulated) */
|
||||
4, /* 56: MMU Configuration Error (unemulated) */
|
||||
4, /* 57: MMU Illegal Operation Error (unemulated) */
|
||||
4, /* 58: MMU Access Level Violation Error (unemulated) */
|
||||
4, /* 59: RESERVED */
|
||||
4, /* 60: RESERVED */
|
||||
4, /* 61: RESERVED */
|
||||
4, /* 62: RESERVED */
|
||||
4, /* 63: RESERVED */
|
||||
/* 64-255: User Defined */
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
},
|
||||
{ /* 020 */
|
||||
4, /* 0: Reset - Initial Stack Pointer */
|
||||
4, /* 1: Reset - Initial Program Counter */
|
||||
50, /* 2: Bus Error (unemulated) */
|
||||
50, /* 3: Address Error (unemulated) */
|
||||
20, /* 4: Illegal Instruction */
|
||||
38, /* 5: Divide by Zero */
|
||||
40, /* 6: CHK */
|
||||
20, /* 7: TRAPV */
|
||||
34, /* 8: Privilege Violation */
|
||||
25, /* 9: Trace */
|
||||
20, /* 10: 1010 */
|
||||
20, /* 11: 1111 */
|
||||
4, /* 12: RESERVED */
|
||||
4, /* 13: Coprocessor Protocol Violation (unemulated) */
|
||||
4, /* 14: Format Error */
|
||||
30, /* 15: Uninitialized Interrupt */
|
||||
4, /* 16: RESERVED */
|
||||
4, /* 17: RESERVED */
|
||||
4, /* 18: RESERVED */
|
||||
4, /* 19: RESERVED */
|
||||
4, /* 20: RESERVED */
|
||||
4, /* 21: RESERVED */
|
||||
4, /* 22: RESERVED */
|
||||
4, /* 23: RESERVED */
|
||||
30, /* 24: Spurious Interrupt */
|
||||
30, /* 25: Level 1 Interrupt Autovector */
|
||||
30, /* 26: Level 2 Interrupt Autovector */
|
||||
30, /* 27: Level 3 Interrupt Autovector */
|
||||
30, /* 28: Level 4 Interrupt Autovector */
|
||||
30, /* 29: Level 5 Interrupt Autovector */
|
||||
30, /* 30: Level 6 Interrupt Autovector */
|
||||
30, /* 31: Level 7 Interrupt Autovector */
|
||||
20, /* 32: TRAP #0 */
|
||||
20, /* 33: TRAP #1 */
|
||||
20, /* 34: TRAP #2 */
|
||||
20, /* 35: TRAP #3 */
|
||||
20, /* 36: TRAP #4 */
|
||||
20, /* 37: TRAP #5 */
|
||||
20, /* 38: TRAP #6 */
|
||||
20, /* 39: TRAP #7 */
|
||||
20, /* 40: TRAP #8 */
|
||||
20, /* 41: TRAP #9 */
|
||||
20, /* 42: TRAP #10 */
|
||||
20, /* 43: TRAP #11 */
|
||||
20, /* 44: TRAP #12 */
|
||||
20, /* 45: TRAP #13 */
|
||||
20, /* 46: TRAP #14 */
|
||||
20, /* 47: TRAP #15 */
|
||||
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
|
||||
4, /* 49: FP Inexact Result (unemulated) */
|
||||
4, /* 50: FP Divide by Zero (unemulated) */
|
||||
4, /* 51: FP Underflow (unemulated) */
|
||||
4, /* 52: FP Operand Error (unemulated) */
|
||||
4, /* 53: FP Overflow (unemulated) */
|
||||
4, /* 54: FP Signaling NAN (unemulated) */
|
||||
4, /* 55: FP Unimplemented Data Type (unemulated) */
|
||||
4, /* 56: MMU Configuration Error (unemulated) */
|
||||
4, /* 57: MMU Illegal Operation Error (unemulated) */
|
||||
4, /* 58: MMU Access Level Violation Error (unemulated) */
|
||||
4, /* 59: RESERVED */
|
||||
4, /* 60: RESERVED */
|
||||
4, /* 61: RESERVED */
|
||||
4, /* 62: RESERVED */
|
||||
4, /* 63: RESERVED */
|
||||
/* 64-255: User Defined */
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
|
||||
}
|
||||
};
|
||||
|
||||
uint8 m68ki_ea_idx_cycle_table[64] =
|
||||
{
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, /* ..01.000 no memory indirect, base NULL */
|
||||
5, /* ..01..01 memory indirect, base NULL, outer NULL */
|
||||
7, /* ..01..10 memory indirect, base NULL, outer 16 */
|
||||
7, /* ..01..11 memory indirect, base NULL, outer 32 */
|
||||
0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7,
|
||||
2, /* ..10.000 no memory indirect, base 16 */
|
||||
7, /* ..10..01 memory indirect, base 16, outer NULL */
|
||||
9, /* ..10..10 memory indirect, base 16, outer 16 */
|
||||
9, /* ..10..11 memory indirect, base 16, outer 32 */
|
||||
0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9,
|
||||
6, /* ..11.000 no memory indirect, base 32 */
|
||||
11, /* ..11..01 memory indirect, base 32, outer NULL */
|
||||
13, /* ..11..10 memory indirect, base 32, outer 16 */
|
||||
13, /* ..11..11 memory indirect, base 32, outer 32 */
|
||||
0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* =============================== CALLBACKS ============================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* Default callbacks used if the callback hasn't been set yet, or if the
|
||||
* callback is set to NULL
|
||||
*/
|
||||
|
||||
/* Interrupt acknowledge */
|
||||
static int default_int_ack_callback_data;
|
||||
static int default_int_ack_callback(int int_level)
|
||||
{
|
||||
default_int_ack_callback_data = int_level;
|
||||
CPU_INT_LEVEL = 0;
|
||||
return M68K_INT_ACK_AUTOVECTOR;
|
||||
}
|
||||
|
||||
/* Breakpoint acknowledge */
|
||||
static unsigned int default_bkpt_ack_callback_data;
|
||||
static void default_bkpt_ack_callback(unsigned int data)
|
||||
{
|
||||
default_bkpt_ack_callback_data = data;
|
||||
}
|
||||
|
||||
/* Called when a reset instruction is executed */
|
||||
static void default_reset_instr_callback(void)
|
||||
{
|
||||
}
|
||||
|
||||
/* Called when the program counter changed by a large value */
|
||||
static unsigned int default_pc_changed_callback_data;
|
||||
static void default_pc_changed_callback(unsigned int new_pc)
|
||||
{
|
||||
default_pc_changed_callback_data = new_pc;
|
||||
}
|
||||
|
||||
/* Called every time there's bus activity (read/write to/from memory */
|
||||
static unsigned int default_set_fc_callback_data;
|
||||
static void default_set_fc_callback(unsigned int new_fc)
|
||||
{
|
||||
default_set_fc_callback_data = new_fc;
|
||||
}
|
||||
|
||||
/* Called every instruction cycle prior to execution */
|
||||
static void default_instr_hook_callback(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ================================= API ================================== */
|
||||
/* ======================================================================== */
|
||||
|
||||
/* Access the internals of the CPU */
|
||||
unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
|
||||
{
|
||||
m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu;
|
||||
|
||||
switch(regnum)
|
||||
{
|
||||
case M68K_REG_D0: return cpu->dar[0];
|
||||
case M68K_REG_D1: return cpu->dar[1];
|
||||
case M68K_REG_D2: return cpu->dar[2];
|
||||
case M68K_REG_D3: return cpu->dar[3];
|
||||
case M68K_REG_D4: return cpu->dar[4];
|
||||
case M68K_REG_D5: return cpu->dar[5];
|
||||
case M68K_REG_D6: return cpu->dar[6];
|
||||
case M68K_REG_D7: return cpu->dar[7];
|
||||
case M68K_REG_A0: return cpu->dar[8];
|
||||
case M68K_REG_A1: return cpu->dar[9];
|
||||
case M68K_REG_A2: return cpu->dar[10];
|
||||
case M68K_REG_A3: return cpu->dar[11];
|
||||
case M68K_REG_A4: return cpu->dar[12];
|
||||
case M68K_REG_A5: return cpu->dar[13];
|
||||
case M68K_REG_A6: return cpu->dar[14];
|
||||
case M68K_REG_A7: return cpu->dar[15];
|
||||
case M68K_REG_PC: return MASK_OUT_ABOVE_32(cpu->pc);
|
||||
case M68K_REG_SR: return cpu->t1_flag |
|
||||
cpu->t0_flag |
|
||||
(cpu->s_flag << 11) |
|
||||
(cpu->m_flag << 11) |
|
||||
cpu->int_mask |
|
||||
((cpu->x_flag & XFLAG_SET) >> 4) |
|
||||
((cpu->n_flag & NFLAG_SET) >> 4) |
|
||||
((!cpu->not_z_flag) << 2) |
|
||||
((cpu->v_flag & VFLAG_SET) >> 6) |
|
||||
((cpu->c_flag & CFLAG_SET) >> 8);
|
||||
case M68K_REG_SP: return cpu->dar[15];
|
||||
case M68K_REG_USP: return cpu->s_flag ? cpu->sp[0] : cpu->dar[15];
|
||||
case M68K_REG_ISP: return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4];
|
||||
case M68K_REG_MSP: return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6];
|
||||
case M68K_REG_SFC: return cpu->sfc;
|
||||
case M68K_REG_DFC: return cpu->dfc;
|
||||
case M68K_REG_VBR: return cpu->vbr;
|
||||
case M68K_REG_CACR: return cpu->cacr;
|
||||
case M68K_REG_CAAR: return cpu->caar;
|
||||
case M68K_REG_PREF_ADDR: return cpu->pref_addr;
|
||||
case M68K_REG_PREF_DATA: return cpu->pref_data;
|
||||
case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc);
|
||||
case M68K_REG_IR: return cpu->ir;
|
||||
case M68K_REG_CPU_TYPE:
|
||||
switch(cpu->cpu_type)
|
||||
{
|
||||
case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000;
|
||||
case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010;
|
||||
case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020;
|
||||
case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020;
|
||||
}
|
||||
return M68K_CPU_TYPE_INVALID;
|
||||
default: return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void m68k_set_reg(m68k_register_t regnum, unsigned int value)
|
||||
{
|
||||
switch(regnum)
|
||||
{
|
||||
case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
|
||||
case M68K_REG_SR: m68ki_set_sr(value); return;
|
||||
case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_USP: if(FLAG_S)
|
||||
REG_USP = MASK_OUT_ABOVE_32(value);
|
||||
else
|
||||
REG_SP = MASK_OUT_ABOVE_32(value);
|
||||
return;
|
||||
case M68K_REG_ISP: if(FLAG_S && !FLAG_M)
|
||||
REG_SP = MASK_OUT_ABOVE_32(value);
|
||||
else
|
||||
REG_ISP = MASK_OUT_ABOVE_32(value);
|
||||
return;
|
||||
case M68K_REG_MSP: if(FLAG_S && FLAG_M)
|
||||
REG_SP = MASK_OUT_ABOVE_32(value);
|
||||
else
|
||||
REG_MSP = MASK_OUT_ABOVE_32(value);
|
||||
return;
|
||||
case M68K_REG_VBR: REG_VBR = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_SFC: REG_SFC = value & 7; return;
|
||||
case M68K_REG_DFC: REG_DFC = value & 7; return;
|
||||
case M68K_REG_CACR: REG_CACR = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_CAAR: REG_CAAR = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_PPC: REG_PPC = MASK_OUT_ABOVE_32(value); return;
|
||||
case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return;
|
||||
case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the callbacks */
|
||||
void m68k_set_int_ack_callback(int (*callback)(int int_level))
|
||||
{
|
||||
CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
|
||||
}
|
||||
|
||||
void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data))
|
||||
{
|
||||
CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback;
|
||||
}
|
||||
|
||||
void m68k_set_reset_instr_callback(void (*callback)(void))
|
||||
{
|
||||
CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
|
||||
}
|
||||
|
||||
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc))
|
||||
{
|
||||
CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback;
|
||||
}
|
||||
|
||||
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
|
||||
{
|
||||
CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
|
||||
}
|
||||
|
||||
void m68k_set_instr_hook_callback(void (*callback)(void))
|
||||
{
|
||||
CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
/* Set the CPU type. */
|
||||
void m68k_set_cpu_type(unsigned int cpu_type)
|
||||
{
|
||||
switch(cpu_type)
|
||||
{
|
||||
case M68K_CPU_TYPE_68000:
|
||||
CPU_TYPE = CPU_TYPE_000;
|
||||
CPU_ADDRESS_MASK = 0x00ffffff;
|
||||
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
|
||||
CYC_INSTRUCTION = m68ki_cycles[0];
|
||||
CYC_EXCEPTION = m68ki_exception_cycle_table[0];
|
||||
CYC_BCC_NOTAKE_B = -2;
|
||||
CYC_BCC_NOTAKE_W = 2;
|
||||
CYC_DBCC_F_NOEXP = -2;
|
||||
CYC_DBCC_F_EXP = 2;
|
||||
CYC_SCC_R_FALSE = 2;
|
||||
CYC_MOVEM_W = 2;
|
||||
CYC_MOVEM_L = 3;
|
||||
CYC_SHIFT = 1;
|
||||
CYC_RESET = 132;
|
||||
return;
|
||||
case M68K_CPU_TYPE_68010:
|
||||
CPU_TYPE = CPU_TYPE_010;
|
||||
CPU_ADDRESS_MASK = 0x00ffffff;
|
||||
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
|
||||
CYC_INSTRUCTION = m68ki_cycles[1];
|
||||
CYC_EXCEPTION = m68ki_exception_cycle_table[1];
|
||||
CYC_BCC_NOTAKE_B = -4;
|
||||
CYC_BCC_NOTAKE_W = 0;
|
||||
CYC_DBCC_F_NOEXP = 0;
|
||||
CYC_DBCC_F_EXP = 6;
|
||||
CYC_SCC_R_FALSE = 0;
|
||||
CYC_MOVEM_W = 2;
|
||||
CYC_MOVEM_L = 3;
|
||||
CYC_SHIFT = 1;
|
||||
CYC_RESET = 130;
|
||||
return;
|
||||
case M68K_CPU_TYPE_68EC020:
|
||||
CPU_TYPE = CPU_TYPE_EC020;
|
||||
CPU_ADDRESS_MASK = 0x00ffffff;
|
||||
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
|
||||
CYC_INSTRUCTION = m68ki_cycles[2];
|
||||
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
|
||||
CYC_BCC_NOTAKE_B = -2;
|
||||
CYC_BCC_NOTAKE_W = 0;
|
||||
CYC_DBCC_F_NOEXP = 0;
|
||||
CYC_DBCC_F_EXP = 4;
|
||||
CYC_SCC_R_FALSE = 0;
|
||||
CYC_MOVEM_W = 2;
|
||||
CYC_MOVEM_L = 2;
|
||||
CYC_SHIFT = 0;
|
||||
CYC_RESET = 518;
|
||||
return;
|
||||
case M68K_CPU_TYPE_68020:
|
||||
CPU_TYPE = CPU_TYPE_020;
|
||||
CPU_ADDRESS_MASK = 0xffffffff;
|
||||
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
|
||||
CYC_INSTRUCTION = m68ki_cycles[2];
|
||||
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
|
||||
CYC_BCC_NOTAKE_B = -2;
|
||||
CYC_BCC_NOTAKE_W = 0;
|
||||
CYC_DBCC_F_NOEXP = 0;
|
||||
CYC_DBCC_F_EXP = 4;
|
||||
CYC_SCC_R_FALSE = 0;
|
||||
CYC_MOVEM_W = 2;
|
||||
CYC_MOVEM_L = 2;
|
||||
CYC_SHIFT = 0;
|
||||
CYC_RESET = 518;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Execute some instructions until we use up num_cycles clock cycles */
|
||||
/* ASG: removed per-instruction interrupt checks */
|
||||
int m68k_execute(int num_cycles)
|
||||
{
|
||||
/* Make sure we're not stopped */
|
||||
if(!CPU_STOPPED)
|
||||
{
|
||||
/* Set our pool of clock cycles available */
|
||||
SET_CYCLES(num_cycles);
|
||||
m68ki_initial_cycles = num_cycles;
|
||||
|
||||
/* ASG: update cycles */
|
||||
USE_CYCLES(CPU_INT_CYCLES);
|
||||
CPU_INT_CYCLES = 0;
|
||||
|
||||
/* Return point if we had an address error */
|
||||
m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
/* Main loop. Keep going until we run out of clock cycles */
|
||||
do
|
||||
{
|
||||
/* Set tracing accodring to T1. (T0 is done inside instruction) */
|
||||
m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
/* Set the address space for reads */
|
||||
m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
/* Call external hook to peek at CPU */
|
||||
m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
/* Record previous program counter */
|
||||
REG_PPC = REG_PC;
|
||||
|
||||
/* Read an instruction and call its handler */
|
||||
REG_IR = m68ki_read_imm_16();
|
||||
m68ki_instruction_jump_table[REG_IR]();
|
||||
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
|
||||
|
||||
/* Trace m68k_exception, if necessary */
|
||||
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
|
||||
} while(GET_CYCLES() > 0);
|
||||
|
||||
/* set previous PC to current PC for the next entry into the loop */
|
||||
REG_PPC = REG_PC;
|
||||
|
||||
/* ASG: update cycles */
|
||||
USE_CYCLES(CPU_INT_CYCLES);
|
||||
CPU_INT_CYCLES = 0;
|
||||
|
||||
/* return how many clocks we used */
|
||||
return m68ki_initial_cycles - GET_CYCLES();
|
||||
}
|
||||
|
||||
/* We get here if the CPU is stopped or halted */
|
||||
SET_CYCLES(0);
|
||||
CPU_INT_CYCLES = 0;
|
||||
|
||||
return num_cycles;
|
||||
}
|
||||
|
||||
|
||||
int m68k_cycles_run(void)
|
||||
{
|
||||
return m68ki_initial_cycles - GET_CYCLES();
|
||||
}
|
||||
|
||||
int m68k_cycles_remaining(void)
|
||||
{
|
||||
return GET_CYCLES();
|
||||
}
|
||||
|
||||
/* Change the timeslice */
|
||||
void m68k_modify_timeslice(int cycles)
|
||||
{
|
||||
m68ki_initial_cycles += cycles;
|
||||
ADD_CYCLES(cycles);
|
||||
}
|
||||
|
||||
|
||||
void m68k_end_timeslice(void)
|
||||
{
|
||||
m68ki_initial_cycles = GET_CYCLES();
|
||||
SET_CYCLES(0);
|
||||
}
|
||||
|
||||
|
||||
/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
|
||||
/* KS: Modified so that IPL* bits match with mask positions in the SR
|
||||
* and cleaned out remenants of the interrupt controller.
|
||||
*/
|
||||
void m68k_set_irq(unsigned int int_level)
|
||||
{
|
||||
uint old_level = CPU_INT_LEVEL;
|
||||
CPU_INT_LEVEL = int_level << 8;
|
||||
|
||||
/* A transition from < 7 to 7 always interrupts (NMI) */
|
||||
/* Note: Level 7 can also level trigger like a normal IRQ */
|
||||
if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700)
|
||||
m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */
|
||||
else
|
||||
m68ki_check_interrupts(); /* Level triggered (IRQ) */
|
||||
}
|
||||
|
||||
|
||||
/* Pulse the RESET line on the CPU */
|
||||
void m68k_pulse_reset(void)
|
||||
{
|
||||
static uint emulation_initialized = 0;
|
||||
|
||||
/* The first call to this function initializes the opcode handler jump table */
|
||||
if(!emulation_initialized)
|
||||
{
|
||||
m68ki_build_opcode_table();
|
||||
m68k_set_int_ack_callback(NULL);
|
||||
m68k_set_bkpt_ack_callback(NULL);
|
||||
m68k_set_reset_instr_callback(NULL);
|
||||
m68k_set_pc_changed_callback(NULL);
|
||||
m68k_set_fc_callback(NULL);
|
||||
m68k_set_instr_hook_callback(NULL);
|
||||
|
||||
emulation_initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
if(CPU_TYPE == 0) /* KW 990319 */
|
||||
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||
|
||||
/* Clear all stop levels and eat up all remaining cycles */
|
||||
CPU_STOPPED = 0;
|
||||
SET_CYCLES(0);
|
||||
|
||||
/* Turn off tracing */
|
||||
FLAG_T1 = FLAG_T0 = 0;
|
||||
m68ki_clear_trace();
|
||||
/* Interrupt mask to level 7 */
|
||||
FLAG_INT_MASK = 0x0700;
|
||||
/* Reset VBR */
|
||||
REG_VBR = 0;
|
||||
/* Go to supervisor mode */
|
||||
m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR);
|
||||
|
||||
/* Invalidate the prefetch queue */
|
||||
#if M68K_EMULATE_PREFETCH
|
||||
/* Set to arbitrary number since our first fetch is from 0 */
|
||||
CPU_PREF_ADDR = 0x1000;
|
||||
#endif /* M68K_EMULATE_PREFETCH */
|
||||
|
||||
/* Read the initial stack pointer and program counter */
|
||||
m68ki_jump(0);
|
||||
REG_SP = m68ki_read_imm_32();
|
||||
REG_PC = m68ki_read_imm_32();
|
||||
m68ki_jump(REG_PC);
|
||||
}
|
||||
|
||||
/* Pulse the HALT line on the CPU */
|
||||
void m68k_pulse_halt(void)
|
||||
{
|
||||
CPU_STOPPED |= STOP_LEVEL_HALT;
|
||||
}
|
||||
|
||||
|
||||
/* Get and set the current CPU context */
|
||||
/* This is to allow for multiple CPUs */
|
||||
unsigned int m68k_context_size()
|
||||
{
|
||||
return sizeof(m68ki_cpu_core);
|
||||
}
|
||||
|
||||
unsigned int m68k_get_context(void* dst)
|
||||
{
|
||||
if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu;
|
||||
return sizeof(m68ki_cpu_core);
|
||||
}
|
||||
|
||||
void m68k_set_context(void* src)
|
||||
{
|
||||
if(src) m68ki_cpu = *(m68ki_cpu_core*)src;
|
||||
}
|
||||
|
||||
void m68k_save_context( void (*save_value)(char*, unsigned int))
|
||||
{
|
||||
if(!save_value)
|
||||
return;
|
||||
|
||||
save_value("CPU_TYPE" , m68k_get_reg(NULL, M68K_REG_CPU_TYPE));
|
||||
save_value("D0" , REG_D[0]);
|
||||
save_value("D1" , REG_D[1]);
|
||||
save_value("D2" , REG_D[2]);
|
||||
save_value("D3" , REG_D[3]);
|
||||
save_value("D4" , REG_D[4]);
|
||||
save_value("D5" , REG_D[5]);
|
||||
save_value("D6" , REG_D[6]);
|
||||
save_value("D7" , REG_D[7]);
|
||||
save_value("A0" , REG_A[0]);
|
||||
save_value("A1" , REG_A[1]);
|
||||
save_value("A2" , REG_A[2]);
|
||||
save_value("A3" , REG_A[3]);
|
||||
save_value("A4" , REG_A[4]);
|
||||
save_value("A5" , REG_A[5]);
|
||||
save_value("A6" , REG_A[6]);
|
||||
save_value("A7" , REG_A[7]);
|
||||
save_value("PPC" , REG_PPC);
|
||||
save_value("PC" , REG_PC);
|
||||
save_value("USP" , REG_USP);
|
||||
save_value("ISP" , REG_ISP);
|
||||
save_value("MSP" , REG_MSP);
|
||||
save_value("VBR" , REG_VBR);
|
||||
save_value("SFC" , REG_SFC);
|
||||
save_value("DFC" , REG_DFC);
|
||||
save_value("CACR" , REG_CACR);
|
||||
save_value("CAAR" , REG_CAAR);
|
||||
save_value("SR" , m68ki_get_sr());
|
||||
save_value("INT_LEVEL" , CPU_INT_LEVEL);
|
||||
save_value("INT_CYCLES", CPU_INT_CYCLES);
|
||||
save_value("STOPPED" , (CPU_STOPPED & STOP_LEVEL_STOP) != 0);
|
||||
save_value("HALTED" , (CPU_STOPPED & STOP_LEVEL_HALT) != 0);
|
||||
save_value("PREF_ADDR" , CPU_PREF_ADDR);
|
||||
save_value("PREF_DATA" , CPU_PREF_DATA);
|
||||
}
|
||||
|
||||
void m68k_load_context(unsigned int (*load_value)(char*))
|
||||
{
|
||||
unsigned int temp;
|
||||
|
||||
m68k_set_cpu_type(load_value("CPU_TYPE"));
|
||||
REG_PPC = load_value("PPC");
|
||||
REG_PC = load_value("PC");
|
||||
m68ki_jump(REG_PC);
|
||||
CPU_INT_LEVEL = 0;
|
||||
m68ki_set_sr_noint(load_value("SR"));
|
||||
REG_D[0] = load_value("D0");
|
||||
REG_D[1] = load_value("D1");
|
||||
REG_D[2] = load_value("D2");
|
||||
REG_D[3] = load_value("D3");
|
||||
REG_D[4] = load_value("D4");
|
||||
REG_D[5] = load_value("D5");
|
||||
REG_D[6] = load_value("D6");
|
||||
REG_D[7] = load_value("D7");
|
||||
REG_A[0] = load_value("A0");
|
||||
REG_A[1] = load_value("A1");
|
||||
REG_A[2] = load_value("A2");
|
||||
REG_A[3] = load_value("A3");
|
||||
REG_A[4] = load_value("A4");
|
||||
REG_A[5] = load_value("A5");
|
||||
REG_A[6] = load_value("A6");
|
||||
REG_A[7] = load_value("A7");
|
||||
REG_USP = load_value("USP");
|
||||
REG_ISP = load_value("ISP");
|
||||
REG_MSP = load_value("MSP");
|
||||
REG_VBR = load_value("VBR");
|
||||
REG_SFC = load_value("SFC");
|
||||
REG_DFC = load_value("DFC");
|
||||
REG_CACR = load_value("CACR");
|
||||
REG_CAAR = load_value("CAAR");
|
||||
CPU_INT_LEVEL = load_value("INT_LEVEL");
|
||||
CPU_INT_CYCLES = load_value("INT_CYCLES");
|
||||
|
||||
CPU_STOPPED = 0;
|
||||
temp = load_value("STOPPED");
|
||||
if(temp) CPU_STOPPED |= STOP_LEVEL_STOP;
|
||||
temp = load_value("HALTED");
|
||||
if(temp) CPU_STOPPED |= STOP_LEVEL_HALT;
|
||||
|
||||
CPU_PREF_ADDR = load_value("PREF_ADDR");
|
||||
CPU_PREF_DATA = load_value("PREF_DATA");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ======================================================================== */
|
||||
/* ============================== END OF FILE ============================= */
|
||||
/* ======================================================================== */
|
1837
source/m68k/m68kcpu.h
Normal file
1837
source/m68k/m68kcpu.h
Normal file
File diff suppressed because it is too large
Load Diff
11948
source/m68k/m68kopac.c
Normal file
11948
source/m68k/m68kopac.c
Normal file
File diff suppressed because it is too large
Load Diff
13286
source/m68k/m68kopdm.c
Normal file
13286
source/m68k/m68kopdm.c
Normal file
File diff suppressed because it is too large
Load Diff
8746
source/m68k/m68kopnz.c
Normal file
8746
source/m68k/m68kopnz.c
Normal file
File diff suppressed because it is too large
Load Diff
2093
source/m68k/m68kops.c
Normal file
2093
source/m68k/m68kops.c
Normal file
File diff suppressed because it is too large
Load Diff
1984
source/m68k/m68kops.h
Normal file
1984
source/m68k/m68kops.h
Normal file
File diff suppressed because it is too large
Load Diff
34
source/macros.h
Normal file
34
source/macros.h
Normal file
@ -0,0 +1,34 @@
|
||||
|
||||
#ifndef _MACROS_H_
|
||||
#define _MACROS_H_
|
||||
|
||||
#ifdef LSB_FIRST
|
||||
|
||||
#define READ_BYTE(BASE, ADDR) (BASE)[(ADDR)^1]
|
||||
#define READ_WORD(BASE, ADDR) (((BASE)[ADDR]<<8) | \
|
||||
(BASE)[(ADDR)+1])
|
||||
#define READ_WORD_LONG(BASE, ADDR) (((BASE)[ADDR]<<24) | \
|
||||
((BASE)[(ADDR)+1]<<16) | \
|
||||
((BASE)[(ADDR)+2]<<8) | \
|
||||
(BASE)[(ADDR)+3])
|
||||
|
||||
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[(ADDR)^1] = (VAL)&0xff
|
||||
#define WRITE_WORD(BASE, ADDR, VAL) (BASE)[ADDR] = ((VAL)>>8) & 0xff; \
|
||||
(BASE)[(ADDR)+1] = (VAL)&0xff
|
||||
#define WRITE_WORD_LONG(BASE, ADDR, VAL) (BASE)[(ADDR] = ((VAL)>>24) & 0xff; \
|
||||
(BASE)[(ADDR)+1] = ((VAL)>>16)&0xff; \
|
||||
(BASE)[(ADDR)+2] = ((VAL)>>8)&0xff; \
|
||||
(BASE)[(ADDR)+3] = (VAL)&0xff
|
||||
|
||||
#else
|
||||
|
||||
#define READ_BYTE(BASE, ADDR) (BASE)[ADDR]
|
||||
#define READ_WORD(BASE, ADDR) *(uint16 *)((BASE) + (ADDR));
|
||||
#define READ_WORD_LONG(BASE, ADDR) *(uint32 *)((BASE) + (ADDR));
|
||||
#define WRITE_BYTE(BASE, ADDR, VAL) (BASE)[ADDR] = VAL & 0xff
|
||||
#define WRITE_WORD(BASE, ADDR, VAL) *(uint16 *)((BASE) + (ADDR)) = VAL & 0xffff
|
||||
#define WRITE_WORD_LONG(BASE, ADDR, VAL) *(uint32 *)((BASE) + (ADDR)) = VAL & 0xffffffff
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* _MACROS_H_ */
|
776
source/mem68k.c
Normal file
776
source/mem68k.c
Normal file
@ -0,0 +1,776 @@
|
||||
#include "shared.h"
|
||||
|
||||
static uint16 next_int = 1;
|
||||
static uint8 prot_bytes[2]; /* simple protection faking (from Picodrive) */
|
||||
|
||||
unsigned int m68k_read_bus_8(unsigned int address)
|
||||
{
|
||||
uint16 temp = m68k_read_bus_16(address);
|
||||
return ((address & 1) ? (temp & 0xFF) : (temp >> 8));
|
||||
}
|
||||
|
||||
unsigned int m68k_read_bus_16(unsigned int address)
|
||||
{
|
||||
next_int ^= 0xFFFF;
|
||||
return next_int;
|
||||
}
|
||||
|
||||
|
||||
void m68k_unused_w (unsigned int address, unsigned int value)
|
||||
{
|
||||
error("Unused 3 %08X = %08X \n", address, value);
|
||||
}
|
||||
|
||||
void m68k_unused_8_w (unsigned int address, unsigned int value)
|
||||
{
|
||||
error("Unused 2 %08X = %02X \n", address, value);
|
||||
}
|
||||
|
||||
void m68k_unused_16_w (unsigned int address, unsigned int value)
|
||||
{
|
||||
error("Unused 1 %08X = %04X \n", address, value);
|
||||
}
|
||||
|
||||
/*
|
||||
Functions to handle memory accesses which cause the Genesis to halt
|
||||
either temporarily (press RESET button to restart) or unrecoverably
|
||||
(cycle power to restart).
|
||||
*/
|
||||
|
||||
void m68k_lockup_w_8 (unsigned int address, unsigned int value)
|
||||
{
|
||||
error ("Lockup %08X = %02X (%08X)\n", address, value, m68k_get_reg (NULL, M68K_REG_PC));
|
||||
gen_running = 0;
|
||||
m68k_end_timeslice ();
|
||||
}
|
||||
|
||||
void m68k_lockup_w_16 (unsigned int address, unsigned int value)
|
||||
{
|
||||
error ("Lockup %08X = %04X (%08X)\n", address, value, m68k_get_reg (NULL, M68K_REG_PC));
|
||||
gen_running = 0;
|
||||
m68k_end_timeslice ();
|
||||
}
|
||||
|
||||
unsigned int m68k_lockup_r_8 (unsigned int address)
|
||||
{
|
||||
error ("Lockup %08X.b (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
|
||||
gen_running = 0;
|
||||
m68k_end_timeslice ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
unsigned int m68k_lockup_r_16 (unsigned int address)
|
||||
{
|
||||
error ("Lockup %08X.w (%08X)\n", address, m68k_get_reg (NULL, M68K_REG_PC));
|
||||
gen_running = 0;
|
||||
m68k_end_timeslice ();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
/* 68000 memory handlers */
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
unsigned int m68k_read_memory_8 (unsigned int address)
|
||||
{
|
||||
switch ((address >> 21) & 7)
|
||||
{
|
||||
case 0: /* ROM Cartridge*/
|
||||
case 1:
|
||||
/* SRAM */
|
||||
if (sram.on)
|
||||
{
|
||||
if (address >= sram.start && address <= sram.end)
|
||||
{
|
||||
if (sram.custom) return (EEPROM_Read(address)&0xffff);
|
||||
return READ_BYTE(sram.sram, (address - sram.start) & 0xffff);
|
||||
}
|
||||
}
|
||||
|
||||
/* ROM data */
|
||||
if (address < genromsize) return READ_BYTE(cart_rom, address);
|
||||
|
||||
/* default */
|
||||
return 0x00;
|
||||
|
||||
case 7: /* RAM */
|
||||
return READ_BYTE(work_ram, address & 0xFFFF);
|
||||
|
||||
case 5: /* Z80 & I/O */
|
||||
if (address <= 0xA0FFFF) /* Z80 area */
|
||||
{
|
||||
/* Z80 controls Z bus */
|
||||
if (zbusack == 1) return (m68k_read_bus_8 (address));
|
||||
else
|
||||
{
|
||||
/* Read data from Z bus */
|
||||
switch (address & 0x6000)
|
||||
{
|
||||
case 0x0000: /* RAM */
|
||||
case 0x2000:
|
||||
return (zram[(address & 0x1FFF)]);
|
||||
|
||||
case 0x4000: /* YM2612 */
|
||||
return (fm_read (address & 3));
|
||||
|
||||
case 0x6000: /* Unused */
|
||||
switch (address & 0xFF00)
|
||||
{
|
||||
case 0x7F00: /* VDP */
|
||||
m68k_lockup_r_8 (address);
|
||||
|
||||
default: /* Unused */
|
||||
return (0xFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (address <= 0xA1001F)
|
||||
{
|
||||
/* I/O */
|
||||
return (io_read((address >> 1) & 0x0F));
|
||||
}
|
||||
else if (address <= 0xA1FFFF) /* CONTROL */
|
||||
{
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x11: /* BUSACK */
|
||||
if ((address & 1) == 0) return (gen_busack_r () | (m68k_read_bus_8 (address) & 0xFE));
|
||||
else return (m68k_read_bus_8 (address));
|
||||
|
||||
case 0x00: /* UNKNOWN (BallZ) */
|
||||
case 0x10: /* MEMORY MODE */
|
||||
case 0x12: /* RESET */
|
||||
case 0x20: /* MEGA-CD */
|
||||
case 0x40: /* TMSS */
|
||||
case 0x41: /* BOOTROM */
|
||||
case 0x50: /* SVP REGISTERS */
|
||||
return (m68k_read_bus_8 (address));
|
||||
|
||||
default: /* Unused */
|
||||
return (m68k_lockup_r_8 (address));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unused */
|
||||
return (m68k_lockup_r_8 (address));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 6: /* VDP */
|
||||
if ((address & 0xE700E0) == 0xC00000)
|
||||
{
|
||||
switch (address & 0x1F)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
case 0x02:
|
||||
return (vdp_data_r () >> 8);
|
||||
|
||||
case 0x01: /* DATA */
|
||||
case 0x03:
|
||||
return (vdp_data_r () & 0xFF);
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
case 0x06:
|
||||
return ((m68k_read_bus_8 (address) & 0xFC) | (vdp_ctrl_r () >> 8));
|
||||
|
||||
case 0x05: /* CTRL */
|
||||
case 0x07:
|
||||
return (vdp_ctrl_r () & 0xFF);
|
||||
|
||||
case 0x08: /* HVC */
|
||||
case 0x0A:
|
||||
case 0x0C:
|
||||
case 0x0E:
|
||||
return (vdp_hvc_r () >> 8);
|
||||
|
||||
case 0x09: /* HVC */
|
||||
case 0x0B:
|
||||
case 0x0D:
|
||||
case 0x0F:
|
||||
return (vdp_hvc_r () & 0xFF);
|
||||
|
||||
case 0x10: /* PSG */
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
return (m68k_lockup_r_8 (address));
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
return (m68k_read_bus_8 (address));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unused */
|
||||
return (m68k_lockup_r_8 (address));
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: /* Unused */
|
||||
/* Some unlicensed games have a simple protection device mapped here */
|
||||
return prot_bytes[(address>>2)&1];
|
||||
|
||||
case 3: /* Unused */
|
||||
return (m68k_read_bus_8 (address));
|
||||
|
||||
case 4: /* Unused */
|
||||
return (m68k_lockup_r_8 (address));
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
unsigned int m68k_read_memory_16 (unsigned int address)
|
||||
{
|
||||
switch ((address >> 21) & 7)
|
||||
{
|
||||
case 0: /* ROM Cartridge */
|
||||
case 1:
|
||||
/* SRAM */
|
||||
if (sram.on)
|
||||
{
|
||||
if (address >= sram.start && address <= sram.end)
|
||||
{
|
||||
if (sram.custom) return (EEPROM_Read(address) & 0xffff);
|
||||
return *(uint16 *)(sram.sram + ((address - sram.start) & 0xffff));
|
||||
}
|
||||
}
|
||||
|
||||
/* ROM Data */
|
||||
if (address < genromsize) return *(uint16 *)(cart_rom + address);
|
||||
|
||||
/* j-CART */
|
||||
if (j_cart && ((address == 0x3FFFFE) || (address == 0x38FFFE)))
|
||||
return (gamepad_read(5) | (gamepad_read(6) << 8));
|
||||
|
||||
/* Virtua Racing SVP */
|
||||
if (address == 0x30fe02) return 0x01;
|
||||
|
||||
/* default */
|
||||
return 0x00;
|
||||
|
||||
case 7: /* RAM */
|
||||
return *(uint16 *)(work_ram + (address & 0xffff));
|
||||
|
||||
case 5: /* Z80 & I/O */
|
||||
if (address <= 0xA0FFFF) /* Z80 area */
|
||||
{
|
||||
if (zbusack == 1) return (m68k_read_bus_16 (address));
|
||||
else
|
||||
{
|
||||
uint8 temp;
|
||||
switch (address & 0x6000)
|
||||
{
|
||||
case 0x0000: /* RAM */
|
||||
case 0x2000:
|
||||
temp = zram[address & 0x1FFF];
|
||||
return (temp << 8 | temp);
|
||||
|
||||
case 0x4000: /* YM2612 */
|
||||
temp = fm_read (address & 3);
|
||||
return (temp << 8 | temp);
|
||||
|
||||
case 0x6000:
|
||||
switch (address & 0xFF00)
|
||||
{
|
||||
case 0x7F00: /* VDP */
|
||||
m68k_lockup_r_16 (address);
|
||||
|
||||
default: /* Unused */
|
||||
return (0xFFFF);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (address <= 0xA1001F) /* I/O */
|
||||
{
|
||||
uint8 temp = io_read ((address >> 1) & 0x0F);
|
||||
return (temp << 8 | temp);
|
||||
}
|
||||
else if (address <= 0xA1FFFF) /* CONTROL */
|
||||
{
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x11: /* BUSACK */
|
||||
return ((m68k_read_bus_16 (address) & 0xFEFF) | (gen_busack_r () << 8));
|
||||
|
||||
case 0x00: /* UNKNOWN (BallZ) */
|
||||
case 0x10: /* MEMORY MODE */
|
||||
case 0x12: /* RESET */
|
||||
case 0x20: /* MEGA-CD */
|
||||
case 0x40: /* TMSS */
|
||||
case 0x41: /* BOOTROM */
|
||||
case 0x50: /* SVP REGISTERS */
|
||||
return (m68k_read_bus_16 (address));
|
||||
|
||||
default: /* Unused */
|
||||
return (m68k_lockup_r_16 (address));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unused */
|
||||
return (m68k_lockup_r_16 (address));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 6: /* VDP */
|
||||
if ((address & 0xE700E0) == 0xC00000)
|
||||
{
|
||||
switch (address & 0x1F)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
case 0x02:
|
||||
return (vdp_data_r ());
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
case 0x06:
|
||||
return (vdp_ctrl_r () | (m68k_read_bus_16 (address) & 0xFC00));
|
||||
|
||||
case 0x08: /* HVC */
|
||||
case 0x0A:
|
||||
case 0x0C:
|
||||
case 0x0E:
|
||||
return (vdp_hvc_r ());
|
||||
|
||||
case 0x10: /* PSG */
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
case 0x16:
|
||||
return (m68k_lockup_r_16 (address));
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x1A:
|
||||
case 0x1C:
|
||||
case 0x1E:
|
||||
return (m68k_read_bus_16 (address));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return (m68k_lockup_r_16 (address));
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
return (m68k_read_bus_16 (address));
|
||||
|
||||
case 4:
|
||||
return (m68k_lockup_r_16 (address));
|
||||
}
|
||||
|
||||
return (0xA5A5);
|
||||
}
|
||||
|
||||
|
||||
unsigned int m68k_read_memory_32 (unsigned int address)
|
||||
{
|
||||
/* Split into 2 reads */
|
||||
return (m68k_read_memory_16 (address + 0) << 16 |
|
||||
m68k_read_memory_16 (address + 2));
|
||||
}
|
||||
|
||||
|
||||
void m68k_write_memory_8 (unsigned int address, unsigned int value)
|
||||
{
|
||||
switch ((address >> 21) & 7)
|
||||
{
|
||||
case 7: /* RAM */
|
||||
WRITE_BYTE(work_ram, address & 0xFFFF, value);
|
||||
return;
|
||||
|
||||
case 6: /* VDP */
|
||||
if ((address & 0xE700E0) == 0xC00000)
|
||||
{
|
||||
switch (address & 0x1F)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
vdp_data_w (value << 8 | value);
|
||||
return;
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
vdp_ctrl_w (value << 8 | value);
|
||||
return;
|
||||
|
||||
case 0x08: /* HVC */
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0D:
|
||||
case 0x0E:
|
||||
case 0x0F:
|
||||
m68k_lockup_w_8 (address, value);
|
||||
return;
|
||||
|
||||
case 0x10: /* PSG */
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
case 0x16:
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
|
||||
case 0x11: /* PSG */
|
||||
case 0x13:
|
||||
case 0x15:
|
||||
case 0x17:
|
||||
psg_write (value);
|
||||
return;
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m68k_lockup_w_8 (address, value);
|
||||
return;
|
||||
}
|
||||
|
||||
case 5: /* Z80 & IO */
|
||||
if (address <= 0xA0FFFF) /* Z80 area */
|
||||
{
|
||||
if (zbusack == 1)
|
||||
{
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (address & 0x6000)
|
||||
{
|
||||
case 0x0000:
|
||||
case 0x2000:
|
||||
zram[(address & 0x1FFF)] = value;
|
||||
return;
|
||||
|
||||
case 0x4000:
|
||||
fm_write (address & 3, value);
|
||||
return;
|
||||
|
||||
case 0x6000:
|
||||
switch (address & 0xFF00)
|
||||
{
|
||||
case 0x6000: /* BANK */
|
||||
gen_bank_w (value & 1);
|
||||
return;
|
||||
|
||||
case 0x7F00: /* VDP */
|
||||
m68k_lockup_w_8 (address, value);
|
||||
return;
|
||||
|
||||
default: /* Unused */
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (address <= 0xA1001F) /* I/O */
|
||||
{
|
||||
/* I/O chip only gets /LWR */
|
||||
if (address & 1) io_write ((address >> 1) & 0x0F, value);
|
||||
return;
|
||||
}
|
||||
else if (address <= 0xA1FFFF) /* CONTROL */
|
||||
{
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x11: /* BUSREQ */
|
||||
if ((address & 1) == 0) gen_busreq_w (value & 1);
|
||||
else m68k_unused_8_w (address, value);
|
||||
return;
|
||||
|
||||
case 0x12: /* RESET */
|
||||
gen_reset_w (value & 1);
|
||||
return;
|
||||
|
||||
case 0x30: /* TIME */
|
||||
if (SSF2TNC) ssf2bankrom (address, value & 0xf); /* banked ROM */
|
||||
else if (address == 0xA130F1) /* banked SRAM */
|
||||
{
|
||||
sram.on = value & 1;
|
||||
sram.write = (value & 2) ? 0 : 1;
|
||||
}
|
||||
else m68k_unused_8_w (address, value);
|
||||
return;
|
||||
|
||||
case 0x10: /* MEMORY MODE */
|
||||
case 0x20: /* MEGA-CD */
|
||||
case 0x40: /* TMSS */
|
||||
case 0x41: /* BOOTROM */
|
||||
case 0x50: /* SVP REGISTERS */
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
|
||||
default:
|
||||
m68k_lockup_w_8 (address, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Unused */
|
||||
m68k_lockup_w_8 (address, value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0: /* ROM Cartridge */
|
||||
case 1:
|
||||
|
||||
/* external SRAM */
|
||||
if (sram.on && sram.write)
|
||||
{
|
||||
if (address >= sram.start && address <= sram.end)
|
||||
{
|
||||
/* serial EEPROM */
|
||||
if (sram.custom)
|
||||
{
|
||||
EEPROM_Write(address, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/* normal SRAM */
|
||||
WRITE_BYTE(sram.sram, (address - sram.start) & 0xffff, value & 0xff);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
|
||||
case 2: /* Unused */
|
||||
/* Some unlicensed games have a simple protection device mapped here */
|
||||
prot_bytes[(address>>2)&1] = value;
|
||||
return;
|
||||
case 3:
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
|
||||
case 4: /* Unused */
|
||||
m68k_lockup_w_8 (address, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void m68k_write_memory_16 (unsigned int address, unsigned int value)
|
||||
{
|
||||
switch ((address >> 21) & 7)
|
||||
{
|
||||
case 7: /* Work RAM */
|
||||
*(uint16 *)(work_ram + (address& 0xFFFF)) = value & 0xffff;
|
||||
return;
|
||||
|
||||
case 6: /* VDP */
|
||||
if ((address & 0xE700E0) == 0xC00000)
|
||||
{
|
||||
switch (address & 0x1C)
|
||||
{
|
||||
case 0x00: /* DATA */
|
||||
vdp_data_w (value);
|
||||
return;
|
||||
|
||||
case 0x04: /* CTRL */
|
||||
vdp_ctrl_w (value);
|
||||
return;
|
||||
|
||||
case 0x08: /* HV counter */
|
||||
case 0x0C: /* HV counter */
|
||||
m68k_lockup_w_16 (address, value);
|
||||
return;
|
||||
|
||||
case 0x10: /* PSG */
|
||||
case 0x14: /* PSG */
|
||||
psg_write (value & 0xFF);
|
||||
return;
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x1C: /* Unused */
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid address */
|
||||
m68k_lockup_w_16 (address, value);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: /* Z80 area, I/O chip, miscellaneous. */
|
||||
if (address <= 0xA0FFFF) /* Z80 area */
|
||||
{
|
||||
/* Writes are ignored when the Z80 hogs the Z-bus */
|
||||
if (zbusack == 1)
|
||||
{
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Write into Z80 address space */
|
||||
switch (address & 0x6000)
|
||||
{
|
||||
case 0x0000: /* Work RAM */
|
||||
case 0x2000: /* Work RAM */
|
||||
zram[(address & 0x1FFF)] = (value >> 8) & 0xFF;
|
||||
return;
|
||||
|
||||
case 0x4000: /* YM2612 */
|
||||
fm_write (address & 3, (value >> 8) & 0xFF);
|
||||
return;
|
||||
|
||||
case 0x6000: /* Bank register and VDP */
|
||||
switch (address & 0x7F00)
|
||||
{
|
||||
case 0x6000: /* Bank register */
|
||||
gen_bank_w ((value >> 8) & 1);
|
||||
return;
|
||||
|
||||
case 0x7F00: /* VDP registers */
|
||||
m68k_lockup_w_16 (address, value);
|
||||
return;
|
||||
|
||||
default: /* Unused */
|
||||
m68k_unused_8_w (address, value);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (address <= 0xA1001F) /* I/O */
|
||||
{
|
||||
io_write ((address >> 1) & 0x0F, value & 0x00FF);
|
||||
return;
|
||||
}
|
||||
else if (address <= 0xA1FFFF) /* CONTROL */
|
||||
{
|
||||
switch ((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x11: /* BUSREQ */
|
||||
gen_busreq_w ((value >> 8) & 1);
|
||||
return;
|
||||
|
||||
case 0x12: /* RESET */
|
||||
gen_reset_w ((value >> 8) & 1);
|
||||
return;
|
||||
|
||||
case 0x30: /* TIME */
|
||||
if (SSF2TNC) ssf2bankrom (address, value & 0xf); /* banked ROM */
|
||||
else if (address == 0xA130F1) /* banked SRAM */
|
||||
{
|
||||
sram.on = value & 1;
|
||||
sram.write = (value & 2) ? 0 : 1;
|
||||
}
|
||||
else m68k_unused_16_w (address, value);
|
||||
return;
|
||||
|
||||
case 0x10: /* MEMORY MODE */
|
||||
case 0x20: /* MEGA-CD */
|
||||
case 0x40: /* TMSS */
|
||||
case 0x41: /* BOOTROM */
|
||||
case 0x50: /* SVP REGISTERS */
|
||||
m68k_unused_16_w (address, value);
|
||||
return;
|
||||
|
||||
default: /* Unused */
|
||||
m68k_lockup_w_16 (address, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m68k_lockup_w_16 (address, value);
|
||||
return;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 0: /* Cartridge ROM */
|
||||
case 1:
|
||||
/* J-CART extension (TH signal) */
|
||||
if ((address == 0x3FFFFE) || (address == 0x38FFFE))
|
||||
{
|
||||
if (!j_cart)
|
||||
{
|
||||
j_cart = 1;
|
||||
input_reset(pad_type);
|
||||
}
|
||||
gamepad_write(5, (value&1) <<6 );
|
||||
gamepad_write(6, (value&1) <<6);
|
||||
return;
|
||||
}
|
||||
|
||||
/* external SRAM */
|
||||
if (sram.on && sram.write)
|
||||
{
|
||||
if (address >= sram.start && address <= sram.end)
|
||||
{
|
||||
/* serial EEPROM */
|
||||
if (sram.custom)
|
||||
{
|
||||
EEPROM_Write(address, value);
|
||||
return;
|
||||
}
|
||||
|
||||
/* normal SRAM */
|
||||
*(uint16 *)(sram.sram + ((address - sram.start) & 0xffff)) = value & 0xffff;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m68k_unused_16_w (address, value);
|
||||
return;
|
||||
|
||||
case 2: /* Unused */
|
||||
case 3:
|
||||
m68k_unused_16_w (address, value);
|
||||
return;
|
||||
|
||||
case 4: /* Unused */
|
||||
m68k_lockup_w_16 (address, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void m68k_write_memory_32 (unsigned int address, unsigned int value)
|
||||
{
|
||||
/* Split into 2 writes */
|
||||
m68k_write_memory_16 (address, (value >> 16) & 0xFFFF);
|
||||
m68k_write_memory_16 (address + 2, value & 0xFFFF);
|
||||
}
|
14
source/mem68k.h
Normal file
14
source/mem68k.h
Normal file
@ -0,0 +1,14 @@
|
||||
|
||||
#ifndef _MEM68K_H_
|
||||
#define _MEM68K_H_
|
||||
|
||||
/* Function prototypes */
|
||||
unsigned int m68k_read_bus_8 (unsigned int address);
|
||||
unsigned int m68k_read_bus_16 (unsigned int address);
|
||||
void m68k_unused_w (unsigned int address, unsigned int value);
|
||||
void m68k_lockup_w_8 (unsigned int address, unsigned int value);
|
||||
void m68k_lockup_w_16 (unsigned int address, unsigned int value);
|
||||
unsigned int m68k_lockup_r_8 (unsigned int address);
|
||||
unsigned int m68k_lockup_r_16 (unsigned int address);
|
||||
|
||||
#endif /* _MEM68K_H_ */
|
296
source/membnk.c
Normal file
296
source/membnk.c
Normal file
@ -0,0 +1,296 @@
|
||||
/*
|
||||
membnk.c --
|
||||
Memory handlers Z80 access to the banked V-bus address space.
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
|
||||
void z80_write_banked_memory(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch((address >> 21) & 7)
|
||||
{
|
||||
case 0: /* Cartridge ROM */
|
||||
case 1:
|
||||
z80bank_unused_w(address, data);
|
||||
return;
|
||||
|
||||
case 2: /* Unused */
|
||||
case 3:
|
||||
z80bank_unused_w(address, data);
|
||||
return;
|
||||
|
||||
case 4: /* Unused (lockup) */
|
||||
z80bank_lockup_w(address, data);
|
||||
return;
|
||||
|
||||
case 5: /* Z80, I/O chip, etc. */
|
||||
if(address <= 0xA0FFFF)
|
||||
{
|
||||
z80bank_lockup_w(address, data);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
if(address <= 0xA1001F) io_write((address >> 1) & 0x0F, data);
|
||||
else z80bank_unused_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x11: /* /BUSREQ */
|
||||
if (address & 1) z80bank_unused_w (address, data);
|
||||
else gen_busreq_w (data & 1);
|
||||
return;
|
||||
|
||||
case 0x12: /* /RESET (w) */
|
||||
if (address & 1) z80bank_unused_w (address, data);
|
||||
else gen_reset_w (data & 1);
|
||||
return;
|
||||
|
||||
case 0x10: /* MEMORY MODE */
|
||||
case 0x13: /* TIME */
|
||||
case 0x20: /* ? */
|
||||
case 0x30: /* ? */
|
||||
z80bank_unused_w(address, data);
|
||||
return;
|
||||
|
||||
default: /* Invalid */
|
||||
z80bank_lockup_w(address, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
||||
case 6: /* VDP */
|
||||
z80bank_vdp_w(address, data);
|
||||
return;
|
||||
|
||||
case 7: /* Work RAM */
|
||||
WRITE_BYTE(work_ram, address & 0xFFFF, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int z80_read_banked_memory(unsigned int address)
|
||||
{
|
||||
switch((address >> 21) & 7)
|
||||
{
|
||||
case 0: /* Cartridge ROM */
|
||||
case 1:
|
||||
return READ_BYTE(cart_rom, address);
|
||||
|
||||
case 2: /* Unused */
|
||||
case 3:
|
||||
return z80bank_unused_r(address);
|
||||
|
||||
case 4: /* Unused (lockup) */
|
||||
return z80bank_lockup_r(address);
|
||||
|
||||
case 5: /* Z80, I/O chip, etc.*/
|
||||
if (address <= 0xA0FFFF) return z80bank_lockup_r (address);
|
||||
else
|
||||
{
|
||||
switch((address >> 8) & 0xFF)
|
||||
{
|
||||
case 0x00: /* I/O chip */
|
||||
if (address <= 0xA1001F) return io_read((address >> 1) & 0x0F);
|
||||
else return z80bank_unused_r (address);
|
||||
break;
|
||||
|
||||
case 0x11: /* /BUSACK from Z80 */
|
||||
/* The Z80 can't read this bit (it would be halted
|
||||
when the bit was zero) so we always return '1'. */
|
||||
return 0xFF;
|
||||
|
||||
case 0x10: /* Unused */
|
||||
case 0x12: /* Unused */
|
||||
case 0x13: /* /TIME region */
|
||||
case 0x20: /* Unused */
|
||||
case 0x30: /* Unused */
|
||||
return z80bank_unused_r(address);
|
||||
|
||||
default: /* Lockup */
|
||||
return z80bank_lockup_r(address);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: /* VDP */
|
||||
return z80bank_vdp_r(address);
|
||||
|
||||
case 7: /* Work RAM - can't be read on some Genesis models (!) */
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
|
||||
void z80bank_vdp_w(int address, int data)
|
||||
{
|
||||
if((address & 0xE700E0) == 0xC00000)
|
||||
{
|
||||
switch(address & 0x1F)
|
||||
{
|
||||
case 0x00: /* Data port */
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
vdp_data_w(data << 8 | data);
|
||||
return;
|
||||
|
||||
case 0x04: /* Control port */
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
vdp_ctrl_w(data << 8 | data);
|
||||
return;
|
||||
|
||||
case 0x08: /* Lockup (HVC) */
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0D:
|
||||
case 0x0E:
|
||||
case 0x0F:
|
||||
z80bank_lockup_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x10: /* Unused */
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
case 0x16:
|
||||
z80bank_unused_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x11: /* PSG */
|
||||
case 0x13:
|
||||
case 0x15:
|
||||
case 0x17:
|
||||
psg_write(data);
|
||||
return;
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
z80bank_unused_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x1C: /* Test register */
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
vdp_test_w(data << 8 | data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid VDP address */
|
||||
z80bank_lockup_w(address, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int z80bank_vdp_r(int address)
|
||||
{
|
||||
if((address & 0xE700E0) == 0xC00000)
|
||||
{
|
||||
switch(address & 0x1F)
|
||||
{
|
||||
case 0x00: /* Data */
|
||||
case 0x02:
|
||||
return (vdp_data_r() >> 8) & 0xFF;
|
||||
|
||||
case 0x01: /* Data */
|
||||
case 0x03:
|
||||
return vdp_data_r() & 0xFF;
|
||||
|
||||
case 0x04: /* Control */
|
||||
case 0x06:
|
||||
return (0xFC | (vdp_ctrl_r() >> 8)) & 0xFF;
|
||||
|
||||
case 0x05: /* Control */
|
||||
case 0x07:
|
||||
return vdp_ctrl_r() & 0xFF;
|
||||
|
||||
case 0x08: /* HVC */
|
||||
case 0x0A:
|
||||
case 0x0C:
|
||||
case 0x0E:
|
||||
return (vdp_hvc_r() >> 8) & 0xFF;
|
||||
|
||||
case 0x09: /* HVC */
|
||||
case 0x0B:
|
||||
case 0x0D:
|
||||
case 0x0F:
|
||||
return vdp_hvc_r() & 0xFF;
|
||||
|
||||
case 0x10: /* Lockup */
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
return z80bank_lockup_r(address);
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
case 0x1C:
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
return (z80bank_unused_r(address) | 0xFF);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid VDP address */
|
||||
return z80bank_lockup_r(address);
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Handlers for access to unused addresses and those which make the
|
||||
machine lock up.
|
||||
*/
|
||||
void z80bank_unused_w(int address, int data)
|
||||
{
|
||||
error("Z80 bank unused write %06X = %02X (%04X)\n", address, data, z80_get_reg(Z80_PC));
|
||||
}
|
||||
|
||||
int z80bank_unused_r(int address)
|
||||
{
|
||||
error("Z80 bank unused read %06X (%04X)\n", address, z80_get_reg(Z80_PC));
|
||||
return (address & 1) ? 0x00 : 0xFF;
|
||||
}
|
||||
|
||||
void z80bank_lockup_w(int address, int data)
|
||||
{
|
||||
error("Z80 bank lockup write %06X = %02X (%04X)\n", address, data, z80_get_reg(Z80_PC));
|
||||
gen_running = 0;
|
||||
z80_end_timeslice();
|
||||
}
|
||||
|
||||
int z80bank_lockup_r(int address)
|
||||
{
|
||||
error("Z80 bank lockup read %06X (%04X)\n", address, z80_get_reg(Z80_PC));
|
||||
gen_running = 0;
|
||||
z80_end_timeslice();
|
||||
return 0xFF;
|
||||
}
|
15
source/membnk.h
Normal file
15
source/membnk.h
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
#ifndef _MEMBNK_H_
|
||||
#define _MEMBNK_H_
|
||||
|
||||
/* Function prototypes */
|
||||
void z80_write_banked_memory (unsigned int address, unsigned int data);
|
||||
int z80_read_banked_memory (unsigned int address);
|
||||
void z80bank_vdp_w (int address, int data);
|
||||
int z80bank_vdp_r (int address);
|
||||
void z80bank_unused_w (int address, int data);
|
||||
int z80bank_unused_r (int address);
|
||||
void z80bank_lockup_w (int address, int data);
|
||||
int z80bank_lockup_r (int address);
|
||||
|
||||
#endif /* _MEMBNK_H_ */
|
48
source/memvdp.c
Normal file
48
source/memvdp.c
Normal file
@ -0,0 +1,48 @@
|
||||
/*
|
||||
memvdp.c --
|
||||
Memory handlers for when the VDP reads the V-bus during DMA.
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
unsigned int vdp_dma_r(unsigned int address)
|
||||
{
|
||||
switch((address >> 21) & 7)
|
||||
{
|
||||
case 0: /* Cartridge ROM */
|
||||
case 1:
|
||||
return *(uint16 *)(cart_rom + address);
|
||||
|
||||
case 2: /* Unused */
|
||||
case 3:
|
||||
return 0xFF00;
|
||||
|
||||
case 4: /* Work RAM */
|
||||
case 6:
|
||||
case 7:
|
||||
return *(uint16 *)(work_ram + (address & 0xffff));
|
||||
|
||||
case 5: /* Z80 area and I/O chip */
|
||||
/* Z80 area always returns $FFFF */
|
||||
if(address <= 0xA0FFFF)
|
||||
{
|
||||
/* Return $FFFF only when the Z80 isn't hogging the Z-bus.
|
||||
(e.g. Z80 isn't reset and 68000 has the bus) */
|
||||
return (zbusack == 0) ? 0xFFFF : *(uint16 *)(work_ram + (address & 0xffff));
|
||||
}
|
||||
|
||||
/* The I/O chip and work RAM try to drive the data bus which
|
||||
results in both values being combined in random ways when read.
|
||||
We return the I/O chip values which seem to have precedence, */
|
||||
else if (address <= 0xA1001F)
|
||||
{
|
||||
uint8 temp = io_read((address >> 1) & 0x0F);
|
||||
return (temp << 8 | temp);
|
||||
}
|
||||
/* All remaining locations access work RAM */
|
||||
else return *(uint16 *)(work_ram + (address & 0xffff));
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
8
source/memvdp.h
Normal file
8
source/memvdp.h
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#ifndef _MEMVDP_H_
|
||||
#define _MEMVDP_H_
|
||||
|
||||
/* Function prototypes */
|
||||
unsigned int vdp_dma_r (unsigned int address);
|
||||
|
||||
#endif /* _MEMVDP_H_ */
|
246
source/memz80.c
Normal file
246
source/memz80.c
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
memz80.c --
|
||||
Memory handlers for Z80 memory and port access, and the Z80 to
|
||||
VDP interface.
|
||||
*/
|
||||
|
||||
#define LOG_PORT 0 /* 1= Log Z80 I/O port accesses */
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
|
||||
unsigned int cpu_readmem16(unsigned int address)
|
||||
{
|
||||
switch((address >> 13) & 7)
|
||||
{
|
||||
case 0: /* Work RAM */
|
||||
case 1:
|
||||
return zram[address & 0x1FFF];
|
||||
|
||||
case 2: /* YM2612 */
|
||||
return fm_read(address & 3);
|
||||
|
||||
case 3: /* VDP */
|
||||
if ((address & 0xFF00) == 0x7F00) return z80_vdp_r (address);
|
||||
return 0xFF;
|
||||
|
||||
default: /* V-bus bank */
|
||||
return z80_read_banked_memory(zbank | (address & 0x7FFF));
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
void cpu_writemem16(unsigned int address, unsigned int data)
|
||||
{
|
||||
switch((address >> 13) & 7)
|
||||
{
|
||||
case 0: /* Work RAM */
|
||||
case 1:
|
||||
zram[address & 0x1FFF] = data;
|
||||
return;
|
||||
|
||||
case 2: /* YM2612 */
|
||||
fm_write(address & 3, data);
|
||||
return;
|
||||
|
||||
case 3: /* Bank register and VDP */
|
||||
switch(address & 0xFF00)
|
||||
{
|
||||
case 0x6000:
|
||||
gen_bank_w(data & 1);
|
||||
return;
|
||||
|
||||
case 0x7F00:
|
||||
z80_vdp_w(address, data);
|
||||
return;
|
||||
|
||||
default:
|
||||
z80_unused_w(address, data);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
default: /* V-bus bank */
|
||||
z80_write_banked_memory(zbank | (address & 0x7FFF), data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int z80_vdp_r(int address)
|
||||
{
|
||||
switch(address & 0xFF)
|
||||
{
|
||||
case 0x00: /* VDP data port */
|
||||
case 0x02:
|
||||
return (vdp_data_r() >> 8) & 0xFF;
|
||||
|
||||
case 0x01: /* VDP data port */
|
||||
case 0x03:
|
||||
return (vdp_data_r() & 0xFF);
|
||||
|
||||
case 0x04: /* VDP control port */
|
||||
case 0x06:
|
||||
return (0xFF | ((vdp_ctrl_r() >> 8) & 3));
|
||||
|
||||
case 0x05: /* VDP control port */
|
||||
case 0x07:
|
||||
return (vdp_ctrl_r() & 0xFF);
|
||||
|
||||
case 0x08: /* HV counter */
|
||||
case 0x0A:
|
||||
case 0x0C:
|
||||
case 0x0E:
|
||||
return (vdp_hvc_r() >> 8) & 0xFF;
|
||||
|
||||
case 0x09: /* HV counter */
|
||||
case 0x0B:
|
||||
case 0x0D:
|
||||
case 0x0F:
|
||||
return (vdp_hvc_r() & 0xFF);
|
||||
|
||||
case 0x10: /* Unused (PSG) */
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
case 0x13:
|
||||
case 0x14:
|
||||
case 0x15:
|
||||
case 0x16:
|
||||
case 0x17:
|
||||
return z80_lockup_r(address);
|
||||
|
||||
case 0x18: /* Unused */
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
return z80_unused_r(address);
|
||||
|
||||
case 0x1C: /* Unused (test register) */
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
return z80_unused_r(address);
|
||||
|
||||
default: /* Invalid VDP addresses */
|
||||
return z80_lockup_r(address);
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
|
||||
void z80_vdp_w(int address, int data)
|
||||
{
|
||||
switch(address & 0xFF)
|
||||
{
|
||||
case 0x00: /* VDP data port */
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
case 0x03:
|
||||
vdp_data_w(data << 8 | data);
|
||||
return;
|
||||
|
||||
case 0x04: /* VDP control port */
|
||||
case 0x05:
|
||||
case 0x06:
|
||||
case 0x07:
|
||||
vdp_ctrl_w(data << 8 | data);
|
||||
return;
|
||||
|
||||
case 0x08: /* Unused (HV counter) */
|
||||
case 0x09:
|
||||
case 0x0A:
|
||||
case 0x0B:
|
||||
case 0x0C:
|
||||
case 0x0D:
|
||||
case 0x0E:
|
||||
case 0x0F:
|
||||
z80_lockup_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x11: /* PSG */
|
||||
case 0x13:
|
||||
case 0x15:
|
||||
case 0x17:
|
||||
psg_write(data);
|
||||
return;
|
||||
|
||||
case 0x10: /* Unused */
|
||||
case 0x12:
|
||||
case 0x14:
|
||||
case 0x16:
|
||||
case 0x18:
|
||||
case 0x19:
|
||||
case 0x1A:
|
||||
case 0x1B:
|
||||
z80_unused_w(address, data);
|
||||
return;
|
||||
|
||||
case 0x1C: /* Test register */
|
||||
case 0x1D:
|
||||
case 0x1E:
|
||||
case 0x1F:
|
||||
vdp_test_w(data << 8 | data);
|
||||
return;
|
||||
|
||||
default: /* Invalid VDP addresses */
|
||||
z80_lockup_w(address, data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Port handlers. Ports are unused when not in Mark III compatability mode.
|
||||
|
||||
Games that access ports anyway:
|
||||
- Thunder Force IV reads port $BF in it's interrupt handler.
|
||||
*/
|
||||
|
||||
unsigned int cpu_readport16(unsigned int port)
|
||||
{
|
||||
#if LOG_PORT
|
||||
error("Z80 read port %04X (%04X)\n", port, z80_get_reg(Z80_PC));
|
||||
#endif
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void cpu_writeport16(unsigned int port, unsigned int data)
|
||||
{
|
||||
#if LOG_PORT
|
||||
error("Z80 write %02X to port %04X (%04X)\n", data, port, z80_get_reg(Z80_PC));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Handlers for access to unused addresses and those which make the
|
||||
machine lock up.
|
||||
*/
|
||||
void z80_unused_w(int address, int data)
|
||||
{
|
||||
error("Z80 unused write %04X = %02X (%04X)\n", address, data, z80_get_reg(Z80_PC));
|
||||
}
|
||||
|
||||
int z80_unused_r(int address)
|
||||
{
|
||||
error("Z80 unused read %04X (%04X)\n", address, z80_get_reg(Z80_PC));
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
void z80_lockup_w(int address, int data)
|
||||
{
|
||||
error("Z80 lockup write %04X = %02X (%04X)\n", address, data, z80_get_reg(Z80_PC));
|
||||
gen_running = 0;
|
||||
z80_end_timeslice();
|
||||
}
|
||||
|
||||
int z80_lockup_r(int address)
|
||||
{
|
||||
error("Z80 lockup read %04X (%04X)\n", address, z80_get_reg(Z80_PC));
|
||||
gen_running = 0;
|
||||
z80_end_timeslice();
|
||||
return 0xFF;
|
||||
}
|
17
source/memz80.h
Normal file
17
source/memz80.h
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
#ifndef _MEMZ80_H_
|
||||
#define _MEMZ80_H_
|
||||
|
||||
/* Function prototypes */
|
||||
unsigned int cpu_readmem16 (unsigned int address);
|
||||
void cpu_writemem16 (unsigned int address, unsigned int data);
|
||||
unsigned int cpu_readport16 (unsigned int port);
|
||||
void cpu_writeport16 (unsigned int port, unsigned int data);
|
||||
void z80_unused_w (int address, int data);
|
||||
int z80_unused_r (int address);
|
||||
void z80_lockup_w (int address, int data);
|
||||
int z80_lockup_r (int address);
|
||||
int z80_vdp_r (int address);
|
||||
void z80_vdp_w (int address, int data);
|
||||
|
||||
#endif /* _MEMZ80_H_ */
|
85
source/ngc/gcaram.c
Normal file
85
source/ngc/gcaram.c
Normal file
@ -0,0 +1,85 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
|
||||
#define ARAMSTART 0x8000
|
||||
|
||||
/**
|
||||
* Nintendo GameCube ARAM Wrapper for libOGC aram.c
|
||||
*
|
||||
* This is an often overlooked area of ~16Mb extra RAM
|
||||
* It's use in Genesis Plus is to shadow the ROM.
|
||||
* Actually, only SSF2TNC needs shadowing, but it's always
|
||||
* Good to know :)
|
||||
*/
|
||||
|
||||
#define ARAM_READ 1
|
||||
#define ARAM_WRITE 0
|
||||
|
||||
/**
|
||||
* StartARAM
|
||||
* This simply sets up the call to internal libOGC.
|
||||
* Passing NULL for array list, and 0 items to allocate.
|
||||
* Required so libOGC knows to handle any interrupts etc.
|
||||
*/
|
||||
void
|
||||
StartARAM ()
|
||||
{
|
||||
AR_Init (NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* ARAMPut
|
||||
*
|
||||
* Move data from MAIN memory to ARAM
|
||||
*/
|
||||
void
|
||||
ARAMPut (char *src, char *dst, int len)
|
||||
{
|
||||
DCFlushRange (src, len);
|
||||
AR_StartDMA( ARAM_WRITE, (u32)src, (u32)dst, len);
|
||||
while (AR_GetDMAStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* ARAMFetch
|
||||
*
|
||||
* This function will move data from ARAM to MAIN memory
|
||||
*/
|
||||
void
|
||||
ARAMFetch (char *dst, char *src, int len)
|
||||
{
|
||||
DCInvalidateRange(dst, len);
|
||||
AR_StartDMA( ARAM_READ, (u32) dst, (u32) src, len);
|
||||
while (AR_GetDMAStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* ShadowROM
|
||||
* Copy the rom from cart_rom into ARAM
|
||||
* NB: libOGC appears to use the first 0x4000 bytes.
|
||||
* As there's plenty left, all ARAM addresses are 0x8000 based.
|
||||
* Here, the ROM is simply copied in one swift movement :)
|
||||
*/
|
||||
void
|
||||
ShadowROM ()
|
||||
{
|
||||
ARAMPut (cart_rom, (void *) ARAMSTART, genromsize);
|
||||
}
|
25
source/ngc/gcaram.h
Normal file
25
source/ngc/gcaram.h
Normal file
@ -0,0 +1,25 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
|
||||
extern void StartARAM ();
|
||||
void ShadowROM ();
|
||||
void ARAMFetch (char *src, char *dst, int len);
|
||||
void ARAMPut (char *src, char *dst, int len);
|
||||
|
208
source/ngc/gui/confjoy.c
Normal file
208
source/ngc/gui/confjoy.c
Normal file
@ -0,0 +1,208 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* NGC - Joypad Configuration
|
||||
***************************************************************************/
|
||||
#include <shared.h>
|
||||
|
||||
extern int domenu (char items[][20], int maxitems);
|
||||
extern unsigned short gcpadmap[];
|
||||
extern int menu;
|
||||
extern char menutitle[];
|
||||
extern int padcal;
|
||||
extern void reloadrom();
|
||||
|
||||
int configpadcount = 11;
|
||||
char padmenu[11][20] = {
|
||||
{"Genesis A - B"},
|
||||
{"Genesis B - A"},
|
||||
{"Genesis C - X"},
|
||||
{"Genesis X - TL"},
|
||||
{"Genesis Y - Y"},
|
||||
{"Genesis Z - TR"},
|
||||
{"Analog - 70"},
|
||||
{"Type - 3BUTTONS"},
|
||||
{"PortA - GAMEPAD"},
|
||||
{"PortB - GAMEPAD"},
|
||||
{" Exit Config "}
|
||||
};
|
||||
|
||||
uint8 mpads[6] = {0, 1, 2, 3, 4, 5 }; /*** Default Mapping ***/
|
||||
uint8 sys_type[2] = {0,0};
|
||||
uint8 old_sys_type[2] = {0,0};
|
||||
|
||||
/****************************************************************************
|
||||
* UpdatePadMaps
|
||||
****************************************************************************/
|
||||
void UpdatePadMaps (uint8 padvalue, int padnum)
|
||||
{
|
||||
padmenu[padnum][15] = ' ';
|
||||
padmenu[padnum][16] = ' ';
|
||||
switch (padvalue)
|
||||
{
|
||||
case 0:
|
||||
gcpadmap[padnum] = PAD_BUTTON_B;
|
||||
padmenu[padnum][16] = 'B';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
gcpadmap[padnum] = PAD_BUTTON_A;
|
||||
padmenu[padnum][16] = 'A';
|
||||
break;
|
||||
|
||||
case 2:
|
||||
gcpadmap[padnum] = PAD_BUTTON_X;
|
||||
padmenu[padnum][16] = 'X';
|
||||
break;
|
||||
|
||||
case 3:
|
||||
gcpadmap[padnum] = PAD_TRIGGER_R;
|
||||
padmenu[padnum][15] = 'T';
|
||||
padmenu[padnum][16] = 'R';
|
||||
break;
|
||||
|
||||
case 4:
|
||||
gcpadmap[padnum] = PAD_BUTTON_Y;
|
||||
padmenu[padnum][16] = 'Y';
|
||||
break;
|
||||
|
||||
case 5:
|
||||
gcpadmap[padnum] = PAD_TRIGGER_L;
|
||||
padmenu[padnum][15] = 'T';
|
||||
padmenu[padnum][16] = 'L';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* ConfigureJoypads
|
||||
****************************************************************************/
|
||||
void ConfigureJoypads ()
|
||||
{
|
||||
int ret;
|
||||
int quit = 0;
|
||||
int prevmenu = menu;
|
||||
|
||||
strcpy (menutitle, "");
|
||||
|
||||
if (pad_type) sprintf (padmenu[7], "Type - 6BUTTONS");
|
||||
else sprintf (padmenu[7], "Type - 3BUTTONS");
|
||||
|
||||
if (input.system[1] == SYSTEM_MENACER) sprintf (padmenu[8], "PortA - NONE");
|
||||
else if (sys_type[0] == 0) sprintf (padmenu[8], "PortA - GAMEPAD");
|
||||
else if (sys_type[0] == 1) sprintf (padmenu[8], "PortA - MULTITAP");
|
||||
else if (sys_type[0] == 2) sprintf (padmenu[8], "PortA - NONE");
|
||||
|
||||
if (input.system[1] == SYSTEM_MENACER) sprintf (padmenu[9], "PortB - MENACER");
|
||||
else if (sys_type[1] == 0) sprintf (padmenu[9], "PortB - GAMEPAD");
|
||||
else if (sys_type[1] == 1) sprintf (padmenu[9], "PortB - MULTITAP");
|
||||
else if (sys_type[1] == 2) sprintf (padmenu[9], "PortB - NONE");
|
||||
|
||||
menu = 0;
|
||||
while (quit == 0)
|
||||
{
|
||||
ret = domenu (&padmenu[0], configpadcount);
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
mpads[ret]++;
|
||||
if (mpads[ret] > 5) mpads[ret] = 0;
|
||||
UpdatePadMaps (mpads[ret], ret);
|
||||
break;
|
||||
|
||||
case 6: /*** Pad calibrate analog ***/
|
||||
case -8:
|
||||
if (ret>0) padcal += 2;
|
||||
else padcal -= 2;
|
||||
if (padcal > 90) padcal = 0;
|
||||
if (padcal < 0) padcal = 90;
|
||||
sprintf (padmenu[6], "Analog - %02d", padcal);
|
||||
break;
|
||||
|
||||
case 7:
|
||||
pad_type ^= 1;
|
||||
if (pad_type) sprintf (padmenu[7], "Type - 6BUTTONS");
|
||||
else sprintf (padmenu[7], "Type - 3BUTTONS");
|
||||
system_reset();
|
||||
break;
|
||||
|
||||
case 8:
|
||||
if (input.system[1] == SYSTEM_MENACER) break;
|
||||
sys_type[0] ++;
|
||||
if (sys_type[0] > 2) sys_type[0] = 0;
|
||||
|
||||
if (sys_type[0] == 0)
|
||||
{
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
sprintf (padmenu[8], "PortA - GAMEPAD");
|
||||
}
|
||||
else if (sys_type[0] == 1)
|
||||
{
|
||||
input.system[0] = SYSTEM_TEAMPLAYER;
|
||||
sprintf (padmenu[8], "PortA - MULTITAP");
|
||||
}
|
||||
else if (sys_type[0] == 2)
|
||||
{
|
||||
input.system[0] = NO_SYSTEM;
|
||||
sprintf (padmenu[8], "PortA - NONE");
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
if (input.system[1] == SYSTEM_MENACER) break;
|
||||
sys_type[1] ++;
|
||||
if (sys_type[1] > 2) sys_type[1] = 0;
|
||||
|
||||
if (sys_type[1] == 0)
|
||||
{
|
||||
input.system[1] = SYSTEM_GAMEPAD;
|
||||
sprintf (padmenu[9], "PortB - GAMEPAD");
|
||||
}
|
||||
else if (sys_type[1] == 1)
|
||||
{
|
||||
input.system[1] = SYSTEM_TEAMPLAYER;
|
||||
sprintf (padmenu[9], "PortB - MULTITAP");
|
||||
}
|
||||
else if (sys_type[1] == 2)
|
||||
{
|
||||
input.system[1] = NO_SYSTEM;
|
||||
sprintf (padmenu[9], "PortB - NONE");
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
case -1:
|
||||
if ((old_sys_type[0] != sys_type[0]) || (old_sys_type[1] != sys_type[1]))
|
||||
{
|
||||
old_sys_type[0] = sys_type[0];
|
||||
old_sys_type[1] = sys_type[1];
|
||||
system_reset();
|
||||
}
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
menu = prevmenu;
|
||||
}
|
877
source/ngc/gui/dkpro.h
Normal file
877
source/ngc/gui/dkpro.h
Normal file
@ -0,0 +1,877 @@
|
||||
/*******************************************************************
|
||||
* Image File : /public/dkpro.bmp
|
||||
* Width : 218
|
||||
* Height : 65
|
||||
*
|
||||
* This header contains a compressed Zip image.
|
||||
* Use zlib1.2.3 uncompress function to restore.
|
||||
*******************************************************************/
|
||||
|
||||
#define dkpro_RAW 28340
|
||||
#define dkpro_COMPRESSED 6887
|
||||
#define dkpro_WIDTH 218
|
||||
#define dkpro_HEIGHT 65
|
||||
|
||||
unsigned char dkpro[6887] = {
|
||||
0x78, 0xda, 0xed, 0x9c, 0x67, 0x70, 0x54, 0x57, 0x96, 0xc7, 0xf9, 0xb8,
|
||||
0xb5, 0x55, 0xbb, 0x55,
|
||||
0x53, 0xb5, 0xb5, 0xb3, 0x9e, 0x31, 0xc6, 0x98, 0x20, 0x31, 0xf6, 0x38,
|
||||
0x7b, 0xc6, 0x33, 0x0e,
|
||||
0xe3, 0x34, 0x60, 0x03, 0x36, 0xc9, 0x80, 0x49, 0xb6, 0x41, 0x42, 0x59,
|
||||
0x42, 0x39, 0x20, 0x75,
|
||||
0xbf, 0xd3, 0x92, 0x90, 0x84, 0x32, 0x41, 0x02, 0x11, 0xd4, 0x48, 0xe4,
|
||||
0x60, 0x72, 0x0e, 0x22,
|
||||
0x98, 0x8c, 0x8d, 0x04, 0x26, 0x83, 0x31, 0xe0, 0xec, 0x71, 0x06, 0xe7,
|
||||
0xa0, 0xfd, 0xdd, 0xdb,
|
||||
0xdd, 0xaf, 0x5f, 0xb7, 0xba, 0x07, 0x30, 0xc6, 0xf6, 0x87, 0xd6, 0xbf,
|
||||
0x1e, 0xb4, 0x6e, 0x38,
|
||||
0xf7, 0xe4, 0x7b, 0xee, 0x7b, 0x4f, 0xdd, 0x4e, 0xda, 0x5d, 0x1d, 0xaa,
|
||||
0xc3, 0x52, 0xba, 0x38,
|
||||
0x3b, 0x46, 0x75, 0x70, 0xb6, 0x8f, 0xbd, 0xb1, 0xfe, 0xc6, 0xf8, 0x3f,
|
||||
0x3a, 0x6f, 0x8c, 0x6f,
|
||||
0xef, 0xbc, 0x29, 0xb6, 0xa3, 0xb3, 0x53, 0x74, 0x57, 0x67, 0xb7, 0x88,
|
||||
0x76, 0x12, 0xc2, 0x6f,
|
||||
0x06, 0x55, 0xe1, 0xd8, 0xea, 0xe6, 0xa8, 0x3f, 0x38, 0xc3, 0x62, 0xfa,
|
||||
0xd5, 0x94, 0xc4, 0x2f,
|
||||
0x28, 0xdd, 0x91, 0x71, 0x74, 0xdc, 0xf9, 0xdc, 0x0b, 0x85, 0xa7, 0x72,
|
||||
0x0f, 0x8c, 0x5f, 0x95,
|
||||
0x59, 0x37, 0x29, 0x32, 0xf1, 0xfe, 0xfa, 0x3f, 0xc4, 0xb4, 0x77, 0x76,
|
||||
0x8a, 0x09, 0x9b, 0x15,
|
||||
0xb2, 0xdd, 0xaf, 0x6f, 0xaf, 0xb0, 0x94, 0x9b, 0x89, 0xa3, 0xbe, 0x93,
|
||||
0x9d, 0x09, 0xef, 0x39,
|
||||
0x5a, 0xed, 0xad, 0x12, 0x0c, 0x3f, 0xca, 0x8e, 0xca, 0x84, 0x94, 0xdb,
|
||||
0x9d, 0xed, 0xa3, 0xba,
|
||||
0x84, 0xec, 0xf6, 0x6b, 0xda, 0x2b, 0xf5, 0x26, 0x67, 0x58, 0x74, 0xe5,
|
||||
0xf8, 0x7f, 0x65, 0x6a,
|
||||
0xab, 0x18, 0xdf, 0x49, 0x50, 0x18, 0x3f, 0xb8, 0x6c, 0x37, 0x6e, 0x5d,
|
||||
0xee, 0xd3, 0x33, 0x6e,
|
||||
0x88, 0xeb, 0xec, 0xec, 0x16, 0x19, 0xd2, 0xe0, 0x2f, 0x9f, 0x0f, 0x3b,
|
||||
0xd4, 0xdf, 0x1b, 0x35,
|
||||
0xaf, 0xa8, 0x75, 0x6c, 0x2b, 0xf6, 0xf8, 0xc6, 0xf8, 0x46, 0x3c, 0xf8,
|
||||
0x9e, 0x98, 0xf2, 0x46,
|
||||
0xd7, 0x0f, 0xf2, 0xad, 0x78, 0xfb, 0xbe, 0x33, 0x68, 0xcd, 0x3f, 0x69,
|
||||
0x1b, 0x36, 0xfd, 0xa6,
|
||||
0xd8, 0x2e, 0xd5, 0xed, 0x52, 0x43, 0x9a, 0xfc, 0x85, 0x50, 0xdd, 0x2d,
|
||||
0xa5, 0xb3, 0xb3, 0x43,
|
||||
0x74, 0x69, 0x49, 0x6b, 0x76, 0xab, 0xf1, 0xb5, 0x7c, 0xa5, 0xa1, 0x6c,
|
||||
0xe5, 0xb2, 0xd3, 0x27,
|
||||
0x72, 0x52, 0xf6, 0xcb, 0x36, 0x69, 0x92, 0x5d, 0x72, 0x48, 0xde, 0x96,
|
||||
0x1f, 0xdc, 0xd6, 0xfb,
|
||||
0x56, 0xdc, 0x63, 0x0d, 0x6c, 0x5a, 0xb0, 0x3b, 0xef, 0xfe, 0xfa, 0x9b,
|
||||
0xa2, 0xc3, 0xab, 0xda,
|
||||
0xa5, 0x84, 0x34, 0x7a, 0xfd, 0xd1, 0xcd, 0xd9, 0x61, 0x74, 0x8f, 0xca,
|
||||
0x8f, 0x53, 0x5b, 0x8d,
|
||||
0xaf, 0xe4, 0x4b, 0x8d, 0x6f, 0xb0, 0xc9, 0xb7, 0x72, 0x5c, 0xe6, 0x48,
|
||||
0x86, 0x3c, 0x2b, 0x4f,
|
||||
0x4b, 0x5f, 0xe9, 0x2f, 0x03, 0x40, 0x7f, 0xe9, 0x27, 0x7d, 0xf8, 0x3d,
|
||||
0x5a, 0x2a, 0x65, 0x27,
|
||||
0xb6, 0x6c, 0xc5, 0xae, 0xae, 0x19, 0x5f, 0x2a, 0xbb, 0x95, 0x8c, 0xcf,
|
||||
0xea, 0xe8, 0x0c, 0x8b,
|
||||
0x0a, 0x69, 0xf4, 0x7a, 0xc7, 0x58, 0x58, 0xca, 0x1f, 0xa7, 0x94, 0x24,
|
||||
0xfd, 0x68, 0xff, 0x46,
|
||||
0x2e, 0x6a, 0x7c, 0x85, 0x25, 0x3e, 0x90, 0x06, 0x19, 0x8d, 0xb5, 0x06,
|
||||
0xcb, 0x70, 0x79, 0x41,
|
||||
0x5e, 0x6c, 0x83, 0x11, 0x32, 0x84, 0xde, 0x61, 0x32, 0x4e, 0x5e, 0xd5,
|
||||
0xd6, 0xbd, 0xa4, 0x67,
|
||||
0x5e, 0x22, 0x4f, 0x1e, 0x9a, 0x78, 0x4b, 0xca, 0xef, 0x9d, 0x37, 0x24,
|
||||
0xdd, 0xe0, 0xbc, 0x21,
|
||||
0x31, 0x74, 0x5d, 0xdb, 0xd5, 0xa1, 0xaa, 0x5d, 0x7a, 0x20, 0x9b, 0x85,
|
||||
0xcd, 0xea, 0x34, 0x7a,
|
||||
0x4d, 0x61, 0x6b, 0xee, 0xe7, 0xc6, 0x67, 0xf2, 0x99, 0x7c, 0x4e, 0xdc,
|
||||
0x9c, 0x93, 0x72, 0xe2,
|
||||
0x69, 0x08, 0x96, 0x19, 0x75, 0x19, 0x8c, 0xc4, 0x76, 0x03, 0x24, 0x81,
|
||||
0xac, 0xf9, 0x9d, 0x7c,
|
||||
0x21, 0x9f, 0x69, 0x7c, 0x65, 0x04, 0xaf, 0x34, 0x43, 0xb8, 0x3a, 0xac,
|
||||
0x99, 0xdc, 0x21, 0xb9,
|
||||
0x6d, 0xdd, 0xd1, 0x35, 0xb5, 0xc3, 0xc4, 0xe6, 0x94, 0xef, 0xed, 0x9f,
|
||||
0x88, 0xc2, 0x25, 0x62,
|
||||
0xac, 0x51, 0x86, 0x62, 0x89, 0xc8, 0xab, 0xc0, 0x48, 0x79, 0x4e, 0xc6,
|
||||
0xca, 0x19, 0xec, 0xf6,
|
||||
0xa9, 0x7c, 0x12, 0xc2, 0xcf, 0x05, 0xea, 0x8a, 0x39, 0x35, 0x1d, 0x92,
|
||||
0xda, 0xc6, 0x58, 0x97,
|
||||
0xc8, 0x23, 0xf2, 0x95, 0xfd, 0x43, 0x51, 0xf8, 0x42, 0x8e, 0x92, 0x0f,
|
||||
0x87, 0x73, 0x45, 0x5d,
|
||||
0x35, 0x46, 0x92, 0x45, 0x17, 0x90, 0x1d, 0x3f, 0x96, 0x0f, 0x43, 0xf8,
|
||||
0x79, 0x60, 0x7c, 0x21,
|
||||
0x8d, 0x35, 0x37, 0x27, 0xf9, 0xd7, 0xf6, 0xed, 0x27, 0xee, 0x4e, 0xbd,
|
||||
0x64, 0x7f, 0x5f, 0xde,
|
||||
0x67, 0xff, 0xfa, 0x5a, 0x56, 0x90, 0x0d, 0x47, 0x4b, 0xec, 0x4f, 0x44,
|
||||
0x8c, 0x3c, 0x2f, 0x42,
|
||||
0xa4, 0xaa, 0x5a, 0x32, 0x84, 0x6b, 0xc3, 0x87, 0x58, 0xe4, 0x7d, 0xe3,
|
||||
0x73, 0x69, 0xf0, 0xb3,
|
||||
0x99, 0xaa, 0x15, 0xe7, 0x17, 0x7c, 0x99, 0xf7, 0xae, 0xbc, 0x2b, 0xef,
|
||||
0x11, 0x8b, 0x33, 0x89,
|
||||
0xb0, 0x38, 0x89, 0xbf, 0x26, 0x44, 0x63, 0x37, 0xb5, 0xcb, 0x85, 0x70,
|
||||
0x2d, 0x18, 0x28, 0x47,
|
||||
0x88, 0xa1, 0x77, 0x8d, 0x4f, 0xc5, 0xe9, 0x67, 0xb3, 0x9b, 0xa7, 0x66,
|
||||
0xc4, 0x7d, 0x61, 0x7f,
|
||||
0xdb, 0xf1, 0x16, 0xe7, 0xad, 0xcf, 0x64, 0xaa, 0x44, 0x48, 0xa2, 0x24,
|
||||
0x5d, 0x33, 0x12, 0x43,
|
||||
0xb8, 0x66, 0x8c, 0x94, 0x63, 0xc4, 0xd1, 0x5b, 0xc6, 0x47, 0x52, 0x6f,
|
||||
0xb5, 0x59, 0x75, 0x97,
|
||||
0xd4, 0xbf, 0x95, 0x5f, 0x4c, 0xbf, 0x60, 0x9c, 0x97, 0xf3, 0xd8, 0x74,
|
||||
0x16, 0x95, 0x44, 0x4a,
|
||||
0x08, 0xbf, 0x11, 0x44, 0xc9, 0x6b, 0xf2, 0x96, 0x9c, 0x37, 0x3e, 0x90,
|
||||
0xe9, 0x35, 0x1d, 0x4d,
|
||||
0x9b, 0x85, 0x3b, 0x3b, 0x8e, 0xde, 0xe6, 0x78, 0xdb, 0x7e, 0x56, 0xce,
|
||||
0x62, 0xd1, 0xd5, 0xec,
|
||||
0x46, 0x69, 0x57, 0x81, 0x74, 0x13, 0x69, 0xd7, 0x1d, 0xe9, 0x57, 0xb9,
|
||||
0x5a, 0xaa, 0xbe, 0x52,
|
||||
0xaf, 0x61, 0x95, 0xf4, 0x5f, 0x54, 0xbe, 0x40, 0x88, 0x91, 0x43, 0x44,
|
||||
0xd2, 0x59, 0xe3, 0x5d,
|
||||
0x99, 0x66, 0xb1, 0xd9, 0x2d, 0x75, 0xa9, 0x71, 0x1f, 0xd8, 0x4f, 0x3b,
|
||||
0x4e, 0xcb, 0x1b, 0xd2,
|
||||
0xcc, 0xf9, 0x2a, 0x53, 0xb2, 0xae, 0x10, 0x99, 0x3e, 0x92, 0xa4, 0x4b,
|
||||
0xc6, 0x15, 0xcf, 0xbc,
|
||||
0x7a, 0x64, 0xfa, 0x69, 0x2d, 0xfd, 0xdf, 0xf2, 0x99, 0x89, 0xa5, 0xd4,
|
||||
0x8e, 0xea, 0xaa, 0x63,
|
||||
0xa3, 0xf1, 0xc3, 0x64, 0x66, 0x5c, 0xfd, 0x2a, 0x69, 0x7e, 0xf2, 0x65,
|
||||
0x5e, 0x47, 0x09, 0x03,
|
||||
0x23, 0x41, 0x0e, 0x12, 0x4b, 0xa7, 0x8d, 0x37, 0x65, 0xaa, 0xc7, 0x66,
|
||||
0xd4, 0x8b, 0xb7, 0x54,
|
||||
0x9d, 0x4d, 0x3f, 0x65, 0x9c, 0x90, 0x93, 0xf4, 0x8d, 0x83, 0xab, 0xb1,
|
||||
0x57, 0x88, 0x2c, 0x19,
|
||||
0x23, 0x2f, 0xc8, 0x30, 0xce, 0xdb, 0x0a, 0xc3, 0xa9, 0x33, 0xd3, 0x25,
|
||||
0xfb, 0x8a, 0x67, 0x5f,
|
||||
0x1d, 0x72, 0xd0, 0x57, 0x2c, 0x27, 0xc5, 0xa1, 0xe6, 0x6a, 0xa3, 0x69,
|
||||
0xc9, 0x09, 0x3a, 0x3e,
|
||||
0x93, 0x9d, 0x40, 0x5d, 0xb1, 0x54, 0x52, 0xb1, 0x58, 0x2f, 0x8d, 0x2c,
|
||||
0x93, 0xa6, 0xc7, 0xe7,
|
||||
0xc0, 0xa3, 0xb2, 0x4d, 0x86, 0x86, 0xb2, 0x81, 0x97, 0xe7, 0x6c, 0x2c,
|
||||
0xfd, 0xa2, 0x29, 0x91,
|
||||
0x15, 0x43, 0x59, 0xf1, 0x79, 0xf6, 0x0c, 0x65, 0xfb, 0x8c, 0xeb, 0x26,
|
||||
0x65, 0x20, 0x24, 0xcb,
|
||||
0x2b, 0x72, 0x5a, 0x4e, 0xb0, 0x6f, 0xd5, 0xd6, 0xba, 0x6c, 0xd6, 0x6d,
|
||||
0x56, 0xc7, 0x48, 0x5b,
|
||||
0xd1, 0xf9, 0x9c, 0x23, 0x54, 0x27, 0xa7, 0x39, 0x53, 0x65, 0x88, 0xed,
|
||||
0x8a, 0xa1, 0xfc, 0x6e,
|
||||
0xbf, 0x6c, 0x91, 0xcd, 0x1a, 0x4d, 0xf2, 0x2a, 0x3a, 0xcd, 0x11, 0xfb,
|
||||
0x55, 0x50, 0xb8, 0x72,
|
||||
0xe4, 0xa2, 0x77, 0xa7, 0xec, 0x34, 0x57, 0xdb, 0x2e, 0x6b, 0xa9, 0x93,
|
||||
0xc6, 0x06, 0x1d, 0x9f,
|
||||
0x49, 0x74, 0xf9, 0xde, 0x45, 0xa8, 0x46, 0xe3, 0x36, 0xb8, 0xcb, 0xc1,
|
||||
0xd3, 0x46, 0x70, 0xee,
|
||||
0x1f, 0xa4, 0x31, 0x84, 0x3d, 0x3e, 0x03, 0xea, 0x36, 0xdd, 0x97, 0xc9,
|
||||
0x2a, 0x07, 0x90, 0x64,
|
||||
0x73, 0x1b, 0x34, 0xc9, 0x4a, 0x99, 0x27, 0xe5, 0xd8, 0x7d, 0x04, 0x67,
|
||||
0xcf, 0x04, 0x2c, 0x9d,
|
||||
0x7b, 0x5d, 0xe4, 0x0c, 0xa4, 0xe5, 0xfd, 0x72, 0x5c, 0x8e, 0x18, 0x67,
|
||||
0x64, 0xb2, 0x3b, 0xce,
|
||||
0xc2, 0x9d, 0x5d, 0x22, 0x0f, 0x18, 0x47, 0x8c, 0x43, 0x72, 0x98, 0xbd,
|
||||
0x6e, 0xac, 0x18, 0x72,
|
||||
0xa5, 0x3f, 0x06, 0x3e, 0x99, 0xe2, 0xa7, 0x97, 0xdb, 0xd0, 0xc8, 0xf5,
|
||||
0xf9, 0xb1, 0xa1, 0xdb,
|
||||
0x26, 0x9f, 0xb5, 0xde, 0x94, 0x87, 0xd0, 0x72, 0xb0, 0x9f, 0x4c, 0xa2,
|
||||
0xe2, 0x0b, 0xf9, 0xc1,
|
||||
0x7c, 0xbe, 0xd7, 0x0a, 0xb7, 0x23, 0x34, 0xd7, 0x69, 0x52, 0x88, 0x77,
|
||||
0x36, 0xbb, 0x71, 0x48,
|
||||
0x5a, 0x88, 0x44, 0x97, 0xdc, 0x06, 0xd6, 0x7b, 0xfe, 0xb2, 0x77, 0x90,
|
||||
0xbe, 0xc6, 0xaa, 0xd1,
|
||||
0xc4, 0x62, 0x16, 0x3c, 0xfd, 0x12, 0x3f, 0x59, 0xb2, 0x07, 0xcb, 0x1c,
|
||||
0x32, 0x4e, 0xca, 0xc4,
|
||||
0x9a, 0x8e, 0x89, 0xca, 0x66, 0x9d, 0xa7, 0x45, 0xc4, 0xbe, 0x6e, 0x6f,
|
||||
0x76, 0x34, 0x13, 0x67,
|
||||
0x0d, 0x70, 0x5d, 0x70, 0x85, 0x28, 0xe4, 0x4a, 0xc3, 0x2b, 0x5b, 0x3d,
|
||||
0xf7, 0xf1, 0x41, 0xab,
|
||||
0xfc, 0x51, 0xf2, 0xe8, 0x29, 0xbc, 0x62, 0x2a, 0x57, 0xbe, 0x9a, 0x90,
|
||||
0xb3, 0x56, 0xc9, 0x8f,
|
||||
0xe6, 0x5a, 0xdf, 0xc9, 0x51, 0xb9, 0x5b, 0xf2, 0x03, 0xae, 0xa5, 0xda,
|
||||
0x72, 0xb0, 0xd0, 0xa7,
|
||||
0xe8, 0xd7, 0xcb, 0x9b, 0xca, 0xe3, 0xaa, 0x27, 0x85, 0x59, 0xea, 0xf9,
|
||||
0x83, 0x0b, 0xad, 0x9c,
|
||||
0xfb, 0x9f, 0xc0, 0x66, 0x8a, 0xeb, 0x7c, 0xf4, 0x33, 0xd8, 0x47, 0xa2,
|
||||
0x40, 0xf8, 0x5a, 0x3f,
|
||||
0x7b, 0x9a, 0x43, 0x8c, 0x8e, 0x15, 0xc7, 0xcf, 0x2e, 0x69, 0x5b, 0xe4,
|
||||
0xc9, 0x6e, 0xfc, 0xaa,
|
||||
0xd9, 0x38, 0x26, 0xd5, 0x6e, 0x9b, 0xdd, 0x34, 0x71, 0x69, 0x6a, 0x8b,
|
||||
0x71, 0x80, 0x9c, 0xb9,
|
||||
0x5f, 0x8a, 0xd8, 0xcd, 0x8a, 0x2e, 0x8b, 0x62, 0xa0, 0xfe, 0x1d, 0xa7,
|
||||
0x33, 0x49, 0xab, 0x7c,
|
||||
0x6e, 0xa2, 0x55, 0xda, 0xe3, 0xf9, 0x81, 0x66, 0x78, 0xe7, 0xfd, 0x34,
|
||||
0x14, 0xc3, 0xfb, 0x48,
|
||||
0x59, 0x21, 0xdf, 0x9a, 0x6b, 0x7d, 0x45, 0x5e, 0xb8, 0x87, 0xd6, 0x60,
|
||||
0x34, 0xf3, 0xc8, 0x9c,
|
||||
0x1f, 0x11, 0x69, 0x17, 0xdd, 0x50, 0x36, 0x8b, 0xd0, 0x12, 0xa6, 0xd0,
|
||||
0xe7, 0xe5, 0xfa, 0x12,
|
||||
0x67, 0x9b, 0xfb, 0x89, 0x98, 0x22, 0xdd, 0x97, 0x43, 0xae, 0xb4, 0x4a,
|
||||
0x14, 0x1c, 0xad, 0x64,
|
||||
0xea, 0x61, 0x78, 0xd2, 0xb8, 0x9f, 0x20, 0x4b, 0xb1, 0x45, 0x2b, 0x97,
|
||||
0x87, 0x21, 0x3b, 0xd8,
|
||||
0x75, 0x0e, 0x18, 0x87, 0xa5, 0xb2, 0x16, 0x9b, 0x55, 0x87, 0xa5, 0xdc,
|
||||
0x56, 0x71, 0x32, 0x75,
|
||||
0xaf, 0xec, 0x25, 0xde, 0x97, 0xb2, 0x7e, 0x69, 0x50, 0x94, 0x81, 0x52,
|
||||
0x19, 0x2f, 0x25, 0x7a,
|
||||
0xad, 0x12, 0x3e, 0x95, 0x92, 0xd1, 0x93, 0xd0, 0xa2, 0xf7, 0x9e, 0x58,
|
||||
0xab, 0x74, 0x44, 0x8b,
|
||||
0xae, 0x91, 0xbe, 0x33, 0xc6, 0xb9, 0x65, 0x73, 0xcd, 0xf3, 0x8c, 0x08,
|
||||
0xbe, 0x8e, 0xff, 0x88,
|
||||
0x32, 0x68, 0x44, 0xc1, 0xe1, 0x25, 0x73, 0xad, 0xcf, 0x90, 0xe3, 0x7e,
|
||||
0xe8, 0x05, 0xa3, 0x95,
|
||||
0x0f, 0x6f, 0xff, 0x72, 0x3f, 0x13, 0x72, 0xd9, 0x4c, 0xd5, 0x91, 0x6a,
|
||||
0x6c, 0x06, 0x36, 0xfb,
|
||||
0xc6, 0xa4, 0xf3, 0x09, 0x67, 0x9f, 0x07, 0xd0, 0xbd, 0x8b, 0x8a, 0x8d,
|
||||
0x4a, 0xe3, 0xfb, 0x2b,
|
||||
0xbc, 0x03, 0xf8, 0x23, 0xd6, 0xcf, 0x80, 0x83, 0xc0, 0x72, 0x28, 0xb9,
|
||||
0x95, 0xb4, 0xe3, 0x03,
|
||||
0x68, 0xa3, 0xc8, 0xad, 0x8f, 0x62, 0xb7, 0x36, 0x4a, 0xff, 0x8d, 0x3e,
|
||||
0x4a, 0x89, 0xff, 0x6d,
|
||||
0xb2, 0x4f, 0xf6, 0x1a, 0xcd, 0x52, 0xae, 0x6a, 0x90, 0xea, 0xce, 0xa9,
|
||||
0x11, 0x25, 0xcd, 0x59,
|
||||
0x3b, 0xd9, 0xdb, 0xf7, 0x4b, 0x0d, 0x3b, 0x6c, 0x45, 0x10, 0x54, 0x72,
|
||||
0x95, 0xb3, 0x82, 0x50,
|
||||
0x31, 0x25, 0xe3, 0xb1, 0x69, 0xd8, 0xab, 0x10, 0xaf, 0x4c, 0x42, 0x2b,
|
||||
0xef, 0x9a, 0xf8, 0x5e,
|
||||
0x6e, 0x81, 0x97, 0x4a, 0x0d, 0x35, 0xab, 0x4c, 0x7b, 0x49, 0x26, 0xe3,
|
||||
0xe3, 0x75, 0xed, 0x36,
|
||||
0x86, 0xdc, 0x63, 0xc0, 0x69, 0x99, 0x9b, 0x66, 0x39, 0x1c, 0x15, 0x61,
|
||||
0xe5, 0x7c, 0x33, 0xa7,
|
||||
0x95, 0x68, 0x1e, 0x5c, 0xab, 0x95, 0x40, 0xcb, 0xd3, 0x33, 0x8e, 0xbe,
|
||||
0x18, 0x59, 0x2c, 0x1f,
|
||||
0x9b, 0x6b, 0x7d, 0x88, 0x9f, 0xfd, 0x4d, 0x53, 0x2a, 0x63, 0x64, 0xa1,
|
||||
0x39, 0x32, 0x9f, 0xb1,
|
||||
0xc5, 0x9a, 0xd7, 0x6c, 0xe9, 0x21, 0x37, 0x49, 0x07, 0x8d, 0x9b, 0xc1,
|
||||
0x7d, 0xd8, 0x4a, 0x71,
|
||||
0xa4, 0xb8, 0xb8, 0x68, 0xd2, 0x79, 0x5f, 0xce, 0xc9, 0x5f, 0x90, 0x64,
|
||||
0x9c, 0x5e, 0x5b, 0xd8,
|
||||
0xcf, 0xbe, 0xb4, 0x48, 0xa4, 0x70, 0xc9, 0x8d, 0x4f, 0xf1, 0x01, 0x6b,
|
||||
0xfb, 0x47, 0xb2, 0x4b,
|
||||
0x06, 0x6a, 0x69, 0x8a, 0xcd, 0xf5, 0x0b, 0xa1, 0x5f, 0xaa, 0xa5, 0xb2,
|
||||
0xe9, 0x3a, 0x3d, 0x9f,
|
||||
0xcf, 0x15, 0xa6, 0x36, 0x4a, 0xdc, 0xfa, 0x8b, 0xd7, 0x77, 0x64, 0x93,
|
||||
0xa8, 0x2e, 0x6c, 0x3a,
|
||||
0x4e, 0xca, 0x4d, 0x8d, 0x05, 0x42, 0x09, 0x75, 0xd7, 0x2e, 0xd9, 0x49,
|
||||
0x2e, 0x2c, 0xad, 0xb9,
|
||||
0x25, 0x91, 0x9a, 0x71, 0x74, 0x4d, 0xc1, 0xee, 0xbc, 0xed, 0x54, 0x61,
|
||||
0x5b, 0x99, 0x39, 0x31,
|
||||
0x28, 0x26, 0x40, 0x73, 0x1c, 0xd2, 0xa6, 0xf0, 0x79, 0x31, 0x15, 0x54,
|
||||
0x23, 0xdc, 0xc4, 0xea,
|
||||
0x3a, 0xfa, 0x23, 0x64, 0xf6, 0xe0, 0x92, 0x74, 0x41, 0x57, 0xae, 0xf1,
|
||||
0x55, 0x7c, 0xca, 0x65,
|
||||
0x44, 0x3a, 0xf5, 0xda, 0x22, 0xd9, 0x48, 0xfd, 0xb0, 0x89, 0x99, 0x55,
|
||||
0x50, 0x88, 0x25, 0x7f,
|
||||
0x96, 0xd2, 0xaa, 0xc6, 0x14, 0xf3, 0x39, 0x85, 0x2a, 0x4c, 0x21, 0x09,
|
||||
0xaf, 0x55, 0x3d, 0x13,
|
||||
0x98, 0x5f, 0x05, 0xa7, 0x79, 0xcc, 0x4d, 0xd4, 0x3d, 0x63, 0xb0, 0xbb,
|
||||
0xb0, 0xef, 0x2f, 0x40,
|
||||
0x53, 0x9e, 0xb5, 0xde, 0x26, 0x63, 0x3c, 0xc4, 0xb8, 0x4a, 0xf4, 0x94,
|
||||
0x61, 0xd2, 0x48, 0xe4,
|
||||
0xd3, 0x58, 0xb4, 0x53, 0xae, 0xf5, 0x1f, 0x47, 0x75, 0x38, 0x50, 0x9e,
|
||||
0x05, 0x83, 0xb0, 0x45,
|
||||
0xaa, 0xf6, 0xef, 0x5c, 0x72, 0x6c, 0x16, 0xda, 0xf7, 0xd0, 0xb9, 0xc0,
|
||||
0x09, 0xe7, 0x2f, 0xd0,
|
||||
0xce, 0x40, 0xa2, 0x32, 0x68, 0x8d, 0xc4, 0x2f, 0xce, 0x59, 0xf0, 0x31,
|
||||
0x19, 0x55, 0xdd, 0x8d,
|
||||
0x48, 0x86, 0xaf, 0x3d, 0x96, 0x79, 0x0a, 0x5f, 0xca, 0x3f, 0xb1, 0x93,
|
||||
0xb2, 0x4f, 0xaa, 0x7b,
|
||||
0xfd, 0x64, 0x5d, 0x83, 0xd9, 0xb0, 0x4a, 0xae, 0x4c, 0x41, 0xee, 0x32,
|
||||
0x56, 0x74, 0xc9, 0x53,
|
||||
0x8a, 0xb7, 0xc6, 0xe1, 0xeb, 0x65, 0x48, 0xb1, 0x01, 0x2b, 0x6c, 0x95,
|
||||
0x97, 0x64, 0x2a, 0x72,
|
||||
0xc5, 0x60, 0xc5, 0x12, 0xfa, 0x27, 0x04, 0xd5, 0x7d, 0x05, 0x9a, 0xdb,
|
||||
0x21, 0xdb, 0x8d, 0xbd,
|
||||
0x52, 0x8c, 0xcd, 0xc2, 0x67, 0x75, 0x89, 0x58, 0x23, 0x5b, 0xed, 0x8a,
|
||||
0xc2, 0x32, 0x66, 0xd5,
|
||||
0x04, 0xc5, 0x04, 0x38, 0x8b, 0xa6, 0xd6, 0x3d, 0x8f, 0xae, 0x2e, 0xf0,
|
||||
0xef, 0x9b, 0x68, 0xaf,
|
||||
0x45, 0xd7, 0xcc, 0xef, 0x51, 0x83, 0x79, 0xf0, 0xb1, 0x84, 0xa1, 0x2b,
|
||||
0xd7, 0xf8, 0xf1, 0xe8,
|
||||
0xcf, 0x4e, 0x2c, 0xbc, 0xa9, 0x67, 0x78, 0xf4, 0xa3, 0x3e, 0x6f, 0xd5,
|
||||
0xf7, 0x26, 0xca, 0xe0,
|
||||
0xa6, 0x1a, 0xc9, 0x8e, 0xa0, 0xb3, 0xe3, 0x6e, 0xbc, 0x41, 0x6b, 0x1e,
|
||||
0xed, 0x35, 0xf4, 0xe4,
|
||||
0xc9, 0x5c, 0x79, 0xdd, 0xec, 0x39, 0x2f, 0x93, 0xc8, 0x5a, 0xf3, 0x98,
|
||||
0xed, 0x59, 0xeb, 0x1c,
|
||||
0x72, 0x3f, 0xcc, 0xb8, 0x12, 0x7c, 0x60, 0xbb, 0x9c, 0x32, 0x47, 0x9e,
|
||||
0x24, 0x72, 0xd4, 0xee,
|
||||
0x57, 0x01, 0x85, 0x63, 0x8c, 0x3b, 0xe5, 0xc6, 0x05, 0xc6, 0xaa, 0x13,
|
||||
0x65, 0x33, 0x23, 0x4e,
|
||||
0xca, 0x19, 0x0b, 0xd7, 0x67, 0x98, 0x75, 0x02, 0x7a, 0x55, 0x68, 0xb5,
|
||||
0x08, 0x0b, 0x59, 0x25,
|
||||
0x3a, 0xcd, 0xce, 0xd5, 0x0e, 0xdf, 0x78, 0x4c, 0x1e, 0x91, 0xbb, 0xe4,
|
||||
0x77, 0xe8, 0xf9, 0xbc,
|
||||
0xa5, 0xef, 0x7d, 0xe4, 0xcf, 0x46, 0xef, 0xfb, 0x2d, 0xeb, 0xbf, 0x23,
|
||||
0x3d, 0xb1, 0xcd, 0x7e,
|
||||
0xfe, 0x7f, 0x0b, 0x7f, 0xce, 0xa3, 0x77, 0x32, 0x12, 0x95, 0xe9, 0xfb,
|
||||
0x28, 0x4d, 0x70, 0xf1,
|
||||
0x8e, 0xa9, 0x8d, 0xf3, 0xa2, 0xee, 0xed, 0x1e, 0x84, 0xdb, 0x18, 0xae,
|
||||
0x6a, 0xc6, 0x05, 0xd3,
|
||||
0xfd, 0x7a, 0x66, 0x6e, 0x31, 0x76, 0xca, 0x38, 0x6c, 0x16, 0xe6, 0xbc,
|
||||
0x3b, 0x62, 0x9b, 0x7d,
|
||||
0x23, 0x51, 0xb0, 0x59, 0x66, 0xe3, 0x17, 0x53, 0x03, 0xa0, 0x8e, 0xab,
|
||||
0x16, 0x2f, 0x89, 0x23,
|
||||
0x7f, 0xbe, 0x4e, 0xad, 0x76, 0xc4, 0xc4, 0x71, 0xd6, 0x2c, 0x83, 0x73,
|
||||
0x6f, 0xcb, 0x3b, 0xf2,
|
||||
0x27, 0x24, 0xaf, 0x63, 0x1d, 0x65, 0xb1, 0x25, 0x70, 0x75, 0xdc, 0xd2,
|
||||
0xeb, 0xc1, 0x09, 0xe6,
|
||||
0x4d, 0xc2, 0x27, 0x2b, 0x91, 0x25, 0x4b, 0x66, 0xa0, 0xb3, 0xa3, 0x6e,
|
||||
0xa8, 0xf3, 0xe1, 0x08,
|
||||
0x78, 0x9f, 0x8a, 0x04, 0xf1, 0xd8, 0xfb, 0x84, 0xbb, 0xfd, 0x18, 0x2b,
|
||||
0xdf, 0x43, 0x04, 0xcc,
|
||||
0x46, 0x37, 0x5e, 0x2a, 0xeb, 0xd0, 0x63, 0x29, 0xe3, 0x96, 0x6b, 0xbe,
|
||||
0x5c, 0x38, 0x8e, 0x1e,
|
||||
0x9f, 0x64, 0x9f, 0xab, 0x86, 0x7a, 0x32, 0xf6, 0x39, 0x6e, 0xf6, 0x9c,
|
||||
0x47, 0x02, 0x75, 0xd7,
|
||||
0x7b, 0xbf, 0xa6, 0xea, 0xcb, 0xd1, 0x31, 0xdd, 0x1f, 0x8f, 0x56, 0xcb,
|
||||
0xd8, 0x35, 0xcf, 0xf9,
|
||||
0xf4, 0x29, 0x99, 0xaa, 0x65, 0x1a, 0x98, 0x04, 0xb7, 0xd1, 0xf8, 0x95,
|
||||
0xb7, 0xef, 0x0d, 0xe8,
|
||||
0x25, 0x43, 0x75, 0xa7, 0xc9, 0xe9, 0x51, 0xc6, 0x77, 0x14, 0x75, 0x77,
|
||||
0x42, 0xf5, 0x9f, 0xe3,
|
||||
0xdc, 0x9f, 0x8a, 0xf6, 0x14, 0x2f, 0x53, 0x91, 0xfa, 0x44, 0x00, 0x6d,
|
||||
0x28, 0x7f, 0x5c, 0xcf,
|
||||
0xb8, 0x12, 0xb4, 0xe6, 0xd2, 0xb6, 0x3f, 0x6a, 0x64, 0x0d, 0x16, 0xda,
|
||||
0x68, 0x6c, 0x93, 0x82,
|
||||
0xda, 0x5b, 0x92, 0xba, 0xce, 0x78, 0x2a, 0xea, 0x65, 0xfb, 0x5a, 0xc7,
|
||||
0x5a, 0x66, 0xcd, 0x42,
|
||||
0x7b, 0x33, 0x03, 0x62, 0x06, 0x5a, 0xcc, 0x90, 0x85, 0xf0, 0xf3, 0x6a,
|
||||
0x1b, 0xbc, 0xe6, 0xf3,
|
||||
0xdb, 0x59, 0xf9, 0x33, 0x63, 0xa7, 0x63, 0x8b, 0x64, 0xe2, 0xf6, 0xb8,
|
||||
0xd9, 0x7e, 0x90, 0x1a,
|
||||
0xef, 0x08, 0xd7, 0x41, 0xb3, 0xe5, 0x04, 0xde, 0x93, 0x8e, 0x16, 0x4a,
|
||||
0xd0, 0xd1, 0x29, 0xb3,
|
||||
0xb5, 0x19, 0xe9, 0xfb, 0x41, 0x61, 0x06, 0x51, 0x92, 0x80, 0xdc, 0x9e,
|
||||
0xf6, 0xc3, 0x64, 0xd5,
|
||||
0x3f, 0x21, 0xbd, 0xd3, 0xb2, 0xde, 0x21, 0x32, 0xf4, 0xc3, 0x5a, 0x23,
|
||||
0x27, 0x2c, 0xf3, 0xcf,
|
||||
0xb1, 0x87, 0x75, 0x25, 0x5a, 0x66, 0x42, 0x7f, 0x0c, 0xb9, 0xac, 0xd9,
|
||||
0xec, 0x3b, 0xc9, 0x89,
|
||||
0x5a, 0x69, 0x78, 0xbb, 0xa5, 0xcd, 0x8a, 0x13, 0xf4, 0x67, 0xe1, 0x71,
|
||||
0xb1, 0x16, 0x7a, 0x2e,
|
||||
0x99, 0x6e, 0x83, 0x4f, 0xa5, 0x85, 0x5a, 0xb2, 0x5e, 0x86, 0x45, 0x2a,
|
||||
0x45, 0x33, 0x8a, 0xac,
|
||||
0x99, 0x44, 0xc4, 0xb7, 0x98, 0x6d, 0xc7, 0x90, 0xeb, 0x84, 0x65, 0xcd,
|
||||
0x74, 0xe4, 0xc9, 0xc1,
|
||||
0xe2, 0xc7, 0x03, 0xae, 0xea, 0xc2, 0x51, 0x59, 0x8b, 0x37, 0x4c, 0x64,
|
||||
0x54, 0x20, 0xfd, 0x4f,
|
||||
0xe3, 0x8c, 0xb3, 0x4e, 0xd6, 0x1a, 0x9b, 0xc5, 0x51, 0xd3, 0x29, 0xb1,
|
||||
0xcb, 0xb4, 0x11, 0xb1,
|
||||
0x9b, 0xed, 0x2b, 0x45, 0x61, 0x56, 0x10, 0x34, 0x60, 0x03, 0x55, 0x85,
|
||||
0x1d, 0x64, 0x1f, 0xbc,
|
||||
0x1c, 0x8e, 0xca, 0xed, 0x44, 0xeb, 0x34, 0x4e, 0x2d, 0xb5, 0x68, 0xc6,
|
||||
0xd3, 0xba, 0x1b, 0xfd,
|
||||
0x2e, 0x20, 0x67, 0xce, 0x87, 0xc6, 0x6e, 0xcb, 0xd8, 0x24, 0x72, 0xfd,
|
||||
0x64, 0x4e, 0x5d, 0x9b,
|
||||
0xd0, 0xad, 0xa7, 0xf5, 0x90, 0x0c, 0x65, 0xb5, 0xe9, 0x7a, 0x27, 0x7f,
|
||||
0xc5, 0x6c, 0x6d, 0x61,
|
||||
0x37, 0x7a, 0x8e, 0x5d, 0x62, 0x1a, 0x51, 0xe2, 0x69, 0xdb, 0x47, 0x1c,
|
||||
0xdf, 0x81, 0xcd, 0x5b,
|
||||
0x2c, 0xeb, 0x9c, 0x90, 0x07, 0xa5, 0x1b, 0x51, 0xd1, 0x08, 0xdf, 0x93,
|
||||
0xb1, 0xcf, 0x56, 0xcb,
|
||||
0x7a, 0x2d, 0xc4, 0x69, 0x2a, 0xb9, 0x78, 0x17, 0xda, 0x3b, 0xe4, 0xc3,
|
||||
0xf5, 0x1e, 0x1d, 0x1f,
|
||||
0xe7, 0xf4, 0x3e, 0x3b, 0x91, 0x68, 0x6b, 0xf6, 0xe9, 0x3d, 0x46, 0x5d,
|
||||
0x95, 0xaf, 0x2b, 0x3e,
|
||||
0x21, 0x6f, 0xd6, 0x5b, 0x38, 0x50, 0xdc, 0x0e, 0xc0, 0xce, 0xa9, 0xc4,
|
||||
0xc1, 0x1e, 0x0b, 0x17,
|
||||
0xbb, 0xcc, 0x55, 0x5b, 0x64, 0x14, 0x56, 0x2e, 0x46, 0x1f, 0x87, 0x2d,
|
||||
0xb3, 0x76, 0x6b, 0x1f,
|
||||
0x6e, 0xb1, 0xcc, 0xd9, 0x45, 0x4b, 0x0d, 0x23, 0xeb, 0xf0, 0xca, 0xb6,
|
||||
0x16, 0xa8, 0x27, 0x93,
|
||||
0x60, 0x21, 0x63, 0xbd, 0xd8, 0xb1, 0x59, 0xe7, 0xa9, 0x71, 0x71, 0xeb,
|
||||
0xec, 0xcb, 0x88, 0x89,
|
||||
0xa5, 0xe4, 0x9d, 0x40, 0x98, 0xc3, 0x35, 0x03, 0x49, 0x5f, 0x62, 0x17,
|
||||
0xdc, 0x6a, 0x62, 0x3b,
|
||||
0xfa, 0x6c, 0x61, 0x9d, 0x3d, 0x96, 0x36, 0x85, 0x83, 0x9c, 0x72, 0xeb,
|
||||
0xf4, 0xea, 0xbb, 0xcc,
|
||||
0xb6, 0x6d, 0x9c, 0x22, 0xba, 0xcb, 0x7f, 0xa2, 0xcb, 0x8e, 0x68, 0xf4,
|
||||
0x80, 0xd9, 0xbe, 0x03,
|
||||
0x4e, 0xa2, 0xb4, 0xef, 0x16, 0x22, 0x85, 0xa7, 0x75, 0x37, 0x96, 0xc9,
|
||||
0x81, 0x46, 0x1e, 0xeb,
|
||||
0x7a, 0x57, 0x3c, 0x2c, 0xe1, 0xec, 0x35, 0x0e, 0xfc, 0x61, 0xa7, 0xd9,
|
||||
0xf6, 0x32, 0x96, 0x79,
|
||||
0x1c, 0x7a, 0xdb, 0xcc, 0x75, 0x0e, 0xb1, 0xeb, 0xdc, 0x4a, 0x84, 0xce,
|
||||
0x85, 0xeb, 0x39, 0xe4,
|
||||
0x94, 0x34, 0xf6, 0xfa, 0x6d, 0xe6, 0xf8, 0x7d, 0x78, 0x47, 0x0e, 0x36,
|
||||
0x19, 0x2a, 0x37, 0xca,
|
||||
0x53, 0x16, 0x3e, 0xb6, 0xe3, 0x33, 0x37, 0x63, 0x97, 0x4e, 0xf2, 0x77,
|
||||
0xbd, 0xa3, 0x27, 0x92,
|
||||
0x93, 0xad, 0x32, 0xed, 0x97, 0xde, 0xfa, 0xe4, 0x9c, 0x8f, 0xd7, 0xcd,
|
||||
0xb1, 0xc8, 0xa5, 0xd0,
|
||||
0x42, 0x16, 0x2e, 0x64, 0xc7, 0x5a, 0xae, 0x6b, 0x38, 0xaf, 0xc4, 0xd6,
|
||||
0x35, 0xd5, 0x3d, 0xce,
|
||||
0x55, 0x96, 0xfe, 0x6d, 0x50, 0x4c, 0x93, 0x47, 0x39, 0x07, 0x6e, 0x41,
|
||||
0x06, 0xeb, 0x3a, 0xc3,
|
||||
0x89, 0xe7, 0x46, 0xad, 0x71, 0x5f, 0x34, 0x62, 0x1d, 0x6c, 0x64, 0xac,
|
||||
0x91, 0xbc, 0xda, 0x4e,
|
||||
0x89, 0x9d, 0x6a, 0xd3, 0x12, 0x56, 0xda, 0x17, 0x8b, 0xc2, 0x82, 0x20,
|
||||
0x98, 0x8f, 0x06, 0x33,
|
||||
0x58, 0x73, 0x9d, 0x89, 0x0d, 0xec, 0x7e, 0x0f, 0xc8, 0x7f, 0x53, 0x41,
|
||||
0xa7, 0xa2, 0xd7, 0x75,
|
||||
0x16, 0xec, 0x92, 0x7b, 0x89, 0x11, 0x55, 0x5d, 0x6c, 0x36, 0xdb, 0xb6,
|
||||
0x22, 0x53, 0x7b, 0x64,
|
||||
0x9e, 0x82, 0xff, 0x0f, 0x67, 0xc7, 0x6e, 0x32, 0x7b, 0xb6, 0x93, 0xc5,
|
||||
0xab, 0xd0, 0x52, 0x2c,
|
||||
0xa3, 0xd7, 0xbb, 0xdb, 0x36, 0x52, 0x67, 0x0c, 0xa3, 0x2d, 0x07, 0xcf,
|
||||
0xf2, 0xb4, 0x6d, 0xc2,
|
||||
0xfb, 0xee, 0x84, 0x8b, 0x22, 0x64, 0xda, 0x64, 0xe1, 0x62, 0x01, 0xb2,
|
||||
0x6c, 0x74, 0xff, 0xb6,
|
||||
0x1e, 0x4d, 0xdf, 0x4f, 0x66, 0x9e, 0x4a, 0x0e, 0x77, 0xf1, 0x3d, 0x83,
|
||||
0x75, 0xbd, 0x34, 0xd4,
|
||||
0x6a, 0x23, 0xb0, 0xfb, 0x1c, 0xec, 0x92, 0xc8, 0xce, 0xb6, 0xcd, 0x42,
|
||||
0x67, 0x39, 0x5c, 0x67,
|
||||
0x62, 0x97, 0x6a, 0xac, 0x3d, 0x4d, 0x47, 0xe7, 0x3a, 0x1f, 0xbc, 0x0c,
|
||||
0xcf, 0x0a, 0x5b, 0x2c,
|
||||
0xab, 0xbb, 0x78, 0x5d, 0x8a, 0x8f, 0xd4, 0x52, 0xd9, 0x2c, 0x82, 0xca,
|
||||
0x3a, 0x3f, 0xac, 0x67,
|
||||
0xf4, 0x2e, 0x6c, 0x96, 0x82, 0x57, 0x36, 0x59, 0xda, 0xf7, 0xb0, 0x5a,
|
||||
0x07, 0x2c, 0xd6, 0x97,
|
||||
0x9c, 0xbb, 0xce, 0x32, 0xaf, 0x09, 0x0e, 0x6c, 0x70, 0xb0, 0x30, 0x80,
|
||||
0x0d, 0xb4, 0x85, 0x8c,
|
||||
0x15, 0x32, 0x56, 0xd9, 0xac, 0x26, 0x2b, 0x71, 0xa9, 0xa1, 0x5a, 0x17,
|
||||
0x92, 0x69, 0x16, 0x07,
|
||||
0xc0, 0x12, 0x7a, 0x6a, 0xc8, 0x61, 0x6b, 0x90, 0xcc, 0x83, 0x2d, 0x9c,
|
||||
0x8b, 0xee, 0x85, 0xd3,
|
||||
0x5c, 0xf9, 0x07, 0xbe, 0xb7, 0xda, 0xd2, 0xb3, 0x59, 0xfe, 0x8a, 0xcd,
|
||||
0x0a, 0xf0, 0x8c, 0x95,
|
||||
0x66, 0xdb, 0x26, 0xec, 0xdb, 0x47, 0xdf, 0xcd, 0x53, 0x77, 0x79, 0x5f,
|
||||
0x44, 0x16, 0x4f, 0xcf,
|
||||
0x5a, 0x5a, 0x6d, 0xd8, 0x23, 0x85, 0x6b, 0xa5, 0x85, 0x46, 0x1f, 0x5d,
|
||||
0xe7, 0x7b, 0x57, 0xdc,
|
||||
0x28, 0x83, 0xd9, 0x17, 0xe6, 0x90, 0x9d, 0xaa, 0x7c, 0x56, 0x5b, 0x69,
|
||||
0x99, 0xb5, 0x16, 0x9e,
|
||||
0xd4, 0xbe, 0xf3, 0x12, 0x1c, 0xbb, 0xe0, 0xc4, 0xee, 0x8b, 0x64, 0x85,
|
||||
0x39, 0x62, 0x03, 0xbe,
|
||||
0x50, 0xa0, 0xa5, 0x9c, 0x42, 0x0e, 0x5c, 0x6b, 0xa1, 0xb2, 0x80, 0xaa,
|
||||
0x65, 0xb6, 0xce, 0x35,
|
||||
0x4b, 0xd8, 0x3d, 0x52, 0x2d, 0x7d, 0xff, 0x1e, 0x4d, 0x9c, 0x20, 0x5e,
|
||||
0x60, 0xef, 0xb0, 0xc3,
|
||||
0xdb, 0x4a, 0x9f, 0x9e, 0x55, 0xd8, 0x7d, 0x0d, 0x3e, 0x30, 0x15, 0x3f,
|
||||
0x49, 0xc1, 0x4b, 0x56,
|
||||
0x5b, 0x56, 0x5b, 0x2c, 0xff, 0xa7, 0x4f, 0x3f, 0x73, 0xe8, 0xb1, 0xea,
|
||||
0x75, 0x15, 0x5e, 0x16,
|
||||
0x41, 0x84, 0x2c, 0x69, 0x63, 0x89, 0x25, 0x2e, 0x3b, 0x1a, 0x4b, 0x25,
|
||||
0x5b, 0xc7, 0x59, 0x46,
|
||||
0xe2, 0x22, 0x43, 0x65, 0x92, 0xb9, 0x48, 0xb7, 0x2c, 0x00, 0x96, 0x33,
|
||||
0x63, 0x22, 0xd9, 0xdc,
|
||||
0x1b, 0x87, 0x8b, 0xe0, 0x32, 0x1c, 0xaf, 0x5f, 0x89, 0x7e, 0x6a, 0xd9,
|
||||
0x39, 0x97, 0x5a, 0xfc,
|
||||
0x61, 0x15, 0xf9, 0x45, 0xed, 0x66, 0x8d, 0x16, 0x6f, 0x59, 0x08, 0x1f,
|
||||
0x0b, 0x88, 0x9e, 0xb9,
|
||||
0x5c, 0xf3, 0xc1, 0x42, 0x0b, 0xa5, 0xa9, 0xd8, 0x70, 0x2e, 0x12, 0x64,
|
||||
0x41, 0xcb, 0xd3, 0xba,
|
||||
0x8c, 0x8c, 0x99, 0x48, 0xac, 0x2e, 0x31, 0x5b, 0x56, 0x10, 0x3f, 0xd5,
|
||||
0x70, 0x50, 0xee, 0xc3,
|
||||
0x87, 0x2f, 0x96, 0xe3, 0xb9, 0x39, 0x7a, 0xf6, 0x72, 0xf7, 0x35, 0x07,
|
||||
0xaf, 0xb2, 0xf2, 0xb1,
|
||||
0x9c, 0x1d, 0xb1, 0x98, 0x7f, 0x97, 0xc2, 0xa1, 0xcd, 0x42, 0x7d, 0x11,
|
||||
0x3b, 0xc6, 0x93, 0x8c,
|
||||
0x5e, 0xae, 0x67, 0x39, 0xa9, 0x19, 0x5e, 0x0a, 0x9a, 0x73, 0xac, 0x50,
|
||||
0x67, 0xa3, 0x1b, 0x91,
|
||||
0x60, 0x01, 0x59, 0x73, 0xa6, 0x4f, 0x74, 0x2c, 0xc1, 0x6f, 0x6f, 0x92,
|
||||
0xff, 0xa0, 0x16, 0xba,
|
||||
0x15, 0xff, 0x13, 0x7c, 0x7e, 0x91, 0xd9, 0xf7, 0x12, 0x5c, 0x0e, 0x40,
|
||||
0x8a, 0x15, 0x7c, 0x9a,
|
||||
0xc4, 0xe7, 0x97, 0x2c, 0x7c, 0x38, 0xf1, 0x81, 0xf9, 0x6e, 0x3e, 0xac,
|
||||
0x58, 0xe1, 0xca, 0xf6,
|
||||
0xc6, 0x42, 0xc9, 0xc0, 0x66, 0x9d, 0x6b, 0x13, 0xe3, 0xe7, 0x19, 0x6a,
|
||||
0x9f, 0x6b, 0xc4, 0x17,
|
||||
0x56, 0x06, 0xc0, 0x2a, 0x64, 0x9c, 0x80, 0xae, 0xe6, 0x30, 0xc2, 0x85,
|
||||
0xb9, 0xe8, 0xee, 0x51,
|
||||
0xf8, 0x5a, 0x0d, 0xad, 0x06, 0x32, 0xf3, 0x3c, 0xb3, 0xa7, 0x91, 0xd6,
|
||||
0x07, 0xe0, 0xd7, 0xa1,
|
||||
0xe9, 0x79, 0xe1, 0x9f, 0x9d, 0xbd, 0x58, 0x84, 0xb6, 0x16, 0xf0, 0x7f,
|
||||
0x14, 0x9f, 0x3c, 0x6d,
|
||||
0xf3, 0xd8, 0x21, 0xfa, 0xa1, 0xd7, 0xd9, 0xe6, 0x7a, 0x95, 0x44, 0xf5,
|
||||
0x42, 0xf8, 0xa8, 0x44,
|
||||
0xe7, 0x73, 0x7d, 0xe6, 0x5b, 0xb1, 0x10, 0x2a, 0xf5, 0x48, 0xe8, 0xe2,
|
||||
0x5a, 0x3d, 0x37, 0xb1,
|
||||
0xe1, 0xb9, 0xb3, 0x2d, 0x6b, 0x0d, 0x46, 0x8e, 0x55, 0x70, 0x3d, 0x83,
|
||||
0x28, 0xf6, 0x72, 0x3d,
|
||||
0x07, 0xff, 0x7b, 0x0a, 0x5d, 0xb9, 0x66, 0xcd, 0xc6, 0x7f, 0xe6, 0x05,
|
||||
0x5d, 0xc3, 0x3b, 0x47,
|
||||
0x9d, 0x87, 0xff, 0x8b, 0x3c, 0xba, 0x02, 0x99, 0x0b, 0xf9, 0x3c, 0xdb,
|
||||
0x22, 0xed, 0x3c, 0xf9,
|
||||
0x3d, 0xa7, 0xf8, 0x49, 0x7c, 0x9a, 0xcf, 0x55, 0xc2, 0x27, 0xaf, 0xf6,
|
||||
0x16, 0xe0, 0xe5, 0xf1,
|
||||
0x70, 0xa9, 0x22, 0x6f, 0x3a, 0x3b, 0xc5, 0x3c, 0xcb, 0xbc, 0x06, 0x2c,
|
||||
0x3c, 0xd7, 0xcd, 0x87,
|
||||
0x15, 0xab, 0xe9, 0xc3, 0x46, 0xc6, 0x3c, 0x49, 0xc3, 0x66, 0x5d, 0xa6,
|
||||
0x8e, 0x8c, 0x9b, 0x6d,
|
||||
0x9f, 0x81, 0x14, 0xf5, 0x96, 0xcc, 0xef, 0x9b, 0x95, 0x57, 0xe2, 0x27,
|
||||
0x85, 0x8c, 0x98, 0xe6,
|
||||
0xc6, 0x4c, 0x7e, 0x1b, 0x08, 0xdd, 0xf5, 0xe4, 0x90, 0xf9, 0xf8, 0xf2,
|
||||
0x54, 0xd6, 0xf6, 0xf4,
|
||||
0xcd, 0x26, 0x5b, 0x3a, 0xb1, 0x59, 0x9d, 0xd9, 0xe2, 0x9a, 0x51, 0x1f,
|
||||
0x10, 0x33, 0xe1, 0xf0,
|
||||
0x19, 0x7c, 0x6e, 0x99, 0xbe, 0xa7, 0xee, 0x59, 0x61, 0x3a, 0xd1, 0xfb,
|
||||
0x0c, 0x94, 0x3c, 0xb3,
|
||||
0x1b, 0x91, 0x3f, 0x12, 0x4e, 0x56, 0x52, 0x09, 0x5a, 0xf9, 0xf0, 0xc7,
|
||||
0x4c, 0x2c, 0x92, 0x0d,
|
||||
0xb5, 0x35, 0x5a, 0x92, 0xb5, 0x7c, 0x52, 0x1e, 0xee, 0xe5, 0xad, 0x01,
|
||||
0x3a, 0x15, 0xf4, 0xad,
|
||||
0xe1, 0x93, 0x4d, 0x57, 0xd0, 0x2e, 0xcc, 0x20, 0x8f, 0xf4, 0xc2, 0x06,
|
||||
0xeb, 0xf4, 0x3c, 0x25,
|
||||
0xd1, 0x4c, 0x3f, 0xca, 0x56, 0x9e, 0x9d, 0xcc, 0x9e, 0x47, 0x5b, 0x7f,
|
||||
0x2c, 0x96, 0x86, 0xc5,
|
||||
0xd6, 0xc3, 0xfd, 0x78, 0xbc, 0x7a, 0xba, 0x65, 0xf4, 0x58, 0xf2, 0xb4,
|
||||
0xca, 0xe8, 0x1b, 0xb8,
|
||||
0x96, 0xeb, 0xbb, 0x70, 0x5e, 0xae, 0xd5, 0x9b, 0x36, 0x39, 0x58, 0x61,
|
||||
0x03, 0x7c, 0xcc, 0x62,
|
||||
0xb7, 0xf0, 0xae, 0xa5, 0x28, 0x28, 0x0f, 0x6e, 0x6b, 0x83, 0x8d, 0xfa,
|
||||
0x1c, 0x36, 0xc3, 0x68,
|
||||
0x94, 0x94, 0xda, 0xce, 0xd4, 0xfa, 0x03, 0x62, 0x1a, 0xec, 0x75, 0x8e,
|
||||
0x3a, 0xb4, 0xbc, 0x81,
|
||||
0x9d, 0x67, 0x63, 0x1b, 0xa8, 0x5d, 0xb7, 0x8e, 0x8c, 0x5d, 0x83, 0xb7,
|
||||
0xb8, 0x50, 0x83, 0x4d,
|
||||
0x86, 0xb2, 0xea, 0x66, 0x66, 0xcc, 0xc7, 0x63, 0xbd, 0x3d, 0x93, 0x58,
|
||||
0xf7, 0x31, 0x74, 0x5c,
|
||||
0xc0, 0xbe, 0x33, 0xc9, 0x32, 0x3e, 0x5f, 0x3f, 0x1b, 0xf6, 0xc0, 0xfa,
|
||||
0x04, 0xd6, 0x86, 0xb6,
|
||||
0x96, 0xb1, 0x82, 0x93, 0xba, 0x7f, 0x8a, 0x39, 0x63, 0x0a, 0x55, 0x89,
|
||||
0xf7, 0x37, 0x27, 0x27,
|
||||
0xb3, 0x09, 0xec, 0xa1, 0x6b, 0x68, 0x33, 0x7c, 0x56, 0xf3, 0xc7, 0x14,
|
||||
0x72, 0xea, 0x14, 0xbc,
|
||||
0x69, 0xa3, 0x96, 0x64, 0xa9, 0xbe, 0x17, 0x32, 0xd9, 0xec, 0xad, 0x23,
|
||||
0x27, 0x4d, 0xa0, 0x67,
|
||||
0x03, 0x5e, 0x6f, 0xe5, 0x7a, 0x32, 0x79, 0xb8, 0x37, 0x5c, 0x6c, 0x42,
|
||||
0x22, 0x75, 0x77, 0x2d,
|
||||
0xcf, 0x6f, 0x8d, 0x5a, 0xf7, 0xb3, 0x6d, 0x17, 0xef, 0x31, 0x50, 0xf9,
|
||||
0xb3, 0xfc, 0x0f, 0x7b,
|
||||
0x40, 0xb1, 0xae, 0x8e, 0x36, 0xe1, 0x4b, 0xe5, 0x50, 0xf0, 0xae, 0xa3,
|
||||
0xf2, 0x7d, 0x8c, 0xae,
|
||||
0xd3, 0x14, 0xc5, 0x55, 0xb4, 0xe4, 0xfb, 0xf4, 0x46, 0x41, 0x65, 0xad,
|
||||
0xae, 0xba, 0x94, 0xef,
|
||||
0x58, 0xf9, 0xa8, 0xa4, 0xbe, 0x5e, 0xaa, 0x69, 0xfa, 0xda, 0xa0, 0x09,
|
||||
0x3f, 0xc0, 0x42, 0x46,
|
||||
0xbd, 0x8c, 0xc1, 0x66, 0x61, 0x33, 0x1e, 0x8d, 0x72, 0xda, 0x6b, 0x1c,
|
||||
0x6a, 0xe6, 0x06, 0xf6,
|
||||
0xcd, 0xa6, 0x36, 0xd8, 0x0a, 0x85, 0xd9, 0xac, 0x52, 0xa1, 0xef, 0xe0,
|
||||
0x95, 0xeb, 0x3b, 0xb8,
|
||||
0x25, 0xc4, 0xd9, 0x62, 0xc6, 0xaf, 0xc5, 0x4b, 0xf2, 0x2c, 0x3d, 0xe5,
|
||||
0x50, 0x79, 0x82, 0x1c,
|
||||
0xa4, 0xee, 0xe2, 0x7b, 0x5b, 0x6b, 0x38, 0x45, 0xdd, 0xc2, 0x19, 0xe0,
|
||||
0x5e, 0xae, 0xbb, 0xf9,
|
||||
0x7c, 0x3b, 0xf8, 0xb3, 0xc6, 0x9d, 0x72, 0x0f, 0x5c, 0x2b, 0x9e, 0x56,
|
||||
0xe0, 0xb3, 0x25, 0x96,
|
||||
0x39, 0x95, 0x96, 0x4f, 0xf9, 0xd4, 0x35, 0x2b, 0xa8, 0xf3, 0x36, 0xe0,
|
||||
0x11, 0xbe, 0xab, 0x95,
|
||||
0x63, 0x03, 0xdf, 0xdf, 0xab, 0xa8, 0x08, 0x17, 0xc0, 0xf1, 0x56, 0x4d,
|
||||
0x53, 0xdd, 0x39, 0xf7,
|
||||
0xf6, 0x4f, 0xa4, 0x52, 0x9b, 0x4c, 0xcf, 0x16, 0x46, 0xd8, 0x7c, 0xe4,
|
||||
0x29, 0xe4, 0x1c, 0xbe,
|
||||
0x50, 0xfb, 0xf3, 0x16, 0x74, 0x66, 0xf8, 0xd1, 0xac, 0x93, 0x76, 0x70,
|
||||
0x7d, 0x0f, 0xb8, 0x9b,
|
||||
0xeb, 0x21, 0xa8, 0x24, 0x63, 0xc7, 0x75, 0xee, 0x8a, 0xbe, 0x09, 0x2d,
|
||||
0x4c, 0xf0, 0x91, 0x77,
|
||||
0x02, 0x36, 0xcb, 0xd6, 0xf7, 0x13, 0x95, 0xf6, 0xd6, 0xeb, 0xb8, 0xab,
|
||||
0xb4, 0x70, 0x98, 0x06,
|
||||
0x8f, 0xab, 0xe9, 0x5b, 0x8f, 0x3c, 0x36, 0x1f, 0x99, 0x0d, 0x72, 0xf4,
|
||||
0xba, 0x00, 0x56, 0xd8,
|
||||
0xc1, 0xc8, 0xc9, 0x52, 0x63, 0x4c, 0x93, 0xc4, 0x9a, 0xce, 0x89, 0xe1,
|
||||
0xce, 0x3b, 0x22, 0x6a,
|
||||
0xed, 0xea, 0x3e, 0x64, 0x25, 0xfe, 0xb2, 0x93, 0xde, 0xb6, 0xd8, 0x86,
|
||||
0x1c, 0xd9, 0x3e, 0xcf,
|
||||
0x7a, 0xca, 0x38, 0x29, 0x96, 0x22, 0x79, 0x83, 0xbe, 0xef, 0x6e, 0xed,
|
||||
0x29, 0x47, 0xfa, 0xe5,
|
||||
0xda, 0x33, 0xbd, 0xad, 0xa5, 0x8c, 0xce, 0x42, 0x27, 0xcb, 0xb0, 0xf3,
|
||||
0x6c, 0xd6, 0x2e, 0xd5,
|
||||
0x99, 0xb0, 0x50, 0xdf, 0xab, 0x99, 0xaf, 0x6b, 0xf0, 0x1d, 0x68, 0xab,
|
||||
0x82, 0x6a, 0xbb, 0x24,
|
||||
0xc0, 0xb3, 0xa3, 0x72, 0x62, 0x20, 0x1e, 0xbe, 0x5f, 0x46, 0x0b, 0x33,
|
||||
0x7d, 0xe8, 0x16, 0xc1,
|
||||
0xf3, 0x5f, 0xc9, 0xa2, 0x15, 0x96, 0x96, 0x12, 0x38, 0x2d, 0xd0, 0xfa,
|
||||
0xdc, 0x41, 0x5c, 0xaa,
|
||||
0xb3, 0x6c, 0xb1, 0x85, 0xd2, 0x33, 0x78, 0xf9, 0xcb, 0xf4, 0x2d, 0xc1,
|
||||
0xf6, 0xc5, 0x96, 0xa7,
|
||||
0x59, 0x25, 0xf4, 0x94, 0x93, 0xa7, 0x57, 0x61, 0xed, 0x15, 0xcc, 0xf1,
|
||||
0xe5, 0xa0, 0x42, 0x1e,
|
||||
0x81, 0xfb, 0xd5, 0xf4, 0xae, 0x06, 0xeb, 0xe1, 0x63, 0x07, 0x54, 0x5e,
|
||||
0x36, 0xf5, 0xb3, 0x11,
|
||||
0x99, 0xc4, 0x47, 0xde, 0xe1, 0xd0, 0xdf, 0xa6, 0x47, 0xa8, 0x53, 0xc2,
|
||||
0x62, 0x2a, 0x51, 0xab,
|
||||
0x64, 0xa5, 0xe4, 0x55, 0xb5, 0x6b, 0x2d, 0xa2, 0xd5, 0xe1, 0x33, 0x2f,
|
||||
0x92, 0xca, 0x76, 0xab,
|
||||
0x85, 0xb2, 0x07, 0x7b, 0xe0, 0x7b, 0x82, 0x4c, 0x34, 0xa6, 0x48, 0x5c,
|
||||
0x4d, 0xe7, 0x84, 0x6e,
|
||||
0xb3, 0xc2, 0x22, 0xc6, 0x4b, 0xb5, 0xbd, 0x0a, 0x9e, 0x1b, 0x39, 0xd5,
|
||||
0xed, 0x0e, 0x88, 0x8d,
|
||||
0x58, 0x26, 0xcf, 0xe7, 0x69, 0x77, 0x01, 0xb9, 0xcc, 0x0e, 0xf2, 0xfc,
|
||||
0x9e, 0x82, 0x8f, 0xc3,
|
||||
0x53, 0xd6, 0x63, 0xe3, 0x31, 0x70, 0x63, 0xfd, 0x89, 0xc6, 0x53, 0x54,
|
||||
0xad, 0x51, 0xa5, 0xdf,
|
||||
0x05, 0x70, 0x68, 0xb8, 0x7e, 0xd6, 0x41, 0x7f, 0x0f, 0x7c, 0x2e, 0xc1,
|
||||
0x32, 0x8e, 0x00, 0xcf,
|
||||
0xd5, 0xc7, 0x51, 0x7b, 0xcd, 0x64, 0xcc, 0x5e, 0x6c, 0xdb, 0xa8, 0xef,
|
||||
0xee, 0x7b, 0x7e, 0xf2,
|
||||
0x99, 0xd1, 0x81, 0x88, 0x1f, 0xeb, 0x33, 0xaf, 0x80, 0xb5, 0x1a, 0xf4,
|
||||
0xdf, 0x32, 0x6e, 0x44,
|
||||
0x0b, 0x63, 0x2d, 0x3d, 0x85, 0xf2, 0x34, 0x5c, 0xa8, 0x3b, 0x14, 0x2b,
|
||||
0xe0, 0xc2, 0xf7, 0x0d,
|
||||
0x0a, 0xf5, 0x54, 0xc9, 0x86, 0x2f, 0x2a, 0xbb, 0x14, 0xfa, 0xf5, 0x8d,
|
||||
0x93, 0x9e, 0xd8, 0x69,
|
||||
0x9f, 0xec, 0x35, 0xb1, 0xc7, 0x47, 0x3b, 0x4d, 0xe4, 0xe3, 0x5c, 0x1f,
|
||||
0x0e, 0x9e, 0x83, 0xfe,
|
||||
0x2e, 0xf7, 0xa8, 0x9d, 0xf0, 0x91, 0xeb, 0xd3, 0xef, 0x20, 0xd2, 0x32,
|
||||
0xf5, 0x53, 0x92, 0x5c,
|
||||
0x9f, 0x75, 0xc6, 0xcb, 0x7d, 0x5c, 0x7b, 0xfc, 0xa8, 0x2b, 0xbc, 0x42,
|
||||
0x14, 0x54, 0x48, 0x95,
|
||||
0x31, 0x49, 0x62, 0x6a, 0xbb, 0x24, 0x76, 0x9b, 0xd5, 0x39, 0x22, 0xa9,
|
||||
0xa0, 0x2a, 0xaf, 0x4c,
|
||||
0x3f, 0xe5, 0x69, 0x81, 0xb3, 0xb6, 0xd8, 0x8f, 0xb6, 0x1a, 0xd0, 0x44,
|
||||
0x9e, 0xcf, 0x4e, 0x94,
|
||||
0x1b, 0xf0, 0x0d, 0x21, 0x3b, 0xfb, 0xd3, 0x16, 0x7d, 0x3a, 0x1c, 0x63,
|
||||
0x19, 0x91, 0xab, 0xdf,
|
||||
0x99, 0xb2, 0x41, 0xc1, 0xfa, 0xb6, 0x52, 0x1e, 0xbc, 0x3f, 0x48, 0xc6,
|
||||
0x53, 0x2b, 0xec, 0xd5,
|
||||
0x92, 0xb5, 0x7d, 0xdf, 0x2b, 0x0f, 0xdf, 0xf8, 0x3b, 0xde, 0xbf, 0x1f,
|
||||
0xec, 0xc4, 0x3b, 0xd3,
|
||||
0x7c, 0xfa, 0x62, 0xe5, 0x79, 0xfd, 0xac, 0xd8, 0xee, 0xf7, 0x7e, 0x56,
|
||||
0x0a, 0x9a, 0xdf, 0xc5,
|
||||
0x8e, 0x51, 0x4e, 0xdd, 0xee, 0xcb, 0x5b, 0xbd, 0x96, 0x68, 0x9d, 0x7e,
|
||||
0x8f, 0x67, 0xac, 0x9f,
|
||||
0x3c, 0x79, 0xc4, 0xc7, 0x34, 0x3c, 0xae, 0xc8, 0xef, 0x9d, 0x2a, 0x97,
|
||||
0x4c, 0x07, 0x02, 0xea,
|
||||
0x46, 0x61, 0x3b, 0x9e, 0x90, 0xe9, 0x33, 0x7e, 0x20, 0xf2, 0xef, 0x85,
|
||||
0x63, 0x57, 0xff, 0xcb,
|
||||
0xd4, 0x0f, 0xa3, 0x7d, 0xb4, 0x97, 0xa7, 0xdf, 0xfc, 0xf2, 0xdf, 0xd9,
|
||||
0x53, 0x38, 0x5f, 0xae,
|
||||
0x34, 0x67, 0x59, 0xd1, 0xcc, 0x9e, 0x33, 0x5e, 0xca, 0x8c, 0x2a, 0x89,
|
||||
0xc2, 0x66, 0xed, 0xaa,
|
||||
0xbb, 0xa6, 0xf6, 0x2e, 0xa9, 0xcc, 0x2a, 0xd1, 0x4f, 0xe3, 0x76, 0x06,
|
||||
0xbc, 0x7b, 0x7a, 0x10,
|
||||
0x3a, 0x4d, 0xfa, 0xee, 0x6a, 0x46, 0x80, 0xb7, 0x34, 0xd5, 0xfb, 0x8c,
|
||||
0xde, 0xdf, 0xb2, 0xf0,
|
||||
0xe5, 0xed, 0xac, 0xb2, 0x06, 0x4d, 0xa6, 0x59, 0xc6, 0x67, 0x04, 0x98,
|
||||
0x6b, 0xc0, 0x63, 0x12,
|
||||
0xba, 0x70, 0xad, 0xb2, 0x8b, 0xbc, 0x19, 0xd9, 0x66, 0x54, 0x0e, 0xb9,
|
||||
0x36, 0x01, 0x3f, 0x3b,
|
||||
0x08, 0xf6, 0x92, 0xa1, 0x92, 0x2d, 0x7d, 0x99, 0x9c, 0x40, 0x63, 0xc9,
|
||||
0x41, 0xe3, 0x65, 0xa4,
|
||||
0x7e, 0x27, 0xd1, 0xbb, 0x56, 0x2c, 0x1e, 0xb8, 0x0d, 0x3d, 0x57, 0xe1,
|
||||
0x39, 0x5e, 0x8a, 0xd9,
|
||||
0xe4, 0x80, 0x06, 0xbd, 0x56, 0x13, 0x76, 0x49, 0x69, 0xc3, 0x4f, 0x36,
|
||||
0xb6, 0x99, 0x88, 0x7f,
|
||||
0x8c, 0x27, 0x97, 0xa5, 0xb7, 0x91, 0xe9, 0x60, 0xd0, 0xfb, 0xbb, 0x3b,
|
||||
0xf5, 0x5d, 0x01, 0x2b,
|
||||
0x9d, 0x7e, 0xc4, 0xea, 0x2b, 0xee, 0x19, 0x07, 0xf5, 0x5b, 0x5c, 0xe9,
|
||||
0x54, 0x25, 0x99, 0x41,
|
||||
0xdf, 0x74, 0x4d, 0xd7, 0xef, 0x7d, 0xa9, 0x7b, 0x45, 0x07, 0x02, 0xae,
|
||||
0x73, 0x84, 0xd3, 0x29,
|
||||
0x79, 0xdf, 0x28, 0x97, 0xc8, 0xda, 0x2e, 0x09, 0xed, 0xaa, 0xc3, 0x53,
|
||||
0xfe, 0x54, 0x51, 0x99,
|
||||
0x5a, 0xa8, 0xdf, 0x91, 0x99, 0xab, 0xef, 0x9e, 0xb6, 0x45, 0x0b, 0x56,
|
||||
0x9b, 0x43, 0xa5, 0x9c,
|
||||
0xae, 0x9f, 0xfc, 0x59, 0x91, 0xca, 0x6a, 0x03, 0xb0, 0x8e, 0xf7, 0xf7,
|
||||
0x7e, 0xfa, 0xce, 0xe8,
|
||||
0x7e, 0x3c, 0xb6, 0xa7, 0x7e, 0x4a, 0x96, 0x1c, 0x10, 0xea, 0x5e, 0xed,
|
||||
0xdf, 0xe5, 0x7e, 0xf6,
|
||||
0xef, 0xc3, 0xee, 0x35, 0x5e, 0x25, 0xd2, 0xd4, 0x73, 0x6c, 0xdf, 0x71,
|
||||
0x59, 0xd4, 0x2b, 0x33,
|
||||
0xf4, 0x98, 0xc3, 0xfa, 0xdd, 0x87, 0x31, 0x96, 0x11, 0xea, 0x3d, 0xc4,
|
||||
0x44, 0xfc, 0x63, 0x33,
|
||||
0x36, 0x4b, 0xf4, 0xe3, 0x6c, 0x34, 0xf9, 0x6f, 0x33, 0xde, 0x19, 0x6f,
|
||||
0x69, 0x4b, 0xc3, 0x66,
|
||||
0xf3, 0xe0, 0xed, 0x10, 0xd9, 0xa7, 0x11, 0x7b, 0xfb, 0xf3, 0x96, 0x06,
|
||||
0xc7, 0xb5, 0xe8, 0xb7,
|
||||
0x42, 0x3f, 0xb9, 0x4c, 0xf6, 0x93, 0xe9, 0x70, 0x40, 0xcd, 0x28, 0xec,
|
||||
0x45, 0x37, 0x49, 0x3e,
|
||||
0x74, 0xfa, 0x60, 0xf7, 0x66, 0xcb, 0x8c, 0x03, 0x44, 0xf6, 0x20, 0xea,
|
||||
0xc5, 0xb6, 0xfa, 0xf3,
|
||||
0xcc, 0xc8, 0xa5, 0x4a, 0x7b, 0x9a, 0x88, 0x0c, 0xbc, 0xc2, 0x09, 0x5d,
|
||||
0x89, 0x15, 0x1a, 0x25,
|
||||
0x32, 0x4a, 0xc5, 0x99, 0x7a, 0xef, 0x6a, 0x52, 0x4a, 0x72, 0x81, 0xe1,
|
||||
0xd0, 0xf7, 0x60, 0x8f,
|
||||
0xb6, 0x79, 0xb2, 0xe4, 0xc2, 0x6b, 0xac, 0x5b, 0x23, 0xff, 0xa4, 0xe2,
|
||||
0x49, 0x32, 0xff, 0xe6,
|
||||
0x25, 0x41, 0x3f, 0x85, 0xf8, 0x03, 0x3b, 0x74, 0x9a, 0x65, 0xfd, 0xe7,
|
||||
0x18, 0x79, 0x54, 0x8f,
|
||||
0x9f, 0xce, 0x59, 0x6d, 0x28, 0x2d, 0x49, 0x8c, 0x8c, 0xb7, 0xcc, 0x4a,
|
||||
0x42, 0x0b, 0x51, 0xd2,
|
||||
0x89, 0x2a, 0x6c, 0x05, 0x94, 0x8f, 0x9a, 0x2b, 0xec, 0x23, 0x2e, 0x22,
|
||||
0x7d, 0x64, 0x51, 0x6f,
|
||||
0xaa, 0x3f, 0x84, 0x24, 0x47, 0xf5, 0xb8, 0x16, 0xf2, 0xa8, 0x7a, 0x56,
|
||||
0xe5, 0xed, 0x7d, 0x1e,
|
||||
0x8f, 0x79, 0x0d, 0xcf, 0x9c, 0x23, 0x43, 0x7c, 0xb4, 0x96, 0x0c, 0x9f,
|
||||
0x45, 0x44, 0x5a, 0x3d,
|
||||
0x19, 0xdd, 0xaa, 0xfb, 0xde, 0x9c, 0xc2, 0x8e, 0x6a, 0x4a, 0x3b, 0xe1,
|
||||
0x64, 0x84, 0x7e, 0x47,
|
||||
0xc2, 0xf3, 0x57, 0x20, 0x49, 0xd0, 0xeb, 0xcd, 0xce, 0xa9, 0xf6, 0xfb,
|
||||
0x68, 0x3f, 0x9d, 0xba,
|
||||
0x64, 0x3a, 0x12, 0x10, 0xea, 0xf9, 0xd4, 0x0a, 0x1f, 0x6f, 0x4b, 0xa5,
|
||||
0xb2, 0xac, 0xb6, 0x48,
|
||||
0xa6, 0x64, 0x6b, 0xa1, 0x32, 0x53, 0x7f, 0x77, 0x9e, 0xc8, 0xb8, 0x44,
|
||||
0x1f, 0x6d, 0xa8, 0xb7,
|
||||
0x34, 0x86, 0x72, 0x76, 0x18, 0x80, 0x8f, 0x05, 0x5b, 0xe3, 0x0c, 0x3b,
|
||||
0xad, 0x5d, 0x1c, 0x46,
|
||||
0xa1, 0xbc, 0xa8, 0xe2, 0x4c, 0xfd, 0x9d, 0xe0, 0xb4, 0xee, 0x31, 0x85,
|
||||
0x76, 0x9b, 0x43, 0xbd,
|
||||
0xc5, 0xb9, 0x5a, 0xce, 0x62, 0xd5, 0x40, 0x50, 0xbc, 0x55, 0xa3, 0xc1,
|
||||
0x1e, 0x44, 0xb9, 0x4b,
|
||||
0xc6, 0x68, 0xe2, 0xe4, 0x77, 0xc8, 0x93, 0xcd, 0x09, 0xf2, 0x2e, 0x5d,
|
||||
0xc7, 0xdf, 0xcd, 0xff,
|
||||
0xf1, 0x70, 0x78, 0x52, 0x8f, 0x57, 0xcf, 0x5f, 0x9e, 0xa5, 0x9e, 0xef,
|
||||
0x81, 0xd7, 0x7b, 0xfe,
|
||||
0xc2, 0x63, 0x0c, 0x9f, 0x9f, 0x92, 0xce, 0xf2, 0xbf, 0xe8, 0x7b, 0x8d,
|
||||
0x0f, 0xfd, 0xe3, 0xf8,
|
||||
0xe5, 0x26, 0x22, 0xe7, 0x2e, 0x93, 0x96, 0xaa, 0xac, 0xbb, 0xe0, 0x47,
|
||||
0x47, 0x4c, 0x0e, 0xf6,
|
||||
0xe1, 0x8f, 0xf7, 0x59, 0xfa, 0xef, 0xc2, 0x32, 0xa7, 0xe4, 0x18, 0x51,
|
||||
0x5d, 0x8a, 0x7f, 0x78,
|
||||
0xdb, 0x55, 0xcf, 0x20, 0xe2, 0x76, 0x35, 0xff, 0xde, 0x69, 0xb6, 0xdd,
|
||||
0x29, 0x8f, 0xd2, 0xa6,
|
||||
0x78, 0x3b, 0xc6, 0x5a, 0x6b, 0xb1, 0xf3, 0xed, 0xcc, 0xea, 0xa5, 0xff,
|
||||
0x8e, 0x7f, 0x00, 0xa7,
|
||||
0xd9, 0xee, 0xf2, 0x00, 0xb5, 0xdc, 0x21, 0xb4, 0xdb, 0xd3, 0x32, 0xcb,
|
||||
0x2a, 0x53, 0x60, 0xbc,
|
||||
0x86, 0x57, 0x45, 0x5b, 0xf8, 0xbe, 0x4b, 0xfe, 0xc2, 0x19, 0xd8, 0x77,
|
||||
0xfc, 0x31, 0x46, 0x6d,
|
||||
0xc1, 0x93, 0xd4, 0x59, 0x61, 0xa8, 0xe9, 0x27, 0x63, 0xf0, 0xc9, 0x27,
|
||||
0xf4, 0x1b, 0x2b, 0xc9,
|
||||
0xfa, 0x39, 0x52, 0x30, 0x9c, 0xd7, 0x6f, 0x69, 0xd8, 0x88, 0xab, 0x11,
|
||||
0xb5, 0x5d, 0x13, 0x5c,
|
||||
0xef, 0x11, 0x87, 0x8d, 0xca, 0x34, 0x72, 0x0d, 0xf5, 0xde, 0x73, 0x36,
|
||||
0xfd, 0x67, 0x7c, 0x9e,
|
||||
0xac, 0x7b, 0x71, 0x12, 0xad, 0x6d, 0x60, 0xbd, 0x7b, 0x24, 0x0c, 0xad,
|
||||
0xb7, 0x97, 0x9b, 0xf1,
|
||||
0x9c, 0x3a, 0x72, 0x80, 0xaa, 0x38, 0x5c, 0x3b, 0x96, 0x7a, 0xb3, 0x76,
|
||||
0xb5, 0xf9, 0xdc, 0xfe,
|
||||
0x14, 0x9f, 0x0e, 0xea, 0xea, 0xe5, 0x3e, 0xc6, 0x87, 0x11, 0x59, 0x1d,
|
||||
0xe5, 0x46, 0xfe, 0x7d,
|
||||
0x8c, 0x91, 0x4b, 0xb1, 0xd1, 0xeb, 0x7e, 0x2b, 0x9d, 0x82, 0xfe, 0x72,
|
||||
0x76, 0xb0, 0x74, 0xf7,
|
||||
0x3b, 0xd9, 0x8a, 0x5e, 0x11, 0x7e, 0xef, 0xed, 0x3f, 0x46, 0x85, 0x60,
|
||||
0x33, 0xfb, 0xb3, 0xc8,
|
||||
0xff, 0x4d, 0x50, 0x39, 0x0d, 0xad, 0x83, 0xec, 0x44, 0x19, 0x26, 0x32,
|
||||
0xf5, 0xb3, 0x4b, 0xf5,
|
||||
0xd4, 0xae, 0xde, 0xa7, 0x6d, 0x2a, 0xb6, 0xf2, 0xd0, 0x3a, 0xce, 0x8e,
|
||||
0x53, 0x8f, 0xae, 0xfa,
|
||||
0xcb, 0xe3, 0xd8, 0xf2, 0x51, 0xec, 0x34, 0x80, 0xda, 0x60, 0x1f, 0x3d,
|
||||
0x2d, 0xfa, 0x59, 0x92,
|
||||
0x97, 0x07, 0xab, 0x4c, 0x81, 0xa0, 0x9e, 0x9c, 0x2f, 0xd6, 0xbb, 0xba,
|
||||
0x67, 0x46, 0x25, 0xf9,
|
||||
0xf2, 0x4c, 0xc0, 0x71, 0x6b, 0xd0, 0xf0, 0x13, 0xd2, 0x15, 0x74, 0x46,
|
||||
0x13, 0x37, 0x92, 0x11,
|
||||
0x7b, 0xb0, 0xea, 0x26, 0xe8, 0xbf, 0x1e, 0x94, 0xfe, 0x69, 0x79, 0x1b,
|
||||
0x3d, 0x64, 0xc9, 0x58,
|
||||
0xc3, 0x26, 0xc3, 0xdc, 0x36, 0x53, 0x75, 0x48, 0x9f, 0xa2, 0xbc, 0x9c,
|
||||
0x2c, 0xfd, 0xf6, 0xfd,
|
||||
0x62, 0x79, 0x57, 0xce, 0x06, 0xc1, 0xeb, 0xfa, 0xfd, 0x8c, 0xdd, 0x68,
|
||||
0x76, 0x0e, 0x1e, 0xd9,
|
||||
0x84, 0xef, 0xb8, 0x5a, 0xcf, 0xb8, 0x39, 0x54, 0xfd, 0x67, 0xf5, 0xe5,
|
||||
0x9d, 0x71, 0x06, 0x4d,
|
||||
0xef, 0x45, 0xd7, 0xf3, 0xf5, 0x9d, 0xc3, 0xe5, 0xfa, 0x29, 0xb1, 0x7a,
|
||||
0x97, 0xe3, 0x8d, 0x00,
|
||||
0xf4, 0xcf, 0x58, 0x68, 0x9d, 0xd6, 0xbf, 0x9d, 0xf5, 0xa1, 0x77, 0xc6,
|
||||
0x0d, 0x57, 0xef, 0x19,
|
||||
0x68, 0x78, 0x56, 0xb4, 0xce, 0x73, 0xf5, 0xf9, 0x8e, 0xf6, 0x50, 0x7b,
|
||||
0xdd, 0x4f, 0x1a, 0xa5,
|
||||
0xc7, 0x66, 0xbd, 0xef, 0x1f, 0xc2, 0x63, 0x4e, 0xb9, 0xe9, 0x58, 0x69,
|
||||
0xb5, 0x95, 0xa9, 0xad,
|
||||
0x56, 0xac, 0x7c, 0xab, 0xcf, 0x6f, 0x04, 0x19, 0xaf, 0x68, 0x29, 0x3f,
|
||||
0xde, 0xe2, 0x7e, 0x5a,
|
||||
0xb9, 0x4c, 0x3f, 0xf3, 0x3b, 0x13, 0x50, 0x17, 0x56, 0xbc, 0x47, 0xb5,
|
||||
0x41, 0x2d, 0x44, 0x54,
|
||||
0x0d, 0x31, 0x6d, 0xd6, 0x2d, 0xa5, 0x6b, 0x55, 0x46, 0x6a, 0xba, 0x91,
|
||||
0xa6, 0xdf, 0x1e, 0x3a,
|
||||
0x8a, 0x5d, 0xcf, 0x07, 0xc4, 0x05, 0x0d, 0xf5, 0xde, 0xc9, 0x3b, 0xfa,
|
||||
0x0d, 0x95, 0xb7, 0xdc,
|
||||
0x2d, 0x6f, 0x5a, 0x70, 0x41, 0xbf, 0xe1, 0x63, 0x1d, 0xff, 0xa6, 0x7e,
|
||||
0x8b, 0xc7, 0x35, 0x47,
|
||||
0xfd, 0xff, 0x96, 0xdf, 0x28, 0x5f, 0xfa, 0x6f, 0x06, 0xa5, 0x76, 0x3e,
|
||||
0xe0, 0x5a, 0x17, 0x7c,
|
||||
0xd6, 0xf1, 0xef, 0xbb, 0x12, 0xde, 0xde, 0x72, 0x23, 0xd8, 0xac, 0x60,
|
||||
0xdc, 0xb6, 0xa5, 0x74,
|
||||
0xb9, 0xf1, 0xde, 0x15, 0x5d, 0xda, 0x78, 0x47, 0x6b, 0xe3, 0xc2, 0x65,
|
||||
0xe8, 0x9f, 0x97, 0x0f,
|
||||
0xc9, 0x64, 0x54, 0x2a, 0x46, 0xa6, 0x0c, 0xf6, 0xd8, 0xcc, 0xbd, 0xa7,
|
||||
0x65, 0xda, 0x93, 0x1d,
|
||||
0xc9, 0xd8, 0xcc, 0x2e, 0x9f, 0x6a, 0x5a, 0x21, 0xfc, 0x56, 0xf0, 0x29,
|
||||
0xf5, 0x21, 0xb5, 0x17,
|
||||
0x31, 0x35, 0xb0, 0xc6, 0x6b, 0xb3, 0x6e, 0xb3, 0xba, 0x46, 0x8c, 0x74,
|
||||
0x8c, 0xb1, 0xab, 0x9d,
|
||||
0x31, 0x82, 0xea, 0xe9, 0x22, 0xf1, 0xf8, 0xf3, 0xe1, 0x03, 0xf9, 0x38,
|
||||
0xf4, 0x4d, 0x11, 0xd7,
|
||||
0x80, 0xef, 0xd8, 0xc5, 0xe3, 0x24, 0xd1, 0x18, 0x23, 0x03, 0x2c, 0x71,
|
||||
0xa6, 0xce, 0x69, 0xb7,
|
||||
0x97, 0x8f, 0x49, 0x8b, 0x33, 0xe2, 0xe8, 0x7d, 0x41, 0x56, 0xc9, 0xd7,
|
||||
0xf2, 0x2f, 0x74, 0xfd,
|
||||
0x73, 0xe0, 0x13, 0x72, 0xc0, 0x0a, 0x7d, 0xaf, 0x2e, 0x84, 0x9f, 0x86,
|
||||
0x4d, 0xfa, 0x6f, 0x3d,
|
||||
0xe3, 0x8c, 0x44, 0xe9, 0x67, 0xb5, 0x19, 0xe8, 0x3a, 0xed, 0xb1, 0x98,
|
||||
0x04, 0x7b, 0xb4, 0x43,
|
||||
0xfd, 0x65, 0xe4, 0x10, 0x2a, 0x8c, 0x6f, 0x88, 0x8e, 0x8f, 0xae, 0x19,
|
||||
0x17, 0xc9, 0xc6, 0x71,
|
||||
0x32, 0x8c, 0xda, 0x3e, 0x84, 0x9f, 0x8e, 0xd1, 0x54, 0xdf, 0xd1, 0xc4,
|
||||
0x53, 0x9f, 0xda, 0xb0,
|
||||
0x78, 0x9f, 0xef, 0x9a, 0x20, 0x3f, 0xf6, 0x2d, 0x88, 0xc9, 0x55, 0xdf,
|
||||
0xa4, 0x13, 0x81, 0x96,
|
||||
0xd7, 0x49, 0xab, 0x7c, 0x46, 0x2e, 0xbd, 0x16, 0xa8, 0x68, 0x4d, 0x22,
|
||||
0x6e, 0x23, 0x43, 0xb8,
|
||||
0x76, 0x18, 0xd1, 0xf2, 0x4c, 0x6d, 0x58, 0x82, 0xff, 0xf7, 0xff, 0x75,
|
||||
0x9d, 0x34, 0x78, 0x4c,
|
||||
0xa4, 0xe1, 0xfa, 0xe6, 0xaa, 0x7e, 0x9c, 0xad, 0xd4, 0x77, 0xc4, 0x7d,
|
||||
0xfe, 0x13, 0x71, 0x51,
|
||||
0x7e, 0xe4, 0x3c, 0x38, 0x44, 0x46, 0xb8, 0xbf, 0x0b, 0x2b, 0xd2, 0x1e,
|
||||
0xe9, 0x08, 0x5d, 0xd7,
|
||||
0x70, 0xd9, 0xa2, 0x1c, 0x6d, 0x6c, 0xa6, 0x63, 0x2d, 0x7c, 0xd4, 0x73,
|
||||
0x32, 0xca, 0xfe, 0x82,
|
||||
0x28, 0x0c, 0xe4, 0x04, 0xf8, 0xa5, 0xfe, 0x0b, 0xba, 0x2f, 0xae, 0x1a,
|
||||
0xdf, 0x32, 0x6f, 0x89,
|
||||
0x0c, 0xc6, 0x62, 0x8a, 0xd2, 0x8b, 0xf6, 0x91, 0xd2, 0xab, 0xac, 0x57,
|
||||
0x7a, 0xaf, 0xf2, 0x5f,
|
||||
0xfb, 0x7a, 0x2a, 0xbd, 0x7b, 0x45, 0xf7, 0xb4, 0xee, 0xe5, 0xbd, 0xd2,
|
||||
0x2e, 0x37, 0xb6, 0x67,
|
||||
0x39, 0xe3, 0x18, 0xdb, 0xd3, 0x6c, 0x7b, 0x32, 0xfd, 0x91, 0xca, 0x47,
|
||||
0x52, 0x1f, 0xa9, 0xe8,
|
||||
0xc1, 0xdc, 0x9e, 0xf4, 0xf7, 0xcc, 0xe8, 0xf9, 0x4b, 0xca, 0x54, 0xd6,
|
||||
0x3b, 0xfd, 0xe1, 0xba,
|
||||
0xf0, 0x98, 0x40, 0xdf, 0xb5, 0x19, 0x36, 0xe9, 0xd9, 0xa4, 0x17, 0xec,
|
||||
0xc3, 0x1d, 0xc3, 0x65,
|
||||
0xb8, 0x0c, 0x92, 0x01, 0xd4, 0x23, 0xea, 0xef, 0x51, 0xbf, 0xba, 0x0a,
|
||||
0xa8, 0xbf, 0x83, 0x3d,
|
||||
0x2b, 0x29, 0xd2, 0x87, 0x0c, 0x0b, 0x15, 0x03, 0xbb, 0x95, 0xdd, 0x93,
|
||||
0xde, 0xb5, 0x21, 0x2c,
|
||||
0x22, 0x2c, 0x74, 0x5d, 0xf3, 0x15, 0xf0, 0xfb, 0x36, 0x89, 0xb5, 0x5e,
|
||||
0x05, 0x2f, 0xd8, 0x86,
|
||||
0x1a, 0x43, 0xf5, 0x77, 0x04, 0x3c, 0xad, 0x9f, 0x98, 0xb4, 0xea, 0xbf,
|
||||
0x66, 0xfd, 0xe6, 0x32,
|
||||
0xf8, 0xd6, 0xfd, 0x2d, 0xaa, 0xd5, 0xd8, 0x6b, 0xa0, 0x0c, 0xd5, 0x18,
|
||||
0x0e, 0x9d, 0xbb, 0x66,
|
||||
0x86, 0x8f, 0x0e, 0x7d, 0x33, 0xe6, 0xf5, 0xfd, 0x5e, 0xdb, 0xae, 0x75,
|
||||
0xff, 0x88, 0x1b, 0x6a,
|
||||
0x1b, 0x22, 0xcf, 0x81, 0xc1, 0xc4, 0x5a, 0x0f, 0xf6, 0xb7, 0x55, 0x3a,
|
||||
0x4f, 0xba, 0x6c, 0xd7,
|
||||
0xf6, 0x1b, 0xa4, 0x3d, 0xdf, 0x4f, 0x7c, 0x58, 0xf2, 0x19, 0xdd, 0x97,
|
||||
0x59, 0x6a, 0xee, 0x73,
|
||||
0xf6, 0x61, 0x8e, 0xbe, 0x13, 0xc3, 0x93, 0xc2, 0xab, 0x43, 0xdf, 0x6f,
|
||||
0x7b, 0xdd, 0xbf, 0xdb,
|
||||
0x96, 0x58, 0xbb, 0xb3, 0xe2, 0xd9, 0xd4, 0x21, 0xf6, 0x41, 0x0e, 0xd7,
|
||||
0x37, 0x32, 0xf4, 0x97,
|
||||
0xa7, 0xa8, 0x4a, 0xb2, 0x65, 0x99, 0xbc, 0x1d, 0xf0, 0x6f, 0xf9, 0x2f,
|
||||
0xca, 0x3e, 0xa9, 0x60,
|
||||
0xf7, 0x7a, 0x52, 0x47, 0x98, 0x9e, 0x63, 0x0c, 0x96, 0xa1, 0xc5, 0x0f,
|
||||
0x67, 0x87, 0xcf, 0xea,
|
||||
0x36, 0x2a, 0xa4, 0xd1, 0x5f, 0x26, 0xd6, 0xc2, 0x67, 0x85, 0x47, 0x3c,
|
||||
0x58, 0x3c, 0x30, 0x7b,
|
||||
0xa0, 0x7d, 0x80, 0x0c, 0x70, 0x7f, 0xf7, 0xf0, 0x33, 0xd8, 0xe4, 0x31,
|
||||
0x79, 0x1c, 0xdb, 0x64,
|
||||
0x4a, 0x91, 0x4c, 0x90, 0x49, 0x52, 0xc6, 0x19, 0x3d, 0x9a, 0xfc, 0xf9,
|
||||
0x88, 0x74, 0x97, 0xde,
|
||||
0xc4, 0x97, 0x7b, 0xac, 0xf1, 0xac, 0x0c, 0xca, 0x7f, 0xca, 0x76, 0x9b,
|
||||
0x33, 0x3c, 0xa2, 0x5b,
|
||||
0x28, 0xc6, 0x7e, 0x59, 0xbb, 0x39, 0x6f, 0x8d, 0x78, 0xb4, 0x70, 0x60,
|
||||
0xee, 0xb3, 0xf6, 0xfe,
|
||||
0xe2, 0x85, 0x7a, 0x7a, 0xd7, 0x5b, 0x7a, 0x49, 0x4f, 0x62, 0xaf, 0x27,
|
||||
0x9f, 0x9e, 0xd1, 0xdf,
|
||||
0x28, 0x6d, 0x02, 0x1b, 0x0f, 0x32, 0x7a, 0x19, 0xf7, 0xcc, 0x08, 0x8f,
|
||||
0x0a, 0xd9, 0xeb, 0xd7,
|
||||
0x8a, 0xb7, 0x6e, 0xa3, 0x1e, 0x1c, 0xff, 0x74, 0x66, 0x7f, 0x5b, 0xbf,
|
||||
0xfc, 0xbe, 0x46, 0x5f,
|
||||
0x09, 0x0a, 0xfa, 0xfa, 0xd9, 0xfa, 0x3b, 0xfa, 0x16, 0x3e, 0x9e, 0x7b,
|
||||
0x47, 0x7d, 0xd8, 0xe8,
|
||||
0x50, 0x4e, 0xfc, 0xd5, 0xf3, 0xe4, 0xa8, 0x3b, 0x26, 0x3f, 0x9c, 0xd0,
|
||||
0xd3, 0x20, 0xca, 0xf2,
|
||||
0xfa, 0xe6, 0xf7, 0xb5, 0xf7, 0x71, 0xf4, 0x31, 0xfa, 0x88, 0xbe, 0xec,
|
||||
0x7d, 0x1d, 0x7d, 0x6d,
|
||||
0xfd, 0x1c, 0xfd, 0xed, 0xcf, 0x38, 0x9e, 0xa8, 0xbc, 0x2f, 0x45, 0xed,
|
||||
0x85, 0xa1, 0xf8, 0xfa,
|
||||
0x6d, 0xd8, 0x4d, 0xd9, 0x22, 0xac, 0xa1, 0xdb, 0xa8, 0x3b, 0x6a, 0xef,
|
||||
0x8f, 0x7f, 0xa8, 0xf4,
|
||||
0xb1, 0x8c, 0x7f, 0x16, 0xf6, 0x18, 0xdb, 0xa3, 0xb0, 0x7b, 0xee, 0xe3,
|
||||
0xe3, 0xff, 0x91, 0xf5,
|
||||
0xc0, 0xa4, 0xbb, 0x93, 0x6e, 0x65, 0xff, 0x53, 0x7b, 0x60, 0xb7, 0x50,
|
||||
0x7c, 0xfd, 0x26, 0x6d,
|
||||
0x17, 0xde, 0xc0, 0xd5, 0x88, 0x8d, 0xd4, 0xa5, 0x3e, 0x63, 0xa7, 0x90,
|
||||
0xad, 0x42, 0x08, 0x21,
|
||||
0x30, 0xfe, 0x1f, 0x7e, 0x26, 0xe7, 0x5b
|
||||
};
|
148
source/ngc/gui/dvd.c
Normal file
148
source/ngc/gui/dvd.c
Normal file
@ -0,0 +1,148 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Nintendo Gamecube DVD Reading Library
|
||||
*
|
||||
* This is NOT a complete DVD library, in that it works for reading
|
||||
* ISO9660 discs only.
|
||||
*
|
||||
* If you need softmod drivecodes etc, look elsewhere.
|
||||
* There are known issues with libogc dvd handling, so these work
|
||||
* outside of it ,if you will.
|
||||
*
|
||||
* This is ideal for using with a gc-linux self booting DVD only.
|
||||
* Go http://www.gc-linux.org for further information and the tools
|
||||
* for your platform.
|
||||
*
|
||||
* To keep libOGC stable, make sure you call DVD_Init before using
|
||||
* these functions.
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
|
||||
/** DVD I/O Address base **/
|
||||
volatile unsigned long *dvd = (volatile unsigned long *) 0xCC006000;
|
||||
static unsigned char *inquiry=(unsigned char *)0x80000004;
|
||||
|
||||
/** Due to lack of memory, we'll use this little 2k keyhole for all DVD operations **/
|
||||
unsigned char DVDreadbuffer[2048] ATTRIBUTE_ALIGN (32);
|
||||
|
||||
/***************************************************************************
|
||||
* dvd_read
|
||||
*
|
||||
* Read DVD disc sectors
|
||||
***************************************************************************/
|
||||
extern u8 isWII;
|
||||
|
||||
int dvd_read (void *dst, unsigned int len, u64 offset)
|
||||
{
|
||||
unsigned char *buffer = (unsigned char *) (unsigned int) DVDreadbuffer;
|
||||
|
||||
if (len > 2048) return 1; /*** We only allow 2k reads **/
|
||||
DCInvalidateRange((void *)buffer, len);
|
||||
|
||||
if(offset < 0x57057C00 || (isWII == 1 && offset < 0x118244F00LL)) // don't read past the end of the DVD
|
||||
{
|
||||
offset >>= 2;
|
||||
dvd[0] = 0x2E;
|
||||
dvd[1] = 0;
|
||||
dvd[2] = 0xA8000000;
|
||||
dvd[3] = (u32)offset;
|
||||
dvd[4] = len;
|
||||
dvd[5] = (unsigned long) buffer;
|
||||
dvd[6] = len;
|
||||
dvd[7] = 3; /*** Enable reading with DMA ***/
|
||||
while (dvd[7] & 1);
|
||||
memcpy (dst, buffer, len);
|
||||
}
|
||||
else return 0; // Let's not read past end of DVD
|
||||
|
||||
if (dvd[0] & 0x4) return 0; /* Ensure it has completed */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* uselessinquiry
|
||||
*
|
||||
* As the name suggests, this function is quite useless.
|
||||
* It's only purpose is to stop any pending DVD interrupts while we use the
|
||||
* memcard interface.
|
||||
*
|
||||
* libOGC tends to foul up if you don't, and sometimes does if you do!
|
||||
****************************************************************************/
|
||||
void uselessinquiry ()
|
||||
{
|
||||
|
||||
dvd[0] = 0;
|
||||
dvd[1] = 0;
|
||||
dvd[2] = 0x12000000;
|
||||
dvd[3] = 0;
|
||||
dvd[4] = 0x20;
|
||||
dvd[5] = 0x80000000;
|
||||
dvd[6] = 0x20;
|
||||
dvd[7] = 1;
|
||||
|
||||
while (dvd[7] & 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* dvd_motor_off
|
||||
*
|
||||
* Stop the DVD Motor
|
||||
*
|
||||
* This can be used to prevent the Disc from spinning during playtime
|
||||
****************************************************************************/
|
||||
void dvd_motor_off( )
|
||||
{
|
||||
dvd[0] = 0x2e;
|
||||
dvd[1] = 0;
|
||||
dvd[2] = 0xe3000000;
|
||||
dvd[3] = 0;
|
||||
dvd[4] = 0;
|
||||
dvd[5] = 0;
|
||||
dvd[6] = 0;
|
||||
dvd[7] = 1; // Do immediate
|
||||
while (dvd[7] & 1);
|
||||
|
||||
/*** PSO Stops blackscreen at reload ***/
|
||||
dvd[0] = 0x14;
|
||||
dvd[1] = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* dvd_inquiry
|
||||
*
|
||||
* Return the Current DVD Drive ID
|
||||
*
|
||||
* This can be used to determine whereas the console is a Gamecube or a Wii
|
||||
****************************************************************************/
|
||||
int dvd_inquiry()
|
||||
{
|
||||
dvd[0] = 0x2e;
|
||||
dvd[1] = 0;
|
||||
dvd[2] = 0x12000000;
|
||||
dvd[3] = 0;
|
||||
dvd[4] = 0x20;
|
||||
dvd[5] = 0x80000000;
|
||||
dvd[6] = 0x20;
|
||||
dvd[7] = 3;
|
||||
while( dvd[7] & 1 );
|
||||
DCFlushRange((void *)0x80000000, 32);
|
||||
return (int)inquiry[2];
|
||||
}
|
24
source/ngc/gui/dvd.h
Normal file
24
source/ngc/gui/dvd.h
Normal file
@ -0,0 +1,24 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
|
||||
extern int dvd_read (void *dst, unsigned int len, u64 offset);
|
||||
extern void uselessinquiry ();
|
||||
extern void dvd_motor_off ();
|
||||
extern int dvd_inquiry();
|
540
source/ngc/gui/filesel.c
Normal file
540
source/ngc/gui/filesel.c
Normal file
@ -0,0 +1,540 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* File Selection
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
#include "dvd.h"
|
||||
#include "iso9660.h"
|
||||
#include "font.h"
|
||||
#include "unzip.h"
|
||||
|
||||
#define PAGESIZE 12
|
||||
#define PADCAL 70
|
||||
|
||||
static int maxfiles;
|
||||
u8 havedir = 0;
|
||||
u8 haveSDdir = 0;
|
||||
u8 UseSDCARD = 0;
|
||||
sd_file *filehandle;
|
||||
char rootSDdir[SDCARD_MAX_PATH_LEN];
|
||||
int LoadFile (unsigned char *buffer);
|
||||
int offset = 0;
|
||||
int selection = 0;
|
||||
int old_selection = 0;
|
||||
int old_offset = 0;
|
||||
|
||||
extern void reloadrom ();
|
||||
|
||||
/***************************************************************************
|
||||
* Showfile screen
|
||||
***************************************************************************/
|
||||
static void ShowFiles (int offset, int selection)
|
||||
{
|
||||
int i, j;
|
||||
char text[MAXJOLIET+2];
|
||||
|
||||
ClearScreen ();
|
||||
j = 0;
|
||||
|
||||
for (i = offset; i < (offset + PAGESIZE) && (i < maxfiles); i++)
|
||||
{
|
||||
memset(text,0,MAXJOLIET+2);
|
||||
if (filelist[i].flags) sprintf(text, "[%s]", filelist[i].filename + filelist[i].filename_offset);
|
||||
else sprintf (text, "%s", filelist[i].filename + filelist[i].filename_offset);
|
||||
|
||||
if (j == (selection - offset)) WriteCentre_HL ((j * fheight) + 120, text);
|
||||
else WriteCentre ((j * fheight) + 120, text);
|
||||
j++;
|
||||
}
|
||||
SetScreen ();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Update SDCARD curent directory name
|
||||
***************************************************************************/
|
||||
int updateSDdirname()
|
||||
{
|
||||
int size=0;
|
||||
char *test;
|
||||
char temp[1024];
|
||||
|
||||
/* current directory doesn't change */
|
||||
if (strcmp(filelist[selection].filename,".") == 0) return 0;
|
||||
|
||||
/* go up to parent directory */
|
||||
else if (strcmp(filelist[selection].filename,"..") == 0)
|
||||
{
|
||||
/* determine last subdirectory namelength */
|
||||
sprintf(temp,"%s",rootSDdir);
|
||||
test= strtok(temp,"\\");
|
||||
while (test != NULL)
|
||||
{
|
||||
size = strlen(test);
|
||||
test = strtok(NULL,"\\");
|
||||
}
|
||||
|
||||
/* remove last subdirectory name */
|
||||
size = strlen(rootSDdir) - size - 1;
|
||||
rootSDdir[size] = 0;
|
||||
|
||||
/* handles root name */
|
||||
if (strcmp(rootSDdir,"dev0:") == 0) sprintf(rootSDdir,"dev0:\\genplus\\..");
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* test new directory namelength */
|
||||
if ((strlen(rootSDdir)+1+strlen(filelist[selection].filename)) < SDCARD_MAX_PATH_LEN)
|
||||
{
|
||||
/* handles root name */
|
||||
if (strcmp(rootSDdir,"dev0:\\genplus\\..") == 0) sprintf(rootSDdir,"dev0:");
|
||||
|
||||
/* update current directory name */
|
||||
sprintf(rootSDdir, "%s\\%s",rootSDdir, filelist[selection].filename);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WaitPrompt ("Dirname is too long !");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Browse SDCARD subdirectories
|
||||
***************************************************************************/
|
||||
int parseSDdirectory()
|
||||
{
|
||||
int entries = 0;
|
||||
int nbfiles = 0;
|
||||
DIR *sddir = NULL;
|
||||
|
||||
/* Get a list of files from the actual root directory */
|
||||
entries = SDCARD_ReadDir (rootSDdir, &sddir);
|
||||
|
||||
if (entries < 0) entries = 0;
|
||||
if (entries > MAXFILES) entries = MAXFILES;
|
||||
|
||||
/* Move to DVD structure - this is required for the file selector */
|
||||
while (entries)
|
||||
{
|
||||
memset (&filelist[nbfiles], 0, sizeof (FILEENTRIES));
|
||||
strncpy(filelist[nbfiles].filename,sddir[nbfiles].fname,MAXJOLIET);
|
||||
filelist[nbfiles].filename[MAXJOLIET-1] = 0;
|
||||
filelist[nbfiles].length = sddir[nbfiles].fsize;
|
||||
filelist[nbfiles].flags = (char)(sddir[nbfiles].fattr & SDCARD_ATTR_DIR);
|
||||
nbfiles++;
|
||||
entries--;
|
||||
}
|
||||
|
||||
/*** Release memory ***/
|
||||
free(sddir);
|
||||
|
||||
return nbfiles;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* FileSelector
|
||||
*
|
||||
* Let user select a file from the File listing
|
||||
****************************************************************************/
|
||||
void FileSelector ()
|
||||
{
|
||||
short p;
|
||||
signed char a,b;
|
||||
int haverom = 0;
|
||||
int redraw = 1;
|
||||
int go_up = 0;
|
||||
int i,size;
|
||||
|
||||
while (haverom == 0)
|
||||
{
|
||||
if (redraw) ShowFiles (offset, selection);
|
||||
redraw = 0;
|
||||
p = PAD_ButtonsDown (0);
|
||||
a = PAD_StickY (0);
|
||||
b = PAD_StickX (0);
|
||||
|
||||
/*
|
||||
* check selection screen changes
|
||||
*/
|
||||
|
||||
/* scroll displayed filename */
|
||||
if ((p & PAD_BUTTON_LEFT) || (b < -PADCAL))
|
||||
{
|
||||
if (filelist[selection].filename_offset > 0)
|
||||
{
|
||||
filelist[selection].filename_offset --;
|
||||
redraw = 1;
|
||||
}
|
||||
}
|
||||
else if ((p & PAD_BUTTON_RIGHT) || (b > PADCAL))
|
||||
{
|
||||
size = 0;
|
||||
for (i=filelist[selection].filename_offset; i<strlen(filelist[selection].filename); i++)
|
||||
size += font_size[(int)filelist[selection].filename[i]];
|
||||
|
||||
if (size > back_framewidth)
|
||||
{
|
||||
filelist[selection].filename_offset ++;
|
||||
redraw = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* highlight next item */
|
||||
else if ((p & PAD_BUTTON_DOWN) || (a < -PADCAL))
|
||||
{
|
||||
filelist[selection].filename_offset = 0;
|
||||
selection++;
|
||||
if (selection == maxfiles) selection = offset = 0;
|
||||
if ((selection - offset) >= PAGESIZE) offset += PAGESIZE;
|
||||
redraw = 1;
|
||||
}
|
||||
|
||||
/* highlight previous item */
|
||||
else if ((p & PAD_BUTTON_UP) || (a > PADCAL))
|
||||
{
|
||||
filelist[selection].filename_offset = 0;
|
||||
selection--;
|
||||
if (selection < 0)
|
||||
{
|
||||
selection = maxfiles - 1;
|
||||
offset = selection - PAGESIZE + 1;
|
||||
}
|
||||
if (selection < offset) offset -= PAGESIZE;
|
||||
if (offset < 0) offset = 0;
|
||||
redraw = 1;
|
||||
}
|
||||
|
||||
/* go back one page */
|
||||
else if (p & PAD_TRIGGER_L)
|
||||
{
|
||||
filelist[selection].filename_offset = 0;
|
||||
selection -= PAGESIZE;
|
||||
if (selection < 0)
|
||||
{
|
||||
selection = maxfiles - 1;
|
||||
offset = selection - PAGESIZE + 1;
|
||||
}
|
||||
if (selection < offset) offset -= PAGESIZE;
|
||||
if (offset < 0) offset = 0;
|
||||
redraw = 1;
|
||||
}
|
||||
|
||||
/* go forward one page */
|
||||
else if (p & PAD_TRIGGER_R)
|
||||
{
|
||||
filelist[selection].filename_offset = 0;
|
||||
selection += PAGESIZE;
|
||||
if (selection > maxfiles - 1) selection = offset = 0;
|
||||
if ((selection - offset) >= PAGESIZE) offset += PAGESIZE;
|
||||
redraw = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check pressed key
|
||||
*/
|
||||
|
||||
/* go up one directory or quit */
|
||||
if (p & PAD_BUTTON_B)
|
||||
{
|
||||
filelist[selection].filename_offset = 0;
|
||||
if (((!UseSDCARD) && (basedir == rootdir)) ||
|
||||
(UseSDCARD && strcmp(rootSDdir,"dev0:\\genplus\\..") == 0)) return;
|
||||
go_up = 1;
|
||||
}
|
||||
|
||||
/* quit */
|
||||
if (p & PAD_TRIGGER_Z)
|
||||
{
|
||||
filelist[selection].filename_offset = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* open selected file or directory */
|
||||
if ((p & PAD_BUTTON_A) || go_up)
|
||||
{
|
||||
filelist[selection].filename_offset = 0;
|
||||
if (go_up)
|
||||
{
|
||||
go_up = 0;
|
||||
selection = 1;
|
||||
}
|
||||
|
||||
/*** This is directory ***/
|
||||
if (filelist[selection].flags)
|
||||
{
|
||||
if (UseSDCARD) /* SDCARD directory handler */
|
||||
{
|
||||
/* update current directory */
|
||||
int status = updateSDdirname();
|
||||
|
||||
/* move to new directory */
|
||||
if (status == 1)
|
||||
{
|
||||
/* reinit selector (previous value is saved for one level) */
|
||||
if (selection == 1)
|
||||
{
|
||||
selection = old_selection;
|
||||
offset = old_offset;
|
||||
old_selection = 0;
|
||||
old_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* save current selector value */
|
||||
old_selection = selection;
|
||||
old_offset = offset;
|
||||
selection = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
|
||||
/* set new entry list */
|
||||
maxfiles = parseSDdirectory();
|
||||
if (!maxfiles)
|
||||
{
|
||||
/* quit */
|
||||
WaitPrompt ("Error reading directory !");
|
||||
haverom = 1;
|
||||
haveSDdir = 0;
|
||||
}
|
||||
}
|
||||
else if (status == -1)
|
||||
{
|
||||
/* quit */
|
||||
haverom = 1;
|
||||
haveSDdir = 0;
|
||||
}
|
||||
}
|
||||
else /* DVD directory handler */
|
||||
{
|
||||
/* move to a new directory */
|
||||
if (selection != 0)
|
||||
{
|
||||
/* update current directory */
|
||||
rootdir = filelist[selection].offset;
|
||||
rootdirlength = filelist[selection].length;
|
||||
|
||||
/* reinit selector (previous value is saved for one level) */
|
||||
if (selection == 1)
|
||||
{
|
||||
selection = old_selection;
|
||||
offset = old_offset;
|
||||
old_selection = 0;
|
||||
old_offset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* save current selector value */
|
||||
old_selection = selection;
|
||||
old_offset = offset;
|
||||
selection = 0;
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
/* get new entry list */
|
||||
maxfiles = parsedirectory ();
|
||||
}
|
||||
}
|
||||
}
|
||||
else /*** This is a file ***/
|
||||
{
|
||||
rootdir = filelist[selection].offset;
|
||||
rootdirlength = filelist[selection].length;
|
||||
genromsize = LoadFile (cart_rom);
|
||||
reloadrom ();
|
||||
haverom = 1;
|
||||
}
|
||||
redraw = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* OpenDVD
|
||||
*
|
||||
* Function to load a DVD directory and display to user.
|
||||
****************************************************************************/
|
||||
void OpenDVD ()
|
||||
{
|
||||
UseSDCARD = 0;
|
||||
if (!getpvd())
|
||||
{
|
||||
ShowAction("Mounting DVD ... Wait");
|
||||
DVD_Mount();
|
||||
havedir = 0;
|
||||
if (!getpvd())
|
||||
{
|
||||
WaitPrompt ("Failed to mount DVD");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (havedir == 0)
|
||||
{
|
||||
/* don't mess with SD entries */
|
||||
haveSDdir = 0;
|
||||
|
||||
/* reinit selector */
|
||||
rootdir = basedir;
|
||||
old_selection = selection = offset = old_offset = 0;
|
||||
|
||||
if ((maxfiles = parsedirectory ()))
|
||||
{
|
||||
FileSelector ();
|
||||
havedir = 1;
|
||||
}
|
||||
}
|
||||
else FileSelector ();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* OpenSD updated to use the new libogc. Written by softdev and pasted
|
||||
* into this code by Drack.
|
||||
* Modified for subdirectory browing & quick filelist recovery
|
||||
* Enjoy!
|
||||
*****************************************************************************/
|
||||
int OpenSD ()
|
||||
{
|
||||
UseSDCARD = 1;
|
||||
|
||||
if (haveSDdir == 0)
|
||||
{
|
||||
/* don't mess with DVD entries */
|
||||
havedir = 0;
|
||||
|
||||
/* reinit selector */
|
||||
old_selection = selection = offset = old_offset = 0;
|
||||
|
||||
/* Reset SDCARD root directory */
|
||||
sprintf(rootSDdir,"dev0:\\genplus\\roms");
|
||||
|
||||
/* Parse initial root directory and get entries list */
|
||||
ShowAction("Reading Directory ...");
|
||||
if ((maxfiles = parseSDdirectory ()))
|
||||
{
|
||||
/* Select an entry */
|
||||
FileSelector ();
|
||||
|
||||
/* memorize last entries list, actual root directory and selection for next access */
|
||||
haveSDdir = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* no entries found */
|
||||
WaitPrompt ("Error reading dev0:\\genplus\\roms");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* Retrieve previous entries list and made a new selection */
|
||||
else FileSelector ();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* SDCard Get Info
|
||||
****************************************************************************/
|
||||
void GetSDInfo ()
|
||||
{
|
||||
char fname[SDCARD_MAX_PATH_LEN];
|
||||
rootdirlength = 0;
|
||||
|
||||
/* Check filename length */
|
||||
if ((strlen(rootSDdir)+1+strlen(filelist[selection].filename)) < SDCARD_MAX_PATH_LEN)
|
||||
sprintf(fname, "%s\\%s",rootSDdir,filelist[selection].filename);
|
||||
|
||||
else
|
||||
{
|
||||
WaitPrompt ("Maximum Filename Length reached !");
|
||||
haveSDdir = 0; // reset everything before next access
|
||||
}
|
||||
|
||||
filehandle = SDCARD_OpenFile (fname, "rb");
|
||||
if (filehandle == NULL)
|
||||
{
|
||||
WaitPrompt ("Unable to open file!");
|
||||
return;
|
||||
}
|
||||
rootdirlength = SDCARD_GetFileSize (filehandle);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* LoadFile
|
||||
*
|
||||
* This function will load a file from DVD or SDCARD, in BIN, SMD or ZIP format.
|
||||
* The values for offset and length are inherited from rootdir and
|
||||
* rootdirlength.
|
||||
*
|
||||
* The buffer parameter should re-use the initial ROM buffer.
|
||||
****************************************************************************/
|
||||
int LoadFile (unsigned char *buffer)
|
||||
{
|
||||
int offset;
|
||||
int blocks;
|
||||
int i;
|
||||
u64 discoffset;
|
||||
char readbuffer[2048];
|
||||
|
||||
/* SDCard Addition */
|
||||
if (UseSDCARD) GetSDInfo ();
|
||||
|
||||
/* How many 2k blocks to read */
|
||||
if (rootdirlength == 0) return 0;
|
||||
blocks = rootdirlength / 2048;
|
||||
|
||||
offset = 0;
|
||||
discoffset = rootdir;
|
||||
ShowAction ("Loading ... Wait");
|
||||
|
||||
if (UseSDCARD) SDCARD_ReadFile (filehandle, &readbuffer, 2048);
|
||||
else dvd_read (&readbuffer, 2048, discoffset);
|
||||
|
||||
if (!IsZipFile ((char *) readbuffer))
|
||||
{
|
||||
if (UseSDCARD) SDCARD_SeekFile (filehandle, 0, SDCARD_SEEK_SET);
|
||||
|
||||
for (i = 0; i < blocks; i++)
|
||||
{
|
||||
if (UseSDCARD) SDCARD_ReadFile (filehandle, &readbuffer, 2048);
|
||||
else dvd_read(readbuffer, 2048, discoffset);
|
||||
memcpy (buffer + offset, readbuffer, 2048);
|
||||
offset += 2048;
|
||||
discoffset += 2048;
|
||||
}
|
||||
|
||||
/* And final cleanup */
|
||||
if (rootdirlength % 2048)
|
||||
{
|
||||
i = rootdirlength % 2048;
|
||||
if (UseSDCARD) SDCARD_ReadFile (filehandle, &readbuffer, i);
|
||||
else dvd_read (readbuffer, 2048, discoffset);
|
||||
memcpy (buffer + offset, readbuffer, i);
|
||||
}
|
||||
}
|
||||
else return UnZipBuffer (buffer, discoffset, rootdirlength);
|
||||
|
||||
if (UseSDCARD) SDCARD_CloseFile (filehandle);
|
||||
|
||||
return rootdirlength;
|
||||
}
|
388
source/ngc/gui/font.c
Normal file
388
source/ngc/gui/font.c
Normal file
@ -0,0 +1,388 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* IPL FONT Engine
|
||||
*
|
||||
* Based on Qoob MP3 Player Font
|
||||
* Added IPL font extraction
|
||||
*****************************************************************************/
|
||||
#include "shared.h"
|
||||
#include "font.h"
|
||||
#include "gpback.h"
|
||||
|
||||
/*** Backdrop ***/
|
||||
char backdrop[(640 * 480 * 2) + 32];
|
||||
|
||||
/* Backdrop Frame Width (to avoid writing outside of the background frame) */
|
||||
u16 back_framewidth = 640;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned short font_type, first_char, last_char, subst_char, ascent_units, descent_units, widest_char_width,
|
||||
leading_space, cell_width, cell_height;
|
||||
unsigned long texture_size;
|
||||
unsigned short texture_format, texture_columns, texture_rows, texture_width, texture_height, offset_charwidth;
|
||||
unsigned long offset_tile, size_tile;
|
||||
} FONT_HEADER;
|
||||
|
||||
static unsigned char fontWork[ 0x20000 ] __attribute__((aligned(32)));
|
||||
static unsigned char fontFont[ 0x40000 ] __attribute__((aligned(32)));
|
||||
extern unsigned int *xfb[2];
|
||||
extern int whichfb;
|
||||
|
||||
/****************************************************************************
|
||||
* YAY0 Decoding
|
||||
****************************************************************************/
|
||||
/* Yay0 decompression */
|
||||
void yay0_decode(unsigned char *s, unsigned char *d)
|
||||
{
|
||||
int i, j, k, p, q, cnt;
|
||||
|
||||
i = *(unsigned long *)(s + 4); // size of decoded data
|
||||
j = *(unsigned long *)(s + 8); // link table
|
||||
k = *(unsigned long *)(s + 12); // byte chunks and count modifiers
|
||||
|
||||
q = 0; // current offset in dest buffer
|
||||
cnt = 0; // mask bit counter
|
||||
p = 16; // current offset in mask table
|
||||
|
||||
unsigned long r22 = 0, r5;
|
||||
|
||||
do
|
||||
{
|
||||
// if all bits are done, get next mask
|
||||
if(cnt == 0)
|
||||
{
|
||||
// read word from mask data block
|
||||
r22 = *(unsigned long *)(s + p);
|
||||
p += 4;
|
||||
cnt = 32; // bit counter
|
||||
}
|
||||
// if next bit is set, chunk is non-linked
|
||||
if(r22 & 0x80000000)
|
||||
{
|
||||
// get next byte
|
||||
*(unsigned char *)(d + q) = *(unsigned char *)(s + k);
|
||||
k++, q++;
|
||||
}
|
||||
// do copy, otherwise
|
||||
else
|
||||
{
|
||||
// read 16-bit from link table
|
||||
int r26 = *(unsigned short *)(s + j);
|
||||
j += 2;
|
||||
// 'offset'
|
||||
int r25 = q - (r26 & 0xfff);
|
||||
// 'count'
|
||||
int r30 = r26 >> 12;
|
||||
if(r30 == 0)
|
||||
{
|
||||
// get 'count' modifier
|
||||
r5 = *(unsigned char *)(s + k);
|
||||
k++;
|
||||
r30 = r5 + 18;
|
||||
}
|
||||
else r30 += 2;
|
||||
// do block copy
|
||||
unsigned char *pt = ((unsigned char*)d) + r25;
|
||||
int i;
|
||||
for(i=0; i<r30; i++)
|
||||
{
|
||||
*(unsigned char *)(d + q) = *(unsigned char *)(pt - 1);
|
||||
q++, pt++;
|
||||
}
|
||||
}
|
||||
// next bit in mask
|
||||
r22 <<= 1;
|
||||
cnt--;
|
||||
|
||||
} while(q < i);
|
||||
}
|
||||
|
||||
void untile(unsigned char *dst, unsigned char *src, int xres, int yres)
|
||||
{
|
||||
// 8x8 tiles
|
||||
int x, y;
|
||||
int t=0;
|
||||
for (y = 0; y < yres; y += 8)
|
||||
for (x = 0; x < xres; x += 8)
|
||||
{
|
||||
t = !t;
|
||||
int iy, ix;
|
||||
for (iy = 0; iy < 8; ++iy, src+=2)
|
||||
{
|
||||
unsigned char *d = dst + (y + iy) * xres + x;
|
||||
for (ix = 0; ix < 2; ++ix)
|
||||
{
|
||||
int v = src[ix];
|
||||
*d++ = ((v>>6)&3);
|
||||
*d++ = ((v>>4)&3);
|
||||
*d++ = ((v>>2)&3);
|
||||
*d++ = ((v)&3);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int font_offset[256], font_size[256], fheight;
|
||||
extern void __SYS_ReadROM(void *buf,u32 len,u32 offset);
|
||||
|
||||
void init_font(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
__SYS_ReadROM((unsigned char *)&fontFont,0x3000,0x1FCF00);
|
||||
yay0_decode((unsigned char *)&fontFont, (unsigned char *)&fontWork);
|
||||
FONT_HEADER *fnt;
|
||||
|
||||
fnt = ( FONT_HEADER * )&fontWork;
|
||||
|
||||
untile((unsigned char*)&fontFont, (unsigned char*)&fontWork[fnt->offset_tile], fnt->texture_width, fnt->texture_height);
|
||||
|
||||
for (i=0; i<256; ++i)
|
||||
{
|
||||
int c = i;
|
||||
|
||||
if ((c < fnt->first_char) || (c > fnt->last_char)) c = fnt->subst_char;
|
||||
else c -= fnt->first_char;
|
||||
|
||||
font_size[i] = ((unsigned char*)fnt)[fnt->offset_charwidth + c];
|
||||
|
||||
int r = c / fnt->texture_columns;
|
||||
c %= fnt->texture_columns;
|
||||
font_offset[i] = (r * fnt->cell_height) * fnt->texture_width + (c * fnt->cell_width);
|
||||
}
|
||||
|
||||
fheight = fnt->cell_height;
|
||||
}
|
||||
|
||||
#define TRANSPARENCY (COLOR_BLACK)
|
||||
|
||||
unsigned int blit_lookup[4] = {COLOR_BLACK, 0x6d896d77, 0xb584b57b, 0xff80ff80};
|
||||
unsigned int blit_lookup_inv[4] = {COLOR_WHITE, 0xb584b57b, 0x6d896d77, 0x258e2573};
|
||||
|
||||
void setfontcolour (int fcolour)
|
||||
{
|
||||
if (fcolour == COLOR_WHITE)
|
||||
{
|
||||
blit_lookup[1] = 0x6d896d77;
|
||||
blit_lookup[2] = 0xb584b57b;
|
||||
blit_lookup[3] = 0xff80ff80;
|
||||
}
|
||||
else
|
||||
{
|
||||
blit_lookup[1] = fcolour;
|
||||
blit_lookup[2] = fcolour;
|
||||
blit_lookup[3] = fcolour;
|
||||
}
|
||||
}
|
||||
|
||||
void blit_char(int x, int y, unsigned char c, unsigned int *lookup)
|
||||
{
|
||||
unsigned char *fnt = ((unsigned char*)fontFont) + font_offset[c];
|
||||
int ay, ax;
|
||||
unsigned int llookup;
|
||||
|
||||
for (ay=0; ay<fheight; ++ay)
|
||||
{
|
||||
int h = (ay + y) * 320;
|
||||
|
||||
for (ax=0; ax<font_size[c]; ax++)
|
||||
{
|
||||
int v0 = fnt[ax];
|
||||
int p = h + (( ax + x ) >> 1);
|
||||
unsigned long o = xfb[whichfb][p];
|
||||
|
||||
llookup = lookup[v0];
|
||||
|
||||
if ((o != TRANSPARENCY) && (v0 == 0) && (lookup[0] == TRANSPARENCY))
|
||||
llookup = o;
|
||||
|
||||
if ((ax+x) & 1)
|
||||
{
|
||||
o &= ~0x00FFFFFF;
|
||||
o |= llookup & 0x00FFFFFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
o &= ~0xFF000000;
|
||||
o |= llookup & 0xFF000000;
|
||||
}
|
||||
|
||||
xfb[whichfb][p] = o;
|
||||
}
|
||||
|
||||
fnt += 512;
|
||||
}
|
||||
}
|
||||
|
||||
void write_font(int x, int y, const unsigned char *string)
|
||||
{
|
||||
int ox = x;
|
||||
while (*string && (x < (ox + back_framewidth)))
|
||||
{
|
||||
blit_char(x, y, *string, blit_lookup);
|
||||
x += font_size[*string];
|
||||
string++;
|
||||
}
|
||||
}
|
||||
|
||||
void writex(int x, int y, int sx, int sy, const unsigned char *string, unsigned int *lookup)
|
||||
{
|
||||
int ox = x;
|
||||
while ((*string) && ((x) < (ox + sx)))
|
||||
{
|
||||
blit_char(x, y, *string, lookup);
|
||||
x += font_size[*string];
|
||||
string++;
|
||||
}
|
||||
|
||||
int ay;
|
||||
for (ay=0; ay<sy; ay++)
|
||||
{
|
||||
int ax;
|
||||
for (ax=x; ax<(ox + sx); ax += 2) xfb[whichfb][(ay+y)*320+ax/2] = lookup[0];
|
||||
}
|
||||
}
|
||||
|
||||
void WriteCentre( int y, const unsigned char *string)
|
||||
{
|
||||
int x, t;
|
||||
for (x=t=0; t<strlen(string); t++) x += font_size[string[t]];
|
||||
if (x>back_framewidth) x=back_framewidth;
|
||||
x = (640 - x) >> 1;
|
||||
write_font(x, y, string);
|
||||
}
|
||||
|
||||
void WriteCentre_HL( int y, const unsigned char *string)
|
||||
{
|
||||
int x,t,h;
|
||||
for (x=t=0; t<strlen(string); t++) x += font_size[string[t]];
|
||||
if (x>back_framewidth) x = back_framewidth;
|
||||
h = x;
|
||||
x = (640 - x) >> 1;
|
||||
writex(x, y, h, fheight, string, blit_lookup_inv);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* Draw functions
|
||||
*
|
||||
****************************************************************************/
|
||||
void fntDrawHLine (int x1, int x2, int y, int color)
|
||||
{
|
||||
int i;
|
||||
y = 320 * y;
|
||||
x1 >>= 1;
|
||||
x2 >>= 1;
|
||||
for (i = x1; i <= x2; i++) xfb[whichfb][y + i] = color;
|
||||
}
|
||||
|
||||
void fntDrawVLine (int x, int y1, int y2, int color)
|
||||
{
|
||||
int i;
|
||||
x >>= 1;
|
||||
for (i = y1; i <= y2; i++) xfb[whichfb][x + (640 * i) / 2] = color;
|
||||
}
|
||||
|
||||
void fntDrawBox (int x1, int y1, int x2, int y2, int color)
|
||||
{
|
||||
fntDrawHLine (x1, x2, y1, color);
|
||||
fntDrawHLine (x1, x2, y2, color);
|
||||
fntDrawVLine (x1, y1, y2, color);
|
||||
fntDrawVLine (x2, y1, y2, color);
|
||||
}
|
||||
|
||||
void fntDrawBoxFilled (int x1, int y1, int x2, int y2, int color)
|
||||
{
|
||||
int h;
|
||||
for (h = y1; h <= y2; h++) fntDrawHLine (x1, x2, h, color);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Display functions
|
||||
*
|
||||
****************************************************************************/
|
||||
u8 SILENT = 0;
|
||||
|
||||
void SetScreen ()
|
||||
{
|
||||
VIDEO_SetNextFramebuffer (xfb[whichfb]);
|
||||
VIDEO_Flush ();
|
||||
VIDEO_WaitVSync ();
|
||||
}
|
||||
|
||||
void ClearScreen ()
|
||||
{
|
||||
whichfb ^= 1;
|
||||
memcpy (xfb[whichfb], &backdrop, 1280 * 480);
|
||||
back_framewidth = 440;
|
||||
}
|
||||
|
||||
void WaitPrompt (char *msg)
|
||||
{
|
||||
int quit = 0;
|
||||
|
||||
if (SILENT) return;
|
||||
|
||||
while (PAD_ButtonsDown(0) & PAD_BUTTON_A) {};
|
||||
while (!(PAD_ButtonsDown(0) & PAD_BUTTON_A) && (quit == 0))
|
||||
{
|
||||
ClearScreen();
|
||||
WriteCentre(254, msg);
|
||||
WriteCentre(254 + fheight, "Press A to Continue");
|
||||
SetScreen();
|
||||
while (!(PAD_ButtonsDown(0) & PAD_BUTTON_A));
|
||||
}
|
||||
}
|
||||
|
||||
void ShowAction (char *msg)
|
||||
{
|
||||
if (SILENT) return;
|
||||
|
||||
ClearScreen();
|
||||
WriteCentre(254, msg);
|
||||
SetScreen();
|
||||
}
|
||||
|
||||
void WaitButtonA ()
|
||||
{
|
||||
while (PAD_ButtonsDown(0) & PAD_BUTTON_A) {};
|
||||
while (!(PAD_ButtonsDown(0) & PAD_BUTTON_A));
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Unpack Backdrop
|
||||
*
|
||||
* Called at startup to unpack our backdrop to a temporary
|
||||
* framebuffer.
|
||||
****************************************************************************/
|
||||
void unpackBackdrop ()
|
||||
{
|
||||
unsigned long res, inbytes, outbytes;
|
||||
|
||||
inbytes = gpback_COMPRESSED;
|
||||
outbytes = gpback_RAW;
|
||||
res = uncompress ((char *) &backdrop[0], &outbytes, (char *) &gpback[0], inbytes);
|
||||
if (res != Z_OK) while (1);
|
||||
}
|
||||
|
42
source/ngc/gui/font.h
Normal file
42
source/ngc/gui/font.h
Normal file
@ -0,0 +1,42 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
***************************************************************************/
|
||||
/*****************************************************************************
|
||||
* IPL FONT Engine
|
||||
*
|
||||
* Based on Qoob MP3 Player Font
|
||||
* Added IPL font extraction
|
||||
*****************************************************************************/
|
||||
|
||||
extern void init_font(void);
|
||||
extern void WriteCentre_HL( int y, const unsigned char *string);
|
||||
extern void WriteCentre (int y, const unsigned char *text);
|
||||
extern void write_font (int x, int y, const unsigned char *text);
|
||||
extern void WaitPrompt (char *msg);
|
||||
extern void ShowAction (char *msg);
|
||||
extern void WaitButtonA ();
|
||||
extern void unpackBackdrop ();
|
||||
extern void ClearScreen ();
|
||||
extern void SetScreen ();
|
||||
extern void fntDrawBoxFilled (int x1, int y1, int x2, int y2, int color);
|
||||
extern void setfontcolour (int fcolour);
|
||||
extern int fheight;
|
||||
extern int font_size[256];
|
||||
extern u16 back_framewidth;
|
351
source/ngc/gui/ggentry.c
Normal file
351
source/ngc/gui/ggentry.c
Normal file
@ -0,0 +1,351 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Nintendo Gamecube Game Genie Entry
|
||||
***************************************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
#include "font.h"
|
||||
#include "rominfo.h"
|
||||
|
||||
#define MAXCODES 8
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int address;
|
||||
unsigned short data;
|
||||
} GGPATCH;
|
||||
|
||||
/*** Game Genie Codes Array ***/
|
||||
unsigned char ggcodes[MAXCODES][10]; /*** Codes are entered as XXXX-XXXX ***/
|
||||
int gghpos[MAXCODES]; /*** Edit positions ***/
|
||||
int ggrow = 0;
|
||||
int editing = 0;
|
||||
char ggvalidchars[] = "ABCDEFGHJKLMNPRSTVWXYZ0123456789*";
|
||||
GGPATCH ggpatch[8];
|
||||
extern char menutitle[];
|
||||
|
||||
/****************************************************************************
|
||||
* Decode Game Genie entries to memory patches
|
||||
****************************************************************************/
|
||||
void decode_genie (char *code, int which)
|
||||
{
|
||||
char *p;
|
||||
int n, i;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
/*** This should only happen if memory is corrupt! ***/
|
||||
p = strchr (ggvalidchars, code[i]);
|
||||
if (p == NULL)
|
||||
{
|
||||
ggpatch[which].address = ggpatch[which].data = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
n = p - ggvalidchars;
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
ggpatch[which].data |= n << 3;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
ggpatch[which].data |= n >> 2;
|
||||
ggpatch[which].address |= (n & 3) << 14;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
ggpatch[which].address |= n << 9;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
ggpatch[which].address |= (n & 0xF) << 20 | (n >> 4) << 8;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
ggpatch[which].data |= (n & 1) << 12;
|
||||
ggpatch[which].address |= (n >> 1) << 16;
|
||||
break;
|
||||
|
||||
case 5:
|
||||
ggpatch[which].data |= (n & 1) << 15 | (n >> 1) << 8;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
ggpatch[which].data |= (n >> 3) << 13;
|
||||
ggpatch[which].address |= (n & 7) << 5;
|
||||
break;
|
||||
|
||||
case 7:
|
||||
ggpatch[which].address |= n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void decode_ggcodes ()
|
||||
{
|
||||
int i, j;
|
||||
char thiscode[10];
|
||||
|
||||
/*** Clear out any old patches ***/
|
||||
memset (&ggpatch[0], 0, 8 * sizeof (GGPATCH));
|
||||
memset (&thiscode, 0, 10);
|
||||
|
||||
j = 0;
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
if (strcmp (ggcodes[i], "AAAA-AAAA"))
|
||||
{
|
||||
/*** Move the code into thiscode ***/
|
||||
memcpy (&thiscode, &ggcodes[i], 4);
|
||||
memcpy (&thiscode[4], &ggcodes[i][5], 4);
|
||||
|
||||
decode_genie (thiscode, j);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
/*** And now apply the patches ***/
|
||||
if (j)
|
||||
{
|
||||
for (i = 0; i < j; i++)
|
||||
{
|
||||
if (ggpatch[i].address < rominfo.romend)
|
||||
{
|
||||
/*** Patching ROM space ***/
|
||||
cart_rom[ggpatch[i].address] = ggpatch[i].data & 0x0ff;
|
||||
cart_rom[ggpatch[i].address + 1] = (ggpatch[i].data & 0xff00) >> 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*** Patching 68K memory ***/
|
||||
m68k_write_memory_16 (ggpatch[i].address, ggpatch[i].data);
|
||||
}
|
||||
}
|
||||
/* TODO : Fix Checksum */
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* ClearGGCodes
|
||||
*
|
||||
* Should be called whenever a new rom is loaded
|
||||
****************************************************************************/
|
||||
void ClearGGCodes ()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAXCODES; i++)
|
||||
{
|
||||
strcpy (ggcodes[i], "AAAA-AAAA");
|
||||
gghpos[i] = 0;
|
||||
}
|
||||
ggrow = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DrawGGCodes
|
||||
*
|
||||
* Just draw the codes, with the current one highlighted.
|
||||
****************************************************************************/
|
||||
void DrawGGCodes ()
|
||||
{
|
||||
int i,j;
|
||||
unsigned char c[2] = { 0, 0 };
|
||||
|
||||
ClearScreen ();
|
||||
WriteCentre (134, menutitle);
|
||||
|
||||
for (i = 0; i < MAXCODES; i++)
|
||||
{
|
||||
if (i == ggrow)
|
||||
{
|
||||
/*** Highlight selected ***/
|
||||
WriteCentre_HL (i * fheight + 224, ggcodes[i]);
|
||||
|
||||
/*** If editing, highlight the current character ***/
|
||||
if (editing)
|
||||
{
|
||||
int hpos = 0;
|
||||
|
||||
for (j=0; j<strlen (ggcodes[i]); j++) hpos += font_size[ggcodes[i][j]];
|
||||
hpos = ((640 - hpos) >> 1);
|
||||
for (j=0; j<gghpos[i]; j++) hpos += font_size[ggcodes[i][j]];
|
||||
|
||||
c[0] = ggcodes[i][gghpos[i]];
|
||||
fntDrawBoxFilled (hpos, (i * fheight) + 224, hpos + font_size[c[0]],
|
||||
((i + 1) * fheight) + 224, COLOR_YELLOW);
|
||||
setfontcolour (COLOR_BLUE);
|
||||
write_font (hpos, (i * fheight) + 224, c);
|
||||
setfontcolour (COLOR_WHITE);
|
||||
}
|
||||
}
|
||||
else WriteCentre ((i * fheight) + 224, ggcodes[i]);
|
||||
}
|
||||
SetScreen ();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* GGEditLine
|
||||
*
|
||||
* Up/Down traverses valid character array
|
||||
* Left/Right moves along current line
|
||||
* A exits edit mode
|
||||
****************************************************************************/
|
||||
void GGEditLine ()
|
||||
{
|
||||
short p;
|
||||
char c[2] = { 0, 0 };
|
||||
char *v;
|
||||
int redraw = 1;
|
||||
signed char x, y;
|
||||
|
||||
/** Lose any previous A press **/
|
||||
while (PAD_ButtonsDown (0) & PAD_BUTTON_A);
|
||||
|
||||
editing = 1;
|
||||
|
||||
while (!(PAD_ButtonsDown (0) & PAD_BUTTON_A))
|
||||
{
|
||||
if (redraw)
|
||||
{
|
||||
DrawGGCodes ();
|
||||
redraw = 0;
|
||||
}
|
||||
|
||||
p = PAD_ButtonsDown (0);
|
||||
x = PAD_StickX (0);
|
||||
y = PAD_StickY (0);
|
||||
|
||||
if ((p & PAD_BUTTON_UP) || (y > 70))
|
||||
{
|
||||
/*** Increment the entry ***/
|
||||
redraw = 1;
|
||||
c[0] = ggcodes[ggrow][gghpos[ggrow]];
|
||||
v = strstr (ggvalidchars, c);
|
||||
v++;
|
||||
if (*v == '*') ggcodes[ggrow][gghpos[ggrow]] = 'A';
|
||||
else ggcodes[ggrow][gghpos[ggrow]] = *v;
|
||||
}
|
||||
|
||||
if ((p & PAD_BUTTON_DOWN) || (y < -70))
|
||||
{
|
||||
/*** Decrement entry ***/
|
||||
redraw = 1;
|
||||
c[0] = ggcodes[ggrow][gghpos[ggrow]];
|
||||
v = strstr (ggvalidchars, c);
|
||||
if (*v == 'A') ggcodes[ggrow][gghpos[ggrow]] = '9';
|
||||
else
|
||||
{
|
||||
v--;
|
||||
ggcodes[ggrow][gghpos[ggrow]] = *v;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p & PAD_BUTTON_LEFT) || (x < -70))
|
||||
{
|
||||
redraw = 1;
|
||||
gghpos[ggrow]--;
|
||||
if (gghpos[ggrow] == 4) gghpos[ggrow]--;
|
||||
}
|
||||
|
||||
if ((p & PAD_BUTTON_RIGHT) || (x > 70))
|
||||
{
|
||||
redraw = 1;
|
||||
gghpos[ggrow]++;
|
||||
if (gghpos[ggrow] == 4) gghpos[ggrow]++;
|
||||
}
|
||||
|
||||
if (gghpos[ggrow] < 0) gghpos[ggrow] = 8;
|
||||
if (gghpos[ggrow] > 8) gghpos[ggrow] = 0;
|
||||
}
|
||||
|
||||
/** Lose any previous A press **/
|
||||
while (PAD_ButtonsDown (0) & PAD_BUTTON_A);
|
||||
|
||||
editing = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* GGSelectLine
|
||||
*
|
||||
* Select which line to edit
|
||||
****************************************************************************/
|
||||
void GGSelectLine ()
|
||||
{
|
||||
int redraw = 1;
|
||||
int quit = 0;
|
||||
short j;
|
||||
signed char y;
|
||||
|
||||
/*** To select a line, just move up or down.
|
||||
Pressing A will enter edit mode.
|
||||
Pressing B will exit to caller. ***/
|
||||
|
||||
while (!(PAD_ButtonsDown (0) & PAD_BUTTON_B) && (quit == 0))
|
||||
{
|
||||
if (redraw)
|
||||
{
|
||||
DrawGGCodes ();
|
||||
redraw = 0;
|
||||
}
|
||||
|
||||
j = PAD_ButtonsDown (0);
|
||||
y = PAD_StickY (0);
|
||||
|
||||
if ((j & PAD_BUTTON_UP) || (y > 70))
|
||||
{
|
||||
ggrow--;
|
||||
redraw = 1;
|
||||
}
|
||||
|
||||
if ((j & PAD_BUTTON_DOWN) || (y < -70))
|
||||
{
|
||||
ggrow++;
|
||||
redraw = 1;
|
||||
}
|
||||
|
||||
if (ggrow < 0) ggrow = MAXCODES - 1;
|
||||
if (ggrow == MAXCODES) ggrow = 0;
|
||||
|
||||
if (j & PAD_BUTTON_B) quit = 1;
|
||||
|
||||
if (j & PAD_BUTTON_A)
|
||||
{
|
||||
GGEditLine ();
|
||||
redraw = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* GetGGEntries
|
||||
*
|
||||
* Screen to return encoded Game Genie codes.
|
||||
* No keyboard is available, so it's just a simple wrap round each line kind
|
||||
* of thing.
|
||||
****************************************************************************/
|
||||
void GetGGEntries ()
|
||||
{
|
||||
editing = 0;
|
||||
strcpy (menutitle, "Game Genie Entry");
|
||||
GGSelectLine ();
|
||||
}
|
8991
source/ngc/gui/gpback.h
Normal file
8991
source/ngc/gui/gpback.h
Normal file
File diff suppressed because it is too large
Load Diff
239
source/ngc/gui/iso9660.c
Normal file
239
source/ngc/gui/iso9660.c
Normal file
@ -0,0 +1,239 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* DVD ISO9660/Joliet Parsing
|
||||
*
|
||||
* This is not intended as a complete guide to ISO9660.
|
||||
* Here I use the bare minimum!
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
#include "dvd.h"
|
||||
#include "iso9660.h"
|
||||
|
||||
/** Minimal ISO Directory Definition **/
|
||||
#define RECLEN 0 /* Record length */
|
||||
#define EXTENT 6 /* Extent */
|
||||
#define FILE_LENGTH 14 /* File length (BIG ENDIAN) */
|
||||
#define FILE_FLAGS 25 /* File flags */
|
||||
#define FILENAME_LENGTH 32 /* Filename length */
|
||||
#define FILENAME 33 /* ASCIIZ filename */
|
||||
|
||||
/** Minimal Primary Volume Descriptor **/
|
||||
#define PVDROOT 0x9c
|
||||
|
||||
static int IsJoliet = 0;
|
||||
u64 rootdir = 0;
|
||||
u64 basedir = 0;
|
||||
int rootdirlength = 0;
|
||||
|
||||
/** Global file entry table **/
|
||||
FILEENTRIES filelist[MAXFILES];
|
||||
static char dvdbuffer[2048];
|
||||
|
||||
/****************************************************************************
|
||||
* Primary Volume Descriptor
|
||||
*
|
||||
* The PVD should reside between sector 16 and 31.
|
||||
* This is for single session DVD only.
|
||||
****************************************************************************/
|
||||
int getpvd ()
|
||||
{
|
||||
int sector = 16;
|
||||
u32 rootdir32;
|
||||
|
||||
basedir = rootdirlength = 0;
|
||||
IsJoliet = -1;
|
||||
|
||||
/** Look for Joliet PVD first **/
|
||||
while (sector < 32)
|
||||
{
|
||||
if (dvd_read (&dvdbuffer, 2048, (u64)(sector << 11)))
|
||||
{
|
||||
if (memcmp (&dvdbuffer, "\2CD001\1", 8) == 0)
|
||||
{
|
||||
memcpy(&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4);
|
||||
basedir = (u64)rootdir32;
|
||||
memcpy (&rootdirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4);
|
||||
basedir <<= 11;
|
||||
IsJoliet = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else return 0; /*** Can't read sector! ***/
|
||||
sector++;
|
||||
}
|
||||
|
||||
if (IsJoliet > 0) return 1; /*** Joliet PVD Found ? ***/
|
||||
|
||||
/*** Look for standard ISO9660 PVD ***/
|
||||
sector = 16;
|
||||
while (sector < 32)
|
||||
{
|
||||
if (dvd_read (&dvdbuffer, 2048, (u64)(sector << 11)))
|
||||
{
|
||||
if (memcmp (&dvdbuffer, "\1CD001\1", 8) == 0)
|
||||
{
|
||||
memcpy (&rootdir32, &dvdbuffer[PVDROOT + EXTENT], 4);
|
||||
basedir = (u64)rootdir32;
|
||||
memcpy (&rootdirlength, &dvdbuffer[PVDROOT + FILE_LENGTH], 4);
|
||||
IsJoliet = 0;
|
||||
basedir <<= 11;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else return 0; /*** Can't read sector! ***/
|
||||
sector++;
|
||||
}
|
||||
|
||||
return (IsJoliet == 0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* getentry
|
||||
*
|
||||
* Support function to return the next file entry, if any
|
||||
* Declared static to avoid accidental external entry.
|
||||
****************************************************************************/
|
||||
static int diroffset = 0;
|
||||
static int getentry (int entrycount)
|
||||
{
|
||||
char fname[512]; /* Huge, but experience has determined this */
|
||||
char *ptr;
|
||||
char *filename;
|
||||
char *filenamelength;
|
||||
char *rr;
|
||||
int j;
|
||||
u32 offset32;
|
||||
|
||||
/* Basic checks */
|
||||
if (entrycount >= MAXFILES) return 0;
|
||||
if (diroffset >= 2048) return 0;
|
||||
|
||||
/** Decode this entry **/
|
||||
if (dvdbuffer[diroffset]) /* Record length available */
|
||||
{
|
||||
/* Update offsets into sector buffer */
|
||||
ptr = (char *) &dvdbuffer[0];
|
||||
ptr += diroffset;
|
||||
filename = ptr + FILENAME;
|
||||
filenamelength = ptr + FILENAME_LENGTH;
|
||||
|
||||
/* Check for wrap round - illegal in ISO spec,
|
||||
* but certain crap writers do it! */
|
||||
if ((diroffset + dvdbuffer[diroffset]) > 2048) return 0;
|
||||
|
||||
if (*filenamelength)
|
||||
{
|
||||
memset (&fname, 0, 512);
|
||||
|
||||
/*** Do ISO 9660 first ***/
|
||||
if (!IsJoliet) strcpy (fname, filename);
|
||||
else
|
||||
{
|
||||
/*** The more tortuous unicode joliet entries ***/
|
||||
for (j = 0; j < (*filenamelength >> 1); j++)
|
||||
{
|
||||
fname[j] = filename[j * 2 + 1];
|
||||
}
|
||||
|
||||
fname[j] = 0;
|
||||
|
||||
if (strlen (fname) >= MAXJOLIET) fname[MAXJOLIET - 1] = 0;
|
||||
if (strlen (fname) == 0) fname[0] = filename[0];
|
||||
}
|
||||
|
||||
if (strlen (fname) == 0) strcpy (fname, ".");
|
||||
else
|
||||
{
|
||||
if (fname[0] == 1) strcpy (fname, "..");
|
||||
else
|
||||
{
|
||||
/*
|
||||
* Move *filenamelength to t,
|
||||
* Only to stop gcc warning for noobs :)
|
||||
*/
|
||||
int t = *filenamelength;
|
||||
fname[t] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Rockridge Check **/
|
||||
rr = strstr (fname, ";");
|
||||
if (rr != NULL) *rr = 0;
|
||||
|
||||
strcpy (filelist[entrycount].filename, fname);
|
||||
memcpy (&offset32, &dvdbuffer[diroffset + EXTENT], 4);
|
||||
filelist[entrycount].offset = (u64)offset32;
|
||||
memcpy (&filelist[entrycount].length, &dvdbuffer[diroffset + FILE_LENGTH], 4);
|
||||
memcpy (&filelist[entrycount].flags, &dvdbuffer[diroffset + FILE_FLAGS], 1);
|
||||
|
||||
filelist[entrycount].offset <<= 11;
|
||||
filelist[entrycount].flags = filelist[entrycount].flags & 2;
|
||||
filelist[entrycount].filename_offset = 0;
|
||||
|
||||
/*** Prepare for next entry ***/
|
||||
diroffset += dvdbuffer[diroffset];
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* parsedirectory
|
||||
*
|
||||
* This function will parse the directory tree.
|
||||
* It relies on rootdir and rootdirlength being pre-populated by a call to
|
||||
* getpvd, a previous parse or a menu selection.
|
||||
*
|
||||
* The return value is number of files collected, or 0 on failure.
|
||||
****************************************************************************/
|
||||
int parsedirectory ()
|
||||
{
|
||||
int pdlength;
|
||||
u64 pdoffset;
|
||||
u64 rdoffset;
|
||||
int len = 0;
|
||||
int filecount = 0;
|
||||
|
||||
pdoffset = rdoffset = rootdir;
|
||||
pdlength = rootdirlength;
|
||||
filecount = 0;
|
||||
|
||||
/** Clear any existing values ***/
|
||||
memset (&filelist, 0, sizeof (FILEENTRIES) * MAXFILES);
|
||||
|
||||
/*** Get as many files as possible ***/
|
||||
while (len < pdlength)
|
||||
{
|
||||
if (dvd_read (&dvdbuffer, 2048, pdoffset) == 0) return 0;
|
||||
|
||||
diroffset = 0;
|
||||
|
||||
while (getentry (filecount))
|
||||
{
|
||||
if (filecount < MAXFILES) filecount++;
|
||||
}
|
||||
|
||||
len += 2048;
|
||||
pdoffset = rdoffset + len;
|
||||
}
|
||||
return filecount;
|
||||
}
|
44
source/ngc/gui/iso9660.h
Normal file
44
source/ngc/gui/iso9660.h
Normal file
@ -0,0 +1,44 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* DVD ISO9660/Joliet Parsing
|
||||
*
|
||||
* This is not intended as a complete guide to ISO9660.
|
||||
* Here I use the bare minimum!
|
||||
***************************************************************************/
|
||||
|
||||
#define MAXJOLIET 256
|
||||
#define MAXFILES 1000 /** Restrict to 1000 files per dir **/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 offset;
|
||||
unsigned int length;
|
||||
char flags;
|
||||
char filename[MAXJOLIET];
|
||||
u16 filename_offset;
|
||||
} FILEENTRIES;
|
||||
|
||||
extern u64 basedir;
|
||||
extern u64 rootdir;
|
||||
extern int rootdirlength;
|
||||
|
||||
extern int getpvd ();
|
||||
extern int parsedirectory ();
|
||||
extern FILEENTRIES filelist[MAXFILES];
|
100
source/ngc/gui/legal.c
Normal file
100
source/ngc/gui/legal.c
Normal file
@ -0,0 +1,100 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
#include "font.h"
|
||||
#include "dkpro.h"
|
||||
|
||||
extern u32 *xfb[2];
|
||||
extern int whichfb;
|
||||
|
||||
/*
|
||||
* Unpack the devkit pro logo
|
||||
*/
|
||||
u32 *dkproraw;
|
||||
|
||||
int dkunpack ()
|
||||
{
|
||||
unsigned long res, inbytes, outbytes;
|
||||
|
||||
inbytes = dkpro_COMPRESSED;
|
||||
outbytes = dkpro_RAW;
|
||||
dkproraw = malloc (dkpro_RAW + 16);
|
||||
res = uncompress ((char *) dkproraw, &outbytes, (char *) &dkpro[0], inbytes);
|
||||
if (res == Z_OK) return 1;
|
||||
free (dkproraw);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the legal stuff - which must be shown at program startup
|
||||
* Any derivative work MUST include the same textual output.
|
||||
*
|
||||
* In other words, play nice and give credit where it's due.
|
||||
*/
|
||||
void legal ()
|
||||
{
|
||||
int ypos = 64;
|
||||
|
||||
whichfb ^= 1;
|
||||
VIDEO_ClearFrameBuffer(&TVNtsc480IntDf, xfb[whichfb], COLOR_BLACK);
|
||||
back_framewidth = 640;
|
||||
|
||||
WriteCentre (ypos, "Genesis Plus Sega Mega Drive Emulator (v1.2a)");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "(C) 1999 - 2003 Charles MacDonald");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "This is free software, and you are welcome to");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "redistribute it under the conditions of the");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "GNU GENERAL PUBLIC LICENSE Version 2");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "Additionally, the developers of this port");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "disclaims all copyright interests in the ");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "Nintendo Gamecube Porting code.");
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "You are free to use it as you wish.");
|
||||
ypos += 6 * fheight;
|
||||
|
||||
if (dkunpack ())
|
||||
{
|
||||
int w, h, p, dispoffset;
|
||||
p = 0;
|
||||
dispoffset = (316 * 320) + ((640 - dkpro_WIDTH) >> 2);
|
||||
|
||||
for (h = 0; h < dkpro_HEIGHT; h++)
|
||||
{
|
||||
for (w = 0; w < dkpro_WIDTH >> 1; w++)
|
||||
xfb[whichfb][dispoffset + w] = dkproraw[p++];
|
||||
|
||||
dispoffset += 320;
|
||||
}
|
||||
|
||||
free (dkproraw);
|
||||
}
|
||||
else WriteCentre (ypos, "Developed with DevkitPPC and libOGC");
|
||||
|
||||
WriteCentre (ypos, "Press A to continue");
|
||||
SetScreen ();
|
||||
WaitButtonA ();
|
||||
}
|
587
source/ngc/gui/mcard.c
Normal file
587
source/ngc/gui/mcard.c
Normal file
@ -0,0 +1,587 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
#include "dvd.h"
|
||||
#include "font.h"
|
||||
#include "rominfo.h"
|
||||
#include "saveicon.h" /*** Nice little icon - thanks brakken! ***/
|
||||
|
||||
/* Support for MemCards */
|
||||
/**
|
||||
* libOGC System Work Area
|
||||
*/
|
||||
static u8 SysArea[CARD_WORKAREA] ATTRIBUTE_ALIGN (32);
|
||||
|
||||
/**
|
||||
* DMA Transfer Area.
|
||||
* Must be 32-byte aligned.
|
||||
* 64k SRAM + 2k Icon
|
||||
*/
|
||||
unsigned char savebuffer[0x24000] ATTRIBUTE_ALIGN (32);
|
||||
|
||||
card_dir CardDir;
|
||||
card_file CardFile;
|
||||
card_stat CardStatus;
|
||||
extern int CARDSLOT;
|
||||
extern int use_SDCARD;
|
||||
|
||||
int ManageSRAM (int direction);
|
||||
int ManageState (int direction);
|
||||
|
||||
/****************************************************************************
|
||||
* SRAM autoload
|
||||
*
|
||||
* the detection order is the following:
|
||||
* MCARD (SLOTA) > MCARD (SLOTB) > SDCARD (SLOTA) > SDCARD (SLOTB)
|
||||
*
|
||||
*****************************************************************************/
|
||||
extern u8 SILENT;
|
||||
|
||||
void sram_autoload()
|
||||
{
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
int old_cardslot = CARDSLOT;
|
||||
int old_sdcard = use_SDCARD;
|
||||
|
||||
SILENT = 1; /* this should be transparent to the user */
|
||||
while ((i < 4) && (!ret))
|
||||
{
|
||||
use_SDCARD = (i&2) ? 1 : 0;
|
||||
CARDSLOT = (i&1) ? CARD_SLOTB : CARD_SLOTA;
|
||||
ret = ManageSRAM(1);
|
||||
i++;
|
||||
}
|
||||
if (!ret)
|
||||
{
|
||||
/* restore old settings if not found */
|
||||
CARDSLOT = old_cardslot;
|
||||
use_SDCARD = old_sdcard;
|
||||
}
|
||||
SILENT = 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* SDCARD Access functions
|
||||
*
|
||||
* We use the same buffer as for Memory Card manager
|
||||
* Function returns TRUE on success.
|
||||
*****************************************************************************/
|
||||
int SD_ManageFile(char *filename, int direction, int filetype)
|
||||
{
|
||||
char name[1024];
|
||||
sd_file *handle;
|
||||
int len = 0;
|
||||
int offset = 0;
|
||||
int filesize;
|
||||
unsigned long inbytes,outbytes;
|
||||
|
||||
/* build complete SDCARD filename */
|
||||
sprintf (name, "dev%d:\\genplus\\saves\\%s", CARDSLOT, filename);
|
||||
|
||||
/* open file */
|
||||
handle = direction ? SDCARD_OpenFile (name, "rb") :
|
||||
SDCARD_OpenFile (name, "wb");
|
||||
|
||||
if (handle == NULL)
|
||||
{
|
||||
sprintf (filename, "Error opening %s", name);
|
||||
WaitPrompt(filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case 0: /* SAVING */
|
||||
|
||||
if (filetype) /* SRAM */
|
||||
{
|
||||
inbytes = 0x10000;
|
||||
outbytes = 0x12000;
|
||||
compress2 ((char *) &savebuffer[sizeof(outbytes)], &outbytes, (char *) &sram.sram, inbytes, 9);
|
||||
memcpy(&savebuffer[0], &outbytes, sizeof(outbytes));
|
||||
filesize = outbytes + sizeof(outbytes);
|
||||
}
|
||||
else filesize = state_save(&savebuffer[0]); /* STATE */
|
||||
|
||||
len = SDCARD_WriteFile (handle, savebuffer, filesize);
|
||||
SDCARD_CloseFile (handle);
|
||||
|
||||
if (len != filesize)
|
||||
{
|
||||
sprintf (filename, "Error writing %s", name);
|
||||
WaitPrompt (filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sprintf (filename, "Saved %d bytes successfully", filesize);
|
||||
WaitPrompt (filename);
|
||||
return 1;
|
||||
|
||||
case 1: /* LOADING */
|
||||
|
||||
while ((len = SDCARD_ReadFile (handle, &savebuffer[offset], 2048)) > 0) offset += len;
|
||||
if (filetype) /* SRAM */
|
||||
{
|
||||
memcpy(&inbytes,&savebuffer[0],sizeof(inbytes));
|
||||
outbytes = 0x10000;
|
||||
uncompress ((char *) &sram.sram, &outbytes, (char *) &savebuffer[sizeof(inbytes)], inbytes);
|
||||
sram.crc = crc32 (0, &sram.sram[0], outbytes);
|
||||
system_reset ();
|
||||
}
|
||||
else state_load(&savebuffer[0]); /* STATE */
|
||||
SDCARD_CloseFile (handle);
|
||||
|
||||
sprintf (filename, "Loaded %d bytes successfully", offset);
|
||||
WaitPrompt (filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* MountTheCard
|
||||
*
|
||||
* libOGC provides the CARD_Mount function, and it should be all you need.
|
||||
* However, experience with previous emulators has taught me that you are
|
||||
* better off doing a little bit more than that!
|
||||
*
|
||||
* Function returns TRUE on success.
|
||||
*****************************************************************************/
|
||||
int MountTheCard ()
|
||||
{
|
||||
int tries = 0;
|
||||
int CardError;
|
||||
while (tries < 10)
|
||||
{
|
||||
*(unsigned long *) (0xcc006800) |= 1 << 13; /*** Disable Encryption ***/
|
||||
uselessinquiry ();
|
||||
VIDEO_WaitVSync ();
|
||||
CardError = CARD_Mount (CARDSLOT, SysArea, NULL); /*** Don't need or want a callback ***/
|
||||
if (CardError == 0) return 1;
|
||||
else EXI_ProbeReset ();
|
||||
tries++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* CardFileExists
|
||||
*
|
||||
* Wrapper to search through the files on the card.
|
||||
* Returns TRUE if found.
|
||||
****************************************************************************/
|
||||
int CardFileExists (char *filename)
|
||||
{
|
||||
int CardError = CARD_FindFirst (CARDSLOT, &CardDir, TRUE);
|
||||
while (CardError != CARD_ERROR_NOFILE)
|
||||
{
|
||||
CardError = CARD_FindNext (&CardDir);
|
||||
if (strcmp ((char *) CardDir.filename, filename) == 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* ManageSRAM
|
||||
*
|
||||
* Here is the main SRAM Management stuff.
|
||||
* The output file contains an icon (2K), 64 bytes comment and the SRAM (64k).
|
||||
* As memcards are allocated in blocks of 8k or more, you have a around
|
||||
* 6k bytes to save/load any other data you wish without altering any of the
|
||||
* main save / load code.
|
||||
*
|
||||
* direction == 0 save, 1 load.
|
||||
****************************************************************************/
|
||||
int ManageSRAM (int direction)
|
||||
{
|
||||
char filename[128];
|
||||
char action[80];
|
||||
int CardError;
|
||||
unsigned int SectorSize;
|
||||
int blocks;
|
||||
char comment[2][32] = { {"Genesis Plus 1.2a"}, {"SRAM Save"} };
|
||||
int outbytes = 0;
|
||||
int sbo;
|
||||
int i;
|
||||
unsigned long inzipped,outzipped;
|
||||
|
||||
if (!genromsize) return 0;
|
||||
|
||||
if (direction) ShowAction ("Loading SRAM ...");
|
||||
else ShowAction ("Saving SRAM ...");
|
||||
|
||||
/* First, build a filename based on the information retrieved for this ROM */
|
||||
if (strlen (rominfo.domestic)) strcpy (filename, rominfo.domestic);
|
||||
else strcpy (filename, rominfo.international);
|
||||
|
||||
/* As these names tend to be bulked with spaces, let's strip them */
|
||||
/* Name should be in 16 character blocks, so take first 16 */
|
||||
filename[16] = 0;
|
||||
for (i = strlen (filename) - 1; i > 0; i--)
|
||||
if (filename[i] != 32) break;
|
||||
filename[i + 1] = 0;
|
||||
|
||||
/* Now add the 16bit checksum, to ensure it's the same ROM */
|
||||
sprintf (filename, "%s%02X.srm", filename, rominfo.checksum);
|
||||
strcpy (comment[1], filename);
|
||||
|
||||
/* device is SDCARD, let's go */
|
||||
if (use_SDCARD) return SD_ManageFile(filename,direction,1);
|
||||
|
||||
/* device is MCARD, we continue */
|
||||
if (direction == 0) /*** Saving ***/
|
||||
{
|
||||
/*** Build the output buffer ***/
|
||||
memcpy (&savebuffer, &icon, 2048);
|
||||
memcpy (&savebuffer[2048], &comment[0], 64);
|
||||
|
||||
inzipped = 0x10000;
|
||||
outzipped = 0x12000;
|
||||
compress2 ((char *) &savebuffer[2112+sizeof(outzipped)], &outzipped, (char *) &sram.sram, inzipped, 9);
|
||||
memcpy(&savebuffer[2112], &outzipped, sizeof(outzipped));
|
||||
}
|
||||
|
||||
outbytes = 2048 + 64 + outzipped + sizeof(outzipped);
|
||||
|
||||
/*** Initialise the CARD system ***/
|
||||
memset (&SysArea, 0, CARD_WORKAREA);
|
||||
CARD_Init ("GENP", "00");
|
||||
|
||||
/*** Attempt to mount the card ***/
|
||||
CardError = MountTheCard ();
|
||||
|
||||
if (CardError)
|
||||
{
|
||||
/*** Retrieve the sector size ***/
|
||||
CardError = CARD_GetSectorSize (CARDSLOT, &SectorSize);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case 0: /*** Saving ***/
|
||||
/*** Determine number of blocks on this card ***/
|
||||
blocks = (outbytes / SectorSize) * SectorSize;
|
||||
if (outbytes % SectorSize) blocks += SectorSize;
|
||||
|
||||
/*** Check if a previous save exists ***/
|
||||
if (CardFileExists (filename))
|
||||
{
|
||||
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error Open : %d", CardError);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int size = CardFile.len;
|
||||
CARD_Close (&CardFile);
|
||||
|
||||
if (size < blocks)
|
||||
{
|
||||
/* new size is bigger: check if there is enough space left */
|
||||
CardError = CARD_Create (CARDSLOT, "TEMP", blocks-size, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error Update : %d", CardError);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
CARD_Close (&CardFile);
|
||||
CARD_Delete(CARDSLOT, "TEMP");
|
||||
}
|
||||
|
||||
/* always delete existing slot */
|
||||
CARD_Delete(CARDSLOT, filename);
|
||||
}
|
||||
|
||||
/*** Create a new slot ***/
|
||||
CardError = CARD_Create (CARDSLOT, filename, blocks, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error create : %d %d", CardError, CARDSLOT);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** Continue and save ***/
|
||||
CARD_GetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
|
||||
CardStatus.icon_addr = 0x0;
|
||||
CardStatus.icon_fmt = 2;
|
||||
CardStatus.icon_speed = 1;
|
||||
CardStatus.comment_addr = 2048;
|
||||
CARD_SetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
|
||||
|
||||
/*** And write the blocks out ***/
|
||||
sbo = 0;
|
||||
while (outbytes > 0)
|
||||
{
|
||||
CardError = CARD_Write (&CardFile, &savebuffer[sbo], SectorSize, sbo);
|
||||
outbytes -= SectorSize;
|
||||
sbo += SectorSize;
|
||||
}
|
||||
|
||||
CARD_Close (&CardFile);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
sram.crc = crc32 (0, &sram.sram[0], 0x10000);
|
||||
sprintf (action, "Saved %d bytes successfully", blocks);
|
||||
WaitPrompt (action);
|
||||
return 1;
|
||||
|
||||
default: /*** Loading ***/
|
||||
if (!CardFileExists (filename))
|
||||
{
|
||||
WaitPrompt ("No SRAM File Found");
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset (&CardFile, 0, sizeof (CardFile));
|
||||
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error Open : %d", CardError);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
blocks = CardFile.len;
|
||||
if (blocks < SectorSize) blocks = SectorSize;
|
||||
if (blocks % SectorSize) blocks++;
|
||||
|
||||
/*** Just read the file back in ***/
|
||||
sbo = 0;
|
||||
int size = blocks;
|
||||
while (blocks > 0)
|
||||
{
|
||||
CARD_Read (&CardFile, &savebuffer[sbo], SectorSize, sbo);
|
||||
sbo += SectorSize;
|
||||
blocks -= SectorSize;
|
||||
}
|
||||
CARD_Close (&CardFile);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
|
||||
/* Copy to SRAM */
|
||||
memcpy(&inzipped,&savebuffer[2112],sizeof(inzipped));
|
||||
outzipped = 0x10000;
|
||||
uncompress ((char *) &sram.sram, &outzipped, (char *) &savebuffer[2112+sizeof(inzipped)], inzipped);
|
||||
sram.crc = crc32 (0, &sram.sram[0], 0x10000);
|
||||
system_reset ();
|
||||
|
||||
/*** Inform user ***/
|
||||
sprintf (action, "Loaded %d bytes successfully", size);
|
||||
WaitPrompt (action);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else WaitPrompt ("Unable to mount memory card");
|
||||
return 0; /*** Signal failure ***/
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* ManageSTATE
|
||||
*
|
||||
* Here is the main Freeze File Management stuff.
|
||||
* The output file contains an icon (2K), 64 bytes comment and the STATE (~128k)
|
||||
*
|
||||
* direction == 0 save, 1 load.
|
||||
****************************************************************************/
|
||||
int ManageState (int direction)
|
||||
{
|
||||
char filename[128];
|
||||
char action[80];
|
||||
int CardError;
|
||||
unsigned int SectorSize;
|
||||
int blocks;
|
||||
char comment[2][32] = { {"Genesis Plus 1.2a [FRZ]"}, {"Freeze State"} };
|
||||
int outbytes;
|
||||
int sbo;
|
||||
int i;
|
||||
int state_size = 0;
|
||||
|
||||
if (!genromsize) return 0;
|
||||
|
||||
if (direction) ShowAction ("Loading State ...");
|
||||
else ShowAction ("Saving State ...");
|
||||
|
||||
/* First, build a filename based on the information retrieved for this ROM */
|
||||
if (strlen (rominfo.domestic)) strcpy (filename, rominfo.domestic);
|
||||
else strcpy (filename, rominfo.international);
|
||||
|
||||
/* As these names tend to be bulked with spaces, let's strip them */
|
||||
/* Name should be in 16 character blocks, so take first 16 */
|
||||
filename[16] = 0;
|
||||
for (i = strlen (filename) - 1; i > 0; i--) if (filename[i] != 32) break;
|
||||
filename[i + 1] = 0;
|
||||
|
||||
/* Now add the 16bit checksum, to ensure it's the same ROM */
|
||||
sprintf (filename, "%s%02X.gpz", filename, rominfo.checksum);
|
||||
strcpy (comment[1], filename);
|
||||
|
||||
/* device is SDCARD, let's go */
|
||||
if (use_SDCARD) return SD_ManageFile(filename,direction,0);
|
||||
|
||||
/* device is MCARD, we continue */
|
||||
if (direction == 0) /* Saving */
|
||||
{
|
||||
/* Build the output buffer */
|
||||
memcpy (&savebuffer, &icon, 2048);
|
||||
memcpy (&savebuffer[2048], &comment[0], 64);
|
||||
state_size = state_save(&savebuffer[2112]);
|
||||
}
|
||||
|
||||
outbytes = 2048 + 64 + state_size;
|
||||
|
||||
/*** Initialise the CARD system ***/
|
||||
memset (&SysArea, 0, CARD_WORKAREA);
|
||||
CARD_Init ("GENP", "00");
|
||||
|
||||
/*** Attempt to mount the card ***/
|
||||
CardError = MountTheCard ();
|
||||
|
||||
if (CardError)
|
||||
{
|
||||
/*** Retrieve the sector size ***/
|
||||
CardError = CARD_GetSectorSize (CARDSLOT, &SectorSize);
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case 0: /*** Saving ***/
|
||||
/*** Determine number of blocks on this card ***/
|
||||
blocks = (outbytes / SectorSize) * SectorSize;
|
||||
if (outbytes % SectorSize) blocks += SectorSize;
|
||||
|
||||
/*** Check if a previous save exists ***/
|
||||
if (CardFileExists (filename))
|
||||
{
|
||||
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error Open : %d", CardError);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int size = CardFile.len;
|
||||
CARD_Close (&CardFile);
|
||||
|
||||
if (size < blocks)
|
||||
{
|
||||
/* new size is bigger: check if there is enough space left */
|
||||
CardError = CARD_Create (CARDSLOT, "TEMP", blocks-size, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error Update : %d", CardError);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
CARD_Close (&CardFile);
|
||||
CARD_Delete(CARDSLOT, "TEMP");
|
||||
}
|
||||
|
||||
/* always delete existing slot */
|
||||
CARD_Delete(CARDSLOT, filename);
|
||||
}
|
||||
|
||||
/*** Create a new slot ***/
|
||||
CardError = CARD_Create (CARDSLOT, filename, blocks, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error create : %d %d", CardError, CARDSLOT);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*** Continue and save ***/
|
||||
CARD_GetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
|
||||
CardStatus.icon_addr = 0x0;
|
||||
CardStatus.icon_fmt = 2;
|
||||
CardStatus.icon_speed = 1;
|
||||
CardStatus.comment_addr = 2048;
|
||||
CARD_SetStatus (CARDSLOT, CardFile.filenum, &CardStatus);
|
||||
|
||||
/*** And write the blocks out ***/
|
||||
sbo = 0;
|
||||
while (outbytes > 0)
|
||||
{
|
||||
CardError = CARD_Write (&CardFile, &savebuffer[sbo], SectorSize, sbo);
|
||||
outbytes -= SectorSize;
|
||||
sbo += SectorSize;
|
||||
}
|
||||
|
||||
CARD_Close (&CardFile);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
sprintf (action, "Saved %d bytes successfully", blocks);
|
||||
WaitPrompt (action);
|
||||
return 1;
|
||||
|
||||
default: /*** Loading ***/
|
||||
if (!CardFileExists (filename))
|
||||
{
|
||||
WaitPrompt ("No Savestate Found");
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset (&CardFile, 0, sizeof (CardFile));
|
||||
CardError = CARD_Open (CARDSLOT, filename, &CardFile);
|
||||
if (CardError)
|
||||
{
|
||||
sprintf (action, "Error Open : %d", CardError);
|
||||
WaitPrompt (action);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
blocks = CardFile.len;
|
||||
if (blocks < SectorSize) blocks = SectorSize;
|
||||
if (blocks % SectorSize) blocks++;
|
||||
|
||||
/*** Just read the file back in ***/
|
||||
sbo = 0;
|
||||
int size = blocks;
|
||||
while (blocks > 0)
|
||||
{
|
||||
CARD_Read (&CardFile, &savebuffer[sbo], SectorSize, sbo);
|
||||
sbo += SectorSize;
|
||||
blocks -= SectorSize;
|
||||
}
|
||||
CARD_Close (&CardFile);
|
||||
CARD_Unmount (CARDSLOT);
|
||||
|
||||
state_load(&savebuffer[2112]);
|
||||
|
||||
/*** Inform user ***/
|
||||
sprintf (action, "Loaded %d bytes successfully", size);
|
||||
WaitPrompt (action);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else WaitPrompt ("Unable to mount memory card");
|
||||
return 0; /*** Signal failure ***/
|
||||
}
|
623
source/ngc/gui/menu.c
Normal file
623
source/ngc/gui/menu.c
Normal file
@ -0,0 +1,623 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Nintendo Gamecube Menus
|
||||
*
|
||||
* Please put any user menus here! - softdev March 12 2006
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
#include "dvd.h"
|
||||
#include "rominfo.h"
|
||||
#include "font.h"
|
||||
|
||||
#define PSOSDLOADID 0x7c6000a6
|
||||
|
||||
/***************************************************************************
|
||||
* drawmenu
|
||||
*
|
||||
* As it says, simply draws the menu with a highlight on the currently
|
||||
* selected item :)
|
||||
***************************************************************************/
|
||||
char menutitle[60] = { "" };
|
||||
int menu = 0;
|
||||
|
||||
void drawmenu (char items[][20], int maxitems, int selected)
|
||||
{
|
||||
int i;
|
||||
int ypos;
|
||||
|
||||
ypos = (310 - (fheight * maxitems)) >> 1;
|
||||
ypos += 130;
|
||||
|
||||
ClearScreen ();
|
||||
WriteCentre (134, menutitle);
|
||||
|
||||
for (i = 0; i < maxitems; i++)
|
||||
{
|
||||
if (i == selected) WriteCentre_HL (i * fheight + ypos, (char *) items[i]);
|
||||
else WriteCentre (i * fheight + ypos, (char *) items[i]);
|
||||
}
|
||||
|
||||
SetScreen ();
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* domenu
|
||||
*
|
||||
* Returns index into menu array when A is pressed, -1 for B
|
||||
****************************************************************************/
|
||||
int domenu (char items[][20], int maxitems)
|
||||
{
|
||||
int redraw = 1;
|
||||
int quit = 0;
|
||||
short p;
|
||||
int ret = 0;
|
||||
signed char a,b;
|
||||
|
||||
while (quit == 0)
|
||||
{
|
||||
if (redraw)
|
||||
{
|
||||
drawmenu (&items[0], maxitems, menu);
|
||||
redraw = 0;
|
||||
}
|
||||
|
||||
p = PAD_ButtonsDown (0);
|
||||
a = PAD_StickY (0);
|
||||
b = PAD_StickX (0);
|
||||
|
||||
/*** Look for up ***/
|
||||
if ((p & PAD_BUTTON_UP) || (a > 70))
|
||||
{
|
||||
redraw = 1;
|
||||
menu--;
|
||||
if (menu < 0) menu = maxitems - 1;
|
||||
}
|
||||
|
||||
/*** Look for down ***/
|
||||
if ((p & PAD_BUTTON_DOWN) || (a < -70))
|
||||
{
|
||||
redraw = 1;
|
||||
menu++;
|
||||
if (menu == maxitems) menu = 0;
|
||||
}
|
||||
|
||||
if ((p & PAD_BUTTON_A) || (b > 40) || (p & PAD_BUTTON_RIGHT))
|
||||
{
|
||||
quit = 1;
|
||||
ret = menu;
|
||||
}
|
||||
|
||||
if ((b < -40) || (p & PAD_BUTTON_LEFT))
|
||||
{
|
||||
quit = 1;
|
||||
ret = 0 - 2 - menu;
|
||||
}
|
||||
|
||||
if (p & PAD_BUTTON_B)
|
||||
{
|
||||
quit = 1;
|
||||
ret = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Sound Option menu
|
||||
*
|
||||
****************************************************************************/
|
||||
double psg_preamp = 3.0;
|
||||
double fm_preamp = 1.0;
|
||||
u8 boost = 1;
|
||||
uint8 clipping = 2;
|
||||
uint8 hq_fm = 1;
|
||||
uint8 FM_GENS = 0;
|
||||
uint8 PSG_MAME = 0;
|
||||
|
||||
void soundmenu ()
|
||||
{
|
||||
int ret;
|
||||
int quit = 0;
|
||||
int prevmenu = menu;
|
||||
int count = 7;
|
||||
char items[7][20];
|
||||
|
||||
strcpy (menutitle, "Sound Options");
|
||||
|
||||
sprintf (items[0], "PSG Volume : %1.2f", psg_preamp);
|
||||
sprintf (items[1], "FM Volume : %1.2f", fm_preamp);
|
||||
sprintf (items[2], "Volume Boost: %dX", boost);
|
||||
sprintf (items[3], "HQ YM2612: %s", hq_fm ? "Y" : "N");
|
||||
sprintf (items[4], "FM core : %s", FM_GENS ? "GENS" : "MAME");
|
||||
sprintf (items[5], "PSG core: %s", PSG_MAME ? "MAME" : "SMSP");
|
||||
|
||||
strcpy (items[6], "Return to previous");
|
||||
|
||||
menu = 0;
|
||||
while (quit == 0)
|
||||
{
|
||||
ret = domenu (&items[0], count);
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
case -2:
|
||||
if (ret<0) psg_preamp -= 0.01;
|
||||
else psg_preamp += 0.01;
|
||||
if (psg_preamp < 0.0) psg_preamp = 5.0;
|
||||
if (psg_preamp > 5.0) psg_preamp = 0.0;
|
||||
sprintf (items[0], "PSG Volume : %1.2f", psg_preamp);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
case -3:
|
||||
if (ret<0) fm_preamp -= 0.01;
|
||||
else fm_preamp += 0.01;
|
||||
if (fm_preamp < 0.0) fm_preamp = 5.0;
|
||||
if (fm_preamp > 5.0) fm_preamp = 0.0;
|
||||
sprintf (items[1], "FM Volume : %1.2f", fm_preamp);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
boost ++;
|
||||
if (boost > 4) boost = 0;
|
||||
sprintf (items[2], "Volume Boost: %dX", boost);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
hq_fm ^= 1;
|
||||
sprintf (items[3], "HQ YM2612: %s", hq_fm ? "Y" : "N");
|
||||
if (genromsize)
|
||||
{ audio_init(48000);
|
||||
fm_restore();
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
FM_GENS ^= 1;
|
||||
psg_preamp = PSG_MAME ? (FM_GENS ? 0.85 : 0.50) : (FM_GENS ? 4.0 : 3.0);
|
||||
fm_preamp = 1.0;
|
||||
sprintf (items[0], "PSG Volume : %1.2f", psg_preamp);
|
||||
sprintf (items[1], "FM Volume : %1.2f", fm_preamp);
|
||||
sprintf (items[4], "FM core : %s", FM_GENS ? "GENS" : "MAME");
|
||||
if (genromsize)
|
||||
{
|
||||
audio_init(48000);
|
||||
fm_restore();
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
PSG_MAME ^= 1;
|
||||
psg_preamp = PSG_MAME ? (FM_GENS ? 0.85 : 0.50) : (FM_GENS ? 4.0 : 3.0);
|
||||
fm_preamp = 1.0;
|
||||
sprintf (items[0], "PSG Volume : %1.2f", psg_preamp);
|
||||
sprintf (items[1], "FM Volume : %1.2f", fm_preamp);
|
||||
sprintf (items[5], "PSG core: %s", PSG_MAME ? "MAME" : "SMSP");
|
||||
if (genromsize) audio_init(48000);
|
||||
break;
|
||||
|
||||
case 6:
|
||||
case -1:
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
menu = prevmenu;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Misc Option menu
|
||||
*
|
||||
****************************************************************************/
|
||||
extern void reloadrom ();
|
||||
extern s16 square[];
|
||||
extern int oldvwidth, oldvheight;
|
||||
extern uint8 alttiming;
|
||||
extern uint8 dmatiming;
|
||||
extern uint8 vdptiming;
|
||||
|
||||
uint8 autoload = 0;
|
||||
uint8 region_detect = 0;
|
||||
uint8 cpu_detect = 0;
|
||||
|
||||
void miscmenu ()
|
||||
{
|
||||
int ret;
|
||||
int quit = 0;
|
||||
int prevmenu = menu;
|
||||
int count = 9;
|
||||
char items[9][20];
|
||||
|
||||
sprintf (items[0], "Scale X: %02d", square[3]);
|
||||
sprintf (items[1], "Scale Y: %02d", square[1]);
|
||||
sprintf (items[2], "Vdp Latency: %s", vdptiming ? "Y" : "N");
|
||||
sprintf (items[3], "Dma Timing : %s", dmatiming ? "Y" : "N");
|
||||
sprintf (items[4], "Alt Timing : %s", alttiming ? "Y" : "N");
|
||||
if (cpu_detect == 0) sprintf (items[5], "Cpu Mode: AUTO");
|
||||
else if (cpu_detect == 1) sprintf (items[5], "Cpu Mode: NTSC");
|
||||
else if (cpu_detect == 2) sprintf (items[5], "Cpu Mode: PAL");
|
||||
if (region_detect == 0) sprintf (items[6], "Region: AUTO");
|
||||
else if (region_detect == 1) sprintf (items[6], "Region: USA");
|
||||
else if (region_detect == 2) sprintf (items[6], "Region: EUR");
|
||||
else if (region_detect == 3) sprintf (items[6], "Region: JAP-NTSC");
|
||||
else if (region_detect == 4) sprintf (items[6], "Region: JAP-PAL");
|
||||
sprintf (items[7], "SRAM autoload: %s", autoload ? "Y" : "N");
|
||||
strcpy (items[8], "Return to previous");
|
||||
|
||||
menu = 0;
|
||||
while (quit == 0)
|
||||
{
|
||||
strcpy (menutitle, "");
|
||||
ret = domenu (&items[0], count);
|
||||
switch (ret)
|
||||
{
|
||||
case 0: /*** Scale X ***/
|
||||
case -2:
|
||||
if (ret<0) square[3] -= 2;
|
||||
else square[3] += 2;
|
||||
if (square[3] < 40) square[3] = 80;
|
||||
if (square[3] > 80) square[3] = 40;
|
||||
square[6] = square[3];
|
||||
square[0] = square[9] = -square[3];
|
||||
oldvwidth = -1;
|
||||
sprintf (items[0], "Scale X: %02d", square[3]);
|
||||
break;
|
||||
|
||||
case 1: /*** Scale Y ***/
|
||||
case -3:
|
||||
if (ret<0) square[1] -= 2;
|
||||
else square[1] += 2;
|
||||
if (square[1] < 30) square[1] = 60;
|
||||
if (square[1] > 60) square[1] = 30;
|
||||
square[4] = square[1];
|
||||
square[7] = square[10] = -square[1];
|
||||
oldvheight = -1;
|
||||
sprintf (items[1], "Scale Y: %02d", square[1]);
|
||||
break;
|
||||
|
||||
case 2: /*** VDP access latency ***/
|
||||
vdptiming ^= 1;
|
||||
sprintf (items[2], "Vdp Latency: %s", vdptiming ? "Y" : "N");
|
||||
break;
|
||||
|
||||
case 3: /*** DMA timing fix ***/
|
||||
dmatiming ^= 1;
|
||||
sprintf (items[3], "Dma Timing : %s", dmatiming ? "Y" : "N");
|
||||
break;
|
||||
|
||||
case 4: /*** Alternate rendering timing ***/
|
||||
alttiming ^= 1;
|
||||
sprintf (items[4], "Alt Timing : %s", alttiming ? "Y" : "N");
|
||||
break;
|
||||
|
||||
case 5: /*** Cpu mode : PAL (50hz) or NTSC (60Hz) ***/
|
||||
cpu_detect ++;
|
||||
if (cpu_detect > 2) cpu_detect = 0;
|
||||
if (cpu_detect == 0) sprintf (items[5], "Cpu Mode: AUTO");
|
||||
else if (cpu_detect == 1) sprintf (items[5], "Cpu Mode: NTSC");
|
||||
else if (cpu_detect == 2) sprintf (items[5], "Cpu Mode: PAL");
|
||||
if (genromsize) reloadrom();
|
||||
break;
|
||||
|
||||
case 6: /* region detection */
|
||||
region_detect ++;
|
||||
if (region_detect > 4) region_detect = 0;
|
||||
if (region_detect == 0) sprintf (items[6], "Region: AUTO");
|
||||
else if (region_detect == 1) sprintf (items[6], "Region: USA");
|
||||
else if (region_detect == 2) sprintf (items[6], "Region: EUR");
|
||||
else if (region_detect == 3) sprintf (items[6], "Region: JAP-NTSC");
|
||||
else if (region_detect == 4) sprintf (items[6], "Region: JAP-PAL");
|
||||
if (genromsize) reloadrom();
|
||||
break;
|
||||
|
||||
case 7: /*** VDP access latency ***/
|
||||
autoload ^= 1;
|
||||
sprintf (items[7], "SRAM autoload: %s", autoload ? "Y" : "N");
|
||||
break;
|
||||
|
||||
case 8:
|
||||
case -1:
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
menu = prevmenu;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Main Option menu
|
||||
*
|
||||
****************************************************************************/
|
||||
extern void ConfigureJoypads();
|
||||
extern void GetGGEntries();
|
||||
|
||||
void optionmenu ()
|
||||
{
|
||||
int ret;
|
||||
int quit = 0;
|
||||
int prevmenu = menu;
|
||||
int count = 5;
|
||||
char items[5][20] = {
|
||||
"Misc. Options",
|
||||
"Sound Options",
|
||||
"Configure Joypads",
|
||||
"Game Genie Codes",
|
||||
"Return to previous"
|
||||
};
|
||||
|
||||
menu = 0;
|
||||
while (quit == 0)
|
||||
{
|
||||
strcpy (menutitle, "");
|
||||
ret = domenu (&items[0], count);
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
miscmenu();
|
||||
break;
|
||||
case 1:
|
||||
soundmenu();
|
||||
break;
|
||||
case 2:
|
||||
ConfigureJoypads();
|
||||
break;
|
||||
case 3:
|
||||
GetGGEntries();
|
||||
break;
|
||||
case 4:
|
||||
case -1:
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
menu = prevmenu;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Generic Load/Save menu
|
||||
*
|
||||
****************************************************************************/
|
||||
int CARDSLOT = CARD_SLOTB;
|
||||
int use_SDCARD = 0;
|
||||
extern int ManageSRAM (int direction);
|
||||
extern int ManageState (int direction);
|
||||
|
||||
int loadsavemenu (int which)
|
||||
{
|
||||
int prevmenu = menu;
|
||||
int quit = 0;
|
||||
int ret;
|
||||
int count = 5;
|
||||
char items[5][20];
|
||||
|
||||
strcpy (menutitle, "");
|
||||
|
||||
if (use_SDCARD) sprintf(items[0], "Device: SDCARD");
|
||||
else sprintf(items[0], "Device: MCARD");
|
||||
|
||||
if (CARDSLOT == CARD_SLOTA) sprintf(items[1], "Use: SLOT A");
|
||||
else sprintf(items[1], "Use: SLOT B");
|
||||
|
||||
if (which)
|
||||
{
|
||||
sprintf(items[2], "Save State");
|
||||
sprintf(items[3], "Load State");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(items[2], "Save SRAM");
|
||||
sprintf(items[3], "Load SRAM");
|
||||
}
|
||||
sprintf(items[4], "Return to previous");
|
||||
|
||||
menu = 2;
|
||||
|
||||
while (quit == 0)
|
||||
{
|
||||
ret = domenu (&items[0], count);
|
||||
switch (ret)
|
||||
{
|
||||
case -1:
|
||||
case 4:
|
||||
quit = 1;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
use_SDCARD ^= 1;
|
||||
if (use_SDCARD) sprintf(items[0], "Device: SDCARD");
|
||||
else sprintf(items[0], "Device: MCARD");
|
||||
break;
|
||||
case 1:
|
||||
CARDSLOT ^= 1;
|
||||
if (CARDSLOT == CARD_SLOTA) sprintf(items[1], "Use: SLOT A");
|
||||
else sprintf(items[1], "Use: SLOT B");
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
if (which) quit = ManageState(ret-2);
|
||||
else quit = ManageSRAM(ret-2);
|
||||
if (quit) return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
menu = prevmenu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* File Manager menu
|
||||
*
|
||||
****************************************************************************/
|
||||
int filemenu ()
|
||||
{
|
||||
int prevmenu = menu;
|
||||
int ret;
|
||||
int quit = 0;
|
||||
uint32 crccheck;
|
||||
int count = 3;
|
||||
char items[3][20] = {
|
||||
{"SRAM Manager"},
|
||||
{"STATE Manager"},
|
||||
{"Return to previous"}
|
||||
};
|
||||
|
||||
crccheck = crc32 (0, &sram.sram[0], 0x10000);
|
||||
if (genromsize && (crccheck != sram.crc)) strcpy (menutitle, "*** SRAM has been modified ***");
|
||||
else strcpy (menutitle, "");
|
||||
|
||||
menu = 0;
|
||||
|
||||
while (quit == 0)
|
||||
{
|
||||
ret = domenu (&items[0], count);
|
||||
switch (ret)
|
||||
{
|
||||
case -1: /*** Button B ***/
|
||||
case 2: /*** Quit ***/
|
||||
ret = 0;
|
||||
quit = 1;
|
||||
break;
|
||||
case 0: /*** SRAM Manager ***/
|
||||
case 1: /*** SaveState Manager ***/
|
||||
if (loadsavemenu(ret)) return 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
menu = prevmenu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Load Rom menu
|
||||
*
|
||||
****************************************************************************/
|
||||
extern void OpenDVD ();
|
||||
extern int OpenSD ();
|
||||
extern u8 UseSDCARD;
|
||||
|
||||
void loadmenu ()
|
||||
{
|
||||
int prevmenu = menu;
|
||||
int ret;
|
||||
int quit = 0;
|
||||
int count = 3;
|
||||
char item[3][20] = {
|
||||
{"Load from DVD"},
|
||||
{"Load from SDCARD"},
|
||||
{"Return to previous"}
|
||||
};
|
||||
|
||||
menu = UseSDCARD ? 1 : 0;
|
||||
|
||||
while (quit == 0)
|
||||
{
|
||||
strcpy (menutitle, "");
|
||||
ret = domenu (&item[0], count);
|
||||
switch (ret)
|
||||
{
|
||||
case -1: /*** Button B ***/
|
||||
case 2: /*** Quit ***/
|
||||
quit = 1;
|
||||
menu = prevmenu;
|
||||
break;
|
||||
case 0: /*** Load from DVD ***/
|
||||
OpenDVD ();
|
||||
quit = 1;
|
||||
break;
|
||||
case 1: /*** Load from SCDARD ***/
|
||||
OpenSD ();
|
||||
quit = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Main menu
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void MainMenu ()
|
||||
{
|
||||
menu = 0;
|
||||
int ret;
|
||||
int quit = 0;
|
||||
int *psoid = (int *) 0x80001800;
|
||||
void (*PSOReload) () = (void (*)()) 0x80001800; /*** Stock PSO/SD Reload call ***/
|
||||
int count = 8;
|
||||
char items[8][20] = {
|
||||
{"Play Game"},
|
||||
{"Game Infos"},
|
||||
{"Reset Game"},
|
||||
{"Load New Game"},
|
||||
{"File Management"},
|
||||
{"Emulator Options"},
|
||||
{"Stop DVD Motor"},
|
||||
{"System Reboot"}
|
||||
};
|
||||
|
||||
while (quit == 0)
|
||||
{
|
||||
strcpy (menutitle, "");
|
||||
ret = domenu (&items[0], count);
|
||||
switch (ret)
|
||||
{
|
||||
case -1: /*** Button B ***/
|
||||
case 0: /*** Play Game ***/
|
||||
quit = 1;
|
||||
break;
|
||||
case 1: /*** ROM Information ***/
|
||||
showrominfo ();
|
||||
break;
|
||||
case 2: /*** Emulator Reset ***/
|
||||
system_reset ();
|
||||
quit = 1;
|
||||
break;
|
||||
case 3: /*** Load ROM Menu ***/
|
||||
loadmenu();
|
||||
menu = 0;
|
||||
break;
|
||||
case 4: /*** Memory Manager ***/
|
||||
quit = filemenu ();
|
||||
break;
|
||||
case 5: /*** Emulator Options */
|
||||
optionmenu ();
|
||||
break;
|
||||
case 6: /*** Stop DVD Motor ***/
|
||||
ShowAction("Stopping DVD Motor ...");
|
||||
dvd_motor_off();
|
||||
break;
|
||||
case 7: /*** SD/PSO Reload ***/
|
||||
if (psoid[0] == PSOSDLOADID) PSOReload ();
|
||||
else SYS_ResetSystem(SYS_HOTRESET,0,FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*** Remove any still held buttons ***/
|
||||
while(PAD_ButtonsHeld(0)) VIDEO_WaitVSync();
|
||||
|
||||
/*** Stop the DVD from causing clicks while playing ***/
|
||||
uselessinquiry ();
|
||||
}
|
403
source/ngc/gui/rominfo.c
Normal file
403
source/ngc/gui/rominfo.c
Normal file
@ -0,0 +1,403 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Information in this module was gleaned from
|
||||
* http://en.wikibooks.org/wiki/Genesis_Programming
|
||||
***************************************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
#include "font.h"
|
||||
#include "rominfo.h"
|
||||
|
||||
#define MAXCOMPANY 64
|
||||
|
||||
/*** ROM Information ***/
|
||||
#define ROMCONSOLE 256
|
||||
#define ROMCOPYRIGHT 272
|
||||
#define ROMDOMESTIC 288
|
||||
#define ROMWORLD 336
|
||||
#define ROMTYPE0 384
|
||||
#define ROMTYPE1 385
|
||||
#define ROMPRODUCT 386
|
||||
#define ROMCHECKSUM 398
|
||||
#define ROMIOSUPPORT 400
|
||||
#define ROMROMSTART 416
|
||||
#define ROMROMEND 420
|
||||
#define ROMRAMINFO 424
|
||||
#define ROMRAMSTART 436
|
||||
#define ROMRAMEND 440
|
||||
#define ROMMODEMINFO 444
|
||||
#define ROMMEMO 456
|
||||
#define ROMCOUNTRY 496
|
||||
|
||||
#define P3BUTTONS 1
|
||||
#define P6BUTTONS 2
|
||||
#define PKEYBOARD 4
|
||||
#define PPRINTER 8
|
||||
#define PBALL 16
|
||||
#define PFLOPPY 32
|
||||
#define PACTIVATOR 64
|
||||
#define PTEAMPLAYER 128
|
||||
#define PMSYSTEMPAD 256
|
||||
#define PSERIAL 512
|
||||
#define PTABLET 1024
|
||||
#define PPADDLE 2048
|
||||
#define PCDROM 4096
|
||||
#define PMOUSE 8192
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char companyid[6];
|
||||
char company[30];
|
||||
} COMPANYINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char pID[2];
|
||||
char pName[21];
|
||||
} PERIPHERALINFO;
|
||||
|
||||
int peripherals;
|
||||
int checksumok;
|
||||
ROMINFO rominfo;
|
||||
uint16 GetRealChecksum ();
|
||||
|
||||
/***************************************************************************
|
||||
* Genesis ROM Manufacturers
|
||||
*
|
||||
* Based on the document provided at
|
||||
* http://www.zophar.net/tech/files/Genesis_ROM_Format.txt
|
||||
***************************************************************************/
|
||||
COMPANYINFO companyinfo[MAXCOMPANY] = {
|
||||
{"ACLD", "Ballistic"},
|
||||
{"RSI", "Razorsoft"},
|
||||
{"SEGA", "SEGA"},
|
||||
{"TREC", "Treco"},
|
||||
{"VRGN", "Virgin Games"},
|
||||
{"WSTN", "Westone"},
|
||||
{"10", "Takara"},
|
||||
{"11", "Taito or Accolade"},
|
||||
{"12", "Capcom"},
|
||||
{"13", "Data East"},
|
||||
{"14", "Namco or Tengen"},
|
||||
{"15", "Sunsoft"},
|
||||
{"16", "Bandai"},
|
||||
{"17", "Dempa"},
|
||||
{"18", "Technosoft"},
|
||||
{"19", "Technosoft"},
|
||||
{"20", "Asmik"},
|
||||
{"22", "Micronet"},
|
||||
{"23", "Vic Tokai"},
|
||||
{"24", "American Sammy"},
|
||||
{"29", "Kyugo"},
|
||||
{"32", "Wolfteam"},
|
||||
{"33", "Kaneko"},
|
||||
{"35", "Toaplan"},
|
||||
{"36", "Tecmo"},
|
||||
{"40", "Toaplan"},
|
||||
{"42", "UFL Company Limited"},
|
||||
{"43", "Human"},
|
||||
{"45", "Game Arts"},
|
||||
{"47", "Sage's Creation"},
|
||||
{"48", "Tengen"},
|
||||
{"49", "Renovation or Telenet"},
|
||||
{"50", "Electronic Arts"},
|
||||
{"56", "Razorsoft"},
|
||||
{"58", "Mentrix"},
|
||||
{"60", "Victor Musical Industries"},
|
||||
{"69", "Arena"},
|
||||
{"70", "Virgin"},
|
||||
{"73", "Soft Vision"},
|
||||
{"74", "Palsoft"},
|
||||
{"76", "Koei"},
|
||||
{"79", "U.S. Gold"},
|
||||
{"81", "Acclaim/Flying Edge"},
|
||||
{"83", "Gametek"},
|
||||
{"86", "Absolute"},
|
||||
{"87", "Mindscape"},
|
||||
{"93", "Sony"},
|
||||
{"95", "Konami"},
|
||||
{"97", "Tradewest"},
|
||||
{"100", "T*HQ Software"},
|
||||
{"101", "Tecmagik"},
|
||||
{"112", "Designer Software"},
|
||||
{"113", "Psygnosis"},
|
||||
{"119", "Accolade"},
|
||||
{"120", "Code Masters"},
|
||||
{"125", "Interplay"},
|
||||
{"130", "Activision"},
|
||||
{"132", "Shiny & Playmates"},
|
||||
{"144", "Atlus"},
|
||||
{"151", "Infogrames"},
|
||||
{"161", "Fox Interactive"},
|
||||
{"177", "Ubisoft"},
|
||||
{"239", "Disney Interactive"},
|
||||
{"---", "Unknown"}
|
||||
};
|
||||
|
||||
/***************************************************************************
|
||||
* Genesis Peripheral Information
|
||||
*
|
||||
* Based on the document provided at
|
||||
* http://www.zophar.net/tech/files/Genesis_ROM_Format.txt
|
||||
***************************************************************************/
|
||||
PERIPHERALINFO peripheralinfo[14] = {
|
||||
{"J", "3-Button Joypad"},
|
||||
{"6", "6-button Joypad"},
|
||||
{"K", "Keyboard"},
|
||||
{"P", "Printer"},
|
||||
{"B", "Control Ball"},
|
||||
{"F", "Floppy Drive"},
|
||||
{"L", "Activator"},
|
||||
{"4", "Team Player"},
|
||||
{"0", "MS Joypad"},
|
||||
{"R", "RS232C Serial"},
|
||||
{"T", "Tablet"},
|
||||
{"V", "Paddle"},
|
||||
{"C", "CD-ROM"},
|
||||
{"M", "Mega Mouse"}
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
* getcompany
|
||||
*
|
||||
* Try to determine which company made this rom
|
||||
*
|
||||
* Ok, for some reason there's no standard for this.
|
||||
* It seems that there can be pretty much anything you like following the
|
||||
* copyright (C) symbol!
|
||||
****************************************************************************/
|
||||
int getcompany ()
|
||||
{
|
||||
char *s;
|
||||
int i;
|
||||
char company[10];
|
||||
|
||||
for (i = 3; i < 8; i++) company[i - 3] = rominfo.copyright[i];
|
||||
company[5] = 0;
|
||||
|
||||
/** OK, first look for a hyphen
|
||||
* Capcom use T-12 for example
|
||||
*/
|
||||
s = strstr (company, "-");
|
||||
if (s != NULL)
|
||||
{
|
||||
s++;
|
||||
strcpy (company, s);
|
||||
}
|
||||
|
||||
/** Strip any trailing spaces **/
|
||||
for (i = strlen (company) - 1; i >= 0; i--)
|
||||
if (company[i] == 32) company[i] = 0;
|
||||
|
||||
if (strlen (company) == 0) return MAXCOMPANY - 1;
|
||||
|
||||
for (i = 0; i < MAXCOMPANY - 1; i++)
|
||||
{
|
||||
if (!(strncmp (company, companyinfo[i].companyid, strlen (company)))) return i;
|
||||
}
|
||||
|
||||
return MAXCOMPANY - 1;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* getrominfo
|
||||
*
|
||||
* Pass a pointer to the ROM base address.
|
||||
***************************************************************************/
|
||||
void getrominfo (char *romheader)
|
||||
{
|
||||
int i;
|
||||
|
||||
memset (&rominfo, 0, sizeof (ROMINFO));
|
||||
|
||||
memcpy (&rominfo.consoletype, romheader + ROMCONSOLE, 16);
|
||||
memcpy (&rominfo.copyright, romheader + ROMCOPYRIGHT, 16);
|
||||
memcpy (&rominfo.domestic, romheader + ROMDOMESTIC, 48);
|
||||
memcpy (&rominfo.international, romheader + ROMWORLD, 48);
|
||||
memcpy (&rominfo.ROMType, romheader + ROMTYPE0, 2);
|
||||
memcpy (&rominfo.product, romheader + ROMPRODUCT, 12);
|
||||
memcpy (&rominfo.checksum, romheader + ROMCHECKSUM, 2);
|
||||
memcpy (&rominfo.io_support, romheader + ROMIOSUPPORT, 16);
|
||||
memcpy (&rominfo.romstart, romheader + ROMROMSTART, 4);
|
||||
memcpy (&rominfo.romend, romheader + ROMROMEND, 4);
|
||||
memcpy (&rominfo.RAMInfo, romheader + ROMRAMINFO, 12);
|
||||
memcpy (&rominfo.ramstart, romheader + ROMRAMSTART, 4);
|
||||
memcpy (&rominfo.ramend, romheader + ROMRAMEND, 4);
|
||||
memcpy (&rominfo.modem, romheader + ROMMODEMINFO, 12);
|
||||
memcpy (&rominfo.memo, romheader + ROMMEMO, 40);
|
||||
memcpy (&rominfo.country, romheader + ROMCOUNTRY, 16);
|
||||
|
||||
checksumok = (GetRealChecksum ((char *) cart_rom + 512, genromsize - 512)
|
||||
== rominfo.checksum);
|
||||
|
||||
peripherals = 0;
|
||||
|
||||
for (i = 0; i < 14; i++)
|
||||
{
|
||||
if (rominfo.io_support[i] == peripheralinfo[i].pID[0]) peripherals |= (1 << i);
|
||||
}
|
||||
|
||||
if (peripherals & P6BUTTONS) pad_type = DEVICE_6BUTTON;
|
||||
else pad_type = DEVICE_3BUTTON;
|
||||
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Show rom info screen
|
||||
***************************************************************************/
|
||||
/* Automatically fixing the checksum is not a cool idea
|
||||
* This should be user switchable, or at least only applied
|
||||
* when genromsize == ( romend - romstart )
|
||||
if(realchecksum != (rominfo.checksum))
|
||||
{
|
||||
sprintf(msg, "WARNING: Possible hacked ROM loaded!");
|
||||
write_font( 10, 224, msg);
|
||||
cart_rom[0x18e] = realchecksum >> 8;
|
||||
cart_rom[0x18f] = realchecksum & 0xff;
|
||||
sprintf(msg, "Checksum corrected to %04x", realchecksum);
|
||||
write_font( 10, 248, msg);
|
||||
}
|
||||
*/
|
||||
void showrominfo ()
|
||||
{
|
||||
int ypos;
|
||||
u8 i,j,quit,redraw,max;
|
||||
char msg[128];
|
||||
short p;
|
||||
signed char a;
|
||||
uint16 realchecksum = GetRealChecksum (((uint8 *) cart_rom) + 0x200, genromsize - 0x200);
|
||||
|
||||
quit = 0;
|
||||
j = 0;
|
||||
redraw = 1;
|
||||
|
||||
/*** Remove any still held buttons ***/
|
||||
while(PAD_ButtonsHeld(0)) VIDEO_WaitVSync();
|
||||
|
||||
max = 14;
|
||||
for (i = 0; i < 14; i++)
|
||||
{
|
||||
if ((char) rominfo.io_support[i] == peripheralinfo[i].pID[0]) max ++;
|
||||
}
|
||||
|
||||
|
||||
while (quit == 0)
|
||||
{
|
||||
if (redraw)
|
||||
{
|
||||
ClearScreen ();
|
||||
|
||||
ypos = 134;
|
||||
WriteCentre(ypos, "ROM Header Information");
|
||||
ypos += 2*fheight;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
switch (i+j)
|
||||
{
|
||||
case 0:
|
||||
sprintf (msg, "Console type: %s", rominfo.consoletype);
|
||||
break;
|
||||
case 1:
|
||||
sprintf (msg, "Copyright: %s", rominfo.copyright);
|
||||
break;
|
||||
case 2:
|
||||
sprintf (msg, "Company: %s", companyinfo[getcompany ()].company);
|
||||
break;
|
||||
case 3:
|
||||
sprintf (msg, "Game Domestic Name:");
|
||||
break;
|
||||
case 4:
|
||||
sprintf(msg, " %s",rominfo.domestic);
|
||||
break;
|
||||
case 5:
|
||||
sprintf (msg, "Game International Name:");
|
||||
break;
|
||||
case 6:
|
||||
sprintf(msg, " %s",rominfo.international);
|
||||
break;
|
||||
case 7:
|
||||
sprintf (msg, "Type - %s : %s", rominfo.ROMType, strcmp (rominfo.ROMType, "AI") ? "Game" : "Educational");
|
||||
break;
|
||||
case 8:
|
||||
sprintf (msg, "Product - %s", rominfo.product);
|
||||
break;
|
||||
case 9:
|
||||
sprintf (msg, "Checksum - %04x (%04x) (%s)", rominfo.checksum, realchecksum, rominfo.checksum == realchecksum ? "Good" : "Bad");
|
||||
break;
|
||||
case 10:
|
||||
sprintf (msg, "ROM end: 0x%06X", rominfo.romend);
|
||||
break;
|
||||
case 11:
|
||||
if (sram.detected) sprintf (msg, "External RAM start: 0x%06X", rominfo.ramstart);
|
||||
else sprintf (msg, "External RAM start: UNDETECTED");
|
||||
break;
|
||||
case 12:
|
||||
if (sram.detected) sprintf (msg, "External RAM end : 0x%06X", rominfo.ramend);
|
||||
else sprintf (msg, "External RAM end : UNDETECTED");
|
||||
break;
|
||||
case 13:
|
||||
if (region_code == REGION_USA) sprintf (msg, "Region - %s (USA)", rominfo.country);
|
||||
else if (region_code == REGION_EUROPE) sprintf (msg, "Region - %s (EUR)", rominfo.country);
|
||||
else if (region_code == REGION_JAPAN_NTSC) sprintf (msg, "Region - %s (JAP)", rominfo.country);
|
||||
else if (region_code == REGION_JAPAN_PAL) sprintf (msg, "Region - %s (JPAL)", rominfo.country);
|
||||
break;
|
||||
default:
|
||||
sprintf (msg, "Supports - %s", peripheralinfo[i+j-14].pName);
|
||||
break;
|
||||
}
|
||||
|
||||
write_font (100, ypos, msg);
|
||||
ypos += fheight;
|
||||
}
|
||||
|
||||
ypos += fheight;
|
||||
WriteCentre (ypos, "Press A to Continue");
|
||||
SetScreen ();
|
||||
}
|
||||
|
||||
p = PAD_ButtonsDown (0);
|
||||
a = PAD_StickY (0);
|
||||
redraw = 0;
|
||||
|
||||
if ((j<(max-8)) && ((p & PAD_BUTTON_DOWN) || (a < -70))) {redraw = 1; j++;}
|
||||
if ((j>0) && ((p & PAD_BUTTON_UP) || (a > 70))) {redraw = 1; j--;}
|
||||
if (p & PAD_BUTTON_A) quit = 1;
|
||||
if (p & PAD_BUTTON_B) quit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* softdev - New Checksum Calculation
|
||||
*/
|
||||
uint16 GetRealChecksum (uint8 * rom, int length)
|
||||
{
|
||||
int i;
|
||||
uint16 checksum = 0;
|
||||
|
||||
for (i = 0; i < length; i += 2)
|
||||
{
|
||||
checksum += (uint16) rom[i];
|
||||
checksum += (uint16) rom[i + 1] << 8;
|
||||
}
|
||||
|
||||
return checksum;
|
||||
}
|
49
source/ngc/gui/rominfo.h
Normal file
49
source/ngc/gui/rominfo.h
Normal file
@ -0,0 +1,49 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Information in this module was gleaned from
|
||||
* http://en.wikibooks.org/wiki/Genesis_Programming
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char consoletype[18]; /* Genesis or Mega Drive */
|
||||
char copyright[18]; /* Copyright message */
|
||||
char domestic[50]; /* Domestic name of ROM */
|
||||
char international[50]; /* International name of ROM */
|
||||
char ROMType[4];
|
||||
char product[14]; /* Product type and serial number */
|
||||
unsigned short checksum; /* Checksum */
|
||||
char io_support[18]; /* Actually 16 chars :) */
|
||||
unsigned int romstart;
|
||||
unsigned int romend;
|
||||
char RAMInfo[14];
|
||||
unsigned int ramstart;
|
||||
unsigned int ramend;
|
||||
char modem[14];
|
||||
char memo[50];
|
||||
char country[18];
|
||||
} ROMINFO;
|
||||
|
||||
|
||||
extern void getrominfo (char *romheader);
|
||||
extern void showrominfo ();
|
||||
extern ROMINFO rominfo;
|
136
source/ngc/gui/saveicon.h
Normal file
136
source/ngc/gui/saveicon.h
Normal file
@ -0,0 +1,136 @@
|
||||
/***********************************************************
|
||||
* Genesis Plus Save Icon
|
||||
* Made by Brakken (http://www.tehskeen.com)
|
||||
*
|
||||
************************************************************/
|
||||
unsigned short icon[1024] = {
|
||||
|
||||
0xFFFF, 0xFFFF, 0xFBDE, 0xFBDE, 0xFBDE, 0xFBDE, 0xFBDE, 0xEB5A,
|
||||
0xFBDE, 0xFBDE, 0xFBDE, 0xBDCD, 0xFBDE, 0xF7BD, 0xF7BD, 0xAD49,
|
||||
0xEB59, 0xB9AD, 0xC1EF, 0xC1EF, 0x9062, 0x8000, 0x8C41, 0x8C41,
|
||||
0x8000, 0x9CE6, 0xA0E6, 0xA507, 0x8400, 0x9CC5, 0xA0E6, 0xA0E6,
|
||||
0xC1EF, 0xC1EF, 0xC1EF, 0xC1EF, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x9083, 0x8C63, 0x8C63, 0x9484, 0x8C63, 0x9083, 0x9484, 0x94A4,
|
||||
0xC1EF, 0xC20F, 0xC20F, 0xBDCE, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x9083, 0x8821, 0x8842, 0x8842, 0x8842, 0xA107, 0xB58C, 0xAD6B,
|
||||
0xA529, 0x94A4, 0x9083, 0x94A4, 0x8000, 0x8000, 0x8400, 0x8400,
|
||||
0x8842, 0x8842, 0x8842, 0x8821, 0xB18B, 0xA949, 0xA108, 0xA107,
|
||||
0xA528, 0xB9AD, 0xC630, 0xCE51, 0x8000, 0x8000, 0x8000, 0x8000,
|
||||
0x8821, 0x8821, 0x8821, 0x8400, 0xA108, 0xA529, 0xA108, 0xA529,
|
||||
0xCA30, 0xC630, 0xCA30, 0xFBDE, 0x8000, 0x8000, 0x8000, 0xAD27,
|
||||
0x8400, 0x9083, 0x8863, 0x8400, 0x9CE6, 0x8842, 0x8C63, 0x8C20,
|
||||
0xFBDE, 0xFBDE, 0xFFFF, 0xFFFF, 0xFBDE, 0xFBDE, 0xFBDE, 0xFBDE,
|
||||
0xDA92, 0xFBDE, 0xFBDE, 0xFBDE, 0xC1AB, 0xF7BD, 0xFBDE, 0xFBDE,
|
||||
0xF7BD, 0xF7BD, 0xF7BD, 0xA0E6, 0xF7BD, 0xF7BD, 0xF39C, 0x9484,
|
||||
0xF39C, 0xF39C, 0xDEF7, 0x8C41, 0xF39C, 0xEF7B, 0xD272, 0x8400,
|
||||
0x8C42, 0x9CE6, 0xA507, 0xA0E6, 0x8C63, 0x9CC5, 0xA107, 0x9CE6,
|
||||
0x9484, 0x98A5, 0x9CE6, 0x98C5, 0x9CC5, 0x98C5, 0xA0E7, 0x98C5,
|
||||
0x8C42, 0x9083, 0x94A5, 0x9083, 0x8C42, 0x9083, 0x9084, 0x8C62,
|
||||
0x8C62, 0x9083, 0x9084, 0x8C62, 0x8C63, 0x9083, 0x94A4, 0x8C63,
|
||||
0x8842, 0x9CC6, 0xA107, 0xA0E7, 0x8842, 0x8842, 0xA108, 0xA54A,
|
||||
0x8842, 0x8C63, 0xB5AD, 0xB5AD, 0x8C63, 0x8C62, 0x8842, 0x8C63,
|
||||
0x98C5, 0xA528, 0xB5AC, 0xB5AC, 0xA52A, 0xBDEF, 0xC631, 0xCA52,
|
||||
0xB9CE, 0xB9CE, 0xA94A, 0xAD6B, 0x8C63, 0x8821, 0x8821, 0x8821,
|
||||
0xA529, 0x98C5, 0x98C5, 0xA0E6, 0xC210, 0xA529, 0xA529, 0xA529,
|
||||
0xB5AD, 0xB5CD, 0xB5AD, 0xBDEF, 0x8400, 0x8821, 0x8C62, 0x8821,
|
||||
0xA0E7, 0x8842, 0x8842, 0x8C41, 0x9083, 0x8842, 0x8842, 0x8842,
|
||||
0x94A5, 0x8842, 0x8C62, 0x8C62, 0x8C42, 0x9083, 0x8C62, 0x8C62,
|
||||
0xB548, 0xF7BD, 0xF7BD, 0xF7BD, 0xA4C4, 0xF7BD, 0xF7BD, 0xF7BD,
|
||||
0x9461, 0xDED5, 0xF39C, 0xF39C, 0x8C20, 0xD271, 0xF39C, 0xF39C,
|
||||
0xEF7B, 0xEF7B, 0xC610, 0x8400, 0xEF7B, 0xEB5A, 0xB9AC, 0x8000,
|
||||
0xEB5A, 0xEB5A, 0xA528, 0x9CC5, 0xE739, 0xE739, 0x9CC6, 0x98A5,
|
||||
0x98C5, 0x98C5, 0xA0E6, 0x94A4, 0x94A4, 0x98C5, 0x94A5, 0x9484,
|
||||
0xA528, 0x98C5, 0x9CE6, 0xA0E7, 0x9CE6, 0xA4E6, 0x98A4, 0xA507,
|
||||
0x8C62, 0x9083, 0x9484, 0x9083, 0x94A4, 0x94A5, 0x98C5, 0x98C5,
|
||||
0xA107, 0xA107, 0xA107, 0xB18B, 0xA907, 0x9062, 0x9484, 0x9CE6,
|
||||
0x8842, 0x94A4, 0x9484, 0x9084, 0x8C62, 0x8C63, 0x9CC5, 0x9CC5,
|
||||
0x98C6, 0x8C63, 0x9484, 0xA0E6, 0x9CE6, 0x9084, 0x94A4, 0x90A5,
|
||||
0x8C63, 0x8C42, 0x8C62, 0x8C62, 0x8C63, 0xA108, 0xA94A, 0xA528,
|
||||
0x94A5, 0x8884, 0x8884, 0x8884, 0xB0A5, 0xBC84, 0xA483, 0xA484,
|
||||
0x8C63, 0x8C42, 0x8C63, 0x9083, 0xA94A, 0x9083, 0x8C62, 0x94A4,
|
||||
0x8884, 0x8063, 0x90A5, 0x94A4, 0xA483, 0xBC63, 0xA884, 0x8884,
|
||||
0x9083, 0x8C63, 0x8C42, 0x8C63, 0x9084, 0x8842, 0x9083, 0x9084,
|
||||
0x8C42, 0x8C62, 0x98C6, 0xAD6A, 0x9083, 0x8C63, 0x98C5, 0xA107,
|
||||
0x8400, 0xC1ED, 0xEF7B, 0xEF7B, 0x8400, 0xAD27, 0xEF7B, 0xEF7B,
|
||||
0x9CE6, 0x9CA4, 0xEB5A, 0xEB5A, 0x9CE6, 0x9062, 0xDAB4, 0xE739,
|
||||
0xE739, 0xE318, 0x9483, 0x8C63, 0xE318, 0xCE72, 0x9062, 0x9CC5,
|
||||
0xDEF7, 0xC20F, 0x8C41, 0x9CE6, 0xDAD6, 0xB9AC, 0x8C20, 0x9CC5,
|
||||
0xA0E6, 0xA528, 0x9CC5, 0xA528, 0xA508, 0x94A5, 0x98C6, 0xA108,
|
||||
0x9CE6, 0x9CC5, 0xA0E7, 0xA94A, 0xA0E6, 0xA0E7, 0xA507, 0xAD6B,
|
||||
0xA107, 0x98C6, 0x9CE6, 0x9083, 0x98C6, 0xA108, 0xA107, 0x98C5,
|
||||
0xB9CD, 0xB18B, 0xA107, 0x9CC6, 0xC210, 0xB9CE, 0xA528, 0x9CC6,
|
||||
0x98C5, 0x94A5, 0x9084, 0x8884, 0x9CC6, 0x9CE6, 0x9CC6, 0x94A5,
|
||||
0x9CE6, 0x9CE6, 0x9CE7, 0xA108, 0x98C5, 0x98C5, 0x98C6, 0x98C6,
|
||||
0xB0C6, 0xD0C6, 0xD0C6, 0xD0C6, 0x90A4, 0x90A4, 0x98A5, 0x9CA4,
|
||||
0x9CE6, 0x90A4, 0x9084, 0x9084, 0x98C6, 0x98C6, 0x98C6, 0x98C6,
|
||||
0xD0A5, 0xD0A5, 0xA484, 0x8483, 0x9484, 0x9083, 0x8C83, 0x9084,
|
||||
0x90A5, 0x94A5, 0x9CE6, 0x9CE6, 0x98C6, 0x98C6, 0x9CE6, 0x98C6,
|
||||
0x8C63, 0x9084, 0x9484, 0x9083, 0x98C5, 0x98C5, 0x94A4, 0x94A5,
|
||||
0x98C6, 0x98C6, 0x98C5, 0x98C5, 0x98C6, 0x98C6, 0x98C6, 0x98C6,
|
||||
0x9084, 0x8821, 0xCE51, 0xE739, 0x94A5, 0x8C20, 0xBDCE, 0xE318,
|
||||
0x98C5, 0x8821, 0xB18B, 0xE318, 0x98C6, 0x8842, 0xAD49, 0xDEF7,
|
||||
0xDAD6, 0xAD49, 0x8C41, 0xA508, 0xD6B5, 0xBDCC, 0x8C20, 0x8C41,
|
||||
0xD6B5, 0xD294, 0xB98A, 0xAD06, 0xD294, 0xCE73, 0xCE73, 0xCA52,
|
||||
0xA94A, 0xB5AD, 0xB18C, 0xAD6B, 0x9062, 0x9062, 0x9062, 0x9062,
|
||||
0xAD27, 0xAD06, 0xAD06, 0xAD06, 0xCA52, 0xC631, 0xC631, 0xC210,
|
||||
0xA94B, 0xB18C, 0xB58D, 0xAD6B, 0x9062, 0x9484, 0x98A4, 0x98A4,
|
||||
0xA906, 0xA906, 0xA506, 0xA907, 0xC210, 0xC210, 0xB9F0, 0xBDEF,
|
||||
0xA94B, 0xA94B, 0xA94B, 0xA94B, 0x98A5, 0x98A5, 0x98A4, 0x98A4,
|
||||
0xA907, 0xA907, 0xA907, 0xA506, 0xBDEF, 0xBDEF, 0xBDEF, 0xB1F2,
|
||||
0xA94B, 0xA94A, 0xA54A, 0xA529, 0x9484, 0x9484, 0x9483, 0x9483,
|
||||
0xA4E6, 0xA4E6, 0xA4E6, 0xA4E6, 0xBDEF, 0xBDEF, 0xBDEF, 0xBDEF,
|
||||
0xA529, 0xA529, 0xA529, 0xA108, 0x9062, 0x8C63, 0x9062, 0x9062,
|
||||
0xA4E6, 0x9CE6, 0xA0E6, 0xA506, 0xBDEF, 0xC210, 0xC210, 0xC210,
|
||||
0xA108, 0x9CE7, 0x9CE7, 0x98C6, 0x8C41, 0x8C42, 0x8C41, 0x8C41,
|
||||
0xA507, 0xA508, 0xAD27, 0xB127, 0xC631, 0xC631, 0xCA52, 0xCA52,
|
||||
0x98C6, 0x8C63, 0xA0E6, 0xDAD6, 0x8C41, 0x8400, 0xB548, 0xDAD6,
|
||||
0xB127, 0xB548, 0xD6B5, 0xD6B5, 0xCE73, 0xCE73, 0xD294, 0xD6B5,
|
||||
0xD294, 0xCA74, 0xBA56, 0xB635, 0x9A3B, 0x81FF, 0x81FF, 0x81FF,
|
||||
0x81FF, 0x8A1F, 0xA27F, 0xA27F, 0x81FF, 0xA27F, 0xFFFF, 0xFFFF,
|
||||
0xB635, 0xB214, 0xB214, 0xBE11, 0x81FF, 0x81FF, 0x81FF, 0x81FF,
|
||||
0xA27F, 0xA27F, 0xA27F, 0x8A1F, 0xFFFF, 0xFFFF, 0xFFFF, 0xDF7F,
|
||||
0xA1F7, 0x91FA, 0x81FF, 0x95F9, 0x81FF, 0x81FF, 0x8A1F, 0x81FF,
|
||||
0x81FF, 0xD75F, 0xBEFF, 0x81FF, 0x81FF, 0xFFFF, 0xBEFF, 0x81FF,
|
||||
0xB9CE, 0xB9CE, 0x8DFC, 0x81FF, 0xA9D2, 0xA9D2, 0x81FF, 0x9A5F,
|
||||
0x99D6, 0x99D6, 0x81FF, 0xBEFF, 0x99D6, 0x99D6, 0x81FF, 0xBEFF,
|
||||
0x85FD, 0x95F9, 0xB5CF, 0xB1F1, 0x81FF, 0x81FF, 0x95F9, 0x81FF,
|
||||
0xEFBF, 0x81FF, 0x85FD, 0x81FF, 0xFFFF, 0x81FF, 0x81FF, 0x81FF,
|
||||
0xA5F5, 0xA5F5, 0xB5F2, 0xB214, 0x81FF, 0x81FF, 0x81FF, 0x81FF,
|
||||
0xB2BF, 0xB2BF, 0x81FF, 0x9A5F, 0xDF7F, 0xDF7F, 0x81FF, 0xE79F,
|
||||
0xA218, 0xA218, 0xA218, 0xA639, 0x81FF, 0x81FF, 0x81FF, 0x81FF,
|
||||
0xBEFF, 0xBEFF, 0xBEFF, 0xBEFF, 0xF7DF, 0xDF7F, 0xDF7F, 0xDF7F,
|
||||
0xA639, 0xB657, 0xCA75, 0xD294, 0x81FF, 0x81FF, 0x861E, 0xCA95,
|
||||
0xBEFF, 0xAA9F, 0x81FF, 0xB658, 0xD75F, 0x8A1F, 0x81FF, 0xCA75,
|
||||
0x81FF, 0xA27F, 0xFFFF, 0xA27F, 0x81FF, 0xA27F, 0xFFFF, 0xFFFF,
|
||||
0x81FF, 0xA27F, 0xFFFF, 0xBADF, 0x81FF, 0xA27F, 0xFFFF, 0xA27F,
|
||||
0x81FF, 0x81FF, 0xCF3F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xBADF,
|
||||
0xA27F, 0xA27F, 0xA27F, 0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x81FF,
|
||||
0x923F, 0xFFFF, 0xBEFF, 0x81FF, 0x81FF, 0xFFFF, 0xBEFF, 0x81FF,
|
||||
0x81FF, 0xFFFF, 0xCF3F, 0xA27F, 0x81FF, 0xFFFF, 0xFFFF, 0xFFFF,
|
||||
0x99D6, 0x99D6, 0x81FF, 0xBEFF, 0x81FF, 0x81FF, 0x81FF, 0xBEFF,
|
||||
0xA27F, 0xA27F, 0x9A5F, 0xBADF, 0xFFFF, 0xFFFF, 0xA27F, 0x81FF,
|
||||
0xFFFF, 0x81FF, 0x81FF, 0x81FF, 0xFFFF, 0x81FF, 0x81FF, 0x81FF,
|
||||
0xFFFF, 0xBEFF, 0xBEFF, 0xBEFF, 0xC71F, 0xDF7F, 0xDF7F, 0xDF7F,
|
||||
0xDF7F, 0xDF7F, 0x923F, 0xF7DF, 0xDF7F, 0xDF7F, 0x81FF, 0xAA9F,
|
||||
0xEFBF, 0xC71F, 0x81FF, 0x9A5F, 0xCF3F, 0x81FF, 0x8A1F, 0xD75F,
|
||||
0xE79F, 0xBEFF, 0xBEFF, 0xBEFF, 0xDF7F, 0xDF7F, 0xDF7F, 0xDF7F,
|
||||
0xBEFF, 0xBEFF, 0xBEFF, 0xC71F, 0xDF7F, 0xDF7F, 0xDF7F, 0xDF7F,
|
||||
0xBEFF, 0x81FF, 0x81FF, 0xB657, 0xFFFF, 0xC71F, 0x81FF, 0xA23A,
|
||||
0xFFFF, 0xC71F, 0x81FF, 0xA23A, 0xD75F, 0x8A1F, 0x81FF, 0xB658,
|
||||
0x81FF, 0x9A5F, 0xAA9F, 0x81FF, 0x921D, 0x81FF, 0x81FF, 0x85FE,
|
||||
0xD294, 0xBE55, 0xB657, 0xC653, 0xD294, 0xD294, 0xCE73, 0xCA52,
|
||||
0x8A1D, 0xB214, 0xB214, 0x8DFC, 0xBA34, 0xC631, 0xC210, 0xB612,
|
||||
0xC631, 0xC631, 0xC631, 0xC210, 0xCA52, 0xCA52, 0xC631, 0xC631,
|
||||
0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x8DFC, 0x81FF, 0x81FF, 0x81FF,
|
||||
0xC210, 0xBE10, 0xBDEF, 0xBDEF, 0xC210, 0xC210, 0xC210, 0xBE10,
|
||||
0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x8DFB, 0xA5D4,
|
||||
0xBDEF, 0xB9CE, 0xB9CE, 0xB9CE, 0xBDEF, 0xBDEF, 0xBDEF, 0xBDEF,
|
||||
0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x99F8, 0x8DFB, 0x8DFB, 0x8DFB,
|
||||
0xB9CE, 0xBDEF, 0xBDEF, 0xBDEF, 0xBDEF, 0xBDEF, 0xBE10, 0xC210,
|
||||
0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x95F9, 0xA5F5, 0xA1F7, 0x91FA,
|
||||
0xBDEF, 0xBE10, 0xC210, 0xC210, 0xC210, 0xC210, 0xC631, 0xC631,
|
||||
0x81FF, 0x81FF, 0x81FF, 0x81FF, 0x921C, 0x921C, 0x921C, 0x921C,
|
||||
0xC631, 0xC631, 0xCA52, 0xCA52, 0xC631, 0xCA52, 0xCA52, 0xCE73,
|
||||
0x81FF, 0x81FF, 0x9A3B, 0xD294, 0x961B, 0xAA39, 0xD294, 0xD294,
|
||||
0xCE73, 0xCE73, 0xD294, 0xD6B5, 0xCE73, 0xD294, 0xD6B5, 0xD6B5,
|
||||
};
|
201
source/ngc/loadrom.c
Normal file
201
source/ngc/loadrom.c
Normal file
@ -0,0 +1,201 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
#include "rominfo.h"
|
||||
#include <ctype.h>
|
||||
|
||||
/* 05/05/2006: new region detection routine (taken from GENS sourcecode) */
|
||||
extern uint8 region_detect;
|
||||
extern uint8 cpu_detect;
|
||||
|
||||
void genesis_set_region ()
|
||||
{
|
||||
/* country codes used to differentiate region */
|
||||
/* 0001 = japan ntsc (1) */
|
||||
/* 0010 = japan pal (2) */
|
||||
/* 0100 = usa (4) */
|
||||
/* 1000 = europe (8) */
|
||||
|
||||
int country = 0;
|
||||
int i = 0;
|
||||
char c;
|
||||
|
||||
/* reading header to find the country */
|
||||
if (!strnicmp(rominfo.country, "eur", 3)) country |= 8;
|
||||
else if (!strnicmp(rominfo.country, "usa", 3)) country |= 4;
|
||||
else if (!strnicmp(rominfo.country, "jap", 3)) country |= 1;
|
||||
|
||||
else for(i = 0; i < 4; i++)
|
||||
{
|
||||
c = toupper((int)rominfo.country[i]);
|
||||
if (c == 'U') country |= 4;
|
||||
else if (c == 'J') country |= 1;
|
||||
else if (c == 'E') country |= 8;
|
||||
else if (c < 16) country |= c;
|
||||
else if ((c >= '0') && (c <= '9')) country |= c - '0';
|
||||
else if ((c >= 'A') && (c <= 'F')) country |= c - 'A' + 10;
|
||||
}
|
||||
|
||||
/* automatic detection */
|
||||
/* setting region */
|
||||
/* this is used by IO register */
|
||||
if (country & 4) region_code = REGION_USA;
|
||||
else if (country & 8) region_code = REGION_EUROPE;
|
||||
else if (country & 1) region_code = REGION_JAPAN_NTSC;
|
||||
else if (country & 2) region_code = REGION_JAPAN_PAL;
|
||||
else region_code = REGION_USA;
|
||||
|
||||
/* cpu mode: PAL or NTSC */
|
||||
if ((region_code == REGION_EUROPE) || (region_code == REGION_JAPAN_PAL)) vdp_pal = 1;
|
||||
else vdp_pal = 0;
|
||||
|
||||
/* Force region setting */
|
||||
if (region_detect == 1) region_code = REGION_USA;
|
||||
else if (region_detect == 2) region_code = REGION_EUROPE;
|
||||
else if (region_detect == 3) region_code = REGION_JAPAN_NTSC;
|
||||
else if (region_detect == 4) region_code = REGION_JAPAN_PAL;
|
||||
|
||||
/* Force CPU mode */
|
||||
if (cpu_detect == 1) vdp_pal = 0;
|
||||
else if (cpu_detect == 2) vdp_pal = 1;
|
||||
}
|
||||
|
||||
|
||||
/* patch_game
|
||||
* set specific timings for some games
|
||||
*/
|
||||
extern uint8 alttiming;
|
||||
extern uint8 irqtiming;
|
||||
extern uint8 sys_type[2];
|
||||
|
||||
void patch_game()
|
||||
{
|
||||
if ((strstr(rominfo.product,"T-50406") != NULL) || /* Legend of Galahad */
|
||||
(strstr(rominfo.product,"MK-1079") != NULL) || /* Sonic the Hedgehog 3 (JUE) */
|
||||
(strstr(rominfo.product,"MK-1563") != NULL) || /* Sonic & Knuckes + Sonic the Hedgehog 3 (JUE) */
|
||||
(strstr(rominfo.product,"T-50116") != NULL) || /* Road Rash */
|
||||
(strstr(rominfo.product,"T-50496") != NULL) || /* Road Rash 2 (UE) */
|
||||
(strstr(rominfo.product,"T-106143") != NULL) || /* Road Rash 2 (J) */
|
||||
(strstr(rominfo.product,"T-50966") != NULL) /* Road Rash 3 (UE) */
|
||||
) alttiming = 1;
|
||||
else alttiming = 0;
|
||||
|
||||
/* Sesame's Street Counting Cafe */
|
||||
if (strstr(rominfo.product,"T-50896") != NULL) irqtiming = 1;
|
||||
else irqtiming = 0;
|
||||
|
||||
/* Menacer 6-in-1 Pack */
|
||||
if (strstr(rominfo.product,"MK-1658") != NULL)
|
||||
{
|
||||
input.system[0] = NO_SYSTEM;
|
||||
input.system[1] = SYSTEM_MENACER;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (sys_type[0] == 0) input.system[0] = SYSTEM_GAMEPAD;
|
||||
else if (sys_type[0] == 1) input.system[0] = SYSTEM_TEAMPLAYER;
|
||||
else if (sys_type[0] == 2) input.system[0] = NO_SYSTEM;
|
||||
|
||||
if (sys_type[1] == 0) input.system[1] = SYSTEM_GAMEPAD;
|
||||
else if (sys_type[1] == 1) input.system[1] = SYSTEM_TEAMPLAYER;
|
||||
else if (sys_type[1] == 2) input.system[1] = NO_SYSTEM;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* SMD -interleaved) rom support */
|
||||
static uint8 block[0x4000];
|
||||
|
||||
void deinterleave_block (uint8 * src)
|
||||
{
|
||||
int i;
|
||||
memcpy (block, src, 0x4000);
|
||||
for (i = 0; i < 0x2000; i += 1)
|
||||
{
|
||||
src[i * 2 + 0] = block[0x2000 + (i)];
|
||||
src[i * 2 + 1] = block[0x0000 + (i)];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* load_memrom
|
||||
* softdev 12 March 2006
|
||||
* Changed from using ROM buffer to a single copy in cart_rom
|
||||
*
|
||||
* Saving ROM size in bytes :)
|
||||
* Required for remote loading.
|
||||
*
|
||||
* WIP3 - Removed 5Mb SSF2TNC from main memory to Audio ROM
|
||||
*/
|
||||
void load_memrom (int size)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
SSF2TNC = 0;
|
||||
|
||||
/* Support for interleaved roms */
|
||||
if ((size / 512) & 1)
|
||||
{
|
||||
int i;
|
||||
size -= 512;
|
||||
offset += 512;
|
||||
|
||||
for (i = 0; i < (size / 0x4000); i += 1)
|
||||
{
|
||||
deinterleave_block (cart_rom + offset + (i * 0x4000));
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 0x500000) size = 0x500000;
|
||||
if (offset) memcpy (cart_rom, cart_rom + offset, size);
|
||||
if (size > 0x400000) SSF2TNC = 1; /*** Assume SSF2TNC (mapped ROM) ***/
|
||||
|
||||
genromsize = size;
|
||||
|
||||
/*** Clear out space ***/
|
||||
if (size < 0x500000) memset (cart_rom + size, 0, 0x500000 - size);
|
||||
return;
|
||||
}
|
||||
|
||||
/*** Reloadrom
|
||||
performs some initialization before running the new rom
|
||||
***/
|
||||
extern void decode_ggcodes ();
|
||||
extern void ClearGGCodes ();
|
||||
extern void sram_autoload();
|
||||
extern uint8 autoload;
|
||||
|
||||
void reloadrom ()
|
||||
{
|
||||
load_memrom (genromsize);
|
||||
SRAM_Init (); /* SRAM Infos from ROM header */
|
||||
getrominfo (cart_rom); /* Other Infos from ROM Header */
|
||||
genesis_set_region (); /* Region Detection */
|
||||
patch_game(); /* game special patches */
|
||||
|
||||
system_init ();
|
||||
audio_init(48000);
|
||||
ClearGGCodes (); /* Game Genie */
|
||||
decode_ggcodes ();
|
||||
|
||||
system_reset ();
|
||||
if (autoload) sram_autoload();
|
||||
}
|
640
source/ngc/ngc.c
Normal file
640
source/ngc/ngc.c
Normal file
@ -0,0 +1,640 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
#include "gcaram.h"
|
||||
#include "dvd.h"
|
||||
#include "font.h"
|
||||
|
||||
#define ROMOFFSET 0x80600000
|
||||
|
||||
unsigned char *gen_bmp; /*** Work bitmap ***/
|
||||
int frameticker = 0;
|
||||
int ConfigRequested = 0;
|
||||
int padcal = 70;
|
||||
int RenderedFrameCount = 0;
|
||||
int FrameCount = 0;
|
||||
int FramesPerSecond = 0;
|
||||
u8 isWII = 0;
|
||||
|
||||
/***************************************************************************
|
||||
* Nintendo Gamecube Hardware Specific Functions
|
||||
*
|
||||
* T I M E R
|
||||
***************************************************************************/
|
||||
#define TB_CLOCK 40500000
|
||||
#define mftb(rval) ({unsigned long u; do { \
|
||||
asm volatile ("mftbu %0" : "=r" (u)); \
|
||||
asm volatile ("mftb %0" : "=r" ((rval)->l)); \
|
||||
asm volatile ("mftbu %0" : "=r" ((rval)->u)); \
|
||||
} while(u != ((rval)->u)); })
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long l, u;
|
||||
} tb_t;
|
||||
|
||||
unsigned long tb_diff_msec(tb_t *end, tb_t *start)
|
||||
{
|
||||
unsigned long upper, lower;
|
||||
upper = end->u - start->u;
|
||||
if (start->l > end->l) upper--;
|
||||
lower = end->l - start->l;
|
||||
return ((upper*((unsigned long)0x80000000/(TB_CLOCK/2000))) + (lower/(TB_CLOCK/1000)));
|
||||
}
|
||||
|
||||
int msBetweenFrames = 20;
|
||||
tb_t now, prev;
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* Nintendo Gamecube Hardware Specific Functions
|
||||
*
|
||||
* V I D E O
|
||||
***************************************************************************/
|
||||
/*** 2D Video ***/
|
||||
unsigned int *xfb[2]; /*** Double buffered ***/
|
||||
int whichfb = 0; /*** Switch ***/
|
||||
GXRModeObj *vmode; /*** General video mode ***/
|
||||
|
||||
/*** GX ***/
|
||||
#define TEX_WIDTH 320
|
||||
#define TEX_HEIGHT 256
|
||||
#define DEFAULT_FIFO_SIZE 256 * 1024
|
||||
|
||||
static u8 gp_fifo[DEFAULT_FIFO_SIZE] ATTRIBUTE_ALIGN (32);
|
||||
static u8 texturemem[TEX_WIDTH * (TEX_HEIGHT + 8) * 2] ATTRIBUTE_ALIGN (32);
|
||||
GXTexObj texobj;
|
||||
static Mtx view;
|
||||
int vwidth, vheight, oldvwidth, oldvheight;
|
||||
|
||||
/* New texture based scaler */
|
||||
#define HASPECT 76
|
||||
#define VASPECT 54
|
||||
|
||||
typedef struct tagcamera
|
||||
{
|
||||
Vector pos;
|
||||
Vector up;
|
||||
Vector view;
|
||||
} camera;
|
||||
|
||||
/*** Square Matrix
|
||||
This structure controls the size of the image on the screen.
|
||||
Think of the output as a -80 x 80 by -60 x 60 graph.
|
||||
***/
|
||||
s16 square[] ATTRIBUTE_ALIGN (32) =
|
||||
{
|
||||
/*
|
||||
* X, Y, Z
|
||||
* Values set are for roughly 4:3 aspect
|
||||
*/
|
||||
-HASPECT, VASPECT, 0, // 0
|
||||
HASPECT, VASPECT, 0, // 1
|
||||
HASPECT, -VASPECT, 0, // 2
|
||||
-HASPECT, -VASPECT, 0, // 3
|
||||
};
|
||||
|
||||
static camera cam = { {0.0F, 0.0F, 0.0F},
|
||||
{0.0F, 0.5F, 0.0F},
|
||||
{0.0F, 0.0F, -0.5F}
|
||||
};
|
||||
|
||||
/*** Framestart function
|
||||
Simply increment the tick counter
|
||||
***/
|
||||
static void framestart()
|
||||
{
|
||||
frameticker++;
|
||||
}
|
||||
|
||||
/*** WIP3 - Scaler Support Functions
|
||||
***/
|
||||
static void draw_init (void)
|
||||
{
|
||||
GX_ClearVtxDesc ();
|
||||
GX_SetVtxDesc (GX_VA_POS, GX_INDEX8);
|
||||
GX_SetVtxDesc (GX_VA_CLR0, GX_INDEX8);
|
||||
GX_SetVtxDesc (GX_VA_TEX0, GX_DIRECT);
|
||||
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_S16, 0);
|
||||
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
||||
GX_SetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0);
|
||||
GX_SetArray (GX_VA_POS, square, 3 * sizeof (s16));
|
||||
GX_SetNumTexGens (1);
|
||||
GX_SetTexCoordGen (GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_IDENTITY);
|
||||
GX_InvalidateTexAll ();
|
||||
GX_InitTexObj (&texobj, texturemem, vwidth, vheight, GX_TF_RGB565, GX_CLAMP, GX_CLAMP, GX_FALSE);
|
||||
}
|
||||
|
||||
static void draw_vert (u8 pos, u8 c, f32 s, f32 t)
|
||||
{
|
||||
GX_Position1x8 (pos);
|
||||
GX_Color1x8 (c);
|
||||
GX_TexCoord2f32 (s, t);
|
||||
}
|
||||
|
||||
static void draw_square (Mtx v)
|
||||
{
|
||||
Mtx m; // model matrix.
|
||||
Mtx mv; // modelview matrix.
|
||||
|
||||
guMtxIdentity (m);
|
||||
guMtxTransApply (m, m, 0, 0, -100);
|
||||
guMtxConcat (v, m, mv);
|
||||
GX_LoadPosMtxImm (mv, GX_PNMTX0);
|
||||
GX_Begin (GX_QUADS, GX_VTXFMT0, 4);
|
||||
draw_vert (0, 0, 0.0, 0.0);
|
||||
draw_vert (1, 0, 1.0, 0.0);
|
||||
draw_vert (2, 0, 1.0, 1.0);
|
||||
draw_vert (3, 0, 0.0, 1.0);
|
||||
GX_End ();
|
||||
}
|
||||
|
||||
/*** StartGX
|
||||
This function initialises the GX.
|
||||
WIP3 - Based on texturetest from libOGC examples.
|
||||
***/
|
||||
static void StartGX (void)
|
||||
{
|
||||
Mtx p;
|
||||
GXColor gxbackground = { 0, 0, 0, 0xff };
|
||||
|
||||
/*** Clear out FIFO area ***/
|
||||
memset (&gp_fifo, 0, DEFAULT_FIFO_SIZE);
|
||||
|
||||
/*** Initialise GX ***/
|
||||
GX_Init (&gp_fifo, DEFAULT_FIFO_SIZE);
|
||||
GX_SetCopyClear (gxbackground, 0x00ffffff);
|
||||
GX_SetViewport (0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
|
||||
GX_SetDispCopyYScale ((f32) vmode->xfbHeight / (f32) vmode->efbHeight);
|
||||
GX_SetScissor (0, 0, vmode->fbWidth, vmode->efbHeight);
|
||||
GX_SetDispCopySrc (0, 0, vmode->fbWidth, vmode->efbHeight);
|
||||
GX_SetDispCopyDst (vmode->fbWidth, vmode->xfbHeight);
|
||||
GX_SetCopyFilter (vmode->aa, vmode->sample_pattern, GX_TRUE, vmode->vfilter);
|
||||
GX_SetFieldMode (vmode->field_rendering, ((vmode->viHeight == 2 * vmode->xfbHeight) ? GX_ENABLE : GX_DISABLE));
|
||||
GX_SetPixelFmt (GX_PF_RGB8_Z24, GX_ZC_LINEAR);
|
||||
GX_SetCullMode (GX_CULL_NONE);
|
||||
GX_CopyDisp (xfb[whichfb ^ 1], GX_TRUE);
|
||||
GX_SetDispCopyGamma (GX_GM_1_0);
|
||||
guPerspective (p, 60, 1.33F, 10.0F, 1000.0F);
|
||||
GX_LoadProjectionMtx (p, GX_PERSPECTIVE);
|
||||
memset (texturemem, 0, TEX_WIDTH * TEX_HEIGHT * 2);
|
||||
vwidth = 100;
|
||||
vheight = 100;
|
||||
}
|
||||
|
||||
/*** InitGCVideo
|
||||
This function MUST be called at startup.
|
||||
***/
|
||||
static void InitGCVideo ()
|
||||
{
|
||||
int *romptr = (int *)ROMOFFSET;
|
||||
|
||||
/*
|
||||
* Before doing anything else under libogc,
|
||||
* Call VIDEO_Init
|
||||
*/
|
||||
VIDEO_Init ();
|
||||
|
||||
/*
|
||||
* Before any memory is allocated etc.
|
||||
* Rescue any tagged ROM in data 2
|
||||
*/
|
||||
StartARAM();
|
||||
if ( memcmp((char *)romptr,"GENPLUSR",8) == 0 )
|
||||
{
|
||||
genromsize = romptr[2];
|
||||
ARAMPut ((char *) 0x80600020, (char *) 0x8000, genromsize);
|
||||
}
|
||||
else genromsize = 0;
|
||||
|
||||
/* Init Gamepads */
|
||||
PAD_Init ();
|
||||
|
||||
/*
|
||||
* Reset the video mode
|
||||
* This is always set to 60hz
|
||||
* Whether your running PAL or NTSC
|
||||
*/
|
||||
vmode = &TVNtsc480IntDf;
|
||||
VIDEO_Configure (vmode);
|
||||
|
||||
/*** Now configure the framebuffer.
|
||||
Really a framebuffer is just a chunk of memory
|
||||
to hold the display line by line.
|
||||
**/
|
||||
xfb[0] = (u32 *) MEM_K0_TO_K1((u32 *) SYS_AllocateFramebuffer(vmode));
|
||||
|
||||
/*** I prefer also to have a second buffer for double-buffering.
|
||||
This is not needed for the console demo.
|
||||
***/
|
||||
xfb[1] = (u32 *) MEM_K0_TO_K1((u32 *) SYS_AllocateFramebuffer(vmode));
|
||||
|
||||
/*** Define a console ***/
|
||||
console_init(xfb[0], 20, 64, vmode->fbWidth, vmode->xfbHeight, vmode->fbWidth * 2);
|
||||
|
||||
/*** Clear framebuffer to black ***/
|
||||
VIDEO_ClearFrameBuffer(vmode, xfb[0], COLOR_BLACK);
|
||||
VIDEO_ClearFrameBuffer(vmode, xfb[1], COLOR_BLACK);
|
||||
|
||||
/*** Set the framebuffer to be displayed at next VBlank ***/
|
||||
VIDEO_SetNextFramebuffer(xfb[0]);
|
||||
|
||||
/*** Increment frameticker and timer ***/
|
||||
VIDEO_SetPreRetraceCallback(framestart);
|
||||
|
||||
/*** Get the PAD status updated by libogc ***/
|
||||
VIDEO_SetPostRetraceCallback(PAD_ScanPads);
|
||||
VIDEO_SetBlack (FALSE);
|
||||
|
||||
/*** Update the video for next vblank ***/
|
||||
VIDEO_Flush();
|
||||
|
||||
/*** Wait for VBL ***/
|
||||
VIDEO_WaitVSync();
|
||||
if (vmode->viTVMode & VI_NON_INTERLACE) VIDEO_WaitVSync();
|
||||
|
||||
DVD_Init ();
|
||||
SDCARD_Init ();
|
||||
unpackBackdrop ();
|
||||
init_font();
|
||||
StartGX ();
|
||||
|
||||
/* Wii drive detection for 4.7Gb support */
|
||||
int driveid = dvd_inquiry();
|
||||
if ((driveid == 4) || (driveid == 6) || (driveid == 8)) isWII = 0;
|
||||
else isWII = 1;
|
||||
}
|
||||
|
||||
/*** Video Update
|
||||
called after each emulation frame
|
||||
***/
|
||||
static void update_video ()
|
||||
{
|
||||
int h, w;
|
||||
vwidth = (reg[12] & 1) ? 320 : 256;
|
||||
vheight = (reg[1] & 8) ? 240 : 224;
|
||||
|
||||
long long int *dst = (long long int *)texturemem;
|
||||
long long int *src1 = (long long int *)(bitmap.data + 64);
|
||||
long long int *src2 = src1 + 256;
|
||||
long long int *src3 = src2 + 256;
|
||||
long long int *src4 = src3 + 256;
|
||||
long long int stride = 1024 - ( vwidth >> 2 );
|
||||
|
||||
whichfb ^= 1;
|
||||
|
||||
if ((oldvheight != vheight) || (oldvwidth != vwidth))
|
||||
{
|
||||
/** Update scaling **/
|
||||
oldvwidth = vwidth;
|
||||
oldvheight = vheight;
|
||||
draw_init ();
|
||||
memset (&view, 0, sizeof (Mtx));
|
||||
guLookAt(view, &cam.pos, &cam.up, &cam.view);
|
||||
GX_SetViewport (0, 0, vmode->fbWidth, vmode->efbHeight, 0, 1);
|
||||
}
|
||||
|
||||
GX_InvVtxCache ();
|
||||
GX_InvalidateTexAll ();
|
||||
GX_SetTevOp (GX_TEVSTAGE0, GX_DECAL);
|
||||
GX_SetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
||||
|
||||
for (h = 0; h < vheight; h += 4)
|
||||
{
|
||||
for (w = 0; w < (vwidth >> 2); w++ )
|
||||
{
|
||||
*dst++ = *src1++;
|
||||
*dst++ = *src2++;
|
||||
*dst++ = *src3++;
|
||||
*dst++ = *src4++;
|
||||
}
|
||||
|
||||
src1 += stride;
|
||||
src2 += stride;
|
||||
src3 += stride;
|
||||
src4 += stride;
|
||||
}
|
||||
|
||||
DCFlushRange (texturemem, TEX_WIDTH * TEX_HEIGHT * 2);
|
||||
GX_SetNumChans (1);
|
||||
GX_LoadTexObj (&texobj, GX_TEXMAP0);
|
||||
draw_square (view);
|
||||
GX_DrawDone ();
|
||||
GX_SetZMode (GX_TRUE, GX_LEQUAL, GX_TRUE);
|
||||
GX_SetColorUpdate (GX_TRUE);
|
||||
GX_CopyDisp (xfb[whichfb], GX_TRUE);
|
||||
GX_Flush ();
|
||||
VIDEO_SetNextFramebuffer (xfb[whichfb]);
|
||||
VIDEO_Flush ();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Nintendo Gamecube Hardware Specific Functions
|
||||
*
|
||||
* A U D I O
|
||||
***************************************************************************/
|
||||
unsigned char soundbuffer[16][3840] ATTRIBUTE_ALIGN(32);
|
||||
int mixbuffer = 0;
|
||||
int playbuffer = 0;
|
||||
int IsPlaying = 0;
|
||||
|
||||
/*** AudioSwitchBuffers
|
||||
Genesis Plus only provides sound data on completion of each frame.
|
||||
To try to make the audio less choppy, this function is called from both the
|
||||
DMA completion and update_audio.
|
||||
Testing for data in the buffer ensures that there are no clashes.
|
||||
***/
|
||||
static void AudioSwitchBuffers()
|
||||
{
|
||||
u32 dma_len = (vdp_pal) ? 3840 : 3200;
|
||||
|
||||
if ( !ConfigRequested )
|
||||
{
|
||||
AUDIO_InitDMA((u32) soundbuffer[playbuffer], dma_len);
|
||||
DCFlushRange(soundbuffer[playbuffer], dma_len);
|
||||
AUDIO_StartDMA();
|
||||
playbuffer++;
|
||||
playbuffer &= 0xf;
|
||||
if ( playbuffer == mixbuffer ) playbuffer--;
|
||||
if ( playbuffer < 0 ) playbuffer = 15;
|
||||
IsPlaying = 1;
|
||||
}
|
||||
else IsPlaying = 0;
|
||||
}
|
||||
|
||||
/*** InitGCAudio
|
||||
Stock code to set the DSP at 48Khz
|
||||
***/
|
||||
static void InitGCAudio ()
|
||||
{
|
||||
AUDIO_Init (NULL);
|
||||
AUDIO_SetDSPSampleRate (AI_SAMPLERATE_48KHZ);
|
||||
AUDIO_RegisterDMACallback (AudioSwitchBuffers);
|
||||
memset(soundbuffer, 0, 16 * 3840);
|
||||
}
|
||||
|
||||
/*** Audio Update
|
||||
called after each emulation frame
|
||||
***/
|
||||
static void update_audio ()
|
||||
{
|
||||
if (IsPlaying == 0) AudioSwitchBuffers ();
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Nintendo Gamecube Hardware Specific Functions
|
||||
*
|
||||
* I N P U T
|
||||
***************************************************************************/
|
||||
/**
|
||||
* IMPORTANT
|
||||
* If you change the padmap here, be sure to update confjoy to
|
||||
* reflect the changes - or confusion will ensue!
|
||||
*
|
||||
* DEFAULT MAPPING IS:
|
||||
* Genesis Gamecube
|
||||
* A B
|
||||
* B A
|
||||
* C X
|
||||
* X LT
|
||||
* Y Y
|
||||
* Z RT
|
||||
*
|
||||
* Mode is unused, as it's our menu hotkey for now :)
|
||||
* Also note that libOGC has LT/RT reversed - it's not a typo!
|
||||
*/
|
||||
unsigned int gppadmap[] = { INPUT_A, INPUT_B, INPUT_C,
|
||||
INPUT_X, INPUT_Y, INPUT_Z,
|
||||
INPUT_UP, INPUT_DOWN,
|
||||
INPUT_LEFT, INPUT_RIGHT,
|
||||
INPUT_START, INPUT_MODE
|
||||
};
|
||||
|
||||
unsigned short gcpadmap[] = { PAD_BUTTON_B, PAD_BUTTON_A, PAD_BUTTON_X,
|
||||
PAD_TRIGGER_L, PAD_BUTTON_Y, PAD_TRIGGER_R,
|
||||
PAD_BUTTON_UP, PAD_BUTTON_DOWN,
|
||||
PAD_BUTTON_LEFT, PAD_BUTTON_RIGHT,
|
||||
PAD_BUTTON_START, PAD_TRIGGER_Z
|
||||
};
|
||||
|
||||
static unsigned int DecodeJoy (unsigned short p)
|
||||
{
|
||||
unsigned int J = 0;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 12; i++) if (p & gcpadmap[i]) J |= gppadmap[i];
|
||||
return J;
|
||||
}
|
||||
|
||||
static unsigned int GetAnalog (int Joy)
|
||||
{
|
||||
signed char x, y;
|
||||
unsigned int i = 0;
|
||||
|
||||
x = PAD_StickX (Joy);
|
||||
y = PAD_StickY (Joy);
|
||||
if (x > padcal) i |= INPUT_RIGHT;
|
||||
if (x < -padcal) i |= INPUT_LEFT;
|
||||
if (y > padcal) i |= INPUT_UP;
|
||||
if (y < -padcal) i |= INPUT_DOWN;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*** Inputs Update
|
||||
called before each emulation frame
|
||||
***/
|
||||
static void update_inputs()
|
||||
{
|
||||
int i = 0;
|
||||
int joynum = 0;
|
||||
|
||||
/*** Check for SOFT-RESET combo ***/
|
||||
if ((PAD_ButtonsHeld (0) & PAD_TRIGGER_Z) &&
|
||||
(PAD_ButtonsHeld (0) & PAD_TRIGGER_L))
|
||||
{
|
||||
m68k_pulse_reset ();
|
||||
return;
|
||||
}
|
||||
|
||||
/*** Check for menu combo ***/
|
||||
if (PAD_ButtonsHeld (0) & PAD_TRIGGER_Z)
|
||||
{
|
||||
ConfigRequested = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0; i<MAX_DEVICES; i++)
|
||||
{
|
||||
input.pad[i] = 0;
|
||||
if (input.dev[i] != NO_DEVICE)
|
||||
{
|
||||
input.pad[i] = DecodeJoy(PAD_ButtonsHeld (joynum));
|
||||
input.pad[i] |= GetAnalog (joynum);
|
||||
joynum ++;
|
||||
if (input.dev[i] == DEVICE_LIGHTGUN) lightgun_set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* General Genesis Plus Support
|
||||
*
|
||||
***************************************************************************/
|
||||
void error (char *format, ...)
|
||||
{
|
||||
/* Function does nothing, but must exist! */
|
||||
return;
|
||||
}
|
||||
|
||||
/*** init_machine
|
||||
Initialise the Genesis VM
|
||||
***/
|
||||
static void init_machine ()
|
||||
{
|
||||
/*** Allocate cart_rom here ***/
|
||||
cart_rom = malloc(0x500000 + 32);
|
||||
if ((u32)cart_rom & 0x1f) cart_rom += 32 - ((u32)cart_rom & 0x1f);
|
||||
memset(cart_rom, 0, 0x500000);
|
||||
|
||||
/*** Fetch from ARAM any linked rom ***/
|
||||
if (genromsize) ARAMFetch(cart_rom, (void *)0x8000, genromsize);
|
||||
|
||||
/*** Allocate global work bitmap ***/
|
||||
memset (&bitmap, 0, sizeof (bitmap));
|
||||
bitmap.data = malloc (1024 * 512 * 2);
|
||||
bitmap.width = 1024;
|
||||
bitmap.height = 512;
|
||||
bitmap.depth = 16;
|
||||
bitmap.granularity = 2;
|
||||
bitmap.pitch = (bitmap.width * bitmap.granularity);
|
||||
bitmap.viewport.w = 256;
|
||||
bitmap.viewport.h = 224;
|
||||
bitmap.viewport.x = 0x20;
|
||||
bitmap.viewport.y = 0;
|
||||
bitmap.remap = 1;
|
||||
|
||||
/* default inputs */
|
||||
input.system[0] = SYSTEM_GAMEPAD;
|
||||
input.system[1] = SYSTEM_GAMEPAD;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* M A I N
|
||||
*
|
||||
***************************************************************************/
|
||||
extern void legal ();
|
||||
extern void MainMenu ();
|
||||
extern void reloadrom ();
|
||||
|
||||
int main (int argc, char *argv[])
|
||||
{
|
||||
genromsize = 0;
|
||||
|
||||
/* Initialize GC System */
|
||||
InitGCVideo ();
|
||||
InitGCAudio ();
|
||||
|
||||
init_machine ();
|
||||
legal();
|
||||
|
||||
if (genromsize)
|
||||
{
|
||||
reloadrom ();
|
||||
MainMenu();
|
||||
}
|
||||
else while (!genromsize) MainMenu();
|
||||
|
||||
/* Main emulation loop */
|
||||
frameticker = 0;
|
||||
mftb(&prev);
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* Update all inputs */
|
||||
update_inputs();
|
||||
|
||||
FrameCount++;
|
||||
|
||||
if (vdp_pal) /* PAL 50Hz (use timer) */
|
||||
{
|
||||
mftb(&now);
|
||||
if (tb_diff_msec(&now, &prev) > msBetweenFrames)
|
||||
{
|
||||
memcpy(&prev, &now, sizeof(tb_t));
|
||||
system_frame(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/*** Delay ***/
|
||||
while (tb_diff_msec(&now, &prev) < msBetweenFrames) mftb(&now);
|
||||
memcpy(&prev, &now, sizeof(tb_t) );
|
||||
system_frame(0);
|
||||
RenderedFrameCount++;
|
||||
}
|
||||
}
|
||||
else /* NTSC 60Hz (use vsync) */
|
||||
{
|
||||
while ( frameticker < 1 ) usleep(10);
|
||||
|
||||
/** Simulate a frame **/
|
||||
if (frameticker > 1)
|
||||
{
|
||||
frameticker--;
|
||||
if (frameticker > 5)
|
||||
{
|
||||
system_frame (0);
|
||||
RenderedFrameCount++;
|
||||
frameticker = 1;
|
||||
}
|
||||
else system_frame (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
system_frame (0);
|
||||
RenderedFrameCount++;
|
||||
}
|
||||
}
|
||||
|
||||
frameticker--;
|
||||
|
||||
/** Draw the frame **/
|
||||
update_video ();
|
||||
|
||||
/** add the audio **/
|
||||
update_audio ();
|
||||
|
||||
/** Check render frames **/
|
||||
if ((FrameCount == vdp_rate))
|
||||
{
|
||||
FramesPerSecond = RenderedFrameCount;
|
||||
RenderedFrameCount = 0;
|
||||
FrameCount = 0;
|
||||
}
|
||||
|
||||
if (ConfigRequested)
|
||||
{
|
||||
AUDIO_StopDMA ();
|
||||
IsPlaying = mixbuffer = playbuffer = 0;
|
||||
MainMenu ();
|
||||
ConfigRequested = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
16
source/ngc/osd.h
Normal file
16
source/ngc/osd.h
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
#ifndef _OSD_H_
|
||||
#define _OSD_H_
|
||||
|
||||
#define NGC 1
|
||||
|
||||
#include <gccore.h>
|
||||
#include <ogcsys.h>
|
||||
#include <sdcard.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
extern void error (char *format, ...);
|
||||
|
||||
#endif /* _OSD_H_ */
|
190
source/ngc/unzip.c
Normal file
190
source/ngc/unzip.c
Normal file
@ -0,0 +1,190 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Nintendo Gamecube Zip Support
|
||||
*
|
||||
* Only partial support is included, in that only the first file within the archive
|
||||
* is considered to be a Genesis ROM image.
|
||||
***************************************************************************/
|
||||
#include <zlib.h>
|
||||
#include <sdcard.h>
|
||||
#include "shared.h"
|
||||
#include "dvd.h"
|
||||
#include "font.h"
|
||||
|
||||
extern sd_file *filehandle;
|
||||
extern u8 UseSDCARD;
|
||||
|
||||
/*
|
||||
* PKWare Zip Header - adopted into zip standard
|
||||
*/
|
||||
#define PKZIPID 0x504b0304
|
||||
#define MAXROM 0x500000
|
||||
#define ZIPCHUNK 2048
|
||||
|
||||
/*
|
||||
* Zip file header definition
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
unsigned int zipid __attribute__ ((__packed__)); // 0x04034b50
|
||||
unsigned short zipversion __attribute__ ((__packed__));
|
||||
unsigned short zipflags __attribute__ ((__packed__));
|
||||
unsigned short compressionMethod __attribute__ ((__packed__));
|
||||
unsigned short lastmodtime __attribute__ ((__packed__));
|
||||
unsigned short lastmoddate __attribute__ ((__packed__));
|
||||
unsigned int crc32 __attribute__ ((__packed__));
|
||||
unsigned int compressedSize __attribute__ ((__packed__));
|
||||
unsigned int uncompressedSize __attribute__ ((__packed__));
|
||||
unsigned short filenameLength __attribute__ ((__packed__));
|
||||
unsigned short extraDataLength __attribute__ ((__packed__));
|
||||
} PKZIPHEADER;
|
||||
|
||||
/*
|
||||
* Zip files are stored little endian
|
||||
* Support functions for short and int types
|
||||
*/
|
||||
static inline u32 FLIP32 (u32 b)
|
||||
{
|
||||
unsigned int c;
|
||||
c = (b & 0xff000000) >> 24;
|
||||
c |= (b & 0xff0000) >> 8;
|
||||
c |= (b & 0xff00) << 8;
|
||||
c |= (b & 0xff) << 24;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline u16 FLIP16 (u16 b)
|
||||
{
|
||||
u16 c;
|
||||
c = (b & 0xff00) >> 8;
|
||||
c |= (b & 0xff) << 8;
|
||||
return c;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* IsZipFile
|
||||
*
|
||||
* Returns TRUE when PKZIPID is first four characters of buffer
|
||||
****************************************************************************/
|
||||
int IsZipFile (char *buffer)
|
||||
{
|
||||
unsigned int *check;
|
||||
check = (unsigned int *) buffer;
|
||||
if (check[0] == PKZIPID) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* UnZipBuffer
|
||||
*
|
||||
* It should be noted that there is a limit of 5MB total size for any ROM
|
||||
******************************************************************************/
|
||||
int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length)
|
||||
{
|
||||
PKZIPHEADER pkzip;
|
||||
int zipoffset = 0;
|
||||
int zipchunk = 0;
|
||||
char out[ZIPCHUNK];
|
||||
z_stream zs;
|
||||
int res;
|
||||
int bufferoffset = 0;
|
||||
int have = 0;
|
||||
char readbuffer[2048];
|
||||
char msg[128];
|
||||
|
||||
/*** Read Zip Header ***/
|
||||
if ( UseSDCARD )
|
||||
{
|
||||
SDCARD_SeekFile(filehandle, 0, SDCARD_SEEK_SET);
|
||||
SDCARD_ReadFile(filehandle, &readbuffer, 2048);
|
||||
}
|
||||
else dvd_read (&readbuffer, 2048, discoffset);
|
||||
|
||||
/*** Copy PKZip header to local, used as info ***/
|
||||
memcpy (&pkzip, &readbuffer, sizeof (PKZIPHEADER));
|
||||
|
||||
sprintf (msg, "Unzipping %d bytes ... Wait", FLIP32 (pkzip.uncompressedSize));
|
||||
ShowAction (msg);
|
||||
|
||||
/*** Prepare the zip stream ***/
|
||||
memset (&zs, 0, sizeof (z_stream));
|
||||
zs.zalloc = Z_NULL;
|
||||
zs.zfree = Z_NULL;
|
||||
zs.opaque = Z_NULL;
|
||||
zs.avail_in = 0;
|
||||
zs.next_in = Z_NULL;
|
||||
res = inflateInit2 (&zs, -MAX_WBITS);
|
||||
|
||||
if (res != Z_OK) return 0;
|
||||
|
||||
/*** Set ZipChunk for first pass ***/
|
||||
zipoffset = (sizeof (PKZIPHEADER) + FLIP16 (pkzip.filenameLength) + FLIP16 (pkzip.extraDataLength));
|
||||
zipchunk = ZIPCHUNK - zipoffset;
|
||||
|
||||
/*** Now do it! ***/
|
||||
do
|
||||
{
|
||||
zs.avail_in = zipchunk;
|
||||
zs.next_in = (Bytef *) & readbuffer[zipoffset];
|
||||
|
||||
/*** Now inflate until input buffer is exhausted ***/
|
||||
do
|
||||
{
|
||||
zs.avail_out = ZIPCHUNK;
|
||||
zs.next_out = (Bytef *) & out;
|
||||
res = inflate (&zs, Z_NO_FLUSH);
|
||||
|
||||
if (res == Z_MEM_ERROR)
|
||||
{
|
||||
inflateEnd (&zs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
have = ZIPCHUNK - zs.avail_out;
|
||||
if (have)
|
||||
{
|
||||
/*** Copy to normal block buffer ***/
|
||||
memcpy (&outbuffer[bufferoffset], &out, have);
|
||||
bufferoffset += have;
|
||||
}
|
||||
}
|
||||
while (zs.avail_out == 0);
|
||||
|
||||
/*** Readup the next 2k block ***/
|
||||
zipoffset = 0;
|
||||
zipchunk = ZIPCHUNK;
|
||||
discoffset += 2048;
|
||||
|
||||
if (UseSDCARD) SDCARD_ReadFile(filehandle, &readbuffer, 2048);
|
||||
else dvd_read (&readbuffer, 2048, discoffset);
|
||||
}
|
||||
while (res != Z_STREAM_END);
|
||||
|
||||
inflateEnd (&zs);
|
||||
|
||||
if ( UseSDCARD ) SDCARD_CloseFile(filehandle);
|
||||
|
||||
if (res == Z_STREAM_END)
|
||||
{
|
||||
if (FLIP32 (pkzip.uncompressedSize) == (u32) bufferoffset) return bufferoffset;
|
||||
else return FLIP32 (pkzip.uncompressedSize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
26
source/ngc/unzip.h
Normal file
26
source/ngc/unzip.h
Normal file
@ -0,0 +1,26 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Nintendo Gamecube Zip Support
|
||||
*
|
||||
* Only partial support is included, in that only the first file within the archive
|
||||
* is considered to be a ROM image.
|
||||
***************************************************************************/
|
||||
|
||||
extern int IsZipFile (char *buffer);
|
||||
int UnZipBuffer (unsigned char *outbuffer, u64 discoffset, int length);
|
1536
source/render.c
Normal file
1536
source/render.c
Normal file
File diff suppressed because it is too large
Load Diff
53
source/render.h
Normal file
53
source/render.h
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
#ifndef _RENDER_H_
|
||||
#define _RENDER_H_
|
||||
|
||||
|
||||
/* Look-up pixel table information */
|
||||
#define LUT_MAX (5)
|
||||
#define LUT_SIZE (0x10000)
|
||||
|
||||
/* Clip structure */
|
||||
typedef struct
|
||||
{
|
||||
uint8 left;
|
||||
uint8 right;
|
||||
uint8 enable;
|
||||
}clip_t;
|
||||
|
||||
/* Function prototypes */
|
||||
int render_init(void);
|
||||
void render_reset(void);
|
||||
void render_shutdown(void);
|
||||
void render_line(int line);
|
||||
void render_obj(int line, uint8 *buf, uint8 *table);
|
||||
void render_obj_im2(int line, uint8 *buf, uint8 *table);
|
||||
void render_ntw(int line, uint8 *buf);
|
||||
void render_ntw_im2(int line, uint8 *buf);
|
||||
void render_ntx(int which, int line, uint8 *buf);
|
||||
void render_ntx_im2(int which, int line, uint8 *buf);
|
||||
void render_ntx_vs(int which, int line, uint8 *buf);
|
||||
void update_bg_pattern_cache(void);
|
||||
void get_hscroll(int line, int shift, uint16 *scroll);
|
||||
void window_clip(int line);
|
||||
int make_lut_bg(int bx, int ax);
|
||||
int make_lut_obj(int bx, int sx);
|
||||
int make_lut_bg_ste(int bx, int ax);
|
||||
int make_lut_obj_ste(int bx, int sx);
|
||||
int make_lut_bgobj_ste(int bx, int sx);
|
||||
void remap_8(uint8 *src, uint8 *dst, uint8 *table, int length);
|
||||
void remap_16(uint8 *src, uint16 *dst, uint16 *table, int length);
|
||||
void remap_32(uint8 *src, uint32 *dst, uint32 *table, int length);
|
||||
void merge(uint8 *srca, uint8 *srcb, uint8 *dst, uint8 *table, int width);
|
||||
void color_update_8(int index, uint16 data);
|
||||
void color_update_15(int index, uint16 data);
|
||||
void color_update_16(int index, uint16 data);
|
||||
void color_update_32(int index, uint16 data);
|
||||
void make_name_lut(void);
|
||||
void parse_satb(int line);
|
||||
|
||||
/* global variables */
|
||||
extern uint8 object_index_count;
|
||||
|
||||
#endif /* _RENDER_H_ */
|
||||
|
43
source/shared.h
Normal file
43
source/shared.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef _SHARED_H_
|
||||
#define _SHARED_H_
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <zlib.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "macros.h"
|
||||
#include "m68k.h"
|
||||
#include "z80.h"
|
||||
#include "genesis.h"
|
||||
#include "vdp.h"
|
||||
#include "render.h"
|
||||
#include "mem68k.h"
|
||||
#include "memz80.h"
|
||||
#include "membnk.h"
|
||||
#include "memvdp.h"
|
||||
#include "system.h"
|
||||
#ifndef NGC
|
||||
#include "unzip.h"
|
||||
#include "fileio.h"
|
||||
#include "loadrom.h"
|
||||
#endif
|
||||
#include "io.h"
|
||||
#include "input.h"
|
||||
#include "sound.h"
|
||||
#include "fm.h"
|
||||
#include "sn76496.h"
|
||||
#include "osd.h"
|
||||
#include "state.h"
|
||||
#include "sram.h"
|
||||
#include "eeprom.h"
|
||||
#include "ssf2tnc.h"
|
||||
#include "sn76489.h"
|
||||
#include "ym2612.h"
|
||||
|
||||
extern uint8 FM_GENS;
|
||||
extern uint8 PSG_MAME;
|
||||
|
||||
#endif /* _SHARED_H_ */
|
||||
|
4745
source/sound/fm.c
Normal file
4745
source/sound/fm.c
Normal file
File diff suppressed because it is too large
Load Diff
205
source/sound/fm.h
Normal file
205
source/sound/fm.h
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
File: fm.h -- header file for software emulation for FM sound generator
|
||||
|
||||
*/
|
||||
#ifndef _H_FM_FM_
|
||||
#define _H_FM_FM_
|
||||
#define HAS_YM2612 1
|
||||
#include "shared.h"
|
||||
/* --- select emulation chips --- */
|
||||
#define BUILD_YM2203 (HAS_YM2203) /* build YM2203(OPN) emulator */
|
||||
#define BUILD_YM2608 (HAS_YM2608) /* build YM2608(OPNA) emulator */
|
||||
#define BUILD_YM2610 (HAS_YM2610) /* build YM2610(OPNB) emulator */
|
||||
#define BUILD_YM2610B (HAS_YM2610B) /* build YM2610B(OPNB?)emulator */
|
||||
#define BUILD_YM2612 (HAS_YM2612 || HAS_YM3438) /* build YM2612(OPN2) emulator */
|
||||
|
||||
/* select bit size of output : 8 or 16 */
|
||||
#define FM_SAMPLE_BITS 16
|
||||
|
||||
/* select timer system internal or external */
|
||||
#define FM_INTERNAL_TIMER 0
|
||||
|
||||
/* --- speedup optimize --- */
|
||||
/* busy flag enulation , The definition of FM_GET_TIME_NOW() is necessary. */
|
||||
#define FM_BUSY_FLAG_SUPPORT 0
|
||||
|
||||
/* --- external SSG(YM2149/AY-3-8910)emulator interface port */
|
||||
/* used by YM2203,YM2608,and YM2610 */
|
||||
struct ssg_callbacks
|
||||
{
|
||||
void (*set_clock)(void *param, int clock);
|
||||
void (*write)(void *param, int address, int data);
|
||||
int (*read)(void *param);
|
||||
void (*reset)(void *param);
|
||||
};
|
||||
|
||||
/* --- external callback funstions for realtime update --- */
|
||||
|
||||
/* for busy flag emulation , function FM_GET_TIME_NOW() should */
|
||||
/* return present time in seconds with "double" precision */
|
||||
/* in timer.c */
|
||||
#define FM_GET_TIME_NOW() timer_get_time()
|
||||
|
||||
#if BUILD_YM2203
|
||||
/* in 2203intf.c */
|
||||
void YM2203UpdateRequest(void *param);
|
||||
#define YM2203UpdateReq(chip) YM2203UpdateRequest(chip)
|
||||
#endif
|
||||
#if BUILD_YM2608
|
||||
/* in 2608intf.c */
|
||||
void YM2608UpdateRequest(void *param);
|
||||
#define YM2608UpdateReq(chip) YM2608UpdateRequest(chip);
|
||||
#endif
|
||||
#if BUILD_YM2610
|
||||
/* in 2610intf.c */
|
||||
void YM2610UpdateRequest(void *param);
|
||||
#define YM2610UpdateReq(chip) YM2610UpdateRequest(chip);
|
||||
#endif
|
||||
#if BUILD_YM2612
|
||||
/* in 2612intf.c */
|
||||
void YM2612UpdateRequest(void *param);
|
||||
#define YM2612UpdateReq(chip) YM2612UpdateRequest(chip);
|
||||
#endif
|
||||
|
||||
/* compiler dependence */
|
||||
#if 0
|
||||
#ifndef OSD_CPU_H
|
||||
#define OSD_CPU_H
|
||||
typedef unsigned char UINT8; /* unsigned 8bit */
|
||||
typedef unsigned short UINT16; /* unsigned 16bit */
|
||||
typedef unsigned int UINT32; /* unsigned 32bit */
|
||||
typedef signed char INT8; /* signed 8bit */
|
||||
typedef signed short INT16; /* signed 16bit */
|
||||
typedef signed int INT32; /* signed 32bit */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef INLINE
|
||||
#define INLINE static __inline__
|
||||
#endif
|
||||
|
||||
|
||||
typedef INT16 FMSAMPLE;
|
||||
/*
|
||||
#if (FM_SAMPLE_BITS==16)
|
||||
typedef INT16 FMSAMPLE;
|
||||
#endif
|
||||
#if (FM_SAMPLE_BITS==8)
|
||||
typedef unsigned char FMSAMPLE;
|
||||
#endif
|
||||
*/
|
||||
|
||||
typedef void (*FM_TIMERHANDLER)(void *param,int c,int cnt,double stepTime);
|
||||
typedef void (*FM_IRQHANDLER)(void *param,int irq);
|
||||
/* FM_TIMERHANDLER : Stop or Start timer */
|
||||
/* int n = chip number */
|
||||
/* int c = Channel 0=TimerA,1=TimerB */
|
||||
/* int count = timer count (0=stop) */
|
||||
/* doube stepTime = step time of one count (sec.)*/
|
||||
|
||||
/* FM_IRQHHANDLER : IRQ level changing sense */
|
||||
/* int n = chip number */
|
||||
/* int irq = IRQ level 0=OFF,1=ON */
|
||||
|
||||
#if BUILD_YM2203
|
||||
/* -------------------- YM2203(OPN) Interface -------------------- */
|
||||
|
||||
/*
|
||||
** Initialize YM2203 emulator(s).
|
||||
**
|
||||
** 'num' is the number of virtual YM2203's to allocate
|
||||
** 'baseclock'
|
||||
** 'rate' is sampling rate
|
||||
** 'TimerHandler' timer callback handler when timer start and clear
|
||||
** 'IRQHandler' IRQ callback handler when changed IRQ level
|
||||
** return 0 = success
|
||||
*/
|
||||
void * YM2203Init(void *param, int index, int baseclock, int rate,
|
||||
FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg);
|
||||
|
||||
/*
|
||||
** shutdown the YM2203 emulators
|
||||
*/
|
||||
void YM2203Shutdown(void *chip);
|
||||
|
||||
/*
|
||||
** reset all chip registers for YM2203 number 'num'
|
||||
*/
|
||||
void YM2203ResetChip(void *chip);
|
||||
|
||||
/*
|
||||
** update one of chip
|
||||
*/
|
||||
void YM2203UpdateOne(void *chip, FMSAMPLE *buffer, int length);
|
||||
|
||||
/*
|
||||
** Write
|
||||
** return : InterruptLevel
|
||||
*/
|
||||
int YM2203Write(void *chip,int a,unsigned char v);
|
||||
|
||||
/*
|
||||
** Read
|
||||
** return : InterruptLevel
|
||||
*/
|
||||
unsigned char YM2203Read(void *chip,int a);
|
||||
|
||||
/*
|
||||
** Timer OverFlow
|
||||
*/
|
||||
int YM2203TimerOver(void *chip, int c);
|
||||
|
||||
/*
|
||||
** State Save
|
||||
*/
|
||||
void YM2203Postload(void *chip);
|
||||
#endif /* BUILD_YM2203 */
|
||||
|
||||
#if BUILD_YM2608
|
||||
/* -------------------- YM2608(OPNA) Interface -------------------- */
|
||||
void * YM2608Init(void *param, int index, int baseclock, int rate,
|
||||
void *pcmroma,int pcmsizea,
|
||||
FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg);
|
||||
void YM2608Shutdown(void *chip);
|
||||
void YM2608ResetChip(void *chip);
|
||||
void YM2608UpdateOne(void *chip, FMSAMPLE **buffer, int length);
|
||||
|
||||
int YM2608Write(void *chip, int a,unsigned char v);
|
||||
unsigned char YM2608Read(void *chip,int a);
|
||||
int YM2608TimerOver(void *chip, int c );
|
||||
void YM2608Postload(void *chip);
|
||||
#endif /* BUILD_YM2608 */
|
||||
|
||||
#if (BUILD_YM2610||BUILD_YM2610B)
|
||||
/* -------------------- YM2610(OPNB) Interface -------------------- */
|
||||
void * YM2610Init(void *param, int index, int baseclock, int rate,
|
||||
void *pcmroma,int pcmasize,void *pcmromb,int pcmbsize,
|
||||
FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler, const struct ssg_callbacks *ssg);
|
||||
void YM2610Shutdown(void *chip);
|
||||
void YM2610ResetChip(void *chip);
|
||||
void YM2610UpdateOne(void *chip, FMSAMPLE **buffer, int length);
|
||||
#if BUILD_YM2610B
|
||||
void YM2610BUpdateOne(void *chip, FMSAMPLE **buffer, int length);
|
||||
#endif
|
||||
|
||||
int YM2610Write(void *chip, int a,unsigned char v);
|
||||
unsigned char YM2610Read(void *chip,int a);
|
||||
int YM2610TimerOver(void *chip, int c );
|
||||
void YM2610Postload(void *chip);
|
||||
#endif /* BUILD_YM2610 */
|
||||
|
||||
#if BUILD_YM2612
|
||||
void * YM2612Init(void *param, int index, int baseclock, int rate,
|
||||
FM_TIMERHANDLER TimerHandler,FM_IRQHANDLER IRQHandler);
|
||||
void YM2612Shutdown(void *chip);
|
||||
void YM2612ResetChip(void *chip);
|
||||
void YM2612UpdateOne(void *chip, FMSAMPLE **buffer, int length);
|
||||
|
||||
int YM2612Write(void *chip, int a,unsigned char v);
|
||||
unsigned char YM2612Read(void *chip,int a);
|
||||
int YM2612TimerOver(void *chip, int c );
|
||||
void YM2612Postload(void *chip);
|
||||
#endif /* BUILD_YM2612 */
|
||||
|
||||
|
||||
#endif /* _H_FM_FM_ */
|
290
source/sound/sn76489.c
Normal file
290
source/sound/sn76489.c
Normal file
@ -0,0 +1,290 @@
|
||||
/*
|
||||
SN76489 emulation
|
||||
by Maxim in 2001 and 2002
|
||||
converted from my original Delphi implementation
|
||||
|
||||
I'm a C newbie so I'm sure there are loads of stupid things
|
||||
in here which I'll come back to some day and redo
|
||||
|
||||
Includes:
|
||||
- Super-high quality tone channel "oversampling" by calculating fractional positions on transitions
|
||||
- Noise output pattern reverse engineered from actual SMS output
|
||||
- Volume levels taken from actual SMS output
|
||||
|
||||
07/08/04 Charles MacDonald
|
||||
Modified for use with SMS Plus:
|
||||
- Added support for multiple PSG chips.
|
||||
- Added reset/config/update routines.
|
||||
- Added context management routines.
|
||||
- Removed SN76489_GetValues().
|
||||
- Removed some unused variables.
|
||||
|
||||
25/04/07 Eke-Eke
|
||||
Modified for use with GenesisPlus Gamecube's port:
|
||||
- made SN76489_Update outputs 16bits mono samples
|
||||
- replaced volume table with VGM plugin's one
|
||||
*/
|
||||
|
||||
#include "sn76489.h"
|
||||
#include <float.h> // for FLT_MIN
|
||||
#include <string.h> // for memcpy
|
||||
|
||||
#define NoiseInitialState 0x8000 /* Initial state of shift register */
|
||||
#define PSG_CUTOFF 0x6 /* Value below which PSG does not output */
|
||||
|
||||
static const int PSGVolumeValues[2][16] = {
|
||||
/* These values are taken from a real SMS2's output */
|
||||
{892,892,892,760,623,497,404,323,257,198,159,123,96,75,60,0}, /* I can't remember why 892... :P some scaling I did at some point */
|
||||
/* these values are true volumes for 2dB drops at each step (multiply previous by 10^-0.1), normalised at 760 */
|
||||
{1516,1205,957,760,603,479,381,303,240,191,152,120,96,76,60,0}
|
||||
};
|
||||
|
||||
static SN76489_Context SN76489[MAX_SN76489];
|
||||
|
||||
void SN76489_Init(int which, int PSGClockValue, int SamplingRate)
|
||||
{
|
||||
SN76489_Context *p = &SN76489[which];
|
||||
p->dClock=(float)PSGClockValue/16/SamplingRate;
|
||||
SN76489_Config(which, MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, 1);
|
||||
SN76489_Reset(which);
|
||||
}
|
||||
|
||||
void SN76489_Reset(int which)
|
||||
{
|
||||
SN76489_Context *p = &SN76489[which];
|
||||
int i;
|
||||
|
||||
p->PSGStereo = 0xFF;
|
||||
|
||||
for(i = 0; i <= 3; i++)
|
||||
{
|
||||
/* Initialise PSG state */
|
||||
p->Registers[2*i] = 1; /* tone freq=1 */
|
||||
p->Registers[2*i+1] = 0xf; /* vol=off */
|
||||
p->NoiseFreq = 0x10;
|
||||
|
||||
/* Set counters to 0 */
|
||||
p->ToneFreqVals[i] = 0;
|
||||
|
||||
/* Set flip-flops to 1 */
|
||||
p->ToneFreqPos[i] = 1;
|
||||
|
||||
/* Set intermediate positions to do-not-use value */
|
||||
p->IntermediatePos[i] = FLT_MIN;
|
||||
|
||||
/* Set panning to centre */
|
||||
p->panning[0]=127;
|
||||
}
|
||||
|
||||
p->LatchedRegister=0;
|
||||
|
||||
/* Initialise noise generator */
|
||||
p->NoiseShiftRegister=NoiseInitialState;
|
||||
|
||||
/* Zero clock */
|
||||
p->Clock=0;
|
||||
|
||||
}
|
||||
|
||||
void SN76489_Shutdown(void)
|
||||
{
|
||||
}
|
||||
|
||||
void SN76489_Config(int which, int mute, int volume, int feedback, int sr_width, int boost_noise)
|
||||
{
|
||||
SN76489_Context *p = &SN76489[which];
|
||||
|
||||
p->Mute = mute;
|
||||
p->VolumeArray = volume;
|
||||
p->WhiteNoiseFeedback = feedback;
|
||||
p->SRWidth = sr_width;
|
||||
p->BoostNoise = boost_noise;
|
||||
}
|
||||
|
||||
void SN76489_SetContext(int which, uint8 *data)
|
||||
{
|
||||
memcpy(&SN76489[which], data, sizeof(SN76489_Context));
|
||||
}
|
||||
|
||||
void SN76489_GetContext(int which, uint8 *data)
|
||||
{
|
||||
memcpy(data, &SN76489[which], sizeof(SN76489_Context));
|
||||
}
|
||||
|
||||
uint8 *SN76489_GetContextPtr(int which)
|
||||
{
|
||||
return (uint8 *)&SN76489[which];
|
||||
}
|
||||
|
||||
int SN76489_GetContextSize(void)
|
||||
{
|
||||
return sizeof(SN76489_Context);
|
||||
}
|
||||
|
||||
void SN76489_Write(int which, int data)
|
||||
{
|
||||
SN76489_Context *p = &SN76489[which];
|
||||
|
||||
if (data&0x80) {
|
||||
/* Latch/data byte %1 cc t dddd */
|
||||
p->LatchedRegister=((data>>4)&0x07);
|
||||
p->Registers[p->LatchedRegister]=
|
||||
(p->Registers[p->LatchedRegister] & 0x3f0) /* zero low 4 bits */
|
||||
| (data&0xf); /* and replace with data */
|
||||
} else {
|
||||
/* Data byte %0 - dddddd */
|
||||
if (!(p->LatchedRegister%2)&&(p->LatchedRegister<5))
|
||||
/* Tone register */
|
||||
p->Registers[p->LatchedRegister]=
|
||||
(p->Registers[p->LatchedRegister] & 0x00f) /* zero high 6 bits */
|
||||
| ((data&0x3f)<<4); /* and replace with data */
|
||||
else
|
||||
/* Other register */
|
||||
p->Registers[p->LatchedRegister]=data&0x0f; /* Replace with data */
|
||||
}
|
||||
switch (p->LatchedRegister) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4: /* Tone channels */
|
||||
if (p->Registers[p->LatchedRegister]==0) p->Registers[p->LatchedRegister]=1; /* Zero frequency changed to 1 to avoid div/0 */
|
||||
break;
|
||||
case 6: /* Noise */
|
||||
p->NoiseShiftRegister=NoiseInitialState; /* reset shift register */
|
||||
p->NoiseFreq=0x10<<(p->Registers[6]&0x3); /* set noise signal generator frequency */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SN76489_GGStereoWrite(int which, int data)
|
||||
{
|
||||
SN76489_Context *p = &SN76489[which];
|
||||
p->PSGStereo=data;
|
||||
}
|
||||
|
||||
void SN76489_Update(int which, INT16 *buffer, int length)
|
||||
{
|
||||
SN76489_Context *p = &SN76489[which];
|
||||
int i, j;
|
||||
|
||||
for(j = 0; j < length; j++)
|
||||
{
|
||||
for (i=0;i<=2;++i)
|
||||
if (p->IntermediatePos[i]!=FLT_MIN)
|
||||
p->Channels[i]=(short)((p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->IntermediatePos[i]);
|
||||
else
|
||||
p->Channels[i]=(p->Mute >> i & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[2*i+1]]*p->ToneFreqPos[i];
|
||||
|
||||
p->Channels[3]=(short)((p->Mute >> 3 & 0x1)*PSGVolumeValues[p->VolumeArray][p->Registers[7]]*(p->NoiseShiftRegister & 0x1));
|
||||
|
||||
if (p->BoostNoise) p->Channels[3]<<=1; /* double noise volume */
|
||||
|
||||
buffer[j] =0;
|
||||
for (i=0;i<=3;++i) buffer[j] += p->Channels[i];
|
||||
|
||||
p->Clock+=p->dClock;
|
||||
p->NumClocksForSample=(int)p->Clock; /* truncates */
|
||||
p->Clock-=p->NumClocksForSample; /* remove integer part */
|
||||
/* Looks nicer in Delphi... */
|
||||
/* Clock:=Clock+p->dClock; */
|
||||
/* NumClocksForSample:=Trunc(Clock); */
|
||||
/* Clock:=Frac(Clock); */
|
||||
|
||||
/* Decrement tone channel counters */
|
||||
for (i=0;i<=2;++i)
|
||||
p->ToneFreqVals[i]-=p->NumClocksForSample;
|
||||
|
||||
/* Noise channel: match to tone2 or decrement its counter */
|
||||
if (p->NoiseFreq==0x80) p->ToneFreqVals[3]=p->ToneFreqVals[2];
|
||||
else p->ToneFreqVals[3]-=p->NumClocksForSample;
|
||||
|
||||
/* Tone channels: */
|
||||
for (i=0;i<=2;++i) {
|
||||
if (p->ToneFreqVals[i]<=0) { /* If it gets below 0... */
|
||||
if (p->Registers[i*2]>PSG_CUTOFF) {
|
||||
/* Calculate how much of the sample is + and how much is - */
|
||||
/* Go to floating point and include the clock fraction for extreme accuracy :D */
|
||||
/* Store as long int, maybe it's faster? I'm not very good at this */
|
||||
p->IntermediatePos[i]=(p->NumClocksForSample-p->Clock+2*p->ToneFreqVals[i])*p->ToneFreqPos[i]/(p->NumClocksForSample+p->Clock);
|
||||
p->ToneFreqPos[i]=-p->ToneFreqPos[i]; /* Flip the flip-flop */
|
||||
} else {
|
||||
p->ToneFreqPos[i]=1; /* stuck value */
|
||||
p->IntermediatePos[i]=FLT_MIN;
|
||||
}
|
||||
p->ToneFreqVals[i]+=p->Registers[i*2]*(p->NumClocksForSample/p->Registers[i*2]+1);
|
||||
} else p->IntermediatePos[i]=FLT_MIN;
|
||||
}
|
||||
|
||||
/* Noise channel */
|
||||
if (p->ToneFreqVals[3]<=0) { /* If it gets below 0... */
|
||||
p->ToneFreqPos[3]=-p->ToneFreqPos[3]; /* Flip the flip-flop */
|
||||
if (p->NoiseFreq!=0x80) /* If not matching tone2, decrement counter */
|
||||
p->ToneFreqVals[3]+=p->NoiseFreq*(p->NumClocksForSample/p->NoiseFreq+1);
|
||||
if (p->ToneFreqPos[3]==1) { /* Only once per cycle... */
|
||||
int Feedback;
|
||||
if (p->Registers[6]&0x4) { /* White noise */
|
||||
/* Calculate parity of fed-back bits for feedback */
|
||||
switch (p->WhiteNoiseFeedback) {
|
||||
/* Do some optimised calculations for common (known) feedback values */
|
||||
case 0x0003: /* SC-3000, BBC %00000011 */
|
||||
case 0x0009: /* SMS, GG, MD %00001001 */
|
||||
/* If two bits fed back, I can do Feedback=(nsr & fb) && (nsr & fb ^ fb) */
|
||||
/* since that's (one or more bits set) && (not all bits set) */
|
||||
Feedback=((p->NoiseShiftRegister&p->WhiteNoiseFeedback) && ((p->NoiseShiftRegister&p->WhiteNoiseFeedback)^p->WhiteNoiseFeedback));
|
||||
break;
|
||||
default: /* Default handler for all other feedback values */
|
||||
Feedback=p->NoiseShiftRegister&p->WhiteNoiseFeedback;
|
||||
Feedback^=Feedback>>8;
|
||||
Feedback^=Feedback>>4;
|
||||
Feedback^=Feedback>>2;
|
||||
Feedback^=Feedback>>1;
|
||||
Feedback&=1;
|
||||
break;
|
||||
}
|
||||
} else /* Periodic noise */
|
||||
Feedback=p->NoiseShiftRegister&1;
|
||||
|
||||
p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | (Feedback << (p->SRWidth-1));
|
||||
|
||||
/* Original code: */
|
||||
/* p->NoiseShiftRegister=(p->NoiseShiftRegister>>1) | ((p->Registers[6]&0x4?((p->NoiseShiftRegister&0x9) && (p->NoiseShiftRegister&0x9^0x9)):p->NoiseShiftRegister&1)<<15); */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*void SN76489_UpdateOne(int which, int *l, int *r)
|
||||
{
|
||||
INT16 tl,tr;
|
||||
INT16 *buff[2]={&tl,&tr};
|
||||
SN76489_Update(which,buff,1);
|
||||
*l=tl;
|
||||
*r=tr;
|
||||
}*/
|
||||
|
||||
int SN76489_GetMute(int which)
|
||||
{
|
||||
return SN76489[which].Mute;
|
||||
}
|
||||
|
||||
void SN76489_SetMute(int which, int val)
|
||||
{
|
||||
SN76489[which].Mute=val;
|
||||
}
|
||||
|
||||
int SN76489_GetVolType(int which)
|
||||
{
|
||||
return SN76489[which].VolumeArray;
|
||||
}
|
||||
|
||||
void SN76489_SetVolType(int which, int val)
|
||||
{
|
||||
SN76489[which].VolumeArray=val;
|
||||
}
|
||||
|
||||
void SN76489_SetPanning(int which, int ch0, int ch1, int ch2, int ch3)
|
||||
{
|
||||
SN76489[which].panning[0]=ch0;
|
||||
SN76489[which].panning[1]=ch1;
|
||||
SN76489[which].panning[2]=ch2;
|
||||
SN76489[which].panning[3]=ch3;
|
||||
}
|
91
source/sound/sn76489.h
Normal file
91
source/sound/sn76489.h
Normal file
@ -0,0 +1,91 @@
|
||||
|
||||
#ifndef _SN76489_H_
|
||||
#define _SN76489_H_
|
||||
|
||||
#define MAX_SN76489 4
|
||||
#include "shared.h"
|
||||
/*
|
||||
More testing is needed to find and confirm feedback patterns for
|
||||
SN76489 variants and compatible chips.
|
||||
*/
|
||||
enum feedback_patterns {
|
||||
FB_BBCMICRO = 0x8005, /* Texas Instruments TMS SN76489N (original) from BBC Micro computer */
|
||||
FB_SC3000 = 0x0006, /* Texas Instruments TMS SN76489AN (rev. A) from SC-3000H computer */
|
||||
FB_SEGAVDP = 0x0009, /* SN76489 clone in Sega's VDP chips (315-5124, 315-5246, 315-5313, Game Gear) */
|
||||
};
|
||||
|
||||
enum sr_widths {
|
||||
SRW_SC3000BBCMICRO = 15,
|
||||
SRW_SEGAVDP = 16
|
||||
};
|
||||
|
||||
enum volume_modes {
|
||||
VOL_TRUNC = 0, /* Volume levels 13-15 are identical */
|
||||
VOL_FULL = 1, /* Volume levels 13-15 are unique */
|
||||
};
|
||||
|
||||
enum mute_values {
|
||||
MUTE_ALLOFF = 0, /* All channels muted */
|
||||
MUTE_TONE1 = 1, /* Tone 1 mute control */
|
||||
MUTE_TONE2 = 2, /* Tone 2 mute control */
|
||||
MUTE_TONE3 = 4, /* Tone 3 mute control */
|
||||
MUTE_NOISE = 8, /* Noise mute control */
|
||||
MUTE_ALLON = 15, /* All channels enabled */
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Mute; // per-channel muting
|
||||
int VolumeArray;
|
||||
int BoostNoise; // double noise volume when non-zero
|
||||
|
||||
/* Variables */
|
||||
float Clock;
|
||||
float dClock;
|
||||
int PSGStereo;
|
||||
int NumClocksForSample;
|
||||
int WhiteNoiseFeedback;
|
||||
int SRWidth;
|
||||
|
||||
/* PSG registers: */
|
||||
int Registers[8]; /* Tone, vol x4 */
|
||||
int LatchedRegister;
|
||||
int NoiseShiftRegister;
|
||||
int NoiseFreq; /* Noise channel signal generator frequency */
|
||||
|
||||
/* Output calculation variables */
|
||||
int ToneFreqVals[4]; /* Frequency register values (counters) */
|
||||
int ToneFreqPos[4]; /* Frequency channel flip-flops */
|
||||
int Channels[4]; /* Value of each channel, before stereo is applied */
|
||||
float IntermediatePos[4]; /* intermediate values used at boundaries between + and - (does not need double accuracy)*/
|
||||
|
||||
int panning[4]; /* fake stereo - 0..127..254 */
|
||||
|
||||
} SN76489_Context;
|
||||
|
||||
/* Function prototypes */
|
||||
void SN76489_Init(int which, int PSGClockValue, int SamplingRate);
|
||||
void SN76489_Reset(int which);
|
||||
void SN76489_Shutdown(void);
|
||||
void SN76489_Config(int which, int mute, int volume, int feedback, int sw_width, int boost_noise);
|
||||
void SN76489_SetContext(int which, uint8 *data);
|
||||
void SN76489_GetContext(int which, uint8 *data);
|
||||
uint8 *SN76489_GetContextPtr(int which);
|
||||
int SN76489_GetContextSize(void);
|
||||
void SN76489_Write(int which, int data);
|
||||
/*void SN76489_GGStereoWrite(int which, int data);*/
|
||||
void SN76489_Update(int which, INT16 *buffer, int length);
|
||||
|
||||
/* Non-standard getters and setters */
|
||||
int SN76489_GetMute(int which);
|
||||
void SN76489_SetMute(int which, int val);
|
||||
int SN76489_GetVolType(int which);
|
||||
void SN76489_SetVolType(int which, int val);
|
||||
|
||||
void SN76489_SetPanning(int which, int ch0, int ch1, int ch2, int ch3);
|
||||
|
||||
/* and a non-standard data getter */
|
||||
/*void SN76489_UpdateOne(int which, int *l, int *r);*/
|
||||
|
||||
#endif /* _SN76489_H_ */
|
||||
|
311
source/sound/sn76496.c
Normal file
311
source/sound/sn76496.c
Normal file
@ -0,0 +1,311 @@
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
#define MAX_OUTPUT 0x7fff
|
||||
#define STEP 0x10000
|
||||
#define FB_WNOISE 0x14002
|
||||
#define FB_PNOISE 0x08000
|
||||
#define NG_PRESET 0x0F35
|
||||
|
||||
|
||||
|
||||
struct SN76496 sn[MAX_76496];
|
||||
|
||||
void SN76496Write (int chip, int data)
|
||||
{
|
||||
struct SN76496 *R = &sn[chip];
|
||||
int n;
|
||||
|
||||
if (data & 0x80)
|
||||
{
|
||||
int r = (data & 0x70) >> 4;
|
||||
int c = r / 2;
|
||||
|
||||
R->LastRegister = r;
|
||||
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
|
||||
switch (r)
|
||||
{
|
||||
case 0: /* tone 0 : frequency */
|
||||
case 2: /* tone 1 : frequency */
|
||||
case 4: /* tone 2 : frequency */
|
||||
R->Period[c] = R->UpdateStep * R->Register[r];
|
||||
if (R->Period[c] == 0)
|
||||
R->Period[c] = R->UpdateStep;
|
||||
if (r == 4)
|
||||
{
|
||||
/* update noise shift frequency */
|
||||
if ((R->Register[6] & 0x03) == 0x03)
|
||||
R->Period[3] = 2 * R->Period[2];
|
||||
}
|
||||
break;
|
||||
case 1: /* tone 0 : volume */
|
||||
case 3: /* tone 1 : volume */
|
||||
case 5: /* tone 2 : volume */
|
||||
case 7: /* noise : volume */
|
||||
R->Volume[c] = R->VolTable[data & 0x0f];
|
||||
break;
|
||||
case 6: /* noise : frequency, mode */
|
||||
{
|
||||
n = R->Register[6];
|
||||
R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
|
||||
n &= 3;
|
||||
/* N/512,N/1024,N/2048,Tone #3 output */
|
||||
|
||||
/*
|
||||
* Amended from Mame 1.04s
|
||||
*
|
||||
* R->Period[3] = (n == 3) ? 2 * R->Period[2] : (R->UpdateStep << (5+n));
|
||||
*/
|
||||
R->Period[3] =
|
||||
((n & 3) ==
|
||||
3) ? 2 * R->Period[2] : (R->UpdateStep << (5 + (n & 3)));
|
||||
|
||||
/* reset noise shifter */
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int r = R->LastRegister;
|
||||
int c = r / 2;
|
||||
|
||||
switch (r)
|
||||
{
|
||||
case 0: /* tone 0 : frequency */
|
||||
case 2: /* tone 1 : frequency */
|
||||
case 4: /* tone 2 : frequency */
|
||||
R->Register[r] = (R->Register[r] & 0x0f) | ((data & 0x3f) << 4);
|
||||
R->Period[c] = R->UpdateStep * R->Register[r];
|
||||
if (R->Period[c] == 0)
|
||||
R->Period[c] = R->UpdateStep;
|
||||
if (r == 4)
|
||||
{
|
||||
/* update noise shift frequency */
|
||||
if ((R->Register[6] & 0x03) == 0x03)
|
||||
R->Period[3] = 2 * R->Period[2];
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* Additions from Mame 1.04
|
||||
* Start Here
|
||||
*/
|
||||
|
||||
case 1: /* tone 0 : volume */
|
||||
case 3: /* tone 1 : volume */
|
||||
case 5: /* tone 2 : volume */
|
||||
case 7: /* noise : volume */
|
||||
R->Volume[c] = R->VolTable[data & 0x0f];
|
||||
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
|
||||
break;
|
||||
case 6: /* noise : frequency, mode */
|
||||
{
|
||||
R->Register[r] = (R->Register[r] & 0x3f0) | (data & 0x0f);
|
||||
n = R->Register[6];
|
||||
R->NoiseFB = (n & 4) ? FB_WNOISE : FB_PNOISE;
|
||||
n &= 3;
|
||||
/* N/512,N/1024,N/2048,Tone #3 output */
|
||||
R->Period[3] =
|
||||
((n & 3) ==
|
||||
3) ? 2 * R->Period[2] : (R->UpdateStep << (5 + (n & 3)));
|
||||
/* reset noise shifter */
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SN76496Update (int chip, signed short int *buffer, int length)
|
||||
{
|
||||
int i;
|
||||
struct SN76496 *R = &sn[chip];
|
||||
|
||||
|
||||
/* If the volume is 0, increase the counter */
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
if (R->Volume[i] == 0)
|
||||
{
|
||||
/* note that I do count += length, NOT count = length + 1. You might think */
|
||||
/* it's the same since the volume is 0, but doing the latter could cause */
|
||||
/* interferencies when the program is rapidly modulating the volume. */
|
||||
if (R->Count[i] <= length * STEP)
|
||||
R->Count[i] += length * STEP;
|
||||
}
|
||||
}
|
||||
|
||||
while (length > 0)
|
||||
{
|
||||
int vol[4];
|
||||
unsigned int out;
|
||||
int left;
|
||||
|
||||
|
||||
/* vol[] keeps track of how long each square wave stays */
|
||||
/* in the 1 position during the sample period. */
|
||||
vol[0] = vol[1] = vol[2] = vol[3] = 0;
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
if (R->Output[i])
|
||||
vol[i] += R->Count[i];
|
||||
R->Count[i] -= STEP;
|
||||
/* Period[i] is the half period of the square wave. Here, in each */
|
||||
/* loop I add Period[i] twice, so that at the end of the loop the */
|
||||
/* square wave is in the same status (0 or 1) it was at the start. */
|
||||
/* vol[i] is also incremented by Period[i], since the wave has been 1 */
|
||||
/* exactly half of the time, regardless of the initial position. */
|
||||
/* If we exit the loop in the middle, Output[i] has to be inverted */
|
||||
/* and vol[i] incremented only if the exit status of the square */
|
||||
/* wave is 1. */
|
||||
while (R->Count[i] <= 0)
|
||||
{
|
||||
R->Count[i] += R->Period[i];
|
||||
if (R->Count[i] > 0)
|
||||
{
|
||||
R->Output[i] ^= 1;
|
||||
if (R->Output[i])
|
||||
vol[i] += R->Period[i];
|
||||
break;
|
||||
}
|
||||
R->Count[i] += R->Period[i];
|
||||
vol[i] += R->Period[i];
|
||||
}
|
||||
if (R->Output[i])
|
||||
vol[i] -= R->Count[i];
|
||||
}
|
||||
|
||||
left = STEP;
|
||||
do
|
||||
{
|
||||
int nextevent;
|
||||
|
||||
|
||||
if (R->Count[3] < left)
|
||||
nextevent = R->Count[3];
|
||||
else
|
||||
nextevent = left;
|
||||
|
||||
if (R->Output[3])
|
||||
vol[3] += R->Count[3];
|
||||
R->Count[3] -= nextevent;
|
||||
if (R->Count[3] <= 0)
|
||||
{
|
||||
if (R->RNG & 1)
|
||||
R->RNG ^= R->NoiseFB;
|
||||
R->RNG >>= 1;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
R->Count[3] += R->Period[3];
|
||||
if (R->Output[3])
|
||||
vol[3] += R->Period[3];
|
||||
}
|
||||
if (R->Output[3])
|
||||
vol[3] -= R->Count[3];
|
||||
|
||||
left -= nextevent;
|
||||
}
|
||||
while (left > 0);
|
||||
|
||||
out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] +
|
||||
vol[2] * R->Volume[2] + vol[3] * R->Volume[3];
|
||||
|
||||
if (out > MAX_OUTPUT * STEP)
|
||||
out = MAX_OUTPUT * STEP;
|
||||
|
||||
*(buffer++) = out / STEP;
|
||||
|
||||
length--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SN76496_set_clock (int chip, int clock)
|
||||
{
|
||||
struct SN76496 *R = &sn[chip];
|
||||
|
||||
|
||||
/* the base clock for the tone generators is the chip clock divided by 16; */
|
||||
/* for the noise generator, it is clock / 256. */
|
||||
/* Here we calculate the number of steps which happen during one sample */
|
||||
/* at the given sample rate. No. of events = sample rate / (clock/16). */
|
||||
/* STEP is a multiplier used to turn the fraction into a fixed point */
|
||||
/* number. */
|
||||
R->UpdateStep = ((double) STEP * R->SampleRate * 16) / clock;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SN76496_set_gain (int chip, int gain)
|
||||
{
|
||||
struct SN76496 *R = &sn[chip];
|
||||
int i;
|
||||
double out;
|
||||
|
||||
|
||||
gain &= 0xff;
|
||||
|
||||
/* increase max output basing on gain (0.2 dB per step) */
|
||||
out = MAX_OUTPUT / 3;
|
||||
while (gain-- > 0)
|
||||
out *= 1.023292992; /* = (10 ^ (0.2/20)) */
|
||||
|
||||
/* build volume table (2dB per step) */
|
||||
for (i = 0; i < 15; i++)
|
||||
{
|
||||
/* limit volume to avoid clipping */
|
||||
if (out > MAX_OUTPUT / 3)
|
||||
R->VolTable[i] = MAX_OUTPUT / 3;
|
||||
else
|
||||
R->VolTable[i] = out;
|
||||
|
||||
out /= 1.258925412; /* = 10 ^ (2/20) = 2dB */
|
||||
}
|
||||
R->VolTable[15] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int SN76496_init (int chip, int clock, int volume, int sample_rate)
|
||||
{
|
||||
int i;
|
||||
struct SN76496 *R = &sn[chip];
|
||||
|
||||
R->SampleRate = sample_rate;
|
||||
SN76496_set_clock (chip, clock);
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
R->Volume[i] = 0;
|
||||
|
||||
R->LastRegister = 0;
|
||||
for (i = 0; i < 8; i += 2)
|
||||
{
|
||||
R->Register[i] = 0;
|
||||
R->Register[i + 1] = 0x0f; /* volume = 0 */
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++)
|
||||
{
|
||||
R->Output[i] = 0;
|
||||
R->Period[i] = R->Count[i] = R->UpdateStep;
|
||||
}
|
||||
R->RNG = NG_PRESET;
|
||||
R->Output[3] = R->RNG & 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int SN76496_sh_start (int clock, int volume, int rate)
|
||||
{
|
||||
SN76496_init (0, clock, volume & 0xff, rate);
|
||||
SN76496_set_gain (0, (volume >> 8) & 0xff);
|
||||
return 0;
|
||||
}
|
38
source/sound/sn76496.h
Normal file
38
source/sound/sn76496.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef SN76496_H
|
||||
#define SN76496_H
|
||||
|
||||
#define MAX_76496 1
|
||||
|
||||
struct SN76496interface
|
||||
{
|
||||
int num;
|
||||
int baseclock[MAX_76496];
|
||||
int volume[MAX_76496];
|
||||
};
|
||||
|
||||
struct SN76496
|
||||
{
|
||||
int SampleRate;
|
||||
unsigned int UpdateStep;
|
||||
int VolTable[16];
|
||||
int Register[8];
|
||||
int LastRegister;
|
||||
int Volume[4];
|
||||
unsigned int RNG;
|
||||
int NoiseFB;
|
||||
int Period[4];
|
||||
int Count[4];
|
||||
int Output[4];
|
||||
};
|
||||
|
||||
extern struct SN76496 sn[MAX_76496];
|
||||
|
||||
/* Function prototypes */
|
||||
void SN76496Write (int chip, int data);
|
||||
void SN76496Update (int chip, signed short int *buffer, int length);
|
||||
void SN76496_set_clock (int chip, int clock);
|
||||
void SN76496_set_gain (int chip, int gain);
|
||||
int SN76496_init (int chip, int clock, int volume, int sample_rate);
|
||||
int SN76496_sh_start (int clock, int volume, int rate);
|
||||
|
||||
#endif
|
224
source/sound/sound.c
Normal file
224
source/sound/sound.c
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
sound.c
|
||||
YM2612 and SN76489 emulation
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
/* YM2612 data */
|
||||
int fm_timera_tab[0x400]; /* Precalculated timer A values */
|
||||
int fm_timerb_tab[0x100]; /* Precalculated timer B values */
|
||||
uint8 fm_reg[2][0x100]; /* Register arrays (2x256) */
|
||||
uint8 fm_latch[2]; /* Register latches */
|
||||
uint8 fm_status; /* Read-only status flags */
|
||||
t_timer timer[2]; /* Timers A and B */
|
||||
extern void *myFM;
|
||||
|
||||
/* Initialize the YM2612 and SN76489 emulation */
|
||||
void sound_init(void)
|
||||
{
|
||||
/* Timers run at half the YM2612 input clock */
|
||||
float clock = ((CPU_Clock / 1000000.0) / 7.0) / 2.0;
|
||||
int i;
|
||||
|
||||
/* Make Timer A table */
|
||||
for(i = 0; i < 1024; i += 1)
|
||||
{
|
||||
/* Formula is "time(us) = 72 * (1024 - A) / clock" */
|
||||
fm_timera_tab[i] = (int)((double)(72 * (1024 - i)) / clock);
|
||||
}
|
||||
|
||||
/* Make Timer B table */
|
||||
for(i = 0; i < 256; i += 1)
|
||||
{
|
||||
/* Formula is "time(us) = 1152 * (256 - B) / clock" */
|
||||
fm_timerb_tab[i] = (int)((double)(1152 * (256 - i)) / clock);
|
||||
}
|
||||
}
|
||||
|
||||
void fm_restore(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (FM_GENS) YM2612_Reset();
|
||||
else YM2612ResetChip(myFM);
|
||||
|
||||
/* feed all the registers and update internal state */
|
||||
for(i = 0; i < 0x100; i++)
|
||||
{
|
||||
if (FM_GENS)
|
||||
{
|
||||
YM2612_Write(0, i);
|
||||
YM2612_Write(1, fm_reg[0][i]);
|
||||
YM2612_Write(2, i);
|
||||
YM2612_Write(3, fm_reg[1][i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
YM2612Write(myFM, 0, i);
|
||||
YM2612Write(myFM, 1, fm_reg[0][i]);
|
||||
YM2612Write(myFM, 2, i);
|
||||
YM2612Write(myFM, 3, fm_reg[1][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fm_reset(void)
|
||||
{
|
||||
if (FM_GENS) YM2612_Reset();
|
||||
else YM2612ResetChip(myFM);
|
||||
|
||||
/* reset timers status */
|
||||
timer[0].running = 0;
|
||||
timer[1].running = 0;
|
||||
timer[0].enable = 0;
|
||||
timer[1].enable = 0;
|
||||
timer[0].count = 0;
|
||||
timer[1].count = 0;
|
||||
timer[0].base = 0;
|
||||
timer[1].base = 0;
|
||||
timer[0].index = 0;
|
||||
timer[1].index = 0;
|
||||
|
||||
/* reset FM status */
|
||||
fm_status = 0;
|
||||
}
|
||||
|
||||
void fm_write(int address, int data)
|
||||
{
|
||||
int a0 = (address & 1);
|
||||
int a1 = (address >> 1) & 1;
|
||||
|
||||
if(a0)
|
||||
{
|
||||
/* Register data */
|
||||
fm_reg[a1][fm_latch[a1]] = data;
|
||||
|
||||
/* Timer control only in set A */
|
||||
if(a1 == 0)
|
||||
switch(fm_latch[a1])
|
||||
{
|
||||
case 0x24: /* Timer A (LSB) */
|
||||
timer[0].index = ((timer[0].index & 0x0003) | (data << 2)) & 0x03FF;
|
||||
if (timer[0].base != fm_timera_tab[timer[0].index])
|
||||
{
|
||||
timer[0].base = fm_timera_tab[timer[0].index];
|
||||
timer[0].count = 0;
|
||||
}
|
||||
break;
|
||||
case 0x25: /* Timer A (MSB) */
|
||||
timer[0].index = ((timer[0].index & 0x03FC) | (data & 3)) & 0x03FF;
|
||||
if (timer[0].base != fm_timera_tab[timer[0].index])
|
||||
{
|
||||
timer[0].base = fm_timera_tab[timer[0].index];
|
||||
timer[0].count = 0;
|
||||
}
|
||||
break;
|
||||
case 0x26: /* Timer B */
|
||||
timer[1].index = data;
|
||||
if (timer[1].base != fm_timerb_tab[timer[1].index])
|
||||
{
|
||||
timer[1].base = fm_timerb_tab[timer[1].index];
|
||||
timer[1].count = 0;
|
||||
}
|
||||
break;
|
||||
case 0x27: /* Timer Control */
|
||||
/* LOAD */
|
||||
timer[0].running = (data & 1);
|
||||
timer[1].running = (data & 2);
|
||||
/* ENABLE */
|
||||
timer[0].enable = (data >> 2) & 1;
|
||||
timer[1].enable = (data >> 3) & 1;
|
||||
/* RESET */
|
||||
if(data & 0x10) fm_status &= ~1;
|
||||
if(data & 0x20) fm_status &= ~2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Register latch */
|
||||
fm_latch[a1] = data;
|
||||
}
|
||||
|
||||
if(snd.enabled)
|
||||
{
|
||||
if(snd.fm.curStage - snd.fm.lastStage > 0)
|
||||
{
|
||||
if (FM_GENS)
|
||||
{
|
||||
int *tempBuffer[2];
|
||||
tempBuffer[0] = snd.fm.gens_buffer[0] + snd.fm.lastStage;
|
||||
tempBuffer[1] = snd.fm.gens_buffer[1] + snd.fm.lastStage;
|
||||
YM2612_Update(tempBuffer, snd.fm.curStage - snd.fm.lastStage);
|
||||
}
|
||||
else
|
||||
{
|
||||
int16 *tempBuffer[2];
|
||||
tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage;
|
||||
tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage;
|
||||
YM2612UpdateOne(myFM, tempBuffer, snd.fm.curStage - snd.fm.lastStage);
|
||||
}
|
||||
snd.fm.lastStage = snd.fm.curStage;
|
||||
}
|
||||
|
||||
if (FM_GENS) YM2612_Write(address & 3, data);
|
||||
else YM2612Write(myFM, address & 3, data);
|
||||
}
|
||||
}
|
||||
|
||||
int fm_read(int address)
|
||||
{
|
||||
return (fm_status);
|
||||
}
|
||||
|
||||
void fm_update_timers(int inc)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Process YM2612 timers */
|
||||
for(i = 0; i < 2; i += 1)
|
||||
{
|
||||
/* Is the timer running? */
|
||||
if(timer[i].running)
|
||||
{
|
||||
/* Each scanline takes up roughly 64 microseconds */
|
||||
timer[i].count += inc;
|
||||
|
||||
/* Check if the counter overflowed */
|
||||
if(timer[i].count >= timer[i].base)
|
||||
{
|
||||
/* Reload counter */
|
||||
timer[i].count -= timer[i].base;
|
||||
|
||||
/* Set overflow flag (if flag setting is enabled) */
|
||||
if(timer[i].enable) fm_status |= (1 << i);
|
||||
|
||||
/* Notice FM core (some CH operation on TimerA) */
|
||||
if(i==0)
|
||||
{
|
||||
if (FM_GENS) YM2612TimerAOver();
|
||||
else YM2612TimerOver(myFM,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void psg_write(int data)
|
||||
{
|
||||
if(snd.enabled)
|
||||
{
|
||||
if(snd.psg.curStage - snd.psg.lastStage > 0)
|
||||
{
|
||||
int16 *tempBuffer;
|
||||
tempBuffer = snd.psg.buffer + snd.psg.lastStage;
|
||||
if (PSG_MAME) SN76496Update (0, tempBuffer, snd.psg.curStage - snd.psg.lastStage);
|
||||
else SN76489_Update(0, tempBuffer, snd.psg.curStage - snd.psg.lastStage);
|
||||
snd.psg.lastStage = snd.psg.curStage;
|
||||
}
|
||||
|
||||
if (PSG_MAME) SN76496Write(0, data);
|
||||
else SN76489_Write(0, data);
|
||||
}
|
||||
}
|
29
source/sound/sound.h
Normal file
29
source/sound/sound.h
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
#ifndef _SOUND_H_
|
||||
#define _SOUND_H_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int running;
|
||||
int enable;
|
||||
int count;
|
||||
int base;
|
||||
int index;
|
||||
} t_timer;
|
||||
|
||||
/* Global variables */
|
||||
extern uint8 fm_reg[2][0x100];
|
||||
extern uint8 fm_latch[2];
|
||||
extern uint8 fm_status;
|
||||
extern t_timer timer[2];
|
||||
|
||||
/* Function prototypes */
|
||||
void sound_init (void);
|
||||
void fm_reset (void);
|
||||
void fm_restore(void);
|
||||
void fm_write (int address, int data);
|
||||
int fm_read (int address);
|
||||
void fm_update_timers (int inc);
|
||||
void psg_write (int data);
|
||||
|
||||
#endif /* _SOUND_H_ */
|
2365
source/sound/ym2612.c
Normal file
2365
source/sound/ym2612.c
Normal file
File diff suppressed because it is too large
Load Diff
171
source/sound/ym2612.h
Normal file
171
source/sound/ym2612.h
Normal file
@ -0,0 +1,171 @@
|
||||
#ifndef _YM2612_H_
|
||||
#define _YM2612_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Change it if you need to do long update
|
||||
#define MAX_UPDATE_LENGHT 2000
|
||||
|
||||
// Gens always uses 16 bits sound (in 32 bits buffer) and do the convertion later if needed.
|
||||
#define OUTPUT_BITS 16
|
||||
|
||||
typedef struct slot__ {
|
||||
int *DT; // paramètre detune
|
||||
int MUL; // paramètre "multiple de fréquence"
|
||||
int TL; // Total Level = volume lorsque l'enveloppe est au plus haut
|
||||
int TLL; // Total Level ajusted
|
||||
int SLL; // Sustin Level (ajusted) = volume où l'enveloppe termine sa première phase de régression
|
||||
int KSR_S; // Key Scale Rate Shift = facteur de prise en compte du KSL dans la variations de l'enveloppe
|
||||
int KSR; // Key Scale Rate = cette valeur est calculée par rapport à la fréquence actuelle, elle va influer
|
||||
// sur les différents paramètres de l'enveloppe comme l'attaque, le decay ... comme dans la réalité !
|
||||
int SEG; // Type enveloppe SSG
|
||||
int *AR; // Attack Rate (table pointeur) = Taux d'attaque (AR[KSR])
|
||||
int *DR; // Decay Rate (table pointeur) = Taux pour la régression (DR[KSR])
|
||||
int *SR; // Sustin Rate (table pointeur) = Taux pour le maintien (SR[KSR])
|
||||
int *RR; // Release Rate (table pointeur) = Taux pour le relâchement (RR[KSR])
|
||||
int Fcnt; // Frequency Count = compteur-fréquence pour déterminer l'amplitude actuelle (SIN[Finc >> 16])
|
||||
int Finc; // frequency step = pas d'incrémentation du compteur-fréquence
|
||||
// plus le pas est grand, plus la fréquence est aïgu (ou haute)
|
||||
int Ecurp; // Envelope current phase = cette variable permet de savoir dans quelle phase
|
||||
// de l'enveloppe on se trouve, par exemple phase d'attaque ou phase de maintenue ...
|
||||
// en fonction de la valeur de cette variable, on va appeler une fonction permettant
|
||||
// de mettre à jour l'enveloppe courante.
|
||||
int Ecnt; // Envelope counter = le compteur-enveloppe permet de savoir où l'on se trouve dans l'enveloppe
|
||||
int Einc; // Envelope step courant
|
||||
int Ecmp; // Envelope counter limite pour la prochaine phase
|
||||
int EincA; // Envelope step for Attack = pas d'incrémentation du compteur durant la phase d'attaque
|
||||
// cette valeur est égal à AR[KSR]
|
||||
int EincD; // Envelope step for Decay = pas d'incrémentation du compteur durant la phase de regression
|
||||
// cette valeur est égal à DR[KSR]
|
||||
int EincS; // Envelope step for Sustain = pas d'incrémentation du compteur durant la phase de maintenue
|
||||
// cette valeur est égal à SR[KSR]
|
||||
int EincR; // Envelope step for Release = pas d'incrémentation du compteur durant la phase de relâchement
|
||||
// cette valeur est égal à RR[KSR]
|
||||
int *OUTp; // pointeur of SLOT output = pointeur permettant de connecter la sortie de ce slot à l'entrée
|
||||
// d'un autre ou carrement à la sortie de la voie
|
||||
int INd; // input data of the slot = données en entrée du slot
|
||||
int ChgEnM; // Change envelop mask.
|
||||
int AMS; // AMS depth level of this SLOT = degré de modulation de l'amplitude par le LFO
|
||||
int AMSon; // AMS enable flag = drapeau d'activation de l'AMS
|
||||
} slot_;
|
||||
|
||||
typedef struct channel__ {
|
||||
int S0_OUT[4]; // anciennes sorties slot 0 (pour le feed back)
|
||||
int Old_OUTd; // ancienne sortie de la voie (son brut)
|
||||
int OUTd; // sortie de la voie (son brut)
|
||||
int LEFT; // LEFT enable flag
|
||||
int RIGHT; // RIGHT enable flag
|
||||
int ALGO; // Algorythm = détermine les connections entre les opérateurs
|
||||
int FB; // shift count of self feed back = degré de "Feed-Back" du SLOT 1 (il est son unique entrée)
|
||||
int FMS; // Fréquency Modulation Sensitivity of channel = degré de modulation de la fréquence sur la voie par le LFO
|
||||
int AMS; // Amplitude Modulation Sensitivity of channel = degré de modulation de l'amplitude sur la voie par le LFO
|
||||
int FNUM[4]; // hauteur fréquence de la voie (+ 3 pour le mode spécial)
|
||||
int FOCT[4]; // octave de la voie (+ 3 pour le mode spécial)
|
||||
int KC[4]; // Key Code = valeur fonction de la fréquence (voir KSR pour les slots, KSR = KC >> KSR_S)
|
||||
struct slot__ SLOT[4]; // four slot.operators = les 4 slots de la voie
|
||||
int FFlag; // Frequency step recalculation flag
|
||||
} channel_;
|
||||
|
||||
typedef struct ym2612__ {
|
||||
int Clock; // Horloge YM2612
|
||||
int Rate; // Sample Rate (11025/22050/44100)
|
||||
int TimerBase; // TimerBase calculation
|
||||
int Status; // YM2612 Status (timer overflow)
|
||||
int OPNAadr; // addresse pour l'écriture dans l'OPN A (propre à l'émulateur)
|
||||
int OPNBadr; // addresse pour l'écriture dans l'OPN B (propre à l'émulateur)
|
||||
int LFOcnt; // LFO counter = compteur-fréquence pour le LFO
|
||||
int LFOinc; // LFO step counter = pas d'incrémentation du compteur-fréquence du LFO
|
||||
// plus le pas est grand, plus la fréquence est grande
|
||||
int TimerA; // timerA limit = valeur jusqu'à laquelle le timer A doit compter
|
||||
int TimerAL;
|
||||
int TimerAcnt; // timerA counter = valeur courante du Timer A
|
||||
int TimerB; // timerB limit = valeur jusqu'à laquelle le timer B doit compter
|
||||
int TimerBL;
|
||||
int TimerBcnt; // timerB counter = valeur courante du Timer B
|
||||
int Mode; // Mode actuel des voie 3 et 6 (normal / spécial)
|
||||
int DAC; // DAC enabled flag
|
||||
int DACdata; // DAC data
|
||||
double Frequence; // Fréquence de base, se calcul par rapport à l'horlage et au sample rate
|
||||
unsigned int Inter_Cnt; // Interpolation Counter
|
||||
unsigned int Inter_Step; // Interpolation Step
|
||||
struct channel__ CHANNEL[6]; // Les 6 voies du YM2612
|
||||
int REG[2][0x100]; // Sauvegardes des valeurs de tout les registres, c'est facultatif
|
||||
// cela nous rend le débuggage plus facile
|
||||
} ym2612_;
|
||||
|
||||
/* Gens */
|
||||
|
||||
extern int YM2612_Enable;
|
||||
extern int YM2612_Improv;
|
||||
extern int DAC_Enable;
|
||||
extern int *YM_Buf[2];
|
||||
extern int YM_Len;
|
||||
|
||||
/* end */
|
||||
|
||||
int YM2612_Init(int clock, int rate, int interpolation);
|
||||
int YM2612_End(void);
|
||||
int YM2612_Reset(void);
|
||||
int YM2612_Read(void);
|
||||
int YM2612_Write(unsigned char adr, unsigned char data);
|
||||
void YM2612_Update(int **buf, int length);
|
||||
int YM2612_Save(unsigned char SAVE[0x200]);
|
||||
int YM2612_Restore(unsigned char SAVE[0x200]);
|
||||
|
||||
|
||||
void YM2612_Special_Update(void);
|
||||
void YM2612TimerAOver(void);
|
||||
|
||||
/* end */
|
||||
|
||||
// used for foward...
|
||||
void Update_Chan_Algo0(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo1(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo2(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo3(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo4(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo5(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo6(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo7(channel_ *CH, int **buf, int lenght);
|
||||
|
||||
void Update_Chan_Algo0_LFO(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo1_LFO(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo2_LFO(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo3_LFO(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo4_LFO(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo5_LFO(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo6_LFO(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo7_LFO(channel_ *CH, int **buf, int lenght);
|
||||
|
||||
void Update_Chan_Algo0_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo1_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo2_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo3_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo4_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo5_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo6_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo7_Int(channel_ *CH, int **buf, int lenght);
|
||||
|
||||
void Update_Chan_Algo0_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo1_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo2_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo3_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo4_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo5_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo6_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
void Update_Chan_Algo7_LFO_Int(channel_ *CH, int **buf, int lenght);
|
||||
|
||||
// used for foward...
|
||||
void Env_Attack_Next(slot_ *SL);
|
||||
void Env_Decay_Next(slot_ *SL);
|
||||
void Env_Substain_Next(slot_ *SL);
|
||||
void Env_Release_Next(slot_ *SL);
|
||||
void Env_NULL_Next(slot_ *SL);
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
77
source/sram.c
Normal file
77
source/sram.c
Normal file
@ -0,0 +1,77 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* SRAM MANAGER
|
||||
***************************************************************************/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
T_SRAM sram;
|
||||
|
||||
/****************************************************************************
|
||||
* A quick guide to SRAM on the Genesis
|
||||
*
|
||||
* This is based on observations only - it may be completely wrong!
|
||||
*
|
||||
* The SRAM definition is held at offset 0x1b0 of the ROM header.
|
||||
* From looking at several ROMS, an ID appears:
|
||||
*
|
||||
* 0x1b0 : 0x52 0x41 0xF8 0x20 0x00200001 0x0020ffff
|
||||
*
|
||||
* Assuming 64k SRAM / Battery RAM throughout
|
||||
****************************************************************************/
|
||||
void SRAM_Init ()
|
||||
{
|
||||
memset (&sram, 0, sizeof (T_SRAM));
|
||||
sram.crc = crc32 (0, &sram.sram[0], 0x10000);
|
||||
|
||||
if ((cart_rom[0x1b0] == 0x52) && (cart_rom[0x1b1] == 0x41))
|
||||
{
|
||||
sram.on = 1;
|
||||
sram.write = 1;
|
||||
sram.detected = 1;
|
||||
sram.start = READ_WORD_LONG(cart_rom, 0x1b4);
|
||||
sram.end = READ_WORD_LONG(cart_rom, 0x1b8);
|
||||
|
||||
/* some games have incorrect header informations */
|
||||
if ((sram.start > sram.end) || ((sram.end - sram.start) >= 0x10000))
|
||||
sram.end = sram.start + 0xffff;
|
||||
sram.start &= 0xfffffffe;
|
||||
sram.end |= 1;
|
||||
|
||||
/* game using serial EEPROM as external RAM */
|
||||
if (sram.end - sram.start < 2) EEPROM_Init();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* set SRAM memory region by default */
|
||||
sram.start = 0x200000;
|
||||
sram.end = 0x20ffff;
|
||||
|
||||
/* set SRAM ON by default if game is smaller than 2M */
|
||||
if (genromsize <= 0x200000)
|
||||
{
|
||||
sram.on = 1;
|
||||
sram.write = 1;
|
||||
}
|
||||
|
||||
/* some games using EEPROM don't have the correct header */
|
||||
EEPROM_Init();
|
||||
}
|
||||
}
|
40
source/sram.h
Normal file
40
source/sram.h
Normal file
@ -0,0 +1,40 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* NGC MANAGER
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 detected;
|
||||
uint8 on;
|
||||
uint8 write;
|
||||
uint8 custom;
|
||||
uint32 start;
|
||||
uint32 end;
|
||||
int crc;
|
||||
uint8 sram[0x10000];
|
||||
} T_SRAM;
|
||||
|
||||
/* Function prototypes */
|
||||
extern void SRAM_Init ();
|
||||
|
||||
/* global variables */
|
||||
extern T_SRAM sram;
|
||||
|
98
source/ssf2tnc.c
Normal file
98
source/ssf2tnc.c
Normal file
@ -0,0 +1,98 @@
|
||||
/****************************************************************************
|
||||
* Super Street Fighter 2 - The New Challengers
|
||||
*
|
||||
* This is the ROM mapper for this game.
|
||||
* Called from mem68k.c
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
|
||||
#ifdef NGC
|
||||
char *shadow_rom = (char *) 0x8000;
|
||||
#else
|
||||
char shadow_rom[0x500000];
|
||||
#endif
|
||||
|
||||
int SSF2TNC = 0;
|
||||
static int oldaddr = 0;
|
||||
static uint8 olddata = 0;
|
||||
|
||||
void ssf2bankrom (int address, unsigned char data)
|
||||
{
|
||||
/* Banking performed on odd addresses only */
|
||||
if (!(address & 1)) return;
|
||||
|
||||
/*
|
||||
* Whilst debugging the ARAM stuff, I noticed that this ROM
|
||||
* requested the same address/data on subsequent calls.
|
||||
* This is just a little speedup, which seems to make the
|
||||
* sound etc in the intro much less choppy.
|
||||
*
|
||||
* Happy dance anyone?
|
||||
*/
|
||||
if ((oldaddr == address) && (olddata == data)) return;
|
||||
|
||||
if ((address > 0xa130f2) && (address < 0xa13100))
|
||||
{
|
||||
switch (address & 0xf)
|
||||
{
|
||||
case 0x3: /* 080000-0FFFFF */
|
||||
#ifdef NGC
|
||||
ARAMFetch (cart_rom + 0x080000, shadow_rom + (data * 0x80000), 0x80000);
|
||||
#else
|
||||
memcpy (cart_rom + 0x080000, shadow_rom + (data * 0x80000), 0x80000);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x5: /* 100000 - 17FFFF */
|
||||
#ifdef NGC
|
||||
ARAMFetch (cart_rom + 0x100000, shadow_rom + (data * 0x80000), 0x80000);
|
||||
#else
|
||||
memcpy (cart_rom + 0x100000, shadow_rom + (data * 0x80000), 0x80000);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x7: /* 180000 - 1FFFFF */
|
||||
#ifdef NGC
|
||||
ARAMFetch (cart_rom + 0x180000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#else
|
||||
memcpy (cart_rom + 0x180000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0x9: /* 200000 - 27FFFF */
|
||||
#ifdef NGC
|
||||
ARAMFetch (cart_rom + 0x200000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#else
|
||||
memcpy (cart_rom + 0x200000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xb: /* 280000 - 2FFFFF */
|
||||
#ifdef NGC
|
||||
ARAMFetch (cart_rom + 0x280000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#else
|
||||
memcpy (cart_rom + 0x280000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xd: /* 300000 - 37FFFF */
|
||||
#ifdef NGC
|
||||
ARAMFetch (cart_rom + 0x300000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#else
|
||||
memcpy (cart_rom + 0x300000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 0xf: /* 380000 - 3FFFFF */
|
||||
#ifdef NGC
|
||||
ARAMFetch (cart_rom + 0x380000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#else
|
||||
memcpy (cart_rom + 0x380000, shadow_rom + ( data * 0x80000), 0x80000);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
oldaddr = address;
|
||||
olddata = data;
|
||||
}
|
17
source/ssf2tnc.h
Normal file
17
source/ssf2tnc.h
Normal file
@ -0,0 +1,17 @@
|
||||
/****************************************************************************
|
||||
* Super Street Fighter 2 - The New Challengers
|
||||
*
|
||||
* This is the ROM mapper for this game.
|
||||
* Called from mem68k.c
|
||||
***************************************************************************/
|
||||
|
||||
/* Function prototypes */
|
||||
extern void ssf2bankrom (int address, unsigned char data);
|
||||
|
||||
/* global variables */
|
||||
extern int SSF2TNC;
|
||||
#ifdef NGC
|
||||
extern char *shadow_rom;
|
||||
#else
|
||||
extern char shadow_rom[0x500000];
|
||||
#endif
|
356
source/state.c
Normal file
356
source/state.c
Normal file
@ -0,0 +1,356 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* STATE MANAGER
|
||||
***************************************************************************/
|
||||
#include "shared.h"
|
||||
|
||||
unsigned char state[0x23000];
|
||||
unsigned int bufferptr;
|
||||
|
||||
void load_param(void *param, unsigned int size)
|
||||
{
|
||||
memcpy(param, &state[bufferptr], size);
|
||||
bufferptr+= size;
|
||||
}
|
||||
|
||||
void save_param(void *param, unsigned int size)
|
||||
{
|
||||
memcpy(&state[bufferptr], param, size);
|
||||
bufferptr+= size;
|
||||
}
|
||||
|
||||
void state_load(unsigned char *buffer)
|
||||
{
|
||||
uint32 tmp32;
|
||||
uint16 tmp16;
|
||||
int i;
|
||||
int height, width;
|
||||
unsigned long inbytes, outbytes;
|
||||
|
||||
/* get compressed state size & uncompress state file */
|
||||
memcpy(&inbytes,&buffer[0],sizeof(inbytes));
|
||||
|
||||
#ifdef NGC
|
||||
outbytes = 0x23000;
|
||||
uncompress ((char *) &state[0], &outbytes, (char *) &buffer[sizeof(inbytes)], inbytes);
|
||||
#else
|
||||
outbytes = inbytes;
|
||||
memcpy(&state[0], &buffer[sizeof(inbytes)], outbytes);
|
||||
#endif
|
||||
|
||||
/* load state */
|
||||
system_reset();
|
||||
bufferptr = 0;
|
||||
|
||||
// gen.c stuff
|
||||
load_param(work_ram, sizeof(work_ram));
|
||||
load_param(zram, sizeof(zram));
|
||||
load_param(&zbusreq, sizeof(zbusreq));
|
||||
load_param(&zreset, sizeof(zreset));
|
||||
load_param(&zbusack, sizeof(zbusack));
|
||||
load_param(&zirq, sizeof(zirq));
|
||||
load_param(&zbank, sizeof(zbank));
|
||||
load_param(&lastbusreqcnt, sizeof(lastbusreqcnt));
|
||||
load_param(&lastbusack, sizeof(lastbusack));
|
||||
|
||||
// io.c stuff
|
||||
load_param(io_reg, sizeof(io_reg));
|
||||
|
||||
// render.c stuff
|
||||
load_param(&object_index_count,sizeof(object_index_count));
|
||||
|
||||
// vdp.c stuff
|
||||
load_param(sat, sizeof(sat));
|
||||
load_param(vram, sizeof(vram));
|
||||
load_param(cram, sizeof(cram));
|
||||
load_param(vsram, sizeof(vsram));
|
||||
load_param(reg, sizeof(reg));
|
||||
load_param(&addr, sizeof(addr));
|
||||
load_param(&addr_latch, sizeof(addr_latch));
|
||||
load_param(&code, sizeof(code));
|
||||
load_param(&pending, sizeof(pending));
|
||||
load_param(&status, sizeof(status));
|
||||
load_param(&ntab, sizeof(ntab));
|
||||
load_param(&ntbb, sizeof(ntbb));
|
||||
load_param(&ntwb, sizeof(ntwb));
|
||||
load_param(&satb, sizeof(satb));
|
||||
load_param(&hscb, sizeof(hscb));
|
||||
load_param(&sat_base_mask, sizeof(sat_base_mask));
|
||||
load_param(&sat_addr_mask, sizeof(sat_addr_mask));
|
||||
load_param(&border, sizeof(border));
|
||||
load_param(&playfield_shift, sizeof(playfield_shift));
|
||||
load_param(&playfield_col_mask, sizeof(playfield_col_mask));
|
||||
load_param(&playfield_row_mask, sizeof(playfield_row_mask));
|
||||
load_param(&y_mask, sizeof(y_mask));
|
||||
load_param(&hint_pending, sizeof(hint_pending));
|
||||
load_param(&vint_pending, sizeof(vint_pending));
|
||||
load_param(&h_counter, sizeof(h_counter));
|
||||
load_param(&hc_latch, sizeof(hc_latch));
|
||||
load_param(&v_counter, sizeof(v_counter));
|
||||
load_param(&dmafill, sizeof(dmafill));
|
||||
load_param(&im2_flag, sizeof(im2_flag));
|
||||
load_param(&frame_end, sizeof(frame_end));
|
||||
load_param(&dma_endCycles, sizeof(dma_endCycles));
|
||||
|
||||
// system.c stuff
|
||||
load_param(&aim_m68k,sizeof(aim_m68k));
|
||||
load_param(&count_m68k,sizeof(count_m68k));
|
||||
load_param(&dma_m68k,sizeof(dma_m68k));
|
||||
load_param(&aim_z80,sizeof(aim_z80));
|
||||
load_param(&count_z80,sizeof(count_z80));
|
||||
|
||||
// FM stuff
|
||||
load_param(fm_reg,sizeof(fm_reg));
|
||||
load_param(&fm_status,sizeof(fm_status));
|
||||
load_param(timer,sizeof(timer));
|
||||
fm_restore();
|
||||
|
||||
// psg stuff
|
||||
load_param(&PSG_MAME,1);
|
||||
if (PSG_MAME)
|
||||
{
|
||||
struct SN76496 *R = &sn[0];
|
||||
load_param(R->Register,27*4);
|
||||
}
|
||||
else load_param(SN76489_GetContextPtr (0),SN76489_GetContextSize ());
|
||||
|
||||
// Window size
|
||||
load_param(&height, sizeof(int));
|
||||
load_param(&width, sizeof(int));
|
||||
if (height != bitmap.viewport.h)
|
||||
{
|
||||
bitmap.viewport.oh = bitmap.viewport.h;
|
||||
bitmap.viewport.h = height;
|
||||
bitmap.viewport.changed = 1;
|
||||
}
|
||||
if (width != bitmap.viewport.w)
|
||||
{
|
||||
bitmap.viewport.ow = bitmap.viewport.w;
|
||||
bitmap.viewport.w = width;
|
||||
bitmap.viewport.changed = 1;
|
||||
}
|
||||
|
||||
// 68000 CPU
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D0, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D1, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D2, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D3, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D4, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D5, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D6, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_D7, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A0, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A1, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A2, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A3, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A4, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A5, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A6, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_A7, tmp32);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_PC, tmp32);
|
||||
load_param(&tmp16, 2); m68k_set_reg(M68K_REG_SR, tmp16);
|
||||
load_param(&tmp32, 4); m68k_set_reg(M68K_REG_USP,tmp32);
|
||||
|
||||
// MAME Z80 CPU
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_PC, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_SP, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_AF, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_BC, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_DE, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_HL, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_IX, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_IY, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_R, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_I, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_AF2, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_BC2, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_DE2, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_HL2, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_IM, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_IFF1,tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_IFF2,tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_HALT,tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_NMI_STATE,tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_IRQ_STATE,tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_DC0, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_DC1, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_DC2, tmp32);
|
||||
load_param(&tmp32, 4); z80_set_reg(Z80_DC3, tmp32);
|
||||
|
||||
// Remake cache
|
||||
for (i=0;i<0x800;i++)
|
||||
{
|
||||
bg_name_list[i]=i;
|
||||
bg_name_dirty[i]=0xFF;
|
||||
}
|
||||
bg_list_index=0x800;
|
||||
color_update = color_update_16;
|
||||
for(i = 0; i < 0x40; i += 1) color_update(i, *(uint16 *)&cram[i << 1]);
|
||||
color_update(0x00, *(uint16 *)&cram[border << 1]);
|
||||
}
|
||||
|
||||
int state_save(unsigned char *buffer)
|
||||
{
|
||||
uint32 tmp32;
|
||||
uint16 tmp16;
|
||||
unsigned long inbytes, outbytes;
|
||||
|
||||
/* save state */
|
||||
bufferptr = 0;
|
||||
|
||||
// gen.c stuff
|
||||
save_param(work_ram, sizeof(work_ram));
|
||||
save_param(zram, sizeof(zram));
|
||||
save_param(&zbusreq, sizeof(zbusreq));
|
||||
save_param(&zreset, sizeof(zreset));
|
||||
save_param(&zbusack, sizeof(zbusack));
|
||||
save_param(&zirq, sizeof(zirq));
|
||||
save_param(&zbank, sizeof(zbank));
|
||||
save_param(&lastbusreqcnt, sizeof(lastbusreqcnt));
|
||||
save_param(&lastbusack, sizeof(lastbusack));
|
||||
|
||||
// io.c stuff
|
||||
save_param(io_reg, sizeof(io_reg));
|
||||
|
||||
// render.c stuff
|
||||
save_param(&object_index_count,sizeof(object_index_count));
|
||||
|
||||
// vdp.c stuff
|
||||
save_param(sat, sizeof(sat));
|
||||
save_param(vram, sizeof(vram));
|
||||
save_param(cram, sizeof(cram));
|
||||
save_param(vsram, sizeof(vsram));
|
||||
save_param(reg, sizeof(reg));
|
||||
save_param(&addr, sizeof(addr));
|
||||
save_param(&addr_latch, sizeof(addr_latch));
|
||||
save_param(&code, sizeof(code));
|
||||
save_param(&pending, sizeof(pending));
|
||||
save_param(&status, sizeof(status));
|
||||
save_param(&ntab, sizeof(ntab));
|
||||
save_param(&ntbb, sizeof(ntbb));
|
||||
save_param(&ntwb, sizeof(ntwb));
|
||||
save_param(&satb, sizeof(satb));
|
||||
save_param(&hscb, sizeof(hscb));
|
||||
save_param(&sat_base_mask, sizeof(sat_base_mask));
|
||||
save_param(&sat_addr_mask, sizeof(sat_addr_mask));
|
||||
save_param(&border, sizeof(border));
|
||||
save_param(&playfield_shift, sizeof(playfield_shift));
|
||||
save_param(&playfield_col_mask, sizeof(playfield_col_mask));
|
||||
save_param(&playfield_row_mask, sizeof(playfield_row_mask));
|
||||
save_param(&y_mask, sizeof(y_mask));
|
||||
save_param(&hint_pending, sizeof(hint_pending));
|
||||
save_param(&vint_pending, sizeof(vint_pending));
|
||||
save_param(&h_counter, sizeof(h_counter));
|
||||
save_param(&hc_latch, sizeof(hc_latch));
|
||||
save_param(&v_counter, sizeof(v_counter));
|
||||
save_param(&dmafill, sizeof(dmafill));
|
||||
save_param(&im2_flag, sizeof(im2_flag));
|
||||
save_param(&frame_end, sizeof(frame_end));
|
||||
save_param(&dma_endCycles, sizeof(dma_endCycles));
|
||||
|
||||
// system.c stuff
|
||||
save_param(&aim_m68k,sizeof(aim_m68k));
|
||||
save_param(&count_m68k,sizeof(count_m68k));
|
||||
save_param(&dma_m68k,sizeof(dma_m68k));
|
||||
save_param(&aim_z80,sizeof(aim_z80));
|
||||
save_param(&count_z80,sizeof(count_z80));
|
||||
|
||||
// FM stuff
|
||||
save_param(fm_reg,sizeof(fm_reg));
|
||||
save_param(&fm_status,sizeof(fm_status));
|
||||
save_param(timer,sizeof(timer));
|
||||
|
||||
// PSG stuff
|
||||
save_param(&PSG_MAME,1);
|
||||
if (PSG_MAME)
|
||||
{
|
||||
struct SN76496 *R = &sn[0];
|
||||
save_param(R->Register,27*4);
|
||||
}
|
||||
else save_param(SN76489_GetContextPtr (0),SN76489_GetContextSize ());
|
||||
|
||||
// Window size
|
||||
save_param(&bitmap.viewport.h, sizeof(int));
|
||||
save_param(&bitmap.viewport.w, sizeof(int));
|
||||
|
||||
// 68000 CPU
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D0); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D1); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D2); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D3); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D4); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D5); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D6); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_D7); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A0); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A1); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A2); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A3); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A4); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A5); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A6); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_A7); save_param(&tmp32, 4);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_PC); save_param(&tmp32, 4);
|
||||
tmp16 = m68k_get_reg(NULL, M68K_REG_SR); save_param(&tmp16, 2);
|
||||
tmp32 = m68k_get_reg(NULL, M68K_REG_USP); save_param(&tmp32, 4);
|
||||
|
||||
// Z80 CPU
|
||||
tmp32 = z80_get_reg(Z80_PC); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_SP); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_AF); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_BC); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_DE); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_HL); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_IX); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_IY); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_R); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_I); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_AF2); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_BC2); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_DE2); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_HL2); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_IM); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_IFF1); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_IFF2); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_HALT); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_NMI_STATE); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_IRQ_STATE); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_DC0); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_DC1); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_DC2); save_param(&tmp32, 4);
|
||||
tmp32 = z80_get_reg(Z80_DC3); save_param(&tmp32, 4);
|
||||
|
||||
inbytes = bufferptr;
|
||||
|
||||
#ifdef NGC
|
||||
/* compress state file */
|
||||
outbytes = 0x24000;
|
||||
compress2 ((char *) &buffer[sizeof(outbytes)], &outbytes, (char *) &state[0], inbytes, 9);
|
||||
#else
|
||||
outbytes = inbytes;
|
||||
memcpy(&buffer[sizeof(outbytes)], &state[0], outbytes);
|
||||
#endif
|
||||
|
||||
/* write compressed size in the first 32 bits for decompression */
|
||||
memcpy(&buffer[0], &outbytes, sizeof(outbytes));
|
||||
|
||||
/* return total size */
|
||||
return (sizeof(outbytes) + outbytes);
|
||||
}
|
29
source/state.h
Normal file
29
source/state.h
Normal file
@ -0,0 +1,29 @@
|
||||
/****************************************************************************
|
||||
* Genesis Plus 1.2a
|
||||
*
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* STATE MANAGER
|
||||
***************************************************************************/
|
||||
#ifndef _STATE_H_
|
||||
#define _STATE_H_
|
||||
|
||||
/* Function prototypes */
|
||||
void state_load(unsigned char *buffer);
|
||||
int state_save(unsigned char *buffer);
|
||||
|
||||
#endif
|
432
source/system.c
Normal file
432
source/system.c
Normal file
@ -0,0 +1,432 @@
|
||||
/*
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "shared.h"
|
||||
|
||||
#define CLOCK_NTSC 53693175
|
||||
#define CLOCK_PAL 53203424
|
||||
#define SND_SIZE (snd.buffer_size * sizeof(int16))
|
||||
|
||||
t_bitmap bitmap;
|
||||
t_snd snd;
|
||||
uint32 aim_m68k = 0;
|
||||
uint32 count_m68k = 0;
|
||||
uint32 dma_m68k = 0;
|
||||
uint32 aim_z80 = 0;
|
||||
uint32 count_z80 = 0;
|
||||
uint16 misc68Kcycles = 488;
|
||||
uint16 miscZ80cycles = 228;
|
||||
uint16 lines_per_frame = 262;
|
||||
double CPU_Clock = (double)CLOCK_NTSC;
|
||||
void *myFM = NULL;
|
||||
static int sound_tbl[312];
|
||||
static int sound_inc[312];
|
||||
uint8 alttiming = 0;
|
||||
|
||||
void m68k_run (int cyc)
|
||||
{
|
||||
int cyc_do = cyc - count_m68k; /* cycles remaining to run for the line */
|
||||
if (cyc_do > 0)
|
||||
{
|
||||
m68k_execute(cyc_do);
|
||||
count_m68k += cyc_do;
|
||||
}
|
||||
}
|
||||
|
||||
void z80_run (int cyc)
|
||||
{
|
||||
int cyc_do = cyc - count_z80;
|
||||
if (cyc_do > 0) count_z80 += z80_execute(cyc_do);
|
||||
}
|
||||
|
||||
void m68k_freeze(int cycles)
|
||||
{
|
||||
extern int m68ki_remaining_cycles;
|
||||
int extra_cycles = cycles - m68k_cycles_remaining();
|
||||
|
||||
if (extra_cycles > 0)
|
||||
{
|
||||
/* end of 68k execution */
|
||||
m68ki_remaining_cycles = 0;
|
||||
|
||||
/* extra cycles are burned at next execution */
|
||||
count_m68k += extra_cycles;
|
||||
}
|
||||
else m68ki_remaining_cycles -= cycles; /* we burn some 68k cycles */
|
||||
}
|
||||
|
||||
extern uint8 hq_fm;
|
||||
int audio_init (int rate)
|
||||
{
|
||||
int i;
|
||||
int vclk = (int)(CPU_Clock / 7.0); /* 68000 and YM2612 clock */
|
||||
int zclk = (int)(CPU_Clock / 15.0); /* Z80 and SN76489 clock */
|
||||
|
||||
/* Clear the sound data context */
|
||||
memset (&snd, 0, sizeof (snd));
|
||||
|
||||
/* Make sure the requested sample rate is valid */
|
||||
if (!rate || ((rate < 8000) | (rate > 48000))) return (0);
|
||||
|
||||
/* Calculate the sound buffer size */
|
||||
snd.buffer_size = (rate / vdp_rate);
|
||||
snd.sample_rate = rate;
|
||||
|
||||
/* Allocate sound buffers */
|
||||
if (FM_GENS)
|
||||
{
|
||||
snd.fm.gens_buffer[0] = realloc (snd.fm.gens_buffer[0], snd.buffer_size * sizeof (int));
|
||||
snd.fm.gens_buffer[1] = realloc (snd.fm.gens_buffer[1], snd.buffer_size * sizeof (int));
|
||||
if (!snd.fm.gens_buffer[0] || !snd.fm.gens_buffer[1]) return (-1);
|
||||
memset (snd.fm.gens_buffer[0], 0, SND_SIZE*2);
|
||||
memset (snd.fm.gens_buffer[1], 0, SND_SIZE*2);
|
||||
}
|
||||
else
|
||||
{
|
||||
snd.fm.buffer[0] = realloc (snd.fm.buffer[0], snd.buffer_size * sizeof (int16));
|
||||
snd.fm.buffer[1] = realloc (snd.fm.buffer[1], snd.buffer_size * sizeof (int16));
|
||||
if (!snd.fm.buffer[0] || !snd.fm.buffer[1]) return (-1);
|
||||
memset (snd.fm.buffer[0], 0, SND_SIZE);
|
||||
memset (snd.fm.buffer[1], 0, SND_SIZE);
|
||||
}
|
||||
|
||||
snd.psg.buffer = realloc (snd.psg.buffer, snd.buffer_size * sizeof (int16));
|
||||
if (!snd.psg.buffer) return (-1);
|
||||
memset (snd.psg.buffer, 0, SND_SIZE);
|
||||
|
||||
/* Set audio enable flag */
|
||||
snd.enabled = 1;
|
||||
|
||||
/* Initialize sound chip emulation */
|
||||
if (PSG_MAME) SN76496_sh_start(zclk, 0, rate);
|
||||
else
|
||||
{
|
||||
SN76489_Init(0, zclk, rate);
|
||||
SN76489_Config(0, MUTE_ALLON, VOL_FULL, FB_SEGAVDP, SRW_SEGAVDP, 0);
|
||||
}
|
||||
|
||||
if (FM_GENS) YM2612_Init(vclk, rate, hq_fm);
|
||||
else if (!myFM) myFM = YM2612Init (0, 0, vclk, rate, 0, 0);
|
||||
|
||||
/* Make sound table */
|
||||
for (i = 0; i < lines_per_frame; i++)
|
||||
{
|
||||
float p = (snd.buffer_size * i) / lines_per_frame;
|
||||
float q = (snd.buffer_size * (i+1)) / lines_per_frame;
|
||||
sound_tbl[i] = p;
|
||||
sound_inc[i] = ((q - p) * 1000000) / snd.sample_rate;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void system_init (void)
|
||||
{
|
||||
/* PAL or NTSC timings */
|
||||
vdp_rate = (vdp_pal) ? 50 : 60;
|
||||
lines_per_frame = (vdp_pal) ? 313 : 262;
|
||||
CPU_Clock = (vdp_pal) ? (double)CLOCK_PAL : (double)CLOCK_NTSC;
|
||||
miscZ80cycles = (vdp_pal) ? 227 : 228;
|
||||
misc68Kcycles = (vdp_pal) ? 487 : 488;
|
||||
|
||||
gen_init ();
|
||||
vdp_init ();
|
||||
render_init ();
|
||||
sound_init();
|
||||
}
|
||||
|
||||
void system_reset (void)
|
||||
{
|
||||
aim_m68k = 0;
|
||||
count_m68k = 0;
|
||||
dma_m68k = 0;
|
||||
aim_z80 = 0;
|
||||
count_z80 = 0;
|
||||
|
||||
gen_reset ();
|
||||
io_reset();
|
||||
vdp_reset ();
|
||||
render_reset ();
|
||||
|
||||
if (snd.enabled)
|
||||
{
|
||||
fm_reset();
|
||||
if (FM_GENS)
|
||||
{
|
||||
memset (snd.fm.gens_buffer[0], 0, SND_SIZE*2);
|
||||
memset (snd.fm.gens_buffer[1], 0, SND_SIZE*2);
|
||||
}
|
||||
else
|
||||
{
|
||||
memset (snd.fm.buffer[0], 0, SND_SIZE);
|
||||
memset (snd.fm.buffer[1], 0, SND_SIZE);
|
||||
}
|
||||
|
||||
if (!PSG_MAME) SN76489_Reset(0);
|
||||
memset (snd.psg.buffer, 0, SND_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void system_shutdown (void)
|
||||
{
|
||||
gen_shutdown ();
|
||||
vdp_shutdown ();
|
||||
render_shutdown ();
|
||||
}
|
||||
|
||||
int system_frame (int do_skip)
|
||||
{
|
||||
/* update total cycles count */
|
||||
dma_m68k += count_m68k;
|
||||
|
||||
/* reset line cycles counts */
|
||||
aim_m68k = 0;
|
||||
count_m68k = 0;
|
||||
aim_z80 = 0;
|
||||
count_z80 = 0;
|
||||
lastbusreqcnt = -1000;
|
||||
|
||||
if (!gen_running) return 0;
|
||||
|
||||
/* Clear V-Blank flag */
|
||||
status &= 0xFFF7;
|
||||
|
||||
/* Toggle even/odd flag (IM2 only) */
|
||||
if (im2_flag) status ^= 0x0010;
|
||||
|
||||
/* Reset HCounter */
|
||||
h_counter = reg[10];
|
||||
|
||||
/* Point to start of sound buffer */
|
||||
snd.fm.lastStage = snd.fm.curStage = 0;
|
||||
snd.psg.lastStage = snd.psg.curStage = 0;
|
||||
|
||||
/* Parse sprites for line 0 (done on line 261 or 312) */
|
||||
parse_satb (0x80);
|
||||
|
||||
/* Line processing */
|
||||
for (v_counter = 0; v_counter < lines_per_frame; v_counter ++)
|
||||
{
|
||||
/* update cpu cycles goal for the line */
|
||||
aim_z80 += miscZ80cycles;
|
||||
aim_m68k += misc68Kcycles;
|
||||
|
||||
/* 6-Buttons or Menacer update */
|
||||
input_update();
|
||||
|
||||
/* If a Z80 interrupt is still pending after a scanline, cancel it */
|
||||
if (zirq)
|
||||
{
|
||||
zirq = 0;
|
||||
z80_set_irq_line(0, CLEAR_LINE);
|
||||
}
|
||||
|
||||
/* H Int */
|
||||
if (v_counter <= frame_end)
|
||||
{
|
||||
if(--h_counter < 0)
|
||||
{
|
||||
h_counter = reg[10];
|
||||
hint_pending = 1;
|
||||
if(reg[0] & 0x10) m68k_set_irq(4);
|
||||
}
|
||||
}
|
||||
|
||||
/* Render a line of the display if needed */
|
||||
if (do_skip == 0 && !alttiming)
|
||||
{
|
||||
if (v_counter < frame_end) render_line(v_counter);
|
||||
if (v_counter < (frame_end-1)) parse_satb(0x81 + v_counter);
|
||||
}
|
||||
|
||||
/* H retrace */
|
||||
status |= 0x0004; // HBlank = 1
|
||||
m68k_run(aim_m68k - 404);
|
||||
status &= 0xFFFB; // HBlank = 0
|
||||
|
||||
if (do_skip == 0 && alttiming) /* hack for Legend of Galahad and Road Rash serie (one-line glitch)*/
|
||||
{
|
||||
if (v_counter < frame_end) render_line(v_counter);
|
||||
if (v_counter < (frame_end-1)) parse_satb(0x81 + v_counter);
|
||||
}
|
||||
|
||||
if (v_counter == frame_end)
|
||||
{
|
||||
/* V Retrace */
|
||||
status |= 0x0008; // VBlank = 1
|
||||
m68k_run(aim_m68k - 360);
|
||||
if (zreset == 1 && zbusreq == 0) z80_run(aim_z80 - 168);
|
||||
else count_z80 = aim_z80 - 168;
|
||||
|
||||
/* V Int */
|
||||
status |= 0x0080;
|
||||
vint_pending = 1;
|
||||
if (reg[1] & 0x20) m68k_set_irq(6);
|
||||
|
||||
/* Z Int */
|
||||
if (zreset == 1 && zbusreq == 0)
|
||||
{
|
||||
zirq = 1;
|
||||
z80_set_irq_line(0, ASSERT_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Process end of line */
|
||||
m68k_run(aim_m68k);
|
||||
if (zreset == 1 && zbusreq == 0) z80_run(aim_z80);
|
||||
else count_z80 = aim_z80;
|
||||
|
||||
/* Update sound buffers and timers */
|
||||
fm_update_timers (sound_inc[v_counter]);
|
||||
snd.fm.curStage = sound_tbl[v_counter];
|
||||
snd.psg.curStage = sound_tbl[v_counter];
|
||||
}
|
||||
|
||||
if (snd.enabled) audio_update ();
|
||||
return gen_running;
|
||||
}
|
||||
|
||||
#ifdef NGC
|
||||
/****************************************************************************
|
||||
* softdev - 09 Mar 2006
|
||||
*
|
||||
*
|
||||
* Nintendo Gamecube Specific Mixer from here on in ...
|
||||
****************************************************************************/
|
||||
extern unsigned char soundbuffer[16][3840];
|
||||
extern int mixbuffer;
|
||||
extern double psg_preamp;
|
||||
extern double fm_preamp;
|
||||
extern u8 boost;
|
||||
static int ll, rr;
|
||||
|
||||
void audio_update (void)
|
||||
{
|
||||
int i;
|
||||
int l, r;
|
||||
int16 *tempBuffer[2];
|
||||
int16 *sb = (int16 *) soundbuffer[mixbuffer];
|
||||
|
||||
/* get remaining samples */
|
||||
/* YM2612 */
|
||||
if (FM_GENS)
|
||||
{
|
||||
int *fmBuffer[2];
|
||||
fmBuffer[0] = snd.fm.gens_buffer[0] + snd.fm.lastStage;
|
||||
fmBuffer[1] = snd.fm.gens_buffer[1] + snd.fm.lastStage;
|
||||
YM2612_Update(fmBuffer, snd.buffer_size - snd.fm.lastStage);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage;
|
||||
tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage;
|
||||
YM2612UpdateOne (myFM, tempBuffer, snd.buffer_size - snd.fm.lastStage);
|
||||
}
|
||||
|
||||
/* PSG */
|
||||
tempBuffer[0] = snd.psg.buffer + snd.psg.lastStage;
|
||||
if (PSG_MAME) SN76496Update (0, tempBuffer[0], snd.buffer_size - snd.psg.lastStage);
|
||||
else SN76489_Update(0, tempBuffer[0], snd.buffer_size - snd.psg.lastStage);
|
||||
|
||||
/* mix samples */
|
||||
for (i = 0; i < snd.buffer_size; i ++)
|
||||
{
|
||||
/* PSG */
|
||||
l = r = (int) ((double)snd.psg.buffer[i] * psg_preamp);
|
||||
|
||||
if (FM_GENS)
|
||||
{
|
||||
l += (int) ((double)snd.fm.gens_buffer[0][i] * fm_preamp);
|
||||
r += (int) ((double)snd.fm.gens_buffer[1][i] * fm_preamp);
|
||||
snd.fm.gens_buffer[0][i] = 0;
|
||||
snd.fm.gens_buffer[1][i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
l += (int) ((double)snd.fm.buffer[0][i] * fm_preamp);
|
||||
r += (int) ((double)snd.fm.buffer[1][i] * fm_preamp);
|
||||
}
|
||||
|
||||
/* single-pole low-pass filter (6 dB/octave) */
|
||||
ll = (ll + l) >> 1;
|
||||
rr = (rr + r) >> 1;
|
||||
|
||||
l = ll * boost;
|
||||
r = rr * boost;
|
||||
|
||||
/* clipping */
|
||||
if (l > 32767) l = 32767;
|
||||
else if (l < -32768) l = -32768;
|
||||
if (r > 32767) r = 32767;
|
||||
else if (r < -32768) r = -32768;
|
||||
|
||||
*sb++ = l;
|
||||
*sb++ = r;
|
||||
}
|
||||
|
||||
mixbuffer++;
|
||||
mixbuffer &= 0xf;
|
||||
}
|
||||
#else
|
||||
void audio_update (void)
|
||||
{
|
||||
int i;
|
||||
int16 acc;
|
||||
int16 *tempBuffer[2];
|
||||
|
||||
if (FM_GENS)
|
||||
{
|
||||
int *fmBuffer[2];
|
||||
fmBuffer[0] = snd.fm.gens_buffer[0] + snd.fm.lastStage;
|
||||
fmBuffer[1] = snd.fm.gens_buffer[1] + snd.fm.lastStage;
|
||||
YM2612_Update(fmBuffer, snd.buffer_size - snd.fm.lastStage);
|
||||
}
|
||||
else
|
||||
{
|
||||
tempBuffer[0] = snd.fm.buffer[0] + snd.fm.lastStage;
|
||||
tempBuffer[1] = snd.fm.buffer[1] + snd.fm.lastStage;
|
||||
YM2612UpdateOne (myFM, tempBuffer, snd.buffer_size - snd.fm.lastStage);
|
||||
}
|
||||
|
||||
tempBuffer[0] = snd.psg.buffer + snd.psg.lastStage;
|
||||
if (PSG_MAME) SN76496Update (0, tempBuffer[0], snd.buffer_size - snd.psg.lastStage);
|
||||
else SN76489_Update(0, tempBuffer[0], snd.buffer_size - snd.psg.lastStage);
|
||||
|
||||
for (i = 0; i < snd.buffer_size; i += 1)
|
||||
{
|
||||
int16 psg = snd.psg.buffer[i] / 2;
|
||||
|
||||
acc = 0;
|
||||
acc += FM_GENS ? snd.fm.gens_buffer[0][i] : snd.fm.buffer[0][i];
|
||||
acc += psg;
|
||||
snd.buffer[0][i] = acc;
|
||||
|
||||
acc = 0;
|
||||
acc += FM_GENS ? snd.fm.gens_buffer[1][i] : snd.fm.buffer[1][i];
|
||||
acc += psg;
|
||||
snd.buffer[1][i] = acc;
|
||||
|
||||
if (FM_GENS)
|
||||
{
|
||||
snd.fm.gens_buffer[0][i] = 0;
|
||||
snd.fm.gens_buffer[1][i] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
74
source/system.h
Normal file
74
source/system.h
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
#ifndef _SYSTEM_H_
|
||||
#define _SYSTEM_H_
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8 *data; /* Bitmap data */
|
||||
int width; /* Bitmap width (32+512+32) */
|
||||
int height; /* Bitmap height (256) */
|
||||
int depth; /* Color depth (8 bits) */
|
||||
int pitch; /* Width of bitmap in bytes */
|
||||
int granularity; /* Size of each pixel in bytes */
|
||||
int remap; /* 1= Translate pixel data */
|
||||
struct
|
||||
{
|
||||
int x; /* X offset of viewport within bitmap */
|
||||
int y; /* Y offset of viewport within bitmap */
|
||||
int w; /* Width of viewport */
|
||||
int h; /* Height of viewport */
|
||||
int ow; /* Previous width of viewport */
|
||||
int oh; /* Previous height of viewport */
|
||||
int changed; /* 1= Viewport width or height have changed */
|
||||
} viewport;
|
||||
} t_bitmap;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int sample_rate; /* Sample rate (8000-44100) */
|
||||
int enabled; /* 1= sound emulation is enabled */
|
||||
int buffer_size; /* Size of sound buffer (in bytes) */
|
||||
int16 *buffer[2]; /* Signed 16-bit stereo sound data */
|
||||
struct
|
||||
{
|
||||
int curStage;
|
||||
int lastStage;
|
||||
int *gens_buffer[2];
|
||||
int16 *buffer[2];
|
||||
} fm;
|
||||
struct
|
||||
{
|
||||
int curStage;
|
||||
int lastStage;
|
||||
int16 *buffer;
|
||||
} psg;
|
||||
} t_snd;
|
||||
|
||||
/* Global variables */
|
||||
extern t_bitmap bitmap;
|
||||
extern t_snd snd;
|
||||
extern uint8 initialized;
|
||||
extern uint32 aim_m68k;
|
||||
extern uint32 count_m68k;
|
||||
extern uint32 dma_m68k;
|
||||
extern uint32 aim_z80;
|
||||
extern uint32 count_z80;
|
||||
extern uint16 misc68Kcycles;
|
||||
extern uint16 miscZ80cycles;
|
||||
extern uint16 lines_per_frame;
|
||||
extern double CPU_Clock;
|
||||
|
||||
/* Function prototypes */
|
||||
void system_init (void);
|
||||
void system_reset (void);
|
||||
void system_shutdown (void);
|
||||
int system_frame(int skip);
|
||||
void m68k_run (int cyc);
|
||||
void z80_run (int cyc);
|
||||
void m68k_freeze(int cycles);
|
||||
int audio_init (int rate);
|
||||
void audio_update (void);
|
||||
|
||||
#endif /* _SYSTEM_H_ */
|
||||
|
13
source/types.h
Normal file
13
source/types.h
Normal file
@ -0,0 +1,13 @@
|
||||
|
||||
#ifndef _TYPES_H_
|
||||
#define _TYPES_H_
|
||||
|
||||
typedef unsigned char uint8;
|
||||
typedef unsigned short int uint16;
|
||||
typedef unsigned long int uint32;
|
||||
|
||||
typedef signed char int8;
|
||||
typedef signed short int int16;
|
||||
typedef signed long int int32;
|
||||
|
||||
#endif /* _TYPES_H_ */
|
288
source/unused/dos/SEALINTF.C
Normal file
288
source/unused/dos/SEALINTF.C
Normal file
@ -0,0 +1,288 @@
|
||||
|
||||
#include "osd.h"
|
||||
|
||||
int seal_sample_rate = 44100;
|
||||
int seal_sound_card = -1;
|
||||
|
||||
HAC hVoice[NUMVOICES];
|
||||
LPAUDIOWAVE lpWave[NUMVOICES];
|
||||
AUDIOINFO info;
|
||||
AUDIOCAPS caps;
|
||||
int c[MAX_STREAM_CHANNELS];
|
||||
int nominal_sample_rate;
|
||||
static int attenuation = 0;
|
||||
static int master_volume = 256;
|
||||
|
||||
|
||||
void osd_update_audio(void)
|
||||
{
|
||||
if (seal_sample_rate == 0) return;
|
||||
AUpdateAudio();
|
||||
}
|
||||
|
||||
|
||||
/* attenuation in dB */
|
||||
void osd_set_mastervolume(int _attenuation)
|
||||
{
|
||||
float volume;
|
||||
|
||||
attenuation = _attenuation;
|
||||
|
||||
volume = 256.0; /* range is 0-256 */
|
||||
while (_attenuation++ < 0)
|
||||
volume /= 1.122018454; /* = (10 ^ (1/20)) = 1dB */
|
||||
|
||||
master_volume = volume;
|
||||
|
||||
ASetAudioMixerValue(AUDIO_MIXER_MASTER_VOLUME,master_volume);
|
||||
}
|
||||
|
||||
|
||||
int msdos_init_sound(int *rate, int card)
|
||||
{
|
||||
int i;
|
||||
|
||||
seal_sample_rate = *rate;
|
||||
seal_sound_card = card;
|
||||
|
||||
if (AInitialize() != AUDIO_ERROR_NONE)
|
||||
return 1;
|
||||
|
||||
/* Ask the user if no sound card was chosen */
|
||||
if (seal_sound_card == -1)
|
||||
{
|
||||
unsigned int k;
|
||||
|
||||
printf("\n SELECT YOUR AUDIO DEVICE :\n\n"
|
||||
" AWE32/64 playback requires onboard DRAM,\n"
|
||||
" Sound Blaster playback is the most compatible & better for emulation\n\n");
|
||||
|
||||
for (k = 0;k < AGetAudioNumDevs();k++)
|
||||
{
|
||||
if (AGetAudioDevCaps(k,&caps) == AUDIO_ERROR_NONE)
|
||||
printf(" %2d. %s\n",k,caps.szProductName);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (k < 10)
|
||||
{
|
||||
i = getch();
|
||||
seal_sound_card = i - '0';
|
||||
}
|
||||
else
|
||||
scanf("%d",&seal_sound_card);
|
||||
}
|
||||
|
||||
/* initialize SEAL audio library */
|
||||
if (seal_sound_card == 0) /* silence */
|
||||
{
|
||||
/* update the Machine structure to show that sound is disabled */
|
||||
seal_sample_rate = 0;
|
||||
exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* open audio device */
|
||||
/* info.nDeviceId = AUDIO_DEVICE_MAPPER;*/
|
||||
info.nDeviceId = seal_sound_card;
|
||||
/* always use 16 bit mixing if possible - better quality and same speed of 8 bit */
|
||||
info.wFormat = AUDIO_FORMAT_16BITS | AUDIO_FORMAT_STEREO | AUDIO_FORMAT_RAW_SAMPLE;
|
||||
|
||||
info.nSampleRate = seal_sample_rate;
|
||||
if (AOpenAudio(&info) != AUDIO_ERROR_NONE)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
AGetAudioDevCaps(info.nDeviceId,&caps);
|
||||
printf("Using `%s' at %d-bit %s %u Hz\n",
|
||||
caps.szProductName,
|
||||
info.wFormat & AUDIO_FORMAT_16BITS ? 16 : 8,
|
||||
info.wFormat & AUDIO_FORMAT_STEREO ? "stereo" : "mono",
|
||||
info.nSampleRate);
|
||||
|
||||
/* open and allocate voices, allocate waveforms */
|
||||
if (AOpenVoices(NUMVOICES) != AUDIO_ERROR_NONE)
|
||||
{
|
||||
printf("voices initialization failed\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUMVOICES; i++)
|
||||
{
|
||||
if (ACreateAudioVoice(&hVoice[i]) != AUDIO_ERROR_NONE)
|
||||
{
|
||||
printf("voice #%d creation failed\n",i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ASetVoicePanning(hVoice[i],128);
|
||||
|
||||
lpWave[i] = 0;
|
||||
}
|
||||
|
||||
/* update the Machine structure to reflect the actual sample rate */
|
||||
*rate = seal_sample_rate = info.nSampleRate;
|
||||
|
||||
{
|
||||
uclock_t a,b;
|
||||
LONG start,end;
|
||||
|
||||
|
||||
if ((lpWave[0] = (LPAUDIOWAVE)malloc(sizeof(AUDIOWAVE))) == 0)
|
||||
return 1;
|
||||
|
||||
lpWave[0]->wFormat = AUDIO_FORMAT_8BITS | AUDIO_FORMAT_MONO;
|
||||
lpWave[0]->nSampleRate = seal_sample_rate;
|
||||
lpWave[0]->dwLength = 3*seal_sample_rate;
|
||||
lpWave[0]->dwLoopStart = 0;
|
||||
lpWave[0]->dwLoopEnd = 3*seal_sample_rate;
|
||||
if (ACreateAudioData(lpWave[0]) != AUDIO_ERROR_NONE)
|
||||
{
|
||||
free(lpWave[0]);
|
||||
lpWave[0] = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
memset(lpWave[0]->lpData,0,3*seal_sample_rate);
|
||||
/* upload the data to the audio DRAM local memory */
|
||||
AWriteAudioData(lpWave[0],0,3*seal_sample_rate);
|
||||
APrimeVoice(hVoice[0],lpWave[0]);
|
||||
ASetVoiceFrequency(hVoice[0],seal_sample_rate);
|
||||
ASetVoiceVolume(hVoice[0],0);
|
||||
AStartVoice(hVoice[0]);
|
||||
|
||||
a = uclock();
|
||||
/* wait some time to let everything stabilize */
|
||||
do
|
||||
{
|
||||
osd_update_audio();
|
||||
b = uclock();
|
||||
} while (b-a < UCLOCKS_PER_SEC/10);
|
||||
|
||||
a = uclock();
|
||||
AGetVoicePosition(hVoice[0],&start);
|
||||
do
|
||||
{
|
||||
osd_update_audio();
|
||||
b = uclock();
|
||||
} while (b-a < UCLOCKS_PER_SEC);
|
||||
AGetVoicePosition(hVoice[0],&end);
|
||||
|
||||
nominal_sample_rate = seal_sample_rate;
|
||||
seal_sample_rate = end - start;
|
||||
|
||||
AStopVoice(hVoice[0]);
|
||||
ADestroyAudioData(lpWave[0]);
|
||||
free(lpWave[0]);
|
||||
lpWave[0] = 0;
|
||||
}
|
||||
|
||||
osd_set_mastervolume(0); /* start at maximum volume */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void msdos_shutdown_sound(void)
|
||||
{
|
||||
if (seal_sample_rate != 0)
|
||||
{
|
||||
int n;
|
||||
|
||||
/* stop and release voices */
|
||||
for (n = 0; n < NUMVOICES; n++)
|
||||
{
|
||||
AStopVoice(hVoice[n]);
|
||||
ADestroyAudioVoice(hVoice[n]);
|
||||
if (lpWave[n])
|
||||
{
|
||||
ADestroyAudioData(lpWave[n]);
|
||||
free(lpWave[n]);
|
||||
lpWave[n] = 0;
|
||||
}
|
||||
}
|
||||
ACloseVoices();
|
||||
ACloseAudio();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void playstreamedsample(int channel,signed char *data,int len,int freq,int volume,int pan,int bits)
|
||||
{
|
||||
static int playing[NUMVOICES];
|
||||
static int c[NUMVOICES];
|
||||
|
||||
/* backwards compatibility with old 0-255 volume range */
|
||||
if (volume > 100) volume = volume * 25 / 255;
|
||||
|
||||
if (seal_sample_rate == 0 || channel >= NUMVOICES) return;
|
||||
|
||||
if (!playing[channel])
|
||||
{
|
||||
if (lpWave[channel])
|
||||
{
|
||||
AStopVoice(hVoice[channel]);
|
||||
ADestroyAudioData(lpWave[channel]);
|
||||
free(lpWave[channel]);
|
||||
lpWave[channel] = 0;
|
||||
}
|
||||
|
||||
if ((lpWave[channel] = (LPAUDIOWAVE)malloc(sizeof(AUDIOWAVE))) == 0)
|
||||
return;
|
||||
|
||||
lpWave[channel]->wFormat = (bits == 8 ? AUDIO_FORMAT_8BITS : AUDIO_FORMAT_16BITS)
|
||||
| AUDIO_FORMAT_MONO | AUDIO_FORMAT_LOOP;
|
||||
lpWave[channel]->nSampleRate = nominal_sample_rate;
|
||||
lpWave[channel]->dwLength = 3*len;
|
||||
lpWave[channel]->dwLoopStart = 0;
|
||||
lpWave[channel]->dwLoopEnd = 3*len;
|
||||
if (ACreateAudioData(lpWave[channel]) != AUDIO_ERROR_NONE)
|
||||
{
|
||||
free(lpWave[channel]);
|
||||
lpWave[channel] = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
memset(lpWave[channel]->lpData,0,3*len);
|
||||
memcpy(lpWave[channel]->lpData,data,len);
|
||||
/* upload the data to the audio DRAM local memory */
|
||||
AWriteAudioData(lpWave[channel],0,3*len);
|
||||
APrimeVoice(hVoice[channel],lpWave[channel]);
|
||||
/* need to cast to double because freq*nominal_sample_rate can exceed the size of an int */
|
||||
ASetVoiceFrequency(hVoice[channel],(double)freq*nominal_sample_rate/seal_sample_rate);
|
||||
AStartVoice(hVoice[channel]);
|
||||
playing[channel] = 1;
|
||||
c[channel] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
LONG pos;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
AGetVoicePosition(hVoice[channel],&pos);
|
||||
if (c[channel] == 0 && pos >= len) break;
|
||||
if (c[channel] == 1 && (pos < len || pos >= 2*len)) break;
|
||||
if (c[channel] == 2 && pos < 2*len) break;
|
||||
osd_update_audio();
|
||||
}
|
||||
|
||||
memcpy(&lpWave[channel]->lpData[len * c[channel]],data,len);
|
||||
AWriteAudioData(lpWave[channel],len*c[channel],len);
|
||||
c[channel]++;
|
||||
if (c[channel] == 3) c[channel] = 0;
|
||||
}
|
||||
|
||||
|
||||
ASetVoiceVolume(hVoice[channel],volume * 64 / 100);
|
||||
ASetVoicePanning(hVoice[channel],(pan + 100) * 255 / 200);
|
||||
}
|
||||
|
||||
void osd_play_streamed_sample_16(int channel,signed short *data,int len,int freq,int volume,int pan)
|
||||
{
|
||||
playstreamedsample(channel,(signed char *)data,len,freq,volume,pan,16);
|
||||
}
|
||||
|
17
source/unused/dos/SEALINTF.H
Normal file
17
source/unused/dos/SEALINTF.H
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
#ifndef _SEALINTF_H_
|
||||
#define _SEALINTF_H_
|
||||
|
||||
#define MAX_SOUND 4
|
||||
#define NUMVOICES 16
|
||||
#define MAX_STREAM_CHANNELS 6
|
||||
|
||||
/* Function prototypes */
|
||||
void osd_update_audio(void);
|
||||
void osd_set_mastervolume(int _attenuation);
|
||||
int msdos_init_sound(int *rate, int card);
|
||||
void msdos_shutdown_sound(void);
|
||||
void playstreamedsample(int channel,signed char *data,int len,int freq,int volume,int pan,int bits);
|
||||
void osd_play_streamed_sample_16(int channel,signed short *data,int len,int freq,int volume,int pan);
|
||||
|
||||
#endif /* _SEALINTF_H_ */
|
256
source/unused/dos/config.c
Normal file
256
source/unused/dos/config.c
Normal file
@ -0,0 +1,256 @@
|
||||
|
||||
#include "osd.h"
|
||||
|
||||
t_option option;
|
||||
|
||||
void do_config(char *file)
|
||||
{
|
||||
extern int __crt0_argc;
|
||||
extern char **__crt0_argv;
|
||||
|
||||
/* Our token list */
|
||||
int i, argc;
|
||||
char *argv[TOKEN_LIST_SIZE];
|
||||
|
||||
set_option_defaults();
|
||||
for(i = 0; i < TOKEN_LIST_SIZE; i += 1) argv[i] = NULL;
|
||||
|
||||
/* Check configuration file */
|
||||
if(file) parse_file(file, &argc, argv);
|
||||
|
||||
/* Check extracted tokens */
|
||||
parse_args(argc, argv);
|
||||
|
||||
/* Free token list */
|
||||
for(i = 0; i < argc; i += 1) if(argv[argc]) free (argv[argc]);
|
||||
|
||||
/* Check command line */
|
||||
parse_args(__crt0_argc, __crt0_argv);
|
||||
}
|
||||
|
||||
|
||||
/* Parse configuration file */
|
||||
int parse_file(char *filename, int *argc, char **argv)
|
||||
{
|
||||
char token[0x100];
|
||||
FILE *handle = NULL;
|
||||
|
||||
*argc = 0;
|
||||
handle = fopen(filename, "r");
|
||||
if(!handle) return (0);
|
||||
|
||||
fscanf(handle, "%s", &token[0]);
|
||||
while(!(feof(handle)))
|
||||
{
|
||||
int size = strlen(token) + 1;
|
||||
argv[*argc] = malloc(size);
|
||||
if(!argv[*argc]) return (0);
|
||||
strcpy(argv[*argc], token);
|
||||
*argc += 1;
|
||||
fscanf(handle, "%s", &token[0]);
|
||||
}
|
||||
|
||||
if(handle) fclose(handle);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
int check_bool(char *token)
|
||||
{
|
||||
int result = 1;
|
||||
if(stricmp("off", token) == 0)
|
||||
result = 0;
|
||||
if(stricmp("no", token) == 0)
|
||||
result = 0;
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
void set_option_defaults(void)
|
||||
{
|
||||
option.video_driver = GFX_AUTODETECT;
|
||||
option.video_width = 320;
|
||||
option.video_height = 240;
|
||||
option.video_depth = 8;
|
||||
|
||||
option.remap = 0;
|
||||
option.scanlines = 0;
|
||||
option.scale = 0;
|
||||
|
||||
option.vsync = 0;
|
||||
option.throttle = 0;
|
||||
option.skip = 1;
|
||||
|
||||
option.sound = 0;
|
||||
option.sndcard = -1;
|
||||
option.sndrate = 44100;
|
||||
option.swap = 0;
|
||||
|
||||
option.joy_driver = JOY_TYPE_AUTODETECT;
|
||||
}
|
||||
|
||||
|
||||
void print_options(void)
|
||||
{
|
||||
printf(" -vdriver <s> \t Select video driver (auto)\n");
|
||||
printf(" -res <w> <h> \t Specify display resolution (320x240)\n");
|
||||
printf(" -depth <n> \t Specify display depth (8)\n");
|
||||
printf(" -remap <on|off> \t Enable raster-based palette effects (8-bit color only)\n");
|
||||
printf(" -scanlines <on|off> \t Enable scanlines effect\n");
|
||||
printf(" -scale <on|off> \t Scale display to width of screen\n");
|
||||
printf(" -vsync <on|off> \t Enable vsync polling\n");
|
||||
printf(" -throttle <on|off> \t Enable speed throttling\n");
|
||||
printf(" -skip <n> \t Specify frame skip level (1=no frames skipped)\n");
|
||||
printf(" -sound <on|off> \t Enable sound output\n");
|
||||
printf(" -sndcard <n> \t Select sound card\n");
|
||||
printf(" -sndrate <n> \t Specify sound sample rate (8000-44100)\n");
|
||||
printf(" -swap <on|off> \t Swap left and right channels\n");
|
||||
printf(" -joy <s> \t Select joystick driver (auto)\n");
|
||||
}
|
||||
|
||||
|
||||
void parse_args(int argc, char **argv)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for(i = 0; i < argc; i += 1)
|
||||
{
|
||||
if(stricmp("-vdriver", argv[i]) == 0)
|
||||
{
|
||||
for(j = 0; video_driver_table[j].token != NULL; j += 1)
|
||||
{
|
||||
if(stricmp(argv[i+1], video_driver_table[j].token) == 0)
|
||||
{
|
||||
option.video_driver = video_driver_table[j].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(stricmp("-res", argv[i]) == 0)
|
||||
{
|
||||
option.video_width = atoi(argv[i+1]);
|
||||
option.video_height = atoi(argv[i+2]);
|
||||
}
|
||||
|
||||
if(stricmp("-depth", argv[i]) == 0)
|
||||
{
|
||||
option.video_depth = atoi(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-remap", argv[i]) == 0)
|
||||
{
|
||||
option.remap = check_bool(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-scanlines", argv[i]) == 0)
|
||||
{
|
||||
option.scanlines = check_bool(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-scale", argv[i]) == 0)
|
||||
{
|
||||
option.scale = check_bool(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-vsync", argv[i]) == 0)
|
||||
{
|
||||
option.vsync = check_bool(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-throttle", argv[i]) == 0)
|
||||
{
|
||||
option.throttle = check_bool(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-skip", argv[i]) == 0)
|
||||
{
|
||||
option.skip = atoi(argv[i+1]);
|
||||
if(!option.skip) option.skip = 1;
|
||||
}
|
||||
|
||||
if(stricmp("-sound", argv[i]) == 0)
|
||||
{
|
||||
option.sound = check_bool(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-sndcard", argv[i]) == 0)
|
||||
{
|
||||
option.sndcard = atoi(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-sndrate", argv[i]) == 0)
|
||||
{
|
||||
option.sndrate = atoi(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-swap", argv[i]) == 0)
|
||||
{
|
||||
option.swap = check_bool(argv[i+1]);
|
||||
}
|
||||
|
||||
if(stricmp("-joy", argv[i]) == 0)
|
||||
{
|
||||
for(j = 0; joy_driver_table[j].token != NULL; j += 1)
|
||||
{
|
||||
if(stricmp(argv[i+1], joy_driver_table[j].token) == 0)
|
||||
{
|
||||
option.joy_driver = joy_driver_table[j].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(option.remap) option.video_depth = 8;
|
||||
}
|
||||
|
||||
|
||||
t_strint video_driver_table[] =
|
||||
{
|
||||
{ "auto", GFX_AUTODETECT },
|
||||
{ "safe", GFX_SAFE },
|
||||
{ "vga", GFX_VGA },
|
||||
{ "modex", GFX_MODEX },
|
||||
{ "vesa2l", GFX_VESA2L },
|
||||
{ "vesa3", GFX_VESA3 },
|
||||
{ "vbeaf", GFX_VBEAF },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
|
||||
t_strint joy_driver_table[] =
|
||||
{
|
||||
{ "auto", JOY_TYPE_AUTODETECT },
|
||||
{ "none", JOY_TYPE_NONE },
|
||||
{ "standard", JOY_TYPE_STANDARD },
|
||||
{ "2pads", JOY_TYPE_2PADS },
|
||||
{ "4button", JOY_TYPE_4BUTTON },
|
||||
{ "6button", JOY_TYPE_6BUTTON },
|
||||
{ "8button", JOY_TYPE_8BUTTON },
|
||||
{ "fspro", JOY_TYPE_FSPRO },
|
||||
{ "wingex", JOY_TYPE_WINGEX },
|
||||
{ "sidewinder", JOY_TYPE_SIDEWINDER },
|
||||
{ "gamepadpro", JOY_TYPE_GAMEPAD_PRO },
|
||||
{ "grip", JOY_TYPE_GRIP },
|
||||
{ "grip4", JOY_TYPE_GRIP4 },
|
||||
{ "sneslpt1", JOY_TYPE_SNESPAD_LPT1 },
|
||||
{ "sneslpt2", JOY_TYPE_SNESPAD_LPT2 },
|
||||
{ "sneslpt3", JOY_TYPE_SNESPAD_LPT3 },
|
||||
{ "psxlpt1", JOY_TYPE_PSXPAD_LPT1 },
|
||||
{ "psxlpt2", JOY_TYPE_PSXPAD_LPT2 },
|
||||
{ "psxlpt3", JOY_TYPE_PSXPAD_LPT3 },
|
||||
{ "n64lpt1", JOY_TYPE_N64PAD_LPT1 },
|
||||
{ "n64lpt2", JOY_TYPE_N64PAD_LPT2 },
|
||||
{ "n64lpt3", JOY_TYPE_N64PAD_LPT3 },
|
||||
{ "db9lpt1", JOY_TYPE_DB9_LPT1 },
|
||||
{ "db9lpt2", JOY_TYPE_DB9_LPT2 },
|
||||
{ "db9lpt3", JOY_TYPE_DB9_LPT3 },
|
||||
{ "tglpt1", JOY_TYPE_TURBOGRAFX_LPT1 },
|
||||
{ "tglpt2", JOY_TYPE_TURBOGRAFX_LPT2 },
|
||||
{ "tglpt3", JOY_TYPE_TURBOGRAFX_LPT3 },
|
||||
{ "wingwar", JOY_TYPE_WINGWARRIOR },
|
||||
{ "segaisa", JOY_TYPE_IFSEGA_ISA},
|
||||
{ "segapci", JOY_TYPE_IFSEGA_PCI},
|
||||
{ "segapci2", JOY_TYPE_IFSEGA_PCI_FAST},
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user