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