mirror of
https://github.com/wavemotion-dave/NINTV-DS.git
synced 2025-06-18 13:55:33 -04:00
First commit of semi-working emulator!
This commit is contained in:
parent
6152092a85
commit
30f0688492
44
Makefile
Normal file
44
Makefile
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#export DEVKITPRO=/opt/devkitpro
|
||||||
|
#export DEVKITARM=/opt/devkitpro/devkitARM
|
||||||
|
#
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SECONDARY:
|
||||||
|
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
export TARGET := NINTV-DS
|
||||||
|
export TOPDIR := $(CURDIR)
|
||||||
|
export VERSION := 0.5
|
||||||
|
|
||||||
|
ICON := -b $(CURDIR)/logo.bmp "NINTV-DS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/NINTV-DS"
|
||||||
|
|
||||||
|
.PHONY: arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
all: $(TARGET).nds
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf
|
||||||
|
ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf $(ICON)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
arm7/$(TARGET).elf:
|
||||||
|
$(MAKE) -C arm7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
arm9/$(TARGET).elf:
|
||||||
|
$(MAKE) -C arm9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
$(MAKE) -C arm9 clean
|
||||||
|
$(MAKE) -C arm7 clean
|
||||||
|
rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9
|
127
arm7/Makefile
Normal file
127
arm7/Makefile
Normal file
@ -0,0 +1,127 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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
|
||||||
|
# DATA is a list of directories containing binary files
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source
|
||||||
|
INCLUDES := include build
|
||||||
|
DATA :=
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ARCH := -mthumb-interwork
|
||||||
|
|
||||||
|
CFLAGS := -g -Wall -O2\
|
||||||
|
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
|
||||||
|
-ffast-math \
|
||||||
|
$(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -DARM7
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti
|
||||||
|
|
||||||
|
|
||||||
|
ASFLAGS := -g $(ARCH)
|
||||||
|
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map
|
||||||
|
|
||||||
|
#LIBS := -ldswifi7 -lmm7 -lnds7
|
||||||
|
LIBS := -ldswifi7 -lnds7
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBNDS)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 ARM7ELF := $(CURDIR)/$(TARGET).elf
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
|
||||||
|
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||||
|
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) *.elf
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
DEPENDS := $(OFILES:.o=.d)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(ARM7ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
83
arm7/source/emusoundfifo.c
Normal file
83
arm7/source/emusoundfifo.c
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
#include <nds/arm7/audio.h>
|
||||||
|
#include <nds/fifocommon.h>
|
||||||
|
#include <nds/fifomessages.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMUARM7_INIT_SND = 0x123C,
|
||||||
|
EMUARM7_STOP_SND = 0x123D,
|
||||||
|
EMUARM7_PLAY_SND = 0x123E,
|
||||||
|
} FifoMesType;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void soundEmuDataHandler(int bytes, void *user_data)
|
||||||
|
{
|
||||||
|
int channel = -1;
|
||||||
|
|
||||||
|
FifoMessage msg;
|
||||||
|
|
||||||
|
fifoGetDatamsg(FIFO_USER_01, bytes, (u8*)&msg);
|
||||||
|
|
||||||
|
switch (msg.type) {
|
||||||
|
case EMUARM7_PLAY_SND:
|
||||||
|
channel = (msg.SoundPlay.format & 0xF0)>>4;
|
||||||
|
SCHANNEL_SOURCE(channel) = (u32)msg.SoundPlay.data;
|
||||||
|
SCHANNEL_REPEAT_POINT(channel) = msg.SoundPlay.loopPoint;
|
||||||
|
SCHANNEL_LENGTH(channel) = msg.SoundPlay.dataSize;
|
||||||
|
SCHANNEL_TIMER(channel) = SOUND_FREQ(msg.SoundPlay.freq);
|
||||||
|
SCHANNEL_CR(channel) = SCHANNEL_ENABLE | SOUND_VOL(msg.SoundPlay.volume) | SOUND_PAN(msg.SoundPlay.pan) | ((msg.SoundPlay.format & 0xF) << 29) | (msg.SoundPlay.loop ? SOUND_REPEAT : SOUND_ONE_SHOT);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EMUARM7_INIT_SND:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EMUARM7_STOP_SND:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void soundEmuCommandHandler(u32 command, void* userdata) {
|
||||||
|
int cmd = (command ) & 0x00F00000;
|
||||||
|
int data = command & 0xFFFF;
|
||||||
|
int channel = (command >> 16) & 0xF;
|
||||||
|
|
||||||
|
switch(cmd)
|
||||||
|
{
|
||||||
|
|
||||||
|
case SOUND_SET_VOLUME:
|
||||||
|
SCHANNEL_CR(channel) &= ~0xFF;
|
||||||
|
SCHANNEL_CR(channel) |= data;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOUND_SET_PAN:
|
||||||
|
SCHANNEL_CR(channel) &= ~SOUND_PAN(0xFF);
|
||||||
|
SCHANNEL_CR(channel) |= SOUND_PAN(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOUND_SET_FREQ:
|
||||||
|
SCHANNEL_TIMER(channel) = SOUND_FREQ(data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOUND_SET_WAVEDUTY:
|
||||||
|
SCHANNEL_CR(channel) &= ~(7 << 24);
|
||||||
|
SCHANNEL_CR(channel) |= (data) << 24;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOUND_KILL:
|
||||||
|
case SOUND_PAUSE:
|
||||||
|
SCHANNEL_CR(channel) &= ~SCHANNEL_ENABLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SOUND_RESUME:
|
||||||
|
SCHANNEL_CR(channel) |= SCHANNEL_ENABLE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void installSoundEmuFIFO(void) {
|
||||||
|
fifoSetDatamsgHandler(FIFO_USER_01, soundEmuDataHandler, 0);
|
||||||
|
fifoSetValue32Handler(FIFO_USER_01, soundEmuCommandHandler, 0);
|
||||||
|
}
|
95
arm7/source/main.c
Normal file
95
arm7/source/main.c
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
/*---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
default ARM7 core
|
||||||
|
|
||||||
|
Copyright (C) 2005 - 2010
|
||||||
|
Michael Noland (joat)
|
||||||
|
Jason Rogers (dovoto)
|
||||||
|
Dave Murphy (WinterMute)
|
||||||
|
|
||||||
|
This software is provided 'as-is', without any express or implied
|
||||||
|
warranty. In no event will the authors be held liable for any
|
||||||
|
damages arising from the use of this software.
|
||||||
|
|
||||||
|
Permission is granted to anyone to use this software for any
|
||||||
|
purpose, including commercial applications, and to alter it and
|
||||||
|
redistribute it freely, subject to the following restrictions:
|
||||||
|
|
||||||
|
1. The origin of this software must not be misrepresented; you
|
||||||
|
must not claim that you wrote the original software. If you use
|
||||||
|
this software in a product, an acknowledgment in the product
|
||||||
|
documentation would be appreciated but is not required.
|
||||||
|
|
||||||
|
2. Altered source versions must be plainly marked as such, and
|
||||||
|
must not be misrepresented as being the original software.
|
||||||
|
|
||||||
|
3. This notice may not be removed or altered from any source
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------------*/
|
||||||
|
#include <nds.h>
|
||||||
|
#include <dswifi7.h>
|
||||||
|
#include <maxmod7.h>
|
||||||
|
|
||||||
|
extern void installSoundEmuFIFO(void);
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void VblankHandler(void) {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
Wifi_Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void VcountHandler() {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
inputGetAndSend();
|
||||||
|
}
|
||||||
|
|
||||||
|
volatile bool exitflag = false;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
void powerButtonCB() {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
exitflag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
int main() {
|
||||||
|
//---------------------------------------------------------------------------------
|
||||||
|
readUserSettings();
|
||||||
|
|
||||||
|
irqInit();
|
||||||
|
// Start the RTC tracking IRQ
|
||||||
|
initClockIRQ();
|
||||||
|
touchInit();
|
||||||
|
fifoInit();
|
||||||
|
|
||||||
|
//mmInstall(FIFO_MAXMOD);
|
||||||
|
|
||||||
|
SetYtrigger(80);
|
||||||
|
|
||||||
|
installWifiFIFO();
|
||||||
|
installSoundFIFO();
|
||||||
|
|
||||||
|
installSystemFIFO();
|
||||||
|
|
||||||
|
installSoundEmuFIFO();
|
||||||
|
|
||||||
|
irqSet(IRQ_VCOUNT, VcountHandler);
|
||||||
|
irqSet(IRQ_VBLANK, VblankHandler);
|
||||||
|
|
||||||
|
irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);
|
||||||
|
|
||||||
|
setPowerButtonCB(powerButtonCB);
|
||||||
|
|
||||||
|
// Keep the ARM7 mostly idle
|
||||||
|
while (!exitflag) {
|
||||||
|
if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) {
|
||||||
|
exitflag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
swiWaitForVBlank();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
141
arm9/Makefile
Normal file
141
arm9/Makefile
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
.SUFFIXES:
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(DEVKITARM)),)
|
||||||
|
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(DEVKITARM)/ds_rules
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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
|
||||||
|
# DATA is a list of directories containing binary files
|
||||||
|
# all directories are relative to this makefile
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
BUILD := build
|
||||||
|
SOURCES := source/emucore source/common source
|
||||||
|
INCLUDES := source/emucore source/common include
|
||||||
|
DATA := data
|
||||||
|
GRAPHICS := gfx
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# options for code generation
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
#ARCH := -mthumb -mthumb-interwork
|
||||||
|
ARCH :=
|
||||||
|
|
||||||
|
#CFLAGS := -g -Wall -O2 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH)
|
||||||
|
CFLAGS := -Wno-address-of-packed-member -Wno-multichar -O3 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH)
|
||||||
|
|
||||||
|
CFLAGS += $(INCLUDE) -DARM9
|
||||||
|
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -Wno-conversion-null
|
||||||
|
|
||||||
|
#ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
|
||||||
|
ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s
|
||||||
|
|
||||||
|
LDFLAGS = -specs=ds_arm9.specs $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
//LDFLAGS = -specs=../ds_arm9_hi.specs $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# any extra libraries we wish to link with the project
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBS := -lfat -lnds9
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# list of directories containing libraries, this must be the top level containing
|
||||||
|
# include and lib
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
LIBDIRS := $(LIBNDS)
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# 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 ARM9ELF := $(CURDIR)/$(TARGET).elf
|
||||||
|
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||||
|
|
||||||
|
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||||
|
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||||
|
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||||
|
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||||
|
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# use CXX for linking C++ projects, CC for standard C
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
ifeq ($(strip $(CPPFILES)),)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CC)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
export LD := $(CXX)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
export OFILES := $(addsuffix .o,$(BINFILES)) \
|
||||||
|
$(PNGFILES:.png=.o) $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||||
|
|
||||||
|
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||||
|
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||||
|
-I$(CURDIR)/$(BUILD)
|
||||||
|
|
||||||
|
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
|
|
||||||
|
.PHONY: $(BUILD) clean
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(BUILD):
|
||||||
|
@[ -d $@ ] || mkdir -p $@
|
||||||
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
clean:
|
||||||
|
@echo clean ...
|
||||||
|
@rm -fr $(BUILD) *.elf *.nds* *.bin
|
||||||
|
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
else
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# main targets
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
$(ARM9ELF) : $(OFILES)
|
||||||
|
@echo linking $(notdir $@)
|
||||||
|
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
# you need a rule like this for each extension you use as binary data
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.bin.o : %.bin
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
%.s %.h : %.png
|
||||||
|
# grit $< -fts -W3 -gT! -gzl -gB16 -gb -o$*
|
||||||
|
grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl
|
||||||
|
|
||||||
|
#%.gif.o : %.gif
|
||||||
|
# @echo $(notdir $<)
|
||||||
|
# @$(bin2o)
|
||||||
|
|
||||||
|
%.wav.o : %.wav
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
|
||||||
|
-include $(DEPSDIR)/*.d
|
||||||
|
|
||||||
|
#---------------------------------------------------------------------------------------
|
||||||
|
endif
|
||||||
|
#---------------------------------------------------------------------------------------
|
BIN
arm9/data/clickNoQuit.wav
Normal file
BIN
arm9/data/clickNoQuit.wav
Normal file
Binary file not shown.
BIN
arm9/data/clickQuit.wav
Normal file
BIN
arm9/data/clickQuit.wav
Normal file
Binary file not shown.
BIN
arm9/data/mus_intro.wav
Normal file
BIN
arm9/data/mus_intro.wav
Normal file
Binary file not shown.
11
arm9/ds_arm9_hi.mem
Normal file
11
arm9/ds_arm9_hi.mem
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||||
|
v. 2.0. If a copy of the MPL was not distributed with this file, You can
|
||||||
|
obtain one at https://mozilla.org/MPL/2.0/.
|
||||||
|
--------------------------------------------------------------------------------*/
|
||||||
|
MEMORY {
|
||||||
|
ewram : ORIGIN = 0x02004000, LENGTH = 3M + 512K - 0x4000
|
||||||
|
dtcm : ORIGIN = 0x0b000000, LENGTH = 16K
|
||||||
|
vectors : ORIGIN = 0x01000000, LENGTH = 256
|
||||||
|
itcm : ORIGIN = 0x01000100, LENGTH = 32K - 256
|
||||||
|
}
|
8
arm9/ds_arm9_hi.specs
Normal file
8
arm9/ds_arm9_hi.specs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
%rename link old_link
|
||||||
|
|
||||||
|
*link:
|
||||||
|
%(old_link) -T ../ds_arm9_hi.mem%s -T ds_arm9.ld%s --gc-sections
|
||||||
|
|
||||||
|
*startfile:
|
||||||
|
ds_arm9_crt0%O%s crti%O%s crtbegin%O%s
|
||||||
|
|
BIN
arm9/gfx/bgBottom.png
Normal file
BIN
arm9/gfx/bgBottom.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
BIN
arm9/gfx/bgFileSel.png
Normal file
BIN
arm9/gfx/bgFileSel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
BIN
arm9/gfx/bgInstructions.png
Normal file
BIN
arm9/gfx/bgInstructions.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.5 KiB |
BIN
arm9/gfx/bgOptions.png
Normal file
BIN
arm9/gfx/bgOptions.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
arm9/gfx/bgTop.png
Normal file
BIN
arm9/gfx/bgTop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
1090
arm9/source/ds_tools.cpp
Normal file
1090
arm9/source/ds_tools.cpp
Normal file
File diff suppressed because it is too large
Load Diff
36
arm9/source/ds_tools.h
Normal file
36
arm9/source/ds_tools.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
#ifndef __DS_TOOLS_H
|
||||||
|
#define __DS_TOOLS_H
|
||||||
|
|
||||||
|
#include <nds.h>
|
||||||
|
|
||||||
|
#define STELLADS_MENUINIT 0x01
|
||||||
|
#define STELLADS_MENUSHOW 0x02
|
||||||
|
#define STELLADS_PLAYINIT 0x03
|
||||||
|
#define STELLADS_PLAYGAME 0x04
|
||||||
|
#define STELLADS_QUITSTDS 0x05
|
||||||
|
|
||||||
|
extern unsigned int etatEmu;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EMUARM7_INIT_SND = 0x123C,
|
||||||
|
EMUARM7_STOP_SND = 0x123D,
|
||||||
|
EMUARM7_PLAY_SND = 0x123E,
|
||||||
|
} FifoMesType;
|
||||||
|
|
||||||
|
typedef struct FICtoLoad {
|
||||||
|
char filename[255];
|
||||||
|
bool directory;
|
||||||
|
} FICA2600;
|
||||||
|
|
||||||
|
extern void dsPrintValue(int x, int y, unsigned int isSelect, char *pchStr);
|
||||||
|
extern void dsMainLoop(void);
|
||||||
|
extern void dsInstallSoundEmuFIFO(void);
|
||||||
|
extern void dsInitScreenMain(void);
|
||||||
|
extern void dsInitTimer(void);
|
||||||
|
extern void dsFreeEmu(void);
|
||||||
|
extern void dsShowScreenEmu(void);
|
||||||
|
extern bool dsWaitOnQuit(void);
|
||||||
|
extern void dsChooseOptions(void);
|
||||||
|
extern unsigned int dsWaitForRom(char *chosen_filename);
|
||||||
|
|
||||||
|
#endif
|
1058
arm9/source/emucore/AY38900.ITCM.cpp
Normal file
1058
arm9/source/emucore/AY38900.ITCM.cpp
Normal file
File diff suppressed because it is too large
Load Diff
263
arm9/source/emucore/AY38900.h
Normal file
263
arm9/source/emucore/AY38900.h
Normal file
@ -0,0 +1,263 @@
|
|||||||
|
|
||||||
|
#ifndef AY38900_H
|
||||||
|
#define AY38900_H
|
||||||
|
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "MemoryBus.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
#include "VideoProducer.h"
|
||||||
|
#include "AY38900_Registers.h"
|
||||||
|
#include "MOB.h"
|
||||||
|
#include "BackTabRAM.h"
|
||||||
|
#include "GRAM.h"
|
||||||
|
|
||||||
|
#define AY38900_PIN_IN_SST 0
|
||||||
|
#define AY38900_PIN_OUT_SR1 0
|
||||||
|
#define AY38900_PIN_OUT_SR2 1
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _AY38900State
|
||||||
|
{
|
||||||
|
BackTabRAMState backtab;
|
||||||
|
MOBState mobs[8];
|
||||||
|
INT32 horizontalOffset;
|
||||||
|
INT32 verticalOffset;
|
||||||
|
INT32 mode;
|
||||||
|
UINT16 registers[0x40];
|
||||||
|
INT8 inVBlank;
|
||||||
|
INT8 previousDisplayEnabled;
|
||||||
|
INT8 displayEnabled;
|
||||||
|
INT8 colorStackMode;
|
||||||
|
UINT8 borderColor;
|
||||||
|
INT8 blockLeft;
|
||||||
|
INT8 blockTop;
|
||||||
|
UINT8 _pad[1];
|
||||||
|
} AY38900State; )
|
||||||
|
|
||||||
|
class AY38900 : public Processor, public VideoProducer
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class AY38900_Registers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AY38900(MemoryBus* mb, ROM* go, GRAM* ga);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented from the Processor interface.
|
||||||
|
* Returns the clock speed of the AY-3-8900, currently hardcoded to the NTSC clock
|
||||||
|
* rate of 3.579545 Mhz.
|
||||||
|
*/
|
||||||
|
INT32 getClockSpeed() { return 3579545; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented from the Processor interface.
|
||||||
|
*/
|
||||||
|
void resetProcessor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented from the Processor interface.
|
||||||
|
*/
|
||||||
|
INT32 tick(INT32);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented from the VideoProducer interface.
|
||||||
|
*/
|
||||||
|
void setPixelBuffer(UINT8* pixelBuffer, UINT32 rowSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implemented from the VideoProducer interface.
|
||||||
|
*/
|
||||||
|
void render();
|
||||||
|
|
||||||
|
AY38900State getState();
|
||||||
|
void setState(AY38900State state);
|
||||||
|
|
||||||
|
//registers
|
||||||
|
AY38900_Registers registers;
|
||||||
|
BackTabRAM backtab;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setGraphicsBusVisible(BOOL visible);
|
||||||
|
void renderFrame();
|
||||||
|
BOOL somethingChanged();
|
||||||
|
void markClean();
|
||||||
|
void renderBorders();
|
||||||
|
void renderMOBs();
|
||||||
|
void renderBackground();
|
||||||
|
void renderForegroundBackgroundMode();
|
||||||
|
void renderColorStackMode();
|
||||||
|
void copyBackgroundBufferToStagingArea();
|
||||||
|
void copyMOBsToStagingArea();
|
||||||
|
void renderLine(UINT8 nextByte, INT32 x, INT32 y, UINT8 fgcolor, UINT8 bgcolor);
|
||||||
|
void renderColoredSquares(INT32 x, INT32 y, UINT8 color0, UINT8 color1, UINT8 color2, UINT8 color3);
|
||||||
|
void determineMOBCollisions();
|
||||||
|
BOOL mobsCollide(INT32 mobNum0, INT32 mobNum1);
|
||||||
|
BOOL mobCollidesWithBorder(int mobNum);
|
||||||
|
BOOL mobCollidesWithForeground(int mobNum);
|
||||||
|
//void renderRow(INT32 rowNum);
|
||||||
|
|
||||||
|
const static INT32 TICK_LENGTH_SCANLINE;
|
||||||
|
const static INT32 TICK_LENGTH_FRAME;
|
||||||
|
const static INT32 TICK_LENGTH_VBLANK;
|
||||||
|
const static INT32 TICK_LENGTH_START_ACTIVE_DISPLAY;
|
||||||
|
const static INT32 TICK_LENGTH_IDLE_ACTIVE_DISPLAY;
|
||||||
|
const static INT32 TICK_LENGTH_FETCH_ROW;
|
||||||
|
const static INT32 TICK_LENGTH_RENDER_ROW;
|
||||||
|
const static INT32 LOCATION_BACKTAB;
|
||||||
|
const static INT32 LOCATION_GROM;
|
||||||
|
const static INT32 LOCATION_GRAM;
|
||||||
|
const static INT32 LOCATION_COLORSTACK;
|
||||||
|
const static INT32 FOREGROUND_BIT;
|
||||||
|
|
||||||
|
MemoryBus* memoryBus;
|
||||||
|
|
||||||
|
MOB mobs[8];
|
||||||
|
UINT8 backgroundBuffer[160*96];
|
||||||
|
|
||||||
|
UINT8* pixelBuffer;
|
||||||
|
UINT32 pixelBufferRowSize;
|
||||||
|
|
||||||
|
//memory listeners, for optimizations
|
||||||
|
ROM* grom;
|
||||||
|
GRAM* gram;
|
||||||
|
|
||||||
|
//state info
|
||||||
|
BOOL inVBlank;
|
||||||
|
INT32 mode;
|
||||||
|
BOOL previousDisplayEnabled;
|
||||||
|
BOOL displayEnabled;
|
||||||
|
BOOL colorStackMode;
|
||||||
|
BOOL colorModeChanged;
|
||||||
|
BOOL bordersChanged;
|
||||||
|
BOOL colorStackChanged;
|
||||||
|
BOOL offsetsChanged;
|
||||||
|
BOOL imageBufferChanged;
|
||||||
|
|
||||||
|
//register info
|
||||||
|
UINT8 borderColor;
|
||||||
|
BOOL blockLeft;
|
||||||
|
BOOL blockTop;
|
||||||
|
INT32 horizontalOffset;
|
||||||
|
INT32 verticalOffset;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
#ifndef AY38900_H
|
||||||
|
#define AY38900_H
|
||||||
|
|
||||||
|
#include "AY38900_Registers.h"
|
||||||
|
#include "BackTabRAM.h"
|
||||||
|
#include "GRAM.h"
|
||||||
|
#include "GROM.h"
|
||||||
|
#include "MOB.h"
|
||||||
|
#include "VideoProducer.h"
|
||||||
|
#include "core/types.h"
|
||||||
|
#include "core/cpu/Processor.h"
|
||||||
|
#include "core/cpu/SignalLine.h"
|
||||||
|
#include "core/memory/MemoryBus.h"
|
||||||
|
#include "services/VideoOutputDevice.h"
|
||||||
|
|
||||||
|
#define AY38900_PIN_IN_SST 0
|
||||||
|
|
||||||
|
#define AY38900_PIN_OUT_SR1 0
|
||||||
|
#define AY38900_PIN_OUT_SR2 1
|
||||||
|
|
||||||
|
class AY38900 : public Processor, public VideoProducer
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class AY38900_Registers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AY38900(MemoryBus* memoryBus);
|
||||||
|
void setGROMImage(UINT16* gromImage);
|
||||||
|
BOOL inVerticalBlank();
|
||||||
|
|
||||||
|
//Processor functions
|
||||||
|
void initProcessor();
|
||||||
|
void releaseProcessor();
|
||||||
|
void setVideoOutputDevice(IDirect3DDevice9* vod);
|
||||||
|
INT32 getClockSpeed();
|
||||||
|
INT32 tick();
|
||||||
|
|
||||||
|
//VideoProducer functions
|
||||||
|
void render();
|
||||||
|
|
||||||
|
//registers
|
||||||
|
AY38900_Registers registers;
|
||||||
|
|
||||||
|
static const INT32 TICK_LENGTH_SCANLINE;
|
||||||
|
static const INT32 TICK_LENGTH_FRAME;
|
||||||
|
static const INT32 TICK_LENGTH_VBLANK;
|
||||||
|
static const INT32 TICK_LENGTH_START_ACTIVE_DISPLAY;
|
||||||
|
static const INT32 TICK_LENGTH_IDLE_ACTIVE_DISPLAY;
|
||||||
|
static const INT32 TICK_LENGTH_FETCH_ROW;
|
||||||
|
static const INT32 TICK_LENGTH_RENDER_ROW;
|
||||||
|
static const INT32 LOCATION_BACKTAB;
|
||||||
|
static const INT32 LOCATION_GROM;
|
||||||
|
static const INT32 LOCATION_GRAM;
|
||||||
|
static const INT32 LOCATION_COLORSTACK;
|
||||||
|
static const INT32 FOREGROUND_BIT;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setGraphicsBusVisible(BOOL visible);
|
||||||
|
void renderFrame();
|
||||||
|
BOOL somethingChanged();
|
||||||
|
void markClean();
|
||||||
|
void renderBorders();
|
||||||
|
void renderMOBs();
|
||||||
|
void renderBackground();
|
||||||
|
void copyBackgroundBufferToStagingArea();
|
||||||
|
void renderForegroundBackgroundMode();
|
||||||
|
void renderColorStackMode();
|
||||||
|
void copyMOBsToStagingArea();
|
||||||
|
void renderLine(UINT8 nextUINT8, INT32 x, INT32 y,
|
||||||
|
UINT8 fgcolor, UINT8 bgcolor);
|
||||||
|
void renderColoredSquares(INT32 x, INT32 y, UINT8 color0, UINT8 color1,
|
||||||
|
UINT8 color2, UINT8 color3);
|
||||||
|
void renderMessage();
|
||||||
|
void renderCharacter(char c, INT32 x, INT32 y);
|
||||||
|
void determineMOBCollisions();
|
||||||
|
BOOL mobsCollide(INT32 mobNum0, INT32 mobNum1);
|
||||||
|
|
||||||
|
BOOL mobBuffers[8][16][128];
|
||||||
|
MOB mobs[8];
|
||||||
|
UINT8 backgroundBuffer[160*96];
|
||||||
|
IDirect3DDevice9* videoOutputDevice;
|
||||||
|
IDirect3DTexture9* combinedTexture;
|
||||||
|
IDirect3DVertexBuffer9* vertexBuffer;
|
||||||
|
D3DLOCKED_RECT combinedBufferLock;
|
||||||
|
|
||||||
|
MemoryBus* memoryBus;
|
||||||
|
|
||||||
|
//memory listeners, for optimizations
|
||||||
|
BackTabRAM backtab;
|
||||||
|
GROM grom;
|
||||||
|
GRAM gram;
|
||||||
|
|
||||||
|
//state info
|
||||||
|
BOOL inVBlank;
|
||||||
|
INT32 mode;
|
||||||
|
BOOL previousDisplayEnabled;
|
||||||
|
BOOL displayEnabled;
|
||||||
|
BOOL colorStackMode;
|
||||||
|
BOOL colorModeChanged;
|
||||||
|
BOOL bordersChanged;
|
||||||
|
BOOL colorStackChanged;
|
||||||
|
BOOL offsetsChanged;
|
||||||
|
BOOL imageBufferChanged;
|
||||||
|
|
||||||
|
//register info
|
||||||
|
UINT8 borderColor;
|
||||||
|
BOOL blockLeft;
|
||||||
|
BOOL blockTop;
|
||||||
|
INT32 horizontalOffset;
|
||||||
|
INT32 verticalOffset;
|
||||||
|
|
||||||
|
//palette
|
||||||
|
const static UINT32 palette[32];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
*/
|
198
arm9/source/emucore/AY38900_Registers.cpp
Normal file
198
arm9/source/emucore/AY38900_Registers.cpp
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "AY38900.h"
|
||||||
|
#include "AY38900_Registers.h"
|
||||||
|
|
||||||
|
UINT16 memory[0x40] __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
AY38900_Registers::AY38900_Registers()
|
||||||
|
: RAM(0x40, 0x0000, 0xFFFF, 0x3FFF)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void AY38900_Registers::init(AY38900* ay38900)
|
||||||
|
{
|
||||||
|
this->ay38900 = ay38900;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AY38900_Registers::reset()
|
||||||
|
{
|
||||||
|
memset(memory, 0, sizeof(memory));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AY38900_Registers::poke(UINT16 location, UINT16 value) {
|
||||||
|
if (!enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//incomplete decoding on writes
|
||||||
|
location &= 0x3F;
|
||||||
|
|
||||||
|
switch(location) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x01:
|
||||||
|
case 0x02:
|
||||||
|
case 0x03:
|
||||||
|
case 0x04:
|
||||||
|
case 0x05:
|
||||||
|
case 0x06:
|
||||||
|
case 0x07:
|
||||||
|
value &= 0x07FF;
|
||||||
|
{
|
||||||
|
MOB* mob = &ay38900->mobs[location];
|
||||||
|
mob->setDoubleWidth((value & 0x0400) != 0);
|
||||||
|
mob->setVisible((value & 0x0200) != 0);
|
||||||
|
mob->setFlagCollisions((value & 0x0100) != 0);
|
||||||
|
mob->setXLocation(value & 0x00FF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
case 0x09:
|
||||||
|
case 0x0A:
|
||||||
|
case 0x0B:
|
||||||
|
case 0x0C:
|
||||||
|
case 0x0D:
|
||||||
|
case 0x0E:
|
||||||
|
case 0x0F:
|
||||||
|
value &= 0x0FFF;
|
||||||
|
{
|
||||||
|
MOB* mob = &ay38900->mobs[location & 0x07];
|
||||||
|
mob->setVerticalMirror((value & 0x0800) != 0);
|
||||||
|
mob->setHorizontalMirror((value & 0x0400) != 0);
|
||||||
|
mob->setQuadHeight((value & 0x0200) != 0);
|
||||||
|
mob->setDoubleHeight((value & 0x0100) != 0);
|
||||||
|
mob->setDoubleYResolution((value & 0x0080) != 0);
|
||||||
|
mob->setYLocation(value & 0x007F);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
case 0x11:
|
||||||
|
case 0x12:
|
||||||
|
case 0x13:
|
||||||
|
case 0x14:
|
||||||
|
case 0x15:
|
||||||
|
case 0x16:
|
||||||
|
case 0x17:
|
||||||
|
value &= 0x3FFF;
|
||||||
|
{
|
||||||
|
MOB* mob = &ay38900->mobs[location & 0x07];
|
||||||
|
mob->setBehindForeground((value & 0x2000) != 0);
|
||||||
|
mob->setGROM((value & 0x0800) == 0);
|
||||||
|
mob->setCardNumber((value & 0x07F8) >> 3);
|
||||||
|
mob->setForegroundColor(((value & 0x1000) >> 9) |
|
||||||
|
(value & 0x0007));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
case 0x19:
|
||||||
|
case 0x1A:
|
||||||
|
case 0x1B:
|
||||||
|
case 0x1C:
|
||||||
|
case 0x1D:
|
||||||
|
case 0x1E:
|
||||||
|
case 0x1F:
|
||||||
|
//a MOB's own collision bit is *always* zero, even if a
|
||||||
|
//one is poked into it
|
||||||
|
value &= (~(1 << (location & 0x07))) & 0x03FF;
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
ay38900->displayEnabled = TRUE;
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
value = 0;
|
||||||
|
if (ay38900->colorStackMode) {
|
||||||
|
ay38900->colorStackMode = FALSE;
|
||||||
|
ay38900->colorModeChanged = TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x28:
|
||||||
|
case 0x29:
|
||||||
|
case 0x2A:
|
||||||
|
case 0x2B:
|
||||||
|
value &= 0x000F;
|
||||||
|
ay38900->colorStackChanged = TRUE;
|
||||||
|
break;
|
||||||
|
case 0x2C:
|
||||||
|
value &= 0x000F;
|
||||||
|
ay38900->borderColor = (UINT8)value;
|
||||||
|
ay38900->bordersChanged = TRUE;
|
||||||
|
break;
|
||||||
|
case 0x30:
|
||||||
|
value &= 0x0007;
|
||||||
|
ay38900->horizontalOffset = value;
|
||||||
|
ay38900->offsetsChanged = TRUE;
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
value &= 0x0007;
|
||||||
|
ay38900->verticalOffset = value;
|
||||||
|
ay38900->offsetsChanged = TRUE;
|
||||||
|
break;
|
||||||
|
case 0x32:
|
||||||
|
value &= 0x0003;
|
||||||
|
ay38900->blockLeft = (value & 0x0001) != 0;
|
||||||
|
ay38900->blockTop = (value & 0x0002) != 0;
|
||||||
|
ay38900->bordersChanged = TRUE;
|
||||||
|
break;
|
||||||
|
default: // 0x22 - 0x27
|
||||||
|
value = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
memory[location] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 AY38900_Registers::peek(UINT16 location)
|
||||||
|
{
|
||||||
|
if (!enabled)
|
||||||
|
return location;
|
||||||
|
location &= 0x3F;
|
||||||
|
|
||||||
|
switch (location) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x01:
|
||||||
|
case 0x02:
|
||||||
|
case 0x03:
|
||||||
|
case 0x04:
|
||||||
|
case 0x05:
|
||||||
|
case 0x06:
|
||||||
|
case 0x07:
|
||||||
|
return 0x3800 | memory[location];
|
||||||
|
case 0x08:
|
||||||
|
case 0x09:
|
||||||
|
case 0x0A:
|
||||||
|
case 0x0B:
|
||||||
|
case 0x0C:
|
||||||
|
case 0x0D:
|
||||||
|
case 0x0E:
|
||||||
|
case 0x0F:
|
||||||
|
return 0x3000 | memory[location];
|
||||||
|
case 0x18:
|
||||||
|
case 0x19:
|
||||||
|
case 0x1A:
|
||||||
|
case 0x1B:
|
||||||
|
case 0x1C:
|
||||||
|
case 0x1D:
|
||||||
|
case 0x1E:
|
||||||
|
case 0x1F:
|
||||||
|
//collision register bits $3C00 are always on
|
||||||
|
return 0x3C00 | memory[location];
|
||||||
|
case 0x20:
|
||||||
|
return 0;
|
||||||
|
case 0x21:
|
||||||
|
if (location == 0x0021 && !ay38900->colorStackMode) {
|
||||||
|
ay38900->colorStackMode = TRUE;
|
||||||
|
ay38900->colorModeChanged = TRUE;
|
||||||
|
}
|
||||||
|
return memory[location];
|
||||||
|
case 0x28:
|
||||||
|
case 0x29:
|
||||||
|
case 0x2A:
|
||||||
|
case 0x2B:
|
||||||
|
case 0x2C:
|
||||||
|
return 0x3FF0 | memory[location];
|
||||||
|
case 0x30:
|
||||||
|
case 0x31:
|
||||||
|
return 0x3FF8 | memory[location];
|
||||||
|
case 0x32:
|
||||||
|
return 0x3FFC | memory[location];
|
||||||
|
default:
|
||||||
|
return memory[location];
|
||||||
|
}
|
||||||
|
}
|
37
arm9/source/emucore/AY38900_Registers.h
Normal file
37
arm9/source/emucore/AY38900_Registers.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
#ifndef AY38900_REGISTERS_H
|
||||||
|
#define AY38900_REGISTERS_H
|
||||||
|
|
||||||
|
#include "RAM.h"
|
||||||
|
|
||||||
|
class AY38900;
|
||||||
|
|
||||||
|
extern UINT16 memory[0x40];
|
||||||
|
class AY38900_Registers : public RAM
|
||||||
|
{
|
||||||
|
friend class AY38900;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void poke(UINT16 location, UINT16 value);
|
||||||
|
UINT16 peek(UINT16 location);
|
||||||
|
|
||||||
|
inline size_t getMemoryByteSize() {
|
||||||
|
return sizeof(memory);
|
||||||
|
}
|
||||||
|
void getMemory(void* dst, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(dst, memory + offset, size);
|
||||||
|
}
|
||||||
|
void setMemory(void* src, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(memory + offset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AY38900_Registers();
|
||||||
|
void init(AY38900* ay38900);
|
||||||
|
|
||||||
|
AY38900* ay38900;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
339
arm9/source/emucore/AY38914.ITCM.cpp
Normal file
339
arm9/source/emucore/AY38914.ITCM.cpp
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include "AY38914.h"
|
||||||
|
#include "AudioMixer.h"
|
||||||
|
|
||||||
|
INT32 amplitudes16Bit[16] __attribute__((section(".dtcm"))) =
|
||||||
|
{
|
||||||
|
0x003C, 0x0055, 0x0079, 0x00AB, 0x00F1, 0x0155, 0x01E3, 0x02AA,
|
||||||
|
0x03C5, 0x0555, 0x078B, 0x0AAB, 0x0F16, 0x1555, 0x1E2B, 0x2AAA
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Channel_t channel0 __attribute__((section(".dtcm")));
|
||||||
|
struct Channel_t channel1 __attribute__((section(".dtcm")));
|
||||||
|
struct Channel_t channel2 __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
INT32 clockDivisor __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
//cached total output sample
|
||||||
|
BOOL cachedTotalOutputIsDirty __attribute__((section(".dtcm")));
|
||||||
|
INT32 cachedTotalOutput __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
//envelope data
|
||||||
|
BOOL envelopeIdle __attribute__((section(".dtcm")));
|
||||||
|
INT32 envelopePeriod __attribute__((section(".dtcm")));
|
||||||
|
INT32 envelopePeriodValue __attribute__((section(".dtcm")));
|
||||||
|
INT32 envelopeVolume __attribute__((section(".dtcm")));
|
||||||
|
BOOL envelopeHold __attribute__((section(".dtcm")));
|
||||||
|
BOOL envelopeAltr __attribute__((section(".dtcm")));
|
||||||
|
BOOL envelopeAtak __attribute__((section(".dtcm")));
|
||||||
|
BOOL envelopeCont __attribute__((section(".dtcm")));
|
||||||
|
INT32 envelopeCounter __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
//noise data
|
||||||
|
BOOL noiseIdle __attribute__((section(".dtcm")));
|
||||||
|
INT32 noisePeriod __attribute__((section(".dtcm")));
|
||||||
|
INT32 noisePeriodValue __attribute__((section(".dtcm")));
|
||||||
|
INT32 noiseCounter __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
//data for random number generator, used for white noise accuracy
|
||||||
|
INT32 my_random __attribute__((section(".dtcm")));
|
||||||
|
BOOL noise __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AY-3-8914 chip in the Intellivision, also know as the Programmable
|
||||||
|
* Sound Generator (PSG).
|
||||||
|
*
|
||||||
|
* @author Kyle Davis
|
||||||
|
*/
|
||||||
|
AY38914::AY38914(UINT16 location, AY38914_InputOutput* io0,
|
||||||
|
AY38914_InputOutput* io1)
|
||||||
|
: Processor("AY-3-8914"),
|
||||||
|
registers(location)
|
||||||
|
{
|
||||||
|
this->psgIO0 = io0;
|
||||||
|
this->psgIO1 = io1;
|
||||||
|
clockDivisor = 8; //TODO: was 1... trying to speed thigns up by lowering sound quality...
|
||||||
|
registers.init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 AY38914::getClockSpeed() {
|
||||||
|
return 3579545;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 AY38914::getClocksPerSample() {
|
||||||
|
return clockDivisor<<4;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AY38914::resetProcessor()
|
||||||
|
{
|
||||||
|
//reset the state variables
|
||||||
|
noisePeriod = 0;
|
||||||
|
noisePeriodValue = 0x0040;
|
||||||
|
noiseCounter = noisePeriodValue;
|
||||||
|
my_random = 1;
|
||||||
|
noise = TRUE;
|
||||||
|
noiseIdle = TRUE;
|
||||||
|
envelopeIdle = TRUE;
|
||||||
|
envelopePeriod = 0;
|
||||||
|
envelopePeriodValue = 0x20000;
|
||||||
|
envelopeCounter = envelopePeriodValue;
|
||||||
|
envelopeVolume = 0;
|
||||||
|
envelopeHold = FALSE;
|
||||||
|
envelopeAltr = FALSE;
|
||||||
|
envelopeAtak = FALSE;
|
||||||
|
envelopeCont = FALSE;
|
||||||
|
cachedTotalOutput = 0;
|
||||||
|
cachedTotalOutputIsDirty = TRUE;
|
||||||
|
|
||||||
|
memset(&channel0, 0x00, sizeof(channel0));
|
||||||
|
memset(&channel1, 0x00, sizeof(channel1));
|
||||||
|
memset(&channel2, 0x00, sizeof(channel2));
|
||||||
|
|
||||||
|
channel0.periodValue = 0x1000;
|
||||||
|
channel0.toneCounter = 0x1000;
|
||||||
|
channel0.isDirty = TRUE;
|
||||||
|
|
||||||
|
channel1.periodValue = 0x1000;
|
||||||
|
channel1.toneCounter = 0x1000;
|
||||||
|
channel1.isDirty = TRUE;
|
||||||
|
|
||||||
|
channel2.periodValue = 0x1000;
|
||||||
|
channel2.toneCounter = 0x1000;
|
||||||
|
channel2.isDirty = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AY38914::setClockDivisor(INT32 clockDivisor) {
|
||||||
|
clockDivisor = clockDivisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 AY38914::getClockDivisor() {
|
||||||
|
return clockDivisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tick the AY38914. This method has been profiled over and over again
|
||||||
|
* in an attempt to tweak it for optimal performance. Please be careful
|
||||||
|
* with any modifications that may adversely affect performance.
|
||||||
|
*
|
||||||
|
* @return the number of ticks used by the AY38914, always returns 4.
|
||||||
|
*/
|
||||||
|
ITCM_CODE INT32 AY38914::tick(INT32 minimum)
|
||||||
|
{
|
||||||
|
INT32 totalTicks = 0;
|
||||||
|
do {
|
||||||
|
//iterate the envelope generator
|
||||||
|
envelopeCounter -= clockDivisor;
|
||||||
|
if (envelopeCounter <= 0) {
|
||||||
|
do {
|
||||||
|
envelopeCounter += envelopePeriodValue;
|
||||||
|
if (!envelopeIdle) {
|
||||||
|
envelopeVolume += (envelopeAtak ? 1 : -1);
|
||||||
|
if (envelopeVolume > 15 || envelopeVolume < 0) {
|
||||||
|
if (!envelopeCont) {
|
||||||
|
envelopeVolume = 0;
|
||||||
|
envelopeIdle = TRUE;
|
||||||
|
}
|
||||||
|
else if (envelopeHold) {
|
||||||
|
envelopeVolume = (envelopeAtak == envelopeAltr ? 0 : 15);
|
||||||
|
envelopeIdle = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
envelopeAtak = (envelopeAtak != envelopeAltr);
|
||||||
|
envelopeVolume = (envelopeAtak ? 0 : 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (envelopeCounter <= 0);
|
||||||
|
|
||||||
|
//the envelope volume has changed so the channel outputs
|
||||||
|
//need to be updated if they are using the envelope
|
||||||
|
channel0.isDirty = channel0.envelope;
|
||||||
|
channel1.isDirty = channel1.envelope;
|
||||||
|
channel2.isDirty = channel2.envelope;
|
||||||
|
}
|
||||||
|
|
||||||
|
//iterate the noise generator
|
||||||
|
noiseCounter -= clockDivisor;
|
||||||
|
if (noiseCounter <= 0) {
|
||||||
|
BOOL oldNoise = noise;
|
||||||
|
do {
|
||||||
|
noiseCounter += noisePeriodValue;
|
||||||
|
if (!noiseIdle) {
|
||||||
|
my_random = (my_random >> 1) ^ (noise ? 0x14000 : 0);
|
||||||
|
noise = (my_random & 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (noiseCounter <= 0);
|
||||||
|
|
||||||
|
//if the noise bit changed, then our channel outputs need
|
||||||
|
//to be updated if they are using the noise generator
|
||||||
|
if (!noiseIdle && oldNoise != noise) {
|
||||||
|
channel0.isDirty = (channel0.isDirty | !channel0.noiseDisabled);
|
||||||
|
channel1.isDirty = (channel1.isDirty | !channel1.noiseDisabled);
|
||||||
|
channel2.isDirty = (channel2.isDirty | !channel2.noiseDisabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//iterate the tone generator for channel 0
|
||||||
|
channel0.toneCounter -= clockDivisor;
|
||||||
|
if (channel0.toneCounter <= 0) {
|
||||||
|
do {
|
||||||
|
channel0.toneCounter += channel0.periodValue;
|
||||||
|
channel0.tone = !channel0.tone;
|
||||||
|
}
|
||||||
|
while (channel0.toneCounter <= 0);
|
||||||
|
|
||||||
|
channel0.isDirty = !channel0.toneDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
//iterate the tone generator for channel 1
|
||||||
|
channel1.toneCounter -= clockDivisor;
|
||||||
|
if (channel1.toneCounter <= 0) {
|
||||||
|
do {
|
||||||
|
channel1.toneCounter += channel1.periodValue;
|
||||||
|
channel1.tone = !channel1.tone;
|
||||||
|
}
|
||||||
|
while (channel1.toneCounter <= 0);
|
||||||
|
|
||||||
|
channel1.isDirty = !channel1.toneDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
//iterate the tone generator for channel 2
|
||||||
|
channel2.toneCounter -= clockDivisor;
|
||||||
|
if (channel2.toneCounter <= 0) {
|
||||||
|
do {
|
||||||
|
channel2.toneCounter += channel2.periodValue;
|
||||||
|
channel2.tone = !channel2.tone;
|
||||||
|
}
|
||||||
|
while (channel2.toneCounter <= 0);
|
||||||
|
|
||||||
|
channel2.isDirty = !channel2.toneDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel0.isDirty) {
|
||||||
|
channel0.isDirty = FALSE;
|
||||||
|
channel0.cachedSample = amplitudes16Bit[
|
||||||
|
(((channel0.toneDisabled | channel0.tone) &
|
||||||
|
(channel0.noiseDisabled | noise))
|
||||||
|
? (channel0.envelope ? envelopeVolume
|
||||||
|
: channel0.volume) : 0)];
|
||||||
|
cachedTotalOutputIsDirty = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel1.isDirty) {
|
||||||
|
channel1.isDirty = FALSE;
|
||||||
|
channel1.cachedSample = amplitudes16Bit[
|
||||||
|
(((channel1.toneDisabled | channel1.tone) &
|
||||||
|
(channel1.noiseDisabled | noise))
|
||||||
|
? (channel1.envelope ? envelopeVolume
|
||||||
|
: channel1.volume) : 0)];
|
||||||
|
cachedTotalOutputIsDirty = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (channel2.isDirty) {
|
||||||
|
channel2.isDirty = FALSE;
|
||||||
|
channel2.cachedSample = amplitudes16Bit[
|
||||||
|
(((channel2.toneDisabled | channel2.tone) &
|
||||||
|
(channel2.noiseDisabled | noise))
|
||||||
|
? (channel2.envelope ? envelopeVolume
|
||||||
|
: channel2.volume) : 0)];
|
||||||
|
cachedTotalOutputIsDirty = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//mix all three channel samples together to generate the overall
|
||||||
|
//output sample for the entire AY38914
|
||||||
|
if (cachedTotalOutputIsDirty) {
|
||||||
|
cachedTotalOutputIsDirty = FALSE;
|
||||||
|
cachedTotalOutput = (channel0.cachedSample +
|
||||||
|
channel1.cachedSample + channel2.cachedSample);
|
||||||
|
|
||||||
|
//apply the saturation clipping to correctly model the
|
||||||
|
//cross-channel modulation that occurs on a real Intellivision
|
||||||
|
cachedTotalOutput <<= 1;
|
||||||
|
if (cachedTotalOutput > 0x6000)
|
||||||
|
cachedTotalOutput = 0x6000 + ((cachedTotalOutput - 0x6000)/6);
|
||||||
|
}
|
||||||
|
|
||||||
|
audioOutputLine->playSample((INT16)cachedTotalOutput);
|
||||||
|
|
||||||
|
totalTicks += (clockDivisor<<4);
|
||||||
|
|
||||||
|
} while (totalTicks < minimum);
|
||||||
|
|
||||||
|
//every tick here always uses some multiple of 4 CPU cycles
|
||||||
|
//or 16 NTSC cycles
|
||||||
|
return totalTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
AY38914State AY38914::getState()
|
||||||
|
{
|
||||||
|
AY38914State state = {0};
|
||||||
|
#if 0
|
||||||
|
this->registers.getMemory(state.registers, 0, this->registers.getMemoryByteSize());
|
||||||
|
|
||||||
|
state.clockDivisor = this->clockDivisor;
|
||||||
|
|
||||||
|
state.channel0 = this->channel0.getState();
|
||||||
|
state.channel1 = this->channel1.getState();
|
||||||
|
state.channel2 = this->channel2.getState();
|
||||||
|
|
||||||
|
state.cachedTotalOutputIsDirty = this->cachedTotalOutputIsDirty;
|
||||||
|
state.cachedTotalOutput = this->cachedTotalOutput;
|
||||||
|
|
||||||
|
state.envelopeIdle = this->envelopeIdle;
|
||||||
|
state.envelopePeriod = this->envelopePeriod;
|
||||||
|
state.envelopePeriodValue = this->envelopePeriodValue;
|
||||||
|
state.envelopeCounter = this->envelopeCounter;
|
||||||
|
state.envelopeVolume = this->envelopeVolume;
|
||||||
|
state.envelopeHold = this->envelopeHold;
|
||||||
|
state.envelopeAltr = this->envelopeAltr;
|
||||||
|
state.envelopeAtak = this->envelopeAtak;
|
||||||
|
state.envelopeCont = this->envelopeCont;
|
||||||
|
|
||||||
|
state.noiseIdle = this->noiseIdle;
|
||||||
|
state.noisePeriod = this->noisePeriod;
|
||||||
|
state.noisePeriodValue = this->noisePeriodValue;
|
||||||
|
state.noiseCounter = this->noiseCounter;
|
||||||
|
|
||||||
|
state.my_random = this->my_random;
|
||||||
|
state.noise = this->noise;
|
||||||
|
#endif
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AY38914::setState(AY38914State state)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
this->registers.setMemory(state.registers, 0, this->registers.getMemoryByteSize());
|
||||||
|
|
||||||
|
this->clockDivisor = state.clockDivisor;
|
||||||
|
|
||||||
|
this->channel0.setState(state.channel0);
|
||||||
|
this->channel1.setState(state.channel1);
|
||||||
|
this->channel2.setState(state.channel2);
|
||||||
|
|
||||||
|
this->cachedTotalOutputIsDirty = state.cachedTotalOutputIsDirty;
|
||||||
|
this->cachedTotalOutput = state.cachedTotalOutput;
|
||||||
|
|
||||||
|
this->envelopeIdle = state.envelopeIdle;
|
||||||
|
this->envelopePeriod = state.envelopePeriod;
|
||||||
|
this->envelopePeriodValue = state.envelopePeriodValue;
|
||||||
|
this->envelopeCounter = state.envelopeCounter;
|
||||||
|
this->envelopeVolume = state.envelopeVolume;
|
||||||
|
this->envelopeHold = state.envelopeHold;
|
||||||
|
this->envelopeAltr = state.envelopeAltr;
|
||||||
|
this->envelopeAtak = state.envelopeAtak;
|
||||||
|
this->envelopeCont = state.envelopeCont;
|
||||||
|
|
||||||
|
this->noiseIdle = state.noiseIdle;
|
||||||
|
this->noisePeriod = state.noisePeriod;
|
||||||
|
this->noisePeriodValue = state.noisePeriodValue;
|
||||||
|
this->noiseCounter = state.noiseCounter;
|
||||||
|
|
||||||
|
this->my_random = state.my_random;
|
||||||
|
this->noise = state.noise;
|
||||||
|
#endif
|
||||||
|
}
|
101
arm9/source/emucore/AY38914.h
Normal file
101
arm9/source/emucore/AY38914.h
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
|
||||||
|
#ifndef AY38914_H
|
||||||
|
#define AY38914_H
|
||||||
|
|
||||||
|
#include "AudioProducer.h"
|
||||||
|
#include "AY38914_Registers.h"
|
||||||
|
#include "AY38914_Channel.h"
|
||||||
|
#include "AY38914_InputOutput.h"
|
||||||
|
#include "AudioOutputLine.h"
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class Intellivision;
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _AY38914State
|
||||||
|
{
|
||||||
|
UINT16 registers[0x0E];
|
||||||
|
INT32 clockDivisor;
|
||||||
|
INT32 cachedTotalOutput;
|
||||||
|
INT32 envelopePeriod;
|
||||||
|
INT32 envelopePeriodValue;
|
||||||
|
INT32 envelopeCounter;
|
||||||
|
INT32 envelopeVolume;
|
||||||
|
INT32 noisePeriod;
|
||||||
|
INT32 noisePeriodValue;
|
||||||
|
INT32 noiseCounter;
|
||||||
|
INT32 random;
|
||||||
|
INT8 cachedTotalOutputIsDirty;
|
||||||
|
INT8 envelopeIdle;
|
||||||
|
INT8 envelopeHold;
|
||||||
|
INT8 envelopeAltr;
|
||||||
|
INT8 envelopeAtak;
|
||||||
|
INT8 envelopeCont;
|
||||||
|
INT8 noiseIdle;
|
||||||
|
INT8 noise;
|
||||||
|
} AY38914State; )
|
||||||
|
|
||||||
|
|
||||||
|
//divisor for slowing down the clock speed for the AY38914
|
||||||
|
extern INT32 clockDivisor;
|
||||||
|
|
||||||
|
//cached total output sample
|
||||||
|
extern BOOL cachedTotalOutputIsDirty;
|
||||||
|
extern INT32 cachedTotalOutput;
|
||||||
|
|
||||||
|
//envelope data
|
||||||
|
extern BOOL envelopeIdle;
|
||||||
|
extern INT32 envelopePeriod;
|
||||||
|
extern INT32 envelopePeriodValue;
|
||||||
|
extern INT32 envelopeVolume;
|
||||||
|
extern BOOL envelopeHold;
|
||||||
|
extern BOOL envelopeAltr;
|
||||||
|
extern BOOL envelopeAtak;
|
||||||
|
extern BOOL envelopeCont;
|
||||||
|
extern INT32 envelopeCounter;
|
||||||
|
|
||||||
|
//noise data
|
||||||
|
extern BOOL noiseIdle;
|
||||||
|
extern INT32 noisePeriod;
|
||||||
|
extern INT32 noisePeriodValue;
|
||||||
|
extern INT32 noiseCounter;
|
||||||
|
|
||||||
|
//data for random number generator, used for white noise accuracy
|
||||||
|
extern INT32 my_random;
|
||||||
|
extern BOOL noise;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The AY-3-8914 chip in the Intellivision, also known as the Programmable
|
||||||
|
* Sound Generator (PSG).
|
||||||
|
*
|
||||||
|
* @author Kyle Davis
|
||||||
|
*/
|
||||||
|
class AY38914 : public Processor, public AudioProducer
|
||||||
|
{
|
||||||
|
friend class AY38914_Registers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AY38914(UINT16 location, AY38914_InputOutput* io0,
|
||||||
|
AY38914_InputOutput* io1);
|
||||||
|
void resetProcessor();
|
||||||
|
INT32 getClockSpeed();
|
||||||
|
INT32 getClocksPerSample();
|
||||||
|
INT32 getSampleRate() { return getClockSpeed(); }
|
||||||
|
INT32 tick(INT32);
|
||||||
|
|
||||||
|
void setClockDivisor(INT32 clockDivisor);
|
||||||
|
INT32 getClockDivisor();
|
||||||
|
|
||||||
|
AY38914State getState();
|
||||||
|
void setState(AY38914State state);
|
||||||
|
|
||||||
|
//registers
|
||||||
|
AY38914_Registers registers;
|
||||||
|
|
||||||
|
private:
|
||||||
|
AY38914_InputOutput* psgIO0;
|
||||||
|
AY38914_InputOutput* psgIO1;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
1
arm9/source/emucore/AY38914_Channel.cpp
Normal file
1
arm9/source/emucore/AY38914_Channel.cpp
Normal file
@ -0,0 +1 @@
|
|||||||
|
// Obsoleted...
|
25
arm9/source/emucore/AY38914_Channel.h
Normal file
25
arm9/source/emucore/AY38914_Channel.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
#ifndef AY38914__CHANNEL_H
|
||||||
|
#define AY38914__CHANNEL_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
struct Channel_t
|
||||||
|
{
|
||||||
|
INT32 period;
|
||||||
|
INT32 periodValue;
|
||||||
|
INT32 volume;
|
||||||
|
INT32 toneCounter;
|
||||||
|
BOOL tone;
|
||||||
|
BOOL envelope;
|
||||||
|
BOOL toneDisabled;
|
||||||
|
BOOL noiseDisabled;
|
||||||
|
BOOL isDirty;
|
||||||
|
INT32 cachedSample;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct Channel_t channel0;
|
||||||
|
extern struct Channel_t channel1;
|
||||||
|
extern struct Channel_t channel2;
|
||||||
|
|
||||||
|
#endif
|
16
arm9/source/emucore/AY38914_InputOutput.h
Normal file
16
arm9/source/emucore/AY38914_InputOutput.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
#ifndef AY38914INPUTOUTPUT_H
|
||||||
|
#define AY38914INPUTOUTPUT_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class AY38914_InputOutput
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual UINT16 getInputValue() = 0;
|
||||||
|
virtual void setOutputValue(UINT16 value) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
180
arm9/source/emucore/AY38914_Registers.cpp
Normal file
180
arm9/source/emucore/AY38914_Registers.cpp
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "AY38914.h"
|
||||||
|
#include "AY38914_Registers.h"
|
||||||
|
|
||||||
|
AY38914_Registers::AY38914_Registers(UINT16 address)
|
||||||
|
: RAM(0x10, address, 0xFFFF, 0xFFFF)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void AY38914_Registers::init(AY38914* ay38914)
|
||||||
|
{
|
||||||
|
this->ay38914 = ay38914;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AY38914_Registers::reset()
|
||||||
|
{
|
||||||
|
memset(memory, 0, sizeof(memory));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AY38914_Registers::poke(UINT16 location, UINT16 value)
|
||||||
|
{
|
||||||
|
location &= 0x0F;
|
||||||
|
switch(location) {
|
||||||
|
case 0x00:
|
||||||
|
value = value & 0x00FF;
|
||||||
|
channel0.period = (channel0.period & 0x0F00) |
|
||||||
|
value;
|
||||||
|
channel0.periodValue = (channel0.period
|
||||||
|
? channel0.period : 0x1000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x01:
|
||||||
|
value = value & 0x00FF;
|
||||||
|
channel1.period = (channel1.period & 0x0F00) |
|
||||||
|
value;
|
||||||
|
channel1.periodValue = (channel1.period
|
||||||
|
? channel1.period : 0x1000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x02:
|
||||||
|
value = value & 0x00FF;
|
||||||
|
channel2.period = (channel2.period & 0x0F00) |
|
||||||
|
value;
|
||||||
|
channel2.periodValue = (channel2.period
|
||||||
|
? channel2.period : 0x1000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x03:
|
||||||
|
value = value & 0x00FF;
|
||||||
|
envelopePeriod = (envelopePeriod & 0xFF00) |
|
||||||
|
value;
|
||||||
|
envelopePeriodValue = (envelopePeriod
|
||||||
|
? (envelopePeriod << 1) : 0x20000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x04:
|
||||||
|
value = value & 0x000F;
|
||||||
|
channel0.period = (channel0.period & 0x00FF) |
|
||||||
|
(value<<8);
|
||||||
|
channel0.periodValue = (channel0.period
|
||||||
|
? channel0.period : 0x1000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x05:
|
||||||
|
value = value & 0x000F;
|
||||||
|
channel1.period = (channel1.period & 0x00FF) |
|
||||||
|
(value<<8);
|
||||||
|
channel1.periodValue = (channel1.period
|
||||||
|
? channel1.period : 0x1000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x06:
|
||||||
|
value = value & 0x000F;
|
||||||
|
channel2.period = (channel2.period & 0x00FF) |
|
||||||
|
(value<<8);
|
||||||
|
channel2.periodValue = (channel2.period
|
||||||
|
? channel2.period : 0x1000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x07:
|
||||||
|
value = value & 0x00FF;
|
||||||
|
envelopePeriod = (envelopePeriod & 0x00FF) |
|
||||||
|
(value<<8);
|
||||||
|
envelopePeriodValue = (envelopePeriod
|
||||||
|
? (envelopePeriod << 1) : 0x20000);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x08:
|
||||||
|
value = value & 0x00FF;
|
||||||
|
channel0.toneDisabled = !!(value & 0x0001);
|
||||||
|
channel1.toneDisabled = !!(value & 0x0002);
|
||||||
|
channel2.toneDisabled = !!(value & 0x0004);
|
||||||
|
channel0.noiseDisabled = !!(value & 0x0008);
|
||||||
|
channel1.noiseDisabled = !!(value & 0x0010);
|
||||||
|
channel2.noiseDisabled = !!(value & 0x0020);
|
||||||
|
channel0.isDirty = TRUE;
|
||||||
|
channel1.isDirty = TRUE;
|
||||||
|
channel2.isDirty = TRUE;
|
||||||
|
noiseIdle = channel0.noiseDisabled &
|
||||||
|
channel1.noiseDisabled &
|
||||||
|
channel2.noiseDisabled;
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x09:
|
||||||
|
value = value & 0x001F;
|
||||||
|
noisePeriod = value;
|
||||||
|
noisePeriodValue = (noisePeriod
|
||||||
|
? (noisePeriod << 1) : 0x0040);
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0A:
|
||||||
|
value = value & 0x000F;
|
||||||
|
envelopeHold = !!(value & 0x0001);
|
||||||
|
envelopeAltr = !!(value & 0x0002);
|
||||||
|
envelopeAtak = !!(value & 0x0004);
|
||||||
|
envelopeCont = !!(value & 0x0008);
|
||||||
|
envelopeVolume = (envelopeAtak ? 0 : 15);
|
||||||
|
envelopeCounter = envelopePeriodValue;
|
||||||
|
envelopeIdle = FALSE;
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0B:
|
||||||
|
value = value & 0x003F;
|
||||||
|
channel0.envelope = !!(value & 0x0010);
|
||||||
|
channel0.volume = (value & 0x000F);
|
||||||
|
channel0.isDirty = TRUE;
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0C:
|
||||||
|
value = value & 0x003F;
|
||||||
|
channel1.envelope = !!(value & 0x0010);
|
||||||
|
channel1.volume = (value & 0x000F);
|
||||||
|
channel1.isDirty = TRUE;
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0D:
|
||||||
|
value = value & 0x003F;
|
||||||
|
channel2.envelope = !!(value & 0x0010);
|
||||||
|
channel2.volume = (value & 0x000F);
|
||||||
|
channel2.isDirty = TRUE;
|
||||||
|
memory[location] = value;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0E:
|
||||||
|
ay38914->psgIO1->setOutputValue(value);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0F:
|
||||||
|
ay38914->psgIO0->setOutputValue(value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 AY38914_Registers::peek(UINT16 location)
|
||||||
|
{
|
||||||
|
location &= 0x0F;
|
||||||
|
switch(location) {
|
||||||
|
case 0x0E:
|
||||||
|
return ay38914->psgIO1->getInputValue();
|
||||||
|
case 0x0F:
|
||||||
|
return ay38914->psgIO0->getInputValue();
|
||||||
|
default:
|
||||||
|
return memory[location];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
36
arm9/source/emucore/AY38914_Registers.h
Normal file
36
arm9/source/emucore/AY38914_Registers.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
|
||||||
|
#ifndef AY38914_REGISTERS_H
|
||||||
|
#define AY38914_REGISTERS_H
|
||||||
|
|
||||||
|
#include "RAM.h"
|
||||||
|
|
||||||
|
class AY38914;
|
||||||
|
|
||||||
|
class AY38914_Registers : public RAM
|
||||||
|
{
|
||||||
|
friend class AY38914;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset();
|
||||||
|
void poke(UINT16 location, UINT16 value);
|
||||||
|
UINT16 peek(UINT16 location);
|
||||||
|
|
||||||
|
inline size_t getMemoryByteSize() {
|
||||||
|
return sizeof(memory);
|
||||||
|
}
|
||||||
|
void getMemory(void* dst, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(dst, memory + offset, size);
|
||||||
|
}
|
||||||
|
void setMemory(void* src, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(memory + offset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
AY38914_Registers(UINT16 address);
|
||||||
|
void init(AY38914* ay38914);
|
||||||
|
|
||||||
|
AY38914* ay38914;
|
||||||
|
UINT16 memory[0x0E];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
161
arm9/source/emucore/AudioMixer.cpp
Normal file
161
arm9/source/emucore/AudioMixer.cpp
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "AudioMixer.h"
|
||||||
|
#include "AudioOutputLine.h"
|
||||||
|
|
||||||
|
UINT16 audio_mixer_buffer[1500] __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
extern UINT64 lcm(UINT64, UINT64);
|
||||||
|
|
||||||
|
AudioMixer::AudioMixer()
|
||||||
|
: Processor("Audio Mixer"),
|
||||||
|
audioProducerCount(0),
|
||||||
|
commonClocksPerTick(0),
|
||||||
|
sampleBuffer(NULL),
|
||||||
|
sampleBufferSize(0),
|
||||||
|
sampleCount(0),
|
||||||
|
sampleSize(0)
|
||||||
|
{
|
||||||
|
memset(&audioProducers, 0, sizeof(audioProducers));
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioMixer::~AudioMixer()
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < audioProducerCount; i++)
|
||||||
|
delete audioProducers[i]->audioOutputLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::addAudioProducer(AudioProducer* p)
|
||||||
|
{
|
||||||
|
audioProducers[audioProducerCount] = p;
|
||||||
|
audioProducers[audioProducerCount]->audioOutputLine =
|
||||||
|
new AudioOutputLine();
|
||||||
|
audioProducerCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::removeAudioProducer(AudioProducer* p)
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < audioProducerCount; i++) {
|
||||||
|
if (audioProducers[i] == p) {
|
||||||
|
delete p->audioOutputLine;
|
||||||
|
for (UINT32 j = i; j < (audioProducerCount-1); j++)
|
||||||
|
audioProducers[j] = audioProducers[j+1];
|
||||||
|
audioProducerCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::removeAll()
|
||||||
|
{
|
||||||
|
while (audioProducerCount)
|
||||||
|
removeAudioProducer(audioProducers[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::resetProcessor()
|
||||||
|
{
|
||||||
|
//reset instance data
|
||||||
|
commonClocksPerTick = 0;
|
||||||
|
sampleCount = 0;
|
||||||
|
|
||||||
|
if (sampleBuffer) {
|
||||||
|
memset(sampleBuffer, 0, sampleBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//iterate through my audio output lines to determine the common output clock
|
||||||
|
UINT64 totalClockSpeed = getClockSpeed();
|
||||||
|
for (UINT32 i = 0; i < audioProducerCount; i++) {
|
||||||
|
audioProducers[i]->audioOutputLine->reset();
|
||||||
|
totalClockSpeed = lcm(totalClockSpeed, ((UINT64)audioProducers[i]->getClockSpeed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
//iterate again to determine the clock factor of each
|
||||||
|
commonClocksPerTick = totalClockSpeed / getClockSpeed();
|
||||||
|
for (UINT32 i = 0; i < audioProducerCount; i++) {
|
||||||
|
audioProducers[i]->audioOutputLine->commonClocksPerSample = (totalClockSpeed / audioProducers[i]->getClockSpeed())
|
||||||
|
* audioProducers[i]->getClocksPerSample();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::init(UINT32 sampleRate)
|
||||||
|
{
|
||||||
|
// TODO: assert if sampleRate/clockSpeed is 0
|
||||||
|
|
||||||
|
AudioMixer::release();
|
||||||
|
|
||||||
|
clockSpeed = sampleRate;
|
||||||
|
sampleSize = ( clockSpeed / 60.0 );
|
||||||
|
sampleBufferSize = sampleSize * sizeof(INT16);
|
||||||
|
sampleBuffer = (INT16*) audio_mixer_buffer;
|
||||||
|
|
||||||
|
if (sampleBuffer) {
|
||||||
|
memset(sampleBuffer, 0, sampleBufferSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::release()
|
||||||
|
{
|
||||||
|
if (sampleBuffer) {
|
||||||
|
sampleBufferSize = 0;
|
||||||
|
sampleSize = 0;
|
||||||
|
sampleCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 AudioMixer::getClockSpeed()
|
||||||
|
{
|
||||||
|
return clockSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
ITCM_CODE INT32 AudioMixer::tick(INT32 minimum)
|
||||||
|
{
|
||||||
|
// TODO: assert if sampleCount >= sampleSize
|
||||||
|
|
||||||
|
for (int totalTicks = 0; totalTicks < minimum; totalTicks++) {
|
||||||
|
//mix and flush the sample buffers
|
||||||
|
INT64 totalSample = 0;
|
||||||
|
for (UINT32 i = 0; i < audioProducerCount; i++) {
|
||||||
|
AudioOutputLine* nextLine = audioProducers[i]->audioOutputLine;
|
||||||
|
|
||||||
|
INT64 missingClocks = (this->commonClocksPerTick - nextLine->commonClockCounter);
|
||||||
|
INT64 sampleToUse = (missingClocks < 0 ? nextLine->previousSample : nextLine->currentSample);
|
||||||
|
|
||||||
|
//account for when audio producers idle by adding enough samples to each producer's buffer
|
||||||
|
//to fill the time since last sample calculation
|
||||||
|
INT64 missingSampleCount = (missingClocks / nextLine->commonClocksPerSample);
|
||||||
|
if (missingSampleCount != 0) {
|
||||||
|
nextLine->sampleBuffer += missingSampleCount * sampleToUse * nextLine->commonClocksPerSample;
|
||||||
|
nextLine->commonClockCounter += missingSampleCount * nextLine->commonClocksPerSample;
|
||||||
|
missingClocks -= missingSampleCount * nextLine->commonClocksPerSample;
|
||||||
|
}
|
||||||
|
INT64 partialSample = sampleToUse * missingClocks;
|
||||||
|
|
||||||
|
//calculate the sample for this line
|
||||||
|
totalSample += (INT16)((nextLine->sampleBuffer + partialSample) / commonClocksPerTick);
|
||||||
|
|
||||||
|
//clear the sample buffer for this line
|
||||||
|
nextLine->sampleBuffer = -partialSample;
|
||||||
|
nextLine->commonClockCounter = -missingClocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (audioProducerCount > 1) {
|
||||||
|
totalSample = totalSample / audioProducerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
sampleBuffer[sampleCount++] = totalSample;
|
||||||
|
|
||||||
|
if (sampleCount == sampleSize) {
|
||||||
|
flushAudio();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::flushAudio()
|
||||||
|
{
|
||||||
|
//the platform subclass must copy the sampleBuffer to the device
|
||||||
|
//before calling here (which discards the contents of sampleBuffer)
|
||||||
|
sampleCount = 0;
|
||||||
|
}
|
54
arm9/source/emucore/AudioMixer.h
Normal file
54
arm9/source/emucore/AudioMixer.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
#ifndef AUDIOMIXER_H
|
||||||
|
#define AUDIOMIXER_H
|
||||||
|
|
||||||
|
#include "AudioProducer.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "Processor.h"
|
||||||
|
|
||||||
|
#define MAX_AUDIO_PRODUCERS 10
|
||||||
|
|
||||||
|
template<typename A, typename W> class EmulatorTmpl;
|
||||||
|
|
||||||
|
class AudioMixer : public Processor
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class ProcessorBus;
|
||||||
|
friend class AudioOutputLine;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioMixer();
|
||||||
|
virtual ~AudioMixer();
|
||||||
|
|
||||||
|
inline INT16 clipSample(INT64 sample) {
|
||||||
|
return sample > 32767 ? 32767 : sample < -32768 ? -32768 : (INT16)sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void resetProcessor();
|
||||||
|
INT32 getClockSpeed();
|
||||||
|
INT32 tick(INT32 minimum);
|
||||||
|
virtual void flushAudio();
|
||||||
|
|
||||||
|
//only to be called by the Emulator
|
||||||
|
virtual void init(UINT32 sampleRate);
|
||||||
|
virtual void release();
|
||||||
|
|
||||||
|
void addAudioProducer(AudioProducer*);
|
||||||
|
void removeAudioProducer(AudioProducer*);
|
||||||
|
void removeAll();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//output info
|
||||||
|
INT32 clockSpeed;
|
||||||
|
|
||||||
|
AudioProducer* audioProducers[MAX_AUDIO_PRODUCERS];
|
||||||
|
UINT32 audioProducerCount;
|
||||||
|
|
||||||
|
INT64 commonClocksPerTick;
|
||||||
|
INT16* sampleBuffer;
|
||||||
|
UINT32 sampleBufferSize;
|
||||||
|
UINT32 sampleCount;
|
||||||
|
UINT32 sampleSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
31
arm9/source/emucore/AudioOutputLine.cpp
Normal file
31
arm9/source/emucore/AudioOutputLine.cpp
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
|
||||||
|
#include "AudioOutputLine.h"
|
||||||
|
#include "AudioMixer.h"
|
||||||
|
|
||||||
|
AudioOutputLine::AudioOutputLine()
|
||||||
|
: sampleBuffer(0),
|
||||||
|
previousSample(0),
|
||||||
|
currentSample(0),
|
||||||
|
commonClockCounter(0),
|
||||||
|
commonClocksPerSample(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void AudioOutputLine::reset()
|
||||||
|
{
|
||||||
|
sampleBuffer = 0;
|
||||||
|
previousSample = 0;
|
||||||
|
currentSample = 0;
|
||||||
|
commonClockCounter = 0;
|
||||||
|
commonClocksPerSample = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioOutputLine::playSample(INT16 sample)
|
||||||
|
{
|
||||||
|
sampleBuffer += currentSample * commonClocksPerSample;
|
||||||
|
commonClockCounter += commonClocksPerSample;
|
||||||
|
previousSample = currentSample;
|
||||||
|
currentSample = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
29
arm9/source/emucore/AudioOutputLine.h
Normal file
29
arm9/source/emucore/AudioOutputLine.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
#ifndef AUDIOOUTPUTLINE_H
|
||||||
|
#define AUDIOOUTPUTLINE_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class AudioOutputLine
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class AudioMixer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void playSample(INT16 sample);
|
||||||
|
|
||||||
|
private:
|
||||||
|
AudioOutputLine();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
INT64 sampleBuffer;
|
||||||
|
INT64 previousSample;
|
||||||
|
INT64 currentSample;
|
||||||
|
INT64 commonClockCounter;
|
||||||
|
INT64 commonClocksPerSample;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
26
arm9/source/emucore/AudioProducer.h
Normal file
26
arm9/source/emucore/AudioProducer.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
#ifndef AUDIOPRODUCER_H
|
||||||
|
#define AUDIOPRODUCER_H
|
||||||
|
|
||||||
|
#include "AudioOutputLine.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is implemented by any piece of hardware that produces audio.
|
||||||
|
*/
|
||||||
|
class AudioProducer
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class AudioMixer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
AudioProducer() : audioOutputLine(NULL) {}
|
||||||
|
|
||||||
|
virtual INT32 getClockSpeed() = 0;
|
||||||
|
virtual INT32 getClocksPerSample() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
AudioOutputLine* audioOutputLine;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
79
arm9/source/emucore/BackTabRAM.cpp
Normal file
79
arm9/source/emucore/BackTabRAM.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
|
||||||
|
#include "BackTabRAM.h"
|
||||||
|
|
||||||
|
BackTabRAM::BackTabRAM()
|
||||||
|
: RAM(BACKTAB_SIZE, BACKTAB_LOCATION, 0xFFFF, 0xFFFF)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void BackTabRAM::reset()
|
||||||
|
{
|
||||||
|
dirtyRAM = TRUE;
|
||||||
|
colorAdvanceBitsDirty = TRUE;
|
||||||
|
for (UINT16 i = 0; i < BACKTAB_SIZE; i++) {
|
||||||
|
image[i] = 0;
|
||||||
|
dirtyBytes[i] = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 BackTabRAM::peek(UINT16 location)
|
||||||
|
{
|
||||||
|
return image[location-BACKTAB_LOCATION];
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackTabRAM::poke(UINT16 location, UINT16 value)
|
||||||
|
{
|
||||||
|
value &= 0xFFFF;
|
||||||
|
location -= BACKTAB_LOCATION;
|
||||||
|
|
||||||
|
if (image[location] == value)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((image[location] & 0x2000) != (value & 0x2000))
|
||||||
|
colorAdvanceBitsDirty = TRUE;
|
||||||
|
|
||||||
|
image[location] = value;
|
||||||
|
dirtyBytes[location] = TRUE;
|
||||||
|
dirtyRAM = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackTabRAM::markClean() {
|
||||||
|
if (!dirtyRAM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (UINT16 i = 0; i < BACKTAB_SIZE; i++)
|
||||||
|
dirtyBytes[i] = FALSE;
|
||||||
|
dirtyRAM = FALSE;
|
||||||
|
colorAdvanceBitsDirty = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL BackTabRAM::areColorAdvanceBitsDirty() {
|
||||||
|
return colorAdvanceBitsDirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL BackTabRAM::isDirty() {
|
||||||
|
return dirtyRAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL BackTabRAM::isDirty(UINT16 location) {
|
||||||
|
return dirtyBytes[location-BACKTAB_LOCATION];
|
||||||
|
}
|
||||||
|
|
||||||
|
BackTabRAMState BackTabRAM::getState()
|
||||||
|
{
|
||||||
|
BackTabRAMState state = {0};
|
||||||
|
|
||||||
|
state.RAMState = RAM::getState(state.image);
|
||||||
|
this->getImage(state.image, 0, this->getImageByteSize());
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackTabRAM::setState(BackTabRAMState state, UINT16* image)
|
||||||
|
{
|
||||||
|
memset(this->dirtyBytes, TRUE, sizeof(this->dirtyBytes));
|
||||||
|
RAM::setState(state.RAMState, NULL);
|
||||||
|
this->setImage(state.image, 0, this->getImageByteSize());
|
||||||
|
|
||||||
|
this->dirtyRAM = TRUE;
|
||||||
|
this->colorAdvanceBitsDirty = TRUE;
|
||||||
|
}
|
52
arm9/source/emucore/BackTabRAM.h
Normal file
52
arm9/source/emucore/BackTabRAM.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#ifndef BACKTABRAM_H
|
||||||
|
#define BACKTABRAM_H
|
||||||
|
|
||||||
|
#include "RAM.h"
|
||||||
|
|
||||||
|
#define BACKTAB_SIZE 0xF0
|
||||||
|
#define BACKTAB_LOCATION 0x200
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK(_BackTabRAMState
|
||||||
|
{
|
||||||
|
_RAMState RAMState;
|
||||||
|
UINT16 image[BACKTAB_SIZE];
|
||||||
|
} BackTabRAMState;)
|
||||||
|
|
||||||
|
class BackTabRAM : public RAM
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
BackTabRAM();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
UINT16 peek(UINT16 location);
|
||||||
|
void poke(UINT16 location, UINT16 value);
|
||||||
|
|
||||||
|
BOOL areColorAdvanceBitsDirty();
|
||||||
|
BOOL isDirty();
|
||||||
|
BOOL isDirty(UINT16 location);
|
||||||
|
void markClean();
|
||||||
|
|
||||||
|
inline size_t getImageByteSize() {
|
||||||
|
return size * sizeof(UINT16);
|
||||||
|
}
|
||||||
|
void getImage(void* dst, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(dst, image + offset, size);
|
||||||
|
}
|
||||||
|
void setImage(void* src, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(image + offset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
BackTabRAMState getState();
|
||||||
|
void setState(BackTabRAMState state, UINT16* image);
|
||||||
|
|
||||||
|
private:
|
||||||
|
UINT16 image[BACKTAB_SIZE];
|
||||||
|
BOOL dirtyBytes[BACKTAB_SIZE];
|
||||||
|
BOOL dirtyRAM;
|
||||||
|
BOOL colorAdvanceBitsDirty;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
4258
arm9/source/emucore/CP1610.cpp
Normal file
4258
arm9/source/emucore/CP1610.cpp
Normal file
File diff suppressed because it is too large
Load Diff
159
arm9/source/emucore/CP1610.h
Normal file
159
arm9/source/emucore/CP1610.h
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
|
||||||
|
#ifndef CP1610_H
|
||||||
|
#define CP1610_H
|
||||||
|
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "SignalLine.h"
|
||||||
|
#include "MemoryBus.h"
|
||||||
|
|
||||||
|
#define CP1610_PIN_IN_INTRM 0
|
||||||
|
#define CP1610_PIN_IN_BUSRQ 1
|
||||||
|
|
||||||
|
#define CP1610_PIN_OUT_BUSAK 0
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _CP1610State
|
||||||
|
{
|
||||||
|
INT8 S;
|
||||||
|
INT8 Z;
|
||||||
|
INT8 O;
|
||||||
|
INT8 C;
|
||||||
|
INT8 I;
|
||||||
|
INT8 D;
|
||||||
|
INT8 interruptible;
|
||||||
|
INT8 ext;
|
||||||
|
UINT16 interruptAddress;
|
||||||
|
UINT16 resetAddress;
|
||||||
|
UINT16 r[8];
|
||||||
|
} CP1610State; )
|
||||||
|
|
||||||
|
extern UINT8 interruptible;
|
||||||
|
|
||||||
|
class CP1610 : public Processor
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
CP1610(MemoryBus* m, UINT16 resetAddress,
|
||||||
|
UINT16 interruptAddress);
|
||||||
|
|
||||||
|
//PowerConsumer functions
|
||||||
|
void resetProcessor();
|
||||||
|
|
||||||
|
//Processor functions
|
||||||
|
INT32 getClockSpeed();
|
||||||
|
INT32 tick(INT32);
|
||||||
|
|
||||||
|
BOOL isIdle() {
|
||||||
|
if (!pinIn[CP1610_PIN_IN_BUSRQ]->isHigh && interruptible) {
|
||||||
|
pinOut[CP1610_PIN_OUT_BUSAK]->isHigh = FALSE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pinOut[CP1610_PIN_OUT_BUSAK]->isHigh = TRUE;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef DEVELOPER_VERSION
|
||||||
|
UINT32 getDebugItemCount();
|
||||||
|
const CHAR* getDebugItemName(UINT32 i);
|
||||||
|
const UINT32 getDebugItemValue(UINT32 i);
|
||||||
|
|
||||||
|
//other debugging stuff
|
||||||
|
BOOL isCentralProcessor() { return TRUE; }
|
||||||
|
UINT32 decode(CHAR description[256], UINT32 memoryLocation);
|
||||||
|
UINT32 getProgramCounter();
|
||||||
|
#endif
|
||||||
|
CP1610State getState();
|
||||||
|
void setState(CP1610State state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setIndirect(UINT16 register, UINT16 value);
|
||||||
|
UINT16 getIndirect(UINT16 register);
|
||||||
|
INT32 HLT();
|
||||||
|
INT32 SDBD();
|
||||||
|
INT32 EIS();
|
||||||
|
INT32 DIS();
|
||||||
|
INT32 TCI();
|
||||||
|
INT32 CLRC();
|
||||||
|
INT32 SETC();
|
||||||
|
INT32 J(UINT16 target);
|
||||||
|
INT32 JSR(UINT16 register, UINT16 target);
|
||||||
|
INT32 JE(UINT16 target);
|
||||||
|
INT32 JSRE(UINT16 register, UINT16 target);
|
||||||
|
INT32 JD(UINT16 target);
|
||||||
|
INT32 JSRD(UINT16 register, UINT16 target);
|
||||||
|
INT32 INCR(UINT16 register);
|
||||||
|
INT32 DECR(UINT16 register);
|
||||||
|
INT32 COMR(UINT16 register);
|
||||||
|
INT32 NEGR(UINT16 register);
|
||||||
|
INT32 ADCR(UINT16 register);
|
||||||
|
INT32 RSWD(UINT16 register);
|
||||||
|
INT32 GSWD(UINT16 register);
|
||||||
|
INT32 NOP(UINT16 twoOption);
|
||||||
|
INT32 SIN(UINT16 twoOption);
|
||||||
|
INT32 SWAP_1(UINT16 register);
|
||||||
|
INT32 SWAP_2(UINT16 register);
|
||||||
|
INT32 SLL_1(UINT16 register);
|
||||||
|
INT32 SLL_2(UINT16 register);
|
||||||
|
INT32 RLC_1(UINT16 register);
|
||||||
|
INT32 RLC_2(UINT16 register);
|
||||||
|
INT32 SLLC_1(UINT16 register);
|
||||||
|
INT32 SLLC_2(UINT16 register);
|
||||||
|
INT32 SLR_1(UINT16 register);
|
||||||
|
INT32 SLR_2(UINT16 register);
|
||||||
|
INT32 SAR_1(UINT16 register);
|
||||||
|
INT32 SAR_2(UINT16 register);
|
||||||
|
INT32 RRC_1(UINT16 register);
|
||||||
|
INT32 RRC_2(UINT16 register);
|
||||||
|
INT32 SARC_1(UINT16 register);
|
||||||
|
INT32 SARC_2(UINT16 register);
|
||||||
|
INT32 MOVR(UINT16 sourceReg, UINT16 destReg);
|
||||||
|
INT32 ADDR(UINT16 sourceReg, UINT16 destReg);
|
||||||
|
INT32 SUBR(UINT16 sourceReg, UINT16 destReg);
|
||||||
|
INT32 CMPR(UINT16 sourceReg, UINT16 destReg);
|
||||||
|
INT32 ANDR(UINT16 sourceReg, UINT16 destReg);
|
||||||
|
INT32 XORR(UINT16 sourceReg, UINT16 destReg);
|
||||||
|
INT32 BEXT(UINT16 condition, INT16 displacement);
|
||||||
|
INT32 B(INT16 displacement);
|
||||||
|
INT32 NOPP(INT16 displacement);
|
||||||
|
INT32 BC(INT16 displacement);
|
||||||
|
INT32 BNC(INT16 displacement);
|
||||||
|
INT32 BOV(INT16 displacement);
|
||||||
|
INT32 BNOV(INT16 displacement);
|
||||||
|
INT32 BPL(INT16 displacement);
|
||||||
|
INT32 BMI(INT16 displacement);
|
||||||
|
INT32 BEQ(INT16 displacement);
|
||||||
|
INT32 BNEQ(INT16 displacement);
|
||||||
|
INT32 BLT(INT16 displacement);
|
||||||
|
INT32 BGE(INT16 displacement);
|
||||||
|
INT32 BLE(INT16 displacement);
|
||||||
|
INT32 BGT(INT16 displacement);
|
||||||
|
INT32 BUSC(INT16 displacement);
|
||||||
|
INT32 BESC(INT16 displacement);
|
||||||
|
INT32 MVO(UINT16 register, UINT16 address);
|
||||||
|
INT32 MVO_ind(UINT16 registerWithAddress, UINT16 registerToMove);
|
||||||
|
INT32 MVI(UINT16 address, UINT16 register);
|
||||||
|
INT32 MVI_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
|
||||||
|
INT32 ADD(UINT16 address, UINT16 register);
|
||||||
|
INT32 ADD_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
|
||||||
|
INT32 SUB(UINT16 address, UINT16 register);
|
||||||
|
INT32 SUB_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
|
||||||
|
INT32 CMP(UINT16 address, UINT16 register);
|
||||||
|
INT32 CMP_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
|
||||||
|
INT32 AND(UINT16 address, UINT16 register);
|
||||||
|
INT32 AND_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
|
||||||
|
INT32 XOR(UINT16 address, UINT16 register);
|
||||||
|
INT32 XOR_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
|
||||||
|
INT32 decode(void);
|
||||||
|
|
||||||
|
//the mory bus
|
||||||
|
MemoryBus* memoryBus;
|
||||||
|
|
||||||
|
//interrupt address
|
||||||
|
UINT16 interruptAddress;
|
||||||
|
|
||||||
|
//reset address
|
||||||
|
UINT16 resetAddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
102
arm9/source/emucore/CRC32.cpp
Normal file
102
arm9/source/emucore/CRC32.cpp
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "CRC32.h"
|
||||||
|
|
||||||
|
#define CRC32_POLY 0x04C11DB7
|
||||||
|
|
||||||
|
//using namespace std;
|
||||||
|
|
||||||
|
#ifndef _MAX_PATH
|
||||||
|
#define _MAX_PATH 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UINT64 reflect(UINT64 ref, char ch)
|
||||||
|
{
|
||||||
|
|
||||||
|
UINT64 value(0);
|
||||||
|
|
||||||
|
// Swap bit 0 for bit 7
|
||||||
|
// bit 1 for bit 6, etc.
|
||||||
|
for(int i = 1; i < (ch + 1); i++)
|
||||||
|
{
|
||||||
|
if(ref & 1)
|
||||||
|
value |= 1 << (ch - i);
|
||||||
|
ref >>= 1;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CRC32::CRC32() {
|
||||||
|
UINT32 i, j;
|
||||||
|
for (i = 0; i < 256; ++i) {
|
||||||
|
crc32_table[i]=(UINT32)(reflect(i, 8) << 24);
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
crc32_table[i] = (crc32_table[i] << 1) ^
|
||||||
|
(crc32_table[i] & (1 << 31) ? CRC32_POLY : 0);
|
||||||
|
crc32_table[i] = (UINT32)reflect(crc32_table[i], 32);
|
||||||
|
}
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 CRC32::getCrc(const CHAR* filename)
|
||||||
|
{
|
||||||
|
CRC32 crc;
|
||||||
|
|
||||||
|
FILE* file = fopen(filename, "rb");
|
||||||
|
int read = fgetc(file);
|
||||||
|
while (read != EOF) {
|
||||||
|
crc.update((UINT8)read);
|
||||||
|
read = fgetc(file);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return crc.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 CRC32::getCrc(UINT8* image, UINT32 imageSize)
|
||||||
|
{
|
||||||
|
CRC32 crc;
|
||||||
|
for (UINT32 i = 0; i < imageSize; i++)
|
||||||
|
crc.update(image[i]);
|
||||||
|
|
||||||
|
return crc.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
void CRC32::formInternalFilename(CHAR* out, const CHAR* in, const CHAR* ext)
|
||||||
|
{
|
||||||
|
strcpy(out, in);
|
||||||
|
char *p = strstr(out, ".zip");
|
||||||
|
*p = '\0';
|
||||||
|
strcat(out, ext);
|
||||||
|
p = &out[strlen((char *)out)];
|
||||||
|
while(--p > out)
|
||||||
|
{
|
||||||
|
if(*p == '\\' || *p == '/')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
strcpy(out, p+1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
void CRC32::reset() {
|
||||||
|
crc = 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRC32::update(UINT8 data) {
|
||||||
|
crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ data];
|
||||||
|
}
|
||||||
|
|
||||||
|
void CRC32::update(UINT8* data, UINT32 length) {
|
||||||
|
for (UINT32 i = 0; i < length; i++)
|
||||||
|
//crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ data[i]];
|
||||||
|
crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ data[i]];
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 CRC32::getValue() {
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
28
arm9/source/emucore/CRC32.h
Normal file
28
arm9/source/emucore/CRC32.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
#ifndef CRC32_H
|
||||||
|
#define CRC32_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class CRC32
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
CRC32();
|
||||||
|
void reset();
|
||||||
|
void update(UINT8 data);
|
||||||
|
void update(UINT8* data, UINT32 length);
|
||||||
|
UINT32 getValue();
|
||||||
|
static UINT32 getCrc(const CHAR* filename);
|
||||||
|
static UINT32 getCrc(UINT8* image, UINT32 imageSize);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//static void formInternalFilename(CHAR*, const CHAR*, const CHAR*);
|
||||||
|
|
||||||
|
UINT32 crc;
|
||||||
|
UINT32 crc32_table[256];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
51
arm9/source/emucore/ECS.cpp
Normal file
51
arm9/source/emucore/ECS.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include "ECS.h"
|
||||||
|
|
||||||
|
ECS::ECS()
|
||||||
|
: Peripheral("Electronic Computer System", "ECS"),
|
||||||
|
keyboard(2),
|
||||||
|
ramBank(ECS_RAM_SIZE, 0x4000, 8),
|
||||||
|
uart(4, 0xE0, 8),
|
||||||
|
psg2(0x00F0, &keyboard, &keyboard),
|
||||||
|
bank0("ECS ROM #1", "ecs.bin", 0, 2, 0x1000, 0x2000),
|
||||||
|
bank0Banker(&bank0, 0x2FFF, 0xFFF0, 0x2A50, 0x000F, 1),
|
||||||
|
bank1("ECS ROM #2", "ecs.bin", 8192, 2, 0x1000, 0x7000),
|
||||||
|
bank1Banker(&bank1, 0x7FFF, 0xFFF0, 0x7A50, 0x000F, 0),
|
||||||
|
bank2("ECS ROM #3", "ecs.bin", 16384, 2, 0x1000, 0xE000),
|
||||||
|
bank2Banker(&bank2, 0xEFFF, 0xFFF0, 0xEA50, 0x000F, 1)
|
||||||
|
{
|
||||||
|
AddROM(&bank0);
|
||||||
|
AddRAM(&bank0Banker);
|
||||||
|
AddROM(&bank1);
|
||||||
|
AddRAM(&bank1Banker);
|
||||||
|
AddROM(&bank2);
|
||||||
|
AddRAM(&bank2Banker);
|
||||||
|
|
||||||
|
AddRAM(&ramBank);
|
||||||
|
AddRAM(&uart);
|
||||||
|
|
||||||
|
AddProcessor(&psg2);
|
||||||
|
AddAudioProducer(&psg2);
|
||||||
|
AddRAM(&psg2.registers);
|
||||||
|
|
||||||
|
AddInputConsumer(&keyboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
ECSState ECS::getState()
|
||||||
|
{
|
||||||
|
ECSState state = {0};
|
||||||
|
|
||||||
|
state.ramState = ramBank.getState(state.ramImage);
|
||||||
|
state.uartState = uart.getState(NULL);
|
||||||
|
state.psg2State = psg2.getState();
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECS::setState(ECSState state)
|
||||||
|
{
|
||||||
|
ramBank.setState(state.ramState, state.ramImage);
|
||||||
|
uart.setState(state.uartState, NULL);
|
||||||
|
psg2.setState(state.psg2State);
|
||||||
|
}
|
53
arm9/source/emucore/ECS.h
Normal file
53
arm9/source/emucore/ECS.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
#ifndef ECS_H
|
||||||
|
#define ECS_H
|
||||||
|
|
||||||
|
#include "Peripheral.h"
|
||||||
|
#include "ECSKeyboard.h"
|
||||||
|
#include "AudioOutputLine.h"
|
||||||
|
#include "RAM.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
#include "ROMBanker.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "AY38914.h"
|
||||||
|
|
||||||
|
#define ECS_RAM_SIZE 0x0800
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _ECSState
|
||||||
|
{
|
||||||
|
RAMState ramState;
|
||||||
|
UINT16 ramImage[ECS_RAM_SIZE];
|
||||||
|
RAMState uartState;
|
||||||
|
AY38914State psg2State;
|
||||||
|
} ECSState; )
|
||||||
|
|
||||||
|
class Intellivision;
|
||||||
|
|
||||||
|
class ECS : public Peripheral
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class Intellivision;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ECS();
|
||||||
|
|
||||||
|
ECSState getState();
|
||||||
|
void setState(ECSState state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ECSKeyboard keyboard;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ROM bank0;
|
||||||
|
ROMBanker bank0Banker;
|
||||||
|
ROM bank1;
|
||||||
|
ROMBanker bank1Banker;
|
||||||
|
ROM bank2;
|
||||||
|
ROMBanker bank2Banker;
|
||||||
|
RAM ramBank;
|
||||||
|
RAM uart;
|
||||||
|
AY38914 psg2;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
85
arm9/source/emucore/ECSKeyboard.cpp
Normal file
85
arm9/source/emucore/ECSKeyboard.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
|
||||||
|
#include "ECSKeyboard.h"
|
||||||
|
|
||||||
|
const INT32 ECSKeyboard::sortedObjectIndices[NUM_ECS_OBJECTS] = {
|
||||||
|
24, 29, 34, 28, 33, 27, 32, 26, 31, 25, 30, // ESCAPE, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
|
||||||
|
23, 22, 40, 21, 39, 20, 38, 19, 37, 18, // Q, W, E, R, T, Y, U, I, O, P
|
||||||
|
46, 16, 45, 15, 44, 14, 43, 13, 42, 12, 36, // A, S, D, F, G, H, J, K, L, SEMICOLON, ENTER
|
||||||
|
10, 4, 9, 3, 8, 2, 7, 1, 6, // Z, X, C, V, B, N, M, COMMA, PERIOD
|
||||||
|
41, 47, 5, // CTRL, SHIFT, SPACE,
|
||||||
|
17, 11, 0, 35, // UP, DOWN, LEFT, RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
ECSKeyboard::ECSKeyboard(INT32 id)
|
||||||
|
: InputConsumer(id),
|
||||||
|
rowsToScan(0)
|
||||||
|
{
|
||||||
|
memset(rowInputValues, 0, sizeof(rowInputValues));
|
||||||
|
}
|
||||||
|
|
||||||
|
ECSKeyboard::~ECSKeyboard()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 ECSKeyboard::getInputConsumerObjectCount()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConsumerObject* ECSKeyboard::getInputConsumerObject(INT32 i)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECSKeyboard::resetInputConsumer()
|
||||||
|
{
|
||||||
|
rowsToScan = 0;
|
||||||
|
for (UINT16 i = 0; i < 8; i++)
|
||||||
|
rowInputValues[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECSKeyboard::evaluateInputs()
|
||||||
|
{
|
||||||
|
for (UINT16 row = 0; row < 6; row++)
|
||||||
|
{
|
||||||
|
rowInputValues[row] = 0;
|
||||||
|
if (inputConsumerObjects[row]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x01;
|
||||||
|
if (inputConsumerObjects[row+6]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x02;
|
||||||
|
if (inputConsumerObjects[row+12]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x04;
|
||||||
|
if (inputConsumerObjects[row+18]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x08;
|
||||||
|
if (inputConsumerObjects[row+24]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x10;
|
||||||
|
if (inputConsumerObjects[row+30]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x20;
|
||||||
|
if (inputConsumerObjects[row+36]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x40;
|
||||||
|
if (inputConsumerObjects[row+42]->getInputValue() == 1.0f)
|
||||||
|
rowInputValues[row] |= 0x80;
|
||||||
|
}
|
||||||
|
rowInputValues[6] = (inputConsumerObjects[47]->getInputValue() == 1.0f ? 0x80 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ECSKeyboard::getInputValue()
|
||||||
|
{
|
||||||
|
UINT16 inputValue = 0;
|
||||||
|
UINT16 rowMask = 1;
|
||||||
|
for (UINT16 row = 0; row < 8; row++) {
|
||||||
|
if ((rowsToScan & rowMask) != 0) {
|
||||||
|
rowMask = (UINT16)(rowMask << 1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
inputValue |= rowInputValues[row];
|
||||||
|
|
||||||
|
rowMask = (UINT16)(rowMask << 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (UINT16)(0xFF ^ inputValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ECSKeyboard::setOutputValue(UINT16 value) {
|
||||||
|
this->rowsToScan = value;
|
||||||
|
}
|
49
arm9/source/emucore/ECSKeyboard.h
Normal file
49
arm9/source/emucore/ECSKeyboard.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
#ifndef ECSKEYBOARD_H
|
||||||
|
#define ECSKEYBOARD_H
|
||||||
|
|
||||||
|
#define NUM_ECS_OBJECTS 48
|
||||||
|
|
||||||
|
#include "AY38914_InputOutput.h"
|
||||||
|
#include "InputConsumer.h"
|
||||||
|
|
||||||
|
class EmulationDirector;
|
||||||
|
|
||||||
|
class ECSKeyboard : public AY38914_InputOutput, public InputConsumer
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class EmulationDirector;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ECSKeyboard(INT32 id);
|
||||||
|
virtual ~ECSKeyboard();
|
||||||
|
|
||||||
|
const CHAR* getName() { return "ECS Keyboard"; }
|
||||||
|
|
||||||
|
void resetInputConsumer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poll the controller. This function is invoked by the
|
||||||
|
* InputConsumerBus just after the Emulator indicates it has entered
|
||||||
|
* vertical blank.
|
||||||
|
*/
|
||||||
|
void evaluateInputs();
|
||||||
|
|
||||||
|
//functions to get descriptive info about the input consumer
|
||||||
|
INT32 getInputConsumerObjectCount();
|
||||||
|
InputConsumerObject* getInputConsumerObject(INT32 i);
|
||||||
|
|
||||||
|
UINT16 getInputValue();
|
||||||
|
void setOutputValue(UINT16 value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputConsumerObject* inputConsumerObjects[NUM_ECS_OBJECTS];
|
||||||
|
UINT16 rowsToScan;
|
||||||
|
UINT16 rowInputValues[8];
|
||||||
|
|
||||||
|
static const INT32 sortedObjectIndices[NUM_ECS_OBJECTS];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
264
arm9/source/emucore/Emulator.cpp
Normal file
264
arm9/source/emucore/Emulator.cpp
Normal file
@ -0,0 +1,264 @@
|
|||||||
|
|
||||||
|
#include "Emulator.h"
|
||||||
|
#include "Intellivision.h"
|
||||||
|
|
||||||
|
extern UINT32 systemIDs[NUM_EMULATORS];
|
||||||
|
extern Emulator* emus[NUM_EMULATORS];
|
||||||
|
|
||||||
|
UINT32 Emulator::GetEmulatorCount()
|
||||||
|
{
|
||||||
|
return NUM_EMULATORS;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emulator* Emulator::GetEmulator(UINT32 i)
|
||||||
|
{
|
||||||
|
return emus[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
Emulator* Emulator::GetEmulatorByID(UINT32 targetSystemID)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < NUM_EMULATORS; i++) {
|
||||||
|
if (systemIDs[i] == targetSystemID)
|
||||||
|
return emus[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Emulator::Emulator(const char* name)
|
||||||
|
: Peripheral(name, name),
|
||||||
|
currentRip(NULL),
|
||||||
|
peripheralCount(0)
|
||||||
|
{
|
||||||
|
memset(peripherals, 0, sizeof(peripherals));
|
||||||
|
memset(usePeripheralIndicators, FALSE, sizeof(usePeripheralIndicators));
|
||||||
|
printf("Emulator [%s] Constructed\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::AddPeripheral(Peripheral* p)
|
||||||
|
{
|
||||||
|
peripherals[peripheralCount] = p;
|
||||||
|
printf(" Peripheral [%d] Added\n", peripheralCount);
|
||||||
|
peripheralCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 Emulator::GetPeripheralCount()
|
||||||
|
{
|
||||||
|
return peripheralCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
Peripheral* Emulator::GetPeripheral(UINT32 i)
|
||||||
|
{
|
||||||
|
return peripherals[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::UsePeripheral(UINT32 i, BOOL b)
|
||||||
|
{
|
||||||
|
usePeripheralIndicators[i] = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 Emulator::GetVideoWidth()
|
||||||
|
{
|
||||||
|
return videoWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 Emulator::GetVideoHeight()
|
||||||
|
{
|
||||||
|
return videoHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::InitVideo(VideoBus* video, UINT32 width, UINT32 height)
|
||||||
|
{
|
||||||
|
if ( video != NULL ) {
|
||||||
|
videoBus = video;
|
||||||
|
}
|
||||||
|
|
||||||
|
videoBus->init(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::ReleaseVideo()
|
||||||
|
{
|
||||||
|
if (videoBus) {
|
||||||
|
videoBus->release();
|
||||||
|
videoBus = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::InitAudio(AudioMixer* audio, UINT32 sampleRate)
|
||||||
|
{
|
||||||
|
if (audio != NULL) {
|
||||||
|
audioMixer = audio;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: check for an existing audioMixer processor and release it
|
||||||
|
for (UINT16 i = 0; i < GetProcessorCount(); i++) {
|
||||||
|
Processor* p = GetProcessor(i);
|
||||||
|
if (p == audio) {
|
||||||
|
RemoveProcessor(audio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AddProcessor(audioMixer);
|
||||||
|
audioMixer->init(sampleRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::ReleaseAudio()
|
||||||
|
{
|
||||||
|
if (audioMixer) {
|
||||||
|
audioMixer->release();
|
||||||
|
RemoveProcessor(audioMixer);
|
||||||
|
audioMixer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::Reset()
|
||||||
|
{
|
||||||
|
processorBus.reset();
|
||||||
|
memoryBus.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::SetRip(Rip* rip)
|
||||||
|
{
|
||||||
|
if (this->currentRip != NULL) {
|
||||||
|
processorBus.removeAll();
|
||||||
|
memoryBus.removeAll();
|
||||||
|
videoBus->removeAll();
|
||||||
|
audioMixer->removeAll();
|
||||||
|
inputConsumerBus.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
currentRip = rip;
|
||||||
|
|
||||||
|
//TODO: use the desired peripheral configuration specified by the rip
|
||||||
|
|
||||||
|
if (this->currentRip != NULL) {
|
||||||
|
InsertPeripheral(this);
|
||||||
|
|
||||||
|
//use the desired peripherals
|
||||||
|
for (INT32 i = 0; i < peripheralCount; i++) {
|
||||||
|
if (usePeripheralIndicators[i])
|
||||||
|
InsertPeripheral(peripherals[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertPeripheral(currentRip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::InsertPeripheral(Peripheral* p)
|
||||||
|
{
|
||||||
|
UINT16 i;
|
||||||
|
|
||||||
|
printf(" Peripheral Inserted: [%s]\n", p->GetName());
|
||||||
|
|
||||||
|
printf(" Processors [%d]\n", p->GetProcessorCount());
|
||||||
|
//processors
|
||||||
|
UINT16 count = p->GetProcessorCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
printf(" [%s]\n", p->GetProcessor(i)->getName());
|
||||||
|
processorBus.addProcessor(p->GetProcessor(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" RAM [%d]\n", p->GetRAMCount());
|
||||||
|
//RAM
|
||||||
|
count = p->GetRAMCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
printf(" @ [%04X] Size [%04X]\n", p->GetRAM(i)->getReadAddress(), p->GetRAM(i)->getReadSize());
|
||||||
|
memoryBus.addMemory(p->GetRAM(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" ROM [%d]\n", p->GetROMCount());
|
||||||
|
//ROM
|
||||||
|
count = p->GetROMCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
ROM* nextRom = p->GetROM(i);
|
||||||
|
printf(" [%s] @ [%04X] Size [%04X]\n", nextRom->getName(), nextRom->getReadAddress(), nextRom->getReadSize());
|
||||||
|
if (!nextRom->isInternal())
|
||||||
|
memoryBus.addMemory(nextRom);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" VIDEO PRODUCERS [%d]\n", p->GetVideoProducerCount());
|
||||||
|
//video producers
|
||||||
|
count = p->GetVideoProducerCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
videoBus->addVideoProducer(p->GetVideoProducer(i));
|
||||||
|
|
||||||
|
printf(" AUDIO PRODUCERS [%d]\n", p->GetAudioProducerCount());
|
||||||
|
//audio producers
|
||||||
|
count = p->GetAudioProducerCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
audioMixer->addAudioProducer(p->GetAudioProducer(i));
|
||||||
|
|
||||||
|
printf(" INPUT CONSUMERS [%d]\n", p->GetInputConsumerCount());
|
||||||
|
//input consumers
|
||||||
|
count = p->GetInputConsumerCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
inputConsumerBus.addInputConsumer(p->GetInputConsumer(i));
|
||||||
|
printf(" [%s]\n", p->GetInputConsumer(i)->getName());
|
||||||
|
}
|
||||||
|
printf(" Peripherals Done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::RemovePeripheral(Peripheral* p)
|
||||||
|
{
|
||||||
|
UINT16 i;
|
||||||
|
|
||||||
|
//processors
|
||||||
|
UINT16 count = p->GetProcessorCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
processorBus.removeProcessor(p->GetProcessor(i));
|
||||||
|
|
||||||
|
//RAM
|
||||||
|
count = p->GetRAMCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
memoryBus.removeMemory(p->GetRAM(i));
|
||||||
|
|
||||||
|
//ROM
|
||||||
|
count = p->GetROMCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
memoryBus.removeMemory(p->GetROM(i));
|
||||||
|
|
||||||
|
//video producers
|
||||||
|
count = p->GetVideoProducerCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
videoBus->removeVideoProducer(p->GetVideoProducer(i));
|
||||||
|
|
||||||
|
//audio producers
|
||||||
|
count = p->GetAudioProducerCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
audioMixer->removeAudioProducer(p->GetAudioProducer(i));
|
||||||
|
|
||||||
|
//input consumers
|
||||||
|
count = p->GetInputConsumerCount();
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
inputConsumerBus.removeInputConsumer(p->GetInputConsumer(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::Run()
|
||||||
|
{
|
||||||
|
inputConsumerBus.evaluateInputs();
|
||||||
|
processorBus.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::Render()
|
||||||
|
{
|
||||||
|
videoBus->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emulator::FlushAudio()
|
||||||
|
{
|
||||||
|
audioMixer->flushAudio();
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 Emulator::systemIDs[NUM_EMULATORS] = {
|
||||||
|
ID_SYSTEM_INTELLIVISION,
|
||||||
|
};
|
||||||
|
|
||||||
|
Intellivision Emulator::inty;
|
||||||
|
|
||||||
|
Emulator* Emulator::emus[] = {
|
||||||
|
&inty,
|
||||||
|
};
|
110
arm9/source/emucore/Emulator.h
Normal file
110
arm9/source/emucore/Emulator.h
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
#ifndef EMULATOR_H
|
||||||
|
#define EMULATOR_H
|
||||||
|
|
||||||
|
#include "Peripheral.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "Rip.h"
|
||||||
|
#include "ProcessorBus.h"
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "AudioMixer.h"
|
||||||
|
#include "AudioProducer.h"
|
||||||
|
#include "InputConsumerBus.h"
|
||||||
|
#include "InputConsumer.h"
|
||||||
|
#include "VideoBus.h"
|
||||||
|
#include "VideoProducer.h"
|
||||||
|
#include "MemoryBus.h"
|
||||||
|
#include "Memory.h"
|
||||||
|
|
||||||
|
typedef struct _StateHeader
|
||||||
|
{
|
||||||
|
UINT32 emu;
|
||||||
|
UINT32 state;
|
||||||
|
UINT32 emuID;
|
||||||
|
UINT32 version;
|
||||||
|
UINT32 sys;
|
||||||
|
UINT32 sysID;
|
||||||
|
UINT32 cart;
|
||||||
|
UINT32 cartID;
|
||||||
|
} StateHeader;
|
||||||
|
|
||||||
|
typedef struct _StateChunk
|
||||||
|
{
|
||||||
|
UINT32 id;
|
||||||
|
UINT32 size;
|
||||||
|
} StateChunk;
|
||||||
|
|
||||||
|
#if defined(DEBUG)
|
||||||
|
#define EMU_STATE_VERSION ('dev\0')
|
||||||
|
#else
|
||||||
|
#define EMU_STATE_VERSION (0x02010000)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class Intellivision;
|
||||||
|
|
||||||
|
#define MAX_PERIPHERALS 16
|
||||||
|
#define NUM_EMULATORS 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class Emulator : public Peripheral
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void AddPeripheral(Peripheral* p);
|
||||||
|
UINT32 GetPeripheralCount();
|
||||||
|
Peripheral* GetPeripheral(UINT32);
|
||||||
|
|
||||||
|
UINT32 GetVideoWidth();
|
||||||
|
UINT32 GetVideoHeight();
|
||||||
|
|
||||||
|
void UsePeripheral(UINT32, BOOL);
|
||||||
|
|
||||||
|
void SetRip(Rip* rip);
|
||||||
|
|
||||||
|
void InitVideo(VideoBus* video, UINT32 width, UINT32 height);
|
||||||
|
void ReleaseVideo();
|
||||||
|
void InitAudio(AudioMixer* audio, UINT32 sampleRate);
|
||||||
|
void ReleaseAudio();
|
||||||
|
|
||||||
|
void Reset();
|
||||||
|
void Run();
|
||||||
|
void FlushAudio();
|
||||||
|
void Render();
|
||||||
|
|
||||||
|
virtual BOOL SaveState(const CHAR* filename) = 0;
|
||||||
|
virtual BOOL LoadState(const CHAR* filename) = 0;
|
||||||
|
|
||||||
|
static UINT32 GetEmulatorCount();
|
||||||
|
static Emulator* GetEmulator(UINT32 i);
|
||||||
|
static Emulator* GetEmulatorByID(UINT32 targetSystemID);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Emulator(const char* name);
|
||||||
|
|
||||||
|
MemoryBus memoryBus;
|
||||||
|
|
||||||
|
Rip* currentRip;
|
||||||
|
|
||||||
|
UINT32 videoWidth;
|
||||||
|
UINT32 videoHeight;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ProcessorBus processorBus;
|
||||||
|
AudioMixer *audioMixer;
|
||||||
|
VideoBus *videoBus;
|
||||||
|
InputConsumerBus inputConsumerBus;
|
||||||
|
|
||||||
|
void InsertPeripheral(Peripheral* p);
|
||||||
|
void RemovePeripheral(Peripheral* p);
|
||||||
|
|
||||||
|
Peripheral* peripherals[MAX_PERIPHERALS];
|
||||||
|
BOOL usePeripheralIndicators[MAX_PERIPHERALS];
|
||||||
|
INT32 peripheralCount;
|
||||||
|
|
||||||
|
static UINT32 systemIDs[NUM_EMULATORS];
|
||||||
|
static Emulator* emus[NUM_EMULATORS];
|
||||||
|
static Intellivision inty;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
79
arm9/source/emucore/GRAM.cpp
Normal file
79
arm9/source/emucore/GRAM.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include "GRAM.h"
|
||||||
|
|
||||||
|
#define GRAM_ADDRESS 0x3800
|
||||||
|
#define GRAM_READ_MASK 0xF9FF
|
||||||
|
#define GRAM_WRITE_MASK 0x39FF
|
||||||
|
|
||||||
|
UINT8 gram_image[GRAM_SIZE] __attribute__((section(".dtcm")));
|
||||||
|
UINT8 dirtyCards[GRAM_SIZE>>3] __attribute__((section(".dtcm")));
|
||||||
|
UINT8 dirtyRAM __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
GRAM::GRAM()
|
||||||
|
: RAM(GRAM_SIZE, GRAM_ADDRESS, GRAM_READ_MASK, GRAM_WRITE_MASK)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void GRAM::reset()
|
||||||
|
{
|
||||||
|
UINT16 i;
|
||||||
|
dirtyRAM = TRUE;
|
||||||
|
for (i = 0; i < GRAM_SIZE; i++)
|
||||||
|
gram_image[i] = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 0x40; i++)
|
||||||
|
dirtyCards[i] = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GRAM::poke(UINT16 location, UINT16 value)
|
||||||
|
{
|
||||||
|
location &= 0x01FF;
|
||||||
|
//value &= 0xFF;
|
||||||
|
|
||||||
|
gram_image[location] = (UINT8)value;
|
||||||
|
dirtyCards[location>>3] = TRUE;
|
||||||
|
dirtyRAM = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GRAM::markClean() {
|
||||||
|
if (!dirtyRAM)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (UINT16 i = 0; i < 0x40; i++)
|
||||||
|
dirtyCards[i] = FALSE;
|
||||||
|
dirtyRAM = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GRAM::isDirty() {
|
||||||
|
return dirtyRAM;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL GRAM::isCardDirty(UINT16 cardLocation) {
|
||||||
|
return dirtyCards[cardLocation>>3];
|
||||||
|
}
|
||||||
|
|
||||||
|
RAMState GRAM::getState(UINT16* image)
|
||||||
|
{
|
||||||
|
RAMState state = {0};
|
||||||
|
#if 0
|
||||||
|
state = RAM::getState(NULL);
|
||||||
|
|
||||||
|
if (image != NULL) {
|
||||||
|
this->getImage(image, 0, this->getImageByteSize());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GRAM::setState(RAMState state, UINT16* image)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
RAM::setState(state, NULL);
|
||||||
|
|
||||||
|
if (image != NULL) {
|
||||||
|
this->setImage(image, 0, this->getImageByteSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(this->dirtyCards, TRUE, sizeof(this->dirtyCards));
|
||||||
|
this->dirtyRAM = TRUE;
|
||||||
|
#endif
|
||||||
|
}
|
44
arm9/source/emucore/GRAM.h
Normal file
44
arm9/source/emucore/GRAM.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
#ifndef GRAM_H
|
||||||
|
#define GRAM_H
|
||||||
|
|
||||||
|
#include "RAM.h"
|
||||||
|
|
||||||
|
#define GRAM_SIZE 0x0200
|
||||||
|
|
||||||
|
extern UINT8 gram_image[GRAM_SIZE];
|
||||||
|
extern UINT8 dirtyCards[GRAM_SIZE>>3];
|
||||||
|
extern UINT8 dirtyRAM;
|
||||||
|
|
||||||
|
class GRAM : public RAM
|
||||||
|
{
|
||||||
|
friend class AY38900;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GRAM();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
inline UINT16 peek(UINT16 location) {return gram_image[location & 0x01FF];}
|
||||||
|
void poke(UINT16 location, UINT16 value);
|
||||||
|
|
||||||
|
void markClean();
|
||||||
|
BOOL isDirty();
|
||||||
|
BOOL isCardDirty(UINT16 cardLocation);
|
||||||
|
|
||||||
|
inline size_t getImageByteSize() {
|
||||||
|
return size * sizeof(UINT16);
|
||||||
|
}
|
||||||
|
void getImage(void* dst, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(dst, gram_image + offset, size);
|
||||||
|
}
|
||||||
|
void setImage(void* src, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(gram_image + offset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
RAMState getState(UINT16* image);
|
||||||
|
void setState(RAMState state, UINT16* image);
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
15
arm9/source/emucore/GROM.cpp
Normal file
15
arm9/source/emucore/GROM.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
|
||||||
|
#include "GROM.h"
|
||||||
|
|
||||||
|
GROM::GROM()
|
||||||
|
: ROM("GROM", "grom.bin", 0, 1, GROM_SIZE, GROM_ADDRESS)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void GROM::reset()
|
||||||
|
{
|
||||||
|
visible = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
27
arm9/source/emucore/GROM.h
Normal file
27
arm9/source/emucore/GROM.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
#ifndef GROM_H
|
||||||
|
#define GROM_H
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
|
||||||
|
#define GROM_SIZE 0x0800
|
||||||
|
#define GROM_ADDRESS 0x3000
|
||||||
|
|
||||||
|
class GROM : public ROM
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class AY38900;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GROM();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
inline UINT16 peek(UINT16 location) {return ROM::peek(location);}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BOOL visible;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
107
arm9/source/emucore/HandController.cpp
Normal file
107
arm9/source/emucore/HandController.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
#include "HandController.h"
|
||||||
|
#include "Intellivision.h"
|
||||||
|
|
||||||
|
const UINT16 HandController::BUTTON_OUTPUT_VALUES[15] = {
|
||||||
|
0x81, //OUTPUT_KEYPAD_ONE
|
||||||
|
0x41, //OUTPUT_KEYPAD_TWO
|
||||||
|
0x21, //OUTPUT_KEYPAD_THREE
|
||||||
|
0x82, //OUTPUT_KEYPAD_FOUR
|
||||||
|
0x42, //OUTPUT_KEYPAD_FIVE
|
||||||
|
0x22, //OUTPUT_KEYPAD_SIX
|
||||||
|
0x84, //OUTPUT_KEYPAD_SEVEN
|
||||||
|
0x44, //OUTPUT_KEYPAD_EIGHT
|
||||||
|
0x24, //OUTPUT_KEYPAD_NINE
|
||||||
|
0x88, //OUTPUT_KEYPAD_CLEAR
|
||||||
|
0x48, //OUTPUT_KEYPAD_ZERO
|
||||||
|
0x28, //OUTPUT_KEYPAD_ENTER
|
||||||
|
0xA0, //OUTPUT_ACTION_BUTTON_TOP
|
||||||
|
0x60, //OUTPUT_ACTION_BUTTON_BOTTOM_LEFT
|
||||||
|
0xC0 //OUTPUT_ACTION_BUTTON_BOTTOM_RIGHT
|
||||||
|
};
|
||||||
|
|
||||||
|
const UINT16 HandController::DIRECTION_OUTPUT_VALUES[16] = {
|
||||||
|
0x04, //OUTPUT_DISC_NORTH
|
||||||
|
0x14, //OUTPUT_DISC_NORTH_NORTH_EAST
|
||||||
|
0x16, //OUTPUT_DISC_NORTH_EAST
|
||||||
|
0x06, //OUTPUT_DISC_EAST_NORTH_EAST
|
||||||
|
0x02, //OUTPUT_DISC_EAST
|
||||||
|
0x12, //OUTPUT_DISC_EAST_SOUTH_EAST
|
||||||
|
0x13, //OUTPUT_DISC_SOUTH_EAST
|
||||||
|
0x03, //OUTPUT_DISC_SOUTH_SOUTH_EAST
|
||||||
|
0x01, //OUTPUT_DISC_SOUTH
|
||||||
|
0x11, //OUTPUT_DISC_SOUTH_SOUTH_WEST
|
||||||
|
0x19, //OUTPUT_DISC_SOUTH_WEST
|
||||||
|
0x09, //OUTPUT_DISC_WEST_SOUTH_WEST
|
||||||
|
0x08, //OUTPUT_DISC_WEST
|
||||||
|
0x18, //OUTPUT_DISC_WEST_NORTH_WEST
|
||||||
|
0x1C, //OUTPUT_DISC_NORTH_WEST
|
||||||
|
0x0C //OUTPUT_DISC_NORTH_NORTH_WEST
|
||||||
|
};
|
||||||
|
|
||||||
|
HandController::HandController(INT32 id, const CHAR* n)
|
||||||
|
: InputConsumer(id),
|
||||||
|
name(n)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
HandController::~HandController()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 HandController::getInputConsumerObjectCount()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConsumerObject* HandController::getInputConsumerObject(INT32 i)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ds_key_input[16] = {0}; // Set to '1' if pressed... 0 if released
|
||||||
|
int ds_disc_input[16] = {0}; // Set to '1' if pressed... 0 if released.
|
||||||
|
|
||||||
|
void HandController::evaluateInputs()
|
||||||
|
{
|
||||||
|
inputValue = 0;
|
||||||
|
bool keypad_active = false;
|
||||||
|
|
||||||
|
// TODO: this is a bit of a hack... setup 2 sets of inputs or don't instantiate the 2nd controller...
|
||||||
|
if (strcmp(name, "Hand Controller #1") == 0)
|
||||||
|
{
|
||||||
|
for (UINT16 i = 0; i < 15; i++)
|
||||||
|
{
|
||||||
|
if (ds_key_input[i])
|
||||||
|
{
|
||||||
|
if (i <= 11) keypad_active=true;
|
||||||
|
inputValue |= BUTTON_OUTPUT_VALUES[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keypad has priority over disc...
|
||||||
|
if (!keypad_active)
|
||||||
|
{
|
||||||
|
for (UINT16 i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
if (ds_disc_input[i]) inputValue |= DIRECTION_OUTPUT_VALUES[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputValue = (UINT16)(0xFF ^ inputValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandController::resetInputConsumer()
|
||||||
|
{
|
||||||
|
inputValue = 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandController::setOutputValue(UINT16)
|
||||||
|
{}
|
||||||
|
|
||||||
|
UINT16 HandController::getInputValue()
|
||||||
|
{
|
||||||
|
return inputValue;
|
||||||
|
}
|
||||||
|
|
77
arm9/source/emucore/HandController.h
Normal file
77
arm9/source/emucore/HandController.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
|
||||||
|
#ifndef HANDCONTROLLER_H
|
||||||
|
#define HANDCONTROLLER_H
|
||||||
|
|
||||||
|
#define NUM_HAND_CONTROLLER_OBJECTS 23
|
||||||
|
|
||||||
|
#include "AY38914_InputOutput.h"
|
||||||
|
#include "InputConsumer.h"
|
||||||
|
|
||||||
|
class HandController : public AY38914_InputOutput, public InputConsumer
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
HandController(INT32 id, const CHAR* n);
|
||||||
|
virtual ~HandController();
|
||||||
|
|
||||||
|
const CHAR* getName() { return name; }
|
||||||
|
|
||||||
|
void resetInputConsumer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poll the controller. This function is invoked by the
|
||||||
|
* InputConsumerBus just after the Emulator indicates it has entered
|
||||||
|
* vertical blank.
|
||||||
|
*/
|
||||||
|
void evaluateInputs();
|
||||||
|
|
||||||
|
//functions to get descriptive info about the input consumer
|
||||||
|
INT32 getInputConsumerObjectCount();
|
||||||
|
InputConsumerObject* getInputConsumerObject(INT32 i);
|
||||||
|
|
||||||
|
void setOutputValue(UINT16 value);
|
||||||
|
UINT16 getInputValue();
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CHAR* name;
|
||||||
|
|
||||||
|
InputConsumerObject* inputConsumerObjects[NUM_HAND_CONTROLLER_OBJECTS];
|
||||||
|
UINT16 inputValue;
|
||||||
|
|
||||||
|
static const UINT16 BUTTON_OUTPUT_VALUES[15];
|
||||||
|
static const UINT16 DIRECTION_OUTPUT_VALUES[16];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// jeremiah sypult
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CONTROLLER_DISC_DOWN = 0x01,
|
||||||
|
CONTROLLER_DISC_RIGHT = 0x02,
|
||||||
|
CONTROLLER_DISC_UP = 0x04,
|
||||||
|
CONTROLLER_DISC_LEFT = 0x08,
|
||||||
|
CONTROLLER_DISC_WIDE = 0x10,
|
||||||
|
CONTROLLER_DISC_UP_LEFT = 0x1C,
|
||||||
|
CONTROLLER_DISC_UP_RIGHT = 0x16,
|
||||||
|
CONTROLLER_DISC_DOWN_LEFT = 0x19,
|
||||||
|
CONTROLLER_DISC_DOWN_RIGHT = 0x13,
|
||||||
|
|
||||||
|
CONTROLLER_KEYPAD_ONE = 0x81,
|
||||||
|
CONTROLLER_KEYPAD_TWO = 0x41,
|
||||||
|
CONTROLLER_KEYPAD_THREE = 0x21,
|
||||||
|
CONTROLLER_KEYPAD_FOUR = 0x82,
|
||||||
|
CONTROLLER_KEYPAD_FIVE = 0x42,
|
||||||
|
CONTROLLER_KEYPAD_SIX = 0x22,
|
||||||
|
CONTROLLER_KEYPAD_SEVEN = 0x84,
|
||||||
|
CONTROLLER_KEYPAD_EIGHT = 0x44,
|
||||||
|
CONTROLLER_KEYPAD_NINE = 0x24,
|
||||||
|
CONTROLLER_KEYPAD_CLEAR = 0x88,
|
||||||
|
CONTROLLER_KEYPAD_ZERO = 0x48,
|
||||||
|
CONTROLLER_KEYPAD_ENTER = 0x28,
|
||||||
|
|
||||||
|
CONTROLLER_ACTION_TOP = 0xA0,
|
||||||
|
CONTROLLER_ACTION_BOTTOM_LEFT = 0x60,
|
||||||
|
CONTROLLER_ACTION_BOTTOM_RIGHT = 0xC0
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
42
arm9/source/emucore/InputConsumer.h
Normal file
42
arm9/source/emucore/InputConsumer.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
|
||||||
|
#ifndef INPUTCONSUMER_H
|
||||||
|
#define INPUTCONSUMER_H
|
||||||
|
|
||||||
|
#include "InputConsumerObject.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A InputConsumer is a gaming input device, such as the hand controllers for
|
||||||
|
* the Intellivision and Atari 5200 or the joysticks and paddles for the
|
||||||
|
* Atari2600.
|
||||||
|
*/
|
||||||
|
class InputConsumer
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class InputConsumerBus;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InputConsumer(INT32 i) : id(i) {}
|
||||||
|
|
||||||
|
INT32 getId() { return id; }
|
||||||
|
|
||||||
|
virtual const CHAR* getName() = 0;
|
||||||
|
|
||||||
|
virtual void resetInputConsumer() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Poll the controller. This function is invoked by the
|
||||||
|
* InputConsumerBus just after the Emulator indicates it has entered
|
||||||
|
* vertical blank.
|
||||||
|
*/
|
||||||
|
virtual void evaluateInputs() = 0;
|
||||||
|
|
||||||
|
//functions to get descriptive info about the input consumer
|
||||||
|
virtual INT32 getInputConsumerObjectCount() = 0;
|
||||||
|
virtual InputConsumerObject* getInputConsumerObject(INT32 i) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
INT32 id;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
46
arm9/source/emucore/InputConsumerBus.cpp
Normal file
46
arm9/source/emucore/InputConsumerBus.cpp
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "InputConsumerBus.h"
|
||||||
|
|
||||||
|
InputConsumerBus::InputConsumerBus()
|
||||||
|
{
|
||||||
|
inputConsumerCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConsumerBus::addInputConsumer(InputConsumer* p)
|
||||||
|
{
|
||||||
|
inputConsumers[inputConsumerCount] = p;
|
||||||
|
inputConsumerCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConsumerBus::removeInputConsumer(InputConsumer* p)
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < inputConsumerCount; i++) {
|
||||||
|
if (inputConsumers[i] == p) {
|
||||||
|
for (UINT32 j = i; j < (inputConsumerCount-1); j++)
|
||||||
|
inputConsumers[j] = inputConsumers[j+1];
|
||||||
|
inputConsumerCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConsumerBus::removeAll()
|
||||||
|
{
|
||||||
|
while (inputConsumerCount)
|
||||||
|
removeInputConsumer(inputConsumers[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConsumerBus::reset()
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < inputConsumerCount; i++)
|
||||||
|
inputConsumers[i]->resetInputConsumer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConsumerBus::evaluateInputs()
|
||||||
|
{
|
||||||
|
//tell each of the input consumers that they may now pull their data from
|
||||||
|
//the input device
|
||||||
|
for (UINT32 i = 0; i < inputConsumerCount; i++)
|
||||||
|
inputConsumers[i]->evaluateInputs();
|
||||||
|
}
|
27
arm9/source/emucore/InputConsumerBus.h
Normal file
27
arm9/source/emucore/InputConsumerBus.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
#ifndef INPUTCONSUMERBUS_H
|
||||||
|
#define INPUTCONSUMERBUS_H
|
||||||
|
|
||||||
|
#include "InputConsumer.h"
|
||||||
|
|
||||||
|
const INT32 MAX_INPUT_CONSUMERS = 10;
|
||||||
|
|
||||||
|
class InputConsumerBus
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
InputConsumerBus();
|
||||||
|
void reset();
|
||||||
|
void evaluateInputs();
|
||||||
|
|
||||||
|
void addInputConsumer(InputConsumer* ic);
|
||||||
|
void removeInputConsumer(InputConsumer* ic);
|
||||||
|
void removeAll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
InputConsumer* inputConsumers[MAX_INPUT_CONSUMERS];
|
||||||
|
UINT32 inputConsumerCount;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
65
arm9/source/emucore/InputConsumerObject.cpp
Normal file
65
arm9/source/emucore/InputConsumerObject.cpp
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
// TODO: jeremiah sypult cross-platform
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
#include <dinput.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "InputConsumerObject.h"
|
||||||
|
|
||||||
|
InputConsumerObject::InputConsumerObject(INT32 i, const CHAR* n, GUID ddg, INT32 doid)
|
||||||
|
: id(i),
|
||||||
|
name(n),
|
||||||
|
defaultDeviceGuid(ddg),
|
||||||
|
defaultObjectID(doid),
|
||||||
|
bindingCount(0)
|
||||||
|
{
|
||||||
|
memset(producerBindings, 0, sizeof(producerBindings));
|
||||||
|
memset(objectIDBindings, 0, sizeof(objectIDBindings));
|
||||||
|
memset(subBindingCounts, 0, sizeof(subBindingCounts));
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConsumerObject::~InputConsumerObject()
|
||||||
|
{
|
||||||
|
clearBindings();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConsumerObject::addBinding(InputProducer** producers, INT32* objectids, INT32 count)
|
||||||
|
{
|
||||||
|
if (bindingCount >= MAX_BINDINGS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
producerBindings[bindingCount] = new InputProducer*[count];
|
||||||
|
memcpy(producerBindings[bindingCount], producers, sizeof(InputProducer*)*count);
|
||||||
|
objectIDBindings[bindingCount] = new INT32[count];
|
||||||
|
memcpy(objectIDBindings[bindingCount], objectids, sizeof(INT32)*count);
|
||||||
|
subBindingCounts[bindingCount] = count;
|
||||||
|
bindingCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputConsumerObject::clearBindings()
|
||||||
|
{
|
||||||
|
for (INT32 i = 0; i < bindingCount; i++) {
|
||||||
|
delete[] producerBindings[i];
|
||||||
|
delete[] objectIDBindings[i];
|
||||||
|
}
|
||||||
|
memset(producerBindings, 0, sizeof(producerBindings));
|
||||||
|
memset(objectIDBindings, 0, sizeof(objectIDBindings));
|
||||||
|
memset(subBindingCounts, 0, sizeof(subBindingCounts));
|
||||||
|
bindingCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float InputConsumerObject::getInputValue()
|
||||||
|
{
|
||||||
|
float value = 0.0f;
|
||||||
|
for (INT32 i = 0; i < bindingCount; i++) {
|
||||||
|
float nextValue = 1.0f;
|
||||||
|
for (INT32 j = 0; j < subBindingCounts[i]; j++) {
|
||||||
|
float v = producerBindings[i][j]->getValue(objectIDBindings[i][j]);
|
||||||
|
nextValue = (nextValue < v ? nextValue : v);
|
||||||
|
}
|
||||||
|
value = (value != 0 && value > nextValue ? value : nextValue);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
53
arm9/source/emucore/InputConsumerObject.h
Normal file
53
arm9/source/emucore/InputConsumerObject.h
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
|
||||||
|
#ifndef INPUTCONSUMEROBJECT_H
|
||||||
|
#define INPUTCONSUMEROBJECT_H
|
||||||
|
|
||||||
|
#include "InputProducer.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#define MAX_BINDINGS 10
|
||||||
|
|
||||||
|
class InputConsumerObject
|
||||||
|
{
|
||||||
|
friend class InputConsumer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
InputConsumerObject(INT32 id, const CHAR* name, GUID defaultDeviceGuid, INT32 defaultObjectID);
|
||||||
|
virtual ~InputConsumerObject();
|
||||||
|
|
||||||
|
INT32 getId() { return id; }
|
||||||
|
|
||||||
|
const CHAR* getName() { return name; }
|
||||||
|
|
||||||
|
GUID getDefaultDeviceGuid() { return defaultDeviceGuid; }
|
||||||
|
|
||||||
|
INT32 getDefaultEnum() { return defaultObjectID; }
|
||||||
|
|
||||||
|
INT32 getBindingCount() { return bindingCount; }
|
||||||
|
|
||||||
|
INT32 getSubBindingCount(INT32 i) { return subBindingCounts[i]; }
|
||||||
|
|
||||||
|
InputProducer* getSubBindingProducer(INT32 i, INT32 j) { return producerBindings[i][j]; }
|
||||||
|
|
||||||
|
INT32 getSubBindingEnum(INT32 i, INT32 j) { return objectIDBindings[i][j]; }
|
||||||
|
|
||||||
|
void addBinding(InputProducer** producer, INT32* objectid, INT32 count);
|
||||||
|
|
||||||
|
void clearBindings();
|
||||||
|
|
||||||
|
float getInputValue();
|
||||||
|
|
||||||
|
private:
|
||||||
|
INT32 id;
|
||||||
|
const CHAR* name;
|
||||||
|
GUID defaultDeviceGuid;
|
||||||
|
INT32 defaultObjectID;
|
||||||
|
|
||||||
|
InputProducer** producerBindings[MAX_BINDINGS];
|
||||||
|
INT32* objectIDBindings[MAX_BINDINGS];
|
||||||
|
INT32 subBindingCounts[MAX_BINDINGS];
|
||||||
|
INT32 bindingCount;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
38
arm9/source/emucore/InputProducer.h
Normal file
38
arm9/source/emucore/InputProducer.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
|
||||||
|
#ifndef INPUTPRODUCER_H
|
||||||
|
#define INPUTPRODUCER_H
|
||||||
|
|
||||||
|
// TODO: jeremiah sypult cross-platform
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
#include <dinput.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class InputProducer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
InputProducer(GUID g) : guid(g) {}
|
||||||
|
|
||||||
|
GUID getGuid() { return guid; }
|
||||||
|
|
||||||
|
virtual const CHAR* getName() = 0;
|
||||||
|
// TODO: jeremiah sypult cross-platform
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
virtual IDirectInputDevice8* getDevice() = 0;
|
||||||
|
#endif
|
||||||
|
virtual void poll() = 0;
|
||||||
|
|
||||||
|
virtual INT32 getInputCount() = 0;
|
||||||
|
|
||||||
|
virtual const CHAR* getInputName(INT32) = 0;
|
||||||
|
|
||||||
|
virtual float getValue(INT32 enumeration) = 0;
|
||||||
|
|
||||||
|
virtual BOOL isKeyboardDevice() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
GUID guid;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
60
arm9/source/emucore/InputProducerManager.cpp
Normal file
60
arm9/source/emucore/InputProducerManager.cpp
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "InputProducerManager.h"
|
||||||
|
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
InputProducerManager::InputProducerManager(HWND w)
|
||||||
|
: wnd(w)
|
||||||
|
{
|
||||||
|
DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&directInput, NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InputProducerManager::~InputProducerManager()
|
||||||
|
{
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
directInput->Release();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
IDirectInput8* InputProducerManager::getDevice()
|
||||||
|
{
|
||||||
|
return directInput;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
InputProducer* InputProducerManager::acquireInputProducer(GUID deviceGuid)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 InputProducerManager::getAcquiredInputProducerCount()
|
||||||
|
{
|
||||||
|
return (INT32)devices.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
InputProducer* InputProducerManager::getAcquiredInputProducer(INT32 i)
|
||||||
|
{
|
||||||
|
return devices[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputProducerManager::pollInputProducers()
|
||||||
|
{
|
||||||
|
for (vector<InputProducer*>::iterator it = devices.begin(); it < devices.end(); it++)
|
||||||
|
(*it)->poll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputProducerManager::releaseInputProducers()
|
||||||
|
{
|
||||||
|
for (vector<InputProducer*>::iterator it = devices.begin(); it < devices.end(); it++) {
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
IDirectInputDevice8* nextDevice = (*it)->getDevice();
|
||||||
|
nextDevice->Unacquire();
|
||||||
|
nextDevice->Release();
|
||||||
|
delete (*it);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
devices.clear();
|
||||||
|
}
|
||||||
|
|
43
arm9/source/emucore/InputProducerManager.h
Normal file
43
arm9/source/emucore/InputProducerManager.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
|
||||||
|
#ifndef INPUTPRODUCERMANAGER_H
|
||||||
|
#define INPUTPRODUCERMANAGER_H
|
||||||
|
|
||||||
|
// TODO: jeremiah sypult cross-platform
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
#include <windows.h>
|
||||||
|
#include <dinput.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "InputProducer.h"
|
||||||
|
#include <vector>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
class InputProducerManager
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
InputProducerManager(HWND wnd);
|
||||||
|
#endif
|
||||||
|
virtual ~InputProducerManager();
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
IDirectInput8* getDevice();
|
||||||
|
#endif
|
||||||
|
InputProducer* acquireInputProducer(GUID deviceGuid);
|
||||||
|
INT32 getAcquiredInputProducerCount();
|
||||||
|
InputProducer* getAcquiredInputProducer(INT32 i);
|
||||||
|
|
||||||
|
void pollInputProducers();
|
||||||
|
|
||||||
|
void releaseInputProducers();
|
||||||
|
|
||||||
|
private:
|
||||||
|
#if defined( _WIN32 )
|
||||||
|
HWND wnd;
|
||||||
|
IDirectInput8* directInput;
|
||||||
|
#endif
|
||||||
|
vector<InputProducer*> devices;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
336
arm9/source/emucore/Intellivision.cpp
Normal file
336
arm9/source/emucore/Intellivision.cpp
Normal file
@ -0,0 +1,336 @@
|
|||||||
|
|
||||||
|
#include "Intellivision.h"
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _IntellivisionState
|
||||||
|
{
|
||||||
|
StateHeader header;
|
||||||
|
StateChunk cpu;
|
||||||
|
CP1610State cpuState;
|
||||||
|
StateChunk stic;
|
||||||
|
AY38900State sticState;
|
||||||
|
StateChunk psg;
|
||||||
|
AY38914State psgState;
|
||||||
|
StateChunk RAM8bit;
|
||||||
|
RAMState RAM8bitState;
|
||||||
|
UINT16 RAM8bitImage[RAM8BIT_SIZE];
|
||||||
|
StateChunk RAM16bit;
|
||||||
|
RAMState RAM16bitState;
|
||||||
|
UINT16 RAM16bitImage[RAM16BIT_SIZE];
|
||||||
|
StateChunk GRAM;
|
||||||
|
RAMState GRAMState;
|
||||||
|
UINT16 GRAMImage[GRAM_SIZE];
|
||||||
|
StateChunk ivoice;
|
||||||
|
IntellivoiceState ivoiceState;
|
||||||
|
StateChunk ecs;
|
||||||
|
ECSState ecsState;
|
||||||
|
StateChunk eof;
|
||||||
|
} IntellivisionState; )
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes all of the basic hardware included in the Intellivision
|
||||||
|
* Master Component as well as the ECS and Intellivoice peripherals.
|
||||||
|
* This method is called only once when the Intellivision is constructed.
|
||||||
|
*/
|
||||||
|
Intellivision::Intellivision()
|
||||||
|
: Emulator("Intellivision"),
|
||||||
|
player1Controller(0, "Hand Controller #1"),
|
||||||
|
player2Controller(1, "Hand Controller #2"),
|
||||||
|
psg(0x01F0, &player1Controller, &player2Controller),
|
||||||
|
RAM8bit(RAM8BIT_SIZE, 0x0100, 8),
|
||||||
|
RAM16bit(RAM16BIT_SIZE, 0x0200, 16),
|
||||||
|
execROM("Executive ROM", "exec.bin", 0, 2, 0x1000, 0x1000),
|
||||||
|
grom("GROM", "grom.bin", 0, 1, 0x0800, 0x3000),
|
||||||
|
gram(),
|
||||||
|
cpu(&memoryBus, 0x1000, 0x1004),
|
||||||
|
stic(&memoryBus, &grom, &gram)
|
||||||
|
{
|
||||||
|
// define the video pixel dimensions
|
||||||
|
videoWidth = 160;
|
||||||
|
videoHeight = 192;
|
||||||
|
|
||||||
|
//make the pin connections from the CPU to the STIC
|
||||||
|
stic.connectPinOut(AY38900_PIN_OUT_SR1, &cpu, CP1610_PIN_IN_INTRM);
|
||||||
|
stic.connectPinOut(AY38900_PIN_OUT_SR2, &cpu, CP1610_PIN_IN_BUSRQ);
|
||||||
|
cpu.connectPinOut(CP1610_PIN_OUT_BUSAK, &stic, AY38900_PIN_IN_SST);
|
||||||
|
|
||||||
|
//add the player one hand controller
|
||||||
|
AddInputConsumer(&player1Controller);
|
||||||
|
|
||||||
|
//add the player two hand controller
|
||||||
|
AddInputConsumer(&player2Controller);
|
||||||
|
|
||||||
|
//add the 8-bit RAM
|
||||||
|
AddRAM(&RAM8bit);
|
||||||
|
|
||||||
|
//add the 16-bit RAM
|
||||||
|
AddRAM(&RAM16bit);
|
||||||
|
|
||||||
|
//add the executive ROM
|
||||||
|
AddROM(&execROM);
|
||||||
|
|
||||||
|
//add the GROM
|
||||||
|
AddROM(&grom);
|
||||||
|
|
||||||
|
//add the GRAM
|
||||||
|
AddRAM(&gram);
|
||||||
|
|
||||||
|
//add the backtab ram
|
||||||
|
AddRAM(&stic.backtab);
|
||||||
|
|
||||||
|
//add the CPU
|
||||||
|
AddProcessor(&cpu);
|
||||||
|
|
||||||
|
//add the STIC
|
||||||
|
AddProcessor(&stic);
|
||||||
|
AddVideoProducer(&stic);
|
||||||
|
|
||||||
|
//add the STIC registers
|
||||||
|
AddRAM(&stic.registers);
|
||||||
|
|
||||||
|
//add the PSG
|
||||||
|
AddProcessor(&psg);
|
||||||
|
AddAudioProducer(&psg);
|
||||||
|
|
||||||
|
//add the PSG registers
|
||||||
|
AddRAM(&psg.registers);
|
||||||
|
|
||||||
|
AddPeripheral(&ecs);
|
||||||
|
AddPeripheral(&intellivoice);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL Intellivision::SaveState(const CHAR* filename)
|
||||||
|
{
|
||||||
|
BOOL didSave = FALSE;
|
||||||
|
IntellivisionState state = {9};
|
||||||
|
size_t totalStateSize = sizeof(IntellivisionState);
|
||||||
|
|
||||||
|
size_t hsize = sizeof(StateHeader);
|
||||||
|
size_t csize = sizeof(StateChunk);
|
||||||
|
size_t cpusize = sizeof(CP1610State);
|
||||||
|
size_t sticsize = sizeof(AY38900State);
|
||||||
|
size_t psgsize = sizeof(AY38914State);
|
||||||
|
size_t ivoicesize = sizeof(IntellivoiceState);
|
||||||
|
size_t ecssize = sizeof(ECSState);
|
||||||
|
size_t ramsize = sizeof(RAMState);
|
||||||
|
size_t ram8imgsize = sizeof(state.RAM8bitImage);
|
||||||
|
size_t ram16imgsize = sizeof(state.RAM16bitImage);
|
||||||
|
size_t gramimgsize = sizeof(state.GRAMImage);
|
||||||
|
|
||||||
|
state.header.emu = FOURCHAR('EMUS');
|
||||||
|
state.header.state = FOURCHAR('TATE');
|
||||||
|
state.header.emuID = ID_EMULATOR_BLISS;
|
||||||
|
state.header.version = FOURCHAR(EMU_STATE_VERSION);
|
||||||
|
state.header.sys = FOURCHAR('SYS\0');
|
||||||
|
state.header.sysID = ID_SYSTEM_INTELLIVISION;
|
||||||
|
state.header.cart = FOURCHAR('CART');
|
||||||
|
state.header.cartID = currentRip->GetCRC();
|
||||||
|
|
||||||
|
state.cpu.id = FOURCHAR('CPU\0');
|
||||||
|
state.cpu.size = sizeof(CP1610State);
|
||||||
|
state.cpuState = cpu.getState();
|
||||||
|
|
||||||
|
state.stic.id = FOURCHAR('STIC');
|
||||||
|
state.stic.size = sizeof(AY38900State);
|
||||||
|
state.sticState = stic.getState();
|
||||||
|
|
||||||
|
state.psg.id = FOURCHAR('PSG\0');
|
||||||
|
state.psg.size = sizeof(AY38914State);
|
||||||
|
state.psgState = psg.getState();
|
||||||
|
|
||||||
|
state.RAM8bit.id = FOURCHAR('RAM0');
|
||||||
|
state.RAM8bit.size = sizeof(RAMState) + sizeof(state.RAM8bitImage);
|
||||||
|
state.RAM8bitState = RAM8bit.getState(state.RAM8bitImage);
|
||||||
|
|
||||||
|
state.RAM16bit.id = FOURCHAR('RAM1');
|
||||||
|
state.RAM16bit.size = sizeof(RAMState) + sizeof(state.RAM16bitImage);
|
||||||
|
state.RAM16bitState = RAM16bit.getState(state.RAM16bitImage);
|
||||||
|
|
||||||
|
state.GRAM.id = FOURCHAR('GRAM');
|
||||||
|
state.GRAM.size = sizeof(RAMState) + sizeof(state.GRAMImage);
|
||||||
|
state.GRAMState = gram.getState(state.GRAMImage);
|
||||||
|
|
||||||
|
// TODO: only if ivoice is used for this cart?
|
||||||
|
state.ivoice.id = FOURCHAR('VOIC');
|
||||||
|
state.ivoice.size = sizeof(IntellivoiceState);
|
||||||
|
state.ivoiceState = intellivoice.getState();
|
||||||
|
|
||||||
|
// TODO: only if ecs is used for this cart?
|
||||||
|
state.ecs.id = FOURCHAR('ECS\0');
|
||||||
|
state.ecs.size = sizeof(ECSState);
|
||||||
|
state.ecsState = ecs.getState();
|
||||||
|
|
||||||
|
state.eof.id = FOURCHAR('EOF\0');
|
||||||
|
state.eof.size = sizeof(IntellivisionState);
|
||||||
|
|
||||||
|
FILE* file = fopen(filename, "wb");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
printf("Error: Unable to create file %s\n", filename);
|
||||||
|
didSave = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file != NULL && totalStateSize == fwrite(&state, 1, totalStateSize, file)) {
|
||||||
|
didSave = TRUE;
|
||||||
|
} else {
|
||||||
|
printf("Error: could not write %zu bytes to file %s\n", totalStateSize, filename);
|
||||||
|
didSave = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
fclose(file);
|
||||||
|
file = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return didSave;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL Intellivision::LoadState(const CHAR* filename)
|
||||||
|
{
|
||||||
|
BOOL didLoadState = FALSE;
|
||||||
|
IntellivisionState state = {9};
|
||||||
|
size_t totalStateSize = sizeof(IntellivisionState);
|
||||||
|
|
||||||
|
FILE* file = fopen(filename, "rb");
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
printf("Error: Unable to open file %s\n", filename);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
// read in the whole file
|
||||||
|
if (totalStateSize != fread(&state, 1, totalStateSize, file)) {
|
||||||
|
printf("Error: could not read state (%zu bytes) from file %s\n", totalStateSize, filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
BOOL isParsing = FALSE;
|
||||||
|
StateChunk chunk = {0};
|
||||||
|
|
||||||
|
// read in the header
|
||||||
|
if (sizeof(StateHeader) != fread(&state, 1, sizeof(StateHeader), file)) {
|
||||||
|
printf("Error: could not read state header (%zu bytes) from file %s\n", totalStateSize, filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate file header
|
||||||
|
if (state.header.emu != FOURCHAR('EMUS') || state.header.state != FOURCHAR('TATE')) {
|
||||||
|
printf("Error: invalid header in file %s\n", filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.header.emuID != ID_EMULATOR_BLISS) {
|
||||||
|
printf("Error: invalid emulator ID %x in file %s\n", state.header.emuID, filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FOURCHAR(EMU_STATE_VERSION) != FOURCHAR('dev\0') && state.header.version != FOURCHAR('dev\0') && state.header.version != FOURCHAR(EMU_STATE_VERSION)) {
|
||||||
|
printf("Error: invalid emulator version 0x%08x (expected 0x%08x) in file %s\n", state.header.version, EMU_STATE_VERSION, filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.header.sys != FOURCHAR('SYS\0')) {
|
||||||
|
printf("Error: expected 'SYS ' chunk in file %s\n", filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.header.sysID != ID_SYSTEM_INTELLIVISION) {
|
||||||
|
printf("Error: invalid system ID %x in file %s\n", state.header.sysID, filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.header.cart != FOURCHAR('CART')) {
|
||||||
|
printf("Error: expected 'CART' chunk in file %s\n", filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.header.cartID != 0x00000000 && state.header.cartID != currentRip->GetCRC()) {
|
||||||
|
printf("Error: cartridge mismatch in file %s\n", filename);
|
||||||
|
goto close;
|
||||||
|
}
|
||||||
|
|
||||||
|
isParsing = TRUE;
|
||||||
|
while (isParsing) {
|
||||||
|
size_t fpos = ftell(file);
|
||||||
|
if (sizeof(StateChunk) != fread(&chunk, 1, sizeof(StateChunk), file)) {
|
||||||
|
isParsing = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (chunk.id) {
|
||||||
|
default:
|
||||||
|
fpos = ftell(file);
|
||||||
|
break;
|
||||||
|
case FOURCHAR('CPU\0'):
|
||||||
|
if (chunk.size == sizeof(state.cpuState)) {
|
||||||
|
state.cpu = chunk;
|
||||||
|
fread(&state.cpuState, 1, state.cpu.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('STIC'):
|
||||||
|
if (chunk.size == sizeof(state.sticState)) {
|
||||||
|
state.stic = chunk;
|
||||||
|
fread(&state.sticState, 1, state.stic.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('PSG\0'):
|
||||||
|
if (chunk.size == sizeof(state.psgState)) {
|
||||||
|
state.psg = chunk;
|
||||||
|
fread(&state.psgState, 1, state.psg.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('RAM0'):
|
||||||
|
if (chunk.size == sizeof(state.RAM8bitState) + sizeof(state.RAM8bitImage)) {
|
||||||
|
state.RAM8bit = chunk;
|
||||||
|
fread(&state.RAM8bitState, 1, state.RAM8bit.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('RAM1'):
|
||||||
|
if (chunk.size == sizeof(state.RAM16bitState) + sizeof(state.RAM16bitImage)) {
|
||||||
|
state.RAM16bit = chunk;
|
||||||
|
fread(&state.RAM16bitState, 1, state.RAM16bit.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('GRAM'):
|
||||||
|
if (chunk.size == sizeof(state.GRAMState) + sizeof(state.GRAMImage)) {
|
||||||
|
state.GRAM = chunk;
|
||||||
|
fread(&state.GRAMState, 1, state.GRAM.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('VOIC'):
|
||||||
|
// TODO: only if ivoice/ecs is used for this cart?
|
||||||
|
if (chunk.size == sizeof(state.ivoiceState)) {
|
||||||
|
state.ivoice = chunk;
|
||||||
|
fread(&state.ivoiceState, 1, state.ivoice.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('ECS\0'):
|
||||||
|
// TODO: only if ivoice/ecs is used for this cart?
|
||||||
|
if (chunk.size == sizeof(state.ecsState)) {
|
||||||
|
state.ecs = chunk;
|
||||||
|
fread(&state.ecsState, 1, state.ecs.size, file);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FOURCHAR('EOF\0'):
|
||||||
|
state.eof = chunk;
|
||||||
|
isParsing = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
didLoadState = TRUE;
|
||||||
|
|
||||||
|
cpu.setState(state.cpuState);
|
||||||
|
stic.setState(state.sticState);
|
||||||
|
psg.setState(state.psgState);
|
||||||
|
RAM8bit.setState(state.RAM8bitState, state.RAM8bitImage);
|
||||||
|
RAM16bit.setState(state.RAM16bitState, state.RAM16bitImage);
|
||||||
|
gram.setState(state.GRAMState, state.GRAMImage);
|
||||||
|
intellivoice.setState(state.ivoiceState);
|
||||||
|
ecs.setState(state.ecsState);
|
||||||
|
|
||||||
|
close:
|
||||||
|
fclose(file);
|
||||||
|
file = NULL;
|
||||||
|
end:
|
||||||
|
return didLoadState;
|
||||||
|
}
|
52
arm9/source/emucore/Intellivision.h
Normal file
52
arm9/source/emucore/Intellivision.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
#ifndef INTELLIVISION_H
|
||||||
|
#define INTELLIVISION_H
|
||||||
|
|
||||||
|
#include "Emulator.h"
|
||||||
|
#include "HandController.h"
|
||||||
|
#include "ECS.h"
|
||||||
|
#include "Intellivoice.h"
|
||||||
|
#include "Emulator.h"
|
||||||
|
#include "MemoryBus.h"
|
||||||
|
#include "RAM.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
#include "CP1610.h"
|
||||||
|
#include "AY38900.h"
|
||||||
|
#include "AY38914.h"
|
||||||
|
|
||||||
|
#define RAM8BIT_SIZE 0x00F0
|
||||||
|
#define RAM16BIT_SIZE 0x0160
|
||||||
|
|
||||||
|
class Intellivision : public Emulator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Intellivision();
|
||||||
|
|
||||||
|
BOOL SaveState(const CHAR* filename);
|
||||||
|
BOOL LoadState(const CHAR* filename);
|
||||||
|
|
||||||
|
private:
|
||||||
|
//core processors
|
||||||
|
CP1610 cpu;
|
||||||
|
AY38900 stic;
|
||||||
|
AY38914 psg;
|
||||||
|
|
||||||
|
//core memories
|
||||||
|
RAM RAM8bit;
|
||||||
|
RAM RAM16bit;
|
||||||
|
ROM execROM;
|
||||||
|
ROM grom;
|
||||||
|
GRAM gram;
|
||||||
|
|
||||||
|
//hand controllers
|
||||||
|
HandController player1Controller;
|
||||||
|
HandController player2Controller;
|
||||||
|
|
||||||
|
//the ECS peripheral
|
||||||
|
ECS ecs;
|
||||||
|
|
||||||
|
//the Intellivoice peripheral
|
||||||
|
Intellivoice intellivoice;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
16
arm9/source/emucore/Intellivoice.cpp
Normal file
16
arm9/source/emucore/Intellivoice.cpp
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
|
||||||
|
#include "Intellivoice.h"
|
||||||
|
|
||||||
|
IntellivoiceState Intellivoice::getState()
|
||||||
|
{
|
||||||
|
IntellivoiceState state = {0};
|
||||||
|
|
||||||
|
state.sp0256State = sp0256.getState();
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Intellivoice::setState(IntellivoiceState state)
|
||||||
|
{
|
||||||
|
sp0256.setState(state.sp0256State);
|
||||||
|
}
|
40
arm9/source/emucore/Intellivoice.h
Normal file
40
arm9/source/emucore/Intellivoice.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
#ifndef INTELLIVOICE_H
|
||||||
|
#define INTELLIVOICE_H
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "Peripheral.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "SP0256.h"
|
||||||
|
#include "AudioOutputLine.h"
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _IntellivoiceState
|
||||||
|
{
|
||||||
|
SP0256State sp0256State;
|
||||||
|
} IntellivoiceState; )
|
||||||
|
|
||||||
|
class Intellivoice : public Peripheral
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Intellivoice()
|
||||||
|
: Peripheral("Intellivoice", "Intellivoice")
|
||||||
|
{
|
||||||
|
AddProcessor(&sp0256);
|
||||||
|
AddAudioProducer(&sp0256);
|
||||||
|
AddRAM(&sp0256.registers);
|
||||||
|
AddROM(&sp0256.ivoiceROM);
|
||||||
|
}
|
||||||
|
UINT32 getProcessorCount();
|
||||||
|
void getProcessor(INT32 i, Processor** p);
|
||||||
|
UINT32 getMemoryCount();
|
||||||
|
void getMemory(INT32 i, Memory** m);
|
||||||
|
|
||||||
|
IntellivoiceState getState();
|
||||||
|
void setState(IntellivoiceState state);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SP0256 sp0256;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
204
arm9/source/emucore/MOB.cpp
Normal file
204
arm9/source/emucore/MOB.cpp
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
|
||||||
|
#include "MOB.h"
|
||||||
|
|
||||||
|
void MOB::reset() {
|
||||||
|
xLocation = 0;
|
||||||
|
yLocation = 0;
|
||||||
|
foregroundColor = 0;
|
||||||
|
cardNumber = 0;
|
||||||
|
collisionRegister = 0;
|
||||||
|
isGrom = FALSE;
|
||||||
|
isVisible = FALSE;
|
||||||
|
doubleWidth = FALSE;
|
||||||
|
doubleYResolution = FALSE;
|
||||||
|
doubleHeight = FALSE;
|
||||||
|
quadHeight = FALSE;
|
||||||
|
flagCollisions = FALSE;
|
||||||
|
horizontalMirror = FALSE;
|
||||||
|
verticalMirror = FALSE;
|
||||||
|
behindForeground = FALSE;
|
||||||
|
boundingRectangle.x = 0;
|
||||||
|
boundingRectangle.y = 0;
|
||||||
|
boundingRectangle.width = 0;
|
||||||
|
boundingRectangle.height = 0;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
boundsChanged = TRUE;
|
||||||
|
colorChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setXLocation(INT32 xLocation) {
|
||||||
|
if (xLocation == this->xLocation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->xLocation = xLocation;
|
||||||
|
boundsChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setYLocation(INT32 yLocation) {
|
||||||
|
if (yLocation == this->yLocation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->yLocation = yLocation;
|
||||||
|
boundsChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MOB::setForegroundColor(INT32 foregroundColor) {
|
||||||
|
if (foregroundColor == this->foregroundColor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->foregroundColor = foregroundColor;
|
||||||
|
colorChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setCardNumber(INT32 cardNumber) {
|
||||||
|
if (cardNumber == this->cardNumber)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->cardNumber = cardNumber;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setVisible(BOOL isVisible) {
|
||||||
|
if (isVisible == this->isVisible)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->isVisible = isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setDoubleWidth(BOOL doubleWidth) {
|
||||||
|
if (doubleWidth == this->doubleWidth)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->doubleWidth = doubleWidth;
|
||||||
|
boundsChanged = TRUE;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setDoubleYResolution(BOOL doubleYResolution) {
|
||||||
|
if (doubleYResolution == this->doubleYResolution)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->doubleYResolution = doubleYResolution;
|
||||||
|
boundsChanged = TRUE;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setDoubleHeight(BOOL doubleHeight) {
|
||||||
|
if (doubleHeight == this->doubleHeight)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->doubleHeight = doubleHeight;
|
||||||
|
boundsChanged = TRUE;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setQuadHeight(BOOL quadHeight) {
|
||||||
|
if (quadHeight == this->quadHeight)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->quadHeight = quadHeight;
|
||||||
|
boundsChanged = TRUE;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setFlagCollisions(BOOL flagCollisions) {
|
||||||
|
if (flagCollisions == this->flagCollisions)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->flagCollisions = flagCollisions;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setHorizontalMirror(BOOL horizontalMirror) {
|
||||||
|
if (horizontalMirror == this->horizontalMirror)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->horizontalMirror = horizontalMirror;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setVerticalMirror(BOOL verticalMirror) {
|
||||||
|
if (verticalMirror == this->verticalMirror)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->verticalMirror = verticalMirror;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setBehindForeground(BOOL behindForeground) {
|
||||||
|
if (behindForeground == this->behindForeground)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->behindForeground = behindForeground;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setGROM(BOOL grom) {
|
||||||
|
if (grom == this->isGrom)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this->isGrom = grom;
|
||||||
|
shapeChanged = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::markClean() {
|
||||||
|
shapeChanged = FALSE;
|
||||||
|
colorChanged = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBRect* MOB::getBounds() {
|
||||||
|
if (boundsChanged) {
|
||||||
|
boundingRectangle.x = xLocation-8;
|
||||||
|
boundingRectangle.y = yLocation-8;
|
||||||
|
boundingRectangle.width = 8 * (doubleWidth ? 2 : 1);
|
||||||
|
boundingRectangle.height = 4 * (quadHeight ? 4 : 1) *
|
||||||
|
(doubleHeight ? 2 : 1) * (doubleYResolution ? 2 : 1);
|
||||||
|
boundsChanged = FALSE;
|
||||||
|
}
|
||||||
|
return &boundingRectangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
MOBState MOB::getState()
|
||||||
|
{
|
||||||
|
MOBState state = {0};
|
||||||
|
|
||||||
|
state.xLocation = this->xLocation;;
|
||||||
|
state.yLocation = this->yLocation;;
|
||||||
|
state.foregroundColor = this->foregroundColor;
|
||||||
|
state.cardNumber = this->cardNumber;
|
||||||
|
state.collisionRegister = this->collisionRegister;
|
||||||
|
state.isGrom = this->isGrom;
|
||||||
|
state.isVisible = this->isVisible;
|
||||||
|
state.doubleWidth = this->doubleWidth;
|
||||||
|
state.doubleYResolution = this->doubleYResolution;
|
||||||
|
state.doubleHeight = this->doubleHeight;
|
||||||
|
state.quadHeight = this->quadHeight;
|
||||||
|
state.flagCollisions = this->flagCollisions;
|
||||||
|
state.horizontalMirror = this->horizontalMirror;
|
||||||
|
state.verticalMirror = this->verticalMirror;
|
||||||
|
state.behindForeground = this->behindForeground;
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MOB::setState(MOBState state)
|
||||||
|
{
|
||||||
|
this->xLocation = state.xLocation;
|
||||||
|
this->yLocation = state.yLocation;
|
||||||
|
this->foregroundColor = state.foregroundColor;
|
||||||
|
this->cardNumber = state.cardNumber;
|
||||||
|
this->collisionRegister = state.collisionRegister;
|
||||||
|
this->isGrom = state.isGrom;
|
||||||
|
this->isVisible = state.isVisible;
|
||||||
|
this->doubleWidth = state.doubleWidth;
|
||||||
|
this->doubleYResolution = state.doubleYResolution;
|
||||||
|
this->doubleHeight = state.doubleHeight;
|
||||||
|
this->quadHeight = state.quadHeight;
|
||||||
|
this->flagCollisions = state.flagCollisions;
|
||||||
|
this->horizontalMirror = state.horizontalMirror;
|
||||||
|
this->verticalMirror = state.verticalMirror;
|
||||||
|
this->behindForeground = state.behindForeground;
|
||||||
|
|
||||||
|
this->boundsChanged = TRUE;
|
||||||
|
this->shapeChanged = TRUE;
|
||||||
|
this->colorChanged = TRUE;
|
||||||
|
}
|
81
arm9/source/emucore/MOB.h
Normal file
81
arm9/source/emucore/MOB.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
|
||||||
|
#ifndef SPRITE_H
|
||||||
|
#define SPRITE_H
|
||||||
|
|
||||||
|
#include "MOBRect.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class AY38900;
|
||||||
|
class AY38900_Registers;
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _MOBState
|
||||||
|
{
|
||||||
|
INT32 xLocation;
|
||||||
|
INT32 yLocation;
|
||||||
|
INT32 foregroundColor;
|
||||||
|
INT32 cardNumber;
|
||||||
|
UINT16 collisionRegister;
|
||||||
|
INT8 isGrom;
|
||||||
|
INT8 isVisible;
|
||||||
|
INT8 doubleWidth;
|
||||||
|
INT8 doubleYResolution;
|
||||||
|
INT8 doubleHeight;
|
||||||
|
INT8 quadHeight;
|
||||||
|
INT8 flagCollisions;
|
||||||
|
INT8 horizontalMirror;
|
||||||
|
INT8 verticalMirror;
|
||||||
|
INT8 behindForeground;
|
||||||
|
} MOBState; )
|
||||||
|
|
||||||
|
class MOB
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class AY38900;
|
||||||
|
friend class AY38900_Registers;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MOB() {};
|
||||||
|
void reset();
|
||||||
|
void setXLocation(INT32 xLocation);
|
||||||
|
void setYLocation(INT32 yLocation);
|
||||||
|
void setForegroundColor(INT32 foregroundColor);
|
||||||
|
void setCardNumber(INT32 cardNumber);
|
||||||
|
void setVisible(BOOL isVisible);
|
||||||
|
void setDoubleWidth(BOOL doubleWidth);
|
||||||
|
void setDoubleYResolution(BOOL doubleYResolution);
|
||||||
|
void setDoubleHeight(BOOL doubleHeight);
|
||||||
|
void setQuadHeight(BOOL quadHeight);
|
||||||
|
void setFlagCollisions(BOOL flagCollisions);
|
||||||
|
void setHorizontalMirror(BOOL horizontalMirror);
|
||||||
|
void setVerticalMirror(BOOL verticalMirror);
|
||||||
|
void setBehindForeground(BOOL behindForeground);
|
||||||
|
void setGROM(BOOL grom);
|
||||||
|
void markClean();
|
||||||
|
MOBRect* getBounds();
|
||||||
|
|
||||||
|
MOBState getState();
|
||||||
|
void setState(MOBState state);
|
||||||
|
|
||||||
|
INT32 xLocation;
|
||||||
|
INT32 yLocation;
|
||||||
|
INT32 foregroundColor;
|
||||||
|
INT32 cardNumber;
|
||||||
|
UINT16 collisionRegister;
|
||||||
|
BOOL isGrom;
|
||||||
|
BOOL isVisible;
|
||||||
|
BOOL doubleWidth;
|
||||||
|
BOOL doubleYResolution;
|
||||||
|
BOOL doubleHeight;
|
||||||
|
BOOL quadHeight;
|
||||||
|
BOOL flagCollisions;
|
||||||
|
BOOL horizontalMirror;
|
||||||
|
BOOL verticalMirror;
|
||||||
|
BOOL behindForeground;
|
||||||
|
BOOL boundsChanged;
|
||||||
|
BOOL shapeChanged;
|
||||||
|
BOOL colorChanged;
|
||||||
|
MOBRect boundingRectangle;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
25
arm9/source/emucore/MOBRect.h
Normal file
25
arm9/source/emucore/MOBRect.h
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
#ifndef RECTANGLE_H
|
||||||
|
#define RECTANGLE_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class MOBRect
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
BOOL intersects(MOBRect* r) {
|
||||||
|
return !((r->x + r->width <= x) ||
|
||||||
|
(r->y + r->height <= y) ||
|
||||||
|
(r->x >= x + width) ||
|
||||||
|
(r->y >= y + height));
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 x;
|
||||||
|
INT32 y;
|
||||||
|
INT32 width;
|
||||||
|
INT32 height;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
26
arm9/source/emucore/Memory.h
Normal file
26
arm9/source/emucore/Memory.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
|
||||||
|
#ifndef MEMORY_H
|
||||||
|
#define MEMORY_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class Memory
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Memory() {}
|
||||||
|
|
||||||
|
virtual void reset() = 0;
|
||||||
|
virtual UINT16 getReadSize() = 0;
|
||||||
|
virtual UINT16 getReadAddress() = 0;
|
||||||
|
virtual UINT16 getReadAddressMask() = 0;
|
||||||
|
virtual UINT16 peek(UINT16 location) = 0;
|
||||||
|
|
||||||
|
virtual UINT16 getWriteSize() = 0;
|
||||||
|
virtual UINT16 getWriteAddress() = 0;
|
||||||
|
virtual UINT16 getWriteAddressMask() = 0;
|
||||||
|
virtual void poke(UINT16 location, UINT16 value) = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
230
arm9/source/emucore/MemoryBus.cpp
Normal file
230
arm9/source/emucore/MemoryBus.cpp
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "MemoryBus.h"
|
||||||
|
|
||||||
|
MemoryBus::MemoryBus()
|
||||||
|
{
|
||||||
|
UINT32 size = 1 << (sizeof(UINT16) << 3);
|
||||||
|
UINT64 i;
|
||||||
|
writeableMemoryCounts = new UINT8[size];
|
||||||
|
memset(writeableMemoryCounts, 0, sizeof(UINT8) * size);
|
||||||
|
writeableMemorySpace = new Memory**[size];
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
writeableMemorySpace[i] = new Memory*[MAX_OVERLAPPED_MEMORIES];
|
||||||
|
readableMemoryCounts = new UINT8[size];
|
||||||
|
memset(readableMemoryCounts, 0, sizeof(UINT8) * size);
|
||||||
|
readableMemorySpace = new Memory**[size];
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
readableMemorySpace[i] = new Memory*[MAX_OVERLAPPED_MEMORIES];
|
||||||
|
mappedMemoryCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBus::~MemoryBus()
|
||||||
|
{
|
||||||
|
UINT64 size = 1 << (sizeof(UINT16) << 3);
|
||||||
|
UINT64 i;
|
||||||
|
delete[] writeableMemoryCounts;
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
delete[] writeableMemorySpace[i];
|
||||||
|
delete[] writeableMemorySpace;
|
||||||
|
delete[] readableMemoryCounts;
|
||||||
|
for (i = 0; i < size; i++)
|
||||||
|
delete[] readableMemorySpace[i];
|
||||||
|
delete[] readableMemorySpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBus::reset()
|
||||||
|
{
|
||||||
|
for (UINT8 i = 0; i < mappedMemoryCount; i++)
|
||||||
|
mappedMemories[i]->reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBus::addMemory(Memory* m)
|
||||||
|
{
|
||||||
|
UINT8 bitCount = sizeof(UINT16)<<3;
|
||||||
|
UINT8 bitShifts[sizeof(UINT16)<<3];
|
||||||
|
UINT8 i;
|
||||||
|
|
||||||
|
//get the important info
|
||||||
|
UINT16 readSize = m->getReadSize();
|
||||||
|
UINT16 readAddress = m->getReadAddress();
|
||||||
|
UINT16 readAddressMask = m->getReadAddressMask();
|
||||||
|
UINT16 writeSize = m->getWriteSize();
|
||||||
|
UINT16 writeAddress = m->getWriteAddress();
|
||||||
|
UINT16 writeAddressMask = m->getWriteAddressMask();
|
||||||
|
|
||||||
|
//add all of the readable locations, if any
|
||||||
|
if (readAddressMask != 0) {
|
||||||
|
UINT8 zeroCount = 0;
|
||||||
|
for (i = 0; i < bitCount; i++) {
|
||||||
|
if (!(readAddressMask & (1<<i))) {
|
||||||
|
bitShifts[zeroCount] = (i-zeroCount);
|
||||||
|
zeroCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 combinationCount = (1<<zeroCount);
|
||||||
|
for (i = 0; i < combinationCount; i++) {
|
||||||
|
UINT16 orMask = 0;
|
||||||
|
for (UINT8 j = 0; j < zeroCount; j++)
|
||||||
|
orMask |= (i & (1<<j)) << bitShifts[j];
|
||||||
|
UINT16 nextAddress = readAddress | orMask;
|
||||||
|
UINT16 nextEnd = nextAddress + readSize - 1;
|
||||||
|
|
||||||
|
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
|
||||||
|
UINT16 memCount = readableMemoryCounts[k];
|
||||||
|
readableMemorySpace[k][memCount] = m;
|
||||||
|
readableMemoryCounts[k]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add all of the writeable locations, if any
|
||||||
|
if (writeAddressMask != 0) {
|
||||||
|
UINT8 zeroCount = 0;
|
||||||
|
for (i = 0; i < bitCount; i++) {
|
||||||
|
if (!(writeAddressMask & (1<<i))) {
|
||||||
|
bitShifts[zeroCount] = (i-zeroCount);
|
||||||
|
zeroCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 combinationCount = (1<<zeroCount);
|
||||||
|
for (i = 0; i < combinationCount; i++) {
|
||||||
|
UINT16 orMask = 0;
|
||||||
|
for (UINT8 j = 0; j < zeroCount; j++)
|
||||||
|
orMask |= (i & (1<<j)) << bitShifts[j];
|
||||||
|
UINT16 nextAddress = writeAddress | orMask;
|
||||||
|
UINT16 nextEnd = nextAddress + writeSize - 1;
|
||||||
|
|
||||||
|
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
|
||||||
|
UINT16 memCount = writeableMemoryCounts[k];
|
||||||
|
writeableMemorySpace[k][memCount] = m;
|
||||||
|
writeableMemoryCounts[k]++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add it to our list of memories
|
||||||
|
mappedMemories[mappedMemoryCount] = m;
|
||||||
|
mappedMemoryCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBus::removeMemory(Memory* m)
|
||||||
|
{
|
||||||
|
UINT8 bitCount = sizeof(UINT16)<<3;
|
||||||
|
UINT8 bitShifts[sizeof(UINT16)<<3];
|
||||||
|
UINT32 i;
|
||||||
|
|
||||||
|
//get the important info
|
||||||
|
UINT16 readSize = m->getReadSize();
|
||||||
|
UINT16 readAddress = m->getReadAddress();
|
||||||
|
UINT16 readAddressMask = m->getReadAddressMask();
|
||||||
|
UINT16 writeSize = m->getWriteSize();
|
||||||
|
UINT16 writeAddress = m->getWriteAddress();
|
||||||
|
UINT16 writeAddressMask = m->getWriteAddressMask();
|
||||||
|
|
||||||
|
//add all of the readable locations, if any
|
||||||
|
if (readAddressMask != 0) {
|
||||||
|
UINT8 zeroCount = 0;
|
||||||
|
for (i = 0; i < bitCount; i++) {
|
||||||
|
if (!(readAddressMask & (1<<i))) {
|
||||||
|
bitShifts[zeroCount] = (UINT8)(i-zeroCount);
|
||||||
|
zeroCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 combinationCount = (1<<zeroCount);
|
||||||
|
for (i = 0; i < combinationCount; i++) {
|
||||||
|
UINT16 orMask = 0;
|
||||||
|
for (UINT8 j = 0; j < zeroCount; j++)
|
||||||
|
orMask |= (i & (1<<j)) << bitShifts[j];
|
||||||
|
UINT16 nextAddress = readAddress | orMask;
|
||||||
|
UINT16 nextEnd = nextAddress + readSize - 1;
|
||||||
|
|
||||||
|
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
|
||||||
|
UINT16 memCount = readableMemoryCounts[k];
|
||||||
|
for (UINT16 n = 0; n < memCount; n++) {
|
||||||
|
if (readableMemorySpace[k][n] == m) {
|
||||||
|
for (INT32 l = n; l < (memCount-1); l++) {
|
||||||
|
readableMemorySpace[k][l] = readableMemorySpace[k][l+1];
|
||||||
|
}
|
||||||
|
readableMemorySpace[k][memCount-1] = NULL;
|
||||||
|
readableMemoryCounts[k]--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//add all of the writeable locations, if any
|
||||||
|
if (writeAddressMask != 0) {
|
||||||
|
UINT8 zeroCount = 0;
|
||||||
|
for (i = 0; i < bitCount; i++) {
|
||||||
|
if (!(writeAddressMask & (1<<i))) {
|
||||||
|
bitShifts[zeroCount] = (UINT8)(i-zeroCount);
|
||||||
|
zeroCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 combinationCount = (1<<zeroCount);
|
||||||
|
for (i = 0; i < combinationCount; i++) {
|
||||||
|
UINT16 orMask = 0;
|
||||||
|
for (UINT8 j = 0; j < zeroCount; j++)
|
||||||
|
orMask |= (i & (1<<j)) << bitShifts[j];
|
||||||
|
UINT16 nextAddress = writeAddress | orMask;
|
||||||
|
UINT16 nextEnd = nextAddress + writeSize - 1;
|
||||||
|
|
||||||
|
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
|
||||||
|
UINT16 memCount = writeableMemoryCounts[k];
|
||||||
|
for (UINT16 n = 0; n < memCount; n++) {
|
||||||
|
if (writeableMemorySpace[k][n] == m) {
|
||||||
|
for (INT32 l = n; l < (memCount-1); l++) {
|
||||||
|
writeableMemorySpace[k][l] =
|
||||||
|
writeableMemorySpace[k][l+1];
|
||||||
|
}
|
||||||
|
writeableMemorySpace[k][memCount-1] = NULL;
|
||||||
|
writeableMemoryCounts[k]--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove it from our list of memories
|
||||||
|
for (i = 0; i < mappedMemoryCount; i++) {
|
||||||
|
if (mappedMemories[i] == m) {
|
||||||
|
for (UINT32 j = i; j < (UINT32)(mappedMemoryCount-1); j++)
|
||||||
|
mappedMemories[j] = mappedMemories[j+1];
|
||||||
|
mappedMemoryCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBus::removeAll()
|
||||||
|
{
|
||||||
|
while (mappedMemoryCount)
|
||||||
|
removeMemory(mappedMemories[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
UINT16 MemoryBus::peek(UINT16 location)
|
||||||
|
{
|
||||||
|
UINT8 numMemories = readableMemoryCounts[location];
|
||||||
|
|
||||||
|
UINT16 value = 0xFFFF;
|
||||||
|
for (UINT16 i = 0; i < numMemories; i++)
|
||||||
|
value &= readableMemorySpace[location][i]->peek(location);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBus::poke(UINT16 location, UINT16 value)
|
||||||
|
{
|
||||||
|
UINT8 numMemories = writeableMemoryCounts[location];
|
||||||
|
|
||||||
|
for (UINT16 i = 0; i < numMemories; i++)
|
||||||
|
writeableMemorySpace[location][i]->poke(location, value);
|
||||||
|
}
|
||||||
|
|
46
arm9/source/emucore/MemoryBus.h
Normal file
46
arm9/source/emucore/MemoryBus.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
#ifndef MEMORYBUS_H
|
||||||
|
#define MEMORYBUS_H
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "Memory.h"
|
||||||
|
|
||||||
|
#define MAX_MAPPED_MEMORIES 20
|
||||||
|
#define MAX_OVERLAPPED_MEMORIES 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emulates a 64K memory bus which may be composed of 8-bit or 16-bit memory units.
|
||||||
|
*
|
||||||
|
* @author Kyle Davis
|
||||||
|
*/
|
||||||
|
extern UINT16 r[8];
|
||||||
|
|
||||||
|
class MemoryBus
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
MemoryBus();
|
||||||
|
virtual ~MemoryBus();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
UINT16 peek(UINT16 location);
|
||||||
|
inline UINT16 peek_fast(UINT16 location) {return readableMemorySpace[location][0]->peek(location);}
|
||||||
|
inline UINT16 peek_pc(void) {return readableMemorySpace[r[7]][0]->peek(r[7]);}
|
||||||
|
void poke(UINT16 location, UINT16 value);
|
||||||
|
|
||||||
|
void addMemory(Memory* m);
|
||||||
|
void removeMemory(Memory* m);
|
||||||
|
void removeAll();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Memory* mappedMemories[MAX_MAPPED_MEMORIES];
|
||||||
|
UINT16 mappedMemoryCount;
|
||||||
|
UINT8* writeableMemoryCounts;
|
||||||
|
Memory*** writeableMemorySpace;
|
||||||
|
UINT8* readableMemoryCounts;
|
||||||
|
Memory*** readableMemorySpace;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
14
arm9/source/emucore/Palette.h
Normal file
14
arm9/source/emucore/Palette.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
|
||||||
|
#ifndef PALETTE_H
|
||||||
|
#define PALETTE_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
typedef struct _PALETTE
|
||||||
|
{
|
||||||
|
UINT16 m_iNumEntries;
|
||||||
|
UINT32 m_iEntries[256];
|
||||||
|
|
||||||
|
} PALETTE;
|
||||||
|
|
||||||
|
#endif
|
114
arm9/source/emucore/Peripheral.cpp
Normal file
114
arm9/source/emucore/Peripheral.cpp
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
|
||||||
|
|
||||||
|
#include "Peripheral.h"
|
||||||
|
|
||||||
|
void Peripheral::AddProcessor(Processor* p)
|
||||||
|
{
|
||||||
|
processors[processorCount] = p;
|
||||||
|
processorCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peripheral::RemoveProcessor(Processor* p)
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < processorCount; i++) {
|
||||||
|
if (processors[i] == p) {
|
||||||
|
for (UINT32 j = i; j < (processorCount-1); j++)
|
||||||
|
processors[j] = processors[j+1];
|
||||||
|
processorCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 Peripheral::GetProcessorCount()
|
||||||
|
{
|
||||||
|
return processorCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
Processor* Peripheral::GetProcessor(UINT16 i)
|
||||||
|
{
|
||||||
|
return processors[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peripheral::AddRAM(RAM* m)
|
||||||
|
{
|
||||||
|
rams[ramCount] = m;
|
||||||
|
ramCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 Peripheral::GetRAMCount()
|
||||||
|
{
|
||||||
|
return ramCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAM* Peripheral::GetRAM(UINT16 i)
|
||||||
|
{
|
||||||
|
return rams[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peripheral::AddVideoProducer(VideoProducer* vp)
|
||||||
|
{
|
||||||
|
videoProducers[videoProducerCount] = vp;
|
||||||
|
videoProducerCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 Peripheral::GetVideoProducerCount()
|
||||||
|
{
|
||||||
|
return videoProducerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoProducer* Peripheral::GetVideoProducer(UINT16 i)
|
||||||
|
{
|
||||||
|
return videoProducers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peripheral::AddAudioProducer(AudioProducer* ap)
|
||||||
|
{
|
||||||
|
audioProducers[audioProducerCount] = ap;
|
||||||
|
audioProducerCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 Peripheral::GetAudioProducerCount()
|
||||||
|
{
|
||||||
|
return audioProducerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
AudioProducer* Peripheral::GetAudioProducer(UINT16 i)
|
||||||
|
{
|
||||||
|
return audioProducers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peripheral::AddInputConsumer(InputConsumer* ic)
|
||||||
|
{
|
||||||
|
inputConsumers[inputConsumerCount] = ic;
|
||||||
|
inputConsumerCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 Peripheral::GetInputConsumerCount()
|
||||||
|
{
|
||||||
|
return inputConsumerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConsumer* Peripheral::GetInputConsumer(UINT16 i)
|
||||||
|
{
|
||||||
|
return inputConsumers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Peripheral::AddROM(ROM* r)
|
||||||
|
{
|
||||||
|
printf("ROM Added [%s]\n", r->getName());
|
||||||
|
roms[romCount] = r;
|
||||||
|
romCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 Peripheral::GetROMCount()
|
||||||
|
{
|
||||||
|
return romCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
ROM* Peripheral::GetROM(UINT16 i)
|
||||||
|
{
|
||||||
|
return roms[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
236
arm9/source/emucore/Peripheral.h
Normal file
236
arm9/source/emucore/Peripheral.h
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
|
||||||
|
#ifndef PERIPHERAL_H
|
||||||
|
#define PERIPHERAL_H
|
||||||
|
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "RAM.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
#include "AudioProducer.h"
|
||||||
|
#include "VideoProducer.h"
|
||||||
|
#include "InputConsumer.h"
|
||||||
|
|
||||||
|
#define MAX_COMPONENTS 16
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A peripheral represents a device that contains emulated hardware components, including
|
||||||
|
* processors and memory units. Each processor or memory unit may optionally also be a
|
||||||
|
* video producer, audio producer, and/or input consumer. However, some input consumers are
|
||||||
|
* neither processors or memory units.
|
||||||
|
*/
|
||||||
|
class Peripheral
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Gets the name of this peripheral.
|
||||||
|
*
|
||||||
|
* @return the peripheral name
|
||||||
|
*/
|
||||||
|
const char* GetName() { return peripheralName; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the short name of this peripheral.
|
||||||
|
*
|
||||||
|
* @return the short peripheral name
|
||||||
|
*/
|
||||||
|
const char* GetShortName() { return peripheralShortName; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a processor to this peripheral.
|
||||||
|
*
|
||||||
|
* @param processor the processor to add
|
||||||
|
*/
|
||||||
|
void AddProcessor(Processor* processor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a processor from this peripheral.
|
||||||
|
*
|
||||||
|
* @param processor the processor to remove
|
||||||
|
*/
|
||||||
|
void RemoveProcessor(Processor* processor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of processors in this peripheral.
|
||||||
|
*
|
||||||
|
* @return the number of processors
|
||||||
|
*/
|
||||||
|
UINT16 GetProcessorCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pointer to the processor indicated by an index.
|
||||||
|
*
|
||||||
|
* @param index the index of the processor to return
|
||||||
|
* @return a pointer to the processor
|
||||||
|
*/
|
||||||
|
Processor* GetProcessor(UINT16 index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a RAM unit to this peripheral.
|
||||||
|
*
|
||||||
|
* @param ram the RAM unit to add
|
||||||
|
*/
|
||||||
|
void AddRAM(RAM* ram);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of RAM units in this peripheral.
|
||||||
|
*
|
||||||
|
* @return the number of RAM units
|
||||||
|
*/
|
||||||
|
UINT16 GetRAMCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pointer to the RAM unit indicated by an index.
|
||||||
|
*
|
||||||
|
* @param index the index of the RAM unit to return
|
||||||
|
* @return a pointer to the RAM unit
|
||||||
|
*/
|
||||||
|
RAM* GetRAM(UINT16 index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a ROM unit to this peripheral.
|
||||||
|
*
|
||||||
|
* @param rom the ROM unit to add
|
||||||
|
*/
|
||||||
|
void AddROM(ROM* rom);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of ROM units in this peripheral.
|
||||||
|
*
|
||||||
|
* @return the number of ROM units
|
||||||
|
*/
|
||||||
|
UINT16 GetROMCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pointer to the ROM unit indicated by an index.
|
||||||
|
*
|
||||||
|
* @param index the index of the ROM unit to return
|
||||||
|
* @return a pointer to the ROM unit
|
||||||
|
*/
|
||||||
|
ROM* GetROM(UINT16 index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a video producer to this peripheral.
|
||||||
|
*
|
||||||
|
* @param vp the video producer to add
|
||||||
|
*/
|
||||||
|
void AddVideoProducer(VideoProducer* vp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of video producers in this peripheral.
|
||||||
|
*
|
||||||
|
* @return the number of video producers
|
||||||
|
*/
|
||||||
|
UINT16 GetVideoProducerCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pointer to the video producer indicated by an index.
|
||||||
|
*
|
||||||
|
* @param index the index of the video producer to return
|
||||||
|
* @return a pointer to the video producer
|
||||||
|
*/
|
||||||
|
VideoProducer* GetVideoProducer(UINT16 index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an audio producer to this peripheral.
|
||||||
|
*
|
||||||
|
* @param ap the audio producer to add
|
||||||
|
*/
|
||||||
|
void AddAudioProducer(AudioProducer* ap);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of audio producers in this peripheral.
|
||||||
|
*
|
||||||
|
* @return the number of audio producers
|
||||||
|
*/
|
||||||
|
UINT16 GetAudioProducerCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pointer to the audio producer indicated by an index.
|
||||||
|
*
|
||||||
|
* @param index the index of the audio producer to return
|
||||||
|
* @return a pointer to the audio producer
|
||||||
|
*/
|
||||||
|
AudioProducer* GetAudioProducer(UINT16 index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an input consumer to this peripheral.
|
||||||
|
*
|
||||||
|
* @param ic the input consumer to add
|
||||||
|
*/
|
||||||
|
void AddInputConsumer(InputConsumer*);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of input consumers in this peripheral.
|
||||||
|
*
|
||||||
|
* @return the number of input consumers
|
||||||
|
*/
|
||||||
|
UINT16 GetInputConsumerCount();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pointer to the input consumer indicated by an index.
|
||||||
|
*
|
||||||
|
* @param index the index of the input consumer to return
|
||||||
|
* @return a pointer to the input consumer
|
||||||
|
*/
|
||||||
|
InputConsumer* GetInputConsumer(UINT16 index);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Constructs a peripheral.
|
||||||
|
*
|
||||||
|
* @param name the name of the peripheral
|
||||||
|
* @param shortName the short name of the peripheral
|
||||||
|
*/
|
||||||
|
Peripheral(const CHAR* name, const CHAR* shortName)
|
||||||
|
: processorCount(0),
|
||||||
|
videoProducerCount(0),
|
||||||
|
audioProducerCount(0),
|
||||||
|
inputConsumerCount(0),
|
||||||
|
ramCount(0),
|
||||||
|
romCount(0),
|
||||||
|
peripheralName(NULL),
|
||||||
|
peripheralShortName(NULL)
|
||||||
|
{
|
||||||
|
if (name) {
|
||||||
|
peripheralName = new CHAR[strlen(name)+1];
|
||||||
|
strcpy(peripheralName, name);
|
||||||
|
}
|
||||||
|
if (shortName) {
|
||||||
|
peripheralShortName = new CHAR[strlen(shortName)+1];
|
||||||
|
strcpy(peripheralShortName, shortName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the peripheral.
|
||||||
|
*/
|
||||||
|
~Peripheral()
|
||||||
|
{
|
||||||
|
delete[] peripheralShortName;
|
||||||
|
delete[] peripheralName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The peripheral name. The Rip class exposes the periphal name as mutable, so we leave
|
||||||
|
* it exposed as protected access here. This will probably change in the future.
|
||||||
|
*/
|
||||||
|
char* peripheralName;
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* peripheralShortName;
|
||||||
|
Processor* processors[MAX_COMPONENTS];
|
||||||
|
UINT16 processorCount;
|
||||||
|
VideoProducer* videoProducers[MAX_COMPONENTS];
|
||||||
|
UINT16 videoProducerCount;
|
||||||
|
AudioProducer* audioProducers[MAX_COMPONENTS];
|
||||||
|
UINT16 audioProducerCount;
|
||||||
|
InputConsumer* inputConsumers[MAX_COMPONENTS];
|
||||||
|
UINT16 inputConsumerCount;
|
||||||
|
RAM* rams[MAX_COMPONENTS];
|
||||||
|
UINT16 ramCount;
|
||||||
|
ROM* roms[MAX_COMPONENTS];
|
||||||
|
UINT16 romCount;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
49
arm9/source/emucore/Processor.cpp
Normal file
49
arm9/source/emucore/Processor.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
#include "CP1610.h"
|
||||||
|
|
||||||
|
SignalLine nullPin;
|
||||||
|
|
||||||
|
Processor::Processor(const char* nm)
|
||||||
|
: name(nm)
|
||||||
|
{
|
||||||
|
for (UINT8 i = 0; i < MAX_PINS; i++) {
|
||||||
|
pinOut[i] = &nullPin;
|
||||||
|
pinIn[i] = &nullPin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Processor::~Processor()
|
||||||
|
{
|
||||||
|
for (UINT8 i = 0; i < MAX_PINS; i++) {
|
||||||
|
if (pinOut[i] != &nullPin)
|
||||||
|
delete pinOut[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Processor::connectPinOut(UINT8 pinOutNum, Processor* targetProcessor,
|
||||||
|
UINT8 targetPinInNum)
|
||||||
|
{
|
||||||
|
if (pinOut[pinOutNum] != &nullPin)
|
||||||
|
disconnectPinOut(pinOutNum);
|
||||||
|
|
||||||
|
if (targetProcessor->pinIn[targetPinInNum] != &nullPin) {
|
||||||
|
targetProcessor->pinIn[targetPinInNum]->pinOutProcessor->disconnectPinOut(
|
||||||
|
targetProcessor->pinIn[targetPinInNum]->pinOutNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
pinOut[pinOutNum] = new SignalLine(this, pinOutNum, targetProcessor,
|
||||||
|
targetPinInNum);
|
||||||
|
|
||||||
|
targetProcessor->pinIn[targetPinInNum] = pinOut[pinOutNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Processor::disconnectPinOut(UINT8 pinOutNum)
|
||||||
|
{
|
||||||
|
if (pinOut[pinOutNum] == &nullPin)
|
||||||
|
return;
|
||||||
|
|
||||||
|
SignalLine* s = pinOut[pinOutNum];
|
||||||
|
s->pinInProcessor->pinIn[s->pinInNum] = &nullPin;
|
||||||
|
pinOut[pinOutNum] = &nullPin;
|
||||||
|
delete s;
|
||||||
|
}
|
61
arm9/source/emucore/Processor.h
Normal file
61
arm9/source/emucore/Processor.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
|
||||||
|
#ifndef PROCESSOR_H
|
||||||
|
#define PROCESSOR_H
|
||||||
|
|
||||||
|
#include "SignalLine.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "MemoryBus.h"
|
||||||
|
#define MAX_PINS 16
|
||||||
|
|
||||||
|
class ProcessorBus;
|
||||||
|
class ScheduleQueue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract class representing a processor, which is a hardware component
|
||||||
|
* that requires a clock input.
|
||||||
|
*/
|
||||||
|
class Processor
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class ProcessorBus;
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Processor();
|
||||||
|
|
||||||
|
const char* getName() { return name; }
|
||||||
|
|
||||||
|
virtual void resetProcessor() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the clock speed of this processor. Unlike many emulation
|
||||||
|
* codebases, this codebase allows a processor to run at any speed
|
||||||
|
* it prefers, and the ProcessorBus is responsible for scheduling
|
||||||
|
* execution of each processor based on all of the various processor
|
||||||
|
* speeds.
|
||||||
|
*/
|
||||||
|
virtual INT32 getClockSpeed() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
virtual INT32 tick(INT32 i) = 0;
|
||||||
|
|
||||||
|
virtual void connectPinOut(UINT8 pinOutNum, Processor* targetProcessor,
|
||||||
|
UINT8 targetPinInNum);
|
||||||
|
virtual void disconnectPinOut(UINT8 pinOutNum);
|
||||||
|
|
||||||
|
virtual BOOL isIdle() { return FALSE; };
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Processor(const char* name);
|
||||||
|
|
||||||
|
const char* name;
|
||||||
|
SignalLine* pinIn[MAX_PINS];
|
||||||
|
SignalLine* pinOut[MAX_PINS];
|
||||||
|
|
||||||
|
ProcessorBus* processorBus;
|
||||||
|
ScheduleQueue* scheduleQueue;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
318
arm9/source/emucore/ProcessorBus.cpp
Normal file
318
arm9/source/emucore/ProcessorBus.cpp
Normal file
@ -0,0 +1,318 @@
|
|||||||
|
|
||||||
|
#include "ProcessorBus.h"
|
||||||
|
|
||||||
|
ProcessorBus::ProcessorBus()
|
||||||
|
: processorCount(0),
|
||||||
|
startQueue(NULL),
|
||||||
|
endQueue(NULL)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ProcessorBus::~ProcessorBus()
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < processorCount; i++) {
|
||||||
|
if (processors[i]->scheduleQueue)
|
||||||
|
delete processors[i]->scheduleQueue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::addProcessor(Processor* p)
|
||||||
|
{
|
||||||
|
processors[processorCount] = p;
|
||||||
|
processorCount++;
|
||||||
|
p->processorBus = this;
|
||||||
|
p->scheduleQueue = new ScheduleQueue(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::removeProcessor(Processor* p)
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < processorCount; i++) {
|
||||||
|
if (processors[i] == p) {
|
||||||
|
for (UINT32 j = i; j < (processorCount-1); j++)
|
||||||
|
processors[j] = processors[j+1];
|
||||||
|
processorCount--;
|
||||||
|
delete p->scheduleQueue;
|
||||||
|
p->scheduleQueue = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::removeAll()
|
||||||
|
{
|
||||||
|
while (processorCount)
|
||||||
|
removeProcessor(processors[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ProcessorBus::reset()
|
||||||
|
{
|
||||||
|
if (processorCount == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
UINT64 totalClockSpeed = 1;
|
||||||
|
startQueue = endQueue = NULL;
|
||||||
|
|
||||||
|
//reorder the processor queue so that it is in the natural (starting) order
|
||||||
|
for (UINT32 i = 0; i < processorCount; i++) {
|
||||||
|
Processor* p = processors[i];
|
||||||
|
totalClockSpeed = lcm(totalClockSpeed, ((UINT64)p->getClockSpeed()));
|
||||||
|
|
||||||
|
ScheduleQueue* nextQueue = p->scheduleQueue;
|
||||||
|
nextQueue->tick = 0;
|
||||||
|
if (startQueue == NULL) {
|
||||||
|
startQueue = nextQueue;
|
||||||
|
nextQueue->previous = NULL;
|
||||||
|
nextQueue->next = NULL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
endQueue->next = nextQueue;
|
||||||
|
nextQueue->previous = endQueue;
|
||||||
|
nextQueue->next = NULL;
|
||||||
|
}
|
||||||
|
endQueue = nextQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//pre-cache the multiplication factor required to convert each processor's clock speed to
|
||||||
|
//the common clock speed, and reset each processor
|
||||||
|
for (UINT32 i = 0; i < processorCount; i++) {
|
||||||
|
Processor* p = processors[i];
|
||||||
|
p->scheduleQueue->tickFactor = (totalClockSpeed / ((UINT64)p->getClockSpeed()));
|
||||||
|
p->resetProcessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::run()
|
||||||
|
{
|
||||||
|
running = true;
|
||||||
|
while (running) {
|
||||||
|
// TODO: jeremiah sypult, saw crash when NULL
|
||||||
|
if (startQueue->next == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//tick the processor that is at the head of the queue
|
||||||
|
int minTicks = (int)((startQueue->next->tick / startQueue->tickFactor) + 1);
|
||||||
|
startQueue->tick = ((UINT64)startQueue->processor->tick(minTicks)) * startQueue->tickFactor;
|
||||||
|
|
||||||
|
//now reschedule the processor for later processing
|
||||||
|
ScheduleQueue* tmp1 = startQueue;
|
||||||
|
while (tmp1->next != NULL && startQueue->tick > tmp1->next->tick) {
|
||||||
|
startQueue->tick -= tmp1->next->tick;
|
||||||
|
tmp1 = tmp1->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reorganize the scheduling queue
|
||||||
|
ScheduleQueue* queueToShuffle = startQueue;
|
||||||
|
startQueue = startQueue->next;
|
||||||
|
queueToShuffle->previous = tmp1;
|
||||||
|
queueToShuffle->next = tmp1->next;
|
||||||
|
tmp1->next = queueToShuffle;
|
||||||
|
if (queueToShuffle->next != NULL) {
|
||||||
|
queueToShuffle->next->tick -= queueToShuffle->tick;
|
||||||
|
queueToShuffle->next->previous = queueToShuffle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
endQueue = queueToShuffle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::stop()
|
||||||
|
{
|
||||||
|
running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::halt(Processor*)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::unhalt(Processor*)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::pause(Processor* p, int ticks)
|
||||||
|
{
|
||||||
|
ScheduleQueue* q = p->scheduleQueue;
|
||||||
|
UINT64 commonTicks = ((UINT64)ticks) * q->tickFactor;
|
||||||
|
if (q->next == NULL)
|
||||||
|
q->tick += commonTicks;
|
||||||
|
else if (commonTicks <= q->next->tick) {
|
||||||
|
q->tick += commonTicks;
|
||||||
|
q->next->tick -= commonTicks;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//pull this processor out of the scheduling stream and reschedule it
|
||||||
|
//add my current ticks to the next guy's delta ticks
|
||||||
|
q->next->tick += q->tick;
|
||||||
|
//add the common ticks to my ticks
|
||||||
|
q->tick += commonTicks;
|
||||||
|
//have the previous q point to the next q
|
||||||
|
if (q->previous != NULL) {
|
||||||
|
q->previous->next = q->next;
|
||||||
|
q->next->previous = q->previous;
|
||||||
|
}
|
||||||
|
reschedule(p->scheduleQueue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::reschedule(ScheduleQueue* queueToShuffle)
|
||||||
|
{
|
||||||
|
//look for where to put this processor in the scheduling queue
|
||||||
|
ScheduleQueue* tmp1 = queueToShuffle;
|
||||||
|
while (tmp1->next != NULL && queueToShuffle->tick > tmp1->next->tick) {
|
||||||
|
queueToShuffle->tick -= tmp1->next->tick;
|
||||||
|
tmp1 = tmp1->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
//reorganize the scheduling queue
|
||||||
|
if (queueToShuffle == startQueue)
|
||||||
|
startQueue = queueToShuffle->next;
|
||||||
|
queueToShuffle->previous = tmp1;
|
||||||
|
queueToShuffle->next = tmp1->next;
|
||||||
|
tmp1->next = queueToShuffle;
|
||||||
|
if (queueToShuffle->next != NULL) {
|
||||||
|
queueToShuffle->next->tick -= queueToShuffle->tick;
|
||||||
|
queueToShuffle->next->previous = queueToShuffle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
endQueue = queueToShuffle;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT64 lcm(UINT64 a, UINT64 b) {
|
||||||
|
//This is an implementation of Euclid's Algorithm for determining
|
||||||
|
//the greatest common denominator (gcd) of two numbers.
|
||||||
|
UINT64 m = a;
|
||||||
|
UINT64 n = b;
|
||||||
|
UINT64 r = m % n;
|
||||||
|
while (r != 0) {
|
||||||
|
m = n;
|
||||||
|
n = r;
|
||||||
|
r = m % n;
|
||||||
|
}
|
||||||
|
UINT64 gcd = n;
|
||||||
|
|
||||||
|
//lcm is determined from gcd through the following equation
|
||||||
|
return (a/gcd)*b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
ProcessorBus::ProcessorBus()
|
||||||
|
{
|
||||||
|
processorDebugOn = FALSE;
|
||||||
|
processorCount = 0;
|
||||||
|
memset(processors, 0, sizeof(Processor*) * MAX_PROCESSORS);
|
||||||
|
memset(processorTickFactors, 0, sizeof(INT64) * MAX_PROCESSORS);
|
||||||
|
memset(processorTicks, 0, sizeof(INT64) * MAX_PROCESSORS);
|
||||||
|
memset(processorsIdle, 0, sizeof(BOOL) * MAX_PROCESSORS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::setAudioMixer(AudioMixer* am)
|
||||||
|
{
|
||||||
|
this->audioMixer = am;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::init()
|
||||||
|
{
|
||||||
|
UINT64 totalClockSpeed = 1;
|
||||||
|
UINT32 i;
|
||||||
|
for (i = 0; i < processorCount; i++) {
|
||||||
|
totalClockSpeed = lcm(totalClockSpeed,
|
||||||
|
((UINT64)processors[i]->getClockSpeed()));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < processorCount; i++) {
|
||||||
|
processorsIdle[i] = FALSE;
|
||||||
|
processorTicks[i] = 0;
|
||||||
|
processorTickFactors[i] = (totalClockSpeed /
|
||||||
|
((UINT64)processors[i]->getClockSpeed()));
|
||||||
|
|
||||||
|
processors[i]->initProcessor();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::release()
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < processorCount; i++)
|
||||||
|
processors[i]->releaseProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::addProcessor(Processor* p)
|
||||||
|
{
|
||||||
|
processors[processorCount] = p;
|
||||||
|
processorCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::removeProcessor(Processor* p)
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < processorCount; i++) {
|
||||||
|
if (processors[i] == p) {
|
||||||
|
for (UINT32 j = i; j < (processorCount-1); j++)
|
||||||
|
processors[j] = processors[j+1];
|
||||||
|
processorCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::removeAll()
|
||||||
|
{
|
||||||
|
processorCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessorBus::tick()
|
||||||
|
{
|
||||||
|
//determine the next tick delta
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
UINT64 tickDelta = 0xFFFFFFFFFFFFFFFF;
|
||||||
|
#else
|
||||||
|
UINT64 tickDelta = 0xFFFFFFFFFFFFFFFFll;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UINT32 i;
|
||||||
|
for (i = 0; i < processorCount; i++) {
|
||||||
|
//wake up any processors that want to wake up
|
||||||
|
processorsIdle[i] = (processorsIdle[i] && processors[i]->isIdle());
|
||||||
|
|
||||||
|
//if the processor is not idle by this point, use it
|
||||||
|
//to calculate the tick delta
|
||||||
|
if (!processorsIdle[i] && (UINT64)processorTicks[i] < tickDelta)
|
||||||
|
tickDelta = processorTicks[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//move the audio mixer clock forward by the tick delta amount
|
||||||
|
audioMixer->clock += tickDelta;
|
||||||
|
|
||||||
|
for (i = 0; i < processorCount; i++) {
|
||||||
|
//skip this processor if it has been idled
|
||||||
|
if (!processorsIdle[i]) {
|
||||||
|
processorTicks[i] -= tickDelta;
|
||||||
|
|
||||||
|
//if the clock just caught up to the processor, and
|
||||||
|
//if the processor is not about to go idle, then run it
|
||||||
|
if (processorTicks[i] == 0) {
|
||||||
|
if (processors[i]->isIdle())
|
||||||
|
processorsIdle[i] = TRUE;
|
||||||
|
else {
|
||||||
|
processorTicks[i] = (((UINT64)processors[i]->tick()) *
|
||||||
|
processorTickFactors[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT64 lcm(UINT64 a, UINT64 b) {
|
||||||
|
//This is an implementation of Euclid's Algorithm for determining
|
||||||
|
//the greatest common denominator (gcd) of two numbers.
|
||||||
|
UINT64 m = a;
|
||||||
|
UINT64 n = b;
|
||||||
|
UINT64 r = m % n;
|
||||||
|
while (r != 0) {
|
||||||
|
m = n;
|
||||||
|
n = r;
|
||||||
|
r = m % n;
|
||||||
|
}
|
||||||
|
UINT64 gcd = n;
|
||||||
|
|
||||||
|
//lcm is determined from gcd through the following equation
|
||||||
|
return (a/gcd)*b;
|
||||||
|
}
|
||||||
|
*/
|
65
arm9/source/emucore/ProcessorBus.h
Normal file
65
arm9/source/emucore/ProcessorBus.h
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
|
||||||
|
#ifndef PROCESSORBUS_H
|
||||||
|
#define PROCESSORBUS_H
|
||||||
|
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "AudioMixer.h"
|
||||||
|
|
||||||
|
const INT32 MAX_PROCESSORS = 15;
|
||||||
|
|
||||||
|
class ScheduleQueue;
|
||||||
|
|
||||||
|
class ProcessorBus
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
ProcessorBus();
|
||||||
|
virtual ~ProcessorBus();
|
||||||
|
void addProcessor(Processor* p);
|
||||||
|
void removeProcessor(Processor* p);
|
||||||
|
void removeAll();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
void run();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void halt(Processor* p);
|
||||||
|
void unhalt(Processor* p);
|
||||||
|
void pause(Processor* p, int ticks);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void reschedule(ScheduleQueue*);
|
||||||
|
|
||||||
|
UINT32 processorCount;
|
||||||
|
Processor* processors[MAX_PROCESSORS];
|
||||||
|
bool running;
|
||||||
|
ScheduleQueue* startQueue;
|
||||||
|
ScheduleQueue* endQueue;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class ScheduleQueue
|
||||||
|
{
|
||||||
|
friend class ProcessorBus;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ScheduleQueue(Processor* p)
|
||||||
|
: tickFactor(0),
|
||||||
|
tick(0),
|
||||||
|
previous(NULL),
|
||||||
|
next(NULL)
|
||||||
|
{
|
||||||
|
this->processor = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
Processor* processor;
|
||||||
|
UINT64 tickFactor;
|
||||||
|
UINT64 tick;
|
||||||
|
ScheduleQueue* previous;
|
||||||
|
ScheduleQueue* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
UINT64 lcm(UINT64 a, UINT64 b);
|
||||||
|
|
||||||
|
#endif
|
157
arm9/source/emucore/RAM.ITCM.cpp
Normal file
157
arm9/source/emucore/RAM.ITCM.cpp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include "RAM.h"
|
||||||
|
|
||||||
|
UINT16 fast_ram[4096] __attribute__((section(".dtcm")));
|
||||||
|
UINT16 fast_ram_idx = 0;
|
||||||
|
|
||||||
|
RAM::RAM(UINT16 size, UINT16 location)
|
||||||
|
: enabled(TRUE)
|
||||||
|
{
|
||||||
|
this->size = size;
|
||||||
|
this->location = location;
|
||||||
|
this->readAddressMask = 0xFFFF;
|
||||||
|
this->writeAddressMask = 0xFFFF;
|
||||||
|
this->bitWidth = sizeof(UINT16)<<3;
|
||||||
|
this->trimmer = (UINT16)((1 << (sizeof(UINT16) << 3)) - 1);
|
||||||
|
//image = new UINT16[size];
|
||||||
|
image = &fast_ram[fast_ram_idx];
|
||||||
|
fast_ram_idx += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAM::RAM(UINT16 size, UINT16 location, UINT8 bitWidth)
|
||||||
|
: enabled(TRUE)
|
||||||
|
{
|
||||||
|
this->size = size;
|
||||||
|
this->location = location;
|
||||||
|
this->readAddressMask = 0xFFFF;
|
||||||
|
this->writeAddressMask = 0xFFFF;
|
||||||
|
this->bitWidth = bitWidth;
|
||||||
|
this->trimmer = (UINT16)((1 << bitWidth) - 1);
|
||||||
|
//image = new UINT16[size];
|
||||||
|
image = &fast_ram[fast_ram_idx];
|
||||||
|
fast_ram_idx += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAM::RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask)
|
||||||
|
: enabled(TRUE)
|
||||||
|
{
|
||||||
|
this->size = size;
|
||||||
|
this->location = location;
|
||||||
|
this->readAddressMask = readAddressMask;
|
||||||
|
this->writeAddressMask = writeAddressMask;
|
||||||
|
this->bitWidth = sizeof(UINT16)<<3;
|
||||||
|
this->trimmer = (UINT16)((1 << bitWidth) - 1);
|
||||||
|
//image = new UINT16[size];
|
||||||
|
image = &fast_ram[fast_ram_idx];
|
||||||
|
fast_ram_idx += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAM::RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask, UINT8 bitWidth)
|
||||||
|
: enabled(TRUE)
|
||||||
|
{
|
||||||
|
this->size = size;
|
||||||
|
this->location = location;
|
||||||
|
this->readAddressMask = readAddressMask;
|
||||||
|
this->writeAddressMask = writeAddressMask;
|
||||||
|
this->bitWidth = bitWidth;
|
||||||
|
this->trimmer = (UINT16)((1 << bitWidth) - 1);
|
||||||
|
//image = new UINT16[size];
|
||||||
|
image = &fast_ram[fast_ram_idx];
|
||||||
|
fast_ram_idx += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAM::~RAM()
|
||||||
|
{
|
||||||
|
//delete[] image;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RAM::reset()
|
||||||
|
{
|
||||||
|
enabled = TRUE;
|
||||||
|
for (UINT16 i = 0; i < size; i++)
|
||||||
|
image[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RAM::SetEnabled(BOOL b)
|
||||||
|
{
|
||||||
|
enabled = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 RAM::getBitWidth()
|
||||||
|
{
|
||||||
|
return bitWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 RAM::getReadSize()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 RAM::getReadAddress()
|
||||||
|
{
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 RAM::getReadAddressMask()
|
||||||
|
{
|
||||||
|
return readAddressMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 RAM::getWriteSize()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 RAM::getWriteAddress()
|
||||||
|
{
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 RAM::getWriteAddressMask()
|
||||||
|
{
|
||||||
|
return writeAddressMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 RAM::peek(UINT16 location)
|
||||||
|
{
|
||||||
|
return image[(location&readAddressMask)-this->location];
|
||||||
|
}
|
||||||
|
|
||||||
|
void RAM::poke(UINT16 location, UINT16 value)
|
||||||
|
{
|
||||||
|
image[(location&writeAddressMask)-this->location] = (value & trimmer);
|
||||||
|
}
|
||||||
|
|
||||||
|
RAMState RAM::getState(UINT16* image)
|
||||||
|
{
|
||||||
|
RAMState state = {0};
|
||||||
|
|
||||||
|
state.enabled = this->enabled;
|
||||||
|
state.size = this->size;
|
||||||
|
state.location = this->location;
|
||||||
|
state.readAddressMask = this->readAddressMask;
|
||||||
|
state.writeAddressMask = this->writeAddressMask;
|
||||||
|
state.bitWidth = this->bitWidth;
|
||||||
|
state.trimmer = this->trimmer;
|
||||||
|
|
||||||
|
if (image != NULL) {
|
||||||
|
this->getImage(image, 0, this->getImageByteSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RAM::setState(RAMState state, UINT16* image)
|
||||||
|
{
|
||||||
|
this->enabled = state.enabled;
|
||||||
|
this->size = state.size;
|
||||||
|
this->location = state.location;
|
||||||
|
this->readAddressMask = state.readAddressMask;
|
||||||
|
this->writeAddressMask = state.writeAddressMask;
|
||||||
|
this->bitWidth = state.bitWidth;
|
||||||
|
this->trimmer = state.trimmer;
|
||||||
|
|
||||||
|
if (image != NULL) {
|
||||||
|
this->setImage(image, 0, this->getImageByteSize());
|
||||||
|
}
|
||||||
|
}
|
72
arm9/source/emucore/RAM.h
Normal file
72
arm9/source/emucore/RAM.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
#ifndef RAM_H
|
||||||
|
#define RAM_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "Memory.h"
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _RAMState
|
||||||
|
{
|
||||||
|
INT8 enabled;
|
||||||
|
UINT8 bitWidth;
|
||||||
|
UINT16 size;
|
||||||
|
UINT16 location;
|
||||||
|
UINT16 readAddressMask;
|
||||||
|
UINT16 writeAddressMask;
|
||||||
|
UINT16 trimmer;
|
||||||
|
} RAMState; )
|
||||||
|
|
||||||
|
class RAM : public Memory
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
RAM(UINT16 size, UINT16 location);
|
||||||
|
RAM(UINT16 size, UINT16 location, UINT8 bitWidth);
|
||||||
|
RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask);
|
||||||
|
RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask, UINT8 bitWidth);
|
||||||
|
virtual ~RAM();
|
||||||
|
|
||||||
|
virtual void reset();
|
||||||
|
UINT8 getBitWidth();
|
||||||
|
|
||||||
|
UINT16 getReadSize();
|
||||||
|
UINT16 getReadAddress();
|
||||||
|
UINT16 getReadAddressMask();
|
||||||
|
virtual UINT16 peek(UINT16 location);
|
||||||
|
|
||||||
|
UINT16 getWriteSize();
|
||||||
|
UINT16 getWriteAddress();
|
||||||
|
UINT16 getWriteAddressMask();
|
||||||
|
virtual void poke(UINT16 location, UINT16 value);
|
||||||
|
|
||||||
|
inline size_t getImageByteSize() {
|
||||||
|
return size * sizeof(UINT16);
|
||||||
|
}
|
||||||
|
void getImage(void* dst, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(dst, image + offset, size);
|
||||||
|
}
|
||||||
|
void setImage(void* src, UINT16 offset, UINT16 size) {
|
||||||
|
memcpy(image + offset, src, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
RAMState getState(UINT16* image);
|
||||||
|
void setState(RAMState state, UINT16* image);
|
||||||
|
|
||||||
|
//enabled attributes
|
||||||
|
void SetEnabled(BOOL b);
|
||||||
|
BOOL IsEnabled() { return enabled; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
BOOL enabled;
|
||||||
|
UINT16 size;
|
||||||
|
UINT16 location;
|
||||||
|
UINT16 readAddressMask;
|
||||||
|
UINT16 writeAddressMask;
|
||||||
|
|
||||||
|
private:
|
||||||
|
UINT8 bitWidth;
|
||||||
|
UINT16 trimmer;
|
||||||
|
UINT16* image;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
174
arm9/source/emucore/ROM.ITCM.cpp
Normal file
174
arm9/source/emucore/ROM.ITCM.cpp
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ROM.h"
|
||||||
|
|
||||||
|
ROM::ROM(const CHAR* n, const CHAR* f, UINT32 o, UINT8 byteWidth, UINT16 size, UINT16 location, BOOL i)
|
||||||
|
: enabled(TRUE),
|
||||||
|
loaded(FALSE),
|
||||||
|
internal(i)
|
||||||
|
{
|
||||||
|
Initialize(n, f, o, byteWidth, size, location, 0xFFFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
ROM::ROM(const CHAR* n, void* image, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readAddressMask)
|
||||||
|
: enabled(TRUE),
|
||||||
|
loaded(TRUE),
|
||||||
|
internal(FALSE)
|
||||||
|
{
|
||||||
|
Initialize(n, "", 0, byteWidth, size, location, readAddressMask);
|
||||||
|
memcpy(this->image, image, size*byteWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ROM::Initialize(const CHAR* n, const CHAR* f, UINT32 o, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readMask)
|
||||||
|
{
|
||||||
|
name = new CHAR[strlen(n)+1];
|
||||||
|
strcpy(name, n);
|
||||||
|
filename = new CHAR[strlen(f)+1];
|
||||||
|
strcpy(filename, f);
|
||||||
|
fileoffset = o;
|
||||||
|
this->byteWidth = byteWidth;
|
||||||
|
this->multiByte = (byteWidth > 1) ? 1:0;
|
||||||
|
this->size = size;
|
||||||
|
this->location = location;
|
||||||
|
this->readAddressMask = readMask;
|
||||||
|
this->image = new UINT8[size*byteWidth];
|
||||||
|
peekFunc = (byteWidth == 1 ? &ROM::peek1 : (byteWidth == 2 ? &ROM::peek2 :
|
||||||
|
(byteWidth == 4 ? &ROM::peek4 : &ROM::peekN)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ROM::~ROM()
|
||||||
|
{
|
||||||
|
if (name)
|
||||||
|
delete[] name;
|
||||||
|
if (filename)
|
||||||
|
delete[] filename;
|
||||||
|
if (image)
|
||||||
|
delete[] image;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ROM::load(const char* filename)
|
||||||
|
{
|
||||||
|
return load(filename, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ROM::load(const char* filename, UINT32 offset)
|
||||||
|
{
|
||||||
|
FILE* f = fopen(filename, "rb");
|
||||||
|
if (!f)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
fseek(f, offset, SEEK_SET);
|
||||||
|
int byteCount = size*byteWidth;
|
||||||
|
int totalSize = 0;
|
||||||
|
while (totalSize < byteCount) {
|
||||||
|
for (UINT8 k = 0; k < byteWidth; k++)
|
||||||
|
((UINT8*)image)[totalSize+(byteWidth-k-1)] = (UINT8)fgetc(f);
|
||||||
|
totalSize += byteWidth;
|
||||||
|
}
|
||||||
|
fclose(f);
|
||||||
|
loaded = TRUE;
|
||||||
|
|
||||||
|
if (loaded) printf("Successful Load of [%s]\n", filename);
|
||||||
|
else printf("Unsuccessful Load of [%s]\n", filename);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL ROM::load(void* buffer)
|
||||||
|
{
|
||||||
|
UINT8* byteImage = (UINT8*)buffer;
|
||||||
|
int byteCount = size*byteWidth;
|
||||||
|
int totalSize = 0;
|
||||||
|
while (totalSize < byteCount) {
|
||||||
|
for (UINT8 k = 0; k < byteWidth; k++)
|
||||||
|
((UINT8*)image)[totalSize+(byteWidth-k-1)] = byteImage[totalSize+k];
|
||||||
|
totalSize += byteWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded = TRUE;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ROM::SetEnabled(BOOL b)
|
||||||
|
{
|
||||||
|
enabled = b;
|
||||||
|
if (enabled)
|
||||||
|
peekFunc = (byteWidth == 1 ? &ROM::peek1 : (byteWidth == 2 ? &ROM::peek2 :
|
||||||
|
(byteWidth == 4 ? &ROM::peek4 : &ROM::peekN)));
|
||||||
|
else
|
||||||
|
peekFunc = &ROM::peekN;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHAR* ROM::getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHAR* ROM::getDefaultFileName()
|
||||||
|
{
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 ROM::getDefaultFileOffset()
|
||||||
|
{
|
||||||
|
return fileoffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::getReadSize()
|
||||||
|
{
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::getReadAddress() {
|
||||||
|
return location;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::getReadAddressMask()
|
||||||
|
{
|
||||||
|
return readAddressMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::getWriteSize()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::getWriteAddress() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::getWriteAddressMask()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 ROM::getByteWidth()
|
||||||
|
{
|
||||||
|
return byteWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::peek1(UINT16 location)
|
||||||
|
{
|
||||||
|
return ((UINT8*)image)[(location&readAddressMask)-this->location];
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::peek2(UINT16 location)
|
||||||
|
{
|
||||||
|
return ((UINT16*)image)[(location&readAddressMask)-this->location];
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::peek4(UINT16 location)
|
||||||
|
{
|
||||||
|
return (UINT16)((UINT32*)image)[(location&readAddressMask)-this->location];
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 ROM::peekN(UINT16)
|
||||||
|
{
|
||||||
|
return 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ROM::poke(UINT16, UINT16)
|
||||||
|
{
|
||||||
|
//can't change ROM
|
||||||
|
}
|
||||||
|
|
73
arm9/source/emucore/ROM.h
Normal file
73
arm9/source/emucore/ROM.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
|
||||||
|
#ifndef ROM_H
|
||||||
|
#define ROM_H
|
||||||
|
|
||||||
|
#include "Memory.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class ROM : public Memory
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
ROM(const CHAR* name, const CHAR* defaultFilename, UINT32 defaultFileOffset, UINT8 byteWidth, UINT16 size, UINT16 location, BOOL internal = FALSE);
|
||||||
|
ROM(const CHAR* name, void* image, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readAddressMask = 0xFFFF);
|
||||||
|
virtual ~ROM();
|
||||||
|
|
||||||
|
const CHAR* getName();
|
||||||
|
const CHAR* getDefaultFileName();
|
||||||
|
UINT32 getDefaultFileOffset();
|
||||||
|
BOOL load(const CHAR* filename);
|
||||||
|
BOOL load(const CHAR* filename, UINT32 offset);
|
||||||
|
BOOL load(void* image);
|
||||||
|
BOOL isLoaded() { return loaded; }
|
||||||
|
BOOL isInternal() { return internal; }
|
||||||
|
|
||||||
|
//enabled attributes
|
||||||
|
void SetEnabled(BOOL b);
|
||||||
|
BOOL IsEnabled() { return enabled; }
|
||||||
|
|
||||||
|
//functions to implement the Memory interface
|
||||||
|
virtual void reset() {}
|
||||||
|
UINT8 getByteWidth();
|
||||||
|
|
||||||
|
UINT16 getReadSize();
|
||||||
|
UINT16 getReadAddress();
|
||||||
|
UINT16 getReadAddressMask();
|
||||||
|
inline virtual UINT16 peek(UINT16 location)
|
||||||
|
{
|
||||||
|
if (multiByte) return ((UINT16*)image)[(location)-this->location];
|
||||||
|
return ((UINT8*)image)[(location)-this->location];
|
||||||
|
// return (*this.*peekFunc)(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 getWriteSize();
|
||||||
|
UINT16 getWriteAddress();
|
||||||
|
UINT16 getWriteAddressMask();
|
||||||
|
virtual void poke(UINT16 location, UINT16 value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Initialize(const CHAR* n, const CHAR* f, UINT32 o, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readMask);
|
||||||
|
|
||||||
|
UINT16 (ROM::*peekFunc)(UINT16);
|
||||||
|
UINT16 peek1(UINT16 location);
|
||||||
|
UINT16 peek2(UINT16 location);
|
||||||
|
UINT16 peek4(UINT16 location);
|
||||||
|
UINT16 peekN(UINT16 location);
|
||||||
|
|
||||||
|
CHAR* name;
|
||||||
|
CHAR* filename;
|
||||||
|
UINT32 fileoffset;
|
||||||
|
|
||||||
|
UINT8* image;
|
||||||
|
UINT8 byteWidth;
|
||||||
|
UINT8 multiByte;
|
||||||
|
BOOL enabled;
|
||||||
|
UINT16 size;
|
||||||
|
UINT16 location;
|
||||||
|
UINT16 readAddressMask;
|
||||||
|
BOOL loaded;
|
||||||
|
BOOL internal;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
24
arm9/source/emucore/ROMBanker.cpp
Normal file
24
arm9/source/emucore/ROMBanker.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ROMBanker.h"
|
||||||
|
|
||||||
|
ROMBanker::ROMBanker(ROM* r, UINT16 address, UINT16 tm, UINT16 t, UINT16 mm, UINT16 m)
|
||||||
|
: RAM(1, address, 0, 0xFFFF),
|
||||||
|
rom(r),
|
||||||
|
triggerMask(tm),
|
||||||
|
trigger(t),
|
||||||
|
matchMask(mm),
|
||||||
|
match(m)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void ROMBanker::reset()
|
||||||
|
{
|
||||||
|
rom->SetEnabled(match == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ROMBanker::poke(UINT16, UINT16 value)
|
||||||
|
{
|
||||||
|
if ((value & triggerMask) == trigger)
|
||||||
|
rom->SetEnabled((value & matchMask) == match);
|
||||||
|
}
|
27
arm9/source/emucore/ROMBanker.h
Normal file
27
arm9/source/emucore/ROMBanker.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
#ifndef ROMBANKER_H
|
||||||
|
#define ROMBANKER_H
|
||||||
|
|
||||||
|
#include "RAM.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class ROMBanker : public RAM
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
ROMBanker(ROM* rom, UINT16 address, UINT16 triggerMask, UINT16 trigger, UINT16 matchMask, UINT16 match);
|
||||||
|
|
||||||
|
virtual void reset();
|
||||||
|
virtual void poke(UINT16 location, UINT16 value);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ROM* rom;
|
||||||
|
UINT16 triggerMask;
|
||||||
|
UINT16 trigger;
|
||||||
|
UINT16 matchMask;
|
||||||
|
UINT16 match;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
843
arm9/source/emucore/Rip.cpp
Normal file
843
arm9/source/emucore/Rip.cpp
Normal file
@ -0,0 +1,843 @@
|
|||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "Rip.h"
|
||||||
|
#include "RAM.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
#include "ROMBanker.h"
|
||||||
|
#include "CRC32.h"
|
||||||
|
|
||||||
|
#define MAX_MEMORY_UNITS 16
|
||||||
|
#define MAX_STRING_LENGTH 256
|
||||||
|
|
||||||
|
#define ROM_TAG_TITLE 0x01
|
||||||
|
#define ROM_TAG_PUBLISHER 0x02
|
||||||
|
#define ROM_TAG_RELEASE_DATE 0x05
|
||||||
|
#define ROM_TAG_COMPATIBILITY 0x06
|
||||||
|
|
||||||
|
Rip::Rip(UINT32 systemID)
|
||||||
|
: Peripheral("", ""),
|
||||||
|
peripheralCount(0),
|
||||||
|
targetSystemID(systemID),
|
||||||
|
crc(0)
|
||||||
|
{
|
||||||
|
producer = new CHAR[1];
|
||||||
|
strcpy(producer, "");
|
||||||
|
year = new CHAR[1];
|
||||||
|
strcpy(year, "");
|
||||||
|
memset(filename, 0, sizeof(filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
Rip::~Rip()
|
||||||
|
{
|
||||||
|
for (UINT16 i = 0; i < peripheralCount; i++)
|
||||||
|
delete[] peripheralNames[i];
|
||||||
|
UINT16 count = GetROMCount();
|
||||||
|
for (UINT16 i = 0; i < count; i++)
|
||||||
|
delete GetROM(i);
|
||||||
|
delete[] producer;
|
||||||
|
delete[] year;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rip::SetName(const CHAR* n)
|
||||||
|
{
|
||||||
|
if (this->peripheralName)
|
||||||
|
delete[] peripheralName;
|
||||||
|
|
||||||
|
peripheralName = new CHAR[strlen(n)+1];
|
||||||
|
strcpy(peripheralName, n);
|
||||||
|
printf("RIP Peripheral Name [%s]\n", peripheralName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rip::SetProducer(const CHAR* p)
|
||||||
|
{
|
||||||
|
if (this->producer)
|
||||||
|
delete[] producer;
|
||||||
|
|
||||||
|
producer = new CHAR[strlen(p)+1];
|
||||||
|
strcpy(producer, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rip::SetYear(const CHAR* y)
|
||||||
|
{
|
||||||
|
if (this->year)
|
||||||
|
delete[] year;
|
||||||
|
|
||||||
|
year = new CHAR[strlen(y)+1];
|
||||||
|
strcpy(year, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Rip::AddPeripheralUsage(const CHAR* periphName, PeripheralCompatibility usage)
|
||||||
|
{
|
||||||
|
peripheralNames[peripheralCount] = new CHAR[strlen(periphName)+1];
|
||||||
|
strcpy(peripheralNames[peripheralCount], periphName);
|
||||||
|
peripheralUsages[peripheralCount] = usage;
|
||||||
|
peripheralCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
PeripheralCompatibility Rip::GetPeripheralUsage(const CHAR* periphName)
|
||||||
|
{
|
||||||
|
for (UINT16 i = 0; i < peripheralCount; i++) {
|
||||||
|
if (strcmpi(peripheralNames[i], periphName) == 0)
|
||||||
|
return peripheralUsages[i];
|
||||||
|
}
|
||||||
|
return PERIPH_INCOMPATIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rip* Rip::LoadA52(const CHAR* filename)
|
||||||
|
{
|
||||||
|
Rip* rip = new Rip(ID_SYSTEM_ATARI5200);
|
||||||
|
if (rip == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//load the data into the rip
|
||||||
|
FILE* file = fopen(filename, "rb");
|
||||||
|
if (file == NULL) {
|
||||||
|
delete rip;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//obtain the file size
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
size_t size = ftell(file);
|
||||||
|
rewind(file);
|
||||||
|
|
||||||
|
//add an appropriate ROM to the rip
|
||||||
|
ROM* rom = new ROM("Cartridge ROM", "", 0, 1, (UINT16)size, (UINT16)(0xC000-size));
|
||||||
|
rip->AddROM(rom);
|
||||||
|
|
||||||
|
//load in the file image
|
||||||
|
UINT8* image = new UINT8[size];
|
||||||
|
UINT32 count = 0;
|
||||||
|
while (count < size)
|
||||||
|
image[count++] = (UINT8)fgetc(file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
//parse the file image into the rip
|
||||||
|
UINT32 offset = 0;
|
||||||
|
UINT16 romCount = rip->GetROMCount();
|
||||||
|
for (UINT16 i = 0; i < romCount; i++)
|
||||||
|
{
|
||||||
|
if (offset >= size) {
|
||||||
|
//something is wrong, the file we're trying to load isn't large enough
|
||||||
|
//getting here indicates a likely incorrect memory map in knowncarts.cfg
|
||||||
|
delete[] image;
|
||||||
|
delete rip;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ROM* nextRom = rip->GetROM(i);
|
||||||
|
nextRom->load(image+offset);
|
||||||
|
offset += nextRom->getByteWidth() * nextRom->getReadSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete[] image;
|
||||||
|
|
||||||
|
rip->SetFileName(filename);
|
||||||
|
rip->crc = CRC32::getCrc(filename);
|
||||||
|
|
||||||
|
return rip;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rip* Rip::LoadBin(const CHAR* filename, const CHAR* configFile)
|
||||||
|
{
|
||||||
|
//determine the crc of the designated file
|
||||||
|
UINT32 crc = CRC32::getCrc(filename);
|
||||||
|
Rip* rip = LoadCartridgeConfiguration(configFile, crc);
|
||||||
|
if (rip == NULL)
|
||||||
|
return NULL;
|
||||||
|
else printf("Configuration [%s] loaded successfully\n", configFile);
|
||||||
|
|
||||||
|
//load the data into the rip
|
||||||
|
FILE* file = fopen(filename, "rb");
|
||||||
|
if (file == NULL) {
|
||||||
|
delete rip;
|
||||||
|
return NULL;
|
||||||
|
} else printf("File [%s] read into memory successfully\n", filename);
|
||||||
|
|
||||||
|
//obtain the file size
|
||||||
|
fseek(file, 0, SEEK_END);
|
||||||
|
size_t size = ftell(file);
|
||||||
|
rewind(file);
|
||||||
|
printf("The file size is [%d] bytes\n", (int)size);
|
||||||
|
|
||||||
|
//load in the file image
|
||||||
|
UINT8* image = new UINT8[size];
|
||||||
|
UINT32 count = 0;
|
||||||
|
while (count < size)
|
||||||
|
image[count++] = (UINT8)fgetc(file);
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
printf("Parsing file into RIP format\n");
|
||||||
|
//parse the file image into the rip
|
||||||
|
UINT32 offset = 0;
|
||||||
|
UINT16 romCount = rip->GetROMCount();
|
||||||
|
for (UINT16 i = 0; i < romCount; i++)
|
||||||
|
{
|
||||||
|
if (offset >= size)
|
||||||
|
{
|
||||||
|
//something is wrong, the file we're trying to load isn't large enough
|
||||||
|
//getting here indicates a likely incorrect memory map in knowncarts.cfg
|
||||||
|
delete[] image;
|
||||||
|
delete rip;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
ROM* nextRom = rip->GetROM(i);
|
||||||
|
printf("Loading ROM segment [%s %d %d]\n", nextRom->getName(), nextRom->getByteWidth(), nextRom->getReadSize());
|
||||||
|
nextRom->load(image+offset);
|
||||||
|
offset += nextRom->getByteWidth() * nextRom->getReadSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Done parsing...\n");
|
||||||
|
delete[] image;
|
||||||
|
|
||||||
|
rip->SetFileName(filename);
|
||||||
|
rip->crc = CRC32::getCrc(filename);
|
||||||
|
|
||||||
|
printf("RIP loaded!\n");
|
||||||
|
return rip;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rip* Rip::LoadCartridgeConfiguration(const CHAR* configFile, UINT32 crc)
|
||||||
|
{
|
||||||
|
CHAR scrc[9];
|
||||||
|
sprintf(scrc, "%08X", crc);
|
||||||
|
|
||||||
|
//find the config that matches this crc
|
||||||
|
FILE* cfgFile = fopen(configFile, "r");
|
||||||
|
if (cfgFile == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
Rip* rip = NULL;
|
||||||
|
BOOL parseSuccess = FALSE;
|
||||||
|
CHAR nextLine[256];
|
||||||
|
while (!feof(cfgFile)) {
|
||||||
|
fgets(nextLine, 256, cfgFile);
|
||||||
|
//size_t length = strlen(nextLine);
|
||||||
|
if (strstr(nextLine, scrc) != nextLine) {
|
||||||
|
if (parseSuccess)
|
||||||
|
break;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
CHAR* nextToken;
|
||||||
|
if ((nextToken = strstr(nextLine, "Info")) != NULL) {
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (rip == NULL)
|
||||||
|
rip = new Rip(ID_SYSTEM_INTELLIVISION);
|
||||||
|
rip->SetYear(nextToken+1);
|
||||||
|
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
rip->SetProducer(nextToken+1);
|
||||||
|
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
rip->SetName(nextToken+1);
|
||||||
|
|
||||||
|
parseSuccess = TRUE;
|
||||||
|
}
|
||||||
|
else if ((nextToken = strstr(nextLine, "ROM")) != NULL) {
|
||||||
|
//TODO: check to make sure we don't exceed the maximum number of roms for a Rip
|
||||||
|
|
||||||
|
//parse rom bit width
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//first check to see if this is a banked rom; if there is an equals (=) sign in
|
||||||
|
//the last field, then we assume we should parse banking
|
||||||
|
UINT16 triggerAddress, triggerMask, triggerValue, onMask, onValue;
|
||||||
|
triggerAddress = triggerMask = triggerValue = onMask = onValue = 0;
|
||||||
|
CHAR* nextEqual = strrchr(nextLine, '=');
|
||||||
|
if (nextEqual != NULL && nextEqual > nextToken) {
|
||||||
|
onValue = (UINT16)strtol(nextEqual+1, NULL, 16);
|
||||||
|
*nextEqual = NULL;
|
||||||
|
onMask = (UINT16)strtol(nextToken+1, NULL, 16);
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
nextEqual = strrchr(nextLine, '=');
|
||||||
|
if (nextEqual == NULL || nextEqual < nextToken)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CHAR* nextComma = strrchr(nextLine, ',');
|
||||||
|
if (nextComma == NULL || nextComma < nextToken || nextComma > nextEqual)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
triggerValue = (UINT16)strtol(nextEqual+1, NULL, 16);
|
||||||
|
*nextEqual = NULL;
|
||||||
|
triggerMask = (UINT16)strtol(nextComma+1, NULL, 16);
|
||||||
|
*nextComma = NULL;
|
||||||
|
triggerAddress = (UINT16)strtol(nextToken+1, NULL, 16);
|
||||||
|
*nextToken = NULL;
|
||||||
|
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT8 romBitWidth = (UINT8)atoi(nextToken+1);
|
||||||
|
|
||||||
|
//parse rom size
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
UINT16 romSize = (UINT16)strtol(nextToken+1, NULL, 16);
|
||||||
|
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
UINT16 romAddress = (UINT16)strtol(nextToken+1, NULL, 16);
|
||||||
|
|
||||||
|
if (rip == NULL)
|
||||||
|
rip = new Rip(ID_SYSTEM_INTELLIVISION);
|
||||||
|
ROM* nextRom = new ROM("Cartridge ROM", "", 0, (romBitWidth+7)/8, romSize, romAddress);
|
||||||
|
rip->AddROM(nextRom);
|
||||||
|
if (triggerAddress != 0)
|
||||||
|
rip->AddRAM(new ROMBanker(nextRom, triggerAddress, triggerMask, triggerValue, onMask, onValue));
|
||||||
|
|
||||||
|
parseSuccess = TRUE;
|
||||||
|
}
|
||||||
|
else if ((nextToken = strstr(nextLine, "RAM")) != NULL) {
|
||||||
|
//TODO: check to make sure we don't exceed the maximum number of rams for a Rip
|
||||||
|
|
||||||
|
//parse ram width
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
UINT8 ramBitWidth = (UINT8)atoi(nextToken+1);
|
||||||
|
|
||||||
|
//parse ram size
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
UINT16 ramSize = (UINT16)strtol(nextToken+1, NULL, 16);
|
||||||
|
|
||||||
|
//parse ram address
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
UINT16 ramAddress = (UINT16)strtol(nextToken+1, NULL, 16);
|
||||||
|
|
||||||
|
if (rip == NULL)
|
||||||
|
rip = new Rip(ID_SYSTEM_INTELLIVISION);
|
||||||
|
rip->AddRAM(new RAM(ramSize, ramAddress, ramBitWidth));
|
||||||
|
parseSuccess = TRUE;
|
||||||
|
}
|
||||||
|
else if ((nextToken = strstr(nextLine, "Peripheral")) != NULL) {
|
||||||
|
//TODO: check to make sure we don't exceed the maximum number of peripherals for a Rip
|
||||||
|
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PeripheralCompatibility pc;
|
||||||
|
if (strcmpi(nextToken+1, "required") != 0)
|
||||||
|
pc = PERIPH_REQUIRED;
|
||||||
|
else if (strcmpi(nextToken+1, "optional") != 0)
|
||||||
|
pc = PERIPH_OPTIONAL;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*nextToken = NULL;
|
||||||
|
if ((nextToken = strrchr(nextLine, ':')) == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (rip == NULL)
|
||||||
|
rip = new Rip(ID_SYSTEM_INTELLIVISION);
|
||||||
|
rip->AddPeripheralUsage(nextToken+1, pc);
|
||||||
|
parseSuccess = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(cfgFile);
|
||||||
|
|
||||||
|
if (rip != NULL && !parseSuccess) {
|
||||||
|
delete rip;
|
||||||
|
rip = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rip;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rip* Rip::LoadRom(const CHAR* filename)
|
||||||
|
{
|
||||||
|
FILE* infile = fopen(filename, "rb");
|
||||||
|
if (infile == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read the magic byte (should always be $A8)
|
||||||
|
int read = fgetc(infile);
|
||||||
|
if (read != 0xA8) {
|
||||||
|
fclose(infile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//read the number of ROM segments
|
||||||
|
int romSegmentCount = fgetc(infile);
|
||||||
|
read = fgetc(infile);
|
||||||
|
if ((read ^ 0xFF) != romSegmentCount) {
|
||||||
|
fclose(infile);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rip* rip = new Rip(ID_SYSTEM_INTELLIVISION);
|
||||||
|
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < romSegmentCount; i++) {
|
||||||
|
UINT16 start = (UINT16)(fgetc(infile) << 8);
|
||||||
|
UINT16 end = (UINT16)((fgetc(infile) << 8) | 0xFF);
|
||||||
|
UINT16 size = (UINT16)((end-start)+1);
|
||||||
|
|
||||||
|
//finally, transfer the ROM image
|
||||||
|
UINT16* romImage = new UINT16[size];
|
||||||
|
int j;
|
||||||
|
for (j = 0; j < size; j++) {
|
||||||
|
int nextbyte = fgetc(infile) << 8;
|
||||||
|
nextbyte |= fgetc(infile);
|
||||||
|
romImage[j] = (UINT16)nextbyte;
|
||||||
|
}
|
||||||
|
rip->AddROM(new ROM("Cartridge ROM", romImage, 2, size, start, 0xFFFF));
|
||||||
|
delete[] romImage;
|
||||||
|
|
||||||
|
//read the CRC
|
||||||
|
fgetc(infile); fgetc(infile);
|
||||||
|
//TODO: validate the CRC16 instead of just skipping it
|
||||||
|
//int crc16 = (fgetc(infile) << 8) | fgetc(infile);
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
|
||||||
|
//no support currently for the access tables, so skip them
|
||||||
|
for (i = 0; i < 16; i++)
|
||||||
|
fgetc(infile);
|
||||||
|
|
||||||
|
//no support currently for the fine address restriction
|
||||||
|
//tables, so skip them, too
|
||||||
|
for (i = 0; i < 32; i++)
|
||||||
|
fgetc(infile);
|
||||||
|
|
||||||
|
while ((read = fgetc(infile)) != -1) {
|
||||||
|
int length = (read & 0x3F);
|
||||||
|
read = (read & 0xC) >> 6;
|
||||||
|
for (i = 0; i < read; i++)
|
||||||
|
length = (length | (fgetc(infile) << ((8*i)+6)));
|
||||||
|
|
||||||
|
int type = fgetc(infile);
|
||||||
|
int crc16;
|
||||||
|
switch (type) {
|
||||||
|
case ROM_TAG_TITLE:
|
||||||
|
{
|
||||||
|
CHAR* title = new char[length*sizeof(char)];
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
read = fgetc(infile);
|
||||||
|
title[i] = (char)read;
|
||||||
|
}
|
||||||
|
crc16 = (fgetc(infile) << 8) | fgetc(infile);
|
||||||
|
rip->SetName(title);
|
||||||
|
delete[] title;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ROM_TAG_PUBLISHER:
|
||||||
|
{
|
||||||
|
CHAR* publisher = new char[length*sizeof(char)];
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
read = fgetc(infile);
|
||||||
|
publisher[i] = (char)read;
|
||||||
|
}
|
||||||
|
crc16 = (fgetc(infile) << 8) | fgetc(infile);
|
||||||
|
rip->SetProducer(publisher);
|
||||||
|
|
||||||
|
delete[] publisher;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ROM_TAG_COMPATIBILITY:
|
||||||
|
{
|
||||||
|
read = fgetc(infile);
|
||||||
|
BOOL requiresECS = ((read & 0xC0) == 0x80);
|
||||||
|
if (requiresECS)
|
||||||
|
rip->AddPeripheralUsage("ECS", PERIPH_REQUIRED);
|
||||||
|
for (i = 0; i < length-1; i++) {
|
||||||
|
fgetc(infile);
|
||||||
|
fgetc(infile);
|
||||||
|
}
|
||||||
|
fgetc(infile);
|
||||||
|
fgetc(infile);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ROM_TAG_RELEASE_DATE:
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
for (i = 0; i < length; i++) {
|
||||||
|
fgetc(infile);
|
||||||
|
fgetc(infile);
|
||||||
|
}
|
||||||
|
fgetc(infile);
|
||||||
|
fgetc(infile);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(infile);
|
||||||
|
|
||||||
|
rip->SetFileName(filename);
|
||||||
|
rip->crc = CRC32::getCrc(filename);
|
||||||
|
|
||||||
|
return rip;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rip* Rip::LoadRip(const CHAR* filename)
|
||||||
|
{
|
||||||
|
FILE* file = fopen(filename, "rb");
|
||||||
|
if (file == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//first check the magic number
|
||||||
|
unsigned int nextUINT32 = freadUINT32(file);
|
||||||
|
if (nextUINT32 != 0x3F383A34) {
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
nextUINT32 = freadUINT32(file);
|
||||||
|
if (nextUINT32 != 0x7651B5DA) {
|
||||||
|
fclose(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//the magic number is good. this is definitely a RIP file
|
||||||
|
//start reading the records
|
||||||
|
Rip* rip = NULL;
|
||||||
|
unsigned int nextRecordID = freadUINT32(file);
|
||||||
|
while (!feof(file)) {
|
||||||
|
unsigned int nextRecordSize = freadUINT32(file);
|
||||||
|
switch (nextRecordID) {
|
||||||
|
case ID_HEADER_RECORD:
|
||||||
|
{
|
||||||
|
freadUINT16(file); //major file format version
|
||||||
|
freadUINT16(file); //minor file format version
|
||||||
|
UINT32 targetSystemID = freadUINT32(file); //target system
|
||||||
|
rip = new Rip(targetSystemID);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
case ID_BIOS_COMPAT_RECORD:
|
||||||
|
tmp1 = ripFile->biosCount;
|
||||||
|
ripFile->biosCompat[tmp1] =
|
||||||
|
malloc(sizeof(BiosCompatRecord));
|
||||||
|
ripFile->biosCompat[tmp1]->periphNum = fgetc(file);
|
||||||
|
ripFile->biosCompat[tmp1]->biosTypeNum = fgetc(file);
|
||||||
|
ripFile->biosCompat[tmp1]->biosNum = fgetc(file);
|
||||||
|
ripFile->biosCompat[tmp1]->compatibility = fgetc(file);
|
||||||
|
if (ripFile->biosCompat[tmp1]->compatibility > 2)
|
||||||
|
ripFile->biosCompat[tmp1]->compatibility = 2;
|
||||||
|
ripFile->biosCount++;
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
case ID_PERIPH_COMPAT_RECORD:
|
||||||
|
{
|
||||||
|
if (!rip)
|
||||||
|
return NULL;
|
||||||
|
UINT32 periphID = freadUINT32(file);
|
||||||
|
PeripheralCompatibility usage = (PeripheralCompatibility)(fgetc(file) & 0x03);
|
||||||
|
rip->AddPeripheralUsage((periphID == ID_PERIPH_ECS ? "ECS" : "Intellivoice"), usage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ID_NAME_RECORD:
|
||||||
|
{
|
||||||
|
if (!rip)
|
||||||
|
return NULL;
|
||||||
|
CHAR name[MAX_STRING_LENGTH];
|
||||||
|
freadString(file, name, MAX_STRING_LENGTH);
|
||||||
|
rip->SetName(name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ID_PRODUCER_RECORD:
|
||||||
|
{
|
||||||
|
if (!rip)
|
||||||
|
return NULL;
|
||||||
|
CHAR producer[MAX_STRING_LENGTH];
|
||||||
|
freadString(file, producer, MAX_STRING_LENGTH);
|
||||||
|
rip->SetProducer(producer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ID_YEAR_RECORD:
|
||||||
|
{
|
||||||
|
if (!rip)
|
||||||
|
return NULL;
|
||||||
|
CHAR year[MAX_STRING_LENGTH];
|
||||||
|
freadString(file, year, MAX_STRING_LENGTH);
|
||||||
|
rip->SetProducer(year);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ID_RAM_RECORD:
|
||||||
|
{
|
||||||
|
if (!rip)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//TODO: handle when we exceed maximum memory units
|
||||||
|
|
||||||
|
UINT8 flags = (UINT8)fgetc(file);
|
||||||
|
BOOL partialReads = !!(flags & 0x80);
|
||||||
|
BOOL partialWrites = !!(flags & 0x40);
|
||||||
|
BOOL banked = !!(flags & 0x20);
|
||||||
|
UINT8 addressByteWidth = (flags & 0x0F)+1;
|
||||||
|
|
||||||
|
flags = (UINT8)fgetc(file);
|
||||||
|
UINT8 dataBitWidth = (flags & 0x7F)+1;
|
||||||
|
UINT16 address = (UINT16)freadInt(file, addressByteWidth);
|
||||||
|
UINT16 size = (UINT16)freadInt(file, addressByteWidth);
|
||||||
|
//RAM reset value unused at this point, so skip it
|
||||||
|
freadInt(file, (dataBitWidth+7)/8);
|
||||||
|
|
||||||
|
UINT16 readMask = 0xFFFF;
|
||||||
|
if (partialReads)
|
||||||
|
readMask = (UINT16)freadInt(file, addressByteWidth);
|
||||||
|
|
||||||
|
UINT16 writeMask = 0xFFFF;
|
||||||
|
if (partialWrites)
|
||||||
|
writeMask = (UINT16)freadInt(file, addressByteWidth);
|
||||||
|
|
||||||
|
if (banked) {
|
||||||
|
//banking descriptors not yet supported, so just need to skip 'em
|
||||||
|
UINT32 bankingDescriptorCount = freadUINT32(file);
|
||||||
|
for (UINT32 k = 0; k < bankingDescriptorCount; k++) {
|
||||||
|
freadInt(file, addressByteWidth); //target address width
|
||||||
|
freadInt(file, addressByteWidth); //write decoding mask
|
||||||
|
freadInt(file, (dataBitWidth+7)/8); //reset value
|
||||||
|
UINT32 dataCount = freadUINT32(file);
|
||||||
|
for (UINT32 l = 0; l < dataCount; l++)
|
||||||
|
freadInt(file, (dataBitWidth+7)/8); //data banking match values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rip->AddRAM(new RAM(size, address, readMask, writeMask, dataBitWidth));
|
||||||
|
}
|
||||||
|
case ID_ROM_RECORD:
|
||||||
|
{
|
||||||
|
if (!rip)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
//TODO: handle when we exceed maximum memory units
|
||||||
|
|
||||||
|
UINT8 flags = (UINT8)fgetc(file);
|
||||||
|
BOOL partialReads = !!(flags & 0x80);
|
||||||
|
BOOL compressed = !!(flags & 0x40);
|
||||||
|
BOOL banked = !!(flags & 0x20);
|
||||||
|
UINT8 addressByteWidth = (flags & 0x0F)+1;
|
||||||
|
|
||||||
|
flags = (UINT8)fgetc(file);
|
||||||
|
UINT8 dataBitWidth = (flags & 0x7F)+1;
|
||||||
|
UINT16 address = (UINT16)freadInt(file, addressByteWidth);
|
||||||
|
|
||||||
|
UINT32 arraySize = freadUINT32(file);
|
||||||
|
UINT8* romImage = NULL;
|
||||||
|
if (compressed) {
|
||||||
|
//TODO: support zlib compressed rom images
|
||||||
|
for (UINT32 k = 0; k < arraySize; k++)
|
||||||
|
fgetc(file);
|
||||||
|
arraySize = 0;
|
||||||
|
romImage = new UINT8[0];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
UINT32 dataByteWidth = (dataBitWidth+7)/8;
|
||||||
|
romImage = new UINT8[arraySize*dataByteWidth];
|
||||||
|
for (UINT32 k = 0; k < arraySize; k++) {
|
||||||
|
for (UINT8 l = 0; l < dataByteWidth; l++)
|
||||||
|
romImage[(k*dataByteWidth)+(dataByteWidth-l-1)] = (UINT8)fgetc(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 readMask = 0xFFFF;
|
||||||
|
if (partialReads)
|
||||||
|
readMask = (UINT16)freadInt(file, addressByteWidth);
|
||||||
|
|
||||||
|
if (banked) {
|
||||||
|
//banking descriptors not yet supported, so just need to skip 'em
|
||||||
|
UINT32 bankingDescriptorCount = freadUINT32(file);
|
||||||
|
for (UINT32 k = 0; k < bankingDescriptorCount; k++) {
|
||||||
|
freadInt(file, addressByteWidth); //target address width
|
||||||
|
freadInt(file, addressByteWidth); //write decoding mask
|
||||||
|
freadInt(file, (dataBitWidth+7)/8); //reset value
|
||||||
|
UINT32 dataCount = freadUINT32(file);
|
||||||
|
for (UINT32 l = 0; l < dataCount; l++)
|
||||||
|
freadInt(file, (dataBitWidth+7)/8); //data banking match values
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rip->AddROM(new ROM("Cartridge ROM", (void*)romImage, (dataBitWidth+7)/8, (UINT16)arraySize, address, readMask));
|
||||||
|
delete[] romImage;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
//unknown record; just skip it
|
||||||
|
for (UINT32 i = 0; i < nextRecordSize; i++)
|
||||||
|
fgetc(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nextRecordID = freadUINT32(file);
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
rip->SetFileName(filename);
|
||||||
|
rip->crc = CRC32::getCrc(filename);
|
||||||
|
|
||||||
|
return rip;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BOOL Rip::SaveRip(const CHAR* filename)
|
||||||
|
{
|
||||||
|
FILE* file = fopen(filename, "wb");
|
||||||
|
if (file == NULL) {
|
||||||
|
printf("Error: Unable to create file %s\n", filename);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//write the 64-bit magic RIP XBF number
|
||||||
|
fwriteUINT64(file, RIP_MAGIC_NUMBER);
|
||||||
|
|
||||||
|
//write the header record
|
||||||
|
fwriteUINT32(file, ID_HEADER_RECORD);
|
||||||
|
//write the header record size in bytes
|
||||||
|
fwriteUINT32(file, 9);
|
||||||
|
//write the major RIP revision number
|
||||||
|
fwriteUINT16(file, RIP_MAJOR_REVISION);
|
||||||
|
//write the minor RIP revision number
|
||||||
|
fwriteUINT16(file, RIP_MINOR_REVISION);
|
||||||
|
//write the system id
|
||||||
|
fwriteUINT32(file, targetSystemID);
|
||||||
|
|
||||||
|
//write the name record
|
||||||
|
fwriteUINT32(file, ID_NAME_RECORD);
|
||||||
|
fwriteUINT32(file, (UINT32)(4+strlen(GetName())));
|
||||||
|
fwriteString(file, GetName());
|
||||||
|
|
||||||
|
//write the year record
|
||||||
|
fwriteUINT32(file, ID_YEAR_RECORD);
|
||||||
|
fwriteUINT32(file, (UINT32)(4+strlen(year)));
|
||||||
|
fwriteString(file, year);
|
||||||
|
|
||||||
|
//write the producer record
|
||||||
|
fwriteUINT32(file, ID_PRODUCER_RECORD);
|
||||||
|
fwriteUINT32(file, (UINT32)(4+strlen(producer)));
|
||||||
|
fwriteString(file, producer);
|
||||||
|
|
||||||
|
//write the peripheral compatibility records
|
||||||
|
for (UINT16 i = 0; i < peripheralCount; i++) {
|
||||||
|
fwriteUINT32(file, ID_PERIPH_COMPAT_RECORD);
|
||||||
|
fwriteUINT32(file, 5);
|
||||||
|
//these records are hard-coded for Intellivision now, will have to work out something more
|
||||||
|
//flexible when Atari 5200 support is re-added in the future
|
||||||
|
fwriteUINT32(file, (strcmpi(peripheralNames[i], "Intellivoice") == 0) ? ID_PERIPH_INTELLIVOICE : ID_PERIPH_ECS);
|
||||||
|
fputc(peripheralUsages[i], file);
|
||||||
|
}
|
||||||
|
|
||||||
|
//write the RAM records
|
||||||
|
UINT16 ramCount = GetRAMCount();
|
||||||
|
for (UINT16 i = 0; i < ramCount; i++) {
|
||||||
|
RAM* nextMem = GetRAM(i);
|
||||||
|
fwriteUINT32(file, ID_RAM_RECORD);
|
||||||
|
UINT16 readMask = nextMem->getReadAddressMask();
|
||||||
|
UINT16 writeMask = nextMem->getWriteAddressMask();
|
||||||
|
UINT16 byteWidth = (nextMem->getBitWidth()+7)/8;
|
||||||
|
|
||||||
|
//calculate the size of the RAM record
|
||||||
|
int recordSize = 1 + //flags
|
||||||
|
1 + //more flags
|
||||||
|
2 + //address
|
||||||
|
2 + //size
|
||||||
|
byteWidth + //reset value
|
||||||
|
(readMask != 0xFFFF ? 2 : 0) + //read mask
|
||||||
|
(writeMask != 0xFFFF ? 2 : 0) + //write mask
|
||||||
|
0; //banking not supported just yet
|
||||||
|
fwriteUINT32(file, recordSize);
|
||||||
|
|
||||||
|
//flags #1
|
||||||
|
fputc(((readMask != 0xFFFF) ? 0x80 : 0) |
|
||||||
|
((writeMask != 0xFFFF) ? 0x40 : 0) |
|
||||||
|
1, file);
|
||||||
|
|
||||||
|
//flags #2
|
||||||
|
fputc(nextMem->getBitWidth()-1, file);
|
||||||
|
|
||||||
|
//address
|
||||||
|
fwriteUINT16(file, nextMem->getReadAddress());
|
||||||
|
|
||||||
|
//size
|
||||||
|
fwriteUINT16(file, nextMem->getReadSize());
|
||||||
|
|
||||||
|
//reset value, always zero
|
||||||
|
for (UINT16 k = 0; k < byteWidth; k++)
|
||||||
|
fputc(0, file);
|
||||||
|
|
||||||
|
//read mask
|
||||||
|
if (readMask != 0xFFFF)
|
||||||
|
fwriteUINT16(file, readMask);
|
||||||
|
|
||||||
|
//write mask
|
||||||
|
if (writeMask != 0xFFFF)
|
||||||
|
fwriteUINT16(file, writeMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
//write the ROM records
|
||||||
|
UINT16 romCount = GetROMCount();
|
||||||
|
for (UINT16 i = 0; i < romCount; i++) {
|
||||||
|
ROM* nextMem = GetROM(i);
|
||||||
|
fwriteUINT32(file, ID_ROM_RECORD);
|
||||||
|
|
||||||
|
//calculate the size of the ROM record
|
||||||
|
UINT16 readMask = nextMem->getReadAddressMask();
|
||||||
|
UINT16 byteWidth = nextMem->getByteWidth();
|
||||||
|
UINT16 memSize = nextMem->getReadSize();
|
||||||
|
int recordSize = 1 + //flags
|
||||||
|
1 + //more flags
|
||||||
|
2 + //address
|
||||||
|
4 + (byteWidth*memSize) + //ROM image
|
||||||
|
(readMask != 0xFFFF ? 2 : 0) + //read mask
|
||||||
|
0; //banking not supported just yet
|
||||||
|
fwriteUINT32(file, recordSize);
|
||||||
|
|
||||||
|
//flags #1
|
||||||
|
fputc(((readMask != 0xFFFF) ? 0x80 : 0) |
|
||||||
|
1, file);
|
||||||
|
|
||||||
|
//flags #2
|
||||||
|
fputc((byteWidth*8)-1, file);
|
||||||
|
|
||||||
|
//address
|
||||||
|
UINT16 address = nextMem->getReadAddress();
|
||||||
|
fwriteUINT16(file, address);
|
||||||
|
|
||||||
|
//ROM image
|
||||||
|
fwriteUINT32(file, memSize);
|
||||||
|
for (UINT16 j = 0; j < memSize; j++) {
|
||||||
|
switch (byteWidth) {
|
||||||
|
case 1:
|
||||||
|
fputc(nextMem->peek(address+j), file);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
fwriteUINT16(file, nextMem->peek(address+j));
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
fwriteUINT32(file, nextMem->peek(address+j));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for (UINT8 k = 0; k < byteWidth; k++)
|
||||||
|
fputc(0, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//read mask
|
||||||
|
if (readMask != 0xFFFF)
|
||||||
|
fwriteUINT16(file, readMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
87
arm9/source/emucore/Rip.h
Normal file
87
arm9/source/emucore/Rip.h
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
|
||||||
|
#ifndef RIP_H
|
||||||
|
#define RIP_H
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <vector>
|
||||||
|
#include "ripxbf.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "Peripheral.h"
|
||||||
|
#include "Memory.h"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
#define MAX_BIOSES 16
|
||||||
|
#define MAX_PERIPHERALS 16
|
||||||
|
|
||||||
|
typedef struct _CartridgeConfiguration CartridgeConfiguration;
|
||||||
|
|
||||||
|
class Rip : public Peripheral
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~Rip();
|
||||||
|
|
||||||
|
void SetTargetSystemID(UINT32 t) { this->targetSystemID = t; }
|
||||||
|
UINT32 GetTargetSystemID() { return targetSystemID; }
|
||||||
|
|
||||||
|
void SetName(const CHAR* p);
|
||||||
|
|
||||||
|
void SetProducer(const CHAR* p);
|
||||||
|
const CHAR* GetProducer() { return producer; }
|
||||||
|
|
||||||
|
void SetYear(const CHAR* y);
|
||||||
|
const CHAR* GetYear() { return year; }
|
||||||
|
|
||||||
|
PeripheralCompatibility GetPeripheralUsage(const CHAR* periphName);
|
||||||
|
|
||||||
|
//load a regular .rip file
|
||||||
|
static Rip* LoadRip(const CHAR* filename);
|
||||||
|
|
||||||
|
//load a raw binary Atari 5200 image of a game
|
||||||
|
static Rip* LoadA52(const CHAR* filename);
|
||||||
|
|
||||||
|
//load a raw binary Intellivision image of a game
|
||||||
|
static Rip* LoadBin(const CHAR* filename, const CHAR* cfgFilename);
|
||||||
|
|
||||||
|
//load a raw binary image contained within a .zip file
|
||||||
|
static Rip* LoadZip(const CHAR* filename, const CHAR* cfgFilename);
|
||||||
|
|
||||||
|
//load an Intellivision .rom file
|
||||||
|
static Rip* LoadRom(const CHAR* filename);
|
||||||
|
|
||||||
|
BOOL SaveRip(const CHAR* filename);
|
||||||
|
|
||||||
|
const CHAR* GetFileName() {
|
||||||
|
return this->filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 GetCRC() {
|
||||||
|
return this->crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Rip(UINT32 systemID);
|
||||||
|
//Rip(UINT32 systemID, const CHAR* nme, const CHAR* prducer, const CHAR* yr);
|
||||||
|
|
||||||
|
void AddPeripheralUsage(const CHAR* periphName, PeripheralCompatibility usage);
|
||||||
|
static Rip* LoadCartridgeConfiguration(const CHAR* cfgFile, UINT32 crc);
|
||||||
|
|
||||||
|
void SetFileName(const CHAR* fname) {
|
||||||
|
strncpy(this->filename, fname, sizeof(this->filename));
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 targetSystemID;
|
||||||
|
CHAR* producer;
|
||||||
|
CHAR* year;
|
||||||
|
|
||||||
|
//peripheral compatibility indicators
|
||||||
|
CHAR* peripheralNames[MAX_PERIPHERALS];
|
||||||
|
PeripheralCompatibility peripheralUsages[MAX_PERIPHERALS];
|
||||||
|
UINT32 peripheralCount;
|
||||||
|
|
||||||
|
CHAR filename[MAX_PATH];
|
||||||
|
UINT32 crc;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
956
arm9/source/emucore/SP0256.cpp
Normal file
956
arm9/source/emucore/SP0256.cpp
Normal file
@ -0,0 +1,956 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include "SP0256.h"
|
||||||
|
|
||||||
|
INT32 repeat __attribute__((section(".dtcm")));
|
||||||
|
INT32 period __attribute__((section(".dtcm")));
|
||||||
|
INT32 periodCounter __attribute__((section(".dtcm")));
|
||||||
|
INT32 amplitude __attribute__((section(".dtcm")));
|
||||||
|
INT8 b[6] __attribute__((section(".dtcm")));
|
||||||
|
INT8 f[6] __attribute__((section(".dtcm")));
|
||||||
|
INT32 y[6][2] __attribute__((section(".dtcm")));
|
||||||
|
INT8 periodInterpolation __attribute__((section(".dtcm")));
|
||||||
|
INT8 amplitudeInterpolation __attribute__((section(".dtcm")));
|
||||||
|
|
||||||
|
|
||||||
|
UINT16 bitMasks[16] __attribute__((section(".dtcm"))) = {
|
||||||
|
0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
|
||||||
|
0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
|
||||||
|
|
||||||
|
INT16 qtbl[256] __attribute__((section(".dtcm"))) = {
|
||||||
|
0, 511, 510, 509, 508, 507, 506, 505,
|
||||||
|
504, 503, 502, 501, 500, 499, 498, 497,
|
||||||
|
496, 495, 494, 493, 492, 491, 490, 489,
|
||||||
|
488, 487, 486, 485, 484, 483, 482, 481,
|
||||||
|
479, 477, 475, 473, 471, 469, 467, 465,
|
||||||
|
463, 461, 459, 457, 455, 453, 451, 449,
|
||||||
|
447, 445, 443, 441, 439, 437, 435, 433,
|
||||||
|
431, 429, 427, 425, 421, 417, 413, 409,
|
||||||
|
405, 401, 397, 393, 389, 385, 381, 377,
|
||||||
|
373, 369, 365, 361, 357, 353, 349, 345,
|
||||||
|
341, 337, 333, 329, 325, 321, 317, 313,
|
||||||
|
309, 305, 301, 297, 289, 281, 273, 265,
|
||||||
|
257, 249, 241, 233, 225, 217, 209, 201,
|
||||||
|
193, 185, 177, 169, 161, 153, 145, 137,
|
||||||
|
129, 121, 113, 105, 97, 89, 81, 73,
|
||||||
|
65, 57, 49, 41, 33, 25, 12, 9,
|
||||||
|
0, -9, -12, -25, -33, -41, -49, -57,
|
||||||
|
-65, -73, -81, -89, -97, -105, -113, -121,
|
||||||
|
-129, -137, -145, -153, -161, -169, -177, -185,
|
||||||
|
-193, -201, -209, -217, -225, -233, -241, -249,
|
||||||
|
-257, -265, -273, -281, -289, -297, -301, -305,
|
||||||
|
-309, -313, -317, -321, -325, -329, -333, -337,
|
||||||
|
-341, -345, -349, -353, -357, -361, -365, -369,
|
||||||
|
-373, -377, -381, -385, -389, -393, -397, -401,
|
||||||
|
-405, -409, -413, -417, -421, -425, -427, -429,
|
||||||
|
-431, -433, -435, -437, -439, -441, -443, -445,
|
||||||
|
-447, -449, -451, -453, -455, -457, -459, -461,
|
||||||
|
-463, -465, -467, -469, -471, -473, -475, -477,
|
||||||
|
-479, -481, -482, -483, -484, -485, -486, -487,
|
||||||
|
-488, -489, -490, -491, -492, -493, -494, -495,
|
||||||
|
-496, -497, -498, -499, -500, -501, -502, -503,
|
||||||
|
-504, -505, -506, -507, -508, -509, -510, -511
|
||||||
|
};
|
||||||
|
|
||||||
|
SP0256::SP0256()
|
||||||
|
: Processor("SP0256"),
|
||||||
|
ivoiceROM("Intellivoice ROM", "ivoice.bin", 0, 1, 0x800, 0x1000, TRUE)
|
||||||
|
{
|
||||||
|
registers.init(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 SP0256::getClockSpeed() {
|
||||||
|
return 10000;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 SP0256::getClocksPerSample() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::resetProcessor()
|
||||||
|
{
|
||||||
|
currentBits = 0;
|
||||||
|
bitsLeft = 0;
|
||||||
|
|
||||||
|
pc = 0;
|
||||||
|
page = 1;
|
||||||
|
stack = 0;
|
||||||
|
mode = 0;
|
||||||
|
repeatPrefix = 0;
|
||||||
|
command = 0;
|
||||||
|
lrqHigh = TRUE;
|
||||||
|
idle = TRUE;
|
||||||
|
fifoHead = 0;
|
||||||
|
fifoSize = 0;
|
||||||
|
speaking = FALSE;
|
||||||
|
|
||||||
|
amplitude = 0;
|
||||||
|
period = 0;
|
||||||
|
periodCounter = 0x1;
|
||||||
|
random = 1;
|
||||||
|
for (INT32 i = 0; i < 6; i++) {
|
||||||
|
y[i][0] = 0;
|
||||||
|
y[i][1] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 SP0256::tick(INT32 minimum)
|
||||||
|
{
|
||||||
|
if (idle) {
|
||||||
|
//for (int i = 0; i < minimum; i++)
|
||||||
|
// audioOutputLine->playSample(0);
|
||||||
|
return minimum;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 totalTicks = 0;
|
||||||
|
do {
|
||||||
|
|
||||||
|
if (!speaking) {
|
||||||
|
speaking = TRUE;
|
||||||
|
lrqHigh = TRUE;
|
||||||
|
pc = 0x1000 | (command << 1);
|
||||||
|
bitsLeft = 0;
|
||||||
|
command = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the speaking filters are empty, fill 'em up
|
||||||
|
while (!idle && repeat == 0) {
|
||||||
|
INT32 repeatBefore = repeatPrefix;
|
||||||
|
decode();
|
||||||
|
if (repeatBefore != 0)
|
||||||
|
repeatPrefix = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 sample = 0;
|
||||||
|
if (period == 0) {
|
||||||
|
if (periodCounter == 0) {
|
||||||
|
periodCounter = 64;
|
||||||
|
repeat--;
|
||||||
|
for (UINT8 j = 0; j < 6; j++)
|
||||||
|
y[j][0] = y[j][1] = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
periodCounter--;
|
||||||
|
|
||||||
|
sample = ((amplitude & 0x1F) << ((amplitude & 0xE0) >> 5));
|
||||||
|
BOOL noise = ((random & 1) != 0);
|
||||||
|
random = (random >> 1) ^ (noise ? 0x14000 : 0);
|
||||||
|
if (!noise)
|
||||||
|
sample = -sample;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (periodCounter == 0) {
|
||||||
|
periodCounter = period;
|
||||||
|
repeat--;
|
||||||
|
sample = ((amplitude & 0x1F) << ((amplitude & 0xE0) >> 5));
|
||||||
|
for (INT32 j = 0; j < 6; j++)
|
||||||
|
y[j][0] = y[j][1] = 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
periodCounter--;
|
||||||
|
}
|
||||||
|
|
||||||
|
period = ((period | 0x10000) + periodInterpolation) & 0xFFFF;
|
||||||
|
amplitude = ((amplitude | 0x10000) + amplitudeInterpolation) & 0xFFFF;
|
||||||
|
|
||||||
|
for (INT32 i = 0; i < 6; i++) {
|
||||||
|
sample += ((qtbl[0x80+b[i]]*y[i][1]) >> 9);
|
||||||
|
sample += ((qtbl[0x80+f[i]]*y[i][0]) >> 8);
|
||||||
|
y[i][1] = y[i][0];
|
||||||
|
y[i][0] = sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
//clamp the sample to a 12-bit range
|
||||||
|
if (sample > 2047) sample = 2047;
|
||||||
|
if (sample < -2048) sample = -2048;
|
||||||
|
|
||||||
|
audioOutputLine->playSample((INT16)(sample << 4));
|
||||||
|
|
||||||
|
totalTicks++;
|
||||||
|
|
||||||
|
} while (totalTicks < minimum);
|
||||||
|
return totalTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT8 SP0256::readDelta(INT32 numBits) {
|
||||||
|
INT32 value = readBits(numBits);
|
||||||
|
if ((value & (1 << (numBits - 1))) != 0)
|
||||||
|
value |= -1 << numBits;
|
||||||
|
return (INT8)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 SP0256::readBitsReverse(INT32 numBits)
|
||||||
|
{
|
||||||
|
while (bitsLeft < numBits) {
|
||||||
|
if (pc < 0x1800) {
|
||||||
|
currentBits |= (ivoiceROM.peek((UINT16)pc) << bitsLeft);
|
||||||
|
bitsLeft += 8;
|
||||||
|
pc = (pc+1) & 0xFFFF;
|
||||||
|
}
|
||||||
|
else if (pc == 0x1800 && fifoSize > 0) {
|
||||||
|
currentBits |= (fifoBytes[fifoHead] << bitsLeft);
|
||||||
|
fifoHead = (fifoHead+1) & 0x3F;
|
||||||
|
fifoSize--;
|
||||||
|
bitsLeft += 10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//error, read outside of bounds
|
||||||
|
currentBits |= (0x03FF << bitsLeft);
|
||||||
|
bitsLeft += 10;
|
||||||
|
pc = (pc+1) & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 output = currentBits & bitMasks[numBits-1];
|
||||||
|
output = flipEndian(output, numBits);
|
||||||
|
currentBits = currentBits >> numBits;
|
||||||
|
bitsLeft -= numBits;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 SP0256::readBits(INT32 numBits)
|
||||||
|
{
|
||||||
|
while (bitsLeft < numBits) {
|
||||||
|
if (pc < 0x1800) {
|
||||||
|
currentBits |= (ivoiceROM.peek((UINT16)pc) << bitsLeft);
|
||||||
|
bitsLeft += 8;
|
||||||
|
pc = (pc+1) & 0xFFFF;
|
||||||
|
}
|
||||||
|
else if (pc == 0x1800 && fifoSize > 0) {
|
||||||
|
currentBits |= (fifoBytes[fifoHead] << bitsLeft);
|
||||||
|
fifoHead = (fifoHead+1) & 0x3F;
|
||||||
|
fifoSize--;
|
||||||
|
bitsLeft += 10;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//error, read outside of bounds
|
||||||
|
currentBits |= (0x03FF << bitsLeft);
|
||||||
|
bitsLeft += 10;
|
||||||
|
pc = (pc+1) & 0xFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 output = currentBits & bitMasks[numBits-1];
|
||||||
|
currentBits = currentBits >> numBits;
|
||||||
|
bitsLeft -= numBits;
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::RTS() {
|
||||||
|
if (stack == 0) {
|
||||||
|
if (!lrqHigh) {
|
||||||
|
pc = 0x1000 | (command << 1);
|
||||||
|
bitsLeft = 0;
|
||||||
|
command = 0;
|
||||||
|
lrqHigh = TRUE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
speaking = FALSE;
|
||||||
|
idle = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
pc = stack;
|
||||||
|
stack = 0;
|
||||||
|
bitsLeft = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::SETPAGE(INT32 immed4) {
|
||||||
|
this->page = flipEndian(immed4, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::LOADALL(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = readBits(8);
|
||||||
|
period = readBits(8);
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
b[0] = (INT8)readBits(8);
|
||||||
|
f[0] = (INT8)readBits(8);
|
||||||
|
b[1] = (INT8)readBits(8);
|
||||||
|
f[1] = (INT8)readBits(8);
|
||||||
|
b[2] = (INT8)readBits(8);
|
||||||
|
f[2] = (INT8)readBits(8);
|
||||||
|
b[3] = (INT8)readBits(8);
|
||||||
|
f[3] = (INT8)readBits(8);
|
||||||
|
b[4] = (INT8)readBits(8);
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
if ((mode & 0x01) == 0) {
|
||||||
|
amplitudeInterpolation = 0;
|
||||||
|
periodInterpolation = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
amplitudeInterpolation = (INT8)readBits(8);
|
||||||
|
periodInterpolation = (INT8)readBits(8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::LOAD_2(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
period = readBits(8);
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
|
||||||
|
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
|
||||||
|
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
|
||||||
|
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
|
||||||
|
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
|
||||||
|
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
|
||||||
|
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
|
||||||
|
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
|
||||||
|
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
|
||||||
|
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
|
||||||
|
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
|
||||||
|
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
|
||||||
|
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
b[5] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
|
||||||
|
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
|
||||||
|
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
|
||||||
|
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
|
||||||
|
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
|
||||||
|
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
|
||||||
|
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
b[4] = (INT8)readBits(8);
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
|
||||||
|
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
|
||||||
|
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
|
||||||
|
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
|
||||||
|
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
|
||||||
|
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
|
||||||
|
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
b[4] = (INT8)readBits(8);
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
amplitudeInterpolation = (INT8)
|
||||||
|
((amplitudeInterpolation & 0xE0) | (readBits(5)));
|
||||||
|
periodInterpolation = (INT8)
|
||||||
|
((periodInterpolation & 0xE0) | (readBits(5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::SETMSB_3(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
if (mode == 0x00 || mode == 0x02) {
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x1:
|
||||||
|
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
|
||||||
|
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
|
||||||
|
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
case 0x3:
|
||||||
|
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
|
||||||
|
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
|
||||||
|
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
amplitudeInterpolation = (INT8)
|
||||||
|
((amplitudeInterpolation & 0xE0) | (readBits(5)));
|
||||||
|
periodInterpolation = (INT8)
|
||||||
|
((periodInterpolation & 0xE0) | (readBits(5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::LOAD_4(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
period = readBits(8);
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
b[0] = 0;
|
||||||
|
f[0] = 0;
|
||||||
|
b[1] = 0;
|
||||||
|
f[1] = 0;
|
||||||
|
b[2] = 0;
|
||||||
|
f[2] = 0;
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
b[5] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
b[4] = (INT8)readBits(8);
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
b[4] = (INT8)readBits(8);
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
amplitudeInterpolation = 0;
|
||||||
|
periodInterpolation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::SETMSB_5(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
period = readBits(8);
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
if (mode == 0x00 || mode == 0x02) {
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x1:
|
||||||
|
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
|
||||||
|
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
|
||||||
|
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
case 0x3:
|
||||||
|
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
|
||||||
|
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
|
||||||
|
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::SETMSB_6(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
if (mode == 0x00 || mode == 0x02) {
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::JMP(INT32 immed4) {
|
||||||
|
pc = (page << 12) | (flipEndian(immed4, 4) << 8) | readBitsReverse(8);
|
||||||
|
bitsLeft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::SETMODE(INT32 immed4) {
|
||||||
|
immed4 = flipEndian(immed4, 4);
|
||||||
|
mode = immed4 & 0x3;
|
||||||
|
repeatPrefix = (immed4 & 0xC) >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::DELTA_9(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (amplitude + 0x10000 + (readDelta(4) << 2))
|
||||||
|
& 0xFFFF;
|
||||||
|
period = (period + 0x10000 + readDelta(5)) & 0xFFFF;
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
b[0] += readDelta(3) << 4;
|
||||||
|
f[0] += readDelta(3) << 3;
|
||||||
|
b[1] += readDelta(3) << 4;
|
||||||
|
f[1] += readDelta(3) << 3;
|
||||||
|
b[2] += readDelta(3) << 4;
|
||||||
|
f[2] += readDelta(3) << 3;
|
||||||
|
b[3] += readDelta(3) << 3;
|
||||||
|
f[3] += readDelta(4) << 2;
|
||||||
|
b[4] += readDelta(4) << 1;
|
||||||
|
f[4] += readDelta(4) << 2;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
b[0] += readDelta(3) << 4;
|
||||||
|
f[0] += readDelta(3) << 3;
|
||||||
|
b[1] += readDelta(3) << 4;
|
||||||
|
f[1] += readDelta(3) << 3;
|
||||||
|
b[2] += readDelta(3) << 4;
|
||||||
|
f[2] += readDelta(3) << 3;
|
||||||
|
b[3] += readDelta(3) << 3;
|
||||||
|
f[3] += readDelta(4) << 2;
|
||||||
|
b[4] += readDelta(4) << 1;
|
||||||
|
f[4] += readDelta(4) << 2;
|
||||||
|
b[5] += readDelta(5) << 0;
|
||||||
|
f[5] += readDelta(5) << 0;
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
b[0] += readDelta(4) << 2;
|
||||||
|
f[0] += readDelta(4) << 0;
|
||||||
|
b[1] += readDelta(4) << 1;
|
||||||
|
f[1] += readDelta(4) << 2;
|
||||||
|
b[2] += readDelta(4) << 1;
|
||||||
|
f[2] += readDelta(4) << 2;
|
||||||
|
b[3] += readDelta(4) << 1;
|
||||||
|
f[3] += readDelta(5) << 2;
|
||||||
|
b[4] += readDelta(5) << 1;
|
||||||
|
f[4] += readDelta(5) << 1;
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
b[0] += readDelta(4) << 2;
|
||||||
|
f[0] += readDelta(4) << 0;
|
||||||
|
b[1] += readDelta(4) << 1;
|
||||||
|
f[1] += readDelta(4) << 2;
|
||||||
|
b[2] += readDelta(4) << 1;
|
||||||
|
f[2] += readDelta(4) << 2;
|
||||||
|
b[3] += readDelta(4) << 1;
|
||||||
|
f[3] += readDelta(5) << 2;
|
||||||
|
b[4] += readDelta(5) << 1;
|
||||||
|
f[4] += readDelta(5) << 1;
|
||||||
|
b[5] += readDelta(5) << 0;
|
||||||
|
f[5] += readDelta(5) << 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::SETMSB_A(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
case 0x1:
|
||||||
|
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
|
||||||
|
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
|
||||||
|
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
case 0x3:
|
||||||
|
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
|
||||||
|
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
|
||||||
|
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::JSR(INT32 immed4) {
|
||||||
|
INT32 newpc = (page << 12) | (flipEndian(immed4, 4) << 8) | readBitsReverse(8);
|
||||||
|
stack = pc;
|
||||||
|
pc = newpc;
|
||||||
|
bitsLeft = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::LOAD_C(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
period = readBits(8);
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
|
||||||
|
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
|
||||||
|
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
|
||||||
|
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
|
||||||
|
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
|
||||||
|
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
|
||||||
|
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
|
||||||
|
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
|
||||||
|
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
|
||||||
|
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
|
||||||
|
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
|
||||||
|
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
|
||||||
|
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
|
||||||
|
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
|
||||||
|
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
|
||||||
|
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
|
||||||
|
b[5] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
|
||||||
|
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
|
||||||
|
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
|
||||||
|
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
|
||||||
|
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
|
||||||
|
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
|
||||||
|
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
b[4] = (INT8)readBits(8);
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = 0;
|
||||||
|
f[5] = 0;
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
|
||||||
|
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
|
||||||
|
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
|
||||||
|
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
|
||||||
|
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
|
||||||
|
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
|
||||||
|
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
|
||||||
|
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
|
||||||
|
b[4] = (INT8)readBits(8);
|
||||||
|
f[4] = (INT8)readBits(8);
|
||||||
|
b[5] = (INT8)readBits(8);
|
||||||
|
f[5] = (INT8)readBits(8);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
amplitudeInterpolation = 0;
|
||||||
|
periodInterpolation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::DELTA_D(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (amplitude + 0x10000 + (readDelta(4) << 2))
|
||||||
|
& 0xFFFF;
|
||||||
|
period = (period + 0x10000 + readDelta(5)) & 0xFFFF;
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
switch (mode) {
|
||||||
|
case 0x0:
|
||||||
|
b[3] += readDelta(3) << 3;
|
||||||
|
f[3] += readDelta(4) << 2;
|
||||||
|
b[4] += readDelta(4) << 1;
|
||||||
|
f[4] += readDelta(4) << 2;
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
b[3] += readDelta(3) << 3;
|
||||||
|
f[3] += readDelta(4) << 2;
|
||||||
|
b[4] += readDelta(4) << 1;
|
||||||
|
f[4] += readDelta(4) << 2;
|
||||||
|
b[5] += readDelta(5) << 0;
|
||||||
|
f[5] += readDelta(5) << 0;
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
b[3] += readDelta(4) << 1;
|
||||||
|
f[3] += readDelta(5) << 1;
|
||||||
|
b[4] += readDelta(5) << 0;
|
||||||
|
f[4] += readDelta(5) << 0;
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
b[3] += readDelta(4) << 1;
|
||||||
|
f[3] += readDelta(5) << 1;
|
||||||
|
b[4] += readDelta(5) << 0;
|
||||||
|
f[4] += readDelta(5) << 0;
|
||||||
|
b[5] += readDelta(5) << 0;
|
||||||
|
f[5] += readDelta(5) << 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::LOAD_E(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
|
||||||
|
period = readBits(8);
|
||||||
|
//periodCounter = (period == 0 ? 0x100 : period);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::PAUSE(INT32 immed4) {
|
||||||
|
repeat = (repeatPrefix << 4) | immed4;
|
||||||
|
if (repeat == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
//clear everything
|
||||||
|
amplitude = 0;
|
||||||
|
period = 0;
|
||||||
|
for (INT32 j = 0; j < 6; j++) {
|
||||||
|
b[j] = 0;
|
||||||
|
f[j] = 0;
|
||||||
|
}
|
||||||
|
amplitudeInterpolation = 0;
|
||||||
|
periodInterpolation = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::decode() {
|
||||||
|
INT32 immed4 = readBits(4);
|
||||||
|
INT32 nextInstruction = readBitsReverse(4);
|
||||||
|
switch (nextInstruction) {
|
||||||
|
case 0x0:
|
||||||
|
if (immed4 == 0)
|
||||||
|
RTS();
|
||||||
|
else
|
||||||
|
SETPAGE(immed4);
|
||||||
|
break;
|
||||||
|
case 0x8:
|
||||||
|
SETMODE(immed4);
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
LOAD_4(immed4);
|
||||||
|
break;
|
||||||
|
case 0xC:
|
||||||
|
LOAD_C(immed4);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
LOAD_2(immed4);
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
SETMSB_A(immed4);
|
||||||
|
break;
|
||||||
|
case 0x6:
|
||||||
|
SETMSB_6(immed4);
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
LOAD_E(immed4);
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
LOADALL(immed4);
|
||||||
|
break;
|
||||||
|
case 0x9:
|
||||||
|
DELTA_9(immed4);
|
||||||
|
break;
|
||||||
|
case 0x5:
|
||||||
|
SETMSB_5(immed4);
|
||||||
|
break;
|
||||||
|
case 0xD:
|
||||||
|
DELTA_D(immed4);
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
SETMSB_3(immed4);
|
||||||
|
break;
|
||||||
|
case 0xB:
|
||||||
|
JSR(immed4);
|
||||||
|
break;
|
||||||
|
case 0x7:
|
||||||
|
JMP(immed4);
|
||||||
|
break;
|
||||||
|
case 0xF:
|
||||||
|
PAUSE(immed4);
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
case 0x0:
|
||||||
|
if (immed4 == 0)
|
||||||
|
RTS();
|
||||||
|
else
|
||||||
|
SETPAGE(immed4);
|
||||||
|
break;
|
||||||
|
case 0x1:
|
||||||
|
SETMODE(immed4);
|
||||||
|
break;
|
||||||
|
case 0x2:
|
||||||
|
LOAD_4(immed4);
|
||||||
|
break;
|
||||||
|
case 0x3:
|
||||||
|
LOAD_C(immed4);
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
LOAD_2(immed4);
|
||||||
|
break;
|
||||||
|
case 0x5:
|
||||||
|
SETMSB_A(immed4);
|
||||||
|
break;
|
||||||
|
case 0x6:
|
||||||
|
SETMSB_6(immed4);
|
||||||
|
break;
|
||||||
|
case 0x7:
|
||||||
|
LOAD_E(immed4);
|
||||||
|
break;
|
||||||
|
case 0x8:
|
||||||
|
LOADALL(immed4);
|
||||||
|
break;
|
||||||
|
case 0x9:
|
||||||
|
DELTA_9(immed4);
|
||||||
|
break;
|
||||||
|
case 0xA:
|
||||||
|
SETMSB_5(immed4);
|
||||||
|
break;
|
||||||
|
case 0xB:
|
||||||
|
DELTA_D(immed4);
|
||||||
|
break;
|
||||||
|
case 0xC:
|
||||||
|
SETMSB_3(immed4);
|
||||||
|
break;
|
||||||
|
case 0xD:
|
||||||
|
JSR(immed4);
|
||||||
|
break;
|
||||||
|
case 0xE:
|
||||||
|
JMP(immed4);
|
||||||
|
break;
|
||||||
|
case 0xF:
|
||||||
|
PAUSE(immed4);
|
||||||
|
break;
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
INT32 SP0256::flipEndian(INT32 value, INT32 bits) {
|
||||||
|
INT32 output = 0;
|
||||||
|
INT32 bitMask = 1;
|
||||||
|
for (INT32 i = 0; i < bits; i++) {
|
||||||
|
INT32 offset = (bits-1)-(i<<1);
|
||||||
|
if (offset > 0)
|
||||||
|
output |= (value & bitMask) << offset;
|
||||||
|
else
|
||||||
|
output |= (value & bitMask) >> -offset;
|
||||||
|
bitMask = bitMask << 1;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
SP0256State SP0256::getState()
|
||||||
|
{
|
||||||
|
SP0256State state = {0};
|
||||||
|
#if 0
|
||||||
|
state.bitsLeft = this->bitsLeft;
|
||||||
|
state.currentBits = this->currentBits;
|
||||||
|
|
||||||
|
state.pc = this->pc;
|
||||||
|
state.stack = this->stack;
|
||||||
|
state.mode = this->mode;
|
||||||
|
state.repeatPrefix = this->repeatPrefix;
|
||||||
|
state.page = this->page;
|
||||||
|
state.command = this->command;
|
||||||
|
|
||||||
|
state.idle = this->idle;
|
||||||
|
state.lrqHigh = this->lrqHigh;
|
||||||
|
state.speaking = this->speaking;
|
||||||
|
memcpy(state.fifoBytes, this->fifoBytes, sizeof(this->fifoBytes));
|
||||||
|
state.fifoHead = this->fifoHead;
|
||||||
|
state.fifoSize = this->fifoSize;
|
||||||
|
|
||||||
|
state.repeat = this->repeat;
|
||||||
|
state.period = this->period;
|
||||||
|
state.periodCounter = this->periodCounter;
|
||||||
|
state.amplitude = this->amplitude;
|
||||||
|
memcpy(state.b, this->b, sizeof(this->b));
|
||||||
|
memcpy(state.f, this->f, sizeof(this->f));
|
||||||
|
memcpy(state.y, this->y, sizeof(this->f));
|
||||||
|
state.periodInterpolation = this->periodInterpolation;
|
||||||
|
state.amplitudeInterpolation = this->amplitudeInterpolation;
|
||||||
|
|
||||||
|
state.random = this->random;
|
||||||
|
#endif
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256::setState(SP0256State state)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
this->bitsLeft = state.bitsLeft;
|
||||||
|
this->currentBits = state.currentBits;
|
||||||
|
|
||||||
|
this->pc = state.pc;
|
||||||
|
this->stack = state.stack;
|
||||||
|
this->mode = state.mode;
|
||||||
|
this->repeatPrefix = state.repeatPrefix;
|
||||||
|
this->page = state.page;
|
||||||
|
this->command = state.command;
|
||||||
|
|
||||||
|
this->idle = state.idle;
|
||||||
|
this->lrqHigh = state.lrqHigh;
|
||||||
|
this->speaking = state.speaking;
|
||||||
|
memcpy(this->fifoBytes, state.fifoBytes, sizeof(this->fifoBytes));
|
||||||
|
this->fifoHead = state.fifoHead;
|
||||||
|
this->fifoSize = state.fifoSize;
|
||||||
|
|
||||||
|
this->repeat = state.repeat;
|
||||||
|
this->period = state.period;
|
||||||
|
this->periodCounter = state.periodCounter;
|
||||||
|
this->amplitude = state.amplitude;
|
||||||
|
memcpy(this->b, state.b, sizeof(this->b));
|
||||||
|
memcpy(this->f, state.f, sizeof(this->f));
|
||||||
|
memcpy(this->y, state.y, sizeof(this->f));
|
||||||
|
this->periodInterpolation = state.periodInterpolation;
|
||||||
|
this->amplitudeInterpolation = state.amplitudeInterpolation;
|
||||||
|
|
||||||
|
this->random = state.random;
|
||||||
|
#endif
|
||||||
|
}
|
125
arm9/source/emucore/SP0256.h
Normal file
125
arm9/source/emucore/SP0256.h
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
|
||||||
|
#ifndef MICROSEQUENCER_H
|
||||||
|
#define MICROSEQUENCER_H
|
||||||
|
|
||||||
|
#include "AudioProducer.h"
|
||||||
|
#include "SP0256_Registers.h"
|
||||||
|
#include "types.h"
|
||||||
|
#include "Processor.h"
|
||||||
|
#include "ROM.h"
|
||||||
|
#include "AudioOutputLine.h"
|
||||||
|
|
||||||
|
#define FIFO_LOCATION 0x1800
|
||||||
|
#define FIFO_MAX_SIZE 64
|
||||||
|
//#define FIFO_END (FIFO_LOCATION + FIFO_MAX_SIZE)
|
||||||
|
|
||||||
|
|
||||||
|
//registers
|
||||||
|
extern INT32 repeat;
|
||||||
|
extern INT32 period;
|
||||||
|
extern INT32 periodCounter;
|
||||||
|
extern INT32 amplitude;
|
||||||
|
extern INT8 b[6];
|
||||||
|
extern INT8 f[6];
|
||||||
|
extern INT32 y[6][2];
|
||||||
|
extern INT8 periodInterpolation;
|
||||||
|
extern INT8 amplitudeInterpolation;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TYPEDEF_STRUCT_PACK( _SP0256State
|
||||||
|
{
|
||||||
|
INT32 bitsLeft;
|
||||||
|
INT32 currentBits;
|
||||||
|
INT32 pc;
|
||||||
|
INT32 stack;
|
||||||
|
INT32 mode;
|
||||||
|
INT32 repeatPrefix;
|
||||||
|
INT32 page;
|
||||||
|
INT32 command;
|
||||||
|
INT32 repeat;
|
||||||
|
INT32 period;
|
||||||
|
INT32 periodCounter;
|
||||||
|
INT32 amplitude;
|
||||||
|
INT32 random;
|
||||||
|
INT32 fifoHead;
|
||||||
|
INT32 fifoSize;
|
||||||
|
INT32 fifoBytes[64];
|
||||||
|
INT32 y[6][2];
|
||||||
|
INT8 b[6];
|
||||||
|
INT8 f[6];
|
||||||
|
INT8 periodInterpolation;
|
||||||
|
INT8 amplitudeInterpolation;
|
||||||
|
INT8 idle;
|
||||||
|
INT8 lrqHigh;
|
||||||
|
INT8 speaking;
|
||||||
|
UINT8 _pad6[3];
|
||||||
|
} SP0256State; )
|
||||||
|
|
||||||
|
class SP0256 : public Processor, public AudioProducer
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class SP0256_Registers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SP0256();
|
||||||
|
void resetProcessor();
|
||||||
|
INT32 getClockSpeed();
|
||||||
|
INT32 getClocksPerSample();
|
||||||
|
INT32 getSampleRate() { return getClockSpeed(); }
|
||||||
|
INT32 tick(INT32);
|
||||||
|
inline BOOL isIdle() { return idle; }
|
||||||
|
|
||||||
|
SP0256State getState();
|
||||||
|
void setState(SP0256State state);
|
||||||
|
|
||||||
|
SP0256_Registers registers;
|
||||||
|
ROM ivoiceROM;
|
||||||
|
|
||||||
|
private:
|
||||||
|
INT8 readDelta(INT32 numBits);
|
||||||
|
INT32 readBits(INT32 numBits);
|
||||||
|
INT32 readBitsReverse(INT32 numBits);
|
||||||
|
void RTS();
|
||||||
|
void SETPAGE(INT32 immed4);
|
||||||
|
void LOADALL(INT32 immed4);
|
||||||
|
void LOAD_2(INT32 immed4);
|
||||||
|
void SETMSB_3(INT32 immed4);
|
||||||
|
void LOAD_4(INT32 immed4);
|
||||||
|
void SETMSB_5(INT32 immed4);
|
||||||
|
void SETMSB_6(INT32 immed4);
|
||||||
|
void JMP(INT32 immed4);
|
||||||
|
void SETMODE(INT32 immed4);
|
||||||
|
void DELTA_9(INT32 immed4);
|
||||||
|
void SETMSB_A(INT32 immed4);
|
||||||
|
void JSR(INT32 immed4);
|
||||||
|
void LOAD_C(INT32 immed4);
|
||||||
|
void DELTA_D(INT32 immed4);
|
||||||
|
void LOAD_E(INT32 immed4);
|
||||||
|
void PAUSE(INT32 immed4);
|
||||||
|
void decode();
|
||||||
|
static INT32 flipEndian(INT32 value, INT32 bits);
|
||||||
|
|
||||||
|
INT32 bitsLeft;
|
||||||
|
INT32 currentBits;
|
||||||
|
|
||||||
|
//registers
|
||||||
|
INT32 pc;
|
||||||
|
INT32 stack;
|
||||||
|
INT32 mode;
|
||||||
|
INT32 repeatPrefix;
|
||||||
|
INT32 page;
|
||||||
|
INT32 command;
|
||||||
|
|
||||||
|
BOOL idle;
|
||||||
|
BOOL lrqHigh;
|
||||||
|
BOOL speaking;
|
||||||
|
INT32 fifoBytes[64];
|
||||||
|
INT32 fifoHead;
|
||||||
|
INT32 fifoSize;
|
||||||
|
|
||||||
|
//random number generator
|
||||||
|
INT32 random;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
51
arm9/source/emucore/SP0256_Registers.cpp
Normal file
51
arm9/source/emucore/SP0256_Registers.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
|
||||||
|
#include "SP0256.h"
|
||||||
|
#include "SP0256_Registers.h"
|
||||||
|
|
||||||
|
SP0256_Registers::SP0256_Registers()
|
||||||
|
: RAM(2, 0x0080, 0xFFFF, 0xFFFF)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void SP0256_Registers::init(SP0256* ms)
|
||||||
|
{
|
||||||
|
this->ms = ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SP0256_Registers::poke(UINT16 location, UINT16 value)
|
||||||
|
{
|
||||||
|
switch(location) {
|
||||||
|
//a poke of any value into $80 means that the SP0256 should
|
||||||
|
//start speaking
|
||||||
|
case 0x0080:
|
||||||
|
if (ms->lrqHigh) {
|
||||||
|
ms->lrqHigh = FALSE;
|
||||||
|
|
||||||
|
ms->command = value & 0xFF;
|
||||||
|
|
||||||
|
if (!ms->speaking)
|
||||||
|
ms->idle = FALSE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
//$81 will reset the SP0256 or push an 8-bit value into the queue
|
||||||
|
case 0x0081:
|
||||||
|
if (value & 0x0400) {
|
||||||
|
ms->resetProcessor();
|
||||||
|
}
|
||||||
|
else if (ms->fifoSize < FIFO_MAX_SIZE) {
|
||||||
|
ms->fifoBytes[(ms->fifoHead+ms->fifoSize) & 0x3F] = value;
|
||||||
|
ms->fifoSize++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 SP0256_Registers::peek(UINT16 location) {
|
||||||
|
switch(location) {
|
||||||
|
case 0x0080:
|
||||||
|
return (ms->lrqHigh ? 0x8000 : 0);
|
||||||
|
case 0x0081:
|
||||||
|
default:
|
||||||
|
return (ms->fifoSize == FIFO_MAX_SIZE ? 0x8000 : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
28
arm9/source/emucore/SP0256_Registers.h
Normal file
28
arm9/source/emucore/SP0256_Registers.h
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
|
||||||
|
#ifndef MICROSEQUENCER_REGISTERS_H
|
||||||
|
#define MICROSEQUENCER_REGISTERS_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "RAM.h"
|
||||||
|
|
||||||
|
class SP0256;
|
||||||
|
|
||||||
|
class SP0256_Registers : public RAM
|
||||||
|
{
|
||||||
|
|
||||||
|
friend class SP0256;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void reset() {}
|
||||||
|
|
||||||
|
void poke(UINT16 location, UINT16 value);
|
||||||
|
UINT16 peek(UINT16 location);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SP0256_Registers();
|
||||||
|
void init(SP0256* ms);
|
||||||
|
SP0256* ms;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
30
arm9/source/emucore/SignalLine.h
Normal file
30
arm9/source/emucore/SignalLine.h
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
|
||||||
|
#ifndef SIGNALLINE_H
|
||||||
|
#define SIGNALLINE_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
class Processor;
|
||||||
|
|
||||||
|
class SignalLine
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SignalLine()
|
||||||
|
{ SignalLine(NULL, 0, NULL, 0); }
|
||||||
|
|
||||||
|
SignalLine(Processor* pop, UINT8 pon, Processor* pip, UINT8 pin)
|
||||||
|
: pinOutProcessor(pop),
|
||||||
|
pinOutNum(pon),
|
||||||
|
pinInProcessor(pip),
|
||||||
|
pinInNum(pin),
|
||||||
|
isHigh(FALSE) { }
|
||||||
|
|
||||||
|
Processor* pinOutProcessor;
|
||||||
|
UINT8 pinOutNum;
|
||||||
|
Processor* pinInProcessor;
|
||||||
|
UINT8 pinInNum;
|
||||||
|
BOOL isHigh;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
93
arm9/source/emucore/VideoBus.cpp
Normal file
93
arm9/source/emucore/VideoBus.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "VideoBus.h"
|
||||||
|
|
||||||
|
VideoBus::VideoBus()
|
||||||
|
: pixelBuffer(NULL),
|
||||||
|
pixelBufferSize(0),
|
||||||
|
pixelBufferRowSize(0),
|
||||||
|
pixelBufferWidth(0),
|
||||||
|
pixelBufferHeight(0),
|
||||||
|
videoProducerCount(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoBus::~VideoBus()
|
||||||
|
{
|
||||||
|
if (pixelBuffer) {
|
||||||
|
delete[] pixelBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UINT32 i = 0; i < videoProducerCount; i++)
|
||||||
|
videoProducers[i]->setPixelBuffer(NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBus::addVideoProducer(VideoProducer* p)
|
||||||
|
{
|
||||||
|
videoProducers[videoProducerCount] = p;
|
||||||
|
videoProducers[videoProducerCount]->setPixelBuffer(pixelBuffer, pixelBufferRowSize);
|
||||||
|
videoProducerCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBus::removeVideoProducer(VideoProducer* p)
|
||||||
|
{
|
||||||
|
for (UINT32 i = 0; i < videoProducerCount; i++) {
|
||||||
|
if (videoProducers[i] == p) {
|
||||||
|
videoProducers[i]->setPixelBuffer(NULL, 0);
|
||||||
|
|
||||||
|
for (UINT32 j = i; j < (videoProducerCount-1); j++)
|
||||||
|
videoProducers[j] = videoProducers[j+1];
|
||||||
|
videoProducerCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBus::removeAll()
|
||||||
|
{
|
||||||
|
while (videoProducerCount)
|
||||||
|
removeVideoProducer(videoProducers[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBus::init(UINT32 width, UINT32 height)
|
||||||
|
{
|
||||||
|
VideoBus::release();
|
||||||
|
|
||||||
|
pixelBufferWidth = width;
|
||||||
|
pixelBufferHeight = height;
|
||||||
|
pixelBufferRowSize = width * sizeof(UINT8);
|
||||||
|
pixelBufferSize = width * height * sizeof(UINT8);
|
||||||
|
pixelBuffer = new UINT8[width * height];
|
||||||
|
printf("VideoBus::init(%d,%d)\n", width, height);
|
||||||
|
|
||||||
|
if ( pixelBuffer ) {
|
||||||
|
memset(pixelBuffer, 0, pixelBufferSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UINT32 i = 0; i < videoProducerCount; i++)
|
||||||
|
videoProducers[i]->setPixelBuffer(pixelBuffer, pixelBufferRowSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBus::render()
|
||||||
|
{
|
||||||
|
//tell each of the video producers that they can now output their
|
||||||
|
//video contents onto the video device
|
||||||
|
for (UINT32 i = 0; i < videoProducerCount; i++)
|
||||||
|
videoProducers[i]->render();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VideoBus::release()
|
||||||
|
{
|
||||||
|
if (pixelBuffer) {
|
||||||
|
for (UINT32 i = 0; i < videoProducerCount; i++)
|
||||||
|
videoProducers[i]->setPixelBuffer(NULL, 0);
|
||||||
|
|
||||||
|
pixelBufferWidth = 0;
|
||||||
|
pixelBufferHeight = 0;
|
||||||
|
pixelBufferRowSize = 0;
|
||||||
|
pixelBufferSize = 0;
|
||||||
|
delete[] pixelBuffer;
|
||||||
|
pixelBuffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
37
arm9/source/emucore/VideoBus.h
Normal file
37
arm9/source/emucore/VideoBus.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
|
||||||
|
#ifndef VIDEOBUS_H
|
||||||
|
#define VIDEOBUS_H
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
#include "VideoProducer.h"
|
||||||
|
|
||||||
|
const INT32 MAX_VIDEO_PRODUCERS = 10;
|
||||||
|
|
||||||
|
class VideoBus
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
VideoBus();
|
||||||
|
virtual ~VideoBus();
|
||||||
|
|
||||||
|
void addVideoProducer(VideoProducer* ic);
|
||||||
|
void removeVideoProducer(VideoProducer* ic);
|
||||||
|
void removeAll();
|
||||||
|
|
||||||
|
virtual void init(UINT32 width, UINT32 height);
|
||||||
|
virtual void render();
|
||||||
|
virtual void release();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
UINT8* pixelBuffer;
|
||||||
|
UINT32 pixelBufferSize;
|
||||||
|
UINT32 pixelBufferRowSize;
|
||||||
|
UINT32 pixelBufferWidth;
|
||||||
|
UINT32 pixelBufferHeight;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VideoProducer* videoProducers[MAX_VIDEO_PRODUCERS];
|
||||||
|
UINT32 videoProducerCount;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
27
arm9/source/emucore/VideoProducer.h
Normal file
27
arm9/source/emucore/VideoProducer.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
|
||||||
|
#ifndef VIDEOPRODUCER_H
|
||||||
|
#define VIDEOPRODUCER_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface is implemented by any piece of hardware that renders graphic
|
||||||
|
* output.
|
||||||
|
*/
|
||||||
|
class VideoProducer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Tells the video producer to render its output. It should *not* flip
|
||||||
|
* the output onto the screen as that will be done by the video bus
|
||||||
|
* after all video producers have rendered their output to the back
|
||||||
|
* buffer.
|
||||||
|
*
|
||||||
|
* This function will be called once each time the Emulator indicates
|
||||||
|
* that it has entered vertical blank.
|
||||||
|
*/
|
||||||
|
|
||||||
|
virtual void setPixelBuffer(UINT8* pixelBuffer, UINT32 rowSize) = 0;
|
||||||
|
|
||||||
|
virtual void render() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
696
arm9/source/emucore/knowncarts.cfg
Normal file
696
arm9/source/emucore/knowncarts.cfg
Normal file
@ -0,0 +1,696 @@
|
|||||||
|
D7C78754:Info:4-TRIS (GPL):Joseph Zbiciak:2000
|
||||||
|
D7C78754:ROM:5000:2000:16
|
||||||
|
|
||||||
|
B91488E2:Info:4-TRIS (GPL):Joseph Zbiciak:2001
|
||||||
|
B91488E2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A60E25FC:Info:ABPA Backgammon:Mattel:1978
|
||||||
|
A60E25FC:ROM:5000:1000:16
|
||||||
|
|
||||||
|
F8B1F2B7:Info:Advanced Dungeons and Dragons:Mattel:1982
|
||||||
|
F8B1F2B7:ROM:5000:2000:16
|
||||||
|
|
||||||
|
16C3B62F:Info:Advanced Dungeons and Dragons - Treasure of Tarmin:Mattel:1982
|
||||||
|
16C3B62F:ROM:5000:2000:16
|
||||||
|
|
||||||
|
11C3BCFA:Info:Adventure (AD&D - Cloudy Mountain):Mattel:1982
|
||||||
|
11C3BCFA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2C668249:Info:Air Strike:Mattel:1982
|
||||||
|
2C668249:ROM:5000:1000:16
|
||||||
|
|
||||||
|
B45633CF:Info:All-Stars Major League Baseball:Mattel:1980
|
||||||
|
B45633CF:ROM:5000:2000:16
|
||||||
|
B45633CF:ROM:D000:1000:16
|
||||||
|
|
||||||
|
6F91FBC1:Info:Armor Battle:Mattel:1978
|
||||||
|
6F91FBC1:ROM:5000:1000:16
|
||||||
|
|
||||||
|
00BE8BBA:Info:Astrosmash - Meteor:Mattel:1981
|
||||||
|
00BE8BBA:ROM:5000:1000:16
|
||||||
|
|
||||||
|
FAB2992C:Info:Astrosmash:Mattel:1981
|
||||||
|
FAB2992C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
13FF363C:Info:Atlantis:Imagic:1981
|
||||||
|
13FF363C:ROM:4800:2000:16
|
||||||
|
|
||||||
|
B35C1101:Info:Auto Racing:Mattel:1979
|
||||||
|
B35C1101:ROM:5000:1000:16
|
||||||
|
|
||||||
|
8AD19AB3:Info:B-17 Bomber:Mattel:1981
|
||||||
|
8AD19AB3:ROM:5000:2000:16
|
||||||
|
8AD19AB3:ROM:D000:1000:16
|
||||||
|
8AD19AB3:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
DAB36628:Info:Baseball:Mattel:1978
|
||||||
|
DAB36628:ROM:5000:1000:16
|
||||||
|
|
||||||
|
EAF650CC:Info:BeamRider:Activision:1983
|
||||||
|
EAF650CC:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C047D487:Info:Beauty and the Beast:Imagic:1982
|
||||||
|
C047D487:ROM:4800:2000:16
|
||||||
|
|
||||||
|
B03F739B:Info:Blockade Runner:Interphase:1983
|
||||||
|
B03F739B:ROM:5000:2000:16
|
||||||
|
|
||||||
|
4728C3BD:Info:Blow Out:Mattel:1983
|
||||||
|
4728C3BD:ROM:5000:1000:16
|
||||||
|
|
||||||
|
515E1D7E:Info:Body Slam Super Pro Wrestling:Mattel:1988
|
||||||
|
515E1D7E:ROM:5000:2000:16
|
||||||
|
515E1D7E:ROM:9000:2000:16
|
||||||
|
|
||||||
|
32697B72:Info:Bomb Squad:Mattel:1982
|
||||||
|
32697B72:ROM:5000:2000:16
|
||||||
|
32697B72:ROM:D000:1000:16
|
||||||
|
32697B72:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
18E08520:Info:Bouncing Pixels (GPL):JRMZ Electronics:1999
|
||||||
|
18E08520:ROM:5000:0202:16
|
||||||
|
|
||||||
|
AB87C16F:Info:Boxing:Mattel:1980
|
||||||
|
AB87C16F:ROM:5000:1000:16
|
||||||
|
|
||||||
|
9F85015B:Info:Brickout!:Mattel:1981
|
||||||
|
9F85015B:ROM:5000:1000:16
|
||||||
|
|
||||||
|
999CCEED:Info:Bump 'N' Jump:Mattel:1982-83
|
||||||
|
999CCEED:ROM:5000:2000:16
|
||||||
|
999CCEED:ROM:D000:1000:16
|
||||||
|
999CCEED:ROM:F000:1000:16
|
||||||
|
|
||||||
|
43806375:Info:BurgerTime!:Mattel:1982
|
||||||
|
43806375:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C92BAAE8:Info:BurgerTime! - New Levels Hack:David Harley:2002
|
||||||
|
C92BAAE8:ROM:5000:2000:16
|
||||||
|
|
||||||
|
FA492BBD:Info:Buzz Bombers:Mattel:1982
|
||||||
|
FA492BBD:ROM:5000:2000:16
|
||||||
|
|
||||||
|
43870908:Info:Carnival:Coleco:1982
|
||||||
|
43870908:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D5363B8C:Info:Centipede:Atarisoft:1983
|
||||||
|
D5363B8C:ROM:6000:2000:16
|
||||||
|
|
||||||
|
4CC46A04:Info:Championship Tennis:Nice Ideas:1985
|
||||||
|
4CC46A04:ROM:5000:2000:16
|
||||||
|
4CC46A04:ROM:D000:2000:16
|
||||||
|
|
||||||
|
36E1D858:Info:Checkers:Mattel:1979
|
||||||
|
36E1D858:ROM:5000:1000:16
|
||||||
|
|
||||||
|
0BF464C6:Info:Chip Shot Super Pro Golf:Mattel:1987
|
||||||
|
0BF464C6:ROM:5000:2000:16
|
||||||
|
0BF464C6:ROM:9000:2000:16
|
||||||
|
|
||||||
|
47FDD8A8:Info:Choplifter:Mattel:1983
|
||||||
|
47FDD8A8:ROM:5000:2000:16
|
||||||
|
47FDD8A8:ROM:D000:2000:16
|
||||||
|
|
||||||
|
3289C8BA:Info:Commando:INTV:1987
|
||||||
|
3289C8BA:ROM:5000:2000:16
|
||||||
|
3289C8BA:ROM:9000:2000:16
|
||||||
|
|
||||||
|
4B23A757:Info:Congo Bongo:Sega:1983
|
||||||
|
4B23A757:ROM:5000:3000:16
|
||||||
|
|
||||||
|
E1EE408F:Info:Crazy Clones:Mattel:1981
|
||||||
|
E1EE408F:ROM:5000:1000:16
|
||||||
|
|
||||||
|
CDC14ED8:Info:Deadly Dogs!:Unknown:1987
|
||||||
|
CDC14ED8:ROM:5000:1000:16
|
||||||
|
|
||||||
|
6802B191:Info:Deep Pockets - Super Pro Pool and Billiards:Realtime:1990
|
||||||
|
6802B191:ROM:5000:2000:16
|
||||||
|
6802B191:ROM:9000:2000:16
|
||||||
|
|
||||||
|
D8F99AA2:Info:Defender:Atarisoft:1983
|
||||||
|
D8F99AA2:ROM:5000:3000:16
|
||||||
|
|
||||||
|
5E6A8CD8:Info:Demon Attack:Imagic:1982
|
||||||
|
5E6A8CD8:ROM:4800:2000:16
|
||||||
|
|
||||||
|
159AF7F7:Info:Dig Dug:INTV:1987
|
||||||
|
159AF7F7:ROM:5000:3000:16
|
||||||
|
159AF7F7:ROM:9000:1000:16
|
||||||
|
|
||||||
|
13EE56F1:Info:Diner:INTV:1987
|
||||||
|
13EE56F1:ROM:5000:2000:16
|
||||||
|
13EE56F1:ROM:9000:2000:16
|
||||||
|
|
||||||
|
C30F61C0:Info:Donkey Kong:Coleco:1982
|
||||||
|
C30F61C0:ROM:5000:1000:16
|
||||||
|
|
||||||
|
6DF61A9F:Info:Donkey Kong Jr:Coleco:1982
|
||||||
|
6DF61A9F:ROM:5000:2000:16
|
||||||
|
|
||||||
|
84BEDCC1:Info:Dracula:Imagic:1982
|
||||||
|
84BEDCC1:ROM:5000:2000:16
|
||||||
|
|
||||||
|
AF8718A1:Info:Dragonfire:Imagic:1982
|
||||||
|
AF8718A1:ROM:5000:1000:16
|
||||||
|
|
||||||
|
3B99B889:Info:Dreadnaught Factor, The:Activision:1983
|
||||||
|
3B99B889:ROM:5000:2000:16
|
||||||
|
|
||||||
|
BF4D0E9B:Info:Dreadnaught Factor, The (Prototype):Activision:1983
|
||||||
|
BF4D0E9B:ROM:5000:2000:16
|
||||||
|
|
||||||
|
20ACE89D:Info:Easter Eggs:Mattel:1981
|
||||||
|
20ACE89D:ROM:5000:1000:16
|
||||||
|
|
||||||
|
54A3FC11:Info:Electric Company - Math Fun:CTW:1978
|
||||||
|
54A3FC11:ROM:5000:1000:16
|
||||||
|
|
||||||
|
C9EAACAB:Info:Electric Company - Word Fun:CTW:1980
|
||||||
|
C9EAACAB:ROM:5000:1000:16
|
||||||
|
|
||||||
|
4221EDE7:Info:Fathom:Imagic:1983
|
||||||
|
4221EDE7:ROM:5000:2000:16
|
||||||
|
|
||||||
|
37222762:Info:Frog Bog:Mattel:1982
|
||||||
|
37222762:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D27495E9:Info:Frogger:Parker Bros:1983
|
||||||
|
D27495E9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
DBCA82C5:Info:Go For The Gold:Mattel:1981
|
||||||
|
DBCA82C5:ROM:5000:2000:16
|
||||||
|
|
||||||
|
291AC826:Info:Grid Shock:Mattel:1982
|
||||||
|
291AC826:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E573863A:Info:Groovy! (GPL):JRMZ Electronics:1999
|
||||||
|
E573863A:ROM:5000:1E48:16
|
||||||
|
|
||||||
|
4B8C5932:Info:Happy Trails:Activision:1983
|
||||||
|
4B8C5932:ROM:5000:1000:16
|
||||||
|
|
||||||
|
120B53A9:Info:Happy Trails (Overdump):Activision:1983
|
||||||
|
120B53A9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
B6A3D4DE:Info:Hard Hat:Mattel:1979
|
||||||
|
B6A3D4DE:ROM:5000:2000:16
|
||||||
|
|
||||||
|
B5C7F25D:Info:Horse Racing:Mattel:1980
|
||||||
|
B5C7F25D:ROM:5000:1000:16
|
||||||
|
|
||||||
|
FF83FF80:Info:Hover Force:Mattel:1986
|
||||||
|
FF83FF80:ROM:5000:2000:16
|
||||||
|
FF83FF80:ROM:9000:3000:16
|
||||||
|
FF83FF80:ROM:D000:1000:16
|
||||||
|
|
||||||
|
A3147630:Info:Hypnotic Lights:Mattel:1981
|
||||||
|
A3147630:ROM:5000:1000:16
|
||||||
|
|
||||||
|
4F3E3F69:Info:Ice Trek:Imagic:1983
|
||||||
|
4F3E3F69:ROM:5000:2000:16
|
||||||
|
|
||||||
|
02919024:Info:Intellivision - Intelligent Television Demo:Mattel:1978
|
||||||
|
02919024:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C83EEA4C:Info:Intellivision Test Cartridge and Baseball:Mattel:1978
|
||||||
|
C83EEA4C:ROM:5000:1000:16
|
||||||
|
C83EEA4C:ROM:7000:1000:16
|
||||||
|
|
||||||
|
985A78ED:Info:IntyOS 0.2 Alpha:Arnauld Chevallier:2003
|
||||||
|
985A78ED:ROM:5000:1000:16
|
||||||
|
985A78ED:RAM:D000:1000:16
|
||||||
|
985A78ED:RAM:F000:1000:16
|
||||||
|
|
||||||
|
EE5F1BE2:Info:Jetsons, The - Ways With Words:Mattel:1983
|
||||||
|
EE5F1BE2:ROM:5000:2000:16
|
||||||
|
EE5F1BE2:ROM:D000:1000:16
|
||||||
|
EE5F1BE2:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
4422868E:Info:King of the Mountain:Mattel:1982
|
||||||
|
4422868E:ROM:5000:2000:16
|
||||||
|
4422868E:ROM:D000:2000:16
|
||||||
|
|
||||||
|
8C9819A2:Info:Kool-Aid Man:Mattel:1983
|
||||||
|
8C9819A2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A6840736:Info:Lady Bug:Coleco:1983
|
||||||
|
A6840736:ROM:5000:2000:16
|
||||||
|
|
||||||
|
3825C25B:Info:Land Battle:Mattel:1982
|
||||||
|
3825C25B:ROM:5000:2000:16
|
||||||
|
3825C25B:RAM:D000:400:8
|
||||||
|
|
||||||
|
604611C0:Info:Las Vegas Blackjack and Poker:Mattel:1979
|
||||||
|
604611C0:ROM:5000:1000:16
|
||||||
|
|
||||||
|
48D74D3C:Info:Las Vegas Roulette:Mattel:1979
|
||||||
|
48D74D3C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
19360442:Info:League of Light (Prototype Alt1):Activision:1983
|
||||||
|
19360442:ROM:5000:2000:16
|
||||||
|
|
||||||
|
75EE64F6:Info:League of Light (Prototype Alt2):Activision:1983
|
||||||
|
75EE64F6:ROM:5000:2000:16
|
||||||
|
|
||||||
|
B4287B95:Info:League of Light (Prototype):Activision:1983
|
||||||
|
B4287B95:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2C5FD5FA:Info:Learning Fun I - Math Master Factor Fun:INTV:1987
|
||||||
|
2C5FD5FA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
632F6ADF:Info:Learning Fun II - Word Wizard Memory Fun:INTV:1987
|
||||||
|
632F6ADF:ROM:5000:2000:16
|
||||||
|
|
||||||
|
E00D1399:Info:Lock 'N' Chase:Mattel:1982
|
||||||
|
E00D1399:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6B6E80EE:Info:Loco-Motion:Mattel:1982
|
||||||
|
6B6E80EE:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F3B0C759:Info:Magic Carousel:Mattel:1982
|
||||||
|
F3B0C759:ROM:5000:2000:16
|
||||||
|
F3B0C759:ROM:D000:2000:16
|
||||||
|
|
||||||
|
573B9B6D:Info:Masters of the Universe - The Power of He-Man!:Mattel:1983
|
||||||
|
573B9B6D:ROM:5000:2000:16
|
||||||
|
573B9B6D:ROM:D000:1000:16
|
||||||
|
573B9B6D:ROM:F000:1000:16
|
||||||
|
|
||||||
|
7D0F8162:Info:Maze Demo #1 (GPL):JRMZ Electronics:2000
|
||||||
|
7D0F8162:ROM:5000:016E:16
|
||||||
|
|
||||||
|
2138DAD4:Info:Maze Demo #2 (GPL):JRMZ Electronics:2000
|
||||||
|
2138DAD4:ROM:5000:0175:16
|
||||||
|
|
||||||
|
FF68AA22:Info:Melody Blaster:Mattel:1983
|
||||||
|
FF68AA22:ROM:5000:2000:16
|
||||||
|
FF68AA22:ROM:D000:1000:16
|
||||||
|
FF68AA22:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
E00E23E7:Info:Mickey's Hello World:Mickey:2000
|
||||||
|
E00E23E7:ROM:5000:006F:16
|
||||||
|
|
||||||
|
E806AD91:Info:Microsurgeon:Imagic:1982
|
||||||
|
E806AD91:ROM:4800:2000:16
|
||||||
|
|
||||||
|
94096229:Info:Minehunter:Ryan Kinnen:2004
|
||||||
|
94096229:ROM:5000:2000:16
|
||||||
|
|
||||||
|
9D57498F:Info:Mind Strike!:Mattel:1982
|
||||||
|
9D57498F:ROM:5000:2000:16
|
||||||
|
9D57498F:ROM:D000:1000:16
|
||||||
|
9D57498F:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
6746607B:Info:Minotaur V1.1:Mattel:1981
|
||||||
|
6746607B:ROM:5000:2000:16
|
||||||
|
|
||||||
|
5A4CE519:Info:Minotaur V2:Mattel:1981
|
||||||
|
5A4CE519:ROM:5000:2000:16
|
||||||
|
|
||||||
|
BD731E3C:Info:Minotaur:Mattel:1981
|
||||||
|
BD731E3C:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2F9C93FC:Info:Minotaur (Treasure of Tarmin hack):Mattel:1981
|
||||||
|
2F9C93FC:ROM:5000:2000:16
|
||||||
|
|
||||||
|
11FB9974:Info:Mission X:Mattel:1982
|
||||||
|
11FB9974:ROM:5000:2000:16
|
||||||
|
|
||||||
|
5F6E1AF6:Info:Motocross:Mattel:1982
|
||||||
|
5F6E1AF6:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6B5EA9C4:Info:Mountain Madness Super Pro Skiing:INTV:1987
|
||||||
|
6B5EA9C4:ROM:5000:2000:16
|
||||||
|
|
||||||
|
598662F2:Info:Mouse Trap:Coleco:1982
|
||||||
|
598662F2:ROM:5000:1000:16
|
||||||
|
|
||||||
|
0B50A367:Info:Mr. Basic Meets Bits 'N Bytes (Bad Dump):Mattel:1983
|
||||||
|
0B50A367:ROM:5000:2000:16
|
||||||
|
0B50A367:ROM:D000:1000:16
|
||||||
|
0B50A367:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
BEF0B0C7:Info:Mr. Basic Meets Bits 'N Bytes:Mattel:1983
|
||||||
|
BEF0B0C7:ROM:5000:2000:16
|
||||||
|
BEF0B0C7:ROM:D000:1000:16
|
||||||
|
BEF0B0C7:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
DBAB54CA:Info:NASL Soccer:Mattel:1979
|
||||||
|
DBAB54CA:ROM:5000:1000:16
|
||||||
|
|
||||||
|
81E7FB8C:Info:NBA Basketball:Mattel:1978
|
||||||
|
81E7FB8C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
4B91CF16:Info:NFL Football:Mattel:1978
|
||||||
|
4B91CF16:ROM:5000:1000:16
|
||||||
|
|
||||||
|
76564A13:Info:NHL Hockey:Mattel:1979
|
||||||
|
76564A13:ROM:5000:1000:16
|
||||||
|
|
||||||
|
7334CD44:Info:Night Stalker:Mattel:1982
|
||||||
|
7334CD44:ROM:5000:1000:16
|
||||||
|
|
||||||
|
5EE2CC2A:Info:Nova Blast:Imagic:1983
|
||||||
|
5EE2CC2A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
E5D1A8D2:Info:Number Jumble:Mattel:1983
|
||||||
|
E5D1A8D2:ROM:5000:2000:16
|
||||||
|
E5D1A8D2:ROM:D000:1000:16
|
||||||
|
E5D1A8D2:ROM:F000:1000:16
|
||||||
|
|
||||||
|
A21C31C3:Info:Pac-Man:Atarisoft:1983
|
||||||
|
A21C31C3:ROM:5000:3000:16
|
||||||
|
|
||||||
|
6E4E8EB4:Info:Pac-Man:INTV:1983
|
||||||
|
6E4E8EB4:ROM:5000:3000:16
|
||||||
|
|
||||||
|
169E3584:Info:PBA Bowling:Mattel:1980
|
||||||
|
169E3584:ROM:5000:1000:16
|
||||||
|
|
||||||
|
FF87FAEC:Info:PGA Golf:Mattel:1979
|
||||||
|
FF87FAEC:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D7C5849C:Info:Pinball:Mattel:1981
|
||||||
|
D7C5849C:ROM:5000:2000:16
|
||||||
|
D7C5849C:ROM:D000:1000:16
|
||||||
|
|
||||||
|
9C75EFCC:Info:Pitfall!:Activision:1982
|
||||||
|
9C75EFCC:ROM:5000:1000:16
|
||||||
|
|
||||||
|
BB939881:Info:Pole Position:INTV:1986
|
||||||
|
BB939881:ROM:5000:2000:16
|
||||||
|
BB939881:ROM:9000:2000:16
|
||||||
|
|
||||||
|
A982E8D5:Info:Pong:Unknown:1999
|
||||||
|
A982E8D5:ROM:5000:0800:16
|
||||||
|
|
||||||
|
C51464E0:Info:Popeye:Parker Bros:1983
|
||||||
|
C51464E0:ROM:5000:2000:16
|
||||||
|
|
||||||
|
D8C9856A:Info:Q-bert:Parker Bros:1983
|
||||||
|
D8C9856A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C7BB1B0E:Info:Reversi:Mattel:1984
|
||||||
|
C7BB1B0E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
8910C37A:Info:River Raid:Activision:1982-83
|
||||||
|
8910C37A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
95466AD3:Info:River Raid V1 (Prototype):Activision:1982-83
|
||||||
|
95466AD3:ROM:5000:2000:16
|
||||||
|
|
||||||
|
1682D0B4:Info:Robot Rubble V1 (Prototype) (Overdump):Activision:1983
|
||||||
|
1682D0B4:ROM:5000:2000:16
|
||||||
|
|
||||||
|
7473916D:Info:Robot Rubble V1 (Prototype):Activision:1983
|
||||||
|
7473916D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A5E28783:Info:Robot Rubble V2 (Prototype):Activision:1983
|
||||||
|
A5E28783:ROM:5000:2000:16
|
||||||
|
|
||||||
|
243B0812:Info:Robot Rubble V3 (Prototype):Activision:1983
|
||||||
|
243B0812:ROM:5000:2000:16
|
||||||
|
|
||||||
|
DCF4B15D:Info:Royal Dealer:Mattel:1981
|
||||||
|
DCF4B15D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
47AA7977:Info:Safecracker:Imagic:1983
|
||||||
|
47AA7977:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6E0882E7:Info:SameGame and Robots:IntelligentVision:2005
|
||||||
|
6E0882E7:ROM:5000:2000:16
|
||||||
|
6E0882E7:ROM:D000:1000:16
|
||||||
|
6E0882E7:ROM:F000:1000:16
|
||||||
|
|
||||||
|
12BA58D1:Info:SameGame and Robots (Original):Michael J Hayes:2004
|
||||||
|
12BA58D1:ROM:5000:2000:16
|
||||||
|
12BA58D1:ROM:D000:1000:16
|
||||||
|
12BA58D1:ROM:F000:1000:16
|
||||||
|
|
||||||
|
E221808C:Info:Santa's Helper:Mattel:1983
|
||||||
|
E221808C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E9E3F60D:Info:Scooby Doo's Maze Chase:Mattel/Hanna-Barbera:1983
|
||||||
|
E9E3F60D:ROM:5000:2000:16
|
||||||
|
E9E3F60D:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
99AE29A9:Info:Sea Battle:Mattel:1980
|
||||||
|
99AE29A9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E0F0D3DA:Info:Sewer Sam:Interphase:1983
|
||||||
|
E0F0D3DA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A610406E:Info:Shape Escape:John Doherty:2005
|
||||||
|
A610406E:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2A4C761D:Info:Shark! Shark!:Mattel:1982
|
||||||
|
2A4C761D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
FF7CB79E:Info:Sharp Shot:Mattel:1982
|
||||||
|
FF7CB79E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
800B572F:Info:Slam Dunk Super Pro Basketball:INTV:1987
|
||||||
|
800B572F:ROM:5000:2000:16
|
||||||
|
800B572F:ROM:9000:2000:16
|
||||||
|
|
||||||
|
BA68FF28:Info:Slap Shot Super Pro Hockey:INTV:1987
|
||||||
|
BA68FF28:ROM:5000:2000:16
|
||||||
|
|
||||||
|
8F959A6E:Info:Snafu:Mattel:1981
|
||||||
|
8F959A6E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
72C2A343:Info:Song Player - Back in the USSR (GPL):Joseph Zbiciak:1999
|
||||||
|
72C2A343:ROM:5000:2000:16
|
||||||
|
72C2A343:ROM:9000:1241:16
|
||||||
|
|
||||||
|
5E3130E1:Info:Song Player - Copacabana (GPL):Joseph Zbiciak:1999
|
||||||
|
5E3130E1:ROM:5000:2000:16
|
||||||
|
5E3130E1:ROM:9000:088F:16
|
||||||
|
5E3130E1:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
C91B1D79:Info:Song Player - Creep (GPL):Joseph Zbiciak:1999
|
||||||
|
C91B1D79:ROM:5000:1081:16
|
||||||
|
C91B1D79:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
82D2E346:Info:Song Player - Nut March (GPL):Joseph Zbiciak:1999
|
||||||
|
82D2E346:ROM:5000:1B12:16
|
||||||
|
82D2E346:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
FCF06A8B:Info:Song Player - Nut Reed (GPL):Joseph Zbiciak:1999
|
||||||
|
FCF06A8B:ROM:5000:145E:16
|
||||||
|
FCF06A8B:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
5914220A:Info:Song Player - Nut Trep (GPL):Joseph Zbiciak:1999
|
||||||
|
5914220A:ROM:5000:0DC8:16
|
||||||
|
5914220A:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
71F5BE4E:Info:Song Player - Nut Waltz (GPL):Joseph Zbiciak:1999
|
||||||
|
71F5BE4E:ROM:5000:2000:16
|
||||||
|
71F5BE4E:ROM:9000:157C:16
|
||||||
|
71F5BE4E:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
437C0E2D:Info:Song Player - Secret Agent Man (GPL):Joseph Zbiciak:1999
|
||||||
|
437C0E2D:ROM:5000:2000:16
|
||||||
|
437C0E2D:ROM:9000:15A4:16
|
||||||
|
437C0E2D:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
DA5D77EA:Info:Song Player - Take on Me 3 (GPL):Joseph Zbiciak:1999
|
||||||
|
DA5D77EA:ROM:5000:12FD:16
|
||||||
|
DA5D77EA:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
10D721CA:Info:Song Player - Take on Me 6 (GPL):Joseph Zbiciak:1999
|
||||||
|
10D721CA:ROM:5000:1500:16
|
||||||
|
10D721CA:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
CC6F4F90:Info:Song Player - Too Sexy (GPL):Joseph Zbiciak:1999
|
||||||
|
CC6F4F90:ROM:5000:1AA7:16
|
||||||
|
CC6F4F90:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
E8B8EBA5:Info:Space Armada:Mattel:1981
|
||||||
|
E8B8EBA5:ROM:5000:1000:16
|
||||||
|
|
||||||
|
F95504E0:Info:Space Battle:Mattel:1979
|
||||||
|
F95504E0:ROM:5000:1000:16
|
||||||
|
|
||||||
|
F8EF3E5A:Info:Space Cadet:Mattel:1982
|
||||||
|
F8EF3E5A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
39D3B895:Info:Space Hawk:Mattel:1981
|
||||||
|
39D3B895:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E98B9163:Info:Space Shuttle:Mattel:1983
|
||||||
|
E98B9163:ROM:5000:2000:16
|
||||||
|
E98B9163:ROM:D000:3000:16
|
||||||
|
E98B9163:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
3784DC52:Info:Space Spartans:Mattel:1981
|
||||||
|
3784DC52:ROM:5000:2000:16
|
||||||
|
3784DC52:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
A95021FC:Info:Spiker! Super Pro Volleyball:INTV:1988
|
||||||
|
A95021FC:ROM:5000:2000:16
|
||||||
|
A95021FC:ROM:9000:2000:16
|
||||||
|
|
||||||
|
B745C1CA:Info:Stadium Mud Buggies:INTV:1988
|
||||||
|
B745C1CA:ROM:5000:2000:16
|
||||||
|
B745C1CA:ROM:9000:2000:16
|
||||||
|
|
||||||
|
2DEACD15:Info:Stampede:Activision:1982
|
||||||
|
2DEACD15:ROM:5000:1000:16
|
||||||
|
|
||||||
|
72E11FCA:Info:Star Strike:Mattel:1981
|
||||||
|
72E11FCA:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D5B0135A:Info:Star Wars - The Empire Strikes Back:Parker Bros:1983
|
||||||
|
D5B0135A:ROM:5000:1000:16
|
||||||
|
|
||||||
|
A03EDF73:Info:Stack Em:Arnauld Chevallier:2004
|
||||||
|
A03EDF73:ROM:4800:2000:16
|
||||||
|
|
||||||
|
66D396C0:Info:Stonix:Arnauld Chevallier:2004
|
||||||
|
66D396C0:ROM:5000:2000:16
|
||||||
|
66D396C0:ROM:D000:1000:16
|
||||||
|
66D396C0:ROM:F000:1000:16
|
||||||
|
|
||||||
|
B119027D:Info:Stonix Beta 1.2:Arnauld Chevallier:2003
|
||||||
|
B119027D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
4830F720:Info:Street:Mattel:1981
|
||||||
|
4830F720:ROM:5000:1000:16
|
||||||
|
|
||||||
|
3D9949EA:Info:Sub Hunt:Mattel:1981
|
||||||
|
3D9949EA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
8F7D3069:Info:Super Cobra:Konami:1983
|
||||||
|
8F7D3069:ROM:5000:2000:16
|
||||||
|
|
||||||
|
BAB638F2:Info:Super Masters!:Mattel:1982
|
||||||
|
BAB638F2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
16BFB8EB:Info:Super Pro Decathlon:INTV:1978
|
||||||
|
16BFB8EB:ROM:5000:2000:16
|
||||||
|
16BFB8EB:ROM:9000:2000:16
|
||||||
|
|
||||||
|
32076E9D:Info:Super Pro Football:INTV:1986
|
||||||
|
32076E9D:ROM:5000:2000:16
|
||||||
|
32076E9D:ROM:9000:2000:16
|
||||||
|
|
||||||
|
51B82EB7:Info:Super Soccer:Mattel:1983
|
||||||
|
51B82EB7:ROM:5000:2000:16
|
||||||
|
51B82EB7:ROM:D000:1000:16
|
||||||
|
51B82EB7:ROM:F000:1000:16
|
||||||
|
|
||||||
|
15E88FCE:Info:Swords and Serpents:Imagic:1982
|
||||||
|
15E88FCE:ROM:5000:2000:16
|
||||||
|
|
||||||
|
1F584A69:Info:Takeover:Mattel:1982
|
||||||
|
1F584A69:ROM:5000:1000:16
|
||||||
|
|
||||||
|
03E9E62E:Info:Tennis:Mattel:1980
|
||||||
|
03E9E62E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D43FD410:Info:Tetris (GPL):Joseph Zbiciak:2000
|
||||||
|
D43FD410:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F3DF94E0:Info:Thin Ice:Mattel:1983
|
||||||
|
F3DF94E0:ROM:5000:2000:16
|
||||||
|
F3DF94E0:ROM:D000:1000:16
|
||||||
|
F3DF94E0:ROM:F000:1000:16
|
||||||
|
|
||||||
|
D6495910:Info:Thin Ice (Prototype):Mattel:1983
|
||||||
|
D6495910:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C1F1CA74:Info:Thunder Castle:Mattel:1982
|
||||||
|
C1F1CA74:ROM:5000:2000:16
|
||||||
|
C1F1CA74:ROM:D000:1000:16
|
||||||
|
C1F1CA74:ROM:F000:1000:16
|
||||||
|
|
||||||
|
D1D352A0:Info:Tower of Doom:Mattel:1986
|
||||||
|
D1D352A0:ROM:5000:2000:16
|
||||||
|
D1D352A0:ROM:9000:2000:16
|
||||||
|
D1D352A0:ROM:D000:1000:16
|
||||||
|
D1D352A0:ROM:F000:1000:16
|
||||||
|
|
||||||
|
1AC989E2:Info:Triple Action:Mattel:1981
|
||||||
|
1AC989E2:ROM:5000:1000:16
|
||||||
|
|
||||||
|
095638C0:Info:Triple Challenge:INTV:1986
|
||||||
|
095638C0:ROM:5000:2000:16
|
||||||
|
095638C0:ROM:9000:2000:16
|
||||||
|
095638C0:ROM:C000:0800:16
|
||||||
|
095638C0:ROM:D000:1000:16
|
||||||
|
|
||||||
|
7A558CF5:Info:Tron Maze-A-Tron:Mattel:1981
|
||||||
|
7A558CF5:ROM:5000:2000:16
|
||||||
|
|
||||||
|
CA447BBD:Info:Tron Deadly Discs:Mattel:1981
|
||||||
|
CA447BBD:ROM:5000:1000:16
|
||||||
|
|
||||||
|
07FB9435:Info:Tron Solar Sailer:Mattel:1982
|
||||||
|
07FB9435:ROM:5000:2000:16
|
||||||
|
07FB9435:ROM:D000:1000:16
|
||||||
|
07FB9435:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
6F23A741:Info:Tropical Trouble:Imagic:1982
|
||||||
|
6F23A741:ROM:5000:2000:16
|
||||||
|
|
||||||
|
734F3260:Info:Truckin':Imagic:1983
|
||||||
|
734F3260:ROM:5000:2000:16
|
||||||
|
|
||||||
|
275F3512:Info:Turbo:Coleco:1983
|
||||||
|
275F3512:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6FA698B3:Info:Tutankham:Parker Bros:1983
|
||||||
|
6FA698B3:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F093E801:Info:U.S. Ski Team Skiing:Mattel:1980
|
||||||
|
F093E801:ROM:5000:1000:16
|
||||||
|
|
||||||
|
752FD927:Info:USCF Chess:Mattel:1981
|
||||||
|
752FD927:ROM:5000:2000:16
|
||||||
|
752FD927:RAM:D000:400:8
|
||||||
|
|
||||||
|
F9E0789E:Info:Utopia:Mattel:1981
|
||||||
|
F9E0789E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
A4A20354:Info:Vectron:Mattel:1982
|
||||||
|
A4A20354:ROM:5000:2000:16
|
||||||
|
A4A20354:ROM:D000:1000:16
|
||||||
|
|
||||||
|
6EFA67B2:Info:Venture:Coleco:1982
|
||||||
|
6EFA67B2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F1ED7D27:Info:White Water!:Imagic:1983
|
||||||
|
F1ED7D27:ROM:5000:2000:16
|
||||||
|
|
||||||
|
15D9D27A:Info:World Cup Football:Nice Ideas:1985
|
||||||
|
15D9D27A:ROM:5000:2000:16
|
||||||
|
15D9D27A:ROM:D000:1000:16
|
||||||
|
15D9D27A:ROM:F000:1000:16
|
||||||
|
|
||||||
|
C2063C08:Info:World Series Major League Baseball:Mattel:1983
|
||||||
|
C2063C08:ROM:5000:2000:16
|
||||||
|
C2063C08:ROM:D000:1000:16
|
||||||
|
C2063C08:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
|
||||||
|
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
|
||||||
|
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0001
|
||||||
|
C2063C08:Peripheral:Intellivoice:Optional
|
||||||
|
C2063C08:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
A12C27E1:Info:World Series Major League Baseball (Bad Dump):Mattel:1983
|
||||||
|
A12C27E1:ROM:5000:2000:16
|
||||||
|
A12C27E1:ROM:D000:1000:16
|
||||||
|
A12C27E1:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
|
||||||
|
A12C27E1:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
|
||||||
|
A12C27E1:Peripheral:Intellivoice:Optional
|
||||||
|
A12C27E1:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
24B667B9:Info:Worm Whomper:Activision:1983
|
||||||
|
24B667B9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
15C65DC5:Info:Zaxxon:Coleco:1982
|
||||||
|
15C65DC5:ROM:5000:2000:16
|
||||||
|
|
||||||
|
D89AEC27:Info:Zombie Marbles:John Doherty:2004
|
||||||
|
D89AEC27:ROM:5000:2000:16
|
144
arm9/source/emucore/ripxbf.c
Normal file
144
arm9/source/emucore/ripxbf.c
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "ripxbf.h"
|
||||||
|
|
||||||
|
UINT64 freadInt(FILE* file, UINT32 size)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int ret = 0;
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
ret <<= 8;
|
||||||
|
ret |= fgetc(file);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT16 freadUINT16(FILE* file)
|
||||||
|
{
|
||||||
|
return (UINT16)freadInt(file, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT32 freadUINT32(FILE* file)
|
||||||
|
{
|
||||||
|
return (UINT32)freadInt(file, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
UINT64 freadUINT64(FILE* file)
|
||||||
|
{
|
||||||
|
return freadInt(file, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
void freadString(FILE* file, CHAR* out, UINT32 maxLength)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned char next;
|
||||||
|
unsigned int completeLength = freadUINT32(file);
|
||||||
|
if (completeLength+1 < maxLength)
|
||||||
|
maxLength = completeLength+1;
|
||||||
|
|
||||||
|
for (i = 0; i < completeLength; i++) {
|
||||||
|
next = (unsigned char)fgetc(file);
|
||||||
|
if (i < (maxLength-1))
|
||||||
|
out[i] = next;
|
||||||
|
}
|
||||||
|
out[maxLength-1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void fwriteUINT16(FILE* file, UINT16 num)
|
||||||
|
{
|
||||||
|
fputc((num>>8)&0xFF, file);
|
||||||
|
fputc(num&0xFF, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fwriteUINT32(FILE* file, UINT32 num)
|
||||||
|
{
|
||||||
|
fputc((num>>24)&0xFF, file);
|
||||||
|
fputc((num>>16)&0xFF, file);
|
||||||
|
fputc((num>>8)&0xFF, file);
|
||||||
|
fputc(num&0xFF, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fwriteUINT64(FILE* file, UINT64 num)
|
||||||
|
{
|
||||||
|
fputc((int)(num>>56)&0xFF, file);
|
||||||
|
fputc((int)(num>>48)&0xFF, file);
|
||||||
|
fputc((int)(num>>40)&0xFF, file);
|
||||||
|
fputc((int)(num>>32)&0xFF, file);
|
||||||
|
fputc((int)(num>>24)&0xFF, file);
|
||||||
|
fputc((int)(num>>16)&0xFF, file);
|
||||||
|
fputc((int)(num>>8)&0xFF, file);
|
||||||
|
fputc((int)num&0xFF, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fwriteString(FILE* file, const CHAR* s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int length = (int)strlen(s);
|
||||||
|
fwriteUINT32(file, length);
|
||||||
|
for (i = 0; i < length; i++)
|
||||||
|
fputc(s[i], file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
RipSystem SYSTEMS[] =
|
||||||
|
{
|
||||||
|
{ ID_SYSTEM_INTELLIVISION,
|
||||||
|
"Intellivision",
|
||||||
|
2, 2,
|
||||||
|
{ { "Master Component",
|
||||||
|
{ { "Executive ROM",
|
||||||
|
{ { "Original Executive ROM", 0xCBCE86F7 },
|
||||||
|
{ "Intellivision 2 Executive ROM", 0 },
|
||||||
|
{ "Sears Executive ROM", 0 },
|
||||||
|
{ "GPL Executive ROM", 0 },
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
{ "Graphics ROM",
|
||||||
|
{ { "Original GROM", 0x683A4158 },
|
||||||
|
{ "GPL GROM", 0 },
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
{ "Entertainment Computer System",
|
||||||
|
{ { "ECS BIOS",
|
||||||
|
{ { "Original ECS BIOS", 0xEA790A06 },
|
||||||
|
},},
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
{ "Intellivoice",
|
||||||
|
{ { "Intellivoice BIOS",
|
||||||
|
{ { "Original Intellivoice BIOS", 0x0DE7579D },
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
{ ID_SYSTEM_ATARI5200,
|
||||||
|
"Atari 5200",
|
||||||
|
2, 1,
|
||||||
|
{ { "Main Console",
|
||||||
|
{ { "BIOS",
|
||||||
|
{ { "Original BIOS", 0x4248D3E3 },
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
0,
|
||||||
|
},},
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
RipSystem* getSystem(UINT32 systemID)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
while (*((int*)(&SYSTEMS[i])) != 0) {
|
||||||
|
if (SYSTEMS[i].systemID == systemID)
|
||||||
|
return &SYSTEMS[i];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
*/
|
120
arm9/source/emucore/ripxbf.h
Normal file
120
arm9/source/emucore/ripxbf.h
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* This file contains a list of declarations useful for working with
|
||||||
|
* files in the XBF format.
|
||||||
|
*
|
||||||
|
* Author: Kyle Davis
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//compatibility flags
|
||||||
|
typedef enum _BiosCompatibility
|
||||||
|
{
|
||||||
|
BIOS_PREFERRED = 0,
|
||||||
|
BIOS_COMPATIBLE = 1,
|
||||||
|
BIOS_INCOMPATIBLE = 2
|
||||||
|
} BiosCompatibility;
|
||||||
|
|
||||||
|
typedef enum _PeripheralCompatibility
|
||||||
|
{
|
||||||
|
PERIPH_REQUIRED = 0,
|
||||||
|
PERIPH_OPTIONAL = 1,
|
||||||
|
PERIPH_COMPATIBLE = 2,
|
||||||
|
PERIPH_INCOMPATIBLE = 3
|
||||||
|
} PeripheralCompatibility;
|
||||||
|
|
||||||
|
UINT64 freadInt(FILE*, UINT32 length);
|
||||||
|
UINT16 freadUINT16(FILE*);
|
||||||
|
UINT32 freadUINT32(FILE*);
|
||||||
|
UINT64 freadUINT64(FILE*);
|
||||||
|
void freadString(FILE*, CHAR* s, UINT32 maxLength);
|
||||||
|
void fwriteUINT16(FILE*, UINT16);
|
||||||
|
void fwriteUINT32(FILE*, UINT32);
|
||||||
|
void fwriteUINT64(FILE*, UINT64);
|
||||||
|
void fwriteString(FILE*, const CHAR*);
|
||||||
|
|
||||||
|
//the RIP magic number
|
||||||
|
#define RIP_MAGIC_NUMBER 0x3F383A347651B5DAll
|
||||||
|
#define RIP_MAJOR_REVISION 1
|
||||||
|
#define RIP_MINOR_REVISION 0
|
||||||
|
|
||||||
|
//record IDs
|
||||||
|
#define ID_HEADER_RECORD 0xFC41466E
|
||||||
|
#define ID_BIOS_COMPAT_RECORD 0xC183BF3C
|
||||||
|
#define ID_NAME_RECORD 0x5ECC1C53
|
||||||
|
#define ID_PERIPH_COMPAT_RECORD 0xAE4CEDB7
|
||||||
|
#define ID_PRODUCER_RECORD 0x86596370
|
||||||
|
#define ID_YEAR_RECORD 0x9199748D
|
||||||
|
#define ID_RAM_RECORD 0xCF1DC943
|
||||||
|
#define ID_ROM_RECORD 0xA365AF69
|
||||||
|
|
||||||
|
//emulator IDs
|
||||||
|
#define ID_EMULATOR_BLISS 0xC183BF3C
|
||||||
|
|
||||||
|
//system IDs
|
||||||
|
#define ID_SYSTEM_ATARI5200 0xE4453A0B
|
||||||
|
#define ID_SYSTEM_INTELLIVISION 0x4AC771F8
|
||||||
|
#define ID_PERIPH_ECS 0x143D9A97
|
||||||
|
#define ID_PERIPH_INTELLIVOICE 0x6EFF540A
|
||||||
|
|
||||||
|
//bios numbers
|
||||||
|
#define A5200_P_MASTER_COMPONENT 0
|
||||||
|
#define A5200_BT_BIOS 0
|
||||||
|
#define A5200_B_ORIGINAL_BIOS 0
|
||||||
|
|
||||||
|
#define INTV_P_MASTER_COMPONENT 0
|
||||||
|
#define INTV_BT_EXEC 0
|
||||||
|
#define INTV_B_ORIGINAL_EXEC 0
|
||||||
|
#define INTV_B_INTY2_EXEC 1
|
||||||
|
#define INTV_B_SEARS_EXEC 2
|
||||||
|
#define INTV_B_GPL_EXEC 3
|
||||||
|
#define INTV_BT_GROM 1
|
||||||
|
#define INTV_B_ORIGINAL_GROM 0
|
||||||
|
#define INTV_B_GPL_GROM 1
|
||||||
|
#define INTV_P_ECS 1
|
||||||
|
#define INTV_BT_ECS_BIOS 0
|
||||||
|
#define INTV_B_ORIGINAL_ECS_BIOS 0
|
||||||
|
#define INTV_P_INTELLIVOICE 2
|
||||||
|
#define INTV_BT_IVOICE_BIOS 0
|
||||||
|
#define INTV_B_ORIGINAL_IVOICE_BIOS 0
|
||||||
|
|
||||||
|
/*
|
||||||
|
typedef struct _RipBios
|
||||||
|
{
|
||||||
|
CHAR* biosName;
|
||||||
|
UINT32 biosCRC32;
|
||||||
|
} RipBios;
|
||||||
|
|
||||||
|
typedef struct _RipBiosType
|
||||||
|
{
|
||||||
|
CHAR* biosTypeName;
|
||||||
|
RipBios bioses[16];
|
||||||
|
} RipBiosType;
|
||||||
|
|
||||||
|
typedef struct _RipPeripheral
|
||||||
|
{
|
||||||
|
CHAR* peripheralName;
|
||||||
|
RipBiosType biosTypes[16];
|
||||||
|
} RipPeripheral;
|
||||||
|
|
||||||
|
typedef struct _RipSystem
|
||||||
|
{
|
||||||
|
UINT32 systemID;
|
||||||
|
CHAR* systemName;
|
||||||
|
UINT8 addressByteWidth;
|
||||||
|
UINT8 valueByteWidth;
|
||||||
|
RipPeripheral peripherals[16];
|
||||||
|
} RipSystem;
|
||||||
|
|
||||||
|
RipSystem* getSystem(UINT32 systemID);
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
174
arm9/source/emucore/types.h
Normal file
174
arm9/source/emucore/types.h
Normal file
@ -0,0 +1,174 @@
|
|||||||
|
|
||||||
|
#ifndef TYPES_H
|
||||||
|
#define TYPES_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern int debug1, debug2;
|
||||||
|
|
||||||
|
//primitive types
|
||||||
|
typedef signed char INT8;
|
||||||
|
typedef unsigned char UINT8;
|
||||||
|
typedef signed short INT16;
|
||||||
|
typedef unsigned short UINT16;
|
||||||
|
typedef signed int INT32;
|
||||||
|
typedef unsigned int UINT32;
|
||||||
|
|
||||||
|
// There is no ANSI standard for 64 bit integers :(
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
typedef __int64 INT64; // MS VC++
|
||||||
|
typedef unsigned __int64 UINT64; // MS VC++
|
||||||
|
#else
|
||||||
|
typedef signed long long int INT64; // C99 C++11
|
||||||
|
typedef unsigned long long int UINT64; // C99 C++11
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef char CHAR;
|
||||||
|
|
||||||
|
#if !defined(BOOL)
|
||||||
|
#if defined(__MACH__)
|
||||||
|
typedef signed char BOOL;
|
||||||
|
#else
|
||||||
|
typedef int BOOL;
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(TRUE)
|
||||||
|
#define TRUE (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(FALSE)
|
||||||
|
#define FALSE (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(NULL)
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#define NULL (0)
|
||||||
|
#else
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SWAP32BIT(swap) ((((swap) << 24) & 0xFF000000) | \
|
||||||
|
(((swap) << 8) & 0x00FF0000) | \
|
||||||
|
(((swap) >> 8) & 0x0000FF00) | \
|
||||||
|
(((swap) >> 24) & 0x000000FF))
|
||||||
|
|
||||||
|
#if !defined(__LITTLE_ENDIAN__) && defined(_WIN32)
|
||||||
|
#define __LITTLE_ENDIAN__ (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__LITTLE_ENDIAN__)
|
||||||
|
#define FOURCHAR(x) SWAP32BIT((UINT32)(x))
|
||||||
|
#else
|
||||||
|
#define FOURCHAR(x) (x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(TYPEDEF_STRUCT_PACK)
|
||||||
|
#define TYPEDEF_STRUCT_PACK(_x_) typedef struct __attribute__((__packed__)) _x_
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
typedef unsigned char UCHAR;
|
||||||
|
typedef unsigned short USHORT;
|
||||||
|
|
||||||
|
#ifndef FLOAT
|
||||||
|
typedef float FLOAT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef GUID
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int data1;
|
||||||
|
unsigned short data2;
|
||||||
|
unsigned short data3;
|
||||||
|
unsigned char data4[8];
|
||||||
|
} GUID;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ZeroMemory
|
||||||
|
#define ZeroMemory(ptr,size) memset(ptr, 0, size)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef strcmpi
|
||||||
|
#define strcmpi strcasecmp
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MAX_PATH
|
||||||
|
#define MAX_PATH 256
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// total hack for non-windows
|
||||||
|
#ifndef GUID_SysKeyboard
|
||||||
|
#define GUID_SysKeyboard (GUID){0}
|
||||||
|
#define DIK_NUMPAD7 ((INT32)0x81)
|
||||||
|
#define DIK_NUMPAD8 ((INT32)0x41)
|
||||||
|
#define DIK_NUMPAD9 ((INT32)0x21)
|
||||||
|
#define DIK_NUMPAD4 ((INT32)0x82)
|
||||||
|
#define DIK_NUMPAD5 ((INT32)0x42)
|
||||||
|
#define DIK_NUMPAD6 ((INT32)0x22)
|
||||||
|
#define DIK_NUMPAD1 ((INT32)0x84)
|
||||||
|
#define DIK_NUMPAD2 ((INT32)0x44)
|
||||||
|
#define DIK_NUMPAD3 ((INT32)0x24)
|
||||||
|
#define DIK_NUMPADPERIOD ((INT32)0x88)
|
||||||
|
#define DIK_NUMPAD0 ((INT32)0x48)
|
||||||
|
#define DIK_NUMPADENTER ((INT32)0x28)
|
||||||
|
#define DIK_SPACE ((INT32)0xA0)
|
||||||
|
#define DIK_LALT ((INT32)0x00)
|
||||||
|
#define DIK_LCONTROL ((INT32)0x60)
|
||||||
|
#define DIK_RCONTROL ((INT32)0xC0)
|
||||||
|
#define DIK_UP ((INT32)0x04)
|
||||||
|
#define DIK_W ((INT32)0x16)
|
||||||
|
#define DIK_RIGHT ((INT32)0x02)
|
||||||
|
#define DIK_S ((INT32)0x13)
|
||||||
|
#define DIK_DOWN ((INT32)0x01)
|
||||||
|
#define DIK_A ((INT32)0x19)
|
||||||
|
#define DIK_LEFT ((INT32)0x08)
|
||||||
|
#define DIK_Q ((INT32)0x1C)
|
||||||
|
|
||||||
|
#define DIK_COMMA ((INT32)0x0)
|
||||||
|
#define DIK_N ((INT32)0x0)
|
||||||
|
#define DIK_V ((INT32)0x0)
|
||||||
|
#define DIK_X ((INT32)0x0)
|
||||||
|
#define DIK_PERIOD ((INT32)0x0)
|
||||||
|
#define DIK_M ((INT32)0x0)
|
||||||
|
#define DIK_B ((INT32)0x0)
|
||||||
|
#define DIK_C ((INT32)0x0)
|
||||||
|
#define DIK_Z ((INT32)0x0)
|
||||||
|
#define DIK_SEMICOLON ((INT32)0x0)
|
||||||
|
#define DIK_K ((INT32)0x0)
|
||||||
|
#define DIK_H ((INT32)0x0)
|
||||||
|
#define DIK_F ((INT32)0x0)
|
||||||
|
#define DIK_P ((INT32)0x0)
|
||||||
|
#define DIK_I ((INT32)0x0)
|
||||||
|
#define DIK_Y ((INT32)0x0)
|
||||||
|
#define DIK_R ((INT32)0x0)
|
||||||
|
#define DIK_GRAVE ((INT32)0x0)
|
||||||
|
#define DIK_TAB ((INT32)0x0)
|
||||||
|
#define DIK_RETURN ((INT32)0x0)
|
||||||
|
#define DIK_O ((INT32)0x0)
|
||||||
|
#define DIK_U ((INT32)0x0)
|
||||||
|
#define DIK_T ((INT32)0x0)
|
||||||
|
#define DIK_E ((INT32)0x0)
|
||||||
|
#define DIK_L ((INT32)0x0)
|
||||||
|
#define DIK_J ((INT32)0x0)
|
||||||
|
#define DIK_G ((INT32)0x0)
|
||||||
|
#define DIK_D ((INT32)0x0)
|
||||||
|
#define DIK_LSHIFT ((INT32)0x0)
|
||||||
|
|
||||||
|
#define DIK_F2 ((INT32)0x0)
|
||||||
|
|
||||||
|
#define DI__WTFX ((INT32)0xFA)
|
||||||
|
#define DI__WTFY ((INT32)0xFB)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //TYPES_H
|
||||||
|
|
40
arm9/source/main.cpp
Normal file
40
arm9/source/main.cpp
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#include <nds.h>
|
||||||
|
#include <fat.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ds_tools.h"
|
||||||
|
|
||||||
|
#include "clickNoQuit_wav.h"
|
||||||
|
#include "clickQuit_wav.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
// Init sound
|
||||||
|
consoleDemoInit();
|
||||||
|
soundEnable();
|
||||||
|
lcdMainOnTop();
|
||||||
|
|
||||||
|
// Init Fat
|
||||||
|
if (!fatInitDefault())
|
||||||
|
{
|
||||||
|
iprintf("Unable to initialize libfat!\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init Timer
|
||||||
|
dsInitTimer();
|
||||||
|
|
||||||
|
// Init sound FIFO
|
||||||
|
dsInstallSoundEmuFIFO();
|
||||||
|
|
||||||
|
// Setup the main screen handling
|
||||||
|
dsInitScreenMain();
|
||||||
|
|
||||||
|
// Main loop of emulation
|
||||||
|
dsMainLoop();
|
||||||
|
|
||||||
|
// Free memory to be correct
|
||||||
|
dsFreeEmu();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
699
knowncarts.cfg
Normal file
699
knowncarts.cfg
Normal file
@ -0,0 +1,699 @@
|
|||||||
|
D7C78754:Info:4-TRIS (GPL):Joseph Zbiciak:2000
|
||||||
|
D7C78754:ROM:5000:2000:16
|
||||||
|
|
||||||
|
B91488E2:Info:4-TRIS (GPL):Joseph Zbiciak:2001
|
||||||
|
B91488E2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A60E25FC:Info:ABPA Backgammon:Mattel:1978
|
||||||
|
A60E25FC:ROM:5000:1000:16
|
||||||
|
|
||||||
|
F8B1F2B7:Info:Advanced Dungeons and Dragons:Mattel:1982
|
||||||
|
F8B1F2B7:ROM:5000:2000:16
|
||||||
|
|
||||||
|
16C3B62F:Info:Advanced Dungeons and Dragons - Treasure of Tarmin:Mattel:1982
|
||||||
|
16C3B62F:ROM:5000:2000:16
|
||||||
|
|
||||||
|
11C3BCFA:Info:Adventure (AD&D - Cloudy Mountain):Mattel:1982
|
||||||
|
11C3BCFA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2C668249:Info:Air Strike:Mattel:1982
|
||||||
|
2C668249:ROM:5000:1000:16
|
||||||
|
|
||||||
|
B45633CF:Info:All-Stars Major League Baseball:Mattel:1980
|
||||||
|
B45633CF:ROM:5000:2000:16
|
||||||
|
B45633CF:ROM:D000:1000:16
|
||||||
|
|
||||||
|
6F91FBC1:Info:Armor Battle:Mattel:1978
|
||||||
|
6F91FBC1:ROM:5000:1000:16
|
||||||
|
|
||||||
|
00BE8BBA:Info:Astrosmash - Meteor:Mattel:1981
|
||||||
|
00BE8BBA:ROM:5000:1000:16
|
||||||
|
|
||||||
|
FAB2992C:Info:Astrosmash:Mattel:1981
|
||||||
|
FAB2992C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
13FF363C:Info:Atlantis:Imagic:1981
|
||||||
|
13FF363C:ROM:4800:2000:16
|
||||||
|
|
||||||
|
B35C1101:Info:Auto Racing:Mattel:1979
|
||||||
|
B35C1101:ROM:5000:1000:16
|
||||||
|
|
||||||
|
8AD19AB3:Info:B-17 Bomber:Mattel:1981
|
||||||
|
8AD19AB3:ROM:5000:2000:16
|
||||||
|
8AD19AB3:ROM:D000:1000:16
|
||||||
|
8AD19AB3:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
DAB36628:Info:Baseball:Mattel:1978
|
||||||
|
DAB36628:ROM:5000:1000:16
|
||||||
|
|
||||||
|
EAF650CC:Info:BeamRider:Activision:1983
|
||||||
|
EAF650CC:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C047D487:Info:Beauty and the Beast:Imagic:1982
|
||||||
|
C047D487:ROM:4800:2000:16
|
||||||
|
|
||||||
|
B03F739B:Info:Blockade Runner:Interphase:1983
|
||||||
|
B03F739B:ROM:5000:2000:16
|
||||||
|
|
||||||
|
4728C3BD:Info:Blow Out:Mattel:1983
|
||||||
|
4728C3BD:ROM:5000:1000:16
|
||||||
|
|
||||||
|
515E1D7E:Info:Body Slam Super Pro Wrestling:Mattel:1988
|
||||||
|
515E1D7E:ROM:5000:2000:16
|
||||||
|
515E1D7E:ROM:9000:2000:16
|
||||||
|
|
||||||
|
32697B72:Info:Bomb Squad:Mattel:1982
|
||||||
|
32697B72:ROM:5000:2000:16
|
||||||
|
32697B72:ROM:D000:1000:16
|
||||||
|
32697B72:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
18E08520:Info:Bouncing Pixels (GPL):JRMZ Electronics:1999
|
||||||
|
18E08520:ROM:5000:0202:16
|
||||||
|
|
||||||
|
AB87C16F:Info:Boxing:Mattel:1980
|
||||||
|
AB87C16F:ROM:5000:1000:16
|
||||||
|
|
||||||
|
9F85015B:Info:Brickout!:Mattel:1981
|
||||||
|
9F85015B:ROM:5000:1000:16
|
||||||
|
|
||||||
|
999CCEED:Info:Bump 'N' Jump:Mattel:1982-83
|
||||||
|
999CCEED:ROM:5000:2000:16
|
||||||
|
999CCEED:ROM:D000:1000:16
|
||||||
|
999CCEED:ROM:F000:1000:16
|
||||||
|
|
||||||
|
43806375:Info:BurgerTime!:Mattel:1982
|
||||||
|
43806375:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C92BAAE8:Info:BurgerTime! - New Levels Hack:David Harley:2002
|
||||||
|
C92BAAE8:ROM:5000:2000:16
|
||||||
|
|
||||||
|
FA492BBD:Info:Buzz Bombers:Mattel:1982
|
||||||
|
FA492BBD:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2A1E0C1C:Info:Buzz Bombers:Mattel:1982
|
||||||
|
2A1E0C1C:ROM:5000:2000:16
|
||||||
|
|
||||||
|
43870908:Info:Carnival:Coleco:1982
|
||||||
|
43870908:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D5363B8C:Info:Centipede:Atarisoft:1983
|
||||||
|
D5363B8C:ROM:6000:2000:16
|
||||||
|
|
||||||
|
4CC46A04:Info:Championship Tennis:Nice Ideas:1985
|
||||||
|
4CC46A04:ROM:5000:2000:16
|
||||||
|
4CC46A04:ROM:D000:2000:16
|
||||||
|
|
||||||
|
36E1D858:Info:Checkers:Mattel:1979
|
||||||
|
36E1D858:ROM:5000:1000:16
|
||||||
|
|
||||||
|
0BF464C6:Info:Chip Shot Super Pro Golf:Mattel:1987
|
||||||
|
0BF464C6:ROM:5000:2000:16
|
||||||
|
0BF464C6:ROM:9000:2000:16
|
||||||
|
|
||||||
|
47FDD8A8:Info:Choplifter:Mattel:1983
|
||||||
|
47FDD8A8:ROM:5000:2000:16
|
||||||
|
47FDD8A8:ROM:D000:2000:16
|
||||||
|
|
||||||
|
3289C8BA:Info:Commando:INTV:1987
|
||||||
|
3289C8BA:ROM:5000:2000:16
|
||||||
|
3289C8BA:ROM:9000:2000:16
|
||||||
|
|
||||||
|
4B23A757:Info:Congo Bongo:Sega:1983
|
||||||
|
4B23A757:ROM:5000:3000:16
|
||||||
|
|
||||||
|
E1EE408F:Info:Crazy Clones:Mattel:1981
|
||||||
|
E1EE408F:ROM:5000:1000:16
|
||||||
|
|
||||||
|
CDC14ED8:Info:Deadly Dogs!:Unknown:1987
|
||||||
|
CDC14ED8:ROM:5000:1000:16
|
||||||
|
|
||||||
|
6802B191:Info:Deep Pockets - Super Pro Pool and Billiards:Realtime:1990
|
||||||
|
6802B191:ROM:5000:2000:16
|
||||||
|
6802B191:ROM:9000:2000:16
|
||||||
|
|
||||||
|
D8F99AA2:Info:Defender:Atarisoft:1983
|
||||||
|
D8F99AA2:ROM:5000:3000:16
|
||||||
|
|
||||||
|
5E6A8CD8:Info:Demon Attack:Imagic:1982
|
||||||
|
5E6A8CD8:ROM:4800:2000:16
|
||||||
|
|
||||||
|
159AF7F7:Info:Dig Dug:INTV:1987
|
||||||
|
159AF7F7:ROM:5000:3000:16
|
||||||
|
159AF7F7:ROM:9000:1000:16
|
||||||
|
|
||||||
|
13EE56F1:Info:Diner:INTV:1987
|
||||||
|
13EE56F1:ROM:5000:2000:16
|
||||||
|
13EE56F1:ROM:9000:2000:16
|
||||||
|
|
||||||
|
C30F61C0:Info:Donkey Kong:Coleco:1982
|
||||||
|
C30F61C0:ROM:5000:1000:16
|
||||||
|
|
||||||
|
6DF61A9F:Info:Donkey Kong Jr:Coleco:1982
|
||||||
|
6DF61A9F:ROM:5000:2000:16
|
||||||
|
|
||||||
|
84BEDCC1:Info:Dracula:Imagic:1982
|
||||||
|
84BEDCC1:ROM:5000:2000:16
|
||||||
|
|
||||||
|
AF8718A1:Info:Dragonfire:Imagic:1982
|
||||||
|
AF8718A1:ROM:5000:1000:16
|
||||||
|
|
||||||
|
3B99B889:Info:Dreadnaught Factor, The:Activision:1983
|
||||||
|
3B99B889:ROM:5000:2000:16
|
||||||
|
|
||||||
|
BF4D0E9B:Info:Dreadnaught Factor, The (Prototype):Activision:1983
|
||||||
|
BF4D0E9B:ROM:5000:2000:16
|
||||||
|
|
||||||
|
20ACE89D:Info:Easter Eggs:Mattel:1981
|
||||||
|
20ACE89D:ROM:5000:1000:16
|
||||||
|
|
||||||
|
54A3FC11:Info:Electric Company - Math Fun:CTW:1978
|
||||||
|
54A3FC11:ROM:5000:1000:16
|
||||||
|
|
||||||
|
C9EAACAB:Info:Electric Company - Word Fun:CTW:1980
|
||||||
|
C9EAACAB:ROM:5000:1000:16
|
||||||
|
|
||||||
|
4221EDE7:Info:Fathom:Imagic:1983
|
||||||
|
4221EDE7:ROM:5000:2000:16
|
||||||
|
|
||||||
|
37222762:Info:Frog Bog:Mattel:1982
|
||||||
|
37222762:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D27495E9:Info:Frogger:Parker Bros:1983
|
||||||
|
D27495E9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
DBCA82C5:Info:Go For The Gold:Mattel:1981
|
||||||
|
DBCA82C5:ROM:5000:2000:16
|
||||||
|
|
||||||
|
291AC826:Info:Grid Shock:Mattel:1982
|
||||||
|
291AC826:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E573863A:Info:Groovy! (GPL):JRMZ Electronics:1999
|
||||||
|
E573863A:ROM:5000:1E48:16
|
||||||
|
|
||||||
|
4B8C5932:Info:Happy Trails:Activision:1983
|
||||||
|
4B8C5932:ROM:5000:1000:16
|
||||||
|
|
||||||
|
120B53A9:Info:Happy Trails (Overdump):Activision:1983
|
||||||
|
120B53A9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
B6A3D4DE:Info:Hard Hat:Mattel:1979
|
||||||
|
B6A3D4DE:ROM:5000:2000:16
|
||||||
|
|
||||||
|
B5C7F25D:Info:Horse Racing:Mattel:1980
|
||||||
|
B5C7F25D:ROM:5000:1000:16
|
||||||
|
|
||||||
|
FF83FF80:Info:Hover Force:Mattel:1986
|
||||||
|
FF83FF80:ROM:5000:2000:16
|
||||||
|
FF83FF80:ROM:9000:3000:16
|
||||||
|
FF83FF80:ROM:D000:1000:16
|
||||||
|
|
||||||
|
A3147630:Info:Hypnotic Lights:Mattel:1981
|
||||||
|
A3147630:ROM:5000:1000:16
|
||||||
|
|
||||||
|
4F3E3F69:Info:Ice Trek:Imagic:1983
|
||||||
|
4F3E3F69:ROM:5000:2000:16
|
||||||
|
|
||||||
|
02919024:Info:Intellivision - Intelligent Television Demo:Mattel:1978
|
||||||
|
02919024:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C83EEA4C:Info:Intellivision Test Cartridge and Baseball:Mattel:1978
|
||||||
|
C83EEA4C:ROM:5000:1000:16
|
||||||
|
C83EEA4C:ROM:7000:1000:16
|
||||||
|
|
||||||
|
985A78ED:Info:IntyOS 0.2 Alpha:Arnauld Chevallier:2003
|
||||||
|
985A78ED:ROM:5000:1000:16
|
||||||
|
985A78ED:RAM:D000:1000:16
|
||||||
|
985A78ED:RAM:F000:1000:16
|
||||||
|
|
||||||
|
EE5F1BE2:Info:Jetsons, The - Ways With Words:Mattel:1983
|
||||||
|
EE5F1BE2:ROM:5000:2000:16
|
||||||
|
EE5F1BE2:ROM:D000:1000:16
|
||||||
|
EE5F1BE2:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
4422868E:Info:King of the Mountain:Mattel:1982
|
||||||
|
4422868E:ROM:5000:2000:16
|
||||||
|
4422868E:ROM:D000:2000:16
|
||||||
|
|
||||||
|
8C9819A2:Info:Kool-Aid Man:Mattel:1983
|
||||||
|
8C9819A2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A6840736:Info:Lady Bug:Coleco:1983
|
||||||
|
A6840736:ROM:5000:2000:16
|
||||||
|
|
||||||
|
3825C25B:Info:Land Battle:Mattel:1982
|
||||||
|
3825C25B:ROM:5000:2000:16
|
||||||
|
3825C25B:RAM:D000:400:8
|
||||||
|
|
||||||
|
604611C0:Info:Las Vegas Blackjack and Poker:Mattel:1979
|
||||||
|
604611C0:ROM:5000:1000:16
|
||||||
|
|
||||||
|
48D74D3C:Info:Las Vegas Roulette:Mattel:1979
|
||||||
|
48D74D3C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
19360442:Info:League of Light (Prototype Alt1):Activision:1983
|
||||||
|
19360442:ROM:5000:2000:16
|
||||||
|
|
||||||
|
75EE64F6:Info:League of Light (Prototype Alt2):Activision:1983
|
||||||
|
75EE64F6:ROM:5000:2000:16
|
||||||
|
|
||||||
|
B4287B95:Info:League of Light (Prototype):Activision:1983
|
||||||
|
B4287B95:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2C5FD5FA:Info:Learning Fun I - Math Master Factor Fun:INTV:1987
|
||||||
|
2C5FD5FA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
632F6ADF:Info:Learning Fun II - Word Wizard Memory Fun:INTV:1987
|
||||||
|
632F6ADF:ROM:5000:2000:16
|
||||||
|
|
||||||
|
E00D1399:Info:Lock 'N' Chase:Mattel:1982
|
||||||
|
E00D1399:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6B6E80EE:Info:Loco-Motion:Mattel:1982
|
||||||
|
6B6E80EE:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F3B0C759:Info:Magic Carousel:Mattel:1982
|
||||||
|
F3B0C759:ROM:5000:2000:16
|
||||||
|
F3B0C759:ROM:D000:2000:16
|
||||||
|
|
||||||
|
573B9B6D:Info:Masters of the Universe - The Power of He-Man!:Mattel:1983
|
||||||
|
573B9B6D:ROM:5000:2000:16
|
||||||
|
573B9B6D:ROM:D000:1000:16
|
||||||
|
573B9B6D:ROM:F000:1000:16
|
||||||
|
|
||||||
|
7D0F8162:Info:Maze Demo #1 (GPL):JRMZ Electronics:2000
|
||||||
|
7D0F8162:ROM:5000:016E:16
|
||||||
|
|
||||||
|
2138DAD4:Info:Maze Demo #2 (GPL):JRMZ Electronics:2000
|
||||||
|
2138DAD4:ROM:5000:0175:16
|
||||||
|
|
||||||
|
FF68AA22:Info:Melody Blaster:Mattel:1983
|
||||||
|
FF68AA22:ROM:5000:2000:16
|
||||||
|
FF68AA22:ROM:D000:1000:16
|
||||||
|
FF68AA22:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
E00E23E7:Info:Mickey's Hello World:Mickey:2000
|
||||||
|
E00E23E7:ROM:5000:006F:16
|
||||||
|
|
||||||
|
E806AD91:Info:Microsurgeon:Imagic:1982
|
||||||
|
E806AD91:ROM:4800:2000:16
|
||||||
|
|
||||||
|
94096229:Info:Minehunter:Ryan Kinnen:2004
|
||||||
|
94096229:ROM:5000:2000:16
|
||||||
|
|
||||||
|
9D57498F:Info:Mind Strike!:Mattel:1982
|
||||||
|
9D57498F:ROM:5000:2000:16
|
||||||
|
9D57498F:ROM:D000:1000:16
|
||||||
|
9D57498F:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
6746607B:Info:Minotaur V1.1:Mattel:1981
|
||||||
|
6746607B:ROM:5000:2000:16
|
||||||
|
|
||||||
|
5A4CE519:Info:Minotaur V2:Mattel:1981
|
||||||
|
5A4CE519:ROM:5000:2000:16
|
||||||
|
|
||||||
|
BD731E3C:Info:Minotaur:Mattel:1981
|
||||||
|
BD731E3C:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2F9C93FC:Info:Minotaur (Treasure of Tarmin hack):Mattel:1981
|
||||||
|
2F9C93FC:ROM:5000:2000:16
|
||||||
|
|
||||||
|
11FB9974:Info:Mission X:Mattel:1982
|
||||||
|
11FB9974:ROM:5000:2000:16
|
||||||
|
|
||||||
|
5F6E1AF6:Info:Motocross:Mattel:1982
|
||||||
|
5F6E1AF6:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6B5EA9C4:Info:Mountain Madness Super Pro Skiing:INTV:1987
|
||||||
|
6B5EA9C4:ROM:5000:2000:16
|
||||||
|
|
||||||
|
598662F2:Info:Mouse Trap:Coleco:1982
|
||||||
|
598662F2:ROM:5000:1000:16
|
||||||
|
|
||||||
|
0B50A367:Info:Mr. Basic Meets Bits 'N Bytes (Bad Dump):Mattel:1983
|
||||||
|
0B50A367:ROM:5000:2000:16
|
||||||
|
0B50A367:ROM:D000:1000:16
|
||||||
|
0B50A367:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
BEF0B0C7:Info:Mr. Basic Meets Bits 'N Bytes:Mattel:1983
|
||||||
|
BEF0B0C7:ROM:5000:2000:16
|
||||||
|
BEF0B0C7:ROM:D000:1000:16
|
||||||
|
BEF0B0C7:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
DBAB54CA:Info:NASL Soccer:Mattel:1979
|
||||||
|
DBAB54CA:ROM:5000:1000:16
|
||||||
|
|
||||||
|
81E7FB8C:Info:NBA Basketball:Mattel:1978
|
||||||
|
81E7FB8C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
4B91CF16:Info:NFL Football:Mattel:1978
|
||||||
|
4B91CF16:ROM:5000:1000:16
|
||||||
|
|
||||||
|
76564A13:Info:NHL Hockey:Mattel:1979
|
||||||
|
76564A13:ROM:5000:1000:16
|
||||||
|
|
||||||
|
7334CD44:Info:Night Stalker:Mattel:1982
|
||||||
|
7334CD44:ROM:5000:1000:16
|
||||||
|
|
||||||
|
5EE2CC2A:Info:Nova Blast:Imagic:1983
|
||||||
|
5EE2CC2A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
E5D1A8D2:Info:Number Jumble:Mattel:1983
|
||||||
|
E5D1A8D2:ROM:5000:2000:16
|
||||||
|
E5D1A8D2:ROM:D000:1000:16
|
||||||
|
E5D1A8D2:ROM:F000:1000:16
|
||||||
|
|
||||||
|
A21C31C3:Info:Pac-Man:Atarisoft:1983
|
||||||
|
A21C31C3:ROM:5000:3000:16
|
||||||
|
|
||||||
|
6E4E8EB4:Info:Pac-Man:INTV:1983
|
||||||
|
6E4E8EB4:ROM:5000:3000:16
|
||||||
|
|
||||||
|
169E3584:Info:PBA Bowling:Mattel:1980
|
||||||
|
169E3584:ROM:5000:1000:16
|
||||||
|
|
||||||
|
FF87FAEC:Info:PGA Golf:Mattel:1979
|
||||||
|
FF87FAEC:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D7C5849C:Info:Pinball:Mattel:1981
|
||||||
|
D7C5849C:ROM:5000:2000:16
|
||||||
|
D7C5849C:ROM:D000:1000:16
|
||||||
|
|
||||||
|
9C75EFCC:Info:Pitfall!:Activision:1982
|
||||||
|
9C75EFCC:ROM:5000:1000:16
|
||||||
|
|
||||||
|
BB939881:Info:Pole Position:INTV:1986
|
||||||
|
BB939881:ROM:5000:2000:16
|
||||||
|
BB939881:ROM:9000:2000:16
|
||||||
|
|
||||||
|
A982E8D5:Info:Pong:Unknown:1999
|
||||||
|
A982E8D5:ROM:5000:0800:16
|
||||||
|
|
||||||
|
C51464E0:Info:Popeye:Parker Bros:1983
|
||||||
|
C51464E0:ROM:5000:2000:16
|
||||||
|
|
||||||
|
D8C9856A:Info:Q-bert:Parker Bros:1983
|
||||||
|
D8C9856A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C7BB1B0E:Info:Reversi:Mattel:1984
|
||||||
|
C7BB1B0E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
8910C37A:Info:River Raid:Activision:1982-83
|
||||||
|
8910C37A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
95466AD3:Info:River Raid V1 (Prototype):Activision:1982-83
|
||||||
|
95466AD3:ROM:5000:2000:16
|
||||||
|
|
||||||
|
1682D0B4:Info:Robot Rubble V1 (Prototype) (Overdump):Activision:1983
|
||||||
|
1682D0B4:ROM:5000:2000:16
|
||||||
|
|
||||||
|
7473916D:Info:Robot Rubble V1 (Prototype):Activision:1983
|
||||||
|
7473916D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A5E28783:Info:Robot Rubble V2 (Prototype):Activision:1983
|
||||||
|
A5E28783:ROM:5000:2000:16
|
||||||
|
|
||||||
|
243B0812:Info:Robot Rubble V3 (Prototype):Activision:1983
|
||||||
|
243B0812:ROM:5000:2000:16
|
||||||
|
|
||||||
|
DCF4B15D:Info:Royal Dealer:Mattel:1981
|
||||||
|
DCF4B15D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
47AA7977:Info:Safecracker:Imagic:1983
|
||||||
|
47AA7977:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6E0882E7:Info:SameGame and Robots:IntelligentVision:2005
|
||||||
|
6E0882E7:ROM:5000:2000:16
|
||||||
|
6E0882E7:ROM:D000:1000:16
|
||||||
|
6E0882E7:ROM:F000:1000:16
|
||||||
|
|
||||||
|
12BA58D1:Info:SameGame and Robots (Original):Michael J Hayes:2004
|
||||||
|
12BA58D1:ROM:5000:2000:16
|
||||||
|
12BA58D1:ROM:D000:1000:16
|
||||||
|
12BA58D1:ROM:F000:1000:16
|
||||||
|
|
||||||
|
E221808C:Info:Santa's Helper:Mattel:1983
|
||||||
|
E221808C:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E9E3F60D:Info:Scooby Doo's Maze Chase:Mattel/Hanna-Barbera:1983
|
||||||
|
E9E3F60D:ROM:5000:2000:16
|
||||||
|
E9E3F60D:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
99AE29A9:Info:Sea Battle:Mattel:1980
|
||||||
|
99AE29A9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E0F0D3DA:Info:Sewer Sam:Interphase:1983
|
||||||
|
E0F0D3DA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
A610406E:Info:Shape Escape:John Doherty:2005
|
||||||
|
A610406E:ROM:5000:2000:16
|
||||||
|
|
||||||
|
2A4C761D:Info:Shark! Shark!:Mattel:1982
|
||||||
|
2A4C761D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
FF7CB79E:Info:Sharp Shot:Mattel:1982
|
||||||
|
FF7CB79E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
800B572F:Info:Slam Dunk Super Pro Basketball:INTV:1987
|
||||||
|
800B572F:ROM:5000:2000:16
|
||||||
|
800B572F:ROM:9000:2000:16
|
||||||
|
|
||||||
|
BA68FF28:Info:Slap Shot Super Pro Hockey:INTV:1987
|
||||||
|
BA68FF28:ROM:5000:2000:16
|
||||||
|
|
||||||
|
8F959A6E:Info:Snafu:Mattel:1981
|
||||||
|
8F959A6E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
72C2A343:Info:Song Player - Back in the USSR (GPL):Joseph Zbiciak:1999
|
||||||
|
72C2A343:ROM:5000:2000:16
|
||||||
|
72C2A343:ROM:9000:1241:16
|
||||||
|
|
||||||
|
5E3130E1:Info:Song Player - Copacabana (GPL):Joseph Zbiciak:1999
|
||||||
|
5E3130E1:ROM:5000:2000:16
|
||||||
|
5E3130E1:ROM:9000:088F:16
|
||||||
|
5E3130E1:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
C91B1D79:Info:Song Player - Creep (GPL):Joseph Zbiciak:1999
|
||||||
|
C91B1D79:ROM:5000:1081:16
|
||||||
|
C91B1D79:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
82D2E346:Info:Song Player - Nut March (GPL):Joseph Zbiciak:1999
|
||||||
|
82D2E346:ROM:5000:1B12:16
|
||||||
|
82D2E346:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
FCF06A8B:Info:Song Player - Nut Reed (GPL):Joseph Zbiciak:1999
|
||||||
|
FCF06A8B:ROM:5000:145E:16
|
||||||
|
FCF06A8B:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
5914220A:Info:Song Player - Nut Trep (GPL):Joseph Zbiciak:1999
|
||||||
|
5914220A:ROM:5000:0DC8:16
|
||||||
|
5914220A:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
71F5BE4E:Info:Song Player - Nut Waltz (GPL):Joseph Zbiciak:1999
|
||||||
|
71F5BE4E:ROM:5000:2000:16
|
||||||
|
71F5BE4E:ROM:9000:157C:16
|
||||||
|
71F5BE4E:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
437C0E2D:Info:Song Player - Secret Agent Man (GPL):Joseph Zbiciak:1999
|
||||||
|
437C0E2D:ROM:5000:2000:16
|
||||||
|
437C0E2D:ROM:9000:15A4:16
|
||||||
|
437C0E2D:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
DA5D77EA:Info:Song Player - Take on Me 3 (GPL):Joseph Zbiciak:1999
|
||||||
|
DA5D77EA:ROM:5000:12FD:16
|
||||||
|
DA5D77EA:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
10D721CA:Info:Song Player - Take on Me 6 (GPL):Joseph Zbiciak:1999
|
||||||
|
10D721CA:ROM:5000:1500:16
|
||||||
|
10D721CA:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
CC6F4F90:Info:Song Player - Too Sexy (GPL):Joseph Zbiciak:1999
|
||||||
|
CC6F4F90:ROM:5000:1AA7:16
|
||||||
|
CC6F4F90:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
E8B8EBA5:Info:Space Armada:Mattel:1981
|
||||||
|
E8B8EBA5:ROM:5000:1000:16
|
||||||
|
|
||||||
|
F95504E0:Info:Space Battle:Mattel:1979
|
||||||
|
F95504E0:ROM:5000:1000:16
|
||||||
|
|
||||||
|
F8EF3E5A:Info:Space Cadet:Mattel:1982
|
||||||
|
F8EF3E5A:ROM:5000:2000:16
|
||||||
|
|
||||||
|
39D3B895:Info:Space Hawk:Mattel:1981
|
||||||
|
39D3B895:ROM:5000:1000:16
|
||||||
|
|
||||||
|
E98B9163:Info:Space Shuttle:Mattel:1983
|
||||||
|
E98B9163:ROM:5000:2000:16
|
||||||
|
E98B9163:ROM:D000:3000:16
|
||||||
|
E98B9163:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
3784DC52:Info:Space Spartans:Mattel:1981
|
||||||
|
3784DC52:ROM:5000:2000:16
|
||||||
|
3784DC52:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
A95021FC:Info:Spiker! Super Pro Volleyball:INTV:1988
|
||||||
|
A95021FC:ROM:5000:2000:16
|
||||||
|
A95021FC:ROM:9000:2000:16
|
||||||
|
|
||||||
|
B745C1CA:Info:Stadium Mud Buggies:INTV:1988
|
||||||
|
B745C1CA:ROM:5000:2000:16
|
||||||
|
B745C1CA:ROM:9000:2000:16
|
||||||
|
|
||||||
|
2DEACD15:Info:Stampede:Activision:1982
|
||||||
|
2DEACD15:ROM:5000:1000:16
|
||||||
|
|
||||||
|
72E11FCA:Info:Star Strike:Mattel:1981
|
||||||
|
72E11FCA:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D5B0135A:Info:Star Wars - The Empire Strikes Back:Parker Bros:1983
|
||||||
|
D5B0135A:ROM:5000:1000:16
|
||||||
|
|
||||||
|
A03EDF73:Info:Stack Em:Arnauld Chevallier:2004
|
||||||
|
A03EDF73:ROM:4800:2000:16
|
||||||
|
|
||||||
|
66D396C0:Info:Stonix:Arnauld Chevallier:2004
|
||||||
|
66D396C0:ROM:5000:2000:16
|
||||||
|
66D396C0:ROM:D000:1000:16
|
||||||
|
66D396C0:ROM:F000:1000:16
|
||||||
|
|
||||||
|
B119027D:Info:Stonix Beta 1.2:Arnauld Chevallier:2003
|
||||||
|
B119027D:ROM:5000:2000:16
|
||||||
|
|
||||||
|
4830F720:Info:Street:Mattel:1981
|
||||||
|
4830F720:ROM:5000:1000:16
|
||||||
|
|
||||||
|
3D9949EA:Info:Sub Hunt:Mattel:1981
|
||||||
|
3D9949EA:ROM:5000:2000:16
|
||||||
|
|
||||||
|
8F7D3069:Info:Super Cobra:Konami:1983
|
||||||
|
8F7D3069:ROM:5000:2000:16
|
||||||
|
|
||||||
|
BAB638F2:Info:Super Masters!:Mattel:1982
|
||||||
|
BAB638F2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
16BFB8EB:Info:Super Pro Decathlon:INTV:1978
|
||||||
|
16BFB8EB:ROM:5000:2000:16
|
||||||
|
16BFB8EB:ROM:9000:2000:16
|
||||||
|
|
||||||
|
32076E9D:Info:Super Pro Football:INTV:1986
|
||||||
|
32076E9D:ROM:5000:2000:16
|
||||||
|
32076E9D:ROM:9000:2000:16
|
||||||
|
|
||||||
|
51B82EB7:Info:Super Soccer:Mattel:1983
|
||||||
|
51B82EB7:ROM:5000:2000:16
|
||||||
|
51B82EB7:ROM:D000:1000:16
|
||||||
|
51B82EB7:ROM:F000:1000:16
|
||||||
|
|
||||||
|
15E88FCE:Info:Swords and Serpents:Imagic:1982
|
||||||
|
15E88FCE:ROM:5000:2000:16
|
||||||
|
|
||||||
|
1F584A69:Info:Takeover:Mattel:1982
|
||||||
|
1F584A69:ROM:5000:1000:16
|
||||||
|
|
||||||
|
03E9E62E:Info:Tennis:Mattel:1980
|
||||||
|
03E9E62E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
D43FD410:Info:Tetris (GPL):Joseph Zbiciak:2000
|
||||||
|
D43FD410:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F3DF94E0:Info:Thin Ice:Mattel:1983
|
||||||
|
F3DF94E0:ROM:5000:2000:16
|
||||||
|
F3DF94E0:ROM:D000:1000:16
|
||||||
|
F3DF94E0:ROM:F000:1000:16
|
||||||
|
|
||||||
|
D6495910:Info:Thin Ice (Prototype):Mattel:1983
|
||||||
|
D6495910:ROM:5000:2000:16
|
||||||
|
|
||||||
|
C1F1CA74:Info:Thunder Castle:Mattel:1982
|
||||||
|
C1F1CA74:ROM:5000:2000:16
|
||||||
|
C1F1CA74:ROM:D000:1000:16
|
||||||
|
C1F1CA74:ROM:F000:1000:16
|
||||||
|
|
||||||
|
D1D352A0:Info:Tower of Doom:Mattel:1986
|
||||||
|
D1D352A0:ROM:5000:2000:16
|
||||||
|
D1D352A0:ROM:9000:2000:16
|
||||||
|
D1D352A0:ROM:D000:1000:16
|
||||||
|
D1D352A0:ROM:F000:1000:16
|
||||||
|
|
||||||
|
1AC989E2:Info:Triple Action:Mattel:1981
|
||||||
|
1AC989E2:ROM:5000:1000:16
|
||||||
|
|
||||||
|
095638C0:Info:Triple Challenge:INTV:1986
|
||||||
|
095638C0:ROM:5000:2000:16
|
||||||
|
095638C0:ROM:9000:2000:16
|
||||||
|
095638C0:ROM:C000:0800:16
|
||||||
|
095638C0:ROM:D000:1000:16
|
||||||
|
|
||||||
|
7A558CF5:Info:Tron Maze-A-Tron:Mattel:1981
|
||||||
|
7A558CF5:ROM:5000:2000:16
|
||||||
|
|
||||||
|
CA447BBD:Info:Tron Deadly Discs:Mattel:1981
|
||||||
|
CA447BBD:ROM:5000:1000:16
|
||||||
|
|
||||||
|
07FB9435:Info:Tron Solar Sailer:Mattel:1982
|
||||||
|
07FB9435:ROM:5000:2000:16
|
||||||
|
07FB9435:ROM:D000:1000:16
|
||||||
|
07FB9435:Peripheral:Intellivoice:Optional
|
||||||
|
|
||||||
|
6F23A741:Info:Tropical Trouble:Imagic:1982
|
||||||
|
6F23A741:ROM:5000:2000:16
|
||||||
|
|
||||||
|
734F3260:Info:Truckin':Imagic:1983
|
||||||
|
734F3260:ROM:5000:2000:16
|
||||||
|
|
||||||
|
275F3512:Info:Turbo:Coleco:1983
|
||||||
|
275F3512:ROM:5000:2000:16
|
||||||
|
|
||||||
|
6FA698B3:Info:Tutankham:Parker Bros:1983
|
||||||
|
6FA698B3:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F093E801:Info:U.S. Ski Team Skiing:Mattel:1980
|
||||||
|
F093E801:ROM:5000:1000:16
|
||||||
|
|
||||||
|
752FD927:Info:USCF Chess:Mattel:1981
|
||||||
|
752FD927:ROM:5000:2000:16
|
||||||
|
752FD927:RAM:D000:400:8
|
||||||
|
|
||||||
|
F9E0789E:Info:Utopia:Mattel:1981
|
||||||
|
F9E0789E:ROM:5000:1000:16
|
||||||
|
|
||||||
|
A4A20354:Info:Vectron:Mattel:1982
|
||||||
|
A4A20354:ROM:5000:2000:16
|
||||||
|
A4A20354:ROM:D000:1000:16
|
||||||
|
|
||||||
|
6EFA67B2:Info:Venture:Coleco:1982
|
||||||
|
6EFA67B2:ROM:5000:2000:16
|
||||||
|
|
||||||
|
F1ED7D27:Info:White Water!:Imagic:1983
|
||||||
|
F1ED7D27:ROM:5000:2000:16
|
||||||
|
|
||||||
|
15D9D27A:Info:World Cup Football:Nice Ideas:1985
|
||||||
|
15D9D27A:ROM:5000:2000:16
|
||||||
|
15D9D27A:ROM:D000:1000:16
|
||||||
|
15D9D27A:ROM:F000:1000:16
|
||||||
|
|
||||||
|
C2063C08:Info:World Series Major League Baseball:Mattel:1983
|
||||||
|
C2063C08:ROM:5000:2000:16
|
||||||
|
C2063C08:ROM:D000:1000:16
|
||||||
|
C2063C08:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
|
||||||
|
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
|
||||||
|
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0001
|
||||||
|
C2063C08:Peripheral:Intellivoice:Optional
|
||||||
|
C2063C08:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
A12C27E1:Info:World Series Major League Baseball (Bad Dump):Mattel:1983
|
||||||
|
A12C27E1:ROM:5000:2000:16
|
||||||
|
A12C27E1:ROM:D000:1000:16
|
||||||
|
A12C27E1:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
|
||||||
|
A12C27E1:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
|
||||||
|
A12C27E1:Peripheral:Intellivoice:Optional
|
||||||
|
A12C27E1:Peripheral:ECS:Required
|
||||||
|
|
||||||
|
24B667B9:Info:Worm Whomper:Activision:1983
|
||||||
|
24B667B9:ROM:5000:1000:16
|
||||||
|
|
||||||
|
15C65DC5:Info:Zaxxon:Coleco:1982
|
||||||
|
15C65DC5:ROM:5000:2000:16
|
||||||
|
|
||||||
|
D89AEC27:Info:Zombie Marbles:John Doherty:2004
|
||||||
|
D89AEC27:ROM:5000:2000:16
|
Loading…
Reference in New Issue
Block a user