diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..62ae9b4 --- /dev/null +++ b/Makefile @@ -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=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 diff --git a/arm7/Makefile b/arm7/Makefile new file mode 100644 index 0000000..3a120ed --- /dev/null +++ b/arm7/Makefile @@ -0,0 +1,127 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=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 +#--------------------------------------------------------------------------------------- diff --git a/arm7/source/emusoundfifo.c b/arm7/source/emusoundfifo.c new file mode 100644 index 0000000..0bf7780 --- /dev/null +++ b/arm7/source/emusoundfifo.c @@ -0,0 +1,83 @@ +#include +#include +#include + +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); +} diff --git a/arm7/source/main.c b/arm7/source/main.c new file mode 100644 index 0000000..032133f --- /dev/null +++ b/arm7/source/main.c @@ -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 +#include +#include + +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; +} diff --git a/arm9/Makefile b/arm9/Makefile new file mode 100644 index 0000000..6f64548 --- /dev/null +++ b/arm9/Makefile @@ -0,0 +1,141 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=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 +#--------------------------------------------------------------------------------------- diff --git a/arm9/data/clickNoQuit.wav b/arm9/data/clickNoQuit.wav new file mode 100644 index 0000000..16a9253 Binary files /dev/null and b/arm9/data/clickNoQuit.wav differ diff --git a/arm9/data/clickQuit.wav b/arm9/data/clickQuit.wav new file mode 100644 index 0000000..1c642e1 Binary files /dev/null and b/arm9/data/clickQuit.wav differ diff --git a/arm9/data/mus_intro.wav b/arm9/data/mus_intro.wav new file mode 100644 index 0000000..99e77ca Binary files /dev/null and b/arm9/data/mus_intro.wav differ diff --git a/arm9/ds_arm9_hi.mem b/arm9/ds_arm9_hi.mem new file mode 100644 index 0000000..f4522da --- /dev/null +++ b/arm9/ds_arm9_hi.mem @@ -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 +} diff --git a/arm9/ds_arm9_hi.specs b/arm9/ds_arm9_hi.specs new file mode 100644 index 0000000..c5d66ea --- /dev/null +++ b/arm9/ds_arm9_hi.specs @@ -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 + diff --git a/arm9/gfx/bgBottom.png b/arm9/gfx/bgBottom.png new file mode 100644 index 0000000..c2dca19 Binary files /dev/null and b/arm9/gfx/bgBottom.png differ diff --git a/arm9/gfx/bgFileSel.png b/arm9/gfx/bgFileSel.png new file mode 100644 index 0000000..489e12b Binary files /dev/null and b/arm9/gfx/bgFileSel.png differ diff --git a/arm9/gfx/bgInstructions.png b/arm9/gfx/bgInstructions.png new file mode 100644 index 0000000..43b9116 Binary files /dev/null and b/arm9/gfx/bgInstructions.png differ diff --git a/arm9/gfx/bgOptions.png b/arm9/gfx/bgOptions.png new file mode 100644 index 0000000..132093a Binary files /dev/null and b/arm9/gfx/bgOptions.png differ diff --git a/arm9/gfx/bgTop.png b/arm9/gfx/bgTop.png new file mode 100644 index 0000000..4311920 Binary files /dev/null and b/arm9/gfx/bgTop.png differ diff --git a/arm9/source/ds_tools.cpp b/arm9/source/ds_tools.cpp new file mode 100644 index 0000000..71ed89b --- /dev/null +++ b/arm9/source/ds_tools.cpp @@ -0,0 +1,1090 @@ +// ===================================================================================================== +// NINTELLIVISION (c) 2021 by wavemotion-dave +// ===================================================================================================== +#include +#include + +#include + +#include +#include +#include + +#include "ds_tools.h" +#include "bgBottom.h" +#include "bgTop.h" +#include "bgFileSel.h" +#include "bgOptions.h" + +#include "clickNoQuit_wav.h" +#include "clickQuit_wav.h" + +#include "Emulator.h" +#include "InputProducerManager.h" +#include "Rip.h" + +typedef enum _RunState +{ + Stopped, + Paused, + Running, + Quit +} RunState; + +static short key_A_map = 12; +static short key_B_map = 12; +static short key_X_map = 13; +static short key_Y_map = 14; +static short key_L_map = 0; +static short key_R_map = 1; + +#define WAITVBL swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); + +int bg0, bg0b, bg1b; +bool bFirstGameLoaded = false; + +ITCM_CODE void dsPrintValue(int x, int y, unsigned int isSelect, char *pchStr) +{ + u16 *pusEcran,*pusMap; + u16 usCharac; + char *pTrTxt=pchStr; + char ch; + + pusEcran=(u16*) (bgGetMapPtr(bg1b))+x+(y<<5); + pusMap=(u16*) (bgGetMapPtr(bg0b)+(2*isSelect+24)*32); + + while((*pTrTxt)!='\0' ) + { + ch = *pTrTxt; + if (ch >= 'a' && ch <= 'z') ch -= 32; // Faster than strcpy/strtoupper + usCharac=0x0000; + if ((ch) == '|') + usCharac=*(pusMap); + else if (((ch)<' ') || ((ch)>'_')) + usCharac=*(pusMap); + else if((ch)<'@') + usCharac=*(pusMap+(ch)-' '); + else + usCharac=*(pusMap+32+(ch)-'@'); + *pusEcran++=usCharac; + pTrTxt++; + } +} + +class AudioMixerDS : public AudioMixer +{ +public: + AudioMixerDS(UINT16* buffer); + void resetProcessor(); + void flushAudio(); + void init(UINT32 sampleRate); + void release(); + + UINT16* outputBuffer; + UINT32 outputBufferSize; + UINT32 outputBufferWritePosition; +}; + +AudioMixerDS::AudioMixerDS(UINT16* buffer) + : outputBuffer(NULL), + outputBufferSize(0), + outputBufferWritePosition(0) +{ + this->outputBuffer = buffer; + this->outputBufferWritePosition = 0; + this->outputBufferSize = 2048; +} + +void AudioMixerDS::resetProcessor() +{ + if (outputBuffer) + { + outputBufferWritePosition = 0; + } + + // clears the emulator side of the audio mixer + AudioMixer::resetProcessor(); +} + + +void AudioMixerDS::init(UINT32 sampleRate) +{ + release(); + + outputBufferWritePosition = 0; + + AudioMixer::init(sampleRate); +} + +void AudioMixerDS::release() +{ + AudioMixer::release(); +} + +void AudioMixerDS::flushAudio() +{ + if (sampleCount < this->sampleSize) { + return; + } + + // Write to DS ARM7 audio buffer? + memcpy(outputBuffer, this->sampleBuffer, this->sampleBufferSize); + + // clear the sample count + AudioMixer::flushAudio(); +} + + + +class VideoBusDS : public VideoBus +{ +public: + VideoBusDS(); + void init(UINT32 width, UINT32 height); + void release(); + void render(); +}; + +VideoBusDS::VideoBusDS() { } + +void VideoBusDS::init(UINT32 width, UINT32 height) +{ + release(); + + // initialize the pixelBuffer + VideoBus::init(width, height); +} + +void VideoBusDS::release() +{ + VideoBus::release(); +} + +int debug1, debug2; +static int frames=0; +ITCM_CODE void VideoBusDS::render() +{ + frames++; + VideoBus::render(); + + if (frames & 1) return; + UINT32 *ds_video=(UINT32*)0x06000000; + UINT32 *source_video = (UINT32*)pixelBuffer; + + for (int j=0; j<192; j++) + { + memcpy(ds_video, source_video, 160); + ds_video += 64; + source_video += 40; + } +} + +RunState runState; +Emulator *currentEmu; +Rip *currentRip; +VideoBus *videoBus; +AudioMixer *audioMixer; + + +BOOL LoadCart(const CHAR* filename) +{ + if (strlen(filename) < 5) + return FALSE; + + //convert .bin and .rom to .rip, since our emulation only knows how to run .rip + const CHAR* extStart = filename + strlen(filename) - 4; + if (strcmpi(extStart, ".int") == 0 || strcmpi(extStart, ".bin") == 0) + { + //load the bin file as a Rip + CHAR* cfgFilename = (CHAR*)"knowncarts.cfg"; + currentRip = Rip::LoadBin(filename, cfgFilename); + if (currentRip == NULL) + { + return FALSE; + } + + CHAR fileSubname[MAX_PATH]; + strcpy(fileSubname, filename); + strcat(fileSubname, ".rip"); + } + else + { + //load the designated Rip + currentRip = Rip::LoadRip(filename); + if (currentRip == NULL) + { + return FALSE; + } + } + + dsShowScreenEmu(); + bFirstGameLoaded = TRUE; + + return TRUE; +} + +BOOL LoadPeripheralRoms(Peripheral* peripheral) +{ + UINT16 count = peripheral->GetROMCount(); + for (UINT16 i = 0; i < count; i++) { + ROM* r = peripheral->GetROM(i); + if (r->isLoaded()) + continue; + + //TODO: get filenames from config file + //TODO: handle file loading errors + CHAR nextFile[MAX_PATH]; + strcpy(nextFile, "."); + strcat(nextFile, "/"); + strcat(nextFile, r->getDefaultFileName()); + if (!r->load(nextFile, r->getDefaultFileOffset())) + { + return FALSE; + } + } + + return TRUE; +} + + +BOOL InitializeEmulator(void) +{ + //release the current emulator + //ReleaseEmulator(); + + //find the currentEmulator required to run this RIP + currentEmu = Emulator::GetEmulatorByID(currentRip->GetTargetSystemID()); + if (currentEmu == NULL) + { + return FALSE; + } + + //load the BIOS files required for this currentEmulator + if (!LoadPeripheralRoms(currentEmu)) + return FALSE; + + //load peripheral roms + INT32 count = currentEmu->GetPeripheralCount(); + for (INT32 i = 0; i < count; i++) { + Peripheral* p = currentEmu->GetPeripheral(i); + PeripheralCompatibility usage = currentRip->GetPeripheralUsage(p->GetShortName()); + if (usage == PERIPH_INCOMPATIBLE || usage == PERIPH_COMPATIBLE) { + currentEmu->UsePeripheral(i, FALSE); + continue; + } + + BOOL loaded = LoadPeripheralRoms(p); + if (loaded) { + //peripheral loaded, might as well use it. + currentEmu->UsePeripheral(i, TRUE); + } + else if (usage == PERIPH_OPTIONAL) { + //didn't load, but the peripheral is optional, so just skip it + currentEmu->UsePeripheral(i, FALSE); + } + else //usage == PERIPH_REQUIRED, but it didn't load + return FALSE; + } + + //hook the audio and video up to the currentEmulator + currentEmu->InitVideo(videoBus,currentEmu->GetVideoWidth(),currentEmu->GetVideoHeight()); + currentEmu->InitAudio(audioMixer,22050); + + //put the RIP in the currentEmulator + currentEmu->SetRip(currentRip); + + //finally, run everything + currentEmu->Reset(); + + return TRUE; +} + +char newFile[256]; +void pollInputs(void) +{ + extern int ds_key_input[16]; // Set to '1' if pressed... 0 if released + extern int ds_disc_input[16]; // Set to '1' if pressed... 0 if released. + unsigned short keys_pressed = keysCurrent(); + + for (int i=0; i<15; i++) ds_key_input[i] = 0; + for (int i=0; i<16; i++) ds_disc_input[i] = 0; + + // Handle 8 directions on keypad... best we can do... + if (keys_pressed & KEY_UP) + { + if (keys_pressed & KEY_RIGHT) ds_disc_input[2] = 1; + else if (keys_pressed & KEY_LEFT) ds_disc_input[14] = 1; + else ds_disc_input[0] = 1; + } + else if (keys_pressed & KEY_DOWN) + { + if (keys_pressed & KEY_RIGHT) ds_disc_input[6] = 1; + else if (keys_pressed & KEY_LEFT) ds_disc_input[10] = 1; + else ds_disc_input[8] = 1; + } + else if (keys_pressed & KEY_RIGHT) + { + ds_disc_input[4] = 1; + } + else if (keys_pressed & KEY_LEFT) + { + ds_disc_input[12] = 1; + } + + if (keys_pressed & KEY_A) ds_key_input[key_A_map] = 1; + if (keys_pressed & KEY_B) ds_key_input[key_B_map] = 1; + if (keys_pressed & KEY_X) ds_key_input[key_X_map] = 1; + if (keys_pressed & KEY_Y) ds_key_input[key_Y_map] = 1; + if (keys_pressed & KEY_L) ds_key_input[key_L_map] = 1; + if (keys_pressed & KEY_R) ds_key_input[key_R_map] = 1; + + if (keys_pressed & KEY_START) + { + if (bFirstGameLoaded) currentEmu->Reset(); + } + if (keys_pressed & KEY_SELECT) + { + fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME); + if (dsWaitForRom(newFile)) + { + LoadCart(newFile); + InitializeEmulator(); + } + fifoSendValue32(FIFO_USER_01,(1<<16) | (127) | SOUND_SET_VOLUME); + } + + // Now handle the on-screen Intellivision keypad... + if (keys_pressed & KEY_TOUCH) + { + //char tmp[12]; + touchPosition touch; + touchRead(&touch); + //sprintf(tmp, "%3d %3d", touch.px, touch.py); + //dsPrintValue(0,1,0,tmp); + + if (touch.px > 120 && touch.px < 155 && touch.py > 30 && touch.py < 60) ds_key_input[0] = 1; + if (touch.px > 158 && touch.px < 192 && touch.py > 30 && touch.py < 60) ds_key_input[1] = 1; + if (touch.px > 195 && touch.px < 230 && touch.py > 30 && touch.py < 60) ds_key_input[2] = 1; + + if (touch.px > 120 && touch.px < 155 && touch.py > 65 && touch.py < 95) ds_key_input[3] = 1; + if (touch.px > 158 && touch.px < 192 && touch.py > 65 && touch.py < 95) ds_key_input[4] = 1; + if (touch.px > 195 && touch.px < 230 && touch.py > 65 && touch.py < 95) ds_key_input[5] = 1; + + if (touch.px > 120 && touch.px < 155 && touch.py > 101 && touch.py < 135) ds_key_input[6] = 1; + if (touch.px > 158 && touch.px < 192 && touch.py > 101 && touch.py < 135) ds_key_input[7] = 1; + if (touch.px > 195 && touch.px < 230 && touch.py > 101 && touch.py < 135) ds_key_input[8] = 1; + + if (touch.px > 120 && touch.px < 155 && touch.py > 140 && touch.py < 175) ds_key_input[9] = 1; + if (touch.px > 158 && touch.px < 192 && touch.py > 140 && touch.py < 175) ds_key_input[10] = 1; + if (touch.px > 195 && touch.px < 230 && touch.py > 140 && touch.py < 175) ds_key_input[11] = 1; + + + // RESET + if (touch.px > 23 && touch.px < 82 && touch.py > 34 && touch.py < 53) + { + if (bFirstGameLoaded) currentEmu->Reset(); + } + + // LOAD + if (touch.px > 23 && touch.px < 82 && touch.py > 72 && touch.py < 91) + { + fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME); + if (dsWaitForRom(newFile)) + { + LoadCart(newFile); + InitializeEmulator(); + } + fifoSendValue32(FIFO_USER_01,(1<<16) | (127) | SOUND_SET_VOLUME); + } + + // CONFIG + if (touch.px > 23 && touch.px < 82 && touch.py > 111 && touch.py < 130) + { + fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME); + dsChooseOptions(); + fifoSendValue32(FIFO_USER_01,(1<<16) | (127) | SOUND_SET_VOLUME); + } + + // QUIT + if (touch.px > 23 && touch.px < 82 && touch.py > 150 && touch.py < 170) + { + fifoSendValue32(FIFO_USER_01,(1<<16) | (0) | SOUND_SET_VOLUME); + if (dsWaitOnQuit()) + { + runState = Quit; + } + fifoSendValue32(FIFO_USER_01,(1<<16) | (127) | SOUND_SET_VOLUME); + } + } + +} + +int full_speed=0; +int emu_frames=1; +void Run() +{ + TIMER1_CR = 0; + TIMER1_DATA = 0; + TIMER1_CR=TIMER_ENABLE | TIMER_DIV_1024; + + TIMER0_CR=0; + TIMER0_DATA=0; + TIMER0_CR=TIMER_ENABLE|TIMER_DIV_1024; + + runState = Running; + while(runState == Running) + { + if (!full_speed) + { + while(TIMER0_DATA < (546*emu_frames)) + ; + } + + // Have we processed 60 frames... start over... + if (++emu_frames == 60) + { + TIMER0_CR=0; + TIMER0_DATA=0; + TIMER0_CR=TIMER_ENABLE|TIMER_DIV_1024; + emu_frames=1; + } + + //poll the input + pollInputs(); + + if (bFirstGameLoaded) + { + //run the emulation + currentEmu->Run(); + + // render the output + currentEmu->Render(); + + //flush the audio + currentEmu->FlushAudio(); + } + + if (TIMER1_DATA >= 32728) // 1000MS (1 sec) + { + char tmp[15]; + TIMER1_CR = 0; + TIMER1_DATA = 0; + TIMER1_CR=TIMER_ENABLE | TIMER_DIV_1024; + if (frames > 0) + { + sprintf(tmp, "%03d", frames); + dsPrintValue(0,0,0,tmp); + } + //sprintf(tmp, "%4d %4d", debug1, debug2); + //dsPrintValue(0,1,0,tmp); + frames=0; + } + } +} +void dsShowScreenMain(bool bFull) +{ + // Init BG mode for 16 bits colors + if (bFull) + { + videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE ); + videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE | DISPLAY_BG1_ACTIVE); + vramSetBankA(VRAM_A_MAIN_BG); vramSetBankC(VRAM_C_SUB_BG); + bg0 = bgInit(0, BgType_Text8bpp, BgSize_T_256x256, 31,0); + bg0b = bgInitSub(0, BgType_Text8bpp, BgSize_T_256x256, 31,0); + bg1b = bgInitSub(1, BgType_Text8bpp, BgSize_T_256x256, 30,0); + bgSetPriority(bg0b,1);bgSetPriority(bg1b,0); + + decompress(bgTopTiles, bgGetGfxPtr(bg0), LZ77Vram); + decompress(bgTopMap, (void*) bgGetMapPtr(bg0), LZ77Vram); + dmaCopy((void *) bgTopPal,(u16*) BG_PALETTE,256*2); + } + + decompress(bgBottomTiles, bgGetGfxPtr(bg0b), LZ77Vram); + decompress(bgBottomMap, (void*) bgGetMapPtr(bg0b), LZ77Vram); + dmaCopy((void *) bgBottomPal,(u16*) BG_PALETTE_SUB,256*2); + unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32); + dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2); + + REG_BLDCNT=0; REG_BLDCNT_SUB=0; REG_BLDY=0; REG_BLDY_SUB=0; + + // ShowStatusLine(); + + swiWaitForVBlank(); +} + +#define SOUND_SIZE 734 +UINT16 soundBuf[SOUND_SIZE+8] = {0}; +void dsMainLoop(void) +{ + // ----------------------------------------------------------------------------------------- + // Eventually these will be used to write to the DS screen and produce DS audio output... + // ----------------------------------------------------------------------------------------- + videoBus = new VideoBusDS(); + audioMixer = new AudioMixerDS(soundBuf); + + dsShowScreenMain(true); + InitializeEmulator(); + + Run(); +} + +//--------------------------------------------------------------------------------- +void dsInstallSoundEmuFIFO(void) +{ + FifoMessage msg; + msg.SoundPlay.data = &soundBuf; + msg.SoundPlay.freq = 22050; + msg.SoundPlay.volume = 127; + msg.SoundPlay.pan = 64; + msg.SoundPlay.loop = 1; + msg.SoundPlay.format = ((1)<<4) | SoundFormat_16Bit; + msg.SoundPlay.loopPoint = 0; + msg.SoundPlay.dataSize = SOUND_SIZE >> 2; + msg.type = EMUARM7_PLAY_SND; + fifoSendDatamsg(FIFO_USER_01, sizeof(msg), (u8*)&msg); +} + + +void vblankIntr() +{ +} + +UINT32 gamePalette[32] = +{ + 0x000000, 0x002DFF, 0xFF3D10, 0xC9CFAB, + 0x386B3F, 0x00A756, 0xFAEA50, 0xFFFCFF, + 0xBDACC8, 0x24B8FF, 0xFFB41F, 0x546E00, + 0xFF4E57, 0xA496FF, 0x75CC80, 0xB51A58, + 0x000000, 0x002DFF, 0xFF3D10, 0xC9CFAB, + 0x386B3F, 0x00A756, 0xFAEA50, 0xFFFCFF, + 0xBDACC8, 0x24B8FF, 0xFFB41F, 0x546E00, + 0xFF4E57, 0xA496FF, 0x75CC80, 0xB51A58, +}; + + +void dsInitPalette(void) +{ + // Init DS Specific palette + for(int i = 0; i < 256; i++) + { + unsigned char r, g, b; + + r = (unsigned char) ((gamePalette[i%32] & 0x00ff0000) >> 19); + g = (unsigned char) ((gamePalette[i%32] & 0x0000ff00) >> 11); + b = (unsigned char) ((gamePalette[i%32] & 0x000000ff) >> 3); + + BG_PALETTE[i]=RGB15(r,g,b); + } +} + +void dsInitScreenMain(void) +{ + // Init vbl and hbl func + SetYtrigger(190); //trigger 2 lines before vsync + irqSet(IRQ_VBLANK, vblankIntr); + irqEnable(IRQ_VBLANK); + vramSetBankD(VRAM_D_LCD ); // Not using this for video but 128K of faster RAM always useful! Mapped at 0x06860000 - + vramSetBankE(VRAM_E_LCD ); // Not using this for video but 64K of faster RAM always useful! Mapped at 0x06880000 - + vramSetBankF(VRAM_F_LCD ); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x06890000 - + vramSetBankG(VRAM_G_LCD ); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x06894000 - + vramSetBankH(VRAM_H_LCD ); // Not using this for video but 32K of faster RAM always useful! Mapped at 0x06898000 - + vramSetBankI(VRAM_I_LCD ); // Not using this for video but 16K of faster RAM always useful! Mapped at 0x068A0000 - + + WAITVBL; +} + +void dsShowScreenEmu(void) +{ + videoSetMode(MODE_5_2D); + vramSetBankA(VRAM_A_MAIN_BG_0x06000000); // The main emulated (top screen) display. + vramSetBankB(VRAM_B_MAIN_BG_0x06060000); // This is where we will put our frame buffers to aid DMA Copy routines... + + bg0 = bgInit(3, BgType_Bmp8, BgSize_B8_256x256, 0,0); + memset((void*)0x06000000, 0x00, 128*1024); + + int stretch_x = ((160 / 256) << 8) | (160 % 256); + REG_BG3PA = stretch_x; + REG_BG3PB = 0; REG_BG3PC = 0; + REG_BG3PD = ((100 / 100) << 8) | (100 % 100) ; + REG_BG3X = 0; + REG_BG3Y = 0; + + dsInitPalette(); + swiWaitForVBlank(); +} + +ITCM_CODE void dsInitTimer(void) +{ + TIMER0_DATA=0; + TIMER0_CR=TIMER_ENABLE|TIMER_DIV_1024; +} + +void dsFreeEmu(void) +{ + // Stop timer of sound + TIMER2_CR=0; irqDisable(IRQ_TIMER2); +} + +//---------------------------------------------------------------------------------- +// Load Rom +//---------------------------------------------------------------------------------- +FICA2600 vcsromlist[512]; +unsigned short int countvcs=0, ucFicAct=0; +char szName[256]; +char szName2[256]; + + +// Find files (.int) available +int a26Filescmp (const void *c1, const void *c2) +{ + FICA2600 *p1 = (FICA2600 *) c1; + FICA2600 *p2 = (FICA2600 *) c2; + + if (p1->filename[0] == '.' && p2->filename[0] != '.') + return -1; + if (p2->filename[0] == '.' && p1->filename[0] != '.') + return 1; + if (p1->directory && !(p2->directory)) + return -1; + if (p2->directory && !(p1->directory)) + return 1; + return strcasecmp (p1->filename, p2->filename); +} + +static char filenametmp[255]; +void vcsFindFiles(void) +{ + DIR *pdir; + struct dirent *pent; + + countvcs = 0; + + pdir = opendir("."); + + if (pdir) { + + while (((pent=readdir(pdir))!=NULL)) + { + strcpy(filenametmp,pent->d_name); + if (pent->d_type == DT_DIR) + { + if (!( (filenametmp[0] == '.') && (strlen(filenametmp) == 1))) { + vcsromlist[countvcs].directory = true; + strcpy(vcsromlist[countvcs].filename,filenametmp); + countvcs++; + } + } + else { + if (strlen(filenametmp)>4) { + if ( (strcasecmp(strrchr(filenametmp, '.'), ".int") == 0) ) { + vcsromlist[countvcs].directory = false; + strcpy(vcsromlist[countvcs].filename,filenametmp); + countvcs++; + } + } + } + } + closedir(pdir); + } + if (countvcs) + qsort (vcsromlist, countvcs, sizeof (FICA2600), a26Filescmp); +} + +void dsDisplayFiles(unsigned int NoDebGame,u32 ucSel) +{ + unsigned int ucBcl,ucGame; + + // Display all games if possible + unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32); + dmaFillWords(dmaVal | (dmaVal<<16),(void*) (bgGetMapPtr(bg1b)),32*24*2); + sprintf(szName,"%04d/%04d GAMES",(int)(1+ucSel+NoDebGame),countvcs); + dsPrintValue(16-strlen(szName)/2,2,0,szName); + dsPrintValue(31,5,0,(char *) (NoDebGame>0 ? "<" : " ")); + dsPrintValue(31,22,0,(char *) (NoDebGame+14" : " ")); + sprintf(szName, "A=CHOOSE B=BACK "); + dsPrintValue(16-strlen(szName)/2,23,0,szName); + for (ucBcl=0;ucBcl<17; ucBcl++) { + ucGame= ucBcl+NoDebGame; + if (ucGame < countvcs) + { + strcpy(szName,vcsromlist[ucGame].filename); + szName[29]='\0'; + if (vcsromlist[ucGame].directory) + { + szName[27]='\0'; + sprintf(szName2,"[%s]",szName); + dsPrintValue(0,5+ucBcl,(ucSel == ucBcl ? 1 : 0),szName2); + } + else + { + dsPrintValue(1,5+ucBcl,(ucSel == ucBcl ? 1 : 0),szName); + } + } + } +} + + + +unsigned int dsWaitForRom(char *chosen_filename) +{ + bool bDone=false, bRet=false; + u32 ucHaut=0x00, ucBas=0x00,ucSHaut=0x00, ucSBas=0x00,romSelected= 0, firstRomDisplay=0,nbRomPerPage, uNbRSPage; + u32 uLenFic=0, ucFlip=0, ucFlop=0; + + strcpy(chosen_filename, "tmpz"); + vcsFindFiles(); // Initial get of files... + + decompress(bgFileSelTiles, bgGetGfxPtr(bg0b), LZ77Vram); + decompress(bgFileSelMap, (void*) bgGetMapPtr(bg0b), LZ77Vram); + dmaCopy((void *) bgFileSelPal,(u16*) BG_PALETTE_SUB,256*2); + unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32); + dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2); + + nbRomPerPage = (countvcs>=17 ? 17 : countvcs); + uNbRSPage = (countvcs>=5 ? 5 : countvcs); + + if (ucFicAct>countvcs-nbRomPerPage) + { + firstRomDisplay=countvcs-nbRomPerPage; + romSelected=ucFicAct-countvcs+nbRomPerPage; + } + else + { + firstRomDisplay=ucFicAct; + romSelected=0; + } + dsDisplayFiles(firstRomDisplay,romSelected); + while (!bDone) + { + if (keysCurrent() & KEY_UP) + { + if (!ucHaut) + { + ucFicAct = (ucFicAct>0 ? ucFicAct-1 : countvcs-1); + if (romSelected>uNbRSPage) { romSelected -= 1; } + else { + if (firstRomDisplay>0) { firstRomDisplay -= 1; } + else { + if (romSelected>0) { romSelected -= 1; } + else { + firstRomDisplay=countvcs-nbRomPerPage; + romSelected=nbRomPerPage-1; + } + } + } + ucHaut=0x01; + dsDisplayFiles(firstRomDisplay,romSelected); + } + else { + + ucHaut++; + if (ucHaut>10) ucHaut=0; + } + uLenFic=0; ucFlip=0; ucFlop=0; + } + else + { + ucHaut = 0; + } + if (keysCurrent() & KEY_DOWN) + { + if (!ucBas) { + ucFicAct = (ucFicAct< countvcs-1 ? ucFicAct+1 : 0); + if (romSelected10) ucBas=0; + } + uLenFic=0; ucFlip=0; ucFlop=0; + } + else { + ucBas = 0; + } + if ((keysCurrent() & KEY_R) || (keysCurrent() & KEY_RIGHT)) + { + if (!ucSBas) + { + ucFicAct = (ucFicAct< countvcs-nbRomPerPage ? ucFicAct+nbRomPerPage : countvcs-nbRomPerPage); + if (firstRomDisplay10) ucSBas=0; + } + uLenFic=0; ucFlip=0; ucFlop=0; + } + else { + ucSBas = 0; + } + if ((keysCurrent() & KEY_L) || (keysCurrent() & KEY_LEFT)) + { + if (!ucSHaut) + { + ucFicAct = (ucFicAct> nbRomPerPage ? ucFicAct-nbRomPerPage : 0); + if (firstRomDisplay>nbRomPerPage) { firstRomDisplay -= nbRomPerPage; } + else { firstRomDisplay = 0; } + if (ucFicAct == 0) romSelected = 0; + if (romSelected > ucFicAct) romSelected = ucFicAct; + ucSHaut=0x01; + dsDisplayFiles(firstRomDisplay,romSelected); + } + else + { + ucSHaut++; + if (ucSHaut>10) ucSHaut=0; + } + uLenFic=0; ucFlip=0; ucFlop=0; + } + else { + ucSHaut = 0; + } + + if ( keysCurrent() & KEY_B ) + { + bDone=true; + while (keysCurrent() & KEY_B); + } + + if (keysCurrent() & KEY_A || keysCurrent() & KEY_Y) + { + if (!vcsromlist[ucFicAct].directory) + { + bRet=true; + bDone=true; + strcpy(chosen_filename, vcsromlist[ucFicAct].filename); + if (keysCurrent() & KEY_Y) full_speed=1; else full_speed=0; + } + else + { + chdir(vcsromlist[ucFicAct].filename); + vcsFindFiles(); + ucFicAct = 0; + nbRomPerPage = (countvcs>=16 ? 16 : countvcs); + uNbRSPage = (countvcs>=5 ? 5 : countvcs); + if (ucFicAct>countvcs-nbRomPerPage) { + firstRomDisplay=countvcs-nbRomPerPage; + romSelected=ucFicAct-countvcs+nbRomPerPage; + } + else { + firstRomDisplay=ucFicAct; + romSelected=0; + } + dsDisplayFiles(firstRomDisplay,romSelected); + while (keysCurrent() & KEY_A); + } + } + + // If the filename is too long... scroll it. + if (strlen(vcsromlist[ucFicAct].filename) > 29) + { + ucFlip++; + if (ucFlip >= 15) + { + ucFlip = 0; + uLenFic++; + if ((uLenFic+29)>strlen(vcsromlist[ucFicAct].filename)) + { + ucFlop++; + if (ucFlop >= 15) + { + uLenFic=0; + ucFlop = 0; + } + else + uLenFic--; + } + strncpy(szName,vcsromlist[ucFicAct].filename+uLenFic,29); + szName[29] = '\0'; + dsPrintValue(1,5+romSelected,1,szName); + } + } + + swiWaitForVBlank(); + } + + dsShowScreenMain(false); + + return bRet; +} + + +bool dsWaitOnQuit(void) +{ + bool bRet=false, bDone=false; + unsigned int keys_pressed; + unsigned int posdeb=0; + char szName[32]; + + decompress(bgFileSelTiles, bgGetGfxPtr(bg0b), LZ77Vram); + decompress(bgFileSelMap, (void*) bgGetMapPtr(bg0b), LZ77Vram); + dmaCopy((void *) bgFileSelPal,(u16*) BG_PALETTE_SUB,256*2); + unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32); + dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2); + + strcpy(szName,"Quit NINTV-DS?"); + dsPrintValue(16-strlen(szName)/2,2,0,szName); + sprintf(szName,"%s","A TO CONFIRM, B TO GO BACK"); + dsPrintValue(16-strlen(szName)/2,23,0,szName); + + while(!bDone) + { + strcpy(szName," YES "); + dsPrintValue(5,10+0,(posdeb == 0 ? 1 : 0),szName); + strcpy(szName," NO "); + dsPrintValue(5,14+1,(posdeb == 2 ? 1 : 0),szName); + swiWaitForVBlank(); + + // Check pad + keys_pressed=keysCurrent(); + if (keys_pressed & KEY_UP) { + if (posdeb) posdeb-=2; + } + if (keys_pressed & KEY_DOWN) { + if (posdeb<1) posdeb+=2; + } + if (keys_pressed & KEY_A) { + bRet = (posdeb ? false : true); + bDone = true; + } + if (keys_pressed & KEY_B) { + bDone = true; + } + } + + dsShowScreenMain(false); + + return bRet; +} + +// ----------------------------------------------------------------------------- +// Options are handled here... we have a number of things the user can tweak +// and these options are applied immediately. The user can also save off +// their option choices for the currently running game into the XEGS.DAT +// configuration database. When games are loaded back up, XEGS.DAT is read +// to see if we have a match and the user settings can be restored for the +// game. +// ----------------------------------------------------------------------------- +struct options_t +{ + const char *label; + const char *option[16]; + short *option_val; + short option_max; +}; + +const struct options_t Option_Table[] = +{ + {"A BUTTON", {"KEY-1", "KEY-2", "KEY-3", "KEY-4", "KEY-5", "KEY-6", "KEY-7", "KEY-8", "KEY-9", "KEY-CLR", "KEY-0", "KEY-ENT", "FIRE", "R-ACT", "L-ACT"}, &key_A_map, 15}, + {"B BUTTON", {"KEY-1", "KEY-2", "KEY-3", "KEY-4", "KEY-5", "KEY-6", "KEY-7", "KEY-8", "KEY-9", "KEY-CLR", "KEY-0", "KEY-ENT", "FIRE", "R-ACT", "L-ACT"}, &key_B_map, 15}, + {"X BUTTON", {"KEY-1", "KEY-2", "KEY-3", "KEY-4", "KEY-5", "KEY-6", "KEY-7", "KEY-8", "KEY-9", "KEY-CLR", "KEY-0", "KEY-ENT", "FIRE", "R-ACT", "L-ACT"}, &key_X_map, 15}, + {"Y BUTTON", {"KEY-1", "KEY-2", "KEY-3", "KEY-4", "KEY-5", "KEY-6", "KEY-7", "KEY-8", "KEY-9", "KEY-CLR", "KEY-0", "KEY-ENT", "FIRE", "R-ACT", "L-ACT"}, &key_Y_map, 15}, + {"L BUTTON", {"KEY-1", "KEY-2", "KEY-3", "KEY-4", "KEY-5", "KEY-6", "KEY-7", "KEY-8", "KEY-9", "KEY-CLR", "KEY-0", "KEY-ENT", "FIRE", "R-ACT", "L-ACT"}, &key_L_map, 15}, + {"R BUTTON", {"KEY-1", "KEY-2", "KEY-3", "KEY-4", "KEY-5", "KEY-6", "KEY-7", "KEY-8", "KEY-9", "KEY-CLR", "KEY-0", "KEY-ENT", "FIRE", "R-ACT", "L-ACT"}, &key_R_map, 15}, + {NULL, {"", ""}, NULL, 2}, +}; + +// ----------------------------------------------------------------------------- +// Allows the user to move the cursor up and down through the various table +// enties above to select options for the game they wish to play. +// ----------------------------------------------------------------------------- +void dsChooseOptions(void) +{ + int optionHighlighted; + int idx; + bool bDone=false; + int keys_pressed; + int last_keys_pressed = 999; + char strBuf[64]; + + // Show the Options background... + decompress(bgOptionsTiles, bgGetGfxPtr(bg0b), LZ77Vram); + decompress(bgOptionsMap, (void*) bgGetMapPtr(bg0b), LZ77Vram); + dmaCopy((void *) bgOptionsPal,(u16*) BG_PALETTE_SUB,256*2); + unsigned short dmaVal = *(bgGetMapPtr(bg1b) +31*32); + dmaFillWords(dmaVal | (dmaVal<<16),(void*) bgGetMapPtr(bg1b),32*24*2); + + idx=0; + while (true) + { + sprintf(strBuf, " %-12s : %-12s ", Option_Table[idx].label, Option_Table[idx].option[*(Option_Table[idx].option_val)]); + dsPrintValue(1,5+idx, (idx==0 ? 1:0), strBuf); + idx++; + if (Option_Table[idx].label == NULL) break; + } + + dsPrintValue(2,23, 0, (char *)"A=TOGGLE, B=SAVE+EXIT"); + optionHighlighted = 0; + while (!bDone) + { + keys_pressed = keysCurrent(); + if (keys_pressed != last_keys_pressed) + { + last_keys_pressed = keys_pressed; + if (keysCurrent() & KEY_UP) // Previous option + { + sprintf(strBuf, " %-12s : %-12s ", Option_Table[optionHighlighted].label, Option_Table[optionHighlighted].option[*(Option_Table[optionHighlighted].option_val)]); + dsPrintValue(1,5+optionHighlighted,0, strBuf); + if (optionHighlighted > 0) optionHighlighted--; else optionHighlighted=(idx-1); + sprintf(strBuf, " %-12s : %-12s ", Option_Table[optionHighlighted].label, Option_Table[optionHighlighted].option[*(Option_Table[optionHighlighted].option_val)]); + dsPrintValue(1,5+optionHighlighted,1, strBuf); + } + if (keysCurrent() & KEY_DOWN) // Next option + { + sprintf(strBuf, " %-12s : %-12s ", Option_Table[optionHighlighted].label, Option_Table[optionHighlighted].option[*(Option_Table[optionHighlighted].option_val)]); + dsPrintValue(1,5+optionHighlighted,0, strBuf); + if (optionHighlighted < (idx-1)) optionHighlighted++; else optionHighlighted=0; + sprintf(strBuf, " %-12s : %-12s ", Option_Table[optionHighlighted].label, Option_Table[optionHighlighted].option[*(Option_Table[optionHighlighted].option_val)]); + dsPrintValue(1,5+optionHighlighted,1, strBuf); + } + + if (keysCurrent() & KEY_A) // Toggle option + { + *(Option_Table[optionHighlighted].option_val) = (*(Option_Table[optionHighlighted].option_val) + 1) % Option_Table[optionHighlighted].option_max; + sprintf(strBuf, " %-12s : %-12s ", Option_Table[optionHighlighted].label, Option_Table[optionHighlighted].option[*(Option_Table[optionHighlighted].option_val)]); + dsPrintValue(1,5+optionHighlighted,1, strBuf); + } + if (keysCurrent() & KEY_START) // Save Options + { + // TODO: write them out... dsWriteConfig(); + } + if (keysCurrent() & KEY_B) // Exit options + { + break; + } + } + swiWaitForVBlank(); + } + + // Restore original bottom graphic + dsShowScreenMain(false); + + // Give a third of a second time delay... + for (int i=0; i<20; i++) + { + swiWaitForVBlank(); + } + + return; +} + +// End of Line + diff --git a/arm9/source/ds_tools.h b/arm9/source/ds_tools.h new file mode 100644 index 0000000..3d17f33 --- /dev/null +++ b/arm9/source/ds_tools.h @@ -0,0 +1,36 @@ +#ifndef __DS_TOOLS_H +#define __DS_TOOLS_H + +#include + +#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 diff --git a/arm9/source/emucore/AY38900.ITCM.cpp b/arm9/source/emucore/AY38900.ITCM.cpp new file mode 100644 index 0000000..ac90176 --- /dev/null +++ b/arm9/source/emucore/AY38900.ITCM.cpp @@ -0,0 +1,1058 @@ +#include +//#include +#include "AY38900.h" +#include "ProcessorBus.h" + +#define MIN(v1, v2) (v1 < v2 ? v1 : v2) +#define MAX(v1, v2) (v1 > v2 ? v1 : v2) + +#define MODE_VBLANK 0 +#define MODE_START_ACTIVE_DISPLAY 1 +#define MODE_IDLE_ACTIVE_DISPLAY 2 +#define MODE_FETCH_ROW_0 3 +#define MODE_RENDER_ROW_0 4 +#define MODE_FETCH_ROW_1 5 +#define MODE_RENDER_ROW_1 6 +#define MODE_FETCH_ROW_2 7 +#define MODE_RENDER_ROW_2 8 +#define MODE_FETCH_ROW_3 9 +#define MODE_RENDER_ROW_3 10 +#define MODE_FETCH_ROW_4 11 +#define MODE_RENDER_ROW_4 12 +#define MODE_FETCH_ROW_5 13 +#define MODE_RENDER_ROW_5 14 +#define MODE_FETCH_ROW_6 15 +#define MODE_RENDER_ROW_6 16 +#define MODE_FETCH_ROW_7 17 +#define MODE_RENDER_ROW_7 18 +#define MODE_FETCH_ROW_8 19 +#define MODE_RENDER_ROW_8 20 +#define MODE_FETCH_ROW_9 21 +#define MODE_RENDER_ROW_9 22 +#define MODE_FETCH_ROW_10 23 +#define MODE_RENDER_ROW_10 24 +#define MODE_FETCH_ROW_11 25 +#define MODE_RENDER_ROW_11 26 +#define MODE_FETCH_ROW_12 27 + +const INT32 AY38900::TICK_LENGTH_SCANLINE = 228; +const INT32 AY38900::TICK_LENGTH_FRAME = 59736; +const INT32 AY38900::TICK_LENGTH_VBLANK = 15164; +const INT32 AY38900::TICK_LENGTH_START_ACTIVE_DISPLAY = 112; +const INT32 AY38900::TICK_LENGTH_IDLE_ACTIVE_DISPLAY = 456; +const INT32 AY38900::TICK_LENGTH_FETCH_ROW = 456; +const INT32 AY38900::TICK_LENGTH_RENDER_ROW = 3192; +const INT32 AY38900::LOCATION_BACKTAB = 0x0200; +const INT32 AY38900::LOCATION_GROM = 0x3000; +const INT32 AY38900::LOCATION_GRAM = 0x3800; +const INT32 AY38900::FOREGROUND_BIT = 0x0010; + +UINT16 mobBuffers[8][128] __attribute__((section(".dtcm"))); +UINT8 stretch[16] __attribute__((section(".dtcm"))) = {0x00, 0x03, 0x0C, 0x0F, 0x30, 0x33, 0x3C, 0x3F, 0xC0, 0xC3, 0xCC, 0xCF, 0xF0, 0xF3, 0xFC, 0xFF}; +UINT8 reverse[16] __attribute__((section(".dtcm"))) = {0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF}; + +AY38900::AY38900(MemoryBus* mb, ROM* go, GRAM* ga) + : Processor("AY-3-8900"), + memoryBus(mb), + grom(go), + gram(ga), + backtab() +{ + registers.init(this); + + horizontalOffset = 0; + verticalOffset = 0; + blockTop = FALSE; + blockLeft = FALSE; + mode = 0; +} + +void AY38900::resetProcessor() +{ + //switch to bus copy mode + setGraphicsBusVisible(TRUE); + + //reset the mobs + for (UINT8 i = 0; i < 8; i++) + mobs[i].reset(); + + //reset the state variables + mode = -1; + pinOut[AY38900_PIN_OUT_SR1]->isHigh = TRUE; + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + previousDisplayEnabled = TRUE; + displayEnabled = FALSE; + colorStackMode = FALSE; + colorModeChanged = TRUE; + bordersChanged = TRUE; + colorStackChanged = TRUE; + offsetsChanged = TRUE; + + //local register data + borderColor = 0; + blockLeft = blockTop = FALSE; + horizontalOffset = verticalOffset = 0; +} + +void AY38900::setGraphicsBusVisible(BOOL visible) { + registers.SetEnabled(visible); + gram->SetEnabled(visible); + grom->SetEnabled(visible); +} + +INT32 AY38900::tick(INT32 minimum) { + INT32 totalTicks = 0; + do { + switch (mode) + { + //start of vertical blank + case MODE_VBLANK: + //come out of bus isolation mode + setGraphicsBusVisible(TRUE); + if (previousDisplayEnabled) + renderFrame(); + displayEnabled = FALSE; + + //start of vblank, so stop and go back to the main loop + processorBus->stop(); + + //release SR2, allowing the CPU to run + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + + //kick the irq line + pinOut[AY38900_PIN_OUT_SR1]->isHigh = FALSE; + + totalTicks += TICK_LENGTH_VBLANK; + if (totalTicks >= minimum) { + mode = MODE_START_ACTIVE_DISPLAY; + break; + } + + case MODE_START_ACTIVE_DISPLAY: + pinOut[AY38900_PIN_OUT_SR1]->isHigh = TRUE; + + //if the display is not enabled, skip the rest of the modes + if (!displayEnabled) { + if (previousDisplayEnabled) { + //render a blank screen + for (int x = 0; x < 160*192; x++) + pixelBuffer[x] = borderColor; + } + previousDisplayEnabled = FALSE; + mode = MODE_VBLANK; + totalTicks += (TICK_LENGTH_FRAME - TICK_LENGTH_VBLANK); + break; + } + else { + previousDisplayEnabled = TRUE; + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + totalTicks += TICK_LENGTH_START_ACTIVE_DISPLAY; + if (totalTicks >= minimum) { + mode = MODE_IDLE_ACTIVE_DISPLAY; + break; + } + } + + case MODE_IDLE_ACTIVE_DISPLAY: + //switch to bus isolation mode, but only if the CPU has + //acknowledged ~SR2 by asserting ~SST + if (!pinIn[AY38900_PIN_IN_SST]->isHigh) { + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + setGraphicsBusVisible(FALSE); + } + + //release SR2 + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + + totalTicks += TICK_LENGTH_IDLE_ACTIVE_DISPLAY + + (2*verticalOffset*TICK_LENGTH_SCANLINE); + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_0; + break; + } + + case MODE_FETCH_ROW_0: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_0; + break; + } + + case MODE_RENDER_ROW_0: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_1; + break; + } + + case MODE_FETCH_ROW_1: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_1; + break; + } + + case MODE_RENDER_ROW_1: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_2; + break; + } + + case MODE_FETCH_ROW_2: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_2; + break; + } + + case MODE_RENDER_ROW_2: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_3; + break; + } + + case MODE_FETCH_ROW_3: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_3; + break; + } + + case MODE_RENDER_ROW_3: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_4; + break; + } + + case MODE_FETCH_ROW_4: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_4; + break; + } + + case MODE_RENDER_ROW_4: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_5; + break; + } + + case MODE_FETCH_ROW_5: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_5; + break; + } + + case MODE_RENDER_ROW_5: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_6; + break; + } + + case MODE_FETCH_ROW_6: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_6; + break; + } + + case MODE_RENDER_ROW_6: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_7; + break; + } + + case MODE_FETCH_ROW_7: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_7; + break; + } + + case MODE_RENDER_ROW_7: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_8; + break; + } + + case MODE_FETCH_ROW_8: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_8; + break; + } + + case MODE_RENDER_ROW_8: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_9; + break; + } + + case MODE_FETCH_ROW_9: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_9; + break; + } + + case MODE_RENDER_ROW_9: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_10; + break; + } + + case MODE_FETCH_ROW_10: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_10; + break; + } + + case MODE_RENDER_ROW_10: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + pinIn[AY38900_PIN_IN_SST]->isHigh = TRUE; + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_11; + break; + } + + case MODE_FETCH_ROW_11: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + //renderRow((mode-3)/2); + totalTicks += TICK_LENGTH_FETCH_ROW; + if (totalTicks >= minimum) { + mode = MODE_RENDER_ROW_11; + break; + } + + case MODE_RENDER_ROW_11: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = TRUE; + + //this mode could be cut off in tick length if the vertical + //offset is greater than 1 + if (verticalOffset == 0) { + totalTicks += TICK_LENGTH_RENDER_ROW; + if (totalTicks >= minimum) { + mode = MODE_FETCH_ROW_12; + break; + } + } + else if (verticalOffset == 1) { + totalTicks += TICK_LENGTH_RENDER_ROW - TICK_LENGTH_SCANLINE; + mode = MODE_VBLANK; + break; + } + else { + totalTicks += (TICK_LENGTH_RENDER_ROW - TICK_LENGTH_SCANLINE + - (2 * (verticalOffset - 1) * TICK_LENGTH_SCANLINE)); + mode = MODE_VBLANK; + break; + } + + case MODE_FETCH_ROW_12: + default: + pinOut[AY38900_PIN_OUT_SR2]->isHigh = FALSE; + totalTicks += TICK_LENGTH_SCANLINE; + mode = MODE_VBLANK; + break; + } + } while (totalTicks < minimum); + + return totalTicks; +} + +void AY38900::setPixelBuffer(UINT8* pixelBuffer, UINT32 rowSize) +{ + AY38900::pixelBuffer = pixelBuffer; + AY38900::pixelBufferRowSize = rowSize; +} + +ITCM_CODE void AY38900::renderFrame() +{ + //render the next frame + renderBackground(); + renderMOBs(); + for (int i = 0; i < 8; i++) + mobs[i].collisionRegister = 0; + determineMOBCollisions(); + markClean(); + renderBorders(); + copyBackgroundBufferToStagingArea(); + copyMOBsToStagingArea(); + for (int i = 0; i < 8; i++) + memory[0x18+i] |= mobs[i].collisionRegister; +} + +ITCM_CODE void AY38900::render() +{ + // the video bus handles the actual rendering. +} + +ITCM_CODE void AY38900::markClean() { + //everything has been rendered and is now clean + offsetsChanged = FALSE; + bordersChanged = FALSE; + colorStackChanged = FALSE; + colorModeChanged = FALSE; + backtab.markClean(); + gram->markClean(); + for (int i = 0; i < 8; i++) + mobs[i].markClean(); +} + +ITCM_CODE void AY38900::renderBorders() +{ + static int dampen_border_render = 0; + + if (++dampen_border_render & 3) return; + + //draw the top and bottom borders + if (blockTop) { + //move the image up 4 pixels and block the top and bottom 4 rows with the border + for (UINT8 y = 0; y < 8; y++) { + UINT8* buffer0 = ((UINT8*)pixelBuffer) + (y*pixelBufferRowSize); + UINT8* buffer1 = buffer0 + (184*pixelBufferRowSize); + for (UINT8 x = 0; x < 160; x++) { + *buffer0++ = borderColor; + *buffer1++ = borderColor; + } + } + } + else if (verticalOffset != 0) { + //block the top rows of pixels depending on the amount of vertical offset + UINT8 numRows = (UINT8)(verticalOffset<<1); + for (UINT8 y = 0; y < numRows; y++) { + UINT8* buffer0 = ((UINT8*)pixelBuffer) + (y*pixelBufferRowSize); + for (UINT8 x = 0; x < 160; x++) + *buffer0++ = borderColor; + } + } + + //draw the left and right borders + if (blockLeft) { + //move the image to the left 4 pixels and block the left and right 4 columns with the border + for (UINT8 y = 0; y < 192; y++) { + UINT8* buffer0 = ((UINT8*)pixelBuffer) + (y*pixelBufferRowSize); + UINT8* buffer1 = buffer0 + 156; + for (UINT8 x = 0; x < 4; x++) { + *buffer0++ = borderColor; + *buffer1++ = borderColor; + } + } + } + else if (horizontalOffset != 0) { + //block the left columns of pixels depending on the amount of horizontal offset + for (UINT8 y = 0; y < 192; y++) { + UINT8* buffer0 = ((UINT8*)pixelBuffer) + (y*pixelBufferRowSize); + for (UINT8 x = 0; x < horizontalOffset; x++) { + *buffer0++ = borderColor; + } + } + } +} + +ITCM_CODE void AY38900::renderMOBs() +{ + for (int i = 0; i < 8; i++) + { + //if the mob did not change shape and it's rendering from GROM (indicating that + //the source of its rendering could not have changed), then this MOB does not need + //to be re-rendered into its buffer + if (!mobs[i].shapeChanged && mobs[i].isGrom) + continue; + + //start at this memory location + UINT16 firstMemoryLocation = (UINT16)(mobs[i].isGrom + ? LOCATION_GROM + (mobs[i].cardNumber << 3) + : LOCATION_GRAM + ((mobs[i].cardNumber & 0x3F) << 3)); + + //end at this memory location + UINT16 lastMemoryLocation = (UINT16)(firstMemoryLocation + 8); + if (mobs[i].doubleYResolution) + lastMemoryLocation += 8; + + //make the pixels this tall + int pixelHeight = (mobs[i].quadHeight ? 4 : 1) * (mobs[i].doubleHeight ? 2 : 1); + + //start at the first line for regular vertical rendering or start at the last line + //for vertically mirrored rendering + int nextLine = 0; + if (mobs[i].verticalMirror) + nextLine = (pixelHeight * (mobs[i].doubleYResolution ? 15 : 7)); + for (UINT16 j = firstMemoryLocation; j < lastMemoryLocation; j++) { + if (!mobs[i].shapeChanged && !gram->isCardDirty((UINT16)(j & 0x01FF))) { + if (mobs[i].verticalMirror) + nextLine -= pixelHeight; + else + nextLine += pixelHeight; + continue; + } + + //get the next line of pixels + UINT16 nextData = (UINT16)(memoryBus->peek(j) & 0xFF); + + //reverse the pixels horizontally if necessary + if (mobs[i].horizontalMirror) + nextData = (UINT16)((reverse[nextData & 0x0F] << 4) | reverse[(nextData & 0xF0) >> 4]); + + //double them if necessary + if (mobs[i].doubleWidth) + nextData = (UINT16)((stretch[(nextData & 0xF0) >> 4] << 8) | stretch[nextData & 0x0F]); + else + nextData <<= 8; + + //lay down as many lines of pixels as necessary + for (int k = 0; k < pixelHeight; k++) + mobBuffers[i][nextLine++] = nextData; + + if (mobs[i].verticalMirror) + nextLine -= (2*pixelHeight); + } + } +} + +ITCM_CODE void AY38900::renderBackground() +{ + /* + if (!backtab.isDirty() && !gram->isDirty() && !colorStackChanged && !colorModeChanged) + return; + */ + + if (colorStackMode) + renderColorStackMode(); + else + renderForegroundBackgroundMode(); +} + +ITCM_CODE void AY38900::renderForegroundBackgroundMode() +{ + //iterate through all the cards in the backtab + for (UINT8 i = 0; i < 240; i++) { + //get the next card to render + UINT16 nextCard = backtab.peek(LOCATION_BACKTAB+i); + BOOL isGrom = (nextCard & 0x0800) == 0; + UINT16 memoryLocation = nextCard & 0x01F8; + + //render this card only if this card has changed or if the card points to GRAM + //and one of the eight bytes in gram that make up this card have changed + if (colorModeChanged || backtab.isDirty(LOCATION_BACKTAB+i) || (!isGrom && gram->isCardDirty(memoryLocation))) { + UINT8 fgcolor = (UINT8)((nextCard & 0x0007) | FOREGROUND_BIT); + UINT8 bgcolor = (UINT8)(((nextCard & 0x2000) >> 11) | ((nextCard & 0x1600) >> 9)); + + Memory* memory = (isGrom ? (Memory*)grom : (Memory*)gram); + UINT16 address = memory->getReadAddress()+memoryLocation; + UINT8 nextx = (i%20) * 8; + UINT8 nexty = (i/20) * 8; + for (UINT16 j = 0; j < 8; j++) + renderLine((UINT8)memory->peek(address+j), nextx, nexty+j, fgcolor, bgcolor); + } + } +} + +ITCM_CODE void AY38900::renderColorStackMode() +{ + UINT8 csPtr = 0; + //if there are any dirty color advance bits in the backtab, or if + //the color stack or the color mode has changed, the whole scene + //must be rendered + BOOL renderAll = backtab.areColorAdvanceBitsDirty() || + colorStackChanged || colorModeChanged; + + UINT8 nextx = 0; + UINT8 nexty = 0; + //iterate through all the cards in the backtab + for (UINT8 h = 0; h < 240; h++) + { + UINT16 nextCard = backtab.peek(LOCATION_BACKTAB+h); + + //colored squares mode + if ((nextCard & 0x1800) == 0x1000) { + if (renderAll || backtab.isDirty(LOCATION_BACKTAB+h)) { + UINT8 csColor = (UINT8)memory[0x28 + csPtr]; + UINT8 color0 = (UINT8)(nextCard & 0x0007); + UINT8 color1 = (UINT8)((nextCard & 0x0038) >> 3); + UINT8 color2 = (UINT8)((nextCard & 0x01C0) >> 6); + UINT8 color3 = (UINT8)(((nextCard & 0x2000) >> 11) | + ((nextCard & 0x0600) >> 9)); + renderColoredSquares(nextx, nexty, + (color0 == 7 ? csColor : (UINT8)(color0 | FOREGROUND_BIT)), + (color1 == 7 ? csColor : (UINT8)(color1 | FOREGROUND_BIT)), + (color2 == 7 ? csColor : (UINT8)(color2 | FOREGROUND_BIT)), + (color3 == 7 ? csColor : (UINT8)(color3 | FOREGROUND_BIT))); + } + } + //color stack mode + else { + //advance the color pointer, if necessary + if ((nextCard & 0x2000) != 0) + csPtr = (UINT8)((csPtr+1) & 0x03); + + BOOL isGrom = (nextCard & 0x0800) == 0; + UINT16 memoryLocation = (isGrom ? (nextCard & 0x07F8) + : (nextCard & 0x01F8)); + + if (renderAll || backtab.isDirty(LOCATION_BACKTAB+h) || + (!isGrom && gram->isCardDirty(memoryLocation))) { + UINT8 fgcolor = (UINT8)(((nextCard & 0x1000) >> 9) | + (nextCard & 0x0007) | FOREGROUND_BIT); + UINT8 bgcolor = (UINT8)memory[0x28 + csPtr]; + Memory* memory = (isGrom ? (Memory*)grom : (Memory*)gram); + UINT16 address = memory->getReadAddress()+memoryLocation; + for (UINT16 j = 0; j < 8; j++) + renderLine((UINT8)memory->peek(address+j), nextx, nexty+j, fgcolor, bgcolor); + } + } + nextx += 8; + if (nextx == 160) { + nextx = 0; + nexty += 8; + } + } +} + +ITCM_CODE void AY38900::copyBackgroundBufferToStagingArea() +{ + int sourceWidthX = blockLeft ? 152 : (160 - horizontalOffset); + int sourceHeightY = blockTop ? 88 : (96 - verticalOffset); + + int nextSourcePixel = (blockLeft ? (8 - horizontalOffset) : 0) + + ((blockTop ? (8 - verticalOffset) : 0) * 160); + + for (int y = 0; y < sourceHeightY; y++) + { + UINT8* nextPixelStore0 = (UINT8*)pixelBuffer; + nextPixelStore0 += (y*pixelBufferRowSize*4)>>1; + if (blockTop) nextPixelStore0 += (pixelBufferRowSize*4)<<1; + if (blockLeft) nextPixelStore0 += 4; + UINT8* nextPixelStore1 = nextPixelStore0 + pixelBufferRowSize; + for (int x = 0; x < sourceWidthX; x++) { + UINT8 nextColor = backgroundBuffer[nextSourcePixel+x]; + *nextPixelStore0++ = nextColor; + *nextPixelStore1++ = nextColor; + } + nextSourcePixel += 160; + } +#if 0 + int sourceWidthX = blockLeft ? 152 : (160 - horizontalOffset); + int sourceHeightY = blockTop ? 88 : (96 - verticalOffset); + + int nextSourcePixel = (blockLeft ? (8 - horizontalOffset) : 0) + + ((blockTop ? (8 - verticalOffset) : 0) * 160); + + for (int y = 0; y < sourceHeightY; y++) { + UINT32* nextPixelStore0 = (UINT32*)pixelBuffer; + nextPixelStore0 += (y*pixelBufferRowSize)>>1; + if (blockTop) nextPixelStore0 += pixelBufferRowSize<<1; + if (blockLeft) nextPixelStore0 += 4; + UINT32* nextPixelStore1 = nextPixelStore0 + pixelBufferRowSize/4; + for (int x = 0; x < sourceWidthX; x++) { + UINT32 nextColor = backgroundBuffer[nextSourcePixel+x]; + *nextPixelStore0++ = nextColor; + *nextPixelStore1++ = nextColor; + } + nextSourcePixel += 160; + } +#endif +} + +//copy the offscreen mob buffers to the staging area +ITCM_CODE void AY38900::copyMOBsToStagingArea() +{ + for (INT8 i = 7; i >= 0; i--) { + if (mobs[i].xLocation == 0 || (!mobs[i].flagCollisions && !mobs[i].isVisible)) + continue; + + BOOL borderCollision = FALSE; + BOOL foregroundCollision = FALSE; + + MOBRect* r = mobs[i].getBounds(); + UINT8 mobPixelHeight = (UINT8)(r->height << 1); + UINT8 fgcolor = (UINT8)mobs[i].foregroundColor; + + INT16 leftX = (INT16)(r->x + horizontalOffset); + INT16 nextY = (INT16)((r->y + verticalOffset) << 1); + for (UINT8 y = 0; y < mobPixelHeight; y++) { + for (UINT8 x = 0; x < r->width; x++) { + //if this mob pixel is not on, then our life has no meaning + if ((mobBuffers[i][y] & (0x8000 >> x)) == 0) + continue; + + //if the next pixel location is on the border, then we + //have a border collision and we can ignore painting it + int nextX = leftX + x; + if (nextX < (blockLeft ? 8 : 0) || nextX > 158 || + nextY < (blockTop ? 16 : 0) || nextY > 191) { + borderCollision = TRUE; + continue; + } + + //check for foreground collision + UINT8 currentPixel = backgroundBuffer[(r->x+x)+ ((r->y+(y/2))*160)]; + if ((currentPixel & FOREGROUND_BIT) != 0) { + foregroundCollision = TRUE; + if (mobs[i].behindForeground) + continue; + } + if (mobs[i].isVisible) { + UINT8* nextPixel = (UINT8*)pixelBuffer; + nextPixel += leftX - (blockLeft ? 4 : 0) + x; + nextPixel += (nextY - (blockTop ? 8 : 0)) * (pixelBufferRowSize); + *nextPixel = fgcolor | (currentPixel & FOREGROUND_BIT); + } + } + nextY++; + } + + //update the collision bits + if (mobs[i].flagCollisions) { + if (foregroundCollision) + mobs[i].collisionRegister |= 0x0100; + if (borderCollision) + mobs[i].collisionRegister |= 0x0200; + } + } +} + +ITCM_CODE void AY38900::renderLine(UINT8 nextbyte, int x, int y, UINT8 fgcolor, UINT8 bgcolor) +{ + UINT8* nextTargetPixel = backgroundBuffer + x + (y*160); + *nextTargetPixel++ = (nextbyte & 0x80) != 0 ? fgcolor : bgcolor; + *nextTargetPixel++ = (nextbyte & 0x40) != 0 ? fgcolor : bgcolor; + *nextTargetPixel++ = (nextbyte & 0x20) != 0 ? fgcolor : bgcolor; + *nextTargetPixel++ = (nextbyte & 0x10) != 0 ? fgcolor : bgcolor; + + *nextTargetPixel++ = (nextbyte & 0x08) != 0 ? fgcolor : bgcolor; + *nextTargetPixel++ = (nextbyte & 0x04) != 0 ? fgcolor : bgcolor; + *nextTargetPixel++ = (nextbyte & 0x02) != 0 ? fgcolor : bgcolor; + *nextTargetPixel++ = (nextbyte & 0x01) != 0 ? fgcolor : bgcolor; +} + +ITCM_CODE void AY38900::renderColoredSquares(int x, int y, UINT8 color0, UINT8 color1, + UINT8 color2, UINT8 color3) { + int topLeftPixel = x + (y*160); + int topRightPixel = topLeftPixel+4; + int bottomLeftPixel = topLeftPixel+640; + int bottomRightPixel = bottomLeftPixel+4; + + for (UINT8 w = 0; w < 4; w++) { + for (UINT8 i = 0; i < 4; i++) { + backgroundBuffer[topLeftPixel++] = color0; + backgroundBuffer[topRightPixel++] = color1; + backgroundBuffer[bottomLeftPixel++] = color2; + backgroundBuffer[bottomRightPixel++] = color3; + } + topLeftPixel += 156; + topRightPixel += 156; + bottomLeftPixel += 156; + bottomRightPixel += 156; + } +} + +ITCM_CODE void AY38900::determineMOBCollisions() +{ + for (int i = 0; i < 7; i++) { + if (mobs[i].xLocation == 0 || !mobs[i].flagCollisions) + continue; + + /* + //check MOB on foreground collisions + if (mobCollidesWithForeground(i)) + mobs[i].collisionRegister |= 0x0100; + + //check MOB on border collisions + if (mobCollidesWithBorder(i)) + mobs[i].collisionRegister |= 0x0200; + */ + + //check MOB on MOB collisions + for (int j = i+1; j < 8; j++) + { + if (mobs[j].xLocation == 0 || !mobs[j].flagCollisions) + continue; + + if (mobsCollide(i, j)) { + mobs[i].collisionRegister |= (1 << j); + mobs[j].collisionRegister |= (1 << i); + } + } + } +} + +BOOL AY38900::mobCollidesWithBorder(int mobNum) +{ + MOBRect* r = mobs[mobNum].getBounds(); + UINT8 mobPixelHeight = (UINT8)(r->height<<1); + + /* + if (r->x > (blockLeft ? 8 : 0) && r->x+r->width <= 191 && + r->y > (blockTop ? 8 : 0) && r->y+r->height <= 158) + return FALSE; + + for (UINT8 i = 0; i < r->height; i++) { + if (mobBuffers[mobNum][i<<1] == 0 || mobBuffers[mobNum][(i<<1)+1] == 0) + continue; + + if (r->y+i < (blockLeft ? 8 : 0) || r->y+r->height+i > 158) + return TRUE; + + //if (r->x && border + } + */ + + UINT16 leftRightBorder = 0; + //check if could possibly touch the left border + if (r->x < (blockLeft ? 8 : 0)) { + leftRightBorder = (UINT16)((blockLeft ? 0xFFFF : 0xFF00) << mobs[mobNum].xLocation); + } + //check if could possibly touch the right border + else if (r->x+r->width > 158) { + leftRightBorder = 0xFFFF; + if (r->x < 158) + leftRightBorder >>= r->x-158; + } + + //check if touching the left or right border + if (leftRightBorder) { + for (INT32 i = 0; i < mobPixelHeight; i++) { + if ((mobBuffers[mobNum][i] & leftRightBorder) != 0) + return TRUE; + } + } + + //check if touching the top border + UINT8 overlappingStart = 0; + UINT8 overlappingHeight = 0; + if (r->y < (blockTop ? 8 : 0)) { + overlappingHeight = mobPixelHeight; + if (r->y+r->height > (blockTop ? 8 : 0)) + overlappingHeight = (UINT8)(mobPixelHeight - (2*(r->y+r->height-(blockTop ? 8 : 0)))); + } + //check if touching the bottom border + else if (r->y+r->height > 191) { + if (r->y < 191) + overlappingStart = (UINT8)(2*(191-r->y)); + overlappingHeight = mobPixelHeight - overlappingStart; + } + + if (overlappingHeight) { + for (UINT8 i = overlappingStart; i < overlappingHeight; i++) { + if (mobBuffers[mobNum][i] != 0) + return TRUE; + } + } + + return FALSE; +} + +BOOL AY38900::mobsCollide(int mobNum0, int mobNum1) +{ + MOBRect* r0 = mobs[mobNum0].getBounds(); + MOBRect* r1 = mobs[mobNum1].getBounds(); + if (!r0->intersects(r1)) + return FALSE; + + //determine the overlapping horizontal area + int startingX = MAX(r0->x, r1->x); + int offsetXr0 = startingX - r0->x; + int offsetXr1 = startingX - r1->x; + + //determine the overlapping vertical area + int startingY = MAX(r0->y, r1->y); + int offsetYr0 = (startingY - r0->y) * 2; + int offsetYr1 = (startingY - r1->y) * 2; + int overlappingHeight = (MIN(r0->y + r0->height, r1->y + r1->height) - startingY) * 2; + + //iterate over the intersecting bits to see if any touch + for (int y = 0; y < overlappingHeight; y++) { + if (((mobBuffers[mobNum0][offsetYr0 + y] << offsetXr0) & (mobBuffers[mobNum1][offsetYr1 + y] << offsetXr1)) != 0) + return TRUE; + } + + return FALSE; +} + +AY38900State AY38900::getState() +{ + AY38900State state = {0}; +#if 0 + this->registers.getMemory(state.registers, 0, this->registers.getMemoryByteSize()); + state.backtab = this->backtab.getState(); + + state.inVBlank = this->inVBlank; + state.mode = this->mode; + state.previousDisplayEnabled = this->previousDisplayEnabled; + state.displayEnabled = this->displayEnabled; + state.colorStackMode = this->colorStackMode; + + state.borderColor = this->borderColor; + state.blockLeft = this->blockLeft; + state.blockTop = this->blockTop; + state.horizontalOffset = this->horizontalOffset; + state.verticalOffset = this->verticalOffset; + + for (int i = 0; i < 8; i++) { + state.mobs[i] = this->mobs[i].getState(); + } +#endif + return state; +} + +void AY38900::setState(AY38900State state) +{ +#if 0 + this->registers.setMemory(state.registers, 0, this->registers.getMemoryByteSize()); + this->backtab.setState(state.backtab, state.backtab.image); + + this->inVBlank = state.inVBlank; + this->mode = state.mode; + this->previousDisplayEnabled = state.previousDisplayEnabled; + this->displayEnabled = state.displayEnabled; + this->colorStackMode = state.colorStackMode; + + this->borderColor = state.borderColor; + this->blockLeft = state.blockLeft; + this->blockTop = state.blockTop; + this->horizontalOffset = state.horizontalOffset; + this->verticalOffset = state.verticalOffset; + + for (int i = 0; i < 8; i++) { + mobs[i].setState(state.mobs[i]); + } + + this->colorModeChanged = TRUE; + this->bordersChanged = TRUE; + this->colorStackChanged = TRUE; + this->offsetsChanged = TRUE; + this->imageBufferChanged = TRUE; +#endif +} + +/* +void AY38900::renderRow(int rowNum) { + UINT8 backTabPtr = (UINT8)(0x200+(rowNum*20)); + if (colorStackMode) { + UINT8 csPtr = 0; + UINT8 nextx = 0; + UINT8 nexty = 0; + for (UINT8 h = 0; h < 20; h++) { + UINT8 nextCard = (UINT8)backtab.peek(backTabPtr); + backTabPtr++; + + if ((nextCard & 0x1800) == 0x1000) { + //colored squares mode + UINT8 csColor = (UINT8)registers.memory[0x28 + csPtr]; + UINT8 color0 = (UINT8)(nextCard & 0x0007); + UINT8 color1 = (UINT8)((nextCard & 0x0038) >> 3); + UINT8 color2 = (UINT8)((nextCard & 0x01C0) >> 6); + UINT8 color3 = (UINT8)(((nextCard & 0x2000) >> 11) | + ((nextCard & 0x0600) >> 9)); + renderColoredSquares(nextx, nexty, + (color0 == 7 ? csColor : (UINT8)(color0 | FOREGROUND_BIT)), + (color1 == 7 ? csColor : (UINT8)(color1 | FOREGROUND_BIT)), + (color2 == 7 ? csColor : (UINT8)(color2 | FOREGROUND_BIT)), + (color3 == 7 ? csColor : (UINT8)(color3 | FOREGROUND_BIT))); + } + else { + //color stack mode + //advance the color pointer, if necessary + if ((nextCard & 0x2000) != 0) + csPtr = (UINT8)((csPtr+1) & 0x03); + + BOOL isGrom = (nextCard & 0x0800) == 0; + UINT8 memoryLocation = (UINT8)(isGrom ? (nextCard & 0x07F8) + : (nextCard & 0x01F8)); + + UINT8 fgcolor = (UINT8)(((nextCard & 0x1000) >> 9) | + (nextCard & 0x0007) | FOREGROUND_BIT); + UINT8 bgcolor = (UINT8)registers.memory[0x28 + csPtr]; + UINT16* memory = (isGrom ? grom->image : gram->image); + for (int j = 0; j < 8; j++) + renderLine((UINT8)memory[memoryLocation+j], nextx, nexty+j, fgcolor, bgcolor); + } + nextx += 8; + if (nextx == 160) { + nextx = 0; + nexty += 8; + } + } + } + else { + UINT8 nextx = 0; + UINT8 nexty = 0; + for (UINT8 i = 0; i < 240; i++) { + UINT8 nextCard = (UINT8)backtab.peek((UINT8)(0x200+i)); + BOOL isGrom = (nextCard & 0x0800) == 0; + BOOL renderAll = backtab.isDirty((UINT8)(0x200+i)) || colorModeChanged; + UINT8 memoryLocation = (UINT8)(nextCard & 0x01F8); + + if (renderAll || (!isGrom && gram->isCardDirty(memoryLocation))) { + UINT8 fgcolor = (UINT8)((nextCard & 0x0007) | FOREGROUND_BIT); + UINT8 bgcolor = (UINT8)(((nextCard & 0x2000) >> 11) | + ((nextCard & 0x1600) >> 9)); + + UINT16* memory = (isGrom ? grom->image : gram->image); + for (int j = 0; j < 8; j++) + renderLine((UINT8)memory[memoryLocation+j], nextx, nexty+j, fgcolor, bgcolor); + } + nextx += 8; + if (nextx == 160) { + nextx = 0; + nexty += 8; + } + } + } +} +*/ diff --git a/arm9/source/emucore/AY38900.h b/arm9/source/emucore/AY38900.h new file mode 100644 index 0000000..fde13c5 --- /dev/null +++ b/arm9/source/emucore/AY38900.h @@ -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 +*/ diff --git a/arm9/source/emucore/AY38900_Registers.cpp b/arm9/source/emucore/AY38900_Registers.cpp new file mode 100644 index 0000000..38fdd44 --- /dev/null +++ b/arm9/source/emucore/AY38900_Registers.cpp @@ -0,0 +1,198 @@ +#include +#include +#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]; + } +} diff --git a/arm9/source/emucore/AY38900_Registers.h b/arm9/source/emucore/AY38900_Registers.h new file mode 100644 index 0000000..7f8a755 --- /dev/null +++ b/arm9/source/emucore/AY38900_Registers.h @@ -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 diff --git a/arm9/source/emucore/AY38914.ITCM.cpp b/arm9/source/emucore/AY38914.ITCM.cpp new file mode 100644 index 0000000..e5b6053 --- /dev/null +++ b/arm9/source/emucore/AY38914.ITCM.cpp @@ -0,0 +1,339 @@ +#include +#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 +} diff --git a/arm9/source/emucore/AY38914.h b/arm9/source/emucore/AY38914.h new file mode 100644 index 0000000..c56720c --- /dev/null +++ b/arm9/source/emucore/AY38914.h @@ -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 diff --git a/arm9/source/emucore/AY38914_Channel.cpp b/arm9/source/emucore/AY38914_Channel.cpp new file mode 100644 index 0000000..542d1d0 --- /dev/null +++ b/arm9/source/emucore/AY38914_Channel.cpp @@ -0,0 +1 @@ +// Obsoleted... diff --git a/arm9/source/emucore/AY38914_Channel.h b/arm9/source/emucore/AY38914_Channel.h new file mode 100644 index 0000000..d40664c --- /dev/null +++ b/arm9/source/emucore/AY38914_Channel.h @@ -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 diff --git a/arm9/source/emucore/AY38914_InputOutput.h b/arm9/source/emucore/AY38914_InputOutput.h new file mode 100644 index 0000000..f1629bb --- /dev/null +++ b/arm9/source/emucore/AY38914_InputOutput.h @@ -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 diff --git a/arm9/source/emucore/AY38914_Registers.cpp b/arm9/source/emucore/AY38914_Registers.cpp new file mode 100644 index 0000000..b8c41ef --- /dev/null +++ b/arm9/source/emucore/AY38914_Registers.cpp @@ -0,0 +1,180 @@ + +#include +#include +#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]; + } +} + diff --git a/arm9/source/emucore/AY38914_Registers.h b/arm9/source/emucore/AY38914_Registers.h new file mode 100644 index 0000000..e31ebc5 --- /dev/null +++ b/arm9/source/emucore/AY38914_Registers.h @@ -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 diff --git a/arm9/source/emucore/AudioMixer.cpp b/arm9/source/emucore/AudioMixer.cpp new file mode 100644 index 0000000..f789460 --- /dev/null +++ b/arm9/source/emucore/AudioMixer.cpp @@ -0,0 +1,161 @@ +#include +#include +#include +#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; +} diff --git a/arm9/source/emucore/AudioMixer.h b/arm9/source/emucore/AudioMixer.h new file mode 100644 index 0000000..e413829 --- /dev/null +++ b/arm9/source/emucore/AudioMixer.h @@ -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 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 diff --git a/arm9/source/emucore/AudioOutputLine.cpp b/arm9/source/emucore/AudioOutputLine.cpp new file mode 100644 index 0000000..4a193a1 --- /dev/null +++ b/arm9/source/emucore/AudioOutputLine.cpp @@ -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; +} + + + diff --git a/arm9/source/emucore/AudioOutputLine.h b/arm9/source/emucore/AudioOutputLine.h new file mode 100644 index 0000000..ac25298 --- /dev/null +++ b/arm9/source/emucore/AudioOutputLine.h @@ -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 + + diff --git a/arm9/source/emucore/AudioProducer.h b/arm9/source/emucore/AudioProducer.h new file mode 100644 index 0000000..613f519 --- /dev/null +++ b/arm9/source/emucore/AudioProducer.h @@ -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 diff --git a/arm9/source/emucore/BackTabRAM.cpp b/arm9/source/emucore/BackTabRAM.cpp new file mode 100644 index 0000000..01b8e1f --- /dev/null +++ b/arm9/source/emucore/BackTabRAM.cpp @@ -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; +} diff --git a/arm9/source/emucore/BackTabRAM.h b/arm9/source/emucore/BackTabRAM.h new file mode 100644 index 0000000..f1ebeba --- /dev/null +++ b/arm9/source/emucore/BackTabRAM.h @@ -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 diff --git a/arm9/source/emucore/CP1610.cpp b/arm9/source/emucore/CP1610.cpp new file mode 100644 index 0000000..cf0f4ef --- /dev/null +++ b/arm9/source/emucore/CP1610.cpp @@ -0,0 +1,4258 @@ +#include +#include +#include "CP1610.h" +#include "types.h" + +#define MAX(v1, v2) (v1 > v2 ? v1 : v2) + +//the eight registers available in the CP1610 +UINT16 r[8] __attribute__((section(".dtcm"))); + +//the six flags available in the CP1610 +UINT8 S __attribute__((section(".dtcm"))); +UINT8 Z __attribute__((section(".dtcm"))); +UINT8 O __attribute__((section(".dtcm"))); +UINT8 C __attribute__((section(".dtcm"))); +UINT8 I __attribute__((section(".dtcm"))); +UINT8 D __attribute__((section(".dtcm"))); + +UINT16 op __attribute__((section(".dtcm"))); + +//indicates whether the last executed instruction is interruptible +UINT8 interruptible __attribute__((section(".dtcm"))); + +//the four external lines +INT8 ext __attribute__((section(".dtcm")));; + +#pragma warning(disable:4786) // Suppress STL debug info > 255 chars messages + +CP1610::CP1610(MemoryBus* m, UINT16 resetAddress, + UINT16 interruptAddress) + : Processor("CP1610"), + memoryBus(m), + resetAddress(resetAddress), + interruptAddress(interruptAddress) +{ +} + +INT32 CP1610::getClockSpeed() { + return 3579545; +} + +void CP1610::resetProcessor() +{ + //the four external lines + ext = 0; + + pinOut[CP1610_PIN_OUT_BUSAK]->isHigh = TRUE; + interruptible = FALSE; + S = C = O = Z = I = D = FALSE; + for (INT32 i = 0; i < 7; i++) + r[i] = 0; + r[7] = resetAddress; +} + +/** + * This method ticks the CPU and returns the number of cycles that were + * used up, indicating to the main emulation loop when the CPU will need + * to be ticked again. + */ +ITCM_CODE INT32 CP1610::tick(INT32 minimum) +{ + int usedCycles = 0; + + // --------------------------------------------------------------------- + // Small speedup so we don't have to shift usedCycles on every loop.. + // --------------------------------------------------------------------- + int min_shifted = (minimum >> 2); + if ((min_shifted<<2) != minimum) min_shifted++; + + do { + if (interruptible) + { + if (!pinIn[CP1610_PIN_IN_BUSRQ]->isHigh) + { + pinOut[CP1610_PIN_OUT_BUSAK]->isHigh = pinIn[CP1610_PIN_IN_BUSRQ]->isHigh; + return MAX((usedCycles<<2), minimum); + } + + if (I && !pinIn[CP1610_PIN_IN_INTRM]->isHigh) + { + pinIn[CP1610_PIN_IN_INTRM]->isHigh = TRUE; + interruptible = false; + memoryBus->poke(r[6], r[7]); + r[6]++; + r[7] = interruptAddress; + usedCycles += 7; + if ((usedCycles << 2) >= minimum) + return (usedCycles<<2); + } + } + + //do the next instruction + op = memoryBus->peek_pc(); + usedCycles += decode(); + } while ((usedCycles) < min_shifted); + + return (usedCycles<<2); +} + + +UINT16 CP1610::getIndirect(UINT16 registerNum) +{ + UINT16 value; + if (registerNum == 6) + { + r[6]--; + value = memoryBus->peek_fast(r[6]); + if (D) + value = (value & 0xFF) | ((memoryBus->peek(r[6]) & 0xFF) << 8); + } + else + { + value = memoryBus->peek(r[registerNum]); + if (registerNum & 0x04) + r[registerNum]++; + if (D) { + value = (value & 0xFF) | + (memoryBus->peek(r[registerNum]) & 0xFF) << 8; + if (registerNum & 0x04) + r[registerNum]++; + } + } + + return value; +} + +INT32 CP1610::HLT() { + return 1; +} + +INT32 CP1610::SDBD() { + r[7]++; + interruptible = FALSE; + + D = TRUE; + + return 4; +} + +INT32 CP1610::EIS() { + r[7]++; + interruptible = FALSE; + + I = TRUE; + + D = FALSE; + return 4; +} + +INT32 CP1610::DIS() { + r[7]++; + interruptible = FALSE; + + I = FALSE; + + D = FALSE; + return 4; +} + +INT32 CP1610::TCI() { + r[7]++; + interruptible = FALSE; + + //What should this really do? + + D = FALSE; + return 4; +} + +INT32 CP1610::CLRC() { + r[7]++; + interruptible = FALSE; + + C = FALSE; + + D = FALSE; + return 4; +} + +INT32 CP1610::SETC() { + r[7]++; + interruptible = FALSE; + + C = TRUE; + + D = FALSE; + return 4; +} + +INT32 CP1610::J(UINT16 target) { + r[7] = target; + interruptible = TRUE; + + D = FALSE; + return 12; +} + +INT32 CP1610::JSR(UINT16 registerNum, UINT16 target) { + r[registerNum] = r[7]+3; + r[7] = target; + interruptible = TRUE; + + D = FALSE; + return 12; +} + +INT32 CP1610::JE(UINT16 target) { + I = TRUE; + r[7] = target; + interruptible = TRUE; + + D = FALSE; + return 12; +} + +INT32 CP1610::JSRE(UINT16 registerNum, UINT16 target) { + I = TRUE; + r[registerNum] = r[7]+3; + r[7] = target; + interruptible = TRUE; + + D = FALSE; + return 12; +} + +INT32 CP1610::JD(UINT16 target) { + I = FALSE; + r[7] = target; + interruptible = TRUE; + + D = FALSE; + return 12; +} + +INT32 CP1610::JSRD(UINT16 registerNum, UINT16 target) { + I = FALSE; + r[registerNum] = r[7]+3; + r[7] = target; + interruptible = TRUE; + + D = FALSE; + return 12; +} + +INT32 CP1610::INCR(UINT16 registerNum) { + r[7]++; + interruptible = TRUE; + + UINT16 newValue = r[registerNum]+1; + S = !!(newValue & 0x8000); + Z = !newValue; + r[registerNum] = newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::DECR(UINT16 registerNum) { + r[7]++; + interruptible = TRUE; + + UINT16 newValue = r[registerNum]-1; + S = !!(newValue & 0x8000); + Z = !newValue; + r[registerNum] = newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::NEGR(UINT16 registerNum) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = r[registerNum]; + UINT32 newValue = (op1 ^ 0xFFFF) + 1; + C = !!(newValue & 0x10000); + O = !!(newValue & op1 & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[registerNum] = (UINT16)newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::ADCR(UINT16 registerNum) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = r[registerNum]; + UINT16 op2 = (C ? 1 : 0); + UINT32 newValue = op1 + op2; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & ~(op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[registerNum] = (UINT16)newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::RSWD(UINT16 registerNum) { + r[7]++; + interruptible = TRUE; + + UINT16 value = r[registerNum]; + S = !!(value & 0x0080); + Z = !!(value & 0x0040); + O = !!(value & 0x0020); + C = !!(value & 0x0010); + + D = FALSE; + return 6; +} + +INT32 CP1610::GSWD(UINT16 registerNum) { + r[7]++; + interruptible = TRUE; + + UINT16 value = ((S ? 1 : 0) << 7) | ((Z ? 1 : 0) << 6) | + ((O ? 1 : 0) << 5) | ((C ? 1 : 0) << 4); + value |= (value << 8); + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::NOP(UINT16) { + r[7]++; + interruptible = TRUE; + + D = FALSE; + return 6; +} + +INT32 CP1610::SIN(UINT16) { + r[7]++; + interruptible = TRUE; + + //TODO: does SIN need to do anything?! + + D = FALSE; + return 6; +} + +INT32 CP1610::SWAP_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + value = ((value & 0xFF00) >> 8) | ((value & 0xFF) << 8); + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::SWAP_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum] & 0xFF; + value |= (value << 8); + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::COMR(UINT16 registerNum) { + r[7]++; + interruptible = TRUE; + + UINT16 value = r[registerNum] ^ 0xFFFF; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::SLL_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum] << 1; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::SLL_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum] << 2; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::RLC_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + UINT16 carry = (C ? 1 : 0); + C = !!(value & 0x8000); + value = (value << 1) | carry; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::RLC_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + UINT16 carry = (C ? 1 : 0); + UINT16 overflow = (O ? 1 : 0); + C = !!(value & 0x8000); + O = !!(value & 0x4000); + value = (value << 2) | (carry << 1) | overflow; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::SLLC_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + C = !!(value & 0x8000); + value <<= 1; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::SLLC_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + C = !!(value & 0x8000); + O = !!(value & 0x4000); + value <<= 2; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::SLR_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum] >> 1; + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::SLR_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum] >> 2; + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::SAR_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + value = (value >> 1) | (value & 0x8000); + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::SAR_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + UINT16 s = value & 0x8000; + value = (value >> 2) | s | (s >> 1); + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::RRC_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + UINT16 carry = (C ? 1 : 0); + C = !!(value & 0x0001); + value = (value >> 1) | (carry << 15); + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::RRC_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + UINT16 carry = (C ? 1 : 0); + UINT16 overflow = (O ? 1 : 0); + C = !!(value & 0x0001); + O = !!(value & 0x0002); + value = (value >> 2) | (carry << 14) | (overflow << 15); + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::SARC_1(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + C = !!(value & 0x0001); + value = (value >> 1) | (value & 0x8000); + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 6; +} + +INT32 CP1610::SARC_2(UINT16 registerNum) { + r[7]++; + interruptible = FALSE; + + UINT16 value = r[registerNum]; + C = !!(value & 0x0001); + O = !!(value & 0x0002); + UINT16 s = value & 0x8000; + value = (value >> 2) | s | (s >> 1); + S = !!(value & 0x0080); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 8; +} + +INT32 CP1610::MOVR(UINT16 sourceReg, UINT16 destReg) { + r[7]++; + interruptible = TRUE; + + UINT16 value = r[sourceReg]; + S = !!(value & 0x8000); + Z = !value; + r[destReg] = value; + + D = FALSE; + return (destReg >= 6 ? 7 : 6); +} + +INT32 CP1610::ADDR(UINT16 sourceReg, UINT16 destReg) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = r[sourceReg]; + UINT16 op2 = r[destReg]; + UINT32 newValue = op1 + op2; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & ~(op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[destReg] = (UINT16)newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::SUBR(UINT16 sourceReg, UINT16 destReg) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = r[sourceReg]; + UINT16 op2 = r[destReg]; + UINT32 newValue = op2 + (0xFFFF ^ op1) + 1; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & (op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[destReg] = (UINT16)newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::CMPR(UINT16 sourceReg, UINT16 destReg) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = r[sourceReg]; + UINT16 op2 = r[destReg]; + UINT32 newValue = op2 + (0xFFFF ^ op1) + 1; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & (op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + + D = FALSE; + return 6; +} + +INT32 CP1610::ANDR(UINT16 sourceReg, UINT16 destReg) { + r[7]++; + interruptible = TRUE; + + UINT16 newValue = r[destReg] & r[sourceReg]; + S = !!(newValue & 0x8000); + Z = !newValue; + r[destReg] = newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::XORR(UINT16 sourceReg, UINT16 destReg) { + r[7]++; + interruptible = TRUE; + + UINT16 newValue = r[destReg] ^ r[sourceReg]; + S = !!(newValue & 0x8000); + Z = !newValue; + r[destReg] = newValue; + + D = FALSE; + return 6; +} + +INT32 CP1610::BEXT(UINT16 condition, INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (ext == condition) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::B(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + r[7] = (UINT16)(r[7] + displacement); + + D = FALSE; + return 9; +} + +INT32 CP1610::NOPP(INT16) { + r[7] += 2; + interruptible = TRUE; + + D = FALSE; + return 7; +} + +INT32 CP1610::BC(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (C) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BNC(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (!C) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BOV(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (O) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BNOV(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (!O) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BPL(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (!S) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BMI(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (S) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BEQ(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (Z) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BNEQ(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (!Z) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BLT(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (S != O) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BGE(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (S == O) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BLE(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (Z || (S != O)) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BGT(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (!(Z || (S != O))) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BUSC(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (C != S) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::BESC(INT16 displacement) { + r[7] += 2; + interruptible = TRUE; + + if (C == S) { + r[7] = (UINT16)(r[7] + displacement); + D = FALSE; + return 9; + } + + D = FALSE; + return 7; +} + +INT32 CP1610::MVO(UINT16 registerNum, UINT16 address) { + r[7] += 2; + interruptible = FALSE; + + memoryBus->poke(address, r[registerNum]); + + D = FALSE; + return 11; +} + +INT32 CP1610::MVO_ind(UINT16 registerWithAddress, UINT16 registerToMove) { + r[7]++; + interruptible = FALSE; + + memoryBus->poke(r[registerWithAddress], r[registerToMove]); + + //if the register number is 4-7, increment it + if (registerWithAddress & 0x04) + r[registerWithAddress]++; + + D = FALSE; + return 9; +} + +INT32 CP1610::MVI(UINT16 address, UINT16 registerNum) { + r[7] += 2; + interruptible = TRUE; + + r[registerNum] = memoryBus->peek(address); + + D = FALSE; + return 10; +} + +INT32 CP1610::MVI_ind(UINT16 registerWithAddress, UINT16 registerToReceive) { + r[7]++; + interruptible = TRUE; + + r[registerToReceive] = getIndirect(registerWithAddress); + + D = FALSE; + return (D ? 10 : (registerWithAddress == 6 ? 11 : 8)); +} + +INT32 CP1610::ADD(UINT16 address, UINT16 registerNum) { + r[7] += 2; + interruptible = TRUE; + + UINT16 op1 = memoryBus->peek(address); + UINT16 op2 = r[registerNum]; + UINT32 newValue = op1 + op2; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & ~(op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[registerNum] = (UINT16)newValue; + + D = FALSE; + return 10; +} + +INT32 CP1610::ADD_ind(UINT16 registerWithAddress, UINT16 registerToReceive) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = getIndirect(registerWithAddress); + UINT16 op2 = r[registerToReceive]; + UINT32 newValue = op1 + op2; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & ~(op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[registerToReceive] = (UINT16)newValue; + + D = FALSE; + return (D ? 10 : (registerWithAddress == 6 ? 11 : 8)); +} + +INT32 CP1610::SUB(UINT16 address, UINT16 registerNum) { + r[7] += 2; + interruptible = TRUE; + + UINT16 op1 = memoryBus->peek(address); + UINT16 op2 = r[registerNum]; + UINT32 newValue = op2 + (0xFFFF ^ op1) + 1; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & (op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[registerNum] = (UINT16)newValue; + + D = FALSE; + return 10; +} + +INT32 CP1610::SUB_ind(UINT16 registerWithAddress, UINT16 registerToReceive) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = getIndirect(registerWithAddress); + UINT16 op2 = r[registerToReceive]; + UINT32 newValue = op2 + (0xFFFF ^ op1) + 1; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & (op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + r[registerToReceive] = (UINT16)newValue; + + D = FALSE; + return (D ? 10 : (registerWithAddress == 6 ? 11 : 8)); +} + +INT32 CP1610::CMP(UINT16 address, UINT16 registerNum) { + r[7] += 2; + interruptible = TRUE; + + UINT16 op1 = memoryBus->peek(address); + UINT16 op2 = r[registerNum]; + UINT32 newValue = op2 + (0xFFFF ^ op1) + 1; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & (op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + + D = FALSE; + return 10; +} + +INT32 CP1610::CMP_ind(UINT16 registerWithAddress, UINT16 registerToReceive) { + r[7]++; + interruptible = TRUE; + + UINT16 op1 = getIndirect(registerWithAddress); + UINT16 op2 = r[registerToReceive]; + UINT32 newValue = op2 + (0xFFFF ^ op1) + 1; + C = !!(newValue & 0x10000); + O = !!((op2 ^ newValue) & (op1 ^ op2) & 0x8000); + S = !!(newValue & 0x8000); + Z = !(newValue & 0xFFFF); + + D = FALSE; + return (D ? 10 : (registerWithAddress == 6 ? 11 : 8)); +} + +INT32 CP1610::AND(UINT16 address, UINT16 registerNum) { + r[7] += 2; + interruptible = TRUE; + + UINT16 value = memoryBus->peek(address) & r[registerNum]; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 10; +} + +INT32 CP1610::AND_ind(UINT16 registerWithAddress, UINT16 registerToReceive) { + r[7]++; + interruptible = TRUE; + + UINT16 value = getIndirect(registerWithAddress) & r[registerToReceive]; + S = !!(value & 0x8000); + Z = !value; + r[registerToReceive] = value; + + D = FALSE; + return (D ? 10 : (registerWithAddress == 6 ? 11 : 8)); +} + +INT32 CP1610::XOR(UINT16 address, UINT16 registerNum) { + r[7] += 2; + interruptible = TRUE; + + UINT16 value = memoryBus->peek(address) ^ r[registerNum]; + S = !!(value & 0x8000); + Z = !value; + r[registerNum] = value; + + D = FALSE; + return 10; +} + +INT32 CP1610::XOR_ind(UINT16 registerWithAddress, UINT16 registerToReceive) { + r[7]++; + interruptible = TRUE; + + UINT16 value = getIndirect(registerWithAddress) ^ r[registerToReceive]; + S = !!(value & 0x8000); + Z = !value; + r[registerToReceive] = value; + + D = FALSE; + return (D ? 10 : (registerWithAddress == 6 ? 11 : 8)); +} + +INT32 CP1610::decode(void) +{ + switch (op & 0x3FF) { + case 0x0000: + return HLT(); + case 0x0001: + return SDBD(); + case 0x0002: + return EIS(); + case 0x0003: + return DIS(); + case 0x0004: + { + int read = memoryBus->peek((UINT16)(r[7] + 1)); + int reg = ((read & 0x0300) >> 8); + int interrupt = (read & 0x0003); + UINT16 target = (UINT16)((read & 0x00FC) << 8); + read = memoryBus->peek((UINT16)(r[7] + 2)); + target |= (UINT16)(read & 0x03FF); + if (reg == 3) { + if (interrupt == 0) + return J(target); + else if (interrupt == 1) + return JE(target); + else if (interrupt == 2) + return JD(target); + else + return HLT(); //invalid opcode + } + else { + if (interrupt == 0) + return JSR((UINT16)(reg + 4), target); + else if (interrupt == 1) + return JSRE((UINT16)(reg + 4), target); + else if (interrupt == 2) + return JSRD((UINT16)(reg + 4), target); + else + return HLT(); //invalid opcode + } + } + case 0x0005: + return TCI(); + case 0x0006: + return CLRC(); + case 0x0007: + return SETC(); + case 0x0008: + return INCR(0); + case 0x0009: + return INCR(1); + case 0x000A: + return INCR(2); + case 0x000B: + return INCR(3); + case 0x000C: + return INCR(4); + case 0x000D: + return INCR(5); + case 0x000E: + return INCR(6); + case 0x000F: + return INCR(7); + case 0x0010: + return DECR(0); + + case 0x0011: + return DECR(1); + + case 0x0012: + return DECR(2); + + case 0x0013: + return DECR(3); + + case 0x0014: + return DECR(4); + + case 0x0015: + return DECR(5); + + case 0x0016: + return DECR(6); + + case 0x0017: + return DECR(7); + + case 0x0018: + return COMR(0); + + case 0x0019: + return COMR(1); + + case 0x001A: + return COMR(2); + + case 0x001B: + return COMR(3); + + case 0x001C: + return COMR(4); + + case 0x001D: + return COMR(5); + + case 0x001E: + return COMR(6); + + case 0x001F: + return COMR(7); + + case 0x0020: + return NEGR(0); + + case 0x0021: + return NEGR(1); + + case 0x0022: + return NEGR(2); + + case 0x0023: + return NEGR(3); + + case 0x0024: + return NEGR(4); + + case 0x0025: + return NEGR(5); + + case 0x0026: + return NEGR(6); + + case 0x0027: + return NEGR(7); + + case 0x0028: + return ADCR(0); + + case 0x0029: + return ADCR(1); + + case 0x002A: + return ADCR(2); + + case 0x002B: + return ADCR(3); + + case 0x002C: + return ADCR(4); + + case 0x002D: + return ADCR(5); + + case 0x002E: + return ADCR(6); + + case 0x002F: + return ADCR(7); + + case 0x0030: + return GSWD(0); + + case 0x0031: + return GSWD(1); + + case 0x0032: + return GSWD(2); + + case 0x0033: + return GSWD(3); + + case 0x0034: + return NOP(0); + + case 0x0035: + return NOP(1); + + case 0x0036: + return SIN(0); + + case 0x0037: + return SIN(1); + + case 0x0038: + return RSWD(0); + + case 0x0039: + return RSWD(1); + + case 0x003A: + return RSWD(2); + + case 0x003B: + return RSWD(3); + + case 0x003C: + return RSWD(4); + + case 0x003D: + return RSWD(5); + + case 0x003E: + return RSWD(6); + + case 0x003F: + return RSWD(7); + + case 0x0040: + return SWAP_1(0); + + case 0x0041: + return SWAP_1(1); + + case 0x0042: + return SWAP_1(2); + + case 0x0043: + return SWAP_1(3); + + case 0x0044: + return SWAP_2(0); + + case 0x0045: + return SWAP_2(1); + + case 0x0046: + return SWAP_2(2); + + case 0x0047: + return SWAP_2(3); + + case 0x0048: + return SLL_1(0); + + case 0x0049: + return SLL_1(1); + + case 0x004A: + return SLL_1(2); + + case 0x004B: + return SLL_1(3); + + case 0x004C: + return SLL_2(0); + + case 0x004D: + return SLL_2(1); + + case 0x004E: + return SLL_2(2); + + case 0x004F: + return SLL_2(3); + + case 0x0050: + return RLC_1(0); + + case 0x0051: + return RLC_1(1); + + case 0x0052: + return RLC_1(2); + + case 0x0053: + return RLC_1(3); + + case 0x0054: + return RLC_2(0); + + case 0x0055: + return RLC_2(1); + + case 0x0056: + return RLC_2(2); + + case 0x0057: + return RLC_2(3); + + case 0x0058: + return SLLC_1(0); + + case 0x0059: + return SLLC_1(1); + + case 0x005A: + return SLLC_1(2); + + case 0x005B: + return SLLC_1(3); + + case 0x005C: + return SLLC_2(0); + + case 0x005D: + return SLLC_2(1); + + case 0x005E: + return SLLC_2(2); + + case 0x005F: + return SLLC_2(3); + + case 0x0060: + return SLR_1(0); + + case 0x0061: + return SLR_1(1); + + case 0x0062: + return SLR_1(2); + + case 0x0063: + return SLR_1(3); + + case 0x0064: + return SLR_2(0); + + case 0x0065: + return SLR_2(1); + + case 0x0066: + return SLR_2(2); + + case 0x0067: + return SLR_2(3); + + case 0x0068: + return SAR_1(0); + + case 0x0069: + return SAR_1(1); + + case 0x006A: + return SAR_1(2); + + case 0x006B: + return SAR_1(3); + + case 0x006C: + return SAR_2(0); + + case 0x006D: + return SAR_2(1); + + case 0x006E: + return SAR_2(2); + + case 0x006F: + return SAR_2(3); + + case 0x0070: + return RRC_1(0); + + case 0x0071: + return RRC_1(1); + + case 0x0072: + return RRC_1(2); + + case 0x0073: + return RRC_1(3); + + case 0x0074: + return RRC_2(0); + + case 0x0075: + return RRC_2(1); + + case 0x0076: + return RRC_2(2); + + case 0x0077: + return RRC_2(3); + + case 0x0078: + return SARC_1(0); + + case 0x0079: + return SARC_1(1); + + case 0x007A: + return SARC_1(2); + + case 0x007B: + return SARC_1(3); + + case 0x007C: + return SARC_2(0); + + case 0x007D: + return SARC_2(1); + + case 0x007E: + return SARC_2(2); + + case 0x007F: + return SARC_2(3); + + case 0x0080: + return MOVR(0, 0); + + case 0x0081: + return MOVR(0, 1); + + case 0x0082: + return MOVR(0, 2); + + case 0x0083: + return MOVR(0, 3); + + case 0x0084: + return MOVR(0, 4); + + case 0x0085: + return MOVR(0, 5); + + case 0x0086: + return MOVR(0, 6); + + case 0x0087: + return MOVR(0, 7); + + case 0x0088: + return MOVR(1, 0); + + case 0x0089: + return MOVR(1, 1); + + case 0x008A: + return MOVR(1, 2); + + case 0x008B: + return MOVR(1, 3); + + case 0x008C: + return MOVR(1, 4); + + case 0x008D: + return MOVR(1, 5); + + case 0x008E: + return MOVR(1, 6); + + case 0x008F: + return MOVR(1, 7); + + case 0x0090: + return MOVR(2, 0); + + case 0x0091: + return MOVR(2, 1); + + case 0x0092: + return MOVR(2, 2); + + case 0x0093: + return MOVR(2, 3); + + case 0x0094: + return MOVR(2, 4); + + case 0x0095: + return MOVR(2, 5); + + case 0x0096: + return MOVR(2, 6); + + case 0x0097: + return MOVR(2, 7); + + case 0x0098: + return MOVR(3, 0); + + case 0x0099: + return MOVR(3, 1); + + case 0x009A: + return MOVR(3, 2); + + case 0x009B: + return MOVR(3, 3); + + case 0x009C: + return MOVR(3, 4); + + case 0x009D: + return MOVR(3, 5); + + case 0x009E: + return MOVR(3, 6); + + case 0x009F: + return MOVR(3, 7); + + case 0x00A0: + return MOVR(4, 0); + + case 0x00A1: + return MOVR(4, 1); + + case 0x00A2: + return MOVR(4, 2); + + case 0x00A3: + return MOVR(4, 3); + + case 0x00A4: + return MOVR(4, 4); + + case 0x00A5: + return MOVR(4, 5); + + case 0x00A6: + return MOVR(4, 6); + + case 0x00A7: + return MOVR(4, 7); + + case 0x00A8: + return MOVR(5, 0); + + case 0x00A9: + return MOVR(5, 1); + + case 0x00AA: + return MOVR(5, 2); + + case 0x00AB: + return MOVR(5, 3); + + case 0x00AC: + return MOVR(5, 4); + + case 0x00AD: + return MOVR(5, 5); + + case 0x00AE: + return MOVR(5, 6); + + case 0x00AF: + return MOVR(5, 7); + + case 0x00B0: + return MOVR(6, 0); + + case 0x00B1: + return MOVR(6, 1); + + case 0x00B2: + return MOVR(6, 2); + + case 0x00B3: + return MOVR(6, 3); + + case 0x00B4: + return MOVR(6, 4); + + case 0x00B5: + return MOVR(6, 5); + + case 0x00B6: + return MOVR(6, 6); + + case 0x00B7: + return MOVR(6, 7); + + case 0x00B8: + return MOVR(7, 0); + + case 0x00B9: + return MOVR(7, 1); + + case 0x00BA: + return MOVR(7, 2); + + case 0x00BB: + return MOVR(7, 3); + + case 0x00BC: + return MOVR(7, 4); + + case 0x00BD: + return MOVR(7, 5); + + case 0x00BE: + return MOVR(7, 6); + + case 0x00BF: + return MOVR(7, 7); + + case 0x00C0: + return ADDR(0, 0); + + case 0x00C1: + return ADDR(0, 1); + + case 0x00C2: + return ADDR(0, 2); + + case 0x00C3: + return ADDR(0, 3); + + case 0x00C4: + return ADDR(0, 4); + + case 0x00C5: + return ADDR(0, 5); + + case 0x00C6: + return ADDR(0, 6); + + case 0x00C7: + return ADDR(0, 7); + + case 0x00C8: + return ADDR(1, 0); + + case 0x00C9: + return ADDR(1, 1); + + case 0x00CA: + return ADDR(1, 2); + + case 0x00CB: + return ADDR(1, 3); + + case 0x00CC: + return ADDR(1, 4); + + case 0x00CD: + return ADDR(1, 5); + + case 0x00CE: + return ADDR(1, 6); + + case 0x00CF: + return ADDR(1, 7); + + case 0x00D0: + return ADDR(2, 0); + + case 0x00D1: + return ADDR(2, 1); + + case 0x00D2: + return ADDR(2, 2); + + case 0x00D3: + return ADDR(2, 3); + + case 0x00D4: + return ADDR(2, 4); + + case 0x00D5: + return ADDR(2, 5); + + case 0x00D6: + return ADDR(2, 6); + + case 0x00D7: + return ADDR(2, 7); + + case 0x00D8: + return ADDR(3, 0); + + case 0x00D9: + return ADDR(3, 1); + + case 0x00DA: + return ADDR(3, 2); + + case 0x00DB: + return ADDR(3, 3); + + case 0x00DC: + return ADDR(3, 4); + + case 0x00DD: + return ADDR(3, 5); + + case 0x00DE: + return ADDR(3, 6); + + case 0x00DF: + return ADDR(3, 7); + + case 0x00E0: + return ADDR(4, 0); + + case 0x00E1: + return ADDR(4, 1); + + case 0x00E2: + return ADDR(4, 2); + + case 0x00E3: + return ADDR(4, 3); + + case 0x00E4: + return ADDR(4, 4); + + case 0x00E5: + return ADDR(4, 5); + + case 0x00E6: + return ADDR(4, 6); + + case 0x00E7: + return ADDR(4, 7); + + case 0x00E8: + return ADDR(5, 0); + + case 0x00E9: + return ADDR(5, 1); + + case 0x00EA: + return ADDR(5, 2); + + case 0x00EB: + return ADDR(5, 3); + + case 0x00EC: + return ADDR(5, 4); + + case 0x00ED: + return ADDR(5, 5); + + case 0x00EE: + return ADDR(5, 6); + + case 0x00EF: + return ADDR(5, 7); + + case 0x00F0: + return ADDR(6, 0); + + case 0x00F1: + return ADDR(6, 1); + + case 0x00F2: + return ADDR(6, 2); + + case 0x00F3: + return ADDR(6, 3); + + case 0x00F4: + return ADDR(6, 4); + + case 0x00F5: + return ADDR(6, 5); + + case 0x00F6: + return ADDR(6, 6); + + case 0x00F7: + return ADDR(6, 7); + + case 0x00F8: + return ADDR(7, 0); + + case 0x00F9: + return ADDR(7, 1); + + case 0x00FA: + return ADDR(7, 2); + + case 0x00FB: + return ADDR(7, 3); + + case 0x00FC: + return ADDR(7, 4); + + case 0x00FD: + return ADDR(7, 5); + + case 0x00FE: + return ADDR(7, 6); + + case 0x00FF: + return ADDR(7, 7); + + case 0x0100: + return SUBR(0, 0); + + case 0x0101: + return SUBR(0, 1); + + case 0x0102: + return SUBR(0, 2); + + case 0x0103: + return SUBR(0, 3); + + case 0x0104: + return SUBR(0, 4); + + case 0x0105: + return SUBR(0, 5); + + case 0x0106: + return SUBR(0, 6); + + case 0x0107: + return SUBR(0, 7); + + case 0x0108: + return SUBR(1, 0); + + case 0x0109: + return SUBR(1, 1); + + case 0x010A: + return SUBR(1, 2); + + case 0x010B: + return SUBR(1, 3); + + case 0x010C: + return SUBR(1, 4); + + case 0x010D: + return SUBR(1, 5); + + case 0x010E: + return SUBR(1, 6); + + case 0x010F: + return SUBR(1, 7); + + case 0x0110: + return SUBR(2, 0); + + case 0x0111: + return SUBR(2, 1); + + case 0x0112: + return SUBR(2, 2); + + case 0x0113: + return SUBR(2, 3); + + case 0x0114: + return SUBR(2, 4); + + case 0x0115: + return SUBR(2, 5); + + case 0x0116: + return SUBR(2, 6); + + case 0x0117: + return SUBR(2, 7); + + case 0x0118: + return SUBR(3, 0); + + case 0x0119: + return SUBR(3, 1); + + case 0x011A: + return SUBR(3, 2); + + case 0x011B: + return SUBR(3, 3); + + case 0x011C: + return SUBR(3, 4); + + case 0x011D: + return SUBR(3, 5); + + case 0x011E: + return SUBR(3, 6); + + case 0x011F: + return SUBR(3, 7); + + case 0x0120: + return SUBR(4, 0); + + case 0x0121: + return SUBR(4, 1); + + case 0x0122: + return SUBR(4, 2); + + case 0x0123: + return SUBR(4, 3); + + case 0x0124: + return SUBR(4, 4); + + case 0x0125: + return SUBR(4, 5); + + case 0x0126: + return SUBR(4, 6); + + case 0x0127: + return SUBR(4, 7); + + case 0x0128: + return SUBR(5, 0); + + case 0x0129: + return SUBR(5, 1); + + case 0x012A: + return SUBR(5, 2); + + case 0x012B: + return SUBR(5, 3); + + case 0x012C: + return SUBR(5, 4); + + case 0x012D: + return SUBR(5, 5); + + case 0x012E: + return SUBR(5, 6); + + case 0x012F: + return SUBR(5, 7); + + case 0x0130: + return SUBR(6, 0); + + case 0x0131: + return SUBR(6, 1); + + case 0x0132: + return SUBR(6, 2); + + case 0x0133: + return SUBR(6, 3); + + case 0x0134: + return SUBR(6, 4); + + case 0x0135: + return SUBR(6, 5); + + case 0x0136: + return SUBR(6, 6); + + case 0x0137: + return SUBR(6, 7); + + case 0x0138: + return SUBR(7, 0); + + case 0x0139: + return SUBR(7, 1); + + case 0x013A: + return SUBR(7, 2); + + case 0x013B: + return SUBR(7, 3); + + case 0x013C: + return SUBR(7, 4); + + case 0x013D: + return SUBR(7, 5); + + case 0x013E: + return SUBR(7, 6); + + case 0x013F: + return SUBR(7, 7); + + case 0x0140: + return CMPR(0, 0); + + case 0x0141: + return CMPR(0, 1); + + case 0x0142: + return CMPR(0, 2); + + case 0x0143: + return CMPR(0, 3); + + case 0x0144: + return CMPR(0, 4); + + case 0x0145: + return CMPR(0, 5); + + case 0x0146: + return CMPR(0, 6); + + case 0x0147: + return CMPR(0, 7); + + case 0x0148: + return CMPR(1, 0); + + case 0x0149: + return CMPR(1, 1); + + case 0x014A: + return CMPR(1, 2); + + case 0x014B: + return CMPR(1, 3); + + case 0x014C: + return CMPR(1, 4); + + case 0x014D: + return CMPR(1, 5); + + case 0x014E: + return CMPR(1, 6); + + case 0x014F: + return CMPR(1, 7); + + case 0x0150: + return CMPR(2, 0); + + case 0x0151: + return CMPR(2, 1); + + case 0x0152: + return CMPR(2, 2); + + case 0x0153: + return CMPR(2, 3); + + case 0x0154: + return CMPR(2, 4); + + case 0x0155: + return CMPR(2, 5); + + case 0x0156: + return CMPR(2, 6); + + case 0x0157: + return CMPR(2, 7); + + case 0x0158: + return CMPR(3, 0); + + case 0x0159: + return CMPR(3, 1); + + case 0x015A: + return CMPR(3, 2); + + case 0x015B: + return CMPR(3, 3); + + case 0x015C: + return CMPR(3, 4); + + case 0x015D: + return CMPR(3, 5); + + case 0x015E: + return CMPR(3, 6); + + case 0x015F: + return CMPR(3, 7); + + case 0x0160: + return CMPR(4, 0); + + case 0x0161: + return CMPR(4, 1); + + case 0x0162: + return CMPR(4, 2); + + case 0x0163: + return CMPR(4, 3); + + case 0x0164: + return CMPR(4, 4); + + case 0x0165: + return CMPR(4, 5); + + case 0x0166: + return CMPR(4, 6); + + case 0x0167: + return CMPR(4, 7); + + case 0x0168: + return CMPR(5, 0); + + case 0x0169: + return CMPR(5, 1); + + case 0x016A: + return CMPR(5, 2); + + case 0x016B: + return CMPR(5, 3); + + case 0x016C: + return CMPR(5, 4); + + case 0x016D: + return CMPR(5, 5); + + case 0x016E: + return CMPR(5, 6); + + case 0x016F: + return CMPR(5, 7); + + case 0x0170: + return CMPR(6, 0); + + case 0x0171: + return CMPR(6, 1); + + case 0x0172: + return CMPR(6, 2); + + case 0x0173: + return CMPR(6, 3); + + case 0x0174: + return CMPR(6, 4); + + case 0x0175: + return CMPR(6, 5); + + case 0x0176: + return CMPR(6, 6); + + case 0x0177: + return CMPR(6, 7); + + case 0x0178: + return CMPR(7, 0); + + case 0x0179: + return CMPR(7, 1); + + case 0x017A: + return CMPR(7, 2); + + case 0x017B: + return CMPR(7, 3); + + case 0x017C: + return CMPR(7, 4); + + case 0x017D: + return CMPR(7, 5); + + case 0x017E: + return CMPR(7, 6); + + case 0x017F: + return CMPR(7, 7); + + case 0x0180: + return ANDR(0, 0); + + case 0x0181: + return ANDR(0, 1); + + case 0x0182: + return ANDR(0, 2); + + case 0x0183: + return ANDR(0, 3); + + case 0x0184: + return ANDR(0, 4); + + case 0x0185: + return ANDR(0, 5); + + case 0x0186: + return ANDR(0, 6); + + case 0x0187: + return ANDR(0, 7); + + case 0x0188: + return ANDR(1, 0); + + case 0x0189: + return ANDR(1, 1); + + case 0x018A: + return ANDR(1, 2); + + case 0x018B: + return ANDR(1, 3); + + case 0x018C: + return ANDR(1, 4); + + case 0x018D: + return ANDR(1, 5); + + case 0x018E: + return ANDR(1, 6); + + case 0x018F: + return ANDR(1, 7); + + case 0x0190: + return ANDR(2, 0); + + case 0x0191: + return ANDR(2, 1); + + case 0x0192: + return ANDR(2, 2); + + case 0x0193: + return ANDR(2, 3); + + case 0x0194: + return ANDR(2, 4); + + case 0x0195: + return ANDR(2, 5); + + case 0x0196: + return ANDR(2, 6); + + case 0x0197: + return ANDR(2, 7); + + case 0x0198: + return ANDR(3, 0); + + case 0x0199: + return ANDR(3, 1); + + case 0x019A: + return ANDR(3, 2); + + case 0x019B: + return ANDR(3, 3); + + case 0x019C: + return ANDR(3, 4); + + case 0x019D: + return ANDR(3, 5); + + case 0x019E: + return ANDR(3, 6); + + case 0x019F: + return ANDR(3, 7); + + case 0x01A0: + return ANDR(4, 0); + + case 0x01A1: + return ANDR(4, 1); + + case 0x01A2: + return ANDR(4, 2); + + case 0x01A3: + return ANDR(4, 3); + + case 0x01A4: + return ANDR(4, 4); + + case 0x01A5: + return ANDR(4, 5); + + case 0x01A6: + return ANDR(4, 6); + + case 0x01A7: + return ANDR(4, 7); + + case 0x01A8: + return ANDR(5, 0); + + case 0x01A9: + return ANDR(5, 1); + + case 0x01AA: + return ANDR(5, 2); + + case 0x01AB: + return ANDR(5, 3); + + case 0x01AC: + return ANDR(5, 4); + + case 0x01AD: + return ANDR(5, 5); + + case 0x01AE: + return ANDR(5, 6); + + case 0x01AF: + return ANDR(5, 7); + + case 0x01B0: + return ANDR(6, 0); + + case 0x01B1: + return ANDR(6, 1); + + case 0x01B2: + return ANDR(6, 2); + + case 0x01B3: + return ANDR(6, 3); + + case 0x01B4: + return ANDR(6, 4); + + case 0x01B5: + return ANDR(6, 5); + + case 0x01B6: + return ANDR(6, 6); + + case 0x01B7: + return ANDR(6, 7); + + case 0x01B8: + return ANDR(7, 0); + + case 0x01B9: + return ANDR(7, 1); + + case 0x01BA: + return ANDR(7, 2); + + case 0x01BB: + return ANDR(7, 3); + + case 0x01BC: + return ANDR(7, 4); + + case 0x01BD: + return ANDR(7, 5); + + case 0x01BE: + return ANDR(7, 6); + + case 0x01BF: + return ANDR(7, 7); + + case 0x01C0: + return XORR(0, 0); + + case 0x01C1: + return XORR(0, 1); + + case 0x01C2: + return XORR(0, 2); + + case 0x01C3: + return XORR(0, 3); + + case 0x01C4: + return XORR(0, 4); + + case 0x01C5: + return XORR(0, 5); + + case 0x01C6: + return XORR(0, 6); + + case 0x01C7: + return XORR(0, 7); + + case 0x01C8: + return XORR(1, 0); + + case 0x01C9: + return XORR(1, 1); + + case 0x01CA: + return XORR(1, 2); + + case 0x01CB: + return XORR(1, 3); + + case 0x01CC: + return XORR(1, 4); + + case 0x01CD: + return XORR(1, 5); + + case 0x01CE: + return XORR(1, 6); + + case 0x01CF: + return XORR(1, 7); + + case 0x01D0: + return XORR(2, 0); + + case 0x01D1: + return XORR(2, 1); + + case 0x01D2: + return XORR(2, 2); + + case 0x01D3: + return XORR(2, 3); + + case 0x01D4: + return XORR(2, 4); + + case 0x01D5: + return XORR(2, 5); + + case 0x01D6: + return XORR(2, 6); + + case 0x01D7: + return XORR(2, 7); + + case 0x01D8: + return XORR(3, 0); + + case 0x01D9: + return XORR(3, 1); + + case 0x01DA: + return XORR(3, 2); + + case 0x01DB: + return XORR(3, 3); + + case 0x01DC: + return XORR(3, 4); + + case 0x01DD: + return XORR(3, 5); + + case 0x01DE: + return XORR(3, 6); + + case 0x01DF: + return XORR(3, 7); + + case 0x01E0: + return XORR(4, 0); + + case 0x01E1: + return XORR(4, 1); + + case 0x01E2: + return XORR(4, 2); + + case 0x01E3: + return XORR(4, 3); + + case 0x01E4: + return XORR(4, 4); + + case 0x01E5: + return XORR(4, 5); + + case 0x01E6: + return XORR(4, 6); + + case 0x01E7: + return XORR(4, 7); + + case 0x01E8: + return XORR(5, 0); + + case 0x01E9: + return XORR(5, 1); + + case 0x01EA: + return XORR(5, 2); + + case 0x01EB: + return XORR(5, 3); + + case 0x01EC: + return XORR(5, 4); + + case 0x01ED: + return XORR(5, 5); + + case 0x01EE: + return XORR(5, 6); + + case 0x01EF: + return XORR(5, 7); + + case 0x01F0: + return XORR(6, 0); + + case 0x01F1: + return XORR(6, 1); + + case 0x01F2: + return XORR(6, 2); + + case 0x01F3: + return XORR(6, 3); + + case 0x01F4: + return XORR(6, 4); + + case 0x01F5: + return XORR(6, 5); + + case 0x01F6: + return XORR(6, 6); + + case 0x01F7: + return XORR(6, 7); + + case 0x01F8: + return XORR(7, 0); + + case 0x01F9: + return XORR(7, 1); + + case 0x01FA: + return XORR(7, 2); + + case 0x01FB: + return XORR(7, 3); + + case 0x01FC: + return XORR(7, 4); + + case 0x01FD: + return XORR(7, 5); + + case 0x01FE: + return XORR(7, 6); + + case 0x01FF: + return XORR(7, 7); + + case 0x0200: + return B(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0201: + return BC(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0202: + return BOV(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0203: + return BPL(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0204: + return BEQ(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0205: + return BLT(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0206: + return BLE(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0207: + return BUSC(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0208: + return NOPP(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0209: + return BNC(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x020A: + return BNOV(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x020B: + return BMI(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x020C: + return BNEQ(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x020D: + return BGE(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x020E: + return BGT(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x020F: + return BESC(memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0210: + return BEXT(0, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0211: + return BEXT(1, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0212: + return BEXT(2, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0213: + return BEXT(3, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0214: + return BEXT(4, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0215: + return BEXT(5, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0216: + return BEXT(6, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0217: + return BEXT(7, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0218: + return BEXT(8, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0219: + return BEXT(9, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x021A: + return BEXT(10, + memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x021B: + return BEXT(11, + memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x021C: + return BEXT(12, + memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x021D: + return BEXT(13, + memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x021E: + return BEXT(14, + memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x021F: + return BEXT(15, + memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0220: + return B(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0221: + return BC(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0222: + return BOV(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0223: + return BPL(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0224: + return BEQ(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0225: + return BLT(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0226: + return BLE(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0227: + return BUSC(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0228: + return NOPP(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0229: + return BNC(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x022A: + return BNOV(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x022B: + return BMI(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x022C: + return BNEQ(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x022D: + return BGE(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x022E: + return BGT(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x022F: + return BESC(-memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0230: + return BEXT(0, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0231: + return BEXT(1, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0232: + return BEXT(2, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0233: + return BEXT(3, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0234: + return BEXT(4, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0235: + return BEXT(5, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0236: + return BEXT(6, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0237: + return BEXT(7, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0238: + return BEXT(8, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0239: + return BEXT(9, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x023A: + return BEXT(10, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x023B: + return BEXT(11, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x023C: + return BEXT(12, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x023D: + return BEXT(13, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x023E: + return BEXT(14, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x023F: + return BEXT(15, + -memoryBus->peek((UINT16)(r[7] + 1)) - 1); + + case 0x0240: + return MVO(0, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0241: + return MVO(1, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0242: + return MVO(2, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0243: + return MVO(3, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0244: + return MVO(4, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0245: + return MVO(5, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0246: + return MVO(6, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0247: + return MVO(7, memoryBus->peek((UINT16)(r[7] + 1))); + + case 0x0248: + return MVO_ind(1, 0); + + case 0x0249: + return MVO_ind(1, 1); + + case 0x024A: + return MVO_ind(1, 2); + + case 0x024B: + return MVO_ind(1, 3); + + case 0x024C: + return MVO_ind(1, 4); + + case 0x024D: + return MVO_ind(1, 5); + + case 0x024E: + return MVO_ind(1, 6); + + case 0x024F: + return MVO_ind(1, 7); + + case 0x0250: + return MVO_ind(2, 0); + + case 0x0251: + return MVO_ind(2, 1); + + case 0x0252: + return MVO_ind(2, 2); + + case 0x0253: + return MVO_ind(2, 3); + + case 0x0254: + return MVO_ind(2, 4); + + case 0x0255: + return MVO_ind(2, 5); + + case 0x0256: + return MVO_ind(2, 6); + + case 0x0257: + return MVO_ind(2, 7); + + case 0x0258: + return MVO_ind(3, 0); + + case 0x0259: + return MVO_ind(3, 1); + + case 0x025A: + return MVO_ind(3, 2); + + case 0x025B: + return MVO_ind(3, 3); + + case 0x025C: + return MVO_ind(3, 4); + + case 0x025D: + return MVO_ind(3, 5); + + case 0x025E: + return MVO_ind(3, 6); + + case 0x025F: + return MVO_ind(3, 7); + + case 0x0260: + return MVO_ind(4, 0); + + case 0x0261: + return MVO_ind(4, 1); + + case 0x0262: + return MVO_ind(4, 2); + + case 0x0263: + return MVO_ind(4, 3); + + case 0x0264: + return MVO_ind(4, 4); + + case 0x0265: + return MVO_ind(4, 5); + + case 0x0266: + return MVO_ind(4, 6); + + case 0x0267: + return MVO_ind(4, 7); + + case 0x0268: + return MVO_ind(5, 0); + + case 0x0269: + return MVO_ind(5, 1); + + case 0x026A: + return MVO_ind(5, 2); + + case 0x026B: + return MVO_ind(5, 3); + + case 0x026C: + return MVO_ind(5, 4); + + case 0x026D: + return MVO_ind(5, 5); + + case 0x026E: + return MVO_ind(5, 6); + + case 0x026F: + return MVO_ind(5, 7); + + case 0x0270: + return MVO_ind(6, 0); + + case 0x0271: + return MVO_ind(6, 1); + + case 0x0272: + return MVO_ind(6, 2); + + case 0x0273: + return MVO_ind(6, 3); + + case 0x0274: + return MVO_ind(6, 4); + + case 0x0275: + return MVO_ind(6, 5); + + case 0x0276: + return MVO_ind(6, 6); + + case 0x0277: + return MVO_ind(6, 7); + + case 0x0278: + return MVO_ind(7, 0); + + case 0x0279: + return MVO_ind(7, 1); + + case 0x027A: + return MVO_ind(7, 2); + + case 0x027B: + return MVO_ind(7, 3); + + case 0x027C: + return MVO_ind(7, 4); + + case 0x027D: + return MVO_ind(7, 5); + + case 0x027E: + return MVO_ind(7, 6); + + case 0x027F: + return MVO_ind(7, 7); + + case 0x0280: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 0); + + case 0x0281: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 1); + + case 0x0282: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 2); + + case 0x0283: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 3); + + case 0x0284: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 4); + + case 0x0285: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 5); + + case 0x0286: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 6); + + case 0x0287: + return MVI(memoryBus->peek((UINT16)(r[7] + 1)), 7); + + case 0x0288: + return MVI_ind(1, 0); + + case 0x0289: + return MVI_ind(1, 1); + + case 0x028A: + return MVI_ind(1, 2); + + case 0x028B: + return MVI_ind(1, 3); + + case 0x028C: + return MVI_ind(1, 4); + + case 0x028D: + return MVI_ind(1, 5); + + case 0x028E: + return MVI_ind(1, 6); + + case 0x028F: + return MVI_ind(1, 7); + + case 0x0290: + return MVI_ind(2, 0); + + case 0x0291: + return MVI_ind(2, 1); + + case 0x0292: + return MVI_ind(2, 2); + + case 0x0293: + return MVI_ind(2, 3); + + case 0x0294: + return MVI_ind(2, 4); + + case 0x0295: + return MVI_ind(2, 5); + + case 0x0296: + return MVI_ind(2, 6); + + case 0x0297: + return MVI_ind(2, 7); + + case 0x0298: + return MVI_ind(3, 0); + + case 0x0299: + return MVI_ind(3, 1); + + case 0x029A: + return MVI_ind(3, 2); + + case 0x029B: + return MVI_ind(3, 3); + + case 0x029C: + return MVI_ind(3, 4); + + case 0x029D: + return MVI_ind(3, 5); + + case 0x029E: + return MVI_ind(3, 6); + + case 0x029F: + return MVI_ind(3, 7); + + case 0x02A0: + return MVI_ind(4, 0); + + case 0x02A1: + return MVI_ind(4, 1); + + case 0x02A2: + return MVI_ind(4, 2); + + case 0x02A3: + return MVI_ind(4, 3); + + case 0x02A4: + return MVI_ind(4, 4); + + case 0x02A5: + return MVI_ind(4, 5); + + case 0x02A6: + return MVI_ind(4, 6); + + case 0x02A7: + return MVI_ind(4, 7); + + case 0x02A8: + return MVI_ind(5, 0); + + case 0x02A9: + return MVI_ind(5, 1); + + case 0x02AA: + return MVI_ind(5, 2); + + case 0x02AB: + return MVI_ind(5, 3); + + case 0x02AC: + return MVI_ind(5, 4); + + case 0x02AD: + return MVI_ind(5, 5); + + case 0x02AE: + return MVI_ind(5, 6); + + case 0x02AF: + return MVI_ind(5, 7); + + case 0x02B0: + return MVI_ind(6, 0); + + case 0x02B1: + return MVI_ind(6, 1); + + case 0x02B2: + return MVI_ind(6, 2); + + case 0x02B3: + return MVI_ind(6, 3); + + case 0x02B4: + return MVI_ind(6, 4); + + case 0x02B5: + return MVI_ind(6, 5); + + case 0x02B6: + return MVI_ind(6, 6); + + case 0x02B7: + return MVI_ind(6, 7); + + case 0x02B8: + return MVI_ind(7, 0); + + case 0x02B9: + return MVI_ind(7, 1); + + case 0x02BA: + return MVI_ind(7, 2); + + case 0x02BB: + return MVI_ind(7, 3); + + case 0x02BC: + return MVI_ind(7, 4); + + case 0x02BD: + return MVI_ind(7, 5); + + case 0x02BE: + return MVI_ind(7, 6); + + case 0x02BF: + return MVI_ind(7, 7); + + case 0x02C0: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 0); + + case 0x02C1: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 1); + + case 0x02C2: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 2); + + case 0x02C3: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 3); + + case 0x02C4: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 4); + + case 0x02C5: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 5); + + case 0x02C6: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 6); + + case 0x02C7: + return ADD(memoryBus->peek((UINT16)(r[7] + 1)), 7); + + case 0x02C8: + return ADD_ind(1, 0); + + case 0x02C9: + return ADD_ind(1, 1); + + case 0x02CA: + return ADD_ind(1, 2); + + case 0x02CB: + return ADD_ind(1, 3); + + case 0x02CC: + return ADD_ind(1, 4); + + case 0x02CD: + return ADD_ind(1, 5); + + case 0x02CE: + return ADD_ind(1, 6); + + case 0x02CF: + return ADD_ind(1, 7); + + case 0x02D0: + return ADD_ind(2, 0); + + case 0x02D1: + return ADD_ind(2, 1); + + case 0x02D2: + return ADD_ind(2, 2); + + case 0x02D3: + return ADD_ind(2, 3); + + case 0x02D4: + return ADD_ind(2, 4); + + case 0x02D5: + return ADD_ind(2, 5); + + case 0x02D6: + return ADD_ind(2, 6); + + case 0x02D7: + return ADD_ind(2, 7); + + case 0x02D8: + return ADD_ind(3, 0); + + case 0x02D9: + return ADD_ind(3, 1); + + case 0x02DA: + return ADD_ind(3, 2); + + case 0x02DB: + return ADD_ind(3, 3); + + case 0x02DC: + return ADD_ind(3, 4); + + case 0x02DD: + return ADD_ind(3, 5); + + case 0x02DE: + return ADD_ind(3, 6); + + case 0x02DF: + return ADD_ind(3, 7); + + case 0x02E0: + return ADD_ind(4, 0); + + case 0x02E1: + return ADD_ind(4, 1); + + case 0x02E2: + return ADD_ind(4, 2); + + case 0x02E3: + return ADD_ind(4, 3); + + case 0x02E4: + return ADD_ind(4, 4); + + case 0x02E5: + return ADD_ind(4, 5); + + case 0x02E6: + return ADD_ind(4, 6); + + case 0x02E7: + return ADD_ind(4, 7); + + case 0x02E8: + return ADD_ind(5, 0); + + case 0x02E9: + return ADD_ind(5, 1); + + case 0x02EA: + return ADD_ind(5, 2); + + case 0x02EB: + return ADD_ind(5, 3); + + case 0x02EC: + return ADD_ind(5, 4); + + case 0x02ED: + return ADD_ind(5, 5); + + case 0x02EE: + return ADD_ind(5, 6); + + case 0x02EF: + return ADD_ind(5, 7); + + case 0x02F0: + return ADD_ind(6, 0); + + case 0x02F1: + return ADD_ind(6, 1); + + case 0x02F2: + return ADD_ind(6, 2); + + case 0x02F3: + return ADD_ind(6, 3); + + case 0x02F4: + return ADD_ind(6, 4); + + case 0x02F5: + return ADD_ind(6, 5); + + case 0x02F6: + return ADD_ind(6, 6); + + case 0x02F7: + return ADD_ind(6, 7); + + case 0x02F8: + return ADD_ind(7, 0); + + case 0x02F9: + return ADD_ind(7, 1); + + case 0x02FA: + return ADD_ind(7, 2); + + case 0x02FB: + return ADD_ind(7, 3); + + case 0x02FC: + return ADD_ind(7, 4); + + case 0x02FD: + return ADD_ind(7, 5); + + case 0x02FE: + return ADD_ind(7, 6); + + case 0x02FF: + return ADD_ind(7, 7); + + case 0x0300: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 0); + + case 0x0301: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 1); + + case 0x0302: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 2); + + case 0x0303: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 3); + + case 0x0304: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 4); + + case 0x0305: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 5); + + case 0x0306: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 6); + + case 0x0307: + return SUB(memoryBus->peek((UINT16)(r[7] + 1)), 7); + + case 0x0308: + return SUB_ind(1, 0); + + case 0x0309: + return SUB_ind(1, 1); + + case 0x030A: + return SUB_ind(1, 2); + + case 0x030B: + return SUB_ind(1, 3); + + case 0x030C: + return SUB_ind(1, 4); + + case 0x030D: + return SUB_ind(1, 5); + + case 0x030E: + return SUB_ind(1, 6); + + case 0x030F: + return SUB_ind(1, 7); + + case 0x0310: + return SUB_ind(2, 0); + + case 0x0311: + return SUB_ind(2, 1); + + case 0x0312: + return SUB_ind(2, 2); + + case 0x0313: + return SUB_ind(2, 3); + + case 0x0314: + return SUB_ind(2, 4); + + case 0x0315: + return SUB_ind(2, 5); + + case 0x0316: + return SUB_ind(2, 6); + + case 0x0317: + return SUB_ind(2, 7); + + case 0x0318: + return SUB_ind(3, 0); + + case 0x0319: + return SUB_ind(3, 1); + + case 0x031A: + return SUB_ind(3, 2); + + case 0x031B: + return SUB_ind(3, 3); + + case 0x031C: + return SUB_ind(3, 4); + + case 0x031D: + return SUB_ind(3, 5); + + case 0x031E: + return SUB_ind(3, 6); + + case 0x031F: + return SUB_ind(3, 7); + + case 0x0320: + return SUB_ind(4, 0); + + case 0x0321: + return SUB_ind(4, 1); + + case 0x0322: + return SUB_ind(4, 2); + + case 0x0323: + return SUB_ind(4, 3); + + case 0x0324: + return SUB_ind(4, 4); + + case 0x0325: + return SUB_ind(4, 5); + + case 0x0326: + return SUB_ind(4, 6); + + case 0x0327: + return SUB_ind(4, 7); + + case 0x0328: + return SUB_ind(5, 0); + + case 0x0329: + return SUB_ind(5, 1); + + case 0x032A: + return SUB_ind(5, 2); + + case 0x032B: + return SUB_ind(5, 3); + + case 0x032C: + return SUB_ind(5, 4); + + case 0x032D: + return SUB_ind(5, 5); + + case 0x032E: + return SUB_ind(5, 6); + + case 0x032F: + return SUB_ind(5, 7); + + case 0x0330: + return SUB_ind(6, 0); + + case 0x0331: + return SUB_ind(6, 1); + + case 0x0332: + return SUB_ind(6, 2); + + case 0x0333: + return SUB_ind(6, 3); + + case 0x0334: + return SUB_ind(6, 4); + + case 0x0335: + return SUB_ind(6, 5); + + case 0x0336: + return SUB_ind(6, 6); + + case 0x0337: + return SUB_ind(6, 7); + + case 0x0338: + return SUB_ind(7, 0); + + case 0x0339: + return SUB_ind(7, 1); + + case 0x033A: + return SUB_ind(7, 2); + + case 0x033B: + return SUB_ind(7, 3); + + case 0x033C: + return SUB_ind(7, 4); + + case 0x033D: + return SUB_ind(7, 5); + + case 0x033E: + return SUB_ind(7, 6); + + case 0x033F: + return SUB_ind(7, 7); + + case 0x0340: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 0); + + case 0x0341: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 1); + + case 0x0342: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 2); + + case 0x0343: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 3); + + case 0x0344: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 4); + + case 0x0345: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 5); + + case 0x0346: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 6); + + case 0x0347: + return CMP(memoryBus->peek((UINT16)(r[7] + 1)), 7); + + case 0x0348: + return CMP_ind(1, 0); + + case 0x0349: + return CMP_ind(1, 1); + + case 0x034A: + return CMP_ind(1, 2); + + case 0x034B: + return CMP_ind(1, 3); + + case 0x034C: + return CMP_ind(1, 4); + + case 0x034D: + return CMP_ind(1, 5); + + case 0x034E: + return CMP_ind(1, 6); + + case 0x034F: + return CMP_ind(1, 7); + + case 0x0350: + return CMP_ind(2, 0); + + case 0x0351: + return CMP_ind(2, 1); + + case 0x0352: + return CMP_ind(2, 2); + + case 0x0353: + return CMP_ind(2, 3); + + case 0x0354: + return CMP_ind(2, 4); + + case 0x0355: + return CMP_ind(2, 5); + + case 0x0356: + return CMP_ind(2, 6); + + case 0x0357: + return CMP_ind(2, 7); + + case 0x0358: + return CMP_ind(3, 0); + + case 0x0359: + return CMP_ind(3, 1); + + case 0x035A: + return CMP_ind(3, 2); + + case 0x035B: + return CMP_ind(3, 3); + + case 0x035C: + return CMP_ind(3, 4); + + case 0x035D: + return CMP_ind(3, 5); + + case 0x035E: + return CMP_ind(3, 6); + + case 0x035F: + return CMP_ind(3, 7); + + case 0x0360: + return CMP_ind(4, 0); + + case 0x0361: + return CMP_ind(4, 1); + + case 0x0362: + return CMP_ind(4, 2); + + case 0x0363: + return CMP_ind(4, 3); + + case 0x0364: + return CMP_ind(4, 4); + + case 0x0365: + return CMP_ind(4, 5); + + case 0x0366: + return CMP_ind(4, 6); + + case 0x0367: + return CMP_ind(4, 7); + + case 0x0368: + return CMP_ind(5, 0); + + case 0x0369: + return CMP_ind(5, 1); + + case 0x036A: + return CMP_ind(5, 2); + + case 0x036B: + return CMP_ind(5, 3); + + case 0x036C: + return CMP_ind(5, 4); + + case 0x036D: + return CMP_ind(5, 5); + + case 0x036E: + return CMP_ind(5, 6); + + case 0x036F: + return CMP_ind(5, 7); + + case 0x0370: + return CMP_ind(6, 0); + + case 0x0371: + return CMP_ind(6, 1); + + case 0x0372: + return CMP_ind(6, 2); + + case 0x0373: + return CMP_ind(6, 3); + + case 0x0374: + return CMP_ind(6, 4); + + case 0x0375: + return CMP_ind(6, 5); + + case 0x0376: + return CMP_ind(6, 6); + + case 0x0377: + return CMP_ind(6, 7); + + case 0x0378: + return CMP_ind(7, 0); + + case 0x0379: + return CMP_ind(7, 1); + + case 0x037A: + return CMP_ind(7, 2); + + case 0x037B: + return CMP_ind(7, 3); + + case 0x037C: + return CMP_ind(7, 4); + + case 0x037D: + return CMP_ind(7, 5); + + case 0x037E: + return CMP_ind(7, 6); + + case 0x037F: + return CMP_ind(7, 7); + + case 0x0380: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 0); + + case 0x0381: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 1); + + case 0x0382: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 2); + + case 0x0383: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 3); + + case 0x0384: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 4); + + case 0x0385: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 5); + + case 0x0386: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 6); + + case 0x0387: + return AND(memoryBus->peek((UINT16)(r[7] + 1)), 7); + + case 0x0388: + return AND_ind(1, 0); + + case 0x0389: + return AND_ind(1, 1); + + case 0x038A: + return AND_ind(1, 2); + + case 0x038B: + return AND_ind(1, 3); + + case 0x038C: + return AND_ind(1, 4); + + case 0x038D: + return AND_ind(1, 5); + + case 0x038E: + return AND_ind(1, 6); + + case 0x038F: + return AND_ind(1, 7); + + case 0x0390: + return AND_ind(2, 0); + + case 0x0391: + return AND_ind(2, 1); + + case 0x0392: + return AND_ind(2, 2); + + case 0x0393: + return AND_ind(2, 3); + + case 0x0394: + return AND_ind(2, 4); + + case 0x0395: + return AND_ind(2, 5); + + case 0x0396: + return AND_ind(2, 6); + + case 0x0397: + return AND_ind(2, 7); + + case 0x0398: + return AND_ind(3, 0); + + case 0x0399: + return AND_ind(3, 1); + + case 0x039A: + return AND_ind(3, 2); + + case 0x039B: + return AND_ind(3, 3); + + case 0x039C: + return AND_ind(3, 4); + + case 0x039D: + return AND_ind(3, 5); + + case 0x039E: + return AND_ind(3, 6); + + case 0x039F: + return AND_ind(3, 7); + + case 0x03A0: + return AND_ind(4, 0); + + case 0x03A1: + return AND_ind(4, 1); + + case 0x03A2: + return AND_ind(4, 2); + + case 0x03A3: + return AND_ind(4, 3); + + case 0x03A4: + return AND_ind(4, 4); + + case 0x03A5: + return AND_ind(4, 5); + + case 0x03A6: + return AND_ind(4, 6); + + case 0x03A7: + return AND_ind(4, 7); + + case 0x03A8: + return AND_ind(5, 0); + + case 0x03A9: + return AND_ind(5, 1); + + case 0x03AA: + return AND_ind(5, 2); + + case 0x03AB: + return AND_ind(5, 3); + + case 0x03AC: + return AND_ind(5, 4); + + case 0x03AD: + return AND_ind(5, 5); + + case 0x03AE: + return AND_ind(5, 6); + + case 0x03AF: + return AND_ind(5, 7); + + case 0x03B0: + return AND_ind(6, 0); + + case 0x03B1: + return AND_ind(6, 1); + + case 0x03B2: + return AND_ind(6, 2); + + case 0x03B3: + return AND_ind(6, 3); + + case 0x03B4: + return AND_ind(6, 4); + + case 0x03B5: + return AND_ind(6, 5); + + case 0x03B6: + return AND_ind(6, 6); + + case 0x03B7: + return AND_ind(6, 7); + + case 0x03B8: + return AND_ind(7, 0); + + case 0x03B9: + return AND_ind(7, 1); + + case 0x03BA: + return AND_ind(7, 2); + + case 0x03BB: + return AND_ind(7, 3); + + case 0x03BC: + return AND_ind(7, 4); + + case 0x03BD: + return AND_ind(7, 5); + + case 0x03BE: + return AND_ind(7, 6); + + case 0x03BF: + return AND_ind(7, 7); + + case 0x03C0: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 0); + + case 0x03C1: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 1); + + case 0x03C2: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 2); + + case 0x03C3: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 3); + + case 0x03C4: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 4); + + case 0x03C5: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 5); + + case 0x03C6: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 6); + + case 0x03C7: + return XOR(memoryBus->peek((UINT16)(r[7] + 1)), 7); + + case 0x03C8: + return XOR_ind(1, 0); + + case 0x03C9: + return XOR_ind(1, 1); + + case 0x03CA: + return XOR_ind(1, 2); + + case 0x03CB: + return XOR_ind(1, 3); + + case 0x03CC: + return XOR_ind(1, 4); + + case 0x03CD: + return XOR_ind(1, 5); + + case 0x03CE: + return XOR_ind(1, 6); + + case 0x03CF: + return XOR_ind(1, 7); + + case 0x03D0: + return XOR_ind(2, 0); + + case 0x03D1: + return XOR_ind(2, 1); + + case 0x03D2: + return XOR_ind(2, 2); + + case 0x03D3: + return XOR_ind(2, 3); + + case 0x03D4: + return XOR_ind(2, 4); + + case 0x03D5: + return XOR_ind(2, 5); + + case 0x03D6: + return XOR_ind(2, 6); + + case 0x03D7: + return XOR_ind(2, 7); + + case 0x03D8: + return XOR_ind(3, 0); + + case 0x03D9: + return XOR_ind(3, 1); + + case 0x03DA: + return XOR_ind(3, 2); + + case 0x03DB: + return XOR_ind(3, 3); + + case 0x03DC: + return XOR_ind(3, 4); + + case 0x03DD: + return XOR_ind(3, 5); + + case 0x03DE: + return XOR_ind(3, 6); + + case 0x03DF: + return XOR_ind(3, 7); + + case 0x03E0: + return XOR_ind(4, 0); + + case 0x03E1: + return XOR_ind(4, 1); + + case 0x03E2: + return XOR_ind(4, 2); + + case 0x03E3: + return XOR_ind(4, 3); + + case 0x03E4: + return XOR_ind(4, 4); + + case 0x03E5: + return XOR_ind(4, 5); + + case 0x03E6: + return XOR_ind(4, 6); + + case 0x03E7: + return XOR_ind(4, 7); + + case 0x03E8: + return XOR_ind(5, 0); + + case 0x03E9: + return XOR_ind(5, 1); + + case 0x03EA: + return XOR_ind(5, 2); + + case 0x03EB: + return XOR_ind(5, 3); + + case 0x03EC: + return XOR_ind(5, 4); + + case 0x03ED: + return XOR_ind(5, 5); + + case 0x03EE: + return XOR_ind(5, 6); + + case 0x03EF: + return XOR_ind(5, 7); + + case 0x03F0: + return XOR_ind(6, 0); + + case 0x03F1: + return XOR_ind(6, 1); + + case 0x03F2: + return XOR_ind(6, 2); + + case 0x03F3: + return XOR_ind(6, 3); + + case 0x03F4: + return XOR_ind(6, 4); + + case 0x03F5: + return XOR_ind(6, 5); + + case 0x03F6: + return XOR_ind(6, 6); + + case 0x03F7: + return XOR_ind(6, 7); + + case 0x03F8: + return XOR_ind(7, 0); + + case 0x03F9: + return XOR_ind(7, 1); + + case 0x03FA: + return XOR_ind(7, 2); + + case 0x03FB: + return XOR_ind(7, 3); + + case 0x03FC: + return XOR_ind(7, 4); + + case 0x03FD: + return XOR_ind(7, 5); + + case 0x03FE: + return XOR_ind(7, 6); + + case 0x03FF: + default : + return XOR_ind(7, 7); + + } +} + +CP1610State CP1610::getState() +{ + CP1610State state = {0}; + state.interruptAddress = this->interruptAddress; + state.resetAddress = this->resetAddress; + memcpy(state.r, r, sizeof(r)); + state.S = S; + state.Z = Z; + state.O = O; + state.C = C; + state.I = I; + state.D = D; + state.interruptible = interruptible; + state.ext = ext; + + return state; +} + +void CP1610::setState(CP1610State state) +{ + this->interruptAddress = state.interruptAddress; + this->resetAddress = state.resetAddress; + memcpy(r, state.r, sizeof(r)); + S = state.S; + Z = state.Z; + O = state.O; + C = state.C; + I = state.I; + D = state.D; + interruptible = state.interruptible; + ext = state.ext; +} diff --git a/arm9/source/emucore/CP1610.h b/arm9/source/emucore/CP1610.h new file mode 100644 index 0000000..383f585 --- /dev/null +++ b/arm9/source/emucore/CP1610.h @@ -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 diff --git a/arm9/source/emucore/CRC32.cpp b/arm9/source/emucore/CRC32.cpp new file mode 100644 index 0000000..e76f173 --- /dev/null +++ b/arm9/source/emucore/CRC32.cpp @@ -0,0 +1,102 @@ + +#include +#include +#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; +} + diff --git a/arm9/source/emucore/CRC32.h b/arm9/source/emucore/CRC32.h new file mode 100644 index 0000000..c59bdaf --- /dev/null +++ b/arm9/source/emucore/CRC32.h @@ -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 + diff --git a/arm9/source/emucore/ECS.cpp b/arm9/source/emucore/ECS.cpp new file mode 100644 index 0000000..0ecf7fe --- /dev/null +++ b/arm9/source/emucore/ECS.cpp @@ -0,0 +1,51 @@ + +#include +#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); +} diff --git a/arm9/source/emucore/ECS.h b/arm9/source/emucore/ECS.h new file mode 100644 index 0000000..0b42e20 --- /dev/null +++ b/arm9/source/emucore/ECS.h @@ -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 diff --git a/arm9/source/emucore/ECSKeyboard.cpp b/arm9/source/emucore/ECSKeyboard.cpp new file mode 100644 index 0000000..b9eafc7 --- /dev/null +++ b/arm9/source/emucore/ECSKeyboard.cpp @@ -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; +} diff --git a/arm9/source/emucore/ECSKeyboard.h b/arm9/source/emucore/ECSKeyboard.h new file mode 100644 index 0000000..1a22e8d --- /dev/null +++ b/arm9/source/emucore/ECSKeyboard.h @@ -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 + diff --git a/arm9/source/emucore/Emulator.cpp b/arm9/source/emucore/Emulator.cpp new file mode 100644 index 0000000..97e87c9 --- /dev/null +++ b/arm9/source/emucore/Emulator.cpp @@ -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, +}; diff --git a/arm9/source/emucore/Emulator.h b/arm9/source/emucore/Emulator.h new file mode 100644 index 0000000..81944fe --- /dev/null +++ b/arm9/source/emucore/Emulator.h @@ -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 diff --git a/arm9/source/emucore/GRAM.cpp b/arm9/source/emucore/GRAM.cpp new file mode 100644 index 0000000..728ad80 --- /dev/null +++ b/arm9/source/emucore/GRAM.cpp @@ -0,0 +1,79 @@ +#include +#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 +} diff --git a/arm9/source/emucore/GRAM.h b/arm9/source/emucore/GRAM.h new file mode 100644 index 0000000..45c36f7 --- /dev/null +++ b/arm9/source/emucore/GRAM.h @@ -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 diff --git a/arm9/source/emucore/GROM.cpp b/arm9/source/emucore/GROM.cpp new file mode 100644 index 0000000..82d451f --- /dev/null +++ b/arm9/source/emucore/GROM.cpp @@ -0,0 +1,15 @@ + +#include "GROM.h" + +GROM::GROM() +: ROM("GROM", "grom.bin", 0, 1, GROM_SIZE, GROM_ADDRESS) +{} + +void GROM::reset() +{ + visible = TRUE; +} + + + + diff --git a/arm9/source/emucore/GROM.h b/arm9/source/emucore/GROM.h new file mode 100644 index 0000000..0985252 --- /dev/null +++ b/arm9/source/emucore/GROM.h @@ -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 diff --git a/arm9/source/emucore/HandController.cpp b/arm9/source/emucore/HandController.cpp new file mode 100644 index 0000000..ed68671 --- /dev/null +++ b/arm9/source/emucore/HandController.cpp @@ -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; +} + diff --git a/arm9/source/emucore/HandController.h b/arm9/source/emucore/HandController.h new file mode 100644 index 0000000..de36b9c --- /dev/null +++ b/arm9/source/emucore/HandController.h @@ -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 diff --git a/arm9/source/emucore/InputConsumer.h b/arm9/source/emucore/InputConsumer.h new file mode 100644 index 0000000..4ffd08a --- /dev/null +++ b/arm9/source/emucore/InputConsumer.h @@ -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 diff --git a/arm9/source/emucore/InputConsumerBus.cpp b/arm9/source/emucore/InputConsumerBus.cpp new file mode 100644 index 0000000..ff0f7ac --- /dev/null +++ b/arm9/source/emucore/InputConsumerBus.cpp @@ -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(); +} diff --git a/arm9/source/emucore/InputConsumerBus.h b/arm9/source/emucore/InputConsumerBus.h new file mode 100644 index 0000000..712caf6 --- /dev/null +++ b/arm9/source/emucore/InputConsumerBus.h @@ -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 diff --git a/arm9/source/emucore/InputConsumerObject.cpp b/arm9/source/emucore/InputConsumerObject.cpp new file mode 100644 index 0000000..329fb08 --- /dev/null +++ b/arm9/source/emucore/InputConsumerObject.cpp @@ -0,0 +1,65 @@ +#include +#include + +// TODO: jeremiah sypult cross-platform +#if defined( _WIN32 ) +#include +#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; +} diff --git a/arm9/source/emucore/InputConsumerObject.h b/arm9/source/emucore/InputConsumerObject.h new file mode 100644 index 0000000..77e8fb6 --- /dev/null +++ b/arm9/source/emucore/InputConsumerObject.h @@ -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 \ No newline at end of file diff --git a/arm9/source/emucore/InputProducer.h b/arm9/source/emucore/InputProducer.h new file mode 100644 index 0000000..baf7f1f --- /dev/null +++ b/arm9/source/emucore/InputProducer.h @@ -0,0 +1,38 @@ + +#ifndef INPUTPRODUCER_H +#define INPUTPRODUCER_H + +// TODO: jeremiah sypult cross-platform +#if defined( _WIN32 ) +#include +#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 \ No newline at end of file diff --git a/arm9/source/emucore/InputProducerManager.cpp b/arm9/source/emucore/InputProducerManager.cpp new file mode 100644 index 0000000..5e10a57 --- /dev/null +++ b/arm9/source/emucore/InputProducerManager.cpp @@ -0,0 +1,60 @@ +#include +#include +#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::iterator it = devices.begin(); it < devices.end(); it++) + (*it)->poll(); +} + +void InputProducerManager::releaseInputProducers() +{ + for (vector::iterator it = devices.begin(); it < devices.end(); it++) { +#if defined( _WIN32 ) + IDirectInputDevice8* nextDevice = (*it)->getDevice(); + nextDevice->Unacquire(); + nextDevice->Release(); + delete (*it); +#endif + } + devices.clear(); +} + diff --git a/arm9/source/emucore/InputProducerManager.h b/arm9/source/emucore/InputProducerManager.h new file mode 100644 index 0000000..ef7b843 --- /dev/null +++ b/arm9/source/emucore/InputProducerManager.h @@ -0,0 +1,43 @@ + +#ifndef INPUTPRODUCERMANAGER_H +#define INPUTPRODUCERMANAGER_H + +// TODO: jeremiah sypult cross-platform +#if defined( _WIN32 ) +#include +#include +#endif + +#include "InputProducer.h" +#include +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 devices; + +}; + +#endif \ No newline at end of file diff --git a/arm9/source/emucore/Intellivision.cpp b/arm9/source/emucore/Intellivision.cpp new file mode 100644 index 0000000..704c1b2 --- /dev/null +++ b/arm9/source/emucore/Intellivision.cpp @@ -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; +} diff --git a/arm9/source/emucore/Intellivision.h b/arm9/source/emucore/Intellivision.h new file mode 100644 index 0000000..7ce85f7 --- /dev/null +++ b/arm9/source/emucore/Intellivision.h @@ -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 diff --git a/arm9/source/emucore/Intellivoice.cpp b/arm9/source/emucore/Intellivoice.cpp new file mode 100644 index 0000000..a8b2dd5 --- /dev/null +++ b/arm9/source/emucore/Intellivoice.cpp @@ -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); +} diff --git a/arm9/source/emucore/Intellivoice.h b/arm9/source/emucore/Intellivoice.h new file mode 100644 index 0000000..4718ea6 --- /dev/null +++ b/arm9/source/emucore/Intellivoice.h @@ -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 diff --git a/arm9/source/emucore/MOB.cpp b/arm9/source/emucore/MOB.cpp new file mode 100644 index 0000000..61d0a47 --- /dev/null +++ b/arm9/source/emucore/MOB.cpp @@ -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; +} diff --git a/arm9/source/emucore/MOB.h b/arm9/source/emucore/MOB.h new file mode 100644 index 0000000..52661ea --- /dev/null +++ b/arm9/source/emucore/MOB.h @@ -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 diff --git a/arm9/source/emucore/MOBRect.h b/arm9/source/emucore/MOBRect.h new file mode 100644 index 0000000..95065b0 --- /dev/null +++ b/arm9/source/emucore/MOBRect.h @@ -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 diff --git a/arm9/source/emucore/Memory.h b/arm9/source/emucore/Memory.h new file mode 100644 index 0000000..34358df --- /dev/null +++ b/arm9/source/emucore/Memory.h @@ -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 diff --git a/arm9/source/emucore/MemoryBus.cpp b/arm9/source/emucore/MemoryBus.cpp new file mode 100644 index 0000000..e8ba6d2 --- /dev/null +++ b/arm9/source/emucore/MemoryBus.cpp @@ -0,0 +1,230 @@ +#include +#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<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<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); +} + diff --git a/arm9/source/emucore/MemoryBus.h b/arm9/source/emucore/MemoryBus.h new file mode 100644 index 0000000..8ddd8cf --- /dev/null +++ b/arm9/source/emucore/MemoryBus.h @@ -0,0 +1,46 @@ + +#ifndef MEMORYBUS_H +#define MEMORYBUS_H + +#include +#include +#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 diff --git a/arm9/source/emucore/Palette.h b/arm9/source/emucore/Palette.h new file mode 100644 index 0000000..6f4549d --- /dev/null +++ b/arm9/source/emucore/Palette.h @@ -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 diff --git a/arm9/source/emucore/Peripheral.cpp b/arm9/source/emucore/Peripheral.cpp new file mode 100644 index 0000000..79b5bfc --- /dev/null +++ b/arm9/source/emucore/Peripheral.cpp @@ -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]; +} + + diff --git a/arm9/source/emucore/Peripheral.h b/arm9/source/emucore/Peripheral.h new file mode 100644 index 0000000..8a90382 --- /dev/null +++ b/arm9/source/emucore/Peripheral.h @@ -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 + diff --git a/arm9/source/emucore/Processor.cpp b/arm9/source/emucore/Processor.cpp new file mode 100644 index 0000000..2405ff7 --- /dev/null +++ b/arm9/source/emucore/Processor.cpp @@ -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; +} diff --git a/arm9/source/emucore/Processor.h b/arm9/source/emucore/Processor.h new file mode 100644 index 0000000..cfc9c76 --- /dev/null +++ b/arm9/source/emucore/Processor.h @@ -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 diff --git a/arm9/source/emucore/ProcessorBus.cpp b/arm9/source/emucore/ProcessorBus.cpp new file mode 100644 index 0000000..98d28a8 --- /dev/null +++ b/arm9/source/emucore/ProcessorBus.cpp @@ -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; +} +*/ \ No newline at end of file diff --git a/arm9/source/emucore/ProcessorBus.h b/arm9/source/emucore/ProcessorBus.h new file mode 100644 index 0000000..3ab5d96 --- /dev/null +++ b/arm9/source/emucore/ProcessorBus.h @@ -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 diff --git a/arm9/source/emucore/RAM.ITCM.cpp b/arm9/source/emucore/RAM.ITCM.cpp new file mode 100644 index 0000000..4b72a6e --- /dev/null +++ b/arm9/source/emucore/RAM.ITCM.cpp @@ -0,0 +1,157 @@ +#include +#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()); + } +} diff --git a/arm9/source/emucore/RAM.h b/arm9/source/emucore/RAM.h new file mode 100644 index 0000000..77bdc21 --- /dev/null +++ b/arm9/source/emucore/RAM.h @@ -0,0 +1,72 @@ + +#ifndef RAM_H +#define RAM_H + +#include +#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 diff --git a/arm9/source/emucore/ROM.ITCM.cpp b/arm9/source/emucore/ROM.ITCM.cpp new file mode 100644 index 0000000..2de3911 --- /dev/null +++ b/arm9/source/emucore/ROM.ITCM.cpp @@ -0,0 +1,174 @@ +#include +#include +#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 +} + diff --git a/arm9/source/emucore/ROM.h b/arm9/source/emucore/ROM.h new file mode 100644 index 0000000..df9c84d --- /dev/null +++ b/arm9/source/emucore/ROM.h @@ -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 diff --git a/arm9/source/emucore/ROMBanker.cpp b/arm9/source/emucore/ROMBanker.cpp new file mode 100644 index 0000000..44df25e --- /dev/null +++ b/arm9/source/emucore/ROMBanker.cpp @@ -0,0 +1,24 @@ + +#include +#include +#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); +} diff --git a/arm9/source/emucore/ROMBanker.h b/arm9/source/emucore/ROMBanker.h new file mode 100644 index 0000000..3137de1 --- /dev/null +++ b/arm9/source/emucore/ROMBanker.h @@ -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 diff --git a/arm9/source/emucore/Rip.cpp b/arm9/source/emucore/Rip.cpp new file mode 100644 index 0000000..7e2e0e5 --- /dev/null +++ b/arm9/source/emucore/Rip.cpp @@ -0,0 +1,843 @@ + +#include +#include + +#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; +} diff --git a/arm9/source/emucore/Rip.h b/arm9/source/emucore/Rip.h new file mode 100644 index 0000000..8ae19b3 --- /dev/null +++ b/arm9/source/emucore/Rip.h @@ -0,0 +1,87 @@ + +#ifndef RIP_H +#define RIP_H + +#include +#include +#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 diff --git a/arm9/source/emucore/SP0256.cpp b/arm9/source/emucore/SP0256.cpp new file mode 100644 index 0000000..40fd1cb --- /dev/null +++ b/arm9/source/emucore/SP0256.cpp @@ -0,0 +1,956 @@ +#include +#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 +} diff --git a/arm9/source/emucore/SP0256.h b/arm9/source/emucore/SP0256.h new file mode 100644 index 0000000..346b30c --- /dev/null +++ b/arm9/source/emucore/SP0256.h @@ -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 diff --git a/arm9/source/emucore/SP0256_Registers.cpp b/arm9/source/emucore/SP0256_Registers.cpp new file mode 100644 index 0000000..a8072b2 --- /dev/null +++ b/arm9/source/emucore/SP0256_Registers.cpp @@ -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); + } +} + diff --git a/arm9/source/emucore/SP0256_Registers.h b/arm9/source/emucore/SP0256_Registers.h new file mode 100644 index 0000000..44778bc --- /dev/null +++ b/arm9/source/emucore/SP0256_Registers.h @@ -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 diff --git a/arm9/source/emucore/SignalLine.h b/arm9/source/emucore/SignalLine.h new file mode 100644 index 0000000..c881d67 --- /dev/null +++ b/arm9/source/emucore/SignalLine.h @@ -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 diff --git a/arm9/source/emucore/VideoBus.cpp b/arm9/source/emucore/VideoBus.cpp new file mode 100644 index 0000000..5a01362 --- /dev/null +++ b/arm9/source/emucore/VideoBus.cpp @@ -0,0 +1,93 @@ + +#include +#include +#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; + } +} diff --git a/arm9/source/emucore/VideoBus.h b/arm9/source/emucore/VideoBus.h new file mode 100644 index 0000000..e465806 --- /dev/null +++ b/arm9/source/emucore/VideoBus.h @@ -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 diff --git a/arm9/source/emucore/VideoProducer.h b/arm9/source/emucore/VideoProducer.h new file mode 100644 index 0000000..04a0605 --- /dev/null +++ b/arm9/source/emucore/VideoProducer.h @@ -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 diff --git a/arm9/source/emucore/knowncarts.cfg b/arm9/source/emucore/knowncarts.cfg new file mode 100644 index 0000000..b7aa37f --- /dev/null +++ b/arm9/source/emucore/knowncarts.cfg @@ -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 diff --git a/arm9/source/emucore/ripxbf.c b/arm9/source/emucore/ripxbf.c new file mode 100644 index 0000000..071c802 --- /dev/null +++ b/arm9/source/emucore/ripxbf.c @@ -0,0 +1,144 @@ + +#include +#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; +} +*/ diff --git a/arm9/source/emucore/ripxbf.h b/arm9/source/emucore/ripxbf.h new file mode 100644 index 0000000..5e8b962 --- /dev/null +++ b/arm9/source/emucore/ripxbf.h @@ -0,0 +1,120 @@ +/** + * This file contains a list of declarations useful for working with + * files in the XBF format. + * + * Author: Kyle Davis + */ + +#include +#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 + diff --git a/arm9/source/emucore/types.h b/arm9/source/emucore/types.h new file mode 100644 index 0000000..0c916d1 --- /dev/null +++ b/arm9/source/emucore/types.h @@ -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 + +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 + diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp new file mode 100644 index 0000000..d6b7cb6 --- /dev/null +++ b/arm9/source/main.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#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; +} + diff --git a/knowncarts.cfg b/knowncarts.cfg new file mode 100644 index 0000000..f40e61d --- /dev/null +++ b/knowncarts.cfg @@ -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 diff --git a/logo.bmp b/logo.bmp new file mode 100644 index 0000000..25efebd Binary files /dev/null and b/logo.bmp differ