mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-25 02:31:49 +01:00
Removed file/folder
This commit is contained in:
parent
756afc1458
commit
cf5e1dda45
@ -1,174 +0,0 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
# 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 source/ngc/vfat
|
||||
INCLUDES := source source/m68k source/cpu source/sound \
|
||||
source/ngc source/ngc/gui source/ngc/vfat
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
MACHDEP = -DGEKKO -mcpu=750 -meabi -mhard-float
|
||||
CFLAGS = -g -O2 -Wall $(MACHDEP) $(INCLUDE) -DWORDS_BIGENDIAN \
|
||||
-DNGC="1" -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
|
||||
#---------------------------------------------------------------------------------
|
@ -1,143 +0,0 @@
|
||||
The Genesis Plus Project
|
||||
------------------------------
|
||||
|
||||
CHANGELOG:
|
||||
|
||||
[Genesis]
|
||||
- improved big endian support in render.c and vdp.c
|
||||
- fixed leftmost window/nta column renderer and implemented window bug (documented in genvdp.txt)
|
||||
- fixed border color update
|
||||
- fixed VDP address register latch
|
||||
- corrected VRAM access timing so that it does not interfere with DMA timing anymore
|
||||
- fixed READ_xxx and WRITE_xxx macros for portability
|
||||
- added internal game database to detect games using serial EEPROM as backup RAM
|
||||
- completely rewrote EEPROM emulation to support each known EEPROM types (24C01-24C65) and mappers (Sega, EA, Acclaim, Codemasters).
|
||||
This should fix SRAM support in the following games:
|
||||
. Rings of Power, NHLPA Hockey 93 (EA mapper)
|
||||
. NBA Jam (alternate Acclaim mapper)
|
||||
. College Slam, Frank Thomas Big Hurt Baseball (24C65)
|
||||
. Micro Machines serie (Codemasters mapper)
|
||||
|
||||
|
||||
|
||||
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 for big endian platform (fix Contra Hardcorps gfx garbage)
|
||||
|
||||
|
||||
Based on Softdev's initial releases
|
||||
|
||||
|
||||
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
|
@ -1,359 +0,0 @@
|
||||
×××-–—————————————————————————————————-———————————————————————————————————-×××
|
||||
|
||||
·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 Joypad 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 (Megaman Willy Wars, NBA JAM, Wonderboy in Monsterworld...)
|
||||
• Banked ROM support (Super Street Fighter 2)
|
||||
• Banked SRAM support (Phantasy Star 4)
|
||||
• Game Genie Codes support
|
||||
• ROM Information Screen
|
||||
• Zipped Roms support
|
||||
• Interleaved (.smd) Roms support
|
||||
• Load game 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
|
||||
• SDLOAD or IPL reboot option
|
||||
|
||||
|
||||
|
||||
ø°º–––————————————————————————————————————————————————————————————————————×·.
|
||||
°Ø¨–; ×-× 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
|
||||
• Notaz for Picodrive's (Sega Genesis/MegaCD Emulator for GP2X) sourcecode from which
|
||||
unlicensed games support and Virtua racing SVP faking has been taken.
|
||||
|
||||
(see /doc for original credits)
|
||||
|
||||
|
||||
×××-–—————————————————————————————————-———————————————————————————————————-×××
|
@ -1,3 +0,0 @@
|
||||
inject: inject.c
|
||||
@gcc -O2 -Wall inject.c -o inject
|
||||
@strip inject
|
@ -1,154 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
Binary file not shown.
@ -1,30 +0,0 @@
|
||||
|
||||
#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 */
|
@ -1,342 +0,0 @@
|
||||
#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);
|
@ -1,183 +0,0 @@
|
||||
/* ======================================================================== */
|
||||
/* ========================= 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 */
|
@ -1,77 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* 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 */
|
File diff suppressed because it is too large
Load Diff
@ -1,62 +0,0 @@
|
||||
#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
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,373 +0,0 @@
|
||||
|
||||
THE COMPLETE DOCUMENTATION ABOUT
|
||||
GENESIS ROM FORMAT
|
||||
|
||||
Version 1.1
|
||||
|
||||
|
||||
Release history
|
||||
^^^^^^^^^^^^^^^
|
||||
Version 1.0 (December, 1997)
|
||||
- Initial Release
|
||||
|
||||
Version 1.1 (January, 1998)
|
||||
- Splitted rom format explained!
|
||||
- New company codes
|
||||
- New errors in copyright interpreting found <sigh>
|
||||
- Month interpreting (in copyright)
|
||||
|
||||
|
||||
In this document you will find everything you need to know about
|
||||
the information embedded within a Genesis ROM. You will also find
|
||||
how to read all this information from the different ROM formats
|
||||
(BIN, SMD and MD).
|
||||
The information in this document was hacked by Volker Oth (dOnut)
|
||||
and by me with help from technical documents found on internet.
|
||||
The primary document from the internet that we used was gentech.txt.
|
||||
If you want to change this document to add any important info about
|
||||
the Genesis ROMs, do it freely but I would like to receive a copy of
|
||||
the updated document. Then, I'll add your name in it and post it on my
|
||||
homepage. Don't be a lamer and keep all names mentioned here!
|
||||
Note that all numbers with a "H" in the left are in hexadecimal, and
|
||||
the first byte of a file is the ZERO position. All information is
|
||||
provided based on the BIN file-format because of the nature of this
|
||||
format(see sections about each rom format).
|
||||
*This document should be downloaded from my homepage. Any other site
|
||||
may contain outdated material!*
|
||||
If you use this information for anything, please give the proper
|
||||
credits to the all these names listed below! I would thank you if you
|
||||
include a link to our homepages and emails, too!
|
||||
|
||||
Felipe XnaK:
|
||||
http://www.classicgaming.com/launchtool
|
||||
felipe@ComPorts.com
|
||||
Volker Oth (dOnut):
|
||||
http://members.aol.com/~volkeroth
|
||||
volkeroth@aol.com
|
||||
|
||||
|
||||
THE BASIC INFORMATION:
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
H100: 'SEGA MEGA DRIVE' 1
|
||||
H110: '(C)SEGA 1988.JUL' 2
|
||||
H120: GAME NAME (DOMESTIC) 3
|
||||
H150: GAME NAME (OVERSEAS) 4
|
||||
H180: 'XX' 5
|
||||
H182: 'XXXXXXX-XX' 6
|
||||
H18E: XXXX 7
|
||||
H190: 'XXXXXXXXXXXXXXXX' 8
|
||||
H1A0: 00000000, XXXXXXXX 9
|
||||
H1A8: RAM 10
|
||||
H1BC: MODEM DATA 11
|
||||
H1C8: MEMO 12
|
||||
H1F0: Country in which the product 13
|
||||
can be released.
|
||||
|
||||
1: This is just the console name. It can be 'SEGA MEGA DRIVE' or
|
||||
'SEGA GENESIS' depending on the console's country of origin.
|
||||
|
||||
2: Copyright notice. There SHOULD be 4 characters for the company
|
||||
code, a space and then the date in yyyy.mmm format; however, there are
|
||||
variations.
|
||||
For a listing of company codes, see "TABLE OF COMPANY CODES".
|
||||
For a listing of month abbreviations, se "TABLE OF MONTH ABBREVIATIONS".
|
||||
When the company uses a number as a company code, the copyright has
|
||||
(in most cases!) this format: '(C)T-XX 1988.JUL', where XX is the
|
||||
company code. If the company code has three digits, it should use the
|
||||
space between the code and the date.
|
||||
Some wrong copyrights i've found:
|
||||
* The year is written as '199X' or '19XX', or doen't include the
|
||||
millenium and the century.
|
||||
* The company name is '00' or 'XX'
|
||||
* Some companies that use a number for company code overwrite the
|
||||
hiphen, not the space.
|
||||
* Some companies doesn't include the '(C)' in the beginning and
|
||||
others include just their name; some just include the the year
|
||||
* Some copyrights have the year and month separated by ',','/', '-',
|
||||
space or null character (H00). I'd found one that hasn't any separator
|
||||
at all!
|
||||
-- Good luck! --
|
||||
|
||||
3: This is the so-called "Domestic game name". Is the name the game has
|
||||
in its country of origin. This field is 48 bytes long...
|
||||
|
||||
4: ... and this is the so-called "Overseas game name". This is the name
|
||||
the game has worldwide. 48 bytes long too.
|
||||
|
||||
5: Type of product. This is 2 bytes long. Known values:
|
||||
GM = Game
|
||||
Al = Education
|
||||
|
||||
6: Product code and Version number:
|
||||
* The first 7 characters are the product code
|
||||
* The 2 characters after the hiphen is the version number. This will
|
||||
vary depending on the the type of ROM or software version
|
||||
|
||||
7: Check sum, a two-bytes value (see "Calculating the Checksum")
|
||||
|
||||
8: I/0 support: (this is 16 bytes long)
|
||||
J = Joypad 4 = Team Play
|
||||
6 = 6-button Joypad 0 = Joystick for MS
|
||||
K = Keyboard R = Serial RS232C
|
||||
P = Printer T = Tablet
|
||||
B = Control Ball V = Paddle Controller
|
||||
F = Floppy Disk Drive C = CD-ROM
|
||||
L = Activator M = Mega Mouse
|
||||
|
||||
9: ROM capacity. Here you will find the start and end address of the rom,
|
||||
respectively. The start address in most cases is 0 and the end address is
|
||||
the size of rom in BYTES. Note that these values don't include the headers
|
||||
that some rom images have (discussed later). Each address is 4-bytes long.
|
||||
|
||||
10: There is a lot of information here that I can't help you with. What
|
||||
I can say is that you can get the start and end positions of the backup
|
||||
RAM at offset H1B4. Like in ROM addresses, you first acquire the start,
|
||||
then the end address. Remember, these addresses are four bytes each.
|
||||
|
||||
11: If the rom has no support for MODEM, fill this with spaces. If it has
|
||||
support for MODEM, then fill in this format: 'MOxxxxyy.z', where:
|
||||
xxxx Firm name the same as in 2
|
||||
yy MODEM NO.
|
||||
z Version
|
||||
|
||||
12: I don't know what the heck it is! But by it's name and considering
|
||||
all roms that I investigated, it seems that you can write whatever you want
|
||||
in this field...
|
||||
|
||||
13: Countries where the game can be released. What is most interesting
|
||||
here is that changing this info in some games has different behaviour.
|
||||
Streets of Rage, for example, automatically changes it's name for Bare
|
||||
Knuckle if you set the game for Japan. The "official" codes are:
|
||||
E = Europe
|
||||
J = Japan
|
||||
U = USA
|
||||
I've found some others as well(I do not guarantee this is correct!)
|
||||
A = Asia
|
||||
B = Brazil
|
||||
4 = Brazil
|
||||
F = France
|
||||
8 = Hong Kong
|
||||
This field can only contain three countries. This isn't really a
|
||||
problem because all "unofficial" codes run as Europe! Don't forget to
|
||||
set spaces to fill the bytes you don't use in this field.
|
||||
|
||||
|
||||
TABLE OF COMPANY CODES:
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This table was compiled by myself by just getting the company code
|
||||
in the ROM and writing the license that appears on the tittle screen.
|
||||
In other words, it probably contains errors and is missing a lot of
|
||||
companies.
|
||||
When two comp1anies use the same code and are different companies
|
||||
(at least to my knownledge) the names are separeted by an "or". If the
|
||||
companies are the same (like Acclain and Flying Edge), they're separated
|
||||
by a backslash (/).
|
||||
|
||||
CODE COMPANY
|
||||
|
||||
ACLD Ballistic
|
||||
ASCI Asciiware
|
||||
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 Eletronic 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
|
||||
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
|
||||
239 Disney Interactive
|
||||
|
||||
- SPECIAL CASES:
|
||||
|
||||
In "Smurfs II" the copyright is just '(C) INFOGRAMES'
|
||||
In "Baby's day out" rom, the copyright is: '(C) T-SNK 95-FEB',
|
||||
but the company name is "HI-TECH entertainment" <sigh>
|
||||
|
||||
|
||||
TABLE OF MONTH ABBREVIATIONS:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
ABBREVIATIONS MONTH
|
||||
|
||||
JAN January
|
||||
FEB February
|
||||
MAR March
|
||||
APR or APL April
|
||||
MAY May
|
||||
JUN June
|
||||
JUL July
|
||||
AUG or 08 August
|
||||
SEP or SEPT September
|
||||
OCT October
|
||||
NOV November
|
||||
DEC December
|
||||
|
||||
|
||||
CALCULATING THE CHECKSUM:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Genesis checksum is simple enough... All you need to do is:
|
||||
1) Checksum starts as zero
|
||||
2) Skip the first 512 bytes of the ROM
|
||||
3) Read a byte from the rom and multiply its ascii value by 256, then sum
|
||||
it to the checksum
|
||||
4) Read the next byte from the rom and just sum it to the checksum
|
||||
5) If you're not in the end of file, goto step 3
|
||||
6) Get the first 16 bits from the resulting checksum and discard the higher
|
||||
bits
|
||||
7) That's your checksum!
|
||||
|
||||
|
||||
Super Magic Drive Binary file-format (.BIN):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This rom file-format is a simple rom dump. Nothing more to add!
|
||||
|
||||
|
||||
Super Magic Drive Interleaved file-format (.SMD):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This is a much more complex file-format. It have a 512 bytes header
|
||||
and is interleaved in 16KB blocks. These blocks have their even bytes
|
||||
at the beginning and the odd bytes at the end of them.
|
||||
|
||||
WHAT YOU FIND IN THE 512 BYTES HEADER:
|
||||
|
||||
0: Number of blocks 1
|
||||
1: H03 *
|
||||
2: SPLIT? 2
|
||||
8: HAA *
|
||||
9: HBB *
|
||||
ALL OTHER BYTES: H00
|
||||
|
||||
1: This first byte should have the number of 16KB blocks the rom has.
|
||||
The header isn't part of the formula, so this number is:
|
||||
[size of rom-512]/16386
|
||||
If the size is more than 255, the value should be H00.
|
||||
|
||||
2: This byte indicates if the ROM is a part of a splitted rom series. If
|
||||
the rom is the last part of the series (or isn't a splitted rom at all),
|
||||
this byte should be H00. In other cases should be H40. See "CREATING
|
||||
SPLITTED ROMS" for details on this format.
|
||||
|
||||
*: Fixed values
|
||||
|
||||
|
||||
THE DE-INTERLEAVING CODE (how to convert a SMD to a BIN):
|
||||
|
||||
1) Skip the 512 bytes header
|
||||
2) Get 16KB from the ROM (16384 bytes)
|
||||
3) Decode the block
|
||||
4) Write the decoded block to the BIN file
|
||||
|
||||
DECODING A SMD BLOCK (stating byte is 0):
|
||||
|
||||
1) Get Middlepoint (8192)
|
||||
2) Get a byte from the block
|
||||
3) If the byte position is equal or smaller than middlepoint, put it
|
||||
in the first unused EVEN position of the decoded buffer
|
||||
4) If the byte position is greater than middlepoint, put it in the
|
||||
first unused ODD position of the decoded buffer
|
||||
|
||||
To convert a BIN to a SMD, just create a header (as explained before) and
|
||||
then do the reverse process!
|
||||
|
||||
|
||||
Multi Game Doctor file-format (.MD):
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The MD file format also doesn't have a header. The interleaving it uses
|
||||
is equal to the SMD, but without the division in blocks! (Even bytes in
|
||||
the end of file, odd bytes in the beginning).
|
||||
|
||||
THE DECODING A MD (how to convert a MD to a BIN):
|
||||
|
||||
1) Get middlepoint ([size of rom]/2)
|
||||
2) Get a byte from the ROM
|
||||
3) If the byte position is equal or smaller than the middlepoint put the
|
||||
byte in [byte position]*2 of the destination buffer
|
||||
4) If the byte position is greater than the middlepoint, put the byte in
|
||||
([byte position]*2) - [size of rom] -1
|
||||
|
||||
|
||||
CREATING SPLITTED ROMS:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Splitted ROMs are a SMD divided into pieces. Knowing this, you may
|
||||
guess that you first need to convert your ROM to a SMD! :)
|
||||
To have a splitted ROM created all you need is divide your SMD in
|
||||
several pieces, usually all with the same size (with the exception of
|
||||
the last one). After doing that, you need to add a SMD header to all
|
||||
these pieces. About these SMD headers:
|
||||
1) The number of blocks embedded in them should be relative to the
|
||||
piece, not to the joined ROM.
|
||||
2) As stated before, with the exception of the last piece, all roms
|
||||
should have their SPLIT byte set.
|
||||
|
||||
|
||||
HOW YOU CAN HELP ME WITH THIS DOCUMENT:
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
- Telling me the intricacies of a MGD ROM image. I never found one, but
|
||||
I do believe it's equal to MD format.
|
||||
- I'm trying to find out how the sprites are saved in Genesis ROMs. If
|
||||
you have this info, I would like to have it!
|
||||
- I never had a rom with modem support. If you have one, please test if
|
||||
the information about it is correct in this documentation (I got it from
|
||||
gentech). If you find it's correct, please explain me!!!
|
||||
|
||||
If you have any of this information, send it with your addresses (e-mail,
|
||||
homepage, etc) so I can add this to the document!
|
@ -1,22 +0,0 @@
|
||||
|
||||
[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.
|
||||
|
@ -1,232 +0,0 @@
|
||||
This is the result of testing EEPROM support under Genesis Plus.
|
||||
Following games use custom external RAM (serial EEPROM) for backup.
|
||||
It seems that different EEPROM Mapper have been used, depending upon companies.
|
||||
|
||||
Eke~Eke - July 2007
|
||||
|
||||
|
||||
-------------------------------------------------------
|
||||
ACCLAIM (81)
|
||||
-------------------------------------------------------
|
||||
|
||||
NBA Jam (UE)
|
||||
NBA Jam (J)
|
||||
------------
|
||||
T-081326
|
||||
T-81033
|
||||
header OK ($200001-$200001)
|
||||
|
||||
TYPE: 8BITS WORD ADDRESS
|
||||
SIZE_MASK: 0xFF (24C02)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200000 (0)
|
||||
SDA_OUT: 0x200000 (1)
|
||||
SCL : 0x200000 (1)
|
||||
|
||||
Note: this game uses a different EEPROM mapper than other Accolade games.
|
||||
|
||||
|
||||
Blockbuster World Video Game Championship II (U)
|
||||
NBA Jam Tournament Edition (JUE)
|
||||
------------------------------------------------
|
||||
T-81406
|
||||
header KO
|
||||
|
||||
TYPE: TYPE: 8BITS WORD ADDRESS
|
||||
SIZE_MASK: 0xFF (24C02)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200000 (0)
|
||||
|
||||
Note: Rev 00 of the game has buggy eeprom support (incorrect data written), game backup only work with Rev01 version (released apparently in 2002, eight years later !)
|
||||
|
||||
|
||||
NFL Quarterback Club (JUE)
|
||||
-----------------------------
|
||||
T-081276
|
||||
header OK ($200000-$200001)
|
||||
|
||||
TYPE: TYPE: 8BITS WORD ADDRESS
|
||||
SIZE_MASK: 0xFF (24C02)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200000 (0)
|
||||
|
||||
|
||||
NFL Quarterback Club 96 (UE)
|
||||
-----------------------------
|
||||
T-081586
|
||||
header OK ($200000-$200001)
|
||||
|
||||
TYPE: TYPE: 8BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x7FF (24C16)
|
||||
PAGE_MASK: 0x07
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200000 (0)
|
||||
|
||||
|
||||
College Slam (U)
|
||||
----------------
|
||||
T-81576
|
||||
header OK ($200001-$200001)
|
||||
|
||||
TYPE: 16BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x1FFF (24C64)
|
||||
PAGE_MASK: 0x07
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200000 (0)
|
||||
|
||||
|
||||
Frank Thomas Big Hurt Baseball (UE)
|
||||
----------------
|
||||
T-81476
|
||||
header OK ($200000-$200001)
|
||||
|
||||
TYPE: 16BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x1FFF (24C64)
|
||||
PAGE_MASK: 0x07
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200000 (0)
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------
|
||||
CAPCOM (12)
|
||||
-------------------------------------------------------
|
||||
|
||||
Megaman - The Wily Wars (E)
|
||||
Rockman Mega World (J) [alt]
|
||||
----------------
|
||||
T-12046
|
||||
T-12053 (checksum = 0xEA80)
|
||||
header OK ($200001-$200001)
|
||||
|
||||
TYPE: 7BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x7F (24C01)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200001 (1)
|
||||
|
||||
NOTE: the original version of Rockman Mega World (J) uses traditional SRAM, header gives $200000-$203FFF range
|
||||
the alternate version uses a 128bytes serial EEPROM (X24C01)
|
||||
the two versions share the same GAME NAME and PRODUCT ID
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------
|
||||
Electronic Arts (50)
|
||||
-------------------------------------------------------
|
||||
|
||||
NHLPA Hockey 93 (UE)
|
||||
----------------
|
||||
T-50396
|
||||
header KO
|
||||
|
||||
TYPE: 7BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x7F (24C01)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200000 (7)
|
||||
SDA_OUT: 0x200000 (7)
|
||||
SCL : 0x200000 (6)
|
||||
|
||||
|
||||
Rings of Power (UE)
|
||||
----------------
|
||||
T-50176
|
||||
header KO
|
||||
|
||||
TYPE: 7BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x7F (24C01)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200000 (7)
|
||||
SDA_OUT: 0x200000 (7)
|
||||
SCL : 0x200000 (6)
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------
|
||||
SEGA
|
||||
-------------------------------------------------------
|
||||
|
||||
Greatest Heavyweights of the Ring (U)
|
||||
Greatest Heavyweights of the Ring (J)
|
||||
Greatest Heavyweights of the Ring (E)
|
||||
-----------------------------
|
||||
MK-1228
|
||||
G-5538
|
||||
PR-1993
|
||||
header OK ($200001-$200001)
|
||||
|
||||
TYPE: 7BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x7F (24C01)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200001 (1)
|
||||
|
||||
|
||||
Wonder Boy in Monster World (UE)
|
||||
Wonder Boy V - Monster World III (J)
|
||||
----------------
|
||||
G-4060
|
||||
header OK ($200001-$200001)
|
||||
|
||||
TYPE: 7BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x7F (24C01)
|
||||
PAGE_MASK: 0x03
|
||||
SDA_IN : 0x200001 (0)
|
||||
SDA_OUT: 0x200001 (0)
|
||||
SCL : 0x200001 (1)
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------
|
||||
CODEMASTERS
|
||||
-------------------------------------------------------
|
||||
|
||||
Micro Machines 2 - Turbo Tournament (E) (J-Cart)
|
||||
------------------------------------------------
|
||||
T-120096-50
|
||||
header KO
|
||||
|
||||
TYPE: TYPE: 8BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x3FF (24C08)
|
||||
PAGE_MASK: 0x0F
|
||||
SDA_IN : 0x300000 (0)
|
||||
SDA_OUT: 0x380001 (7)
|
||||
SCL : 0x300000 (1)
|
||||
|
||||
Note: this game needs the EEPROM to be initially fullfilled with the string
|
||||
"PETETEST01234567" otherwise it won't initialize memory with correct data.
|
||||
|
||||
|
||||
Micro Machines Military (E) (J-Cart)
|
||||
------------------------------------
|
||||
00000000-00 (checksum = 0x168B or 0xCEE0)
|
||||
header KO
|
||||
|
||||
TYPE: TYPE: 8BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x3FF (24C08)
|
||||
PAGE_MASK: 0x0F
|
||||
SDA_IN : 0x300000 (0)
|
||||
SDA_OUT: 0x380001 (7)
|
||||
SCL : 0x300000 (1)
|
||||
|
||||
|
||||
Micro Machines Turbo Tournament 96 (E) (J-Cart)
|
||||
------------------------------------------------
|
||||
00000000-00 (checksum = 0x165E or 0x2C41)
|
||||
header KO
|
||||
|
||||
TYPE: TYPE: 8BITS WORD ADDRESS
|
||||
SIZE_MASK: 0x7FF (24C16)
|
||||
PAGE_MASK: 0xF
|
||||
SDA_IN : 0x300000 (0)
|
||||
SDA_OUT: 0x380001 (7)
|
||||
SCL : 0x300000 (1)
|
@ -1,235 +0,0 @@
|
||||
<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>
|
@ -1,715 +0,0 @@
|
||||
|
||||
Sega Genesis hardware notes
|
||||
Version 0.8 (03/02/01)
|
||||
|
||||
by Charles MacDonald
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Unpublished work Copyright 2000, 2001 Charles MacDonald
|
||||
|
||||
Here is a compilation of some notes I've written up on the Sega Genesis
|
||||
hardware. Everything described herein has been checked on the real thing,
|
||||
though that doesn't necessarily mean my testing methods were flawless. :)
|
||||
|
||||
Version history
|
||||
---------------
|
||||
[0.8]
|
||||
- Added information on the SVP chip used in Virtua Racing. (section 4.2)
|
||||
- Added information on EEPROM storage. (section 4.1)
|
||||
- Changed miscellaneous section around.
|
||||
[0.7]
|
||||
- Added more information about access to the Z80 bus. (section 2.2)
|
||||
- Updated the VDP register information, and removed some things
|
||||
that were specific to VDP programming. (section 1.1)
|
||||
- Added some background about the PSG. (section 4)
|
||||
[0.6]
|
||||
- Rewrote the 68000 memory map description. (section 1)
|
||||
- Rewrote the Z80 memory map description. (section 2.1)
|
||||
- Added memory access section. (section 1.2)
|
||||
- Added a few miscellaneous topics. (section 4)
|
||||
[0.5]
|
||||
- Added more Z80 banking information.
|
||||
- Added unused VDP address return values from the Z80 side.
|
||||
- Added example of how to start up the Z80 on power-up.
|
||||
- Added information on Phantasy Star 4 from Jeff Quinn.
|
||||
- Added list of consoles that support Mark-III compatibility mode.
|
||||
- Fixed a few typos.
|
||||
[0.4]
|
||||
- Added more details on 68000 and Z80 memory map.
|
||||
- Added more information on VDP addresses.
|
||||
- Added some thoughts on Phantasy Star 4.
|
||||
[0.3]
|
||||
- Added more information on I/O registers. (section 3)
|
||||
- Fixed a few typos pointed out by Tim Meekins.
|
||||
[0.2]
|
||||
- Added section on I/O port programming and gamepads
|
||||
[0.1]
|
||||
- Initial release
|
||||
|
||||
Table of Contents
|
||||
|
||||
1.) 68000 memory map
|
||||
1.1) VDP registers
|
||||
1.2) Memory access quirks
|
||||
1.3) Clock speeds
|
||||
2.) Sound hardware overview
|
||||
2.1) Z80 memory map
|
||||
2.2) RESET and BUSREQ registers
|
||||
2.3) Banking
|
||||
2.4) Interrupts
|
||||
3.) Input and Output
|
||||
3.1) Programming I/O ports
|
||||
3.2) Gamepad specifics
|
||||
4.) Miscellaneous
|
||||
4.1) EEPROM
|
||||
4.2) Virtua Racing
|
||||
4.3) Phantasy Star 4
|
||||
4.4) Other topics
|
||||
5.) Credits
|
||||
6.) Disclaimer
|
||||
|
||||
|
||||
1.) 68000 memory map
|
||||
|
||||
000000-3FFFFFh : ROM
|
||||
400000-7FFFFFh : Unused (1)
|
||||
800000-9FFFFFh : Unused (2)
|
||||
A00000-A0FFFFh : Z80 address space (3)
|
||||
A10000-A1001Fh : I/O
|
||||
A10020-BFFFFFh : Internal registers and expansion (4)
|
||||
C00000-DFFFFFh : VDP (5)
|
||||
E00000-FFFFFFh : RAM (6)
|
||||
|
||||
1. Reads return the MSB of the next instruction to be fetched, with the
|
||||
LSB set to zero. Writes do nothing.
|
||||
|
||||
2. Reading or writing any address will lock up the machine.
|
||||
This area is used for the 32X adapter.
|
||||
|
||||
3. Addresses A08000-A0FFFFh mirror A00000-A07FFFh, so the 68000 cannot
|
||||
access it's own banked memory. All addresses are valid except for
|
||||
the VDP which is at A07F00-A07FFFh and A0FF00-A0FFFFh, writing or
|
||||
reading those addresses will lock up the machine.
|
||||
|
||||
4. Reading some addresses lock up the machine, others return the MSB
|
||||
of the next instruction to be fetched with the LSB is set to zero.
|
||||
|
||||
The latter applies when reading A11100h (except for bit 0 reflects
|
||||
the state of the bus request) and A11200h.
|
||||
|
||||
Valid addresses in this area change depending on the peripherals
|
||||
and cartridges being used; the 32X, Sega CD, and games like Super
|
||||
Street Fighter II and Phantasy Star 4 use addresses within this range.
|
||||
|
||||
5. The VDP is mirrored at certain locations from C00000h to DFFFFFh. In
|
||||
order to explain what addresses are valid, here is a layout of each
|
||||
address bit:
|
||||
|
||||
MSB LSB
|
||||
110n n000 nnnn nnnn 000m mmmm
|
||||
|
||||
'1' - This bit must be 1.
|
||||
'0' - This bit must be 0.
|
||||
'n' - This bit can have any value.
|
||||
'm' - VDP addresses (00-1Fh)
|
||||
|
||||
For example, you could read the status port at D8FF04h or C0A508h,
|
||||
but not D00084h or CF00008h. Accessing invalid addresses will
|
||||
lock up the machine.
|
||||
|
||||
6. The RAM is 64K in size and is repeatedly mirrored throughout the entire
|
||||
range it appears in. Most games only access it at FF0000-FFFFFFh.
|
||||
|
||||
1.1) VDP registers
|
||||
|
||||
The lower five bits of the address specify what memory mapped VDP register
|
||||
to access:
|
||||
|
||||
00h : Data port
|
||||
02h : Data port
|
||||
04h : Control port (1)
|
||||
06h : Control port
|
||||
08h : HV counter (2)
|
||||
0Ah : HV counter
|
||||
0Ch : HV counter
|
||||
0Eh : HV counter
|
||||
11h : SN76489 PSG (3)
|
||||
13h : SN76489 PSG
|
||||
15h : SN76489 PSG
|
||||
17h : SN76489 PSG
|
||||
18h : Unused (4)
|
||||
1Ah : Unused
|
||||
1Ch : Unused
|
||||
1Eh : Unused
|
||||
|
||||
1. For reads, the upper six bits of the status flags are set to the
|
||||
value of the next instruction to be fetched. Bit 6 is always zero.
|
||||
For example:
|
||||
|
||||
move.w $C00004, d0 ; Next word is $4E71
|
||||
nop ; d0 = -1-- 11?? ?0?? ????
|
||||
|
||||
When reading the status flags through the Z80's banked memory area,
|
||||
the upper six bits are set to one.
|
||||
|
||||
2. Writing to the HV counter will cause the machine to lock up.
|
||||
|
||||
3. Reading the PSG addresses will cause the machine to lock up.
|
||||
|
||||
Doing byte-wide writes to even PSG addresses has no effect.
|
||||
|
||||
If you want to write to the PSG via word-wide writes, the data
|
||||
must be in the LSB. For instance:
|
||||
|
||||
move.b (a4)+, d0 ; PSG data in LSB
|
||||
move.w d0, $C00010 ; Write to PSG
|
||||
|
||||
4. Reading the unused addresses returns the next instruction to be fetched.
|
||||
For example:
|
||||
|
||||
move.w $C00018, d0 ; Next word is $4E71
|
||||
nop ; d0 = $4E71
|
||||
|
||||
When reading these addresses through the Z80's banked memory area,
|
||||
the value returned is always FFh.
|
||||
|
||||
Writing to C00018h and C0001Ah has no effect.
|
||||
|
||||
Writing to C0001Ch and C0001Eh seem to corrupt the internal state
|
||||
of the VDP. Here's what each bit does: (assuming word-wide writes)
|
||||
|
||||
8E9Fh : These bits cause brief flicker in the current 8 pixels
|
||||
being drawn when the write occurs.
|
||||
|
||||
5040h : These bits blank the display like bit 6 of register #1 when set.
|
||||
|
||||
2000h : This bit makes every line show the same random garbage data.
|
||||
|
||||
0100h : This bit makes random pattern data appear in the upper eight
|
||||
and lower ten lines of the display, with the normal 224 lines
|
||||
in the middle untouched. For those of you interested, the
|
||||
display is built up like so:
|
||||
|
||||
224 lines for the active display
|
||||
10 lines unused (can show pattern data here with above bit)
|
||||
3 lines vertical blank (no border color shown)
|
||||
3 lines vertical retrace (no picture shown at all)
|
||||
13 lines vertical blank (no border color shown)
|
||||
8 lines unused (can show pattern data here with above bit)
|
||||
|
||||
I know that comes up to 261 lines and not 262. But that's
|
||||
all my monitor shows.
|
||||
|
||||
Turning the display off makes the screen roll vertically,
|
||||
and random pattern data is displayed in all lines when
|
||||
this bit is set.
|
||||
|
||||
0020h : This bit causes the name table and pattern data shown to
|
||||
become corrupt. Not sure if the VRAM is bad or the VDP is
|
||||
just showing the wrong data.
|
||||
|
||||
1.2) Memory access quirks
|
||||
|
||||
Byte-wide writes
|
||||
|
||||
Writing to the VDP control or data ports is interpreted as a 16-bit
|
||||
write, with the LSB duplicated in the MSB. This is regardless of writing
|
||||
to an even or odd address:
|
||||
|
||||
move.w #$A5, $C00003 ; Same as 'move.w #$A5A5, $C00002'
|
||||
move.w #$87, $C00004 ; Same as 'move.w #$8787, $C00004'
|
||||
|
||||
Byte-wide reads
|
||||
|
||||
Reading from even VDP addresses returns the MSB of the 16-bit data,
|
||||
and reading from odd address returns the LSB:
|
||||
|
||||
move.b $C00008, d0 ; D0 = V counter
|
||||
move.b $C00001, d0 ; D0 = LSB of current VDP data word
|
||||
move.b $C0001F, d0 ; D0 = $71
|
||||
nop
|
||||
move.b $C00004, d0 ; D0 = MSB of status flags
|
||||
|
||||
Word-wide writes
|
||||
|
||||
When doing word-wide writes to Z80 RAM, only the MSB is written, and
|
||||
the LSB is ignored:
|
||||
|
||||
0000: AA BB CC DD ; Z80 memory
|
||||
move.w #$1234, $A00000 ; do a word-wide write
|
||||
0000: 12 BB CC DD ; result
|
||||
|
||||
Word-wide reads
|
||||
|
||||
A word-wide read from Z80 RAM has the LSB of the data duplicated in the MSB.
|
||||
|
||||
0000: AA BB CC DD ; Z80 memory
|
||||
move.w $A00000, d0 ; do a word-wide read
|
||||
d0 = $AAAA ; result
|
||||
|
||||
1.3) Clock speeds
|
||||
|
||||
These are for an NTSC Sega Genesis console.
|
||||
|
||||
680000 = 7.67 MHz
|
||||
YM2612 = 7.67 MHz
|
||||
Z80 = 3.58 MHz
|
||||
SN76489 = 3.58 MHz
|
||||
|
||||
If anyone has information about timing for PAL consoles, please let me know.
|
||||
|
||||
2) Sound hardware overview
|
||||
|
||||
The following components used for sound generation:
|
||||
|
||||
- Zilog Z80 CPU
|
||||
- 8k static RAM
|
||||
- Yamaha YM2612 FM sound generator
|
||||
- SN76489 PSG
|
||||
|
||||
2.1) Z80 memory map
|
||||
|
||||
0000-1FFFh : RAM
|
||||
2000-3FFFh : RAM (mirror)
|
||||
4000-5FFFh : YM2612 (1)
|
||||
6000-60FFh : Bank address register (2)
|
||||
6100-7EFFh : Unused (3)
|
||||
7F00-7FFFh : VDP (4)
|
||||
8000-FFFFh : Bank area
|
||||
|
||||
1. The YM2612 has two address lines, so it is available at 4000-4003h and
|
||||
is mirrored repeatedly up to 5FFFh.
|
||||
|
||||
2. Writes go to the bank address register, reads return FFh.
|
||||
The value returned applies to both the 68000 and Z80.
|
||||
|
||||
3. Writes are ignored, reads return FFh.
|
||||
The value returned applies to both the 68000 and Z80.
|
||||
|
||||
4. Only addresses 7F00-7F1Fh are valid, writes to 7F20-7FFFh will
|
||||
lock up the machine.
|
||||
|
||||
Z80 access to the VDP has the same results as doing byte-wide reads
|
||||
and writes as described in section 1.2. So only the HV counter and
|
||||
PSG can be used effectively.
|
||||
|
||||
All I/O ports return FFh, and writing to them has no effect. The Thunder
|
||||
Force games read port BFh in the IRQ subroutine, this would appear to be
|
||||
a misunderstanding on the programmer's behalf.
|
||||
|
||||
The 68000 can write to A06000h to set up the bank address.
|
||||
|
||||
2.2) RESET and BUSREQ registers
|
||||
|
||||
Bit 0 of A11100h (byte access) or bit 8 of A11100h (word access) controls
|
||||
the Z80's /BUSREQ line.
|
||||
|
||||
Writing 1 to this bit will request the Z80 bus. You can then release
|
||||
the bus later on by writing 0.
|
||||
|
||||
Reading this bit will return 0 if the bus can be accessed by the 68000,
|
||||
or 1 if the Z80 is still busy.
|
||||
|
||||
If the Z80 is reset, or if it is running (meaning the 68000 does not
|
||||
have the bus) it will also return 1. The only time it will switch from
|
||||
1 to 0 is right after the bus is requested, and if the Z80 is still
|
||||
busy accessing memory or not.
|
||||
|
||||
Bit 0 of A11200h (byte access) or bit 8 of A11200h (word access) controls
|
||||
the Z80's /RESET line.
|
||||
|
||||
Writing 0 to this bit will start the reset process. The Z80 manual says you
|
||||
have to assert the /RESET line for three Z80 clock cycles as a reset does
|
||||
not happen instantly.
|
||||
|
||||
Writing 1 to this bit will stop the reset process. At this point, the Z80
|
||||
will start executing from address 0000h onwards.
|
||||
|
||||
The /RESET line is shared with the YM2612. For as long as the Z80 is reset,
|
||||
the YM2612 cannot be used.
|
||||
|
||||
The Z80 bus can only be accessed by the 68000 when the Z80 is running
|
||||
and the 68000 has the bus. (as opposed to the Z80 being reset, and/or
|
||||
having the bus itself)
|
||||
|
||||
Otherwise, reading $A00000-A0FFFF will return the MSB of the next
|
||||
instruction to be fetched, and the LSB will be set to zero. Writes
|
||||
are ignored. This even applies to the VDP area that would normally
|
||||
lock up the machine.
|
||||
|
||||
Interestingly enough, you can still access $A10000-A1001F during this
|
||||
time, which seems to be contradictory to some documentation which says
|
||||
you can only access the I/O region when the 68000 has the bus.
|
||||
|
||||
On power-up, the Z80 will be reset and will have the bus.
|
||||
If you want to load a Z80 program and run it, do the following:
|
||||
|
||||
- Stop the reset process
|
||||
- Request bus
|
||||
- Load Z80 program
|
||||
- Start the reset process
|
||||
- Release bus
|
||||
- Stop the reset process
|
||||
|
||||
2.3) Banking
|
||||
|
||||
The Z80 can access the 68000's address space through a banking mechanism
|
||||
which maps 32k pages to 8000-FFFFh on the Z80 side.
|
||||
|
||||
Most games do this to get at large data chunks like YM2612 DAC samples.
|
||||
However, you can access anything else the 68000 can. (I've tried reading
|
||||
the version register and setting the VDP border color this way with
|
||||
success - in fact some 32X sample code shows the PWM sound generator
|
||||
programmed by the Z80 through banking)
|
||||
|
||||
To specify which 32k section you want to access, write the upper nine
|
||||
bits of the complete 24-bit address into bit 0 of the bank address
|
||||
register, which is at 6000h (Z80) or A06000h (68000), starting with
|
||||
bit 15 and ending with bit 23.
|
||||
|
||||
For example:
|
||||
|
||||
ld ix, $6000 ;
|
||||
xor a ;
|
||||
ld (ix), a ; Bit 15 = 0
|
||||
ld (ix), a ; Bit 16 = 0
|
||||
ld (ix), a ; Bit 17 = 0
|
||||
ld (ix), a ; Bit 18 = 0
|
||||
ld (ix), a ; Bit 19 = 0
|
||||
ld (ix), a ; Bit 20 = 0
|
||||
ld (ix), a ; Bit 21 = 0
|
||||
inc a ;
|
||||
ld (ix), a ; Bit 22 = 1
|
||||
ld (ix), a ; Bit 23 = 1
|
||||
|
||||
After this routine executes, Z80 addresses 8000-FFFFh now correspond
|
||||
to 68000 addresses C00000-C07FFFh.
|
||||
|
||||
In my own tests, I've been unable to do the following:
|
||||
|
||||
- Read banked 68000 RAM. (returns FFh)
|
||||
- Find result of partial writes to the bank address register.
|
||||
- Have the Z80 read A00000-A0FFFF through the banked memory area.
|
||||
(locks up the machine)
|
||||
|
||||
Steve Snake informed me that reading 68000 RAM is possible, but is not
|
||||
a recommended practice by Sega. Perhaps only some models of the Genesis
|
||||
allow for it.
|
||||
|
||||
2.4) Interrupts
|
||||
|
||||
The Z80 runs in interrupt mode 1, where an interrupt causes a RST 38h.
|
||||
However, interrupt mode 0 can be used as well, since FFh will be read
|
||||
off the bus.
|
||||
|
||||
The Z80 will recieve an IRQ from the VDP on scanline E0h. This happens
|
||||
once per frame, every frame, regardless of frame interrupts being
|
||||
disabled by the 68000.
|
||||
|
||||
If the Z80 has interrupts disabled when the frame interrupt is supposed
|
||||
to occur, it will be missed, rather than made pending.
|
||||
|
||||
There is no way to trigger an NMI unless the Genesis has been switched
|
||||
into Mark 3 compatability mode, and this only means the NMI line is
|
||||
mapped to the cartridge port, it's not controllable through software.
|
||||
|
||||
3.0) Input and Output
|
||||
|
||||
The Genesis has three general purpose I/O ports. Devices like gamepads,
|
||||
modems, light guns, etc. can be used with them.
|
||||
|
||||
Here's a read-out of the I/O registers in their default state. Each
|
||||
one can be read at an even address (e.g. A1000Dh == A1000Ch) as well.
|
||||
|
||||
A10001h = A0 Version register
|
||||
|
||||
A10003h = 7F Data register for port A
|
||||
A10005h = 7F Data register for port B
|
||||
A10007h = 7F Data register for port C
|
||||
|
||||
A10009h = 00 Ctrl register for port A
|
||||
A1000Bh = 00 Ctrl register for port B
|
||||
A1000Dh = 00 Ctrl register for port C
|
||||
|
||||
A1000Fh = FF TxData register for port A
|
||||
A10011h = 00 RxData register for port A
|
||||
A10013h = 00 S-Ctrl register for port A
|
||||
|
||||
A10015h = FF TxData register for port B
|
||||
A10017h = 00 RxData register for port B
|
||||
A10019h = 00 S-Ctrl register for port B
|
||||
|
||||
A1001Bh = FF TxData register for port C
|
||||
A1001Dh = 00 RxData register for port C
|
||||
A1001Fh = 00 S-Ctrl register for port C
|
||||
|
||||
Bit 7 of the Data registers can be read or written.
|
||||
Any bit that is set as an input will return '1'.
|
||||
Any bit that is set as an output will return the value last written.
|
||||
|
||||
Bits 7-0 of the Ctrl registers can be read or written.
|
||||
|
||||
Bits 7-0 of the TxData registers can be read or written.
|
||||
|
||||
The RxData register will always return zero.
|
||||
|
||||
Bits 7-4 of the S-Ctrl registers can be read or written.
|
||||
|
||||
3.1) Programming I/O ports
|
||||
|
||||
In the context of this description, I'll assume the device plugged in is a
|
||||
gamepad. However, other periperhals like multi-taps, modems, mice, light
|
||||
guns, etc, exist.
|
||||
|
||||
Here's a pin-out of the connector:
|
||||
|
||||
Pin 1 - UP
|
||||
Pin 2 - DOWN
|
||||
Pin 3 - LEFT
|
||||
Pin 4 - RIGHT
|
||||
Pin 5 - Vcc
|
||||
Pin 6 - TL
|
||||
Pin 7 - TH
|
||||
Pin 8 - GND
|
||||
Pin 9 - TR
|
||||
|
||||
Each I/O port has several associated registers. I'll only cover the
|
||||
data and control registers, as the others are used for serial and
|
||||
parallel communication.
|
||||
|
||||
The data register corresponds to the I/O port pins like so:
|
||||
|
||||
Bit 7 - (Not connected)
|
||||
Bit 6 - TH
|
||||
Bit 5 - TL
|
||||
Bit 4 - TR
|
||||
Bit 3 - RIGHT
|
||||
Bit 2 - LEFT
|
||||
Bit 1 - DOWN
|
||||
Bit 0 - UP
|
||||
|
||||
A '0' means a button has been pressed, and '1' means a button has been
|
||||
released.
|
||||
|
||||
Bit 7 isn't connected to any pin on the I/O port. It will latch a value
|
||||
written to it, as shown:
|
||||
|
||||
move.b $A10003, d0 ; D0 = $7F
|
||||
move.b #$80, $A10003 ; Bit 7 = 1
|
||||
move.b $A10003, d0 ; D0 = $FF
|
||||
move.b #$00, $A10003 ; Bit 7 = 0
|
||||
move.b $A10003, d0 ; D0 = $7F
|
||||
|
||||
Bits 6-0 of the control register define what bits of the data register
|
||||
are inputs or outputs. Gamepads use TH as an output and the remaining
|
||||
pins as input, so a value of $40 would be written to the control register.
|
||||
|
||||
3.2) Gamepad specifics
|
||||
|
||||
A gamepad maps the directional pad to the pins mentioned earlier
|
||||
(left, right, up, down), and multiplexes the four buttons (A, B, C, Start)
|
||||
through the TL and TR pins.
|
||||
|
||||
The TH pin controls which pairs of buttons (either A, Start or C, B) are
|
||||
output through TL and TR by the multiplexer chip.
|
||||
|
||||
In order to read all the buttons, A program will set TH = 1, read the data
|
||||
port, set TH = 0, and read the port again. The data returned is as follows:
|
||||
|
||||
TH = 0 : ?0SA00DU
|
||||
TH = 1 : ?1CBRLDU
|
||||
|
||||
? = Whatever was last written to bit 7.
|
||||
S = Start
|
||||
A = Button A
|
||||
B = Button B
|
||||
C = Button C
|
||||
U = Up
|
||||
D = Down
|
||||
L = Left
|
||||
R = Right
|
||||
|
||||
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'
|
||||
|
||||
M = Mode
|
||||
X = Button X
|
||||
Y = Button Y
|
||||
Z = Button Z
|
||||
|
||||
From this point on, the standard 3-button pad values will be returned
|
||||
if any further TH transitions are done.
|
||||
|
||||
If TH isn't modified in about 8192 (probably less than that) 68000 CPU
|
||||
cycles, a 'time-out' will occur and the sequence to read 6-button values
|
||||
can be done again. Games usually poll the gamepad once per frame,
|
||||
which is always enough for the time-out to occur.
|
||||
|
||||
I believe checking if D3-D0 are all set or clear (as shown in the list
|
||||
above) would be another method to verify if 6-button or 3-button pad data
|
||||
was being returned.
|
||||
|
||||
Some games may access the gamepad in a way that causes 6-button values
|
||||
to be returned when 3-button values are expected. To get around this,
|
||||
the MODE button can be held down when powering-up the console, and
|
||||
the 6-button gamepad will respond like a 3-button one.
|
||||
|
||||
4.) Miscellaneous
|
||||
|
||||
The following are miscellaneous topics.
|
||||
|
||||
4.1) EEPROM
|
||||
|
||||
Some cartridges use a Xicor X24C01 EEPROM chip. The chip is programmed
|
||||
in a serial fashion (it has only two wires), and has 128 8-bit bytes
|
||||
of storage.
|
||||
|
||||
Games using EEPROM have the backup data string at offset $1B0 in the
|
||||
cartridge header area formatted like so:
|
||||
|
||||
0001B0: 52 41 E8 40 00 20 00 01 00 20 00 01
|
||||
|
||||
The Sega manual describes how the above data should be interpreted.
|
||||
In this case, it corresponds to a device mapped to odd memory addresses,
|
||||
occupying the byte at $200001.
|
||||
|
||||
The only games I know of which use an EEPROM chip are:
|
||||
|
||||
- Wonderboy 3 / Monster World IV
|
||||
- Rockman Megaworld
|
||||
- Megaman: The Wily Wars
|
||||
|
||||
4.2) Virtua Racing
|
||||
|
||||
The Virtua Racing cartridge has 2MB ROM, 128K RAM, and a custom DSP chip
|
||||
called the 'Sega Virtua Processor' (SVP), which is manufactured by Sega.
|
||||
To the best of my knowledge, the SVP chip has internal ROM and possibly
|
||||
internal RAM.
|
||||
|
||||
The main purpose of the SVP is to render polygons as 8x8 patterns, which
|
||||
the game program transfers to VRAM from the 128K RAM area using DMA.
|
||||
|
||||
The VR cartridge has the following memory map:
|
||||
|
||||
000000-1FFFFFh : Program ROM (2MB)
|
||||
200000-2FFFFFh : Unused
|
||||
300000-31FFFFh : On-cart RAM (128K)
|
||||
320000-3FFFFFh : (?)
|
||||
390000-39FFFFh : (?)
|
||||
3A0000-3AFFFFh : (?)
|
||||
|
||||
The SVP chip has registers mapped in the I/O space:
|
||||
|
||||
A15000.w - Can read and write commands
|
||||
A15005.b - Reading bit 0 acts like a status flag (SVP busy?)
|
||||
A15006.w - Unknown ($0000, $0001, $000A written)
|
||||
A15008.w - Unknown ($0000, $0001, $0000 written)
|
||||
|
||||
Commands are two bytes in size, and are read and written to A15000h.
|
||||
|
||||
FFFFh - Command reset (?) (done before any access)
|
||||
'SV' - Command init (?) (written before SVP communication)
|
||||
'OK' - Command OK (?) (written after 'SV')
|
||||
'Tx' - Where 'x' equals the following value based on the command
|
||||
selected in the test menu:
|
||||
0 - "DSP ROM RD" and
|
||||
"DSP RAM OVER WRITE"
|
||||
1 - "DSP DRAM R/W"
|
||||
2 - "DSP IRAM R/W"
|
||||
4 - "DSP POINTER"
|
||||
|
||||
To emulate the SVP chip, somebody needs to figure out how to dump the
|
||||
internal ROM (the test menu shows that it has a DSP ROM reading option,
|
||||
perhaps sending a certain command to the SVP makes it map it's internal
|
||||
ROM within the $300000-$3FFFFF area) and figure out how the DSP works.
|
||||
|
||||
All of the above information came from physically examining a VR cartridge,
|
||||
and from disassembling the test menu code. (found at $1B000 for those
|
||||
of you who are interested)
|
||||
|
||||
4.3) Phantasy Star 4
|
||||
|
||||
Phantasy Star 4 is a 24 megabit game with 16k of battery backed RAM
|
||||
mapped to $200001-$203FFF. (odd addresses used) It has ROM in the same
|
||||
area where the RAM is. I've observed that the game will always write
|
||||
$01 to $A130F1 before accessing the RAM, and then write $00 when
|
||||
done. It could be that bit 0 of $A130F1 controls ROM/RAM banking at
|
||||
that location.
|
||||
|
||||
Jeff Quinn has tested this and confirmed it to work, and also reported
|
||||
an area of the game where supporting banked SRAM is important; when
|
||||
your characters encounter a GEROTLUX below the town of Tyler on Dezolis,
|
||||
the game will try to access the ROM data that is obscured by SRAM.
|
||||
|
||||
4.4) Other topics
|
||||
|
||||
- The 68000 RESET instruction has no effect.
|
||||
|
||||
- If the VDP is not accessed often enough, it will (appear) to lock up.
|
||||
I'm not sure what the cause is, but any control port access is enough
|
||||
to keep it going. Maybe some of the internal VDP memory is composed
|
||||
of DRAM cells that lose their data after a while. This happens in
|
||||
the Mark III compatability mode as well as mode 4 and mode 5.
|
||||
|
||||
- The status of the YM2612 can be read at any of it's four addresses.
|
||||
Since only address zero is documented as valid, it could be that the
|
||||
other addresses may return an incorrect result in some situations.
|
||||
|
||||
- The PSG is compatible with the Texas Instruments SN76489. It is actually
|
||||
on the same physical chip as the VDP, and it's output comes directly
|
||||
out of the VDP to be mixed with the YM2612. Sega did the same thing
|
||||
with the System C2 (possibly System 18) and SMS VDPs as well.
|
||||
|
||||
Can anyone contribute some information about the Genesis security
|
||||
and operating system ROM features? I know of a few:
|
||||
|
||||
- Games must write the text 'SEGA' to A14000h if the lower four
|
||||
bits of the version register return 01h.
|
||||
- Writing 01h to A14101h disables the OS ROM and swaps in the cart ROM.
|
||||
- The OS ROM checks for 'SEGA' or ' SEGA' at offset 100h in the cart ROM.
|
||||
|
||||
Here's a list of consoles that support the Mark III compatability mode.
|
||||
|
||||
- Sega Mega Drive
|
||||
- Sega Mega Drive 2
|
||||
- Sega Genesis
|
||||
- Sega Genesis 2
|
||||
|
||||
And ones that do not:
|
||||
|
||||
- Genesis 3 (Majesco)
|
||||
|
||||
If anyone has tested this with the Nomad, CDX, MegaJet, etc., please
|
||||
let me know.
|
||||
|
||||
5.) Credits
|
||||
|
||||
I would like to thank the following people for contributing information:
|
||||
|
||||
Bart Trzynadlowski, Christian Schiller, Flavio Morsoletto, Jeff Quinn,
|
||||
Mike Gordon, Naflign, Omar Cornut, Steve Snake, and Tim Meekins.
|
||||
|
||||
Contributors to the Sega Programming FAQ.
|
||||
Gringoz for the Genesis schematics.
|
||||
|
||||
6.) Disclaimer
|
||||
|
||||
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.
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,933 +0,0 @@
|
||||
<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>
|
@ -1,340 +0,0 @@
|
||||
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.
|
@ -1,40 +0,0 @@
|
||||
|
||||
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.
|
||||
|
@ -1,89 +0,0 @@
|
||||
|
||||
Introduction
|
||||
|
||||
Genesis Plus has reasonable speed, and very fast rendering. Here are some
|
||||
details about porting it to another platform
|
||||
|
||||
Porting rules
|
||||
|
||||
- This program is released under the GPL, so please release the source
|
||||
code for your derivative ports. Let me know if you need an alternative
|
||||
to this.
|
||||
|
||||
- Do not change the name of the emulator. Something like 'Genesis Plus / MacOS'
|
||||
is fine as it keeps the original name.
|
||||
|
||||
- Configure the CPU emulators for little or big-endian CPUs, and use the
|
||||
ALIGN_LONG option to handle unaligned memory accesses if needed. E.g. if
|
||||
the emulator crashes when a game scrolls horizontally, you need to enable
|
||||
it.
|
||||
|
||||
Requirements
|
||||
|
||||
- At this time the 16-bit rendering code has been well tested and should
|
||||
be used. There is code to support 8 through 32-bit displays, but I
|
||||
haven't checked if it still works.
|
||||
|
||||
- Audio output, if enabled, uses stereo 16-bit samples.
|
||||
|
||||
Functions to use:
|
||||
|
||||
int load_rom(char *filename);
|
||||
|
||||
Loads a game which can be in BIN, SMD or ZIP formats. It returns zero if
|
||||
an error has occured.
|
||||
|
||||
void system_init(void);
|
||||
|
||||
Initializes the virtual Genesis console. Call this once during startup.
|
||||
|
||||
void audio_init(int rate);
|
||||
|
||||
Initialize the sound emulation part of the emulator. Pass zero or don't
|
||||
call the function to disable sound. Call this after running system_init().
|
||||
|
||||
void system_reset(void);
|
||||
|
||||
Resets the virtual Genesis console. Call this once during setup, and later
|
||||
as needed.
|
||||
|
||||
int system_frame(int skip);
|
||||
|
||||
Updates the emulation for a frame. Pass 1 to prevent rendering (which can
|
||||
be used for frame skipping) and 0 to render the current display.
|
||||
|
||||
This function returns 0 if the virtual Genesis console has locked up.
|
||||
You can do what you'd like with this information, such as notify the user,
|
||||
reset the machine, etc.
|
||||
|
||||
If audio is enabled, the snd.buffer[] array will hold the current audio
|
||||
data for this frame.
|
||||
|
||||
void system_shutdown(void);
|
||||
|
||||
Shuts down the emulator.
|
||||
|
||||
Variables:
|
||||
|
||||
The 'bitmap' structure needs to be filled out prior to calling system_init().
|
||||
This provides the rendering code with information about the type of bitmap
|
||||
it is rendering to. I would advise sticking with a 1024x512 16-bit bitmap:
|
||||
|
||||
memset(&bitmap, 0, sizeof(t_bitmap));
|
||||
bitmap.width = 1024;
|
||||
bitmap.height = 512;
|
||||
bitmap.depth = 16;
|
||||
bitmap.granularity = 2; /* Bytes per pixel */
|
||||
bitmap.pitch = (bitmap.width * bitmap.granularity);
|
||||
bitmap.data = (unsigned char *)bmp->pixels; /* Pointer to your bitmap */
|
||||
bitmap.viewport.w = 256; /* Initial size of display on power-up (do not change) */
|
||||
bitmap.viewport.h = 224;
|
||||
bitmap.viewport.x = 0x20; /* Offset used for rendering (do not change) */
|
||||
bitmap.viewport.y = 0x00;
|
||||
bitmap.remap = 1;
|
||||
|
||||
The variable 'input.pad[0]' holds the button states for the first player
|
||||
gamepad. Update this prior to calling system_frame(), and use the bitmasks
|
||||
defined in system.h such as 'INPUT_UP', etc.
|
||||
|
||||
See the Windows/SDL and DOS drivers for examples.
|
@ -1,122 +0,0 @@
|
||||
----------------------------------------------------------------------------
|
||||
Genesis Plus
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
Version 1.2a
|
||||
by Charles Mac Donald
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
What's New
|
||||
----------
|
||||
|
||||
[06/22/03]
|
||||
- Modified rendering code for portability
|
||||
- Modified memory handling to fix banked PSG access
|
||||
[05/13/03]
|
||||
- Initial release
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
The Windows version runs windowed in a 16-bit desktop with NO sound or
|
||||
joystick support.
|
||||
|
||||
The DOS version has most of the functionality from SMS Plus, such
|
||||
as audio, joysticks, etc.
|
||||
|
||||
Windows/DOS controls:
|
||||
|
||||
Arrow Keys - Directional pad
|
||||
A,S,D,F - 1P gamepad, buttons A, B, C, Start
|
||||
Tab - Reset
|
||||
Esc - Exit program
|
||||
|
||||
DOS only:
|
||||
|
||||
End - Exit program
|
||||
F1-F4 - Set frameskip level (F1 = no skip ... F4 = skip 3 frames)
|
||||
F8 - Make PCX screen snapshot
|
||||
F9 - Toggle VSync
|
||||
F10 - Toggle speed throttling
|
||||
F11 - Toggle FPS meter
|
||||
|
||||
DOS details:
|
||||
|
||||
You can only support a second player if you are using a joystick driver
|
||||
that supports more than one joystick. (e.g. Sidewinder, dual pads, etc.)
|
||||
|
||||
Type 'gen -help' on the command line for a list of useful options.
|
||||
|
||||
-res <x> <y> set the display resolution.
|
||||
-vdriver <n> specify video driver.
|
||||
-depth <n> specify color depth. (8, 16)
|
||||
-scanlines use scanlines effect.
|
||||
-scale scale display to full resolution. (slow)
|
||||
-vsync wait for vertical sync before blitting.
|
||||
-sound enable sound. (force speed throttling)
|
||||
-sndrate <n> specify sound rate. (8000, 11025, 22050, 44100)
|
||||
-sndcard <n> specify sound card. (0-7)
|
||||
-swap swap left and right stereo output.
|
||||
-joy <s> specify joystick type.
|
||||
|
||||
Here is a list of all the video drivers you can pass as a parameter
|
||||
to the '-vdriver' option:
|
||||
|
||||
auto, safe, vga, modex, vesa2l, vesa3, vbeaf
|
||||
|
||||
Here is a list of all the joystick drivers you can pass as a parameter
|
||||
to the '-joy' option:
|
||||
|
||||
auto, none, standard, 2pads, 4button, 6button, 8button, fspro, wingex,
|
||||
sidewinder, gamepadpro, grip, grip4, sneslpt1, sneslpt2, sneslpt3,
|
||||
psxlpt1, psxlpt2, psxlpt3, n64lpt1, n64lpt2, n64lpt3, db9lpt1, db9lpt2,
|
||||
db9lpt3, tglpt1, tglpt2, tglpt3, wingwar, segaisa, segapci, segapci2
|
||||
|
||||
You can put any commandline option into a plain text file which should
|
||||
be called "gen.cfg". Put one option per line, please. Command line options
|
||||
will override anything in the configuration file.
|
||||
|
||||
Currently the zip loading code can manage a zipfile where the game
|
||||
image is the first thing in it. If you try to open a huge archive of
|
||||
games, only the first will be played.
|
||||
|
||||
Credits and Acknowlegements
|
||||
---------------------------
|
||||
|
||||
I would like to thank Omar Cornut, Christian Schiller, and Chris MacDonald
|
||||
for their invaluable help and support with this project.
|
||||
|
||||
Richard Bannister for the Macintosh port and all of the code fixes and
|
||||
suggestions that have made Genesis Plus a better program.
|
||||
(http://www.bannister.org)
|
||||
|
||||
The Genesis emulator authors: Bart Trzynadlowski, Quintesson, Steve Snake,
|
||||
James Ponder, Stef, Gerrie, Sardu.
|
||||
|
||||
The regular people and many lurkers at segadev.
|
||||
|
||||
The MAME team for the CPU and sound chip emulators.
|
||||
|
||||
Everyone who has contributed, donated, and submitted information to help
|
||||
out Genesis Plus and my efforts documenting the Genesis hardware.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
Charles MacDonald
|
||||
E-mail: cgfm2@hotmail.com
|
||||
WWW: http://cgfm2.emuviews.com
|
||||
|
||||
Legal
|
||||
-----
|
||||
|
||||
Copyright (C) 1999, 2000, 2001, 2002, 2003 Charles MacDonald
|
||||
|
||||
The source code is distributed under the terms of the GNU General Public
|
||||
License.
|
||||
|
||||
The Z80 CPU emulator, 68K CPU emulator, and the PSG, YM2612 emulation code
|
||||
are taken from the MAME project, and terms of their use are covered under
|
||||
the MAME license.
|
||||
(http://www.mame.net)
|
||||
|
@ -1,189 +0,0 @@
|
||||
---------------------------------------
|
||||
SSFII GENESIS TECHNICAL INFORMATION
|
||||
Second Edition (July 26, 2000)
|
||||
Bart Trzynadlowski
|
||||
---------------------------------------
|
||||
|
||||
|
||||
The purpose of this document is to discuss the workings of the Genesis port of
|
||||
Capcom's "Super Street Fighter II The New Challengers". Virtually all of this
|
||||
information was originally found by others' efforts.
|
||||
Please credit "those who contributed information" rather than me if
|
||||
you use any of this information. You may pass this document around freely, but
|
||||
please keep it unaltered. If you see any errors or have more info, contact me.
|
||||
I can be reached at trzy@powernet.net.
|
||||
|
||||
Second Edition: July 26, 2000
|
||||
- Major update with correct information thanks to Tim Meekins
|
||||
First Edition: July 21, 2000
|
||||
- Initial release
|
||||
|
||||
|
||||
0. THE SSFII CHALLENGE
|
||||
|
||||
The challenge behind getting "Super Street Fighter II The New Challengers"
|
||||
(SSFII) to work on a Genesis emulator lies primarily in the fact that the game
|
||||
is stored on a 40 megabit (5 megabyte) cartridge.
|
||||
The Sega Genesis maps ROM from 0x000000 to 0x3FFFFF which means that
|
||||
the CPU can only see 4 megabytes of cartridge ROM. SSFII needed more space for
|
||||
the backgrounds and thus Capcom opted for a special 5 megabyte cartridge with
|
||||
bankswitching in order to access the area of ROM outside of normal range.
|
||||
|
||||
|
||||
1. THE BANKSWITCHING MECHANISM
|
||||
|
||||
The bankswitching mechanism probably resides on the cartridge. I'm 99% sure of
|
||||
this. Sega documentation does offer a description of the mechanism, though,
|
||||
which led me to suspect for a moment that perhaps the mechanism was on the
|
||||
Genesis itself.
|
||||
The idea is unlikely though, as that range of registers is used by the
|
||||
32X for an entirely different purpose. I have been informed that that range
|
||||
(which is marked as "SEGA RESERVED" in the Genesis developer's manual) can be
|
||||
used for extra devices which may be present on the cartridge.
|
||||
|
||||
The bankswitching mechanism is very simple. It views the addressable 4 mega-
|
||||
bytes of ROM as 8 512KB regions. The first area, 0x000000-0x07FFFF is fixed
|
||||
and cannot be remapped because that is where the vector table resides.
|
||||
The banking registers on the cartridge work by allocating the 512KB
|
||||
chunk to a given part of the addressable 4MB ROM space. Below are the
|
||||
registers and what range they correspond to. The value written to a register
|
||||
will cause the specified 512KB page to be mapped to that region. A page is
|
||||
specified with 6 bits (bits 7 and 6 are always 0) thus allowing a possible 64
|
||||
pages (SSFII only has 10, though.)
|
||||
|
||||
0xA130F3: 0x080000 - 0x0FFFFF
|
||||
0xA130F5: 0x100000 - 0x17FFFF
|
||||
0xA130F7: 0x180000 - 0x1FFFFF
|
||||
0xA130F9: 0x200000 - 0x27FFFF
|
||||
0xA130FB: 0x280000 - 0x2FFFFF
|
||||
0xA130FD: 0x300000 - 0x37FFFF
|
||||
0xA130FF: 0x380000 - 0x3FFFFF
|
||||
|
||||
The registers are accessed through byte writes. I haven't seen SSFII try to
|
||||
read any of the registers, so I don't know if it's possible or not. I don't
|
||||
emulate anything besides byte writes in my emulator.
|
||||
There is also a register 0xA130F1. Apparently the regions specified by
|
||||
0xA130F9-0xA130FF (0x200000-0x3FFFFF) can be either ROM or RAM and can be
|
||||
write-protected. Here is the layout of the register as far as I know:
|
||||
|
||||
7 6 5 4 3 2 1 0
|
||||
+-----------------------+
|
||||
|??|??|??|??|??|??|WP|MD|
|
||||
+-----------------------+
|
||||
|
||||
MD: Mode -- 0 = ROM, 1 = RAM
|
||||
WP: Write protect -- 0 = writable, 1 = not writable
|
||||
|
||||
Emulation of the 0xA130F1 register is not necessary, SSFII initializes it at
|
||||
start-up by writing 0 I believe, which signifies ROM and no write protection
|
||||
to the regions at 0x200000-0x3FFFFF (ROM isn't writable anyway, there isn't a
|
||||
need for protection.)
|
||||
|
||||
Examples:
|
||||
|
||||
If 0x01 is written to register 0xA130FF, 0x080000-0x0FFFFF is visible
|
||||
at 0x380000-0x3FFFFF.
|
||||
If 0x08 is written to register 0xA130F9, the first 512KB of the
|
||||
normally invisible upper 1MB of ROM is now visible at 0x200000-
|
||||
0x27FFFF.
|
||||
|
||||
The registers simply represent address ranges in the 4MB ROM area and you can
|
||||
page in data to these ranges by specifying the bank # -- it's that simple!
|
||||
|
||||
|
||||
2. CHECKSUM
|
||||
|
||||
SSFII contains a checksum routine which calculates the checksum of the first
|
||||
4MB of the ROM; it then pages in the last 1MB of ROM to 0x300000-0x3FFFFF.
|
||||
It does this by writing to the bank registers. The following code is taken
|
||||
directly from the US ROM dumped by Genesis Power:
|
||||
|
||||
... Checksum first 4MB of ROM (0x000000-0x3FFFFF) ...
|
||||
0x003BEC: move.b #$08, ($A130FD)
|
||||
0x003BF4: move.b #$09, ($A130FF)
|
||||
0x003BFC: lea ($300000), a0
|
||||
... Checksum uppper 1MB of ROM now mapped at 0x300000-0x3FFFFF ...
|
||||
|
||||
The bankswitching hardware must be properly emulated before the game starts
|
||||
working. If it is not, the checksum will fail and the game will hang with a
|
||||
red screen.
|
||||
In the Genesis Power US dump, you can jump to 0x003C3C to avoid the
|
||||
checksum routine, this is where program flow transfers to if the checksum was
|
||||
found to be valid. The game doesn't do anything important before the checksum
|
||||
code as far as emulation is concerned. It writes the SEGA message to the
|
||||
Trademark Security System register and does some joypad init stuff.
|
||||
|
||||
|
||||
3. EMULATING SSFII
|
||||
|
||||
SSFII is fairly straightforward to emulate. All you need to do is detect the
|
||||
game, load up all 5MB, and emulate the banking registers. The easiest way to
|
||||
do it, in my opinion, is to keep a second copy of the ROM and do memcpy()s
|
||||
from that second copy to the ROM being emulated.
|
||||
|
||||
For example, here is how Genital does it... I've got genesis.rom which is the
|
||||
buffer where ROMs are loaded and executed. There is also genesis.rom_ssf2
|
||||
which is another 5MB buffer where I load the SSFII ROM to as well.
|
||||
The bankswitching register emulation is done in my IOWriteByte()
|
||||
function (which handles byte writes to the 0xA00000-0xBFFFFF range). The
|
||||
following is the code I use:
|
||||
|
||||
if (addr >= 0xa130f3 && config.ssf2_emu)
|
||||
{
|
||||
switch (addr & 0xf)
|
||||
{
|
||||
case 0x3: /* 080000-0FFFFF */
|
||||
memcpy((genesis.rom + 0x080000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0x5: /* 100000-17FFFF */
|
||||
memcpy((genesis.rom + 0x100000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0x7: /* 180000-1FFFFF */
|
||||
memcpy((genesis.rom + 0x180000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0x9: /* 200000-27FFFF */
|
||||
memcpy((genesis.rom + 0x200000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0xb: /* 280000-2FFFFF */
|
||||
memcpy((genesis.rom + 0x280000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0xd: /* 300000-37FFFF */
|
||||
memcpy((genesis.rom + 0x300000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
case 0xf: /* 380000-3FFFFF */
|
||||
memcpy((genesis.rom + 0x380000), (genesis.rom_ssf2 + (data * 0x80000)), 0x80000);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Pardon the bad formatting, it just wouldn't fit correctly in the 80 columns
|
||||
that the rest of the document sticks to.
|
||||
The first line checks whether the address is 0xA130F3 or above (notice
|
||||
how 0xA130F1 is ignored, SSFII doesn't really use it) and if SSFII emulation
|
||||
is enabled (in Genital, I have a flag -- config.ssf2_emu -- which is set to 1
|
||||
to indicate SSFII emulation should occur.) The remainder of the code is a
|
||||
switch () statement which handles the register emulation.
|
||||
Since 0x80000 = 512KB, and the data variable holds the byte written to
|
||||
the register, data * 0x80000 yields the offset into the ROM that has been
|
||||
requested to be mapped.
|
||||
At first glance, memcpy()s may seem inefficient and slow. Although it
|
||||
is true, this doesn't apply to emulating SSFII since the game doesn't do much
|
||||
(if any) bankswitching during gameplay. No slowdown due to the memcpy()s is
|
||||
noticable.
|
||||
|
||||
If you are using an emulator like Starscream which requires the ROMs to be
|
||||
byteswapped, make certain both ROM images are byteswapped. If you don't use
|
||||
2 copies of the ROM, you will find the game will still have several glitches
|
||||
because the memcpy()s will be destroying the data they write over.
|
||||
|
||||
|
||||
4. CONCLUSION
|
||||
|
||||
That's all there is to it. This should be sufficient information for anyone
|
||||
wishing to implement SSFII support in their Sega Genesis emulator. If you have
|
||||
any questions at all (I'm not great at making things clear) feel free to email
|
||||
me at trzy@powernet.net.
|
||||
|
@ -1,79 +0,0 @@
|
||||
|
||||
Here are some technical details about things that need to be fixed or
|
||||
added to Genesis Plus.
|
||||
|
||||
Missing features:
|
||||
|
||||
- Support for 6-button controllers
|
||||
- SRAM management
|
||||
- Game Genie / PAR patch codes
|
||||
|
||||
The VDP code could use a lot of cleaning up.
|
||||
|
||||
The rendering code is missing a few bits:
|
||||
|
||||
- Sprite collision
|
||||
- Window bug
|
||||
|
||||
I think the "C" 68000 emulator either has some bugs or I'm not using it
|
||||
correctly. Older DOS-only versions used Turbo68K, which had ran games
|
||||
much better, especially with regards to interrupt handling.
|
||||
|
||||
Things that need to be fixed:
|
||||
|
||||
- Raster garbage on third road in Thunder Blade.
|
||||
|
||||
- Added country codes for Dragon Slayer, but game locks up after
|
||||
passing country check.
|
||||
|
||||
- No inputs in Samurai Shodown.
|
||||
(This game doesn't initialize the port direction registers, at least not
|
||||
directly. Emulation bug or problem with the game?)
|
||||
|
||||
- Palette and raster problems in Mortal Kombat.
|
||||
|
||||
- Bad raster effects and VRAM corruption in Super Skidmarks.
|
||||
(Needs PAL timing)
|
||||
|
||||
- Palette problems in Sonic 2 title screen.
|
||||
|
||||
- Masked half of Sonic sprite visible on Sonic title screen.
|
||||
|
||||
- Sprite masking doesn't work in Micro Machines subscreen.
|
||||
|
||||
- Music has slow tempo in Batman & Robin. (doesn't seem to be a problem
|
||||
with the YM2612 timers - Wonderboy 3 is normal)
|
||||
|
||||
- Music has jerky playback in Sonic 2, 3, 3D Blast. If you run the Z80
|
||||
emulation for one scanline after requesting an interrupt, it runs fine.
|
||||
|
||||
- DAC and PSG output are too loud, both are divided by two for now
|
||||
(though the PSG should be a bit quieter and the DAC a bit louder)
|
||||
|
||||
- Undead Line locks after selecting a stage, also the Z80 sound halts
|
||||
after the first note is played.
|
||||
|
||||
This game single steps the Z80 with the following code:
|
||||
|
||||
MOVEM.L D0,-(A7) ; 009C7C 48 E7 80 00
|
||||
ORI #$0200,SR ; 009C80 00 7C 02 00
|
||||
; Get control of the Z-bus
|
||||
MOVE.W #$0100,$00A11100 ; 009C84 33 FC 01 00 00 A1 11 00
|
||||
BTST #$00,$00A11100 ; 009C8C 08 39 00 00 00 A1 11 00
|
||||
BNE.S *-$08 [00009C8C] ; 009C94 66 F6
|
||||
; Check driver status byte. If zero, release bus and exit.
|
||||
TST.B $00A00008 ; 009C96 4A 39 00 A0 00 08
|
||||
BEQ *+$0016 [00009CB2] ; 009C9C 67 00 00 14
|
||||
; Release bus and wait for Z80 to resume control. Then restart the loop
|
||||
; and immediately get the bus back again, assuming the Z80 ran at least
|
||||
; one instruction in the meantime.
|
||||
CLR.W $00A11100 ; 009CA0 42 79 00 A1 11 00
|
||||
BTST #$00,$00A11100 ; 009CA6 08 39 00 00 00 A1 11 00
|
||||
BEQ.S *-$08 [00009CA6] ; 009CAE 67 F6
|
||||
BRA.S *-$2C [00009C84] ; 009CB0 60 D2
|
||||
; Release bus and exit.
|
||||
CLR.W $00A11100 ; 009CB2 42 79 00 A1 11 00
|
||||
ANDI #$FDFF,SR ; 009CB8 02 7C FD FF
|
||||
MOVEM.L (A7)+,D0 ; 009CBC 4C DF 00 01
|
||||
RTS ; 009CC0 4E 75
|
||||
|
@ -1,445 +0,0 @@
|
||||
#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;
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
/* 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);
|
||||
|
@ -1,184 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
|
||||
#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_ */
|
||||
|
@ -1,440 +0,0 @@
|
||||
|
||||
#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_ */
|
||||
|
@ -1,508 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
#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
|
@ -1,215 +0,0 @@
|
||||
/*
|
||||
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]);
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
#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_ */
|
||||
|
@ -1,894 +0,0 @@
|
||||
/* ======================================================================== */
|
||||
/* ========================= 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 ============================= */
|
||||
/* ======================================================================== */
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,34 +0,0 @@
|
||||
|
||||
#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_ */
|
@ -1,776 +0,0 @@
|
||||
#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);
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
|
||||
#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_ */
|
@ -1,296 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
|
||||
#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_ */
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
|
||||
#ifndef _MEMVDP_H_
|
||||
#define _MEMVDP_H_
|
||||
|
||||
/* Function prototypes */
|
||||
unsigned int vdp_dma_r (unsigned int address);
|
||||
|
||||
#endif /* _MEMVDP_H_ */
|
@ -1,246 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
|
||||
#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_ */
|
@ -1,86 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
|
||||
#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);
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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);
|
||||
|
@ -1,208 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
@ -1,877 +0,0 @@
|
||||
/*******************************************************************
|
||||
* 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
|
||||
};
|
@ -1,148 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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];
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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();
|
@ -1,526 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
#include "diskio.h"
|
||||
#include "vfat.h"
|
||||
|
||||
|
||||
#define PAGESIZE 12
|
||||
#define PADCAL 70
|
||||
|
||||
static int maxfiles;
|
||||
u8 havedir = 0;
|
||||
u8 haveSDdir = 0;
|
||||
u8 UseSDCARD = 0;
|
||||
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;
|
||||
VFATFS fs;
|
||||
FSDIRENTRY f;
|
||||
|
||||
|
||||
extern void reloadrom ();
|
||||
|
||||
/***************************************************************************
|
||||
* Showfile screen
|
||||
***************************************************************************/
|
||||
static void ShowFiles (int offset, int selection)
|
||||
{
|
||||
int i, j;
|
||||
char text[MAX_LONG_NAME+2];
|
||||
|
||||
ClearScreen ();
|
||||
j = 0;
|
||||
|
||||
for (i = offset; i < (offset + PAGESIZE) && (i < maxfiles); i++)
|
||||
{
|
||||
memset(text,0,MAX_LONG_NAME+2);
|
||||
if (filelist[i].flags) sprintf(text, "[%s]", filelist[i].displayname + filelist[i].filename_offset);
|
||||
else sprintf (text, "%s", filelist[i].displayname + 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];
|
||||
|
||||
|
||||
/* go up to parent directory */
|
||||
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;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* update current directory name */
|
||||
sprintf(rootSDdir, "%s/%s",rootSDdir, filelist[selection].filename);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Browse SDCARD subdirectories
|
||||
***************************************************************************/
|
||||
int parseSDdirectory()
|
||||
{
|
||||
int nbfiles = 0;
|
||||
FSDIRENTRY fsdir;
|
||||
|
||||
/* Get a list of files from the actual root directory */
|
||||
int res = VFAT_opendir(0, &fsdir, rootSDdir);
|
||||
|
||||
if (res == FS_SUCCESS)
|
||||
{
|
||||
while ( VFAT_readdir(&fsdir) == FS_SUCCESS )
|
||||
{
|
||||
memset (&filelist[nbfiles], 0, sizeof (FILEENTRIES));
|
||||
strcpy(filelist[nbfiles].displayname, fsdir.longname);
|
||||
strcpy(filelist[nbfiles].filename, fsdir.shortname);
|
||||
filelist[nbfiles].length = fsdir.fsize;
|
||||
filelist[nbfiles].flags = fsdir.dirent.attribute & ATTR_DIRECTORY;
|
||||
nbfiles++;
|
||||
}
|
||||
|
||||
VFAT_closedir(&fsdir);
|
||||
}
|
||||
|
||||
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,"/") == 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 = UseSDCARD ? 0 : 1;
|
||||
}
|
||||
|
||||
/*** This is directory ***/
|
||||
if (filelist[selection].flags)
|
||||
{
|
||||
/* SDCARD directory handler */
|
||||
if (UseSDCARD)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
/* DVD directory handler */
|
||||
else
|
||||
{
|
||||
/* 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;
|
||||
char msg[20];
|
||||
|
||||
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,"/genplus/roms");
|
||||
|
||||
/* Parse initial root directory and get entries list */
|
||||
ShowAction("Reading Directory ...");
|
||||
int res = VFAT_mount(FS_SLOTA, &fs);
|
||||
if ( res != FS_TYPE_FAT16 )
|
||||
{
|
||||
sprintf(msg,"Error mounting SDCARD: %d", res);
|
||||
WaitPrompt (msg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 /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 */
|
||||
sprintf(fname, "%s/%s",rootSDdir,filelist[selection].filename);
|
||||
|
||||
int res = VFAT_fopen(0, &f, fname, FS_READ);
|
||||
if (res != FS_SUCCESS )
|
||||
{
|
||||
WaitPrompt ("Unable to open file!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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) VFAT_fread(&f, readbuffer, 2048);
|
||||
else dvd_read (&readbuffer, 2048, discoffset);
|
||||
|
||||
if (!IsZipFile ((char *) readbuffer))
|
||||
{
|
||||
if (UseSDCARD) VFAT_fseek(&f, 0, SEEK_SET);
|
||||
|
||||
for (i = 0; i < blocks; i++)
|
||||
{
|
||||
if (UseSDCARD) VFAT_fread (&f, 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) VFAT_fread (&f, readbuffer, i);
|
||||
else dvd_read (readbuffer, 2048, discoffset);
|
||||
memcpy (buffer + offset, readbuffer, i);
|
||||
}
|
||||
}
|
||||
else return UnZipBuffer (buffer, discoffset, rootdirlength);
|
||||
|
||||
if (UseSDCARD) VFAT_fclose(&f);
|
||||
|
||||
return rootdirlength;
|
||||
}
|
@ -1,540 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
@ -1,388 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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);
|
||||
}
|
||||
|
@ -1,42 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
@ -1,351 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 ();
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,239 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 "vfat.h"
|
||||
#define MAXFILES 1000 /** Restrict to 1000 files per dir **/
|
||||
#define MAXJOLIET 256
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u64 offset;
|
||||
unsigned int length;
|
||||
char flags;
|
||||
char filename[13];
|
||||
char displayname[MAX_LONG_NAME];
|
||||
u16 filename_offset;
|
||||
} FILEENTRIES;
|
||||
|
||||
extern u64 basedir;
|
||||
extern u64 rootdir;
|
||||
extern int rootdirlength;
|
||||
|
||||
extern int getpvd ();
|
||||
extern int parsedirectory ();
|
||||
extern FILEENTRIES filelist[MAXFILES];
|
@ -1,44 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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];
|
@ -1,100 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 ();
|
||||
}
|
@ -1,588 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
||||
|
||||
if (filetype) sram.crc = crc32 (0, &sram.sram[0], 0x10000);
|
||||
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 ***/
|
||||
}
|
@ -1,623 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 ();
|
||||
}
|
@ -1,414 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 ROMTYPE 384
|
||||
#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,j;
|
||||
|
||||
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 + ROMTYPE, 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;
|
||||
|
||||
i=0;
|
||||
while (rominfo.io_support[i] != 0x20 && i<14)
|
||||
{
|
||||
for (j = 0; j < 14; j++)
|
||||
{
|
||||
if (rominfo.io_support[i] == peripheralinfo[j].pID[0]) peripherals |= (1 << j);
|
||||
}
|
||||
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;
|
||||
char pName[14][21];
|
||||
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 (peripherals & (1 << i))
|
||||
{
|
||||
sprintf(pName[max-14],"%s",peripheralinfo[i].pName);
|
||||
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: $%06X", rominfo.romend);
|
||||
break;
|
||||
case 11:
|
||||
if (sram.custom) sprintf (msg, "EEPROM(%dK) - $%06X", ((eeprom.type.size_mask+1)* 8) /1024, (unsigned int)sram.start);
|
||||
else if (sram.detected) sprintf (msg, "SRAM Start - $%06X", rominfo.ramstart);
|
||||
else sprintf (msg, "External RAM undetected");
|
||||
|
||||
break;
|
||||
case 12:
|
||||
if (sram.custom) sprintf (msg, "EEPROM(%dK) - $%06X", ((eeprom.type.size_mask+1)* 8) /1024, (unsigned int)sram.end);
|
||||
else if (sram.detected) sprintf (msg, "SRAM End - $%06X", rominfo.ramend);
|
||||
else if (sram.on) sprintf (msg, "Default SRAM activated ");
|
||||
else sprintf (msg, "SRAM is disactivated ");
|
||||
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", pName[i+j-14]);
|
||||
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;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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]; /* Educational or Game */
|
||||
char product[14]; /* Product 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;
|
@ -1,136 +0,0 @@
|
||||
/***********************************************************
|
||||
* 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,
|
||||
};
|
@ -1,206 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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>
|
||||
|
||||
/* patch_game
|
||||
* set specific configuration for some games
|
||||
*/
|
||||
extern uint8 alttiming;
|
||||
extern uint8 vdptiming;
|
||||
extern uint8 irqtiming;
|
||||
extern uint8 sys_type[2];
|
||||
|
||||
void set_game_default()
|
||||
{
|
||||
|
||||
if ((strstr(rominfo.product,"T-5040") != NULL) || /* Legend of Galahad */
|
||||
(strstr(rominfo.product,"T-50116") != NULL) || /* Road Rash */
|
||||
(strstr(rominfo.product,"T-50496") != NULL) || /* Road Rash II */
|
||||
(strstr(rominfo.product,"T-106143") != NULL) || /* Road Rash II (J) */
|
||||
(strstr(rominfo.product,"T-50966") != NULL) || /* Road Rash III */
|
||||
(strstr(rominfo.product,"MK-1079") != NULL) || /* Sonic The Hedgehog 3 (UE) */
|
||||
(strstr(rominfo.product,"MK-1563") != NULL)) /* Sonic The Hedgehog 3 (J) */
|
||||
{
|
||||
alttiming = 1;
|
||||
}
|
||||
else alttiming = 0;
|
||||
|
||||
/* Sesame Street Counting cafe */
|
||||
if (strstr(rominfo.product,"T-50896") != NULL) irqtiming = 1;
|
||||
else irqtiming = 0;
|
||||
|
||||
/* 6-in-1 Menacer */
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* 05/05/2006: new detection routine */
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
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);
|
||||
getrominfo (cart_rom); /* get infos from ROM Header */
|
||||
set_game_default(); /* patch specific games */
|
||||
genesis_set_region (); /* Region Detection */
|
||||
SRAM_Init (); /* External RAM infos from ROM header */
|
||||
|
||||
|
||||
system_init ();
|
||||
audio_init(48000);
|
||||
ClearGGCodes (); /* Game Genie */
|
||||
decode_ggcodes ();
|
||||
|
||||
system_reset ();
|
||||
if (autoload) sram_autoload();
|
||||
}
|
@ -1,641 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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 ***/
|
||||
memset(cart_rom, 0, 0x500000);
|
||||
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;
|
||||
}
|
@ -1,19 +0,0 @@
|
||||
|
||||
#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>
|
||||
|
||||
#include "gcaram.h"
|
||||
|
||||
|
||||
extern void error (char *format, ...);
|
||||
|
||||
#endif /* _OSD_H_ */
|
@ -1,193 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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"
|
||||
#include "diskio.h"
|
||||
#include "vfat.h"
|
||||
|
||||
extern VFATFS fs;
|
||||
extern FSDIRENTRY f;
|
||||
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 )
|
||||
{
|
||||
VFAT_fseek(&f, 0, SEEK_SET);
|
||||
VFAT_fread(&f, 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) VFAT_fread(&f, readbuffer, 2048);
|
||||
else dvd_read (&readbuffer, 2048, discoffset);
|
||||
}
|
||||
while (res != Z_STREAM_END);
|
||||
|
||||
inflateEnd (&zs);
|
||||
|
||||
if ( UseSDCARD ) VFAT_fclose(&f);
|
||||
|
||||
if (res == Z_STREAM_END)
|
||||
{
|
||||
if (FLIP32 (pkzip.uncompressedSize) == (u32) bufferoffset) return bufferoffset;
|
||||
else return FLIP32 (pkzip.uncompressedSize);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,190 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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);
|
@ -1,99 +0,0 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* Diskio Module
|
||||
* -------------
|
||||
*
|
||||
* This module is almost identical to the one found in ChaN's TinyFAT FS.
|
||||
* It's a logical abstration after all :)
|
||||
*
|
||||
* This covers stdio file on a SD image file
|
||||
****************************************************************************/
|
||||
#include <gccore.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sdcard.h>
|
||||
#include "vfat.h"
|
||||
|
||||
/* Not so public exports from card_io.c */
|
||||
#define MAX_DRIVE 2
|
||||
extern u8 g_CID[MAX_DRIVE][16];
|
||||
extern u8 g_CSD[MAX_DRIVE][16];
|
||||
extern u8 g_CardStatus[MAX_DRIVE][64];
|
||||
extern s32 card_initIO(s32 drv_no);
|
||||
extern s32 card_readSector(s32 drv_no,u32 sector_no,u8 *buf,u32 len);
|
||||
extern s32 card_writeSector(s32 drv_no,u32 sector_no,const void *buf,u32 len);
|
||||
extern s32 card_readStatus(s32 drv_no);
|
||||
#define CARDIO_ERROR_READY 0
|
||||
|
||||
/* End of not so public exports */
|
||||
|
||||
/****************************************************************************
|
||||
* DISKIO_Init
|
||||
*
|
||||
* Initialise communication with the disc
|
||||
****************************************************************************/
|
||||
int DISKIO_Init( int drive )
|
||||
{
|
||||
int res;
|
||||
|
||||
if ( drive < 0 || drive > 1 )
|
||||
return FS_ERR_PARAM;
|
||||
|
||||
res = card_initIO( drive );
|
||||
|
||||
if ( res == CARDIO_ERROR_READY )
|
||||
return FS_SUCCESS;
|
||||
|
||||
return FS_ERR_IO;
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* DISKIO_ReadSectors
|
||||
*
|
||||
* Read sectors from the disc
|
||||
****************************************************************************/
|
||||
int DISKIO_ReadSectors( int drive, void *buffer, int sector, int count )
|
||||
{
|
||||
int res = -1;
|
||||
int i;
|
||||
int bytes = 0;
|
||||
|
||||
if ( drive != 0 && drive != 1 )
|
||||
return FS_ERR_PARAM; /* Must be 0 or 1 */
|
||||
|
||||
/* libOGC appears to only read in single sectors */
|
||||
for( i = 0; i < count; i++ )
|
||||
{
|
||||
res = card_readSector( (int)drive, sector + i, buffer + bytes, SECTOR_SIZE);
|
||||
if ( res != CARDIO_ERROR_READY )
|
||||
return FS_ERR_IO;
|
||||
bytes += SECTOR_SIZE;
|
||||
}
|
||||
|
||||
if ( res == CARDIO_ERROR_READY )
|
||||
return FS_SUCCESS;
|
||||
|
||||
return FS_ERR_IO;
|
||||
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* Diskio Module
|
||||
* -------------
|
||||
*
|
||||
* This module is almost identical to the one found in ChaN's TinyFAT FS.
|
||||
* It's a logical abstration after all :)
|
||||
*
|
||||
* This covers stdio file on a SD image file
|
||||
****************************************************************************/
|
||||
#ifndef __DISKIO__
|
||||
#define __DISKIO__
|
||||
|
||||
int DISKIO_Init( int drive );
|
||||
int DISKIO_ReadSectors( int drive, void *buffer, int sector, int count );
|
||||
|
||||
#endif
|
||||
|
@ -1,841 +0,0 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* $Date: 2007-08-03 13:23:19 +0100 (Fri, 03 Aug 2007) $
|
||||
* $Rev: 3 $
|
||||
****************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "vfat.h"
|
||||
#include "diskio.h"
|
||||
|
||||
static BYTE sector[SECTOR_SIZE]; /* Local sector buffer */
|
||||
static VFATFS *vfs[2]; /* VFAT Pointers for 2 drives */
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define strcasecmp stricmp
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Z E R O S E C T O R / B I O S P A R A M E T E R B L O C K
|
||||
*
|
||||
* These functions take care of parsing the 0th sector/BPB
|
||||
* Supports SuperFloppy Format and standard partitioning.
|
||||
*
|
||||
*/
|
||||
|
||||
static int BPBCheck( BYTE *sector )
|
||||
{
|
||||
BPB16 *bpb = (BPB16 *)sector;
|
||||
|
||||
/* Check signatures */
|
||||
if ( ( bpb->sigkey1 == 0x55 ) && ( bpb->sigkey2 == 0xAA ) )
|
||||
{
|
||||
/* Check for FAT16 signature */
|
||||
if ( memcmp(bpb->FilSysType, "FAT16", 5) == 0 )
|
||||
return FS_TYPE_FAT16;
|
||||
/* Non MS utilities simply put FAT */
|
||||
if ( memcmp(bpb->FilSysType, "FAT", 3) == 0 )
|
||||
return FS_TYPE_FAT16;
|
||||
}
|
||||
|
||||
return FS_TYPE_NONE;
|
||||
}
|
||||
|
||||
static int PECheck( BYTE *sector )
|
||||
{
|
||||
int i;
|
||||
PARTENTRY *pe;
|
||||
|
||||
if ( ( sector[SECTOR_SIZE-2] == 0x55 ) && ( sector[SECTOR_SIZE-1] == 0xAA ) )
|
||||
{
|
||||
/* Find a FAT16 partition entry */
|
||||
for( i = 0; i < 4; i++ )
|
||||
{
|
||||
pe = (PARTENTRY *)(sector + 446 + (i<<4));
|
||||
if ( pe->partitiontype == 0x06 )
|
||||
{
|
||||
return SWAP32(pe->partitionstart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FS_TYPE_NONE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_Mount
|
||||
*
|
||||
* Function to mount a FAT16-VFAT volume
|
||||
***************************************************************************/
|
||||
int VFAT_mount( int driveid, VFATFS *v )
|
||||
{
|
||||
int ret;
|
||||
int bpbsector = 0;
|
||||
BPB16 *bpb = (BPB16 *)sector;
|
||||
BYTE media = 0;
|
||||
|
||||
if ( driveid < 0 || driveid > 1 )
|
||||
return FS_TYPE_NONE;
|
||||
|
||||
memset(v, 0, sizeof(VFATFS));
|
||||
|
||||
/* Copy pointer */
|
||||
vfs[driveid] = v;
|
||||
|
||||
if ( DISKIO_Init( driveid ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
if ( DISKIO_ReadSectors( driveid, sector, 0, 1 ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
/* Check for SuperFloppy Format */
|
||||
ret = BPBCheck( sector );
|
||||
|
||||
if ( ret == FS_TYPE_NONE )
|
||||
{
|
||||
/* Check for Partition Entry */
|
||||
bpbsector = PECheck(sector);
|
||||
if ( !bpbsector )
|
||||
return FS_TYPE_NONE;
|
||||
|
||||
if ( DISKIO_ReadSectors( driveid, sector, bpbsector, 1 ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
/* Check BPB */
|
||||
ret = BPBCheck( sector );
|
||||
}
|
||||
|
||||
if ( ret == FS_TYPE_FAT16 )
|
||||
{
|
||||
/* Capture defaults to machine native format */
|
||||
v->BaseOffset = bpbsector;
|
||||
v->BytesPerSector = SWAP16(bpb->bytesPerSec);
|
||||
v->SectorsPerFAT = SWAP16(bpb->FATsz16);
|
||||
v->ReservedSectors = SWAP16(bpb->reservedSec);
|
||||
v->NumberOfFATs = bpb->numFATs;
|
||||
v->SectorsPerCluster = bpb->secPerClust;
|
||||
v->RootDirEntries = SWAP16(bpb->rootEntCount);
|
||||
|
||||
/* Calculate number of root directory sectors */
|
||||
v->RootDirSectors = ( ( SWAP16(bpb->rootEntCount) << 5 ) + ( v->BytesPerSector - 1 ) ) / v->BytesPerSector;
|
||||
|
||||
/* First data sector */
|
||||
v->FirstDataSector = v->ReservedSectors + (v->NumberOfFATs * v->SectorsPerFAT) + v->RootDirSectors + v->BaseOffset;
|
||||
|
||||
/* Total sectors */
|
||||
if ( bpb->totSec16 == 0 )
|
||||
v->TotalSectors = SWAP32(bpb->totSec32);
|
||||
else
|
||||
v->TotalSectors = SWAP16(bpb->totSec16);
|
||||
|
||||
/* Data Sectors */
|
||||
v->DataSectors = v->TotalSectors - ( v->ReservedSectors + ( v->NumberOfFATs * v->SectorsPerFAT ) + v->RootDirSectors );
|
||||
|
||||
/* Count of clusters */
|
||||
v->CountOfClusters = v->DataSectors / bpb->secPerClust;
|
||||
|
||||
/* From v1.03 Document - Page 14 - FAT Type Determination */
|
||||
if ( v->CountOfClusters < 4085 )
|
||||
return FS_TYPE_NONE; /* FAT12 Volume */
|
||||
else
|
||||
{
|
||||
if ( v->CountOfClusters >= 65525 )
|
||||
return FS_TYPE_NONE; /* FAT32 Volume */
|
||||
}
|
||||
|
||||
/* Root Directory Offset */
|
||||
v->RootDirOffset = v->ReservedSectors + ( bpb->numFATs * v->SectorsPerFAT ) + v->BaseOffset;
|
||||
|
||||
/* First copy of FAT offset */
|
||||
v->FirstFATOffset = v->ReservedSectors + v->BaseOffset;
|
||||
|
||||
media = bpb->media;
|
||||
|
||||
/* Read first FAT */
|
||||
if ( DISKIO_ReadSectors( driveid, sector, v->FirstFATOffset, 1 ) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
if ( sector[0] == media )
|
||||
{
|
||||
/* Allocate work spaces */
|
||||
v->FAT = (WORD *)malloc(v->SectorsPerFAT * SECTOR_SIZE);
|
||||
if ( v->FAT == NULL )
|
||||
return FS_ERR_NOMEM;
|
||||
|
||||
/* Save time running in and out - just load up the FAT table */
|
||||
if ( DISKIO_ReadSectors(driveid, v->FAT, v->FirstFATOffset, v->SectorsPerFAT) != FS_SUCCESS )
|
||||
{
|
||||
free(v->FAT);
|
||||
return FS_ERR_IO;
|
||||
}
|
||||
|
||||
/* Likewise, the same for the root directory */
|
||||
v->rootDir = (BYTE *)malloc(v->BytesPerSector * v->RootDirSectors);
|
||||
if ( v->rootDir == NULL )
|
||||
{
|
||||
free(v->FAT);
|
||||
return FS_ERR_NOMEM;
|
||||
}
|
||||
|
||||
/* Read root directory */
|
||||
if ( DISKIO_ReadSectors(driveid, v->rootDir, v->RootDirOffset, v->RootDirSectors) != FS_SUCCESS )
|
||||
{
|
||||
free(v->FAT);
|
||||
free(v->rootDir);
|
||||
return FS_ERR_IO;
|
||||
}
|
||||
return FS_TYPE_FAT16;
|
||||
}
|
||||
}
|
||||
|
||||
return FS_TYPE_NONE;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* F I L E N A M I N G S U P P O R T
|
||||
*
|
||||
* Routines to en/decode long and short file names
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
* CalcShortNameChecksum
|
||||
*
|
||||
* Calculate the checksum for a short filename
|
||||
* Filename should be in UPPER case, and padded with spaces to match
|
||||
* a standard directory entry
|
||||
****************************************************************************/
|
||||
static unsigned char CalcShortNameCheckSum( BYTE *fname )
|
||||
{
|
||||
int i;
|
||||
unsigned char sum = 0;
|
||||
|
||||
for( i = 0; i < 11; i++ )
|
||||
sum = ( ( sum & 1 ) ? 0x80 : 0 ) + ( sum >> 1 ) + fname[i];
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* BuildShortNameFromDirEntry
|
||||
*
|
||||
* User friendly shortname
|
||||
****************************************************************************/
|
||||
static void BuildShortNameFromDirEntry( SFNDIRREC *sfn, BYTE *out )
|
||||
{
|
||||
int i,j;
|
||||
|
||||
for(i = 0, j = 0; i < 11; i++ )
|
||||
{
|
||||
if ( sfn->dirname[i] != 32 )
|
||||
{
|
||||
out[j++] = sfn->dirname[i];
|
||||
}
|
||||
|
||||
if ( (i == 7) && ( sfn->dirname[8] != 32 ) )
|
||||
out[j++] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* BuildLongNameFromDirEntry
|
||||
*
|
||||
* Build a long name from unicode to asciiz.
|
||||
* Each directory entry may contain up to 13 characters for sub entry.
|
||||
****************************************************************************/
|
||||
static void BuildLongNameFromDirEntry( LFNDIRREC *lfn, int position, BYTE *out )
|
||||
{
|
||||
int j = ( ( position - 1 ) * 13 );
|
||||
int i;
|
||||
|
||||
/* Part one */
|
||||
for( i = 0; i < 10; i += 2 )
|
||||
{
|
||||
if ( lfn->dirname1[i] == 0xFF )
|
||||
return;
|
||||
|
||||
out[j++] = lfn->dirname1[i];
|
||||
}
|
||||
|
||||
/* Part two */
|
||||
for( i = 0; i < 12; i += 2 )
|
||||
{
|
||||
if ( lfn->dirname2[i] == 0xFF )
|
||||
return;
|
||||
|
||||
out[j++] = lfn->dirname2[i];
|
||||
}
|
||||
|
||||
/* Part three */
|
||||
for( i = 0; i < 4; i += 2 )
|
||||
{
|
||||
if ( lfn->dirname3[i] == 0xFF )
|
||||
return;
|
||||
|
||||
out[j++] = lfn->dirname3[i];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* D I R E C T O R Y F U N C T I O N S
|
||||
*
|
||||
* These routines take care of all directory level parsing
|
||||
*/
|
||||
|
||||
static int SectorFromCluster( int drive, int cluster )
|
||||
{
|
||||
VFATFS *v = vfs[drive];
|
||||
return ( ( cluster - 2 ) * v->SectorsPerCluster ) + v->FirstDataSector;
|
||||
}
|
||||
|
||||
static int ReadCluster( FSDIRENTRY *d )
|
||||
{
|
||||
int sector;
|
||||
|
||||
sector = SectorFromCluster( d->driveid, d->CurrentCluster );
|
||||
if ( DISKIO_ReadSectors( d->driveid, d->clusterdata, sector, vfs[d->driveid]->SectorsPerCluster) != FS_SUCCESS )
|
||||
return FS_ERR_IO;
|
||||
|
||||
d->CachedCluster = d->CurrentCluster;
|
||||
return FS_SUCCESS;
|
||||
}
|
||||
|
||||
static int NextCluster( FSDIRENTRY *d )
|
||||
{
|
||||
d->CurrentCluster = SWAP16(vfs[d->driveid]->FAT[d->CurrentCluster]);
|
||||
if ( d->CurrentCluster >= CLUSTER_END_CHAIN )
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* FindEntry
|
||||
*
|
||||
* Look through a directory tree looking for an active entry.
|
||||
* The current cluster should be available in d->clusterdata
|
||||
****************************************************************************/
|
||||
static int FindEntry( FSDIRENTRY *d, int maxentries )
|
||||
{
|
||||
int found = 0;
|
||||
unsigned char *direntry;
|
||||
VFATFS *v = vfs[d->driveid];
|
||||
SFNDIRREC *sfn;
|
||||
LFNDIRREC *lfn;
|
||||
static BYTE checksum = 0;
|
||||
|
||||
if ( !d->crosscluster )
|
||||
{
|
||||
/* Clear names */
|
||||
memset(d->shortname, 0, 13);
|
||||
memset(d->longname, 0, MAX_LONG_NAME);
|
||||
}
|
||||
|
||||
while( d->CurrentDirEntry < maxentries && !found )
|
||||
{
|
||||
/* Pointer to this directory entry */
|
||||
if ( d->CurrentCluster == ROOTCLUSTER )
|
||||
direntry = (v->rootDir + ( d->CurrentDirEntry << 5 ) );
|
||||
else
|
||||
direntry = (d->clusterdata + ( d->CurrentDirEntry << 5 ) );
|
||||
|
||||
switch( direntry[0] )
|
||||
{
|
||||
case 0x00:
|
||||
case 0xE5:
|
||||
break; /* Inactive entries */
|
||||
|
||||
default:
|
||||
|
||||
sfn = (SFNDIRREC *)direntry;
|
||||
d->crosscluster = 1;
|
||||
|
||||
if ( ( sfn->attribute & ATTR_LONG_NAME_MASK ) == ATTR_LONG_NAME )
|
||||
{
|
||||
if ( direntry[0] & LFN_LAST_ENTRY )
|
||||
memset(&d->longname, 0, MAX_LONG_NAME);
|
||||
|
||||
lfn = (LFNDIRREC *)direntry;
|
||||
BuildLongNameFromDirEntry( lfn, direntry[0] & LFN_ENTRY_MASK, d->longname);
|
||||
checksum = lfn->checksum;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Short name entry */
|
||||
found = 1;
|
||||
memcpy(&d->dirent, direntry, 32);
|
||||
BuildShortNameFromDirEntry( sfn, d->shortname );
|
||||
d->fsize = SWAP32(sfn->filesize);
|
||||
d->crosscluster = 0;
|
||||
/* Ensure long name is populated with something */
|
||||
if ( strlen((char *)d->longname) == 0 )
|
||||
{
|
||||
strcpy((char *)d->longname, (char *)d->shortname);
|
||||
return found;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If checksums don't match - the FS is inconsistent
|
||||
To do no harm, skip this entry */
|
||||
if ( checksum == CalcShortNameCheckSum(sfn->dirname) )
|
||||
return found;
|
||||
else
|
||||
found = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
d->CurrentDirEntry++;
|
||||
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* FindInRootDirectory
|
||||
*
|
||||
* Root directory is somewhat special. It's a fixed length and has no entry
|
||||
* in the FAT as such.
|
||||
*
|
||||
* Logically, this should be the first 2 clusters, but the spec says it can
|
||||
* be set to any size by the format utility (Think NT! FAT64/128/256)
|
||||
*
|
||||
* For speed, as all searches begin here, the root directory is held in
|
||||
* memory throughout.
|
||||
*
|
||||
* FSDIRENTRY should only have the drive id set.
|
||||
****************************************************************************/
|
||||
static int FindInRootDirectory( FSDIRENTRY *d, char *search )
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
d->CurrentDirEntry++;
|
||||
|
||||
while( (FindEntry(d, vfs[d->driveid]->RootDirEntries)) && !found )
|
||||
{
|
||||
if ( strcasecmp(search, (char *) d->shortname) == 0 )
|
||||
{
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if ( strcasecmp(search, (char *) d->longname) == 0 )
|
||||
{
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
d->CurrentDirEntry++;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* FindInClusters
|
||||
*
|
||||
* Generic routine to find a given name in a chain of clusters.
|
||||
* Used for non-Root Directory searching
|
||||
****************************************************************************/
|
||||
static int FindInClusters( FSDIRENTRY *d, char *findme )
|
||||
{
|
||||
int found = 0;
|
||||
|
||||
if ( d->CurrentDirEntry == -1 )
|
||||
d->CurrentDirEntry = 0;
|
||||
|
||||
/* While not at end of chain */
|
||||
while( !found && ( d->CurrentCluster < CLUSTER_END_CHAIN ) )
|
||||
{
|
||||
/* Retrieve dir entries looking for match */
|
||||
while( !found && (FindEntry( d, ( vfs[d->driveid]->BytesPerSector * vfs[d->driveid]->SectorsPerCluster) >> 5 ) ) )
|
||||
{
|
||||
if ( strcasecmp((char *)d->shortname, findme) == 0 )
|
||||
found = 1;
|
||||
if ( strcasecmp((char *)d->longname, findme) == 0 )
|
||||
found = 1;
|
||||
|
||||
if (!found)
|
||||
d->CurrentDirEntry++;
|
||||
}
|
||||
|
||||
/* Read next cluster */
|
||||
if ( !found )
|
||||
{
|
||||
if ( NextCluster(d) )
|
||||
{
|
||||
d->CurrentDirEntry = 0;
|
||||
ReadCluster(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_opendir
|
||||
*
|
||||
* Find the requested directory.
|
||||
****************************************************************************/
|
||||
int VFAT_opendir( int drive, FSDIRENTRY *d, char *search )
|
||||
{
|
||||
char *p;
|
||||
char srchtmp[1024];
|
||||
int searchroot = 1;
|
||||
int found = 0;
|
||||
|
||||
/* Clear out FSDIRENTRY */
|
||||
memset(d, 0, sizeof(FSDIRENTRY));
|
||||
|
||||
/* Set drive and root */
|
||||
d->driveid = drive;
|
||||
d->CurrentCluster = ROOTCLUSTER;
|
||||
d->CurrentDirEntry = -1;
|
||||
|
||||
/* Is this a request for root ? */
|
||||
if ( ( strlen(search) == 0 ) || ( strcmp(search,PSEPS) == 0 ) || ( strcmp(search, DIR_ROOT) == 0 ) )
|
||||
{
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
|
||||
/* Searching for a sub-directory */
|
||||
if ( search[0] == PSEP )
|
||||
strcpy(srchtmp, &search[1]);
|
||||
else
|
||||
strcpy(srchtmp, search);
|
||||
|
||||
p = strtok(srchtmp, PSEPS);
|
||||
while ( p )
|
||||
{
|
||||
found = 0;
|
||||
if ( searchroot )
|
||||
{
|
||||
if ( !FindInRootDirectory(d, p) )
|
||||
return FS_NO_FILE;
|
||||
else
|
||||
{
|
||||
/* MUST be a directory */
|
||||
if ( d->dirent.attribute & ATTR_DIRECTORY )
|
||||
{
|
||||
d->CurrentCluster = d->FirstCluster = SWAP16(d->dirent.fstClustLow);
|
||||
d->CurrentDirEntry = -1;
|
||||
|
||||
/* Allocate the cluster for this data record */
|
||||
d->clusterdata = (BYTE *)malloc(vfs[d->driveid]->SectorsPerCluster * vfs[d->driveid]->BytesPerSector);
|
||||
ReadCluster(d);
|
||||
found = 1;
|
||||
searchroot = 0;
|
||||
}
|
||||
else
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( FindInClusters( d, p ) )
|
||||
{
|
||||
/* MUST be a directory */
|
||||
if ( !( d->dirent.attribute & ATTR_DIRECTORY ) )
|
||||
{
|
||||
free(d->clusterdata);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
/* Read up this cluster */
|
||||
d->CurrentCluster = d->FirstCluster = SWAP16(d->dirent.fstClustLow);
|
||||
d->CurrentDirEntry = 0;
|
||||
ReadCluster(d);
|
||||
found = 1;
|
||||
}
|
||||
}
|
||||
|
||||
p = strtok(NULL, PSEPS);
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
{
|
||||
if ( d->clusterdata != NULL )
|
||||
{
|
||||
free(d->clusterdata);
|
||||
d->clusterdata = NULL;
|
||||
}
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
return FS_FILE_OK;
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_readdir
|
||||
****************************************************************************/
|
||||
int VFAT_readdir( FSDIRENTRY *d )
|
||||
{
|
||||
int ret;
|
||||
|
||||
d->CurrentDirEntry++;
|
||||
/* Are we in root ? */
|
||||
if ( d->CurrentCluster == ROOTCLUSTER )
|
||||
{
|
||||
if( FindEntry( d, vfs[d->driveid]->RootDirEntries ) )
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
while( d->CurrentCluster < CLUSTER_END_CHAIN )
|
||||
{
|
||||
ret = FindEntry( d, ( vfs[d->driveid]->BytesPerSector * vfs[d->driveid]->SectorsPerCluster) >> 5 );
|
||||
|
||||
if ( ret )
|
||||
return FS_FILE_OK;
|
||||
|
||||
if ( NextCluster(d) )
|
||||
{
|
||||
d->CurrentDirEntry = 0;
|
||||
ReadCluster(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_closedir
|
||||
****************************************************************************/
|
||||
void VFAT_closedir( FSDIRENTRY *d )
|
||||
{
|
||||
if ( d->clusterdata != NULL )
|
||||
{
|
||||
free(d->clusterdata);
|
||||
d->clusterdata = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fopen
|
||||
*
|
||||
* v0.1 - VFAT_READ_ONLY Supported
|
||||
****************************************************************************/
|
||||
int VFAT_fopen( int drive, FSDIRENTRY *d, char *fname, int mode )
|
||||
{
|
||||
char filename[1024];
|
||||
char path[1024];
|
||||
char temp[1024];
|
||||
char *p;
|
||||
|
||||
if ( drive < 0 || drive > 1 )
|
||||
return FS_NO_FILE;
|
||||
|
||||
if ( mode != FS_READ )
|
||||
return FS_NO_FILE;
|
||||
|
||||
/* Clear */
|
||||
memset(d, 0, sizeof(FSDIRENTRY));
|
||||
d->driveid = drive;
|
||||
|
||||
path[0] = temp[0] = filename[0] = 0;
|
||||
|
||||
if ( fname[0] == PSEP )
|
||||
strcpy(temp, &fname[1]);
|
||||
else
|
||||
strcpy(temp, fname);
|
||||
|
||||
/* Split into filename and path */
|
||||
p = strrchr(temp, PSEP);
|
||||
if ( p )
|
||||
{
|
||||
/* Have path and filename */
|
||||
*p = 0;
|
||||
strcpy(path, temp);
|
||||
p++;
|
||||
strcpy(filename, p);
|
||||
}
|
||||
else
|
||||
strcpy(filename, temp);
|
||||
|
||||
/* Do search */
|
||||
if ( strlen(path) )
|
||||
{
|
||||
if ( VFAT_opendir(drive, d, path) != FS_FILE_OK )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
if ( !FindInClusters( d, filename ) )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Much simpler check on root directory */
|
||||
d->CurrentCluster = ROOTCLUSTER;
|
||||
d->CurrentDirEntry = -1;
|
||||
if ( !FindInRootDirectory( d, filename ) )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
d->clusterdata = (BYTE *)malloc(vfs[d->driveid]->SectorsPerCluster * vfs[d->driveid]->BytesPerSector);
|
||||
}
|
||||
|
||||
/* Must be a file only */
|
||||
if ( d->dirent.attribute & ( ATTR_DIRECTORY | ATTR_VOLUME_ID ) )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
d->FirstCluster = d->CurrentCluster = SWAP16(d->dirent.fstClustLow);
|
||||
d->CachedCluster = -1;
|
||||
|
||||
return FS_FILE_OK;
|
||||
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fclose
|
||||
****************************************************************************/
|
||||
void VFAT_fclose( FSDIRENTRY *d )
|
||||
{
|
||||
VFAT_closedir(d);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fread
|
||||
****************************************************************************/
|
||||
int VFAT_fread( FSDIRENTRY *d, void *buffer, int length )
|
||||
{
|
||||
int cluster;
|
||||
int tbytes;
|
||||
int umask;
|
||||
int i;
|
||||
int bytesdone = 0;
|
||||
int reallength;
|
||||
BYTE *p = (BYTE *)buffer;
|
||||
|
||||
if ( length <= 0 )
|
||||
return 0;
|
||||
|
||||
/* Determine which cluster in the chain we are in */
|
||||
tbytes = ( vfs[d->driveid]->SectorsPerCluster * vfs[d->driveid]->BytesPerSector );
|
||||
umask = tbytes - 1;
|
||||
cluster = ( d->fpos / tbytes );
|
||||
|
||||
/* Rewind current cluster */
|
||||
d->CurrentCluster = d->FirstCluster;
|
||||
|
||||
/* Bring this cluster into view */
|
||||
for ( i = 0; i < cluster; i++ )
|
||||
d->CurrentCluster = SWAP16(vfs[d->driveid]->FAT[d->CurrentCluster]);
|
||||
|
||||
/* Read the cluster */
|
||||
if ( d->CachedCluster != d->CurrentCluster )
|
||||
ReadCluster(d);
|
||||
|
||||
/* Get real read length */
|
||||
reallength = ( d->fpos + length ) < d->fsize ? length : d->fsize - d->fpos;
|
||||
|
||||
if ( reallength <= 0 )
|
||||
return 0;
|
||||
|
||||
/* Move data */
|
||||
while( reallength )
|
||||
{
|
||||
if ( !(d->fpos & umask) && ( reallength >= tbytes ) )
|
||||
{
|
||||
/* Move a full cluster */
|
||||
memcpy(p + bytesdone, d->clusterdata, tbytes);
|
||||
reallength -= tbytes;
|
||||
bytesdone += tbytes;
|
||||
d->fpos += tbytes;
|
||||
}
|
||||
else
|
||||
{
|
||||
p[bytesdone++] = d->clusterdata[d->fpos & umask];
|
||||
d->fpos++;
|
||||
reallength--;
|
||||
}
|
||||
|
||||
if ( !( d->fpos & umask ) )
|
||||
{
|
||||
if ( NextCluster(d) )
|
||||
{
|
||||
ReadCluster(d);
|
||||
}
|
||||
else
|
||||
return bytesdone;
|
||||
}
|
||||
}
|
||||
|
||||
return bytesdone;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_fseek
|
||||
****************************************************************************/
|
||||
int VFAT_fseek( FSDIRENTRY *d, int where, int whence )
|
||||
{
|
||||
switch( whence )
|
||||
{
|
||||
case SEEK_SET:
|
||||
if ( ( where >= 0 ) && ( where <= d->fsize ) )
|
||||
{
|
||||
d->fpos = where;
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEEK_CUR:
|
||||
if ( ( ( d->fpos + where ) >= 0 ) && ( ( d->fpos + where ) <= d->fsize ) )
|
||||
{
|
||||
d->fpos += where;
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
break;
|
||||
|
||||
case SEEK_END:
|
||||
if ( ( where <= 0 ) && ( abs(where) <= d->fsize ) )
|
||||
{
|
||||
d->fpos = d->fsize + where;
|
||||
return FS_FILE_OK;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FS_NO_FILE;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* VFAT_ftell
|
||||
*
|
||||
* Return the current position of a file
|
||||
****************************************************************************/
|
||||
int VFAT_ftell( FSDIRENTRY *d )
|
||||
{
|
||||
return d->fpos;
|
||||
}
|
||||
|
@ -1,226 +0,0 @@
|
||||
/****************************************************************************
|
||||
* FAT16 - VFAT Support
|
||||
*
|
||||
* NOTE: Only supports FAT16 with Long File Names
|
||||
* I have no interest in adding FAT32
|
||||
*
|
||||
* Reference Documentation:
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.02 May 05, 1999
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* FAT: General Overview of On-Disk Format
|
||||
* Version 1.03 December 06, 2000
|
||||
* Microsoft Corporation
|
||||
*
|
||||
* This is targetted at MMC/SD cards.
|
||||
*
|
||||
* Copyright softdev 2007. All rights reserved.
|
||||
*
|
||||
* $Date: 2007-08-03 13:23:19 +0100 (Fri, 03 Aug 2007) $
|
||||
* $Rev: 3 $
|
||||
****************************************************************************/
|
||||
#ifndef __FATVFAT__
|
||||
#define __FATVFAT__
|
||||
|
||||
/* x86 type definitions */
|
||||
typedef unsigned int DWORD;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
/* Big Endian Support */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define SWAP16(a) (((a&0xff)<<8) | ((a&0xff00)>>8))
|
||||
#define SWAP32(a) (((a&0xff000000)>>24) | ((a&0xff0000) >> 8) | ((a&0xff00)<<8) |((a&0xff)<<24))
|
||||
#else
|
||||
#define SWAP16(a) (a)
|
||||
#define SWAP32(a) (a)
|
||||
#endif
|
||||
|
||||
/* General */
|
||||
#define SECTOR_SIZE 512
|
||||
#define SECTOR_SHIFT_BITS 9
|
||||
#define LFN_LAST_ENTRY 0x40
|
||||
#define LFN_ENTRY_MASK 0x3F
|
||||
#define ROOTCLUSTER 0xdeadc0de
|
||||
#define PSEP '/'
|
||||
#define PSEPS "/"
|
||||
#define DIR_ROOT "."
|
||||
#define DIR_PARENT ".."
|
||||
|
||||
/* FSTYPES */
|
||||
#define FS_TYPE_NONE 0
|
||||
#define FS_TYPE_FAT16 1
|
||||
|
||||
/* Errors */
|
||||
#define FS_FILE_OK 0
|
||||
#define FS_SUCCESS FS_FILE_OK
|
||||
#define FS_ERR_NOMEM -128
|
||||
#define FS_NO_FILE -64
|
||||
#define FS_ERR_IO -32
|
||||
#define FS_ERR_PARAM -16
|
||||
|
||||
/* File modes */
|
||||
#define FS_READ 1
|
||||
|
||||
/* Gamecube Specific */
|
||||
#define FS_SLOTA 0
|
||||
#define FS_SLOTB 1
|
||||
|
||||
/* FAT12/16 */
|
||||
typedef struct
|
||||
{
|
||||
BYTE jmpBoot[3]; /* Always 0xEBxx90 or 0xE9xxxx */
|
||||
BYTE OEMName[8]; /* OEM Name 'MSWIN4.1' or similar */
|
||||
WORD bytesPerSec; /* Bytes per sector */
|
||||
BYTE secPerClust; /* Sectors per cluster */
|
||||
WORD reservedSec; /* Reserved Sector Count */
|
||||
BYTE numFATs; /* Number of FAT copies */
|
||||
WORD rootEntCount; /* FAT12/16 number of root entries. */
|
||||
WORD totSec16; /* Sector count if < 0x10000 */
|
||||
BYTE media; /* Media ID byte (HD == 0xF8) */
|
||||
WORD FATsz16; /* Sectors occupied by one copy of FAT */
|
||||
WORD secPerTrack; /* Sectors per track */
|
||||
WORD numHeads; /* Number of heads */
|
||||
DWORD hiddenSec; /* Hidden sector count */
|
||||
DWORD totSec32; /* Total sectors when >= 0x10000 */
|
||||
BYTE drvNum; /* BIOS Drive Number (0x80) */
|
||||
BYTE reserved1; /* Unused - always zero */
|
||||
BYTE bootSig; /* Boot signature */
|
||||
DWORD volID; /* Volume serial number */
|
||||
BYTE volName[11]; /* Volume Name */
|
||||
BYTE FilSysType[8]; /* File system type */
|
||||
BYTE filler[SECTOR_SIZE-64];
|
||||
BYTE sigkey1; /* 0x55 */
|
||||
BYTE sigkey2; /* 0xAA */
|
||||
}
|
||||
__attribute__((__packed__)) BPB16;
|
||||
|
||||
/* Partition entry */
|
||||
typedef struct
|
||||
{
|
||||
BYTE bootindicator;
|
||||
BYTE startCHS[3];
|
||||
BYTE partitiontype;
|
||||
BYTE endCHS[3];
|
||||
DWORD partitionstart;
|
||||
DWORD partitionsize;
|
||||
}
|
||||
__attribute__((__packed__)) PARTENTRY;
|
||||
|
||||
/* VFAT - Main structure */
|
||||
typedef struct
|
||||
{
|
||||
DWORD BaseOffset;
|
||||
DWORD SectorsPerCluster;
|
||||
DWORD BytesPerSector;
|
||||
DWORD ReservedSectors;
|
||||
DWORD RootDirSectors;
|
||||
DWORD SectorsPerFAT;
|
||||
DWORD NumberOfFATs;
|
||||
DWORD FirstDataSector;
|
||||
DWORD TotalSectors;
|
||||
DWORD CountOfClusters;
|
||||
DWORD DataSectors;
|
||||
DWORD RootDirOffset;
|
||||
DWORD FirstFATOffset;
|
||||
DWORD RootDirEntries;
|
||||
WORD *FAT; /* Holds first FAT copy */
|
||||
BYTE *rootDir; /* Holds entire root directory */
|
||||
}
|
||||
__attribute__((__packed__)) VFATFS;
|
||||
|
||||
/**
|
||||
* Directory
|
||||
*/
|
||||
|
||||
#define MAX_LONG_NAME 256
|
||||
|
||||
/* Directory entry attributes */
|
||||
#define ATTR_READ_ONLY 0x01
|
||||
#define ATTR_HIDDEN 0x02
|
||||
#define ATTR_SYSTEM 0x04
|
||||
#define ATTR_VOLUME_ID 0x08
|
||||
#define ATTR_DIRECTORY 0x10
|
||||
#define ATTR_ARCHIVE 0x20
|
||||
#define ATTR_LONG_NAME (ATTR_READ_ONLY | \
|
||||
ATTR_HIDDEN | \
|
||||
ATTR_SYSTEM | \
|
||||
ATTR_VOLUME_ID )
|
||||
|
||||
#define ATTR_LONG_NAME_MASK ( ATTR_READ_ONLY | \
|
||||
ATTR_HIDDEN | \
|
||||
ATTR_SYSTEM | \
|
||||
ATTR_VOLUME_ID | \
|
||||
ATTR_DIRECTORY | \
|
||||
ATTR_ARCHIVE )
|
||||
|
||||
#define CLUSTER_END_CHAIN 0xFFF8
|
||||
#define CLUSTER_BAD 0xFFF7
|
||||
|
||||
/* Short file name */
|
||||
typedef struct
|
||||
{
|
||||
BYTE dirname[11]; /* Record name */
|
||||
BYTE attribute; /* Attributes */
|
||||
BYTE NTReserved; /* Reserved for Window NT - set 0 */
|
||||
BYTE dirTenthSecs; /* Tenth of a second, 0-199 */
|
||||
WORD dirCreateTime; /* Time of creation */
|
||||
WORD dirCreateDate; /* Date of creation */
|
||||
WORD dirLastAccDate;/* Date of last access */
|
||||
WORD fstClustHigh; /* High word of first cluster - ZERO on FAT16 */
|
||||
WORD dirWriteTime; /* Time of last write */
|
||||
WORD dirWriteDate; /* Date of last write */
|
||||
WORD fstClustLow; /* Low word of first cluster */
|
||||
DWORD filesize; /* Filesize in bytes */
|
||||
}
|
||||
__attribute__((__packed__)) SFNDIRREC;
|
||||
|
||||
/* Long file name */
|
||||
typedef struct
|
||||
{
|
||||
BYTE ordinal; /* Entry number */
|
||||
BYTE dirname1[10];
|
||||
BYTE attribute; /* Attributes */
|
||||
BYTE type; /* Reserved */
|
||||
BYTE checksum; /* SFN Checksum */
|
||||
BYTE dirname2[12];
|
||||
WORD fstClustLo; /* MUST BE ZERO */
|
||||
BYTE dirname3[4];
|
||||
}
|
||||
__attribute__((__packed__)) LFNDIRREC;
|
||||
|
||||
/* User dir entry */
|
||||
typedef struct
|
||||
{
|
||||
BYTE longname[MAX_LONG_NAME];
|
||||
BYTE shortname[13]; /* Keep word aligned*/
|
||||
DWORD fpos;
|
||||
DWORD fsize;
|
||||
DWORD driveid;
|
||||
DWORD FirstCluster;
|
||||
DWORD CurrentCluster;
|
||||
DWORD CachedCluster;
|
||||
DWORD CurrentDirEntry;
|
||||
DWORD crosscluster;
|
||||
BYTE *clusterdata;
|
||||
/* Now a copy of the current directory entry */
|
||||
SFNDIRREC dirent;
|
||||
}
|
||||
__attribute__((__packed__)) FSDIRENTRY;
|
||||
|
||||
/* VFAT API */
|
||||
/* Directory */
|
||||
int VFAT_opendir( int drive, FSDIRENTRY *d, char *search );
|
||||
int VFAT_readdir( FSDIRENTRY *d );
|
||||
void VFAT_closedir( FSDIRENTRY *d );
|
||||
int VFAT_fopen( int drive, FSDIRENTRY *d, char *fname, int mode );
|
||||
void VFAT_fclose( FSDIRENTRY *d );
|
||||
int VFAT_fread( FSDIRENTRY *d, void *buffer, int length );
|
||||
int VFAT_ftell( FSDIRENTRY *d );
|
||||
int VFAT_fseek( FSDIRENTRY *d, int where, int whence );
|
||||
int VFAT_mount( int driveid, VFATFS *v );
|
||||
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,53 +0,0 @@
|
||||
|
||||
#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_ */
|
||||
|
@ -1,43 +0,0 @@
|
||||
#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_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,205 +0,0 @@
|
||||
/*
|
||||
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_ */
|
@ -1,290 +0,0 @@
|
||||
/*
|
||||
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;
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
|
||||
#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_ */
|
||||
|
@ -1,311 +0,0 @@
|
||||
|
||||
#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;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
#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
|
@ -1,224 +0,0 @@
|
||||
/*
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
|
||||
#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_ */
|
File diff suppressed because it is too large
Load Diff
@ -1,171 +0,0 @@
|
||||
#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
|
@ -1,77 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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();
|
||||
}
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
|
@ -1,98 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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;
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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
|
@ -1,358 +0,0 @@
|
||||
/****************************************************************************
|
||||
* 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]);
|
||||
color_update (0x40, *(uint16 *)&cram[border << 1]);
|
||||
color_update (0x80, *(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);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user