First commit of semi-working emulator!

This commit is contained in:
wavemotion-dave 2021-09-02 17:32:31 -04:00
parent 6152092a85
commit 30f0688492
99 changed files with 16793 additions and 0 deletions

44
Makefile Normal file
View File

@ -0,0 +1,44 @@
#export DEVKITPRO=/opt/devkitpro
#export DEVKITARM=/opt/devkitpro/devkitARM
#
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
.SECONDARY:
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
export TARGET := NINTV-DS
export TOPDIR := $(CURDIR)
export VERSION := 0.5
ICON := -b $(CURDIR)/logo.bmp "NINTV-DS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/NINTV-DS"
.PHONY: arm7/$(TARGET).elf arm9/$(TARGET).elf
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all: $(TARGET).nds
#---------------------------------------------------------------------------------
$(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf
ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf $(ICON)
#---------------------------------------------------------------------------------
arm7/$(TARGET).elf:
$(MAKE) -C arm7
#---------------------------------------------------------------------------------
arm9/$(TARGET).elf:
$(MAKE) -C arm9
#---------------------------------------------------------------------------------
clean:
$(MAKE) -C arm9 clean
$(MAKE) -C arm7 clean
rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9

127
arm7/Makefile Normal file
View File

@ -0,0 +1,127 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := source
INCLUDES := include build
DATA :=
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb-interwork
CFLAGS := -g -Wall -O2\
-mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\
-ffast-math \
$(ARCH)
CFLAGS += $(INCLUDE) -DARM7
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map
#LIBS := -ldswifi7 -lmm7 -lnds7
LIBS := -ldswifi7 -lnds7
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ARM7ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) *.elf
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM7ELF) : $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@ -0,0 +1,83 @@
#include <nds/arm7/audio.h>
#include <nds/fifocommon.h>
#include <nds/fifomessages.h>
typedef enum {
EMUARM7_INIT_SND = 0x123C,
EMUARM7_STOP_SND = 0x123D,
EMUARM7_PLAY_SND = 0x123E,
} FifoMesType;
//---------------------------------------------------------------------------------
void soundEmuDataHandler(int bytes, void *user_data)
{
int channel = -1;
FifoMessage msg;
fifoGetDatamsg(FIFO_USER_01, bytes, (u8*)&msg);
switch (msg.type) {
case EMUARM7_PLAY_SND:
channel = (msg.SoundPlay.format & 0xF0)>>4;
SCHANNEL_SOURCE(channel) = (u32)msg.SoundPlay.data;
SCHANNEL_REPEAT_POINT(channel) = msg.SoundPlay.loopPoint;
SCHANNEL_LENGTH(channel) = msg.SoundPlay.dataSize;
SCHANNEL_TIMER(channel) = SOUND_FREQ(msg.SoundPlay.freq);
SCHANNEL_CR(channel) = SCHANNEL_ENABLE | SOUND_VOL(msg.SoundPlay.volume) | SOUND_PAN(msg.SoundPlay.pan) | ((msg.SoundPlay.format & 0xF) << 29) | (msg.SoundPlay.loop ? SOUND_REPEAT : SOUND_ONE_SHOT);
break;
case EMUARM7_INIT_SND:
break;
case EMUARM7_STOP_SND:
break;
}
}
//---------------------------------------------------------------------------------
void soundEmuCommandHandler(u32 command, void* userdata) {
int cmd = (command ) & 0x00F00000;
int data = command & 0xFFFF;
int channel = (command >> 16) & 0xF;
switch(cmd)
{
case SOUND_SET_VOLUME:
SCHANNEL_CR(channel) &= ~0xFF;
SCHANNEL_CR(channel) |= data;
break;
case SOUND_SET_PAN:
SCHANNEL_CR(channel) &= ~SOUND_PAN(0xFF);
SCHANNEL_CR(channel) |= SOUND_PAN(data);
break;
case SOUND_SET_FREQ:
SCHANNEL_TIMER(channel) = SOUND_FREQ(data);
break;
case SOUND_SET_WAVEDUTY:
SCHANNEL_CR(channel) &= ~(7 << 24);
SCHANNEL_CR(channel) |= (data) << 24;
break;
case SOUND_KILL:
case SOUND_PAUSE:
SCHANNEL_CR(channel) &= ~SCHANNEL_ENABLE;
break;
case SOUND_RESUME:
SCHANNEL_CR(channel) |= SCHANNEL_ENABLE;
break;
default: break;
}
}
//---------------------------------------------------------------------------------
void installSoundEmuFIFO(void) {
fifoSetDatamsgHandler(FIFO_USER_01, soundEmuDataHandler, 0);
fifoSetValue32Handler(FIFO_USER_01, soundEmuCommandHandler, 0);
}

95
arm7/source/main.c Normal file
View File

@ -0,0 +1,95 @@
/*---------------------------------------------------------------------------------
default ARM7 core
Copyright (C) 2005 - 2010
Michael Noland (joat)
Jason Rogers (dovoto)
Dave Murphy (WinterMute)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any
damages arising from the use of this software.
Permission is granted to anyone to use this software for any
purpose, including commercial applications, and to alter it and
redistribute it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you
must not claim that you wrote the original software. If you use
this software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and
must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
---------------------------------------------------------------------------------*/
#include <nds.h>
#include <dswifi7.h>
#include <maxmod7.h>
extern void installSoundEmuFIFO(void);
//---------------------------------------------------------------------------------
void VblankHandler(void) {
//---------------------------------------------------------------------------------
Wifi_Update();
}
//---------------------------------------------------------------------------------
void VcountHandler() {
//---------------------------------------------------------------------------------
inputGetAndSend();
}
volatile bool exitflag = false;
//---------------------------------------------------------------------------------
void powerButtonCB() {
//---------------------------------------------------------------------------------
exitflag = true;
}
//---------------------------------------------------------------------------------
int main() {
//---------------------------------------------------------------------------------
readUserSettings();
irqInit();
// Start the RTC tracking IRQ
initClockIRQ();
touchInit();
fifoInit();
//mmInstall(FIFO_MAXMOD);
SetYtrigger(80);
installWifiFIFO();
installSoundFIFO();
installSystemFIFO();
installSoundEmuFIFO();
irqSet(IRQ_VCOUNT, VcountHandler);
irqSet(IRQ_VBLANK, VblankHandler);
irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK);
setPowerButtonCB(powerButtonCB);
// Keep the ARM7 mostly idle
while (!exitflag) {
if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) {
exitflag = true;
}
swiWaitForVBlank();
}
return 0;
}

141
arm9/Makefile Normal file
View File

@ -0,0 +1,141 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files
# DATA is a list of directories containing binary files
# all directories are relative to this makefile
#---------------------------------------------------------------------------------
BUILD := build
SOURCES := source/emucore source/common source
INCLUDES := source/emucore source/common include
DATA := data
GRAPHICS := gfx
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
#ARCH := -mthumb -mthumb-interwork
ARCH :=
#CFLAGS := -g -Wall -O2 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH)
CFLAGS := -Wno-address-of-packed-member -Wno-multichar -O3 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH)
CFLAGS += $(INCLUDE) -DARM9
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -Wno-conversion-null
#ASFLAGS := -g $(ARCH) -march=armv5te -mtune=arm946e-s
ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s
LDFLAGS = -specs=ds_arm9.specs $(ARCH) -Wl,-Map,$(notdir $*.map)
//LDFLAGS = -specs=../ds_arm9_hi.specs $(ARCH) -Wl,-Map,$(notdir $*.map)
#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------
LIBS := -lfat -lnds9
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(LIBNDS)
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export ARM9ELF := $(CURDIR)/$(TARGET).elf
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(PNGFILES:.png=.o) $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean
#---------------------------------------------------------------------------------
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) *.elf *.nds* *.bin
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(ARM9ELF) : $(OFILES)
@echo linking $(notdir $@)
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
@echo $(notdir $<)
@$(bin2o)
%.s %.h : %.png
# grit $< -fts -W3 -gT! -gzl -gB16 -gb -o$*
grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl
#%.gif.o : %.gif
# @echo $(notdir $<)
# @$(bin2o)
%.wav.o : %.wav
@echo $(notdir $<)
@$(bin2o)
-include $(DEPSDIR)/*.d
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

BIN
arm9/data/clickNoQuit.wav Normal file

Binary file not shown.

BIN
arm9/data/clickQuit.wav Normal file

Binary file not shown.

BIN
arm9/data/mus_intro.wav Normal file

Binary file not shown.

11
arm9/ds_arm9_hi.mem Normal file
View File

@ -0,0 +1,11 @@
/*--------------------------------------------------------------------------------
This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can
obtain one at https://mozilla.org/MPL/2.0/.
--------------------------------------------------------------------------------*/
MEMORY {
ewram : ORIGIN = 0x02004000, LENGTH = 3M + 512K - 0x4000
dtcm : ORIGIN = 0x0b000000, LENGTH = 16K
vectors : ORIGIN = 0x01000000, LENGTH = 256
itcm : ORIGIN = 0x01000100, LENGTH = 32K - 256
}

8
arm9/ds_arm9_hi.specs Normal file
View File

@ -0,0 +1,8 @@
%rename link old_link
*link:
%(old_link) -T ../ds_arm9_hi.mem%s -T ds_arm9.ld%s --gc-sections
*startfile:
ds_arm9_crt0%O%s crti%O%s crtbegin%O%s

BIN
arm9/gfx/bgBottom.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
arm9/gfx/bgFileSel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
arm9/gfx/bgInstructions.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
arm9/gfx/bgOptions.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
arm9/gfx/bgTop.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

1090
arm9/source/ds_tools.cpp Normal file

File diff suppressed because it is too large Load Diff

36
arm9/source/ds_tools.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef __DS_TOOLS_H
#define __DS_TOOLS_H
#include <nds.h>
#define STELLADS_MENUINIT 0x01
#define STELLADS_MENUSHOW 0x02
#define STELLADS_PLAYINIT 0x03
#define STELLADS_PLAYGAME 0x04
#define STELLADS_QUITSTDS 0x05
extern unsigned int etatEmu;
typedef enum {
EMUARM7_INIT_SND = 0x123C,
EMUARM7_STOP_SND = 0x123D,
EMUARM7_PLAY_SND = 0x123E,
} FifoMesType;
typedef struct FICtoLoad {
char filename[255];
bool directory;
} FICA2600;
extern void dsPrintValue(int x, int y, unsigned int isSelect, char *pchStr);
extern void dsMainLoop(void);
extern void dsInstallSoundEmuFIFO(void);
extern void dsInitScreenMain(void);
extern void dsInitTimer(void);
extern void dsFreeEmu(void);
extern void dsShowScreenEmu(void);
extern bool dsWaitOnQuit(void);
extern void dsChooseOptions(void);
extern unsigned int dsWaitForRom(char *chosen_filename);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,263 @@
#ifndef AY38900_H
#define AY38900_H
#include "Processor.h"
#include "MemoryBus.h"
#include "ROM.h"
#include "VideoProducer.h"
#include "AY38900_Registers.h"
#include "MOB.h"
#include "BackTabRAM.h"
#include "GRAM.h"
#define AY38900_PIN_IN_SST 0
#define AY38900_PIN_OUT_SR1 0
#define AY38900_PIN_OUT_SR2 1
TYPEDEF_STRUCT_PACK( _AY38900State
{
BackTabRAMState backtab;
MOBState mobs[8];
INT32 horizontalOffset;
INT32 verticalOffset;
INT32 mode;
UINT16 registers[0x40];
INT8 inVBlank;
INT8 previousDisplayEnabled;
INT8 displayEnabled;
INT8 colorStackMode;
UINT8 borderColor;
INT8 blockLeft;
INT8 blockTop;
UINT8 _pad[1];
} AY38900State; )
class AY38900 : public Processor, public VideoProducer
{
friend class AY38900_Registers;
public:
AY38900(MemoryBus* mb, ROM* go, GRAM* ga);
/**
* Implemented from the Processor interface.
* Returns the clock speed of the AY-3-8900, currently hardcoded to the NTSC clock
* rate of 3.579545 Mhz.
*/
INT32 getClockSpeed() { return 3579545; }
/**
* Implemented from the Processor interface.
*/
void resetProcessor();
/**
* Implemented from the Processor interface.
*/
INT32 tick(INT32);
/**
* Implemented from the VideoProducer interface.
*/
void setPixelBuffer(UINT8* pixelBuffer, UINT32 rowSize);
/**
* Implemented from the VideoProducer interface.
*/
void render();
AY38900State getState();
void setState(AY38900State state);
//registers
AY38900_Registers registers;
BackTabRAM backtab;
private:
void setGraphicsBusVisible(BOOL visible);
void renderFrame();
BOOL somethingChanged();
void markClean();
void renderBorders();
void renderMOBs();
void renderBackground();
void renderForegroundBackgroundMode();
void renderColorStackMode();
void copyBackgroundBufferToStagingArea();
void copyMOBsToStagingArea();
void renderLine(UINT8 nextByte, INT32 x, INT32 y, UINT8 fgcolor, UINT8 bgcolor);
void renderColoredSquares(INT32 x, INT32 y, UINT8 color0, UINT8 color1, UINT8 color2, UINT8 color3);
void determineMOBCollisions();
BOOL mobsCollide(INT32 mobNum0, INT32 mobNum1);
BOOL mobCollidesWithBorder(int mobNum);
BOOL mobCollidesWithForeground(int mobNum);
//void renderRow(INT32 rowNum);
const static INT32 TICK_LENGTH_SCANLINE;
const static INT32 TICK_LENGTH_FRAME;
const static INT32 TICK_LENGTH_VBLANK;
const static INT32 TICK_LENGTH_START_ACTIVE_DISPLAY;
const static INT32 TICK_LENGTH_IDLE_ACTIVE_DISPLAY;
const static INT32 TICK_LENGTH_FETCH_ROW;
const static INT32 TICK_LENGTH_RENDER_ROW;
const static INT32 LOCATION_BACKTAB;
const static INT32 LOCATION_GROM;
const static INT32 LOCATION_GRAM;
const static INT32 LOCATION_COLORSTACK;
const static INT32 FOREGROUND_BIT;
MemoryBus* memoryBus;
MOB mobs[8];
UINT8 backgroundBuffer[160*96];
UINT8* pixelBuffer;
UINT32 pixelBufferRowSize;
//memory listeners, for optimizations
ROM* grom;
GRAM* gram;
//state info
BOOL inVBlank;
INT32 mode;
BOOL previousDisplayEnabled;
BOOL displayEnabled;
BOOL colorStackMode;
BOOL colorModeChanged;
BOOL bordersChanged;
BOOL colorStackChanged;
BOOL offsetsChanged;
BOOL imageBufferChanged;
//register info
UINT8 borderColor;
BOOL blockLeft;
BOOL blockTop;
INT32 horizontalOffset;
INT32 verticalOffset;
};
#endif
/*
#ifndef AY38900_H
#define AY38900_H
#include "AY38900_Registers.h"
#include "BackTabRAM.h"
#include "GRAM.h"
#include "GROM.h"
#include "MOB.h"
#include "VideoProducer.h"
#include "core/types.h"
#include "core/cpu/Processor.h"
#include "core/cpu/SignalLine.h"
#include "core/memory/MemoryBus.h"
#include "services/VideoOutputDevice.h"
#define AY38900_PIN_IN_SST 0
#define AY38900_PIN_OUT_SR1 0
#define AY38900_PIN_OUT_SR2 1
class AY38900 : public Processor, public VideoProducer
{
friend class AY38900_Registers;
public:
AY38900(MemoryBus* memoryBus);
void setGROMImage(UINT16* gromImage);
BOOL inVerticalBlank();
//Processor functions
void initProcessor();
void releaseProcessor();
void setVideoOutputDevice(IDirect3DDevice9* vod);
INT32 getClockSpeed();
INT32 tick();
//VideoProducer functions
void render();
//registers
AY38900_Registers registers;
static const INT32 TICK_LENGTH_SCANLINE;
static const INT32 TICK_LENGTH_FRAME;
static const INT32 TICK_LENGTH_VBLANK;
static const INT32 TICK_LENGTH_START_ACTIVE_DISPLAY;
static const INT32 TICK_LENGTH_IDLE_ACTIVE_DISPLAY;
static const INT32 TICK_LENGTH_FETCH_ROW;
static const INT32 TICK_LENGTH_RENDER_ROW;
static const INT32 LOCATION_BACKTAB;
static const INT32 LOCATION_GROM;
static const INT32 LOCATION_GRAM;
static const INT32 LOCATION_COLORSTACK;
static const INT32 FOREGROUND_BIT;
private:
void setGraphicsBusVisible(BOOL visible);
void renderFrame();
BOOL somethingChanged();
void markClean();
void renderBorders();
void renderMOBs();
void renderBackground();
void copyBackgroundBufferToStagingArea();
void renderForegroundBackgroundMode();
void renderColorStackMode();
void copyMOBsToStagingArea();
void renderLine(UINT8 nextUINT8, INT32 x, INT32 y,
UINT8 fgcolor, UINT8 bgcolor);
void renderColoredSquares(INT32 x, INT32 y, UINT8 color0, UINT8 color1,
UINT8 color2, UINT8 color3);
void renderMessage();
void renderCharacter(char c, INT32 x, INT32 y);
void determineMOBCollisions();
BOOL mobsCollide(INT32 mobNum0, INT32 mobNum1);
BOOL mobBuffers[8][16][128];
MOB mobs[8];
UINT8 backgroundBuffer[160*96];
IDirect3DDevice9* videoOutputDevice;
IDirect3DTexture9* combinedTexture;
IDirect3DVertexBuffer9* vertexBuffer;
D3DLOCKED_RECT combinedBufferLock;
MemoryBus* memoryBus;
//memory listeners, for optimizations
BackTabRAM backtab;
GROM grom;
GRAM gram;
//state info
BOOL inVBlank;
INT32 mode;
BOOL previousDisplayEnabled;
BOOL displayEnabled;
BOOL colorStackMode;
BOOL colorModeChanged;
BOOL bordersChanged;
BOOL colorStackChanged;
BOOL offsetsChanged;
BOOL imageBufferChanged;
//register info
UINT8 borderColor;
BOOL blockLeft;
BOOL blockTop;
INT32 horizontalOffset;
INT32 verticalOffset;
//palette
const static UINT32 palette[32];
};
#endif
*/

View File

@ -0,0 +1,198 @@
#include <nds.h>
#include <string.h>
#include "AY38900.h"
#include "AY38900_Registers.h"
UINT16 memory[0x40] __attribute__((section(".dtcm")));
AY38900_Registers::AY38900_Registers()
: RAM(0x40, 0x0000, 0xFFFF, 0x3FFF)
{}
void AY38900_Registers::init(AY38900* ay38900)
{
this->ay38900 = ay38900;
}
void AY38900_Registers::reset()
{
memset(memory, 0, sizeof(memory));
}
void AY38900_Registers::poke(UINT16 location, UINT16 value) {
if (!enabled)
return;
//incomplete decoding on writes
location &= 0x3F;
switch(location) {
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
value &= 0x07FF;
{
MOB* mob = &ay38900->mobs[location];
mob->setDoubleWidth((value & 0x0400) != 0);
mob->setVisible((value & 0x0200) != 0);
mob->setFlagCollisions((value & 0x0100) != 0);
mob->setXLocation(value & 0x00FF);
}
break;
case 0x08:
case 0x09:
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
value &= 0x0FFF;
{
MOB* mob = &ay38900->mobs[location & 0x07];
mob->setVerticalMirror((value & 0x0800) != 0);
mob->setHorizontalMirror((value & 0x0400) != 0);
mob->setQuadHeight((value & 0x0200) != 0);
mob->setDoubleHeight((value & 0x0100) != 0);
mob->setDoubleYResolution((value & 0x0080) != 0);
mob->setYLocation(value & 0x007F);
}
break;
case 0x10:
case 0x11:
case 0x12:
case 0x13:
case 0x14:
case 0x15:
case 0x16:
case 0x17:
value &= 0x3FFF;
{
MOB* mob = &ay38900->mobs[location & 0x07];
mob->setBehindForeground((value & 0x2000) != 0);
mob->setGROM((value & 0x0800) == 0);
mob->setCardNumber((value & 0x07F8) >> 3);
mob->setForegroundColor(((value & 0x1000) >> 9) |
(value & 0x0007));
}
break;
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
//a MOB's own collision bit is *always* zero, even if a
//one is poked into it
value &= (~(1 << (location & 0x07))) & 0x03FF;
break;
case 0x20:
ay38900->displayEnabled = TRUE;
break;
case 0x21:
value = 0;
if (ay38900->colorStackMode) {
ay38900->colorStackMode = FALSE;
ay38900->colorModeChanged = TRUE;
}
break;
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
value &= 0x000F;
ay38900->colorStackChanged = TRUE;
break;
case 0x2C:
value &= 0x000F;
ay38900->borderColor = (UINT8)value;
ay38900->bordersChanged = TRUE;
break;
case 0x30:
value &= 0x0007;
ay38900->horizontalOffset = value;
ay38900->offsetsChanged = TRUE;
break;
case 0x31:
value &= 0x0007;
ay38900->verticalOffset = value;
ay38900->offsetsChanged = TRUE;
break;
case 0x32:
value &= 0x0003;
ay38900->blockLeft = (value & 0x0001) != 0;
ay38900->blockTop = (value & 0x0002) != 0;
ay38900->bordersChanged = TRUE;
break;
default: // 0x22 - 0x27
value = 0;
break;
}
memory[location] = value;
}
UINT16 AY38900_Registers::peek(UINT16 location)
{
if (!enabled)
return location;
location &= 0x3F;
switch (location) {
case 0x00:
case 0x01:
case 0x02:
case 0x03:
case 0x04:
case 0x05:
case 0x06:
case 0x07:
return 0x3800 | memory[location];
case 0x08:
case 0x09:
case 0x0A:
case 0x0B:
case 0x0C:
case 0x0D:
case 0x0E:
case 0x0F:
return 0x3000 | memory[location];
case 0x18:
case 0x19:
case 0x1A:
case 0x1B:
case 0x1C:
case 0x1D:
case 0x1E:
case 0x1F:
//collision register bits $3C00 are always on
return 0x3C00 | memory[location];
case 0x20:
return 0;
case 0x21:
if (location == 0x0021 && !ay38900->colorStackMode) {
ay38900->colorStackMode = TRUE;
ay38900->colorModeChanged = TRUE;
}
return memory[location];
case 0x28:
case 0x29:
case 0x2A:
case 0x2B:
case 0x2C:
return 0x3FF0 | memory[location];
case 0x30:
case 0x31:
return 0x3FF8 | memory[location];
case 0x32:
return 0x3FFC | memory[location];
default:
return memory[location];
}
}

View File

@ -0,0 +1,37 @@
#ifndef AY38900_REGISTERS_H
#define AY38900_REGISTERS_H
#include "RAM.h"
class AY38900;
extern UINT16 memory[0x40];
class AY38900_Registers : public RAM
{
friend class AY38900;
public:
void reset();
void poke(UINT16 location, UINT16 value);
UINT16 peek(UINT16 location);
inline size_t getMemoryByteSize() {
return sizeof(memory);
}
void getMemory(void* dst, UINT16 offset, UINT16 size) {
memcpy(dst, memory + offset, size);
}
void setMemory(void* src, UINT16 offset, UINT16 size) {
memcpy(memory + offset, src, size);
}
private:
AY38900_Registers();
void init(AY38900* ay38900);
AY38900* ay38900;
};
#endif

View File

@ -0,0 +1,339 @@
#include <nds.h>
#include "AY38914.h"
#include "AudioMixer.h"
INT32 amplitudes16Bit[16] __attribute__((section(".dtcm"))) =
{
0x003C, 0x0055, 0x0079, 0x00AB, 0x00F1, 0x0155, 0x01E3, 0x02AA,
0x03C5, 0x0555, 0x078B, 0x0AAB, 0x0F16, 0x1555, 0x1E2B, 0x2AAA
};
struct Channel_t channel0 __attribute__((section(".dtcm")));
struct Channel_t channel1 __attribute__((section(".dtcm")));
struct Channel_t channel2 __attribute__((section(".dtcm")));
INT32 clockDivisor __attribute__((section(".dtcm")));
//cached total output sample
BOOL cachedTotalOutputIsDirty __attribute__((section(".dtcm")));
INT32 cachedTotalOutput __attribute__((section(".dtcm")));
//envelope data
BOOL envelopeIdle __attribute__((section(".dtcm")));
INT32 envelopePeriod __attribute__((section(".dtcm")));
INT32 envelopePeriodValue __attribute__((section(".dtcm")));
INT32 envelopeVolume __attribute__((section(".dtcm")));
BOOL envelopeHold __attribute__((section(".dtcm")));
BOOL envelopeAltr __attribute__((section(".dtcm")));
BOOL envelopeAtak __attribute__((section(".dtcm")));
BOOL envelopeCont __attribute__((section(".dtcm")));
INT32 envelopeCounter __attribute__((section(".dtcm")));
//noise data
BOOL noiseIdle __attribute__((section(".dtcm")));
INT32 noisePeriod __attribute__((section(".dtcm")));
INT32 noisePeriodValue __attribute__((section(".dtcm")));
INT32 noiseCounter __attribute__((section(".dtcm")));
//data for random number generator, used for white noise accuracy
INT32 my_random __attribute__((section(".dtcm")));
BOOL noise __attribute__((section(".dtcm")));
/**
* The AY-3-8914 chip in the Intellivision, also know as the Programmable
* Sound Generator (PSG).
*
* @author Kyle Davis
*/
AY38914::AY38914(UINT16 location, AY38914_InputOutput* io0,
AY38914_InputOutput* io1)
: Processor("AY-3-8914"),
registers(location)
{
this->psgIO0 = io0;
this->psgIO1 = io1;
clockDivisor = 8; //TODO: was 1... trying to speed thigns up by lowering sound quality...
registers.init(this);
}
INT32 AY38914::getClockSpeed() {
return 3579545;
}
INT32 AY38914::getClocksPerSample() {
return clockDivisor<<4;
}
void AY38914::resetProcessor()
{
//reset the state variables
noisePeriod = 0;
noisePeriodValue = 0x0040;
noiseCounter = noisePeriodValue;
my_random = 1;
noise = TRUE;
noiseIdle = TRUE;
envelopeIdle = TRUE;
envelopePeriod = 0;
envelopePeriodValue = 0x20000;
envelopeCounter = envelopePeriodValue;
envelopeVolume = 0;
envelopeHold = FALSE;
envelopeAltr = FALSE;
envelopeAtak = FALSE;
envelopeCont = FALSE;
cachedTotalOutput = 0;
cachedTotalOutputIsDirty = TRUE;
memset(&channel0, 0x00, sizeof(channel0));
memset(&channel1, 0x00, sizeof(channel1));
memset(&channel2, 0x00, sizeof(channel2));
channel0.periodValue = 0x1000;
channel0.toneCounter = 0x1000;
channel0.isDirty = TRUE;
channel1.periodValue = 0x1000;
channel1.toneCounter = 0x1000;
channel1.isDirty = TRUE;
channel2.periodValue = 0x1000;
channel2.toneCounter = 0x1000;
channel2.isDirty = TRUE;
}
void AY38914::setClockDivisor(INT32 clockDivisor) {
clockDivisor = clockDivisor;
}
INT32 AY38914::getClockDivisor() {
return clockDivisor;
}
/**
* Tick the AY38914. This method has been profiled over and over again
* in an attempt to tweak it for optimal performance. Please be careful
* with any modifications that may adversely affect performance.
*
* @return the number of ticks used by the AY38914, always returns 4.
*/
ITCM_CODE INT32 AY38914::tick(INT32 minimum)
{
INT32 totalTicks = 0;
do {
//iterate the envelope generator
envelopeCounter -= clockDivisor;
if (envelopeCounter <= 0) {
do {
envelopeCounter += envelopePeriodValue;
if (!envelopeIdle) {
envelopeVolume += (envelopeAtak ? 1 : -1);
if (envelopeVolume > 15 || envelopeVolume < 0) {
if (!envelopeCont) {
envelopeVolume = 0;
envelopeIdle = TRUE;
}
else if (envelopeHold) {
envelopeVolume = (envelopeAtak == envelopeAltr ? 0 : 15);
envelopeIdle = TRUE;
}
else {
envelopeAtak = (envelopeAtak != envelopeAltr);
envelopeVolume = (envelopeAtak ? 0 : 15);
}
}
}
}
while (envelopeCounter <= 0);
//the envelope volume has changed so the channel outputs
//need to be updated if they are using the envelope
channel0.isDirty = channel0.envelope;
channel1.isDirty = channel1.envelope;
channel2.isDirty = channel2.envelope;
}
//iterate the noise generator
noiseCounter -= clockDivisor;
if (noiseCounter <= 0) {
BOOL oldNoise = noise;
do {
noiseCounter += noisePeriodValue;
if (!noiseIdle) {
my_random = (my_random >> 1) ^ (noise ? 0x14000 : 0);
noise = (my_random & 1);
}
}
while (noiseCounter <= 0);
//if the noise bit changed, then our channel outputs need
//to be updated if they are using the noise generator
if (!noiseIdle && oldNoise != noise) {
channel0.isDirty = (channel0.isDirty | !channel0.noiseDisabled);
channel1.isDirty = (channel1.isDirty | !channel1.noiseDisabled);
channel2.isDirty = (channel2.isDirty | !channel2.noiseDisabled);
}
}
//iterate the tone generator for channel 0
channel0.toneCounter -= clockDivisor;
if (channel0.toneCounter <= 0) {
do {
channel0.toneCounter += channel0.periodValue;
channel0.tone = !channel0.tone;
}
while (channel0.toneCounter <= 0);
channel0.isDirty = !channel0.toneDisabled;
}
//iterate the tone generator for channel 1
channel1.toneCounter -= clockDivisor;
if (channel1.toneCounter <= 0) {
do {
channel1.toneCounter += channel1.periodValue;
channel1.tone = !channel1.tone;
}
while (channel1.toneCounter <= 0);
channel1.isDirty = !channel1.toneDisabled;
}
//iterate the tone generator for channel 2
channel2.toneCounter -= clockDivisor;
if (channel2.toneCounter <= 0) {
do {
channel2.toneCounter += channel2.periodValue;
channel2.tone = !channel2.tone;
}
while (channel2.toneCounter <= 0);
channel2.isDirty = !channel2.toneDisabled;
}
if (channel0.isDirty) {
channel0.isDirty = FALSE;
channel0.cachedSample = amplitudes16Bit[
(((channel0.toneDisabled | channel0.tone) &
(channel0.noiseDisabled | noise))
? (channel0.envelope ? envelopeVolume
: channel0.volume) : 0)];
cachedTotalOutputIsDirty = TRUE;
}
if (channel1.isDirty) {
channel1.isDirty = FALSE;
channel1.cachedSample = amplitudes16Bit[
(((channel1.toneDisabled | channel1.tone) &
(channel1.noiseDisabled | noise))
? (channel1.envelope ? envelopeVolume
: channel1.volume) : 0)];
cachedTotalOutputIsDirty = TRUE;
}
if (channel2.isDirty) {
channel2.isDirty = FALSE;
channel2.cachedSample = amplitudes16Bit[
(((channel2.toneDisabled | channel2.tone) &
(channel2.noiseDisabled | noise))
? (channel2.envelope ? envelopeVolume
: channel2.volume) : 0)];
cachedTotalOutputIsDirty = TRUE;
}
//mix all three channel samples together to generate the overall
//output sample for the entire AY38914
if (cachedTotalOutputIsDirty) {
cachedTotalOutputIsDirty = FALSE;
cachedTotalOutput = (channel0.cachedSample +
channel1.cachedSample + channel2.cachedSample);
//apply the saturation clipping to correctly model the
//cross-channel modulation that occurs on a real Intellivision
cachedTotalOutput <<= 1;
if (cachedTotalOutput > 0x6000)
cachedTotalOutput = 0x6000 + ((cachedTotalOutput - 0x6000)/6);
}
audioOutputLine->playSample((INT16)cachedTotalOutput);
totalTicks += (clockDivisor<<4);
} while (totalTicks < minimum);
//every tick here always uses some multiple of 4 CPU cycles
//or 16 NTSC cycles
return totalTicks;
}
AY38914State AY38914::getState()
{
AY38914State state = {0};
#if 0
this->registers.getMemory(state.registers, 0, this->registers.getMemoryByteSize());
state.clockDivisor = this->clockDivisor;
state.channel0 = this->channel0.getState();
state.channel1 = this->channel1.getState();
state.channel2 = this->channel2.getState();
state.cachedTotalOutputIsDirty = this->cachedTotalOutputIsDirty;
state.cachedTotalOutput = this->cachedTotalOutput;
state.envelopeIdle = this->envelopeIdle;
state.envelopePeriod = this->envelopePeriod;
state.envelopePeriodValue = this->envelopePeriodValue;
state.envelopeCounter = this->envelopeCounter;
state.envelopeVolume = this->envelopeVolume;
state.envelopeHold = this->envelopeHold;
state.envelopeAltr = this->envelopeAltr;
state.envelopeAtak = this->envelopeAtak;
state.envelopeCont = this->envelopeCont;
state.noiseIdle = this->noiseIdle;
state.noisePeriod = this->noisePeriod;
state.noisePeriodValue = this->noisePeriodValue;
state.noiseCounter = this->noiseCounter;
state.my_random = this->my_random;
state.noise = this->noise;
#endif
return state;
}
void AY38914::setState(AY38914State state)
{
#if 0
this->registers.setMemory(state.registers, 0, this->registers.getMemoryByteSize());
this->clockDivisor = state.clockDivisor;
this->channel0.setState(state.channel0);
this->channel1.setState(state.channel1);
this->channel2.setState(state.channel2);
this->cachedTotalOutputIsDirty = state.cachedTotalOutputIsDirty;
this->cachedTotalOutput = state.cachedTotalOutput;
this->envelopeIdle = state.envelopeIdle;
this->envelopePeriod = state.envelopePeriod;
this->envelopePeriodValue = state.envelopePeriodValue;
this->envelopeCounter = state.envelopeCounter;
this->envelopeVolume = state.envelopeVolume;
this->envelopeHold = state.envelopeHold;
this->envelopeAltr = state.envelopeAltr;
this->envelopeAtak = state.envelopeAtak;
this->envelopeCont = state.envelopeCont;
this->noiseIdle = state.noiseIdle;
this->noisePeriod = state.noisePeriod;
this->noisePeriodValue = state.noisePeriodValue;
this->noiseCounter = state.noiseCounter;
this->my_random = state.my_random;
this->noise = state.noise;
#endif
}

View File

@ -0,0 +1,101 @@
#ifndef AY38914_H
#define AY38914_H
#include "AudioProducer.h"
#include "AY38914_Registers.h"
#include "AY38914_Channel.h"
#include "AY38914_InputOutput.h"
#include "AudioOutputLine.h"
#include "Processor.h"
#include "types.h"
class Intellivision;
TYPEDEF_STRUCT_PACK( _AY38914State
{
UINT16 registers[0x0E];
INT32 clockDivisor;
INT32 cachedTotalOutput;
INT32 envelopePeriod;
INT32 envelopePeriodValue;
INT32 envelopeCounter;
INT32 envelopeVolume;
INT32 noisePeriod;
INT32 noisePeriodValue;
INT32 noiseCounter;
INT32 random;
INT8 cachedTotalOutputIsDirty;
INT8 envelopeIdle;
INT8 envelopeHold;
INT8 envelopeAltr;
INT8 envelopeAtak;
INT8 envelopeCont;
INT8 noiseIdle;
INT8 noise;
} AY38914State; )
//divisor for slowing down the clock speed for the AY38914
extern INT32 clockDivisor;
//cached total output sample
extern BOOL cachedTotalOutputIsDirty;
extern INT32 cachedTotalOutput;
//envelope data
extern BOOL envelopeIdle;
extern INT32 envelopePeriod;
extern INT32 envelopePeriodValue;
extern INT32 envelopeVolume;
extern BOOL envelopeHold;
extern BOOL envelopeAltr;
extern BOOL envelopeAtak;
extern BOOL envelopeCont;
extern INT32 envelopeCounter;
//noise data
extern BOOL noiseIdle;
extern INT32 noisePeriod;
extern INT32 noisePeriodValue;
extern INT32 noiseCounter;
//data for random number generator, used for white noise accuracy
extern INT32 my_random;
extern BOOL noise;
/**
* The AY-3-8914 chip in the Intellivision, also known as the Programmable
* Sound Generator (PSG).
*
* @author Kyle Davis
*/
class AY38914 : public Processor, public AudioProducer
{
friend class AY38914_Registers;
public:
AY38914(UINT16 location, AY38914_InputOutput* io0,
AY38914_InputOutput* io1);
void resetProcessor();
INT32 getClockSpeed();
INT32 getClocksPerSample();
INT32 getSampleRate() { return getClockSpeed(); }
INT32 tick(INT32);
void setClockDivisor(INT32 clockDivisor);
INT32 getClockDivisor();
AY38914State getState();
void setState(AY38914State state);
//registers
AY38914_Registers registers;
private:
AY38914_InputOutput* psgIO0;
AY38914_InputOutput* psgIO1;
};
#endif

View File

@ -0,0 +1 @@
// Obsoleted...

View File

@ -0,0 +1,25 @@
#ifndef AY38914__CHANNEL_H
#define AY38914__CHANNEL_H
#include "types.h"
struct Channel_t
{
INT32 period;
INT32 periodValue;
INT32 volume;
INT32 toneCounter;
BOOL tone;
BOOL envelope;
BOOL toneDisabled;
BOOL noiseDisabled;
BOOL isDirty;
INT32 cachedSample;
};
extern struct Channel_t channel0;
extern struct Channel_t channel1;
extern struct Channel_t channel2;
#endif

View File

@ -0,0 +1,16 @@
#ifndef AY38914INPUTOUTPUT_H
#define AY38914INPUTOUTPUT_H
#include "types.h"
class AY38914_InputOutput
{
public:
virtual UINT16 getInputValue() = 0;
virtual void setOutputValue(UINT16 value) = 0;
};
#endif

View File

@ -0,0 +1,180 @@
#include <stdio.h>
#include <string.h>
#include "AY38914.h"
#include "AY38914_Registers.h"
AY38914_Registers::AY38914_Registers(UINT16 address)
: RAM(0x10, address, 0xFFFF, 0xFFFF)
{}
void AY38914_Registers::init(AY38914* ay38914)
{
this->ay38914 = ay38914;
}
void AY38914_Registers::reset()
{
memset(memory, 0, sizeof(memory));
}
void AY38914_Registers::poke(UINT16 location, UINT16 value)
{
location &= 0x0F;
switch(location) {
case 0x00:
value = value & 0x00FF;
channel0.period = (channel0.period & 0x0F00) |
value;
channel0.periodValue = (channel0.period
? channel0.period : 0x1000);
memory[location] = value;
break;
case 0x01:
value = value & 0x00FF;
channel1.period = (channel1.period & 0x0F00) |
value;
channel1.periodValue = (channel1.period
? channel1.period : 0x1000);
memory[location] = value;
break;
case 0x02:
value = value & 0x00FF;
channel2.period = (channel2.period & 0x0F00) |
value;
channel2.periodValue = (channel2.period
? channel2.period : 0x1000);
memory[location] = value;
break;
case 0x03:
value = value & 0x00FF;
envelopePeriod = (envelopePeriod & 0xFF00) |
value;
envelopePeriodValue = (envelopePeriod
? (envelopePeriod << 1) : 0x20000);
memory[location] = value;
break;
case 0x04:
value = value & 0x000F;
channel0.period = (channel0.period & 0x00FF) |
(value<<8);
channel0.periodValue = (channel0.period
? channel0.period : 0x1000);
memory[location] = value;
break;
case 0x05:
value = value & 0x000F;
channel1.period = (channel1.period & 0x00FF) |
(value<<8);
channel1.periodValue = (channel1.period
? channel1.period : 0x1000);
memory[location] = value;
break;
case 0x06:
value = value & 0x000F;
channel2.period = (channel2.period & 0x00FF) |
(value<<8);
channel2.periodValue = (channel2.period
? channel2.period : 0x1000);
memory[location] = value;
break;
case 0x07:
value = value & 0x00FF;
envelopePeriod = (envelopePeriod & 0x00FF) |
(value<<8);
envelopePeriodValue = (envelopePeriod
? (envelopePeriod << 1) : 0x20000);
memory[location] = value;
break;
case 0x08:
value = value & 0x00FF;
channel0.toneDisabled = !!(value & 0x0001);
channel1.toneDisabled = !!(value & 0x0002);
channel2.toneDisabled = !!(value & 0x0004);
channel0.noiseDisabled = !!(value & 0x0008);
channel1.noiseDisabled = !!(value & 0x0010);
channel2.noiseDisabled = !!(value & 0x0020);
channel0.isDirty = TRUE;
channel1.isDirty = TRUE;
channel2.isDirty = TRUE;
noiseIdle = channel0.noiseDisabled &
channel1.noiseDisabled &
channel2.noiseDisabled;
memory[location] = value;
break;
case 0x09:
value = value & 0x001F;
noisePeriod = value;
noisePeriodValue = (noisePeriod
? (noisePeriod << 1) : 0x0040);
memory[location] = value;
break;
case 0x0A:
value = value & 0x000F;
envelopeHold = !!(value & 0x0001);
envelopeAltr = !!(value & 0x0002);
envelopeAtak = !!(value & 0x0004);
envelopeCont = !!(value & 0x0008);
envelopeVolume = (envelopeAtak ? 0 : 15);
envelopeCounter = envelopePeriodValue;
envelopeIdle = FALSE;
memory[location] = value;
break;
case 0x0B:
value = value & 0x003F;
channel0.envelope = !!(value & 0x0010);
channel0.volume = (value & 0x000F);
channel0.isDirty = TRUE;
memory[location] = value;
break;
case 0x0C:
value = value & 0x003F;
channel1.envelope = !!(value & 0x0010);
channel1.volume = (value & 0x000F);
channel1.isDirty = TRUE;
memory[location] = value;
break;
case 0x0D:
value = value & 0x003F;
channel2.envelope = !!(value & 0x0010);
channel2.volume = (value & 0x000F);
channel2.isDirty = TRUE;
memory[location] = value;
break;
case 0x0E:
ay38914->psgIO1->setOutputValue(value);
break;
case 0x0F:
ay38914->psgIO0->setOutputValue(value);
break;
}
}
UINT16 AY38914_Registers::peek(UINT16 location)
{
location &= 0x0F;
switch(location) {
case 0x0E:
return ay38914->psgIO1->getInputValue();
case 0x0F:
return ay38914->psgIO0->getInputValue();
default:
return memory[location];
}
}

View File

@ -0,0 +1,36 @@
#ifndef AY38914_REGISTERS_H
#define AY38914_REGISTERS_H
#include "RAM.h"
class AY38914;
class AY38914_Registers : public RAM
{
friend class AY38914;
public:
void reset();
void poke(UINT16 location, UINT16 value);
UINT16 peek(UINT16 location);
inline size_t getMemoryByteSize() {
return sizeof(memory);
}
void getMemory(void* dst, UINT16 offset, UINT16 size) {
memcpy(dst, memory + offset, size);
}
void setMemory(void* src, UINT16 offset, UINT16 size) {
memcpy(memory + offset, src, size);
}
private:
AY38914_Registers(UINT16 address);
void init(AY38914* ay38914);
AY38914* ay38914;
UINT16 memory[0x0E];
};
#endif

View File

@ -0,0 +1,161 @@
#include <nds.h>
#include <stdio.h>
#include <string.h>
#include "AudioMixer.h"
#include "AudioOutputLine.h"
UINT16 audio_mixer_buffer[1500] __attribute__((section(".dtcm")));
extern UINT64 lcm(UINT64, UINT64);
AudioMixer::AudioMixer()
: Processor("Audio Mixer"),
audioProducerCount(0),
commonClocksPerTick(0),
sampleBuffer(NULL),
sampleBufferSize(0),
sampleCount(0),
sampleSize(0)
{
memset(&audioProducers, 0, sizeof(audioProducers));
}
AudioMixer::~AudioMixer()
{
for (UINT32 i = 0; i < audioProducerCount; i++)
delete audioProducers[i]->audioOutputLine;
}
void AudioMixer::addAudioProducer(AudioProducer* p)
{
audioProducers[audioProducerCount] = p;
audioProducers[audioProducerCount]->audioOutputLine =
new AudioOutputLine();
audioProducerCount++;
}
void AudioMixer::removeAudioProducer(AudioProducer* p)
{
for (UINT32 i = 0; i < audioProducerCount; i++) {
if (audioProducers[i] == p) {
delete p->audioOutputLine;
for (UINT32 j = i; j < (audioProducerCount-1); j++)
audioProducers[j] = audioProducers[j+1];
audioProducerCount--;
return;
}
}
}
void AudioMixer::removeAll()
{
while (audioProducerCount)
removeAudioProducer(audioProducers[0]);
}
void AudioMixer::resetProcessor()
{
//reset instance data
commonClocksPerTick = 0;
sampleCount = 0;
if (sampleBuffer) {
memset(sampleBuffer, 0, sampleBufferSize);
}
//iterate through my audio output lines to determine the common output clock
UINT64 totalClockSpeed = getClockSpeed();
for (UINT32 i = 0; i < audioProducerCount; i++) {
audioProducers[i]->audioOutputLine->reset();
totalClockSpeed = lcm(totalClockSpeed, ((UINT64)audioProducers[i]->getClockSpeed()));
}
//iterate again to determine the clock factor of each
commonClocksPerTick = totalClockSpeed / getClockSpeed();
for (UINT32 i = 0; i < audioProducerCount; i++) {
audioProducers[i]->audioOutputLine->commonClocksPerSample = (totalClockSpeed / audioProducers[i]->getClockSpeed())
* audioProducers[i]->getClocksPerSample();
}
}
void AudioMixer::init(UINT32 sampleRate)
{
// TODO: assert if sampleRate/clockSpeed is 0
AudioMixer::release();
clockSpeed = sampleRate;
sampleSize = ( clockSpeed / 60.0 );
sampleBufferSize = sampleSize * sizeof(INT16);
sampleBuffer = (INT16*) audio_mixer_buffer;
if (sampleBuffer) {
memset(sampleBuffer, 0, sampleBufferSize);
}
}
void AudioMixer::release()
{
if (sampleBuffer) {
sampleBufferSize = 0;
sampleSize = 0;
sampleCount = 0;
}
}
INT32 AudioMixer::getClockSpeed()
{
return clockSpeed;
}
ITCM_CODE INT32 AudioMixer::tick(INT32 minimum)
{
// TODO: assert if sampleCount >= sampleSize
for (int totalTicks = 0; totalTicks < minimum; totalTicks++) {
//mix and flush the sample buffers
INT64 totalSample = 0;
for (UINT32 i = 0; i < audioProducerCount; i++) {
AudioOutputLine* nextLine = audioProducers[i]->audioOutputLine;
INT64 missingClocks = (this->commonClocksPerTick - nextLine->commonClockCounter);
INT64 sampleToUse = (missingClocks < 0 ? nextLine->previousSample : nextLine->currentSample);
//account for when audio producers idle by adding enough samples to each producer's buffer
//to fill the time since last sample calculation
INT64 missingSampleCount = (missingClocks / nextLine->commonClocksPerSample);
if (missingSampleCount != 0) {
nextLine->sampleBuffer += missingSampleCount * sampleToUse * nextLine->commonClocksPerSample;
nextLine->commonClockCounter += missingSampleCount * nextLine->commonClocksPerSample;
missingClocks -= missingSampleCount * nextLine->commonClocksPerSample;
}
INT64 partialSample = sampleToUse * missingClocks;
//calculate the sample for this line
totalSample += (INT16)((nextLine->sampleBuffer + partialSample) / commonClocksPerTick);
//clear the sample buffer for this line
nextLine->sampleBuffer = -partialSample;
nextLine->commonClockCounter = -missingClocks;
}
if (audioProducerCount > 1) {
totalSample = totalSample / audioProducerCount;
}
sampleBuffer[sampleCount++] = totalSample;
if (sampleCount == sampleSize) {
flushAudio();
}
}
return minimum;
}
void AudioMixer::flushAudio()
{
//the platform subclass must copy the sampleBuffer to the device
//before calling here (which discards the contents of sampleBuffer)
sampleCount = 0;
}

View File

@ -0,0 +1,54 @@
#ifndef AUDIOMIXER_H
#define AUDIOMIXER_H
#include "AudioProducer.h"
#include "types.h"
#include "Processor.h"
#define MAX_AUDIO_PRODUCERS 10
template<typename A, typename W> class EmulatorTmpl;
class AudioMixer : public Processor
{
friend class ProcessorBus;
friend class AudioOutputLine;
public:
AudioMixer();
virtual ~AudioMixer();
inline INT16 clipSample(INT64 sample) {
return sample > 32767 ? 32767 : sample < -32768 ? -32768 : (INT16)sample;
}
virtual void resetProcessor();
INT32 getClockSpeed();
INT32 tick(INT32 minimum);
virtual void flushAudio();
//only to be called by the Emulator
virtual void init(UINT32 sampleRate);
virtual void release();
void addAudioProducer(AudioProducer*);
void removeAudioProducer(AudioProducer*);
void removeAll();
protected:
//output info
INT32 clockSpeed;
AudioProducer* audioProducers[MAX_AUDIO_PRODUCERS];
UINT32 audioProducerCount;
INT64 commonClocksPerTick;
INT16* sampleBuffer;
UINT32 sampleBufferSize;
UINT32 sampleCount;
UINT32 sampleSize;
};
#endif

View File

@ -0,0 +1,31 @@
#include "AudioOutputLine.h"
#include "AudioMixer.h"
AudioOutputLine::AudioOutputLine()
: sampleBuffer(0),
previousSample(0),
currentSample(0),
commonClockCounter(0),
commonClocksPerSample(0)
{}
void AudioOutputLine::reset()
{
sampleBuffer = 0;
previousSample = 0;
currentSample = 0;
commonClockCounter = 0;
commonClocksPerSample = 0;
}
void AudioOutputLine::playSample(INT16 sample)
{
sampleBuffer += currentSample * commonClocksPerSample;
commonClockCounter += commonClocksPerSample;
previousSample = currentSample;
currentSample = sample;
}

View File

@ -0,0 +1,29 @@
#ifndef AUDIOOUTPUTLINE_H
#define AUDIOOUTPUTLINE_H
#include "types.h"
class AudioOutputLine
{
friend class AudioMixer;
public:
void playSample(INT16 sample);
private:
AudioOutputLine();
void reset();
INT64 sampleBuffer;
INT64 previousSample;
INT64 currentSample;
INT64 commonClockCounter;
INT64 commonClocksPerSample;
};
#endif

View File

@ -0,0 +1,26 @@
#ifndef AUDIOPRODUCER_H
#define AUDIOPRODUCER_H
#include "AudioOutputLine.h"
/**
* This interface is implemented by any piece of hardware that produces audio.
*/
class AudioProducer
{
friend class AudioMixer;
public:
AudioProducer() : audioOutputLine(NULL) {}
virtual INT32 getClockSpeed() = 0;
virtual INT32 getClocksPerSample() = 0;
protected:
AudioOutputLine* audioOutputLine;
};
#endif

View File

@ -0,0 +1,79 @@
#include "BackTabRAM.h"
BackTabRAM::BackTabRAM()
: RAM(BACKTAB_SIZE, BACKTAB_LOCATION, 0xFFFF, 0xFFFF)
{}
void BackTabRAM::reset()
{
dirtyRAM = TRUE;
colorAdvanceBitsDirty = TRUE;
for (UINT16 i = 0; i < BACKTAB_SIZE; i++) {
image[i] = 0;
dirtyBytes[i] = TRUE;
}
}
UINT16 BackTabRAM::peek(UINT16 location)
{
return image[location-BACKTAB_LOCATION];
}
void BackTabRAM::poke(UINT16 location, UINT16 value)
{
value &= 0xFFFF;
location -= BACKTAB_LOCATION;
if (image[location] == value)
return;
if ((image[location] & 0x2000) != (value & 0x2000))
colorAdvanceBitsDirty = TRUE;
image[location] = value;
dirtyBytes[location] = TRUE;
dirtyRAM = TRUE;
}
void BackTabRAM::markClean() {
if (!dirtyRAM)
return;
for (UINT16 i = 0; i < BACKTAB_SIZE; i++)
dirtyBytes[i] = FALSE;
dirtyRAM = FALSE;
colorAdvanceBitsDirty = FALSE;
}
BOOL BackTabRAM::areColorAdvanceBitsDirty() {
return colorAdvanceBitsDirty;
}
BOOL BackTabRAM::isDirty() {
return dirtyRAM;
}
BOOL BackTabRAM::isDirty(UINT16 location) {
return dirtyBytes[location-BACKTAB_LOCATION];
}
BackTabRAMState BackTabRAM::getState()
{
BackTabRAMState state = {0};
state.RAMState = RAM::getState(state.image);
this->getImage(state.image, 0, this->getImageByteSize());
return state;
}
void BackTabRAM::setState(BackTabRAMState state, UINT16* image)
{
memset(this->dirtyBytes, TRUE, sizeof(this->dirtyBytes));
RAM::setState(state.RAMState, NULL);
this->setImage(state.image, 0, this->getImageByteSize());
this->dirtyRAM = TRUE;
this->colorAdvanceBitsDirty = TRUE;
}

View File

@ -0,0 +1,52 @@
#ifndef BACKTABRAM_H
#define BACKTABRAM_H
#include "RAM.h"
#define BACKTAB_SIZE 0xF0
#define BACKTAB_LOCATION 0x200
TYPEDEF_STRUCT_PACK(_BackTabRAMState
{
_RAMState RAMState;
UINT16 image[BACKTAB_SIZE];
} BackTabRAMState;)
class BackTabRAM : public RAM
{
public:
BackTabRAM();
void reset();
UINT16 peek(UINT16 location);
void poke(UINT16 location, UINT16 value);
BOOL areColorAdvanceBitsDirty();
BOOL isDirty();
BOOL isDirty(UINT16 location);
void markClean();
inline size_t getImageByteSize() {
return size * sizeof(UINT16);
}
void getImage(void* dst, UINT16 offset, UINT16 size) {
memcpy(dst, image + offset, size);
}
void setImage(void* src, UINT16 offset, UINT16 size) {
memcpy(image + offset, src, size);
}
BackTabRAMState getState();
void setState(BackTabRAMState state, UINT16* image);
private:
UINT16 image[BACKTAB_SIZE];
BOOL dirtyBytes[BACKTAB_SIZE];
BOOL dirtyRAM;
BOOL colorAdvanceBitsDirty;
};
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
#ifndef CP1610_H
#define CP1610_H
#include "Processor.h"
#include "SignalLine.h"
#include "MemoryBus.h"
#define CP1610_PIN_IN_INTRM 0
#define CP1610_PIN_IN_BUSRQ 1
#define CP1610_PIN_OUT_BUSAK 0
TYPEDEF_STRUCT_PACK( _CP1610State
{
INT8 S;
INT8 Z;
INT8 O;
INT8 C;
INT8 I;
INT8 D;
INT8 interruptible;
INT8 ext;
UINT16 interruptAddress;
UINT16 resetAddress;
UINT16 r[8];
} CP1610State; )
extern UINT8 interruptible;
class CP1610 : public Processor
{
public:
CP1610(MemoryBus* m, UINT16 resetAddress,
UINT16 interruptAddress);
//PowerConsumer functions
void resetProcessor();
//Processor functions
INT32 getClockSpeed();
INT32 tick(INT32);
BOOL isIdle() {
if (!pinIn[CP1610_PIN_IN_BUSRQ]->isHigh && interruptible) {
pinOut[CP1610_PIN_OUT_BUSAK]->isHigh = FALSE;
return TRUE;
}
else {
pinOut[CP1610_PIN_OUT_BUSAK]->isHigh = TRUE;
return FALSE;
}
}
#ifdef DEVELOPER_VERSION
UINT32 getDebugItemCount();
const CHAR* getDebugItemName(UINT32 i);
const UINT32 getDebugItemValue(UINT32 i);
//other debugging stuff
BOOL isCentralProcessor() { return TRUE; }
UINT32 decode(CHAR description[256], UINT32 memoryLocation);
UINT32 getProgramCounter();
#endif
CP1610State getState();
void setState(CP1610State state);
private:
void setIndirect(UINT16 register, UINT16 value);
UINT16 getIndirect(UINT16 register);
INT32 HLT();
INT32 SDBD();
INT32 EIS();
INT32 DIS();
INT32 TCI();
INT32 CLRC();
INT32 SETC();
INT32 J(UINT16 target);
INT32 JSR(UINT16 register, UINT16 target);
INT32 JE(UINT16 target);
INT32 JSRE(UINT16 register, UINT16 target);
INT32 JD(UINT16 target);
INT32 JSRD(UINT16 register, UINT16 target);
INT32 INCR(UINT16 register);
INT32 DECR(UINT16 register);
INT32 COMR(UINT16 register);
INT32 NEGR(UINT16 register);
INT32 ADCR(UINT16 register);
INT32 RSWD(UINT16 register);
INT32 GSWD(UINT16 register);
INT32 NOP(UINT16 twoOption);
INT32 SIN(UINT16 twoOption);
INT32 SWAP_1(UINT16 register);
INT32 SWAP_2(UINT16 register);
INT32 SLL_1(UINT16 register);
INT32 SLL_2(UINT16 register);
INT32 RLC_1(UINT16 register);
INT32 RLC_2(UINT16 register);
INT32 SLLC_1(UINT16 register);
INT32 SLLC_2(UINT16 register);
INT32 SLR_1(UINT16 register);
INT32 SLR_2(UINT16 register);
INT32 SAR_1(UINT16 register);
INT32 SAR_2(UINT16 register);
INT32 RRC_1(UINT16 register);
INT32 RRC_2(UINT16 register);
INT32 SARC_1(UINT16 register);
INT32 SARC_2(UINT16 register);
INT32 MOVR(UINT16 sourceReg, UINT16 destReg);
INT32 ADDR(UINT16 sourceReg, UINT16 destReg);
INT32 SUBR(UINT16 sourceReg, UINT16 destReg);
INT32 CMPR(UINT16 sourceReg, UINT16 destReg);
INT32 ANDR(UINT16 sourceReg, UINT16 destReg);
INT32 XORR(UINT16 sourceReg, UINT16 destReg);
INT32 BEXT(UINT16 condition, INT16 displacement);
INT32 B(INT16 displacement);
INT32 NOPP(INT16 displacement);
INT32 BC(INT16 displacement);
INT32 BNC(INT16 displacement);
INT32 BOV(INT16 displacement);
INT32 BNOV(INT16 displacement);
INT32 BPL(INT16 displacement);
INT32 BMI(INT16 displacement);
INT32 BEQ(INT16 displacement);
INT32 BNEQ(INT16 displacement);
INT32 BLT(INT16 displacement);
INT32 BGE(INT16 displacement);
INT32 BLE(INT16 displacement);
INT32 BGT(INT16 displacement);
INT32 BUSC(INT16 displacement);
INT32 BESC(INT16 displacement);
INT32 MVO(UINT16 register, UINT16 address);
INT32 MVO_ind(UINT16 registerWithAddress, UINT16 registerToMove);
INT32 MVI(UINT16 address, UINT16 register);
INT32 MVI_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
INT32 ADD(UINT16 address, UINT16 register);
INT32 ADD_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
INT32 SUB(UINT16 address, UINT16 register);
INT32 SUB_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
INT32 CMP(UINT16 address, UINT16 register);
INT32 CMP_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
INT32 AND(UINT16 address, UINT16 register);
INT32 AND_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
INT32 XOR(UINT16 address, UINT16 register);
INT32 XOR_ind(UINT16 registerWithAddress, UINT16 registerToReceive);
INT32 decode(void);
//the mory bus
MemoryBus* memoryBus;
//interrupt address
UINT16 interruptAddress;
//reset address
UINT16 resetAddress;
};
#endif

View File

@ -0,0 +1,102 @@
#include <stdio.h>
#include <string.h>
#include "CRC32.h"
#define CRC32_POLY 0x04C11DB7
//using namespace std;
#ifndef _MAX_PATH
#define _MAX_PATH 255
#endif
UINT64 reflect(UINT64 ref, char ch)
{
UINT64 value(0);
// Swap bit 0 for bit 7
// bit 1 for bit 6, etc.
for(int i = 1; i < (ch + 1); i++)
{
if(ref & 1)
value |= 1 << (ch - i);
ref >>= 1;
}
return value;
}
CRC32::CRC32() {
UINT32 i, j;
for (i = 0; i < 256; ++i) {
crc32_table[i]=(UINT32)(reflect(i, 8) << 24);
for (j = 0; j < 8; j++)
crc32_table[i] = (crc32_table[i] << 1) ^
(crc32_table[i] & (1 << 31) ? CRC32_POLY : 0);
crc32_table[i] = (UINT32)reflect(crc32_table[i], 32);
}
reset();
}
UINT32 CRC32::getCrc(const CHAR* filename)
{
CRC32 crc;
FILE* file = fopen(filename, "rb");
int read = fgetc(file);
while (read != EOF) {
crc.update((UINT8)read);
read = fgetc(file);
}
fclose(file);
return crc.getValue();
}
UINT32 CRC32::getCrc(UINT8* image, UINT32 imageSize)
{
CRC32 crc;
for (UINT32 i = 0; i < imageSize; i++)
crc.update(image[i]);
return crc.getValue();
}
/*
void CRC32::formInternalFilename(CHAR* out, const CHAR* in, const CHAR* ext)
{
strcpy(out, in);
char *p = strstr(out, ".zip");
*p = '\0';
strcat(out, ext);
p = &out[strlen((char *)out)];
while(--p > out)
{
if(*p == '\\' || *p == '/')
break;
}
strcpy(out, p+1);
}
*/
void CRC32::reset() {
crc = 0xFFFFFFFF;
}
void CRC32::update(UINT8 data) {
crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ data];
}
void CRC32::update(UINT8* data, UINT32 length) {
for (UINT32 i = 0; i < length; i++)
//crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ data[i]];
crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ data[i]];
}
UINT32 CRC32::getValue() {
return ~crc;
}

View File

@ -0,0 +1,28 @@
#ifndef CRC32_H
#define CRC32_H
#include "types.h"
class CRC32
{
public:
CRC32();
void reset();
void update(UINT8 data);
void update(UINT8* data, UINT32 length);
UINT32 getValue();
static UINT32 getCrc(const CHAR* filename);
static UINT32 getCrc(UINT8* image, UINT32 imageSize);
private:
//static void formInternalFilename(CHAR*, const CHAR*, const CHAR*);
UINT32 crc;
UINT32 crc32_table[256];
};
#endif

View File

@ -0,0 +1,51 @@
#include <iostream>
#include "ECS.h"
ECS::ECS()
: Peripheral("Electronic Computer System", "ECS"),
keyboard(2),
ramBank(ECS_RAM_SIZE, 0x4000, 8),
uart(4, 0xE0, 8),
psg2(0x00F0, &keyboard, &keyboard),
bank0("ECS ROM #1", "ecs.bin", 0, 2, 0x1000, 0x2000),
bank0Banker(&bank0, 0x2FFF, 0xFFF0, 0x2A50, 0x000F, 1),
bank1("ECS ROM #2", "ecs.bin", 8192, 2, 0x1000, 0x7000),
bank1Banker(&bank1, 0x7FFF, 0xFFF0, 0x7A50, 0x000F, 0),
bank2("ECS ROM #3", "ecs.bin", 16384, 2, 0x1000, 0xE000),
bank2Banker(&bank2, 0xEFFF, 0xFFF0, 0xEA50, 0x000F, 1)
{
AddROM(&bank0);
AddRAM(&bank0Banker);
AddROM(&bank1);
AddRAM(&bank1Banker);
AddROM(&bank2);
AddRAM(&bank2Banker);
AddRAM(&ramBank);
AddRAM(&uart);
AddProcessor(&psg2);
AddAudioProducer(&psg2);
AddRAM(&psg2.registers);
AddInputConsumer(&keyboard);
}
ECSState ECS::getState()
{
ECSState state = {0};
state.ramState = ramBank.getState(state.ramImage);
state.uartState = uart.getState(NULL);
state.psg2State = psg2.getState();
return state;
}
void ECS::setState(ECSState state)
{
ramBank.setState(state.ramState, state.ramImage);
uart.setState(state.uartState, NULL);
psg2.setState(state.psg2State);
}

53
arm9/source/emucore/ECS.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef ECS_H
#define ECS_H
#include "Peripheral.h"
#include "ECSKeyboard.h"
#include "AudioOutputLine.h"
#include "RAM.h"
#include "ROM.h"
#include "ROMBanker.h"
#include "types.h"
#include "AY38914.h"
#define ECS_RAM_SIZE 0x0800
TYPEDEF_STRUCT_PACK( _ECSState
{
RAMState ramState;
UINT16 ramImage[ECS_RAM_SIZE];
RAMState uartState;
AY38914State psg2State;
} ECSState; )
class Intellivision;
class ECS : public Peripheral
{
friend class Intellivision;
public:
ECS();
ECSState getState();
void setState(ECSState state);
private:
ECSKeyboard keyboard;
public:
ROM bank0;
ROMBanker bank0Banker;
ROM bank1;
ROMBanker bank1Banker;
ROM bank2;
ROMBanker bank2Banker;
RAM ramBank;
RAM uart;
AY38914 psg2;
};
#endif

View File

@ -0,0 +1,85 @@
#include "ECSKeyboard.h"
const INT32 ECSKeyboard::sortedObjectIndices[NUM_ECS_OBJECTS] = {
24, 29, 34, 28, 33, 27, 32, 26, 31, 25, 30, // ESCAPE, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0
23, 22, 40, 21, 39, 20, 38, 19, 37, 18, // Q, W, E, R, T, Y, U, I, O, P
46, 16, 45, 15, 44, 14, 43, 13, 42, 12, 36, // A, S, D, F, G, H, J, K, L, SEMICOLON, ENTER
10, 4, 9, 3, 8, 2, 7, 1, 6, // Z, X, C, V, B, N, M, COMMA, PERIOD
41, 47, 5, // CTRL, SHIFT, SPACE,
17, 11, 0, 35, // UP, DOWN, LEFT, RIGHT
};
ECSKeyboard::ECSKeyboard(INT32 id)
: InputConsumer(id),
rowsToScan(0)
{
memset(rowInputValues, 0, sizeof(rowInputValues));
}
ECSKeyboard::~ECSKeyboard()
{
}
INT32 ECSKeyboard::getInputConsumerObjectCount()
{
return 0;
}
InputConsumerObject* ECSKeyboard::getInputConsumerObject(INT32 i)
{
return NULL;
}
void ECSKeyboard::resetInputConsumer()
{
rowsToScan = 0;
for (UINT16 i = 0; i < 8; i++)
rowInputValues[i] = 0;
}
void ECSKeyboard::evaluateInputs()
{
for (UINT16 row = 0; row < 6; row++)
{
rowInputValues[row] = 0;
if (inputConsumerObjects[row]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x01;
if (inputConsumerObjects[row+6]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x02;
if (inputConsumerObjects[row+12]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x04;
if (inputConsumerObjects[row+18]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x08;
if (inputConsumerObjects[row+24]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x10;
if (inputConsumerObjects[row+30]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x20;
if (inputConsumerObjects[row+36]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x40;
if (inputConsumerObjects[row+42]->getInputValue() == 1.0f)
rowInputValues[row] |= 0x80;
}
rowInputValues[6] = (inputConsumerObjects[47]->getInputValue() == 1.0f ? 0x80 : 0);
}
UINT16 ECSKeyboard::getInputValue()
{
UINT16 inputValue = 0;
UINT16 rowMask = 1;
for (UINT16 row = 0; row < 8; row++) {
if ((rowsToScan & rowMask) != 0) {
rowMask = (UINT16)(rowMask << 1);
continue;
}
inputValue |= rowInputValues[row];
rowMask = (UINT16)(rowMask << 1);
}
return (UINT16)(0xFF ^ inputValue);
}
void ECSKeyboard::setOutputValue(UINT16 value) {
this->rowsToScan = value;
}

View File

@ -0,0 +1,49 @@
#ifndef ECSKEYBOARD_H
#define ECSKEYBOARD_H
#define NUM_ECS_OBJECTS 48
#include "AY38914_InputOutput.h"
#include "InputConsumer.h"
class EmulationDirector;
class ECSKeyboard : public AY38914_InputOutput, public InputConsumer
{
friend class EmulationDirector;
public:
ECSKeyboard(INT32 id);
virtual ~ECSKeyboard();
const CHAR* getName() { return "ECS Keyboard"; }
void resetInputConsumer();
/**
* Poll the controller. This function is invoked by the
* InputConsumerBus just after the Emulator indicates it has entered
* vertical blank.
*/
void evaluateInputs();
//functions to get descriptive info about the input consumer
INT32 getInputConsumerObjectCount();
InputConsumerObject* getInputConsumerObject(INT32 i);
UINT16 getInputValue();
void setOutputValue(UINT16 value);
private:
InputConsumerObject* inputConsumerObjects[NUM_ECS_OBJECTS];
UINT16 rowsToScan;
UINT16 rowInputValues[8];
static const INT32 sortedObjectIndices[NUM_ECS_OBJECTS];
};
#endif

View File

@ -0,0 +1,264 @@
#include "Emulator.h"
#include "Intellivision.h"
extern UINT32 systemIDs[NUM_EMULATORS];
extern Emulator* emus[NUM_EMULATORS];
UINT32 Emulator::GetEmulatorCount()
{
return NUM_EMULATORS;
}
Emulator* Emulator::GetEmulator(UINT32 i)
{
return emus[i];
}
Emulator* Emulator::GetEmulatorByID(UINT32 targetSystemID)
{
for (int i = 0; i < NUM_EMULATORS; i++) {
if (systemIDs[i] == targetSystemID)
return emus[i];
}
return NULL;
}
Emulator::Emulator(const char* name)
: Peripheral(name, name),
currentRip(NULL),
peripheralCount(0)
{
memset(peripherals, 0, sizeof(peripherals));
memset(usePeripheralIndicators, FALSE, sizeof(usePeripheralIndicators));
printf("Emulator [%s] Constructed\n", name);
}
void Emulator::AddPeripheral(Peripheral* p)
{
peripherals[peripheralCount] = p;
printf(" Peripheral [%d] Added\n", peripheralCount);
peripheralCount++;
}
UINT32 Emulator::GetPeripheralCount()
{
return peripheralCount;
}
Peripheral* Emulator::GetPeripheral(UINT32 i)
{
return peripherals[i];
}
void Emulator::UsePeripheral(UINT32 i, BOOL b)
{
usePeripheralIndicators[i] = b;
}
UINT32 Emulator::GetVideoWidth()
{
return videoWidth;
}
UINT32 Emulator::GetVideoHeight()
{
return videoHeight;
}
void Emulator::InitVideo(VideoBus* video, UINT32 width, UINT32 height)
{
if ( video != NULL ) {
videoBus = video;
}
videoBus->init(width, height);
}
void Emulator::ReleaseVideo()
{
if (videoBus) {
videoBus->release();
videoBus = NULL;
}
}
void Emulator::InitAudio(AudioMixer* audio, UINT32 sampleRate)
{
if (audio != NULL) {
audioMixer = audio;
}
// TODO: check for an existing audioMixer processor and release it
for (UINT16 i = 0; i < GetProcessorCount(); i++) {
Processor* p = GetProcessor(i);
if (p == audio) {
RemoveProcessor(audio);
}
}
AddProcessor(audioMixer);
audioMixer->init(sampleRate);
}
void Emulator::ReleaseAudio()
{
if (audioMixer) {
audioMixer->release();
RemoveProcessor(audioMixer);
audioMixer = NULL;
}
}
void Emulator::Reset()
{
processorBus.reset();
memoryBus.reset();
}
void Emulator::SetRip(Rip* rip)
{
if (this->currentRip != NULL) {
processorBus.removeAll();
memoryBus.removeAll();
videoBus->removeAll();
audioMixer->removeAll();
inputConsumerBus.removeAll();
}
currentRip = rip;
//TODO: use the desired peripheral configuration specified by the rip
if (this->currentRip != NULL) {
InsertPeripheral(this);
//use the desired peripherals
for (INT32 i = 0; i < peripheralCount; i++) {
if (usePeripheralIndicators[i])
InsertPeripheral(peripherals[i]);
}
InsertPeripheral(currentRip);
}
}
void Emulator::InsertPeripheral(Peripheral* p)
{
UINT16 i;
printf(" Peripheral Inserted: [%s]\n", p->GetName());
printf(" Processors [%d]\n", p->GetProcessorCount());
//processors
UINT16 count = p->GetProcessorCount();
for (i = 0; i < count; i++)
{
printf(" [%s]\n", p->GetProcessor(i)->getName());
processorBus.addProcessor(p->GetProcessor(i));
}
printf(" RAM [%d]\n", p->GetRAMCount());
//RAM
count = p->GetRAMCount();
for (i = 0; i < count; i++)
{
printf(" @ [%04X] Size [%04X]\n", p->GetRAM(i)->getReadAddress(), p->GetRAM(i)->getReadSize());
memoryBus.addMemory(p->GetRAM(i));
}
printf(" ROM [%d]\n", p->GetROMCount());
//ROM
count = p->GetROMCount();
for (i = 0; i < count; i++)
{
ROM* nextRom = p->GetROM(i);
printf(" [%s] @ [%04X] Size [%04X]\n", nextRom->getName(), nextRom->getReadAddress(), nextRom->getReadSize());
if (!nextRom->isInternal())
memoryBus.addMemory(nextRom);
}
printf(" VIDEO PRODUCERS [%d]\n", p->GetVideoProducerCount());
//video producers
count = p->GetVideoProducerCount();
for (i = 0; i < count; i++)
videoBus->addVideoProducer(p->GetVideoProducer(i));
printf(" AUDIO PRODUCERS [%d]\n", p->GetAudioProducerCount());
//audio producers
count = p->GetAudioProducerCount();
for (i = 0; i < count; i++)
audioMixer->addAudioProducer(p->GetAudioProducer(i));
printf(" INPUT CONSUMERS [%d]\n", p->GetInputConsumerCount());
//input consumers
count = p->GetInputConsumerCount();
for (i = 0; i < count; i++)
{
inputConsumerBus.addInputConsumer(p->GetInputConsumer(i));
printf(" [%s]\n", p->GetInputConsumer(i)->getName());
}
printf(" Peripherals Done\n");
}
void Emulator::RemovePeripheral(Peripheral* p)
{
UINT16 i;
//processors
UINT16 count = p->GetProcessorCount();
for (i = 0; i < count; i++)
processorBus.removeProcessor(p->GetProcessor(i));
//RAM
count = p->GetRAMCount();
for (i = 0; i < count; i++)
memoryBus.removeMemory(p->GetRAM(i));
//ROM
count = p->GetROMCount();
for (i = 0; i < count; i++)
memoryBus.removeMemory(p->GetROM(i));
//video producers
count = p->GetVideoProducerCount();
for (i = 0; i < count; i++)
videoBus->removeVideoProducer(p->GetVideoProducer(i));
//audio producers
count = p->GetAudioProducerCount();
for (i = 0; i < count; i++)
audioMixer->removeAudioProducer(p->GetAudioProducer(i));
//input consumers
count = p->GetInputConsumerCount();
for (i = 0; i < count; i++)
inputConsumerBus.removeInputConsumer(p->GetInputConsumer(i));
}
void Emulator::Run()
{
inputConsumerBus.evaluateInputs();
processorBus.run();
}
void Emulator::Render()
{
videoBus->render();
}
void Emulator::FlushAudio()
{
audioMixer->flushAudio();
}
UINT32 Emulator::systemIDs[NUM_EMULATORS] = {
ID_SYSTEM_INTELLIVISION,
};
Intellivision Emulator::inty;
Emulator* Emulator::emus[] = {
&inty,
};

View File

@ -0,0 +1,110 @@
#ifndef EMULATOR_H
#define EMULATOR_H
#include "Peripheral.h"
#include "types.h"
#include "Rip.h"
#include "ProcessorBus.h"
#include "Processor.h"
#include "AudioMixer.h"
#include "AudioProducer.h"
#include "InputConsumerBus.h"
#include "InputConsumer.h"
#include "VideoBus.h"
#include "VideoProducer.h"
#include "MemoryBus.h"
#include "Memory.h"
typedef struct _StateHeader
{
UINT32 emu;
UINT32 state;
UINT32 emuID;
UINT32 version;
UINT32 sys;
UINT32 sysID;
UINT32 cart;
UINT32 cartID;
} StateHeader;
typedef struct _StateChunk
{
UINT32 id;
UINT32 size;
} StateChunk;
#if defined(DEBUG)
#define EMU_STATE_VERSION ('dev\0')
#else
#define EMU_STATE_VERSION (0x02010000)
#endif
class Intellivision;
#define MAX_PERIPHERALS 16
#define NUM_EMULATORS 1
/**
*
*/
class Emulator : public Peripheral
{
public:
void AddPeripheral(Peripheral* p);
UINT32 GetPeripheralCount();
Peripheral* GetPeripheral(UINT32);
UINT32 GetVideoWidth();
UINT32 GetVideoHeight();
void UsePeripheral(UINT32, BOOL);
void SetRip(Rip* rip);
void InitVideo(VideoBus* video, UINT32 width, UINT32 height);
void ReleaseVideo();
void InitAudio(AudioMixer* audio, UINT32 sampleRate);
void ReleaseAudio();
void Reset();
void Run();
void FlushAudio();
void Render();
virtual BOOL SaveState(const CHAR* filename) = 0;
virtual BOOL LoadState(const CHAR* filename) = 0;
static UINT32 GetEmulatorCount();
static Emulator* GetEmulator(UINT32 i);
static Emulator* GetEmulatorByID(UINT32 targetSystemID);
protected:
Emulator(const char* name);
MemoryBus memoryBus;
Rip* currentRip;
UINT32 videoWidth;
UINT32 videoHeight;
private:
ProcessorBus processorBus;
AudioMixer *audioMixer;
VideoBus *videoBus;
InputConsumerBus inputConsumerBus;
void InsertPeripheral(Peripheral* p);
void RemovePeripheral(Peripheral* p);
Peripheral* peripherals[MAX_PERIPHERALS];
BOOL usePeripheralIndicators[MAX_PERIPHERALS];
INT32 peripheralCount;
static UINT32 systemIDs[NUM_EMULATORS];
static Emulator* emus[NUM_EMULATORS];
static Intellivision inty;
};
#endif

View File

@ -0,0 +1,79 @@
#include <nds.h>
#include "GRAM.h"
#define GRAM_ADDRESS 0x3800
#define GRAM_READ_MASK 0xF9FF
#define GRAM_WRITE_MASK 0x39FF
UINT8 gram_image[GRAM_SIZE] __attribute__((section(".dtcm")));
UINT8 dirtyCards[GRAM_SIZE>>3] __attribute__((section(".dtcm")));
UINT8 dirtyRAM __attribute__((section(".dtcm")));
GRAM::GRAM()
: RAM(GRAM_SIZE, GRAM_ADDRESS, GRAM_READ_MASK, GRAM_WRITE_MASK)
{}
void GRAM::reset()
{
UINT16 i;
dirtyRAM = TRUE;
for (i = 0; i < GRAM_SIZE; i++)
gram_image[i] = 0;
for (i = 0; i < 0x40; i++)
dirtyCards[i] = TRUE;
}
void GRAM::poke(UINT16 location, UINT16 value)
{
location &= 0x01FF;
//value &= 0xFF;
gram_image[location] = (UINT8)value;
dirtyCards[location>>3] = TRUE;
dirtyRAM = TRUE;
}
void GRAM::markClean() {
if (!dirtyRAM)
return;
for (UINT16 i = 0; i < 0x40; i++)
dirtyCards[i] = FALSE;
dirtyRAM = FALSE;
}
BOOL GRAM::isDirty() {
return dirtyRAM;
}
BOOL GRAM::isCardDirty(UINT16 cardLocation) {
return dirtyCards[cardLocation>>3];
}
RAMState GRAM::getState(UINT16* image)
{
RAMState state = {0};
#if 0
state = RAM::getState(NULL);
if (image != NULL) {
this->getImage(image, 0, this->getImageByteSize());
}
#endif
return state;
}
void GRAM::setState(RAMState state, UINT16* image)
{
#if 0
RAM::setState(state, NULL);
if (image != NULL) {
this->setImage(image, 0, this->getImageByteSize());
}
memset(this->dirtyCards, TRUE, sizeof(this->dirtyCards));
this->dirtyRAM = TRUE;
#endif
}

View File

@ -0,0 +1,44 @@
#ifndef GRAM_H
#define GRAM_H
#include "RAM.h"
#define GRAM_SIZE 0x0200
extern UINT8 gram_image[GRAM_SIZE];
extern UINT8 dirtyCards[GRAM_SIZE>>3];
extern UINT8 dirtyRAM;
class GRAM : public RAM
{
friend class AY38900;
public:
GRAM();
void reset();
inline UINT16 peek(UINT16 location) {return gram_image[location & 0x01FF];}
void poke(UINT16 location, UINT16 value);
void markClean();
BOOL isDirty();
BOOL isCardDirty(UINT16 cardLocation);
inline size_t getImageByteSize() {
return size * sizeof(UINT16);
}
void getImage(void* dst, UINT16 offset, UINT16 size) {
memcpy(dst, gram_image + offset, size);
}
void setImage(void* src, UINT16 offset, UINT16 size) {
memcpy(gram_image + offset, src, size);
}
RAMState getState(UINT16* image);
void setState(RAMState state, UINT16* image);
private:
};
#endif

View File

@ -0,0 +1,15 @@
#include "GROM.h"
GROM::GROM()
: ROM("GROM", "grom.bin", 0, 1, GROM_SIZE, GROM_ADDRESS)
{}
void GROM::reset()
{
visible = TRUE;
}

View File

@ -0,0 +1,27 @@
#ifndef GROM_H
#define GROM_H
#include "Memory.h"
#include "ROM.h"
#define GROM_SIZE 0x0800
#define GROM_ADDRESS 0x3000
class GROM : public ROM
{
friend class AY38900;
public:
GROM();
void reset();
inline UINT16 peek(UINT16 location) {return ROM::peek(location);}
private:
BOOL visible;
};
#endif

View File

@ -0,0 +1,107 @@
#include "HandController.h"
#include "Intellivision.h"
const UINT16 HandController::BUTTON_OUTPUT_VALUES[15] = {
0x81, //OUTPUT_KEYPAD_ONE
0x41, //OUTPUT_KEYPAD_TWO
0x21, //OUTPUT_KEYPAD_THREE
0x82, //OUTPUT_KEYPAD_FOUR
0x42, //OUTPUT_KEYPAD_FIVE
0x22, //OUTPUT_KEYPAD_SIX
0x84, //OUTPUT_KEYPAD_SEVEN
0x44, //OUTPUT_KEYPAD_EIGHT
0x24, //OUTPUT_KEYPAD_NINE
0x88, //OUTPUT_KEYPAD_CLEAR
0x48, //OUTPUT_KEYPAD_ZERO
0x28, //OUTPUT_KEYPAD_ENTER
0xA0, //OUTPUT_ACTION_BUTTON_TOP
0x60, //OUTPUT_ACTION_BUTTON_BOTTOM_LEFT
0xC0 //OUTPUT_ACTION_BUTTON_BOTTOM_RIGHT
};
const UINT16 HandController::DIRECTION_OUTPUT_VALUES[16] = {
0x04, //OUTPUT_DISC_NORTH
0x14, //OUTPUT_DISC_NORTH_NORTH_EAST
0x16, //OUTPUT_DISC_NORTH_EAST
0x06, //OUTPUT_DISC_EAST_NORTH_EAST
0x02, //OUTPUT_DISC_EAST
0x12, //OUTPUT_DISC_EAST_SOUTH_EAST
0x13, //OUTPUT_DISC_SOUTH_EAST
0x03, //OUTPUT_DISC_SOUTH_SOUTH_EAST
0x01, //OUTPUT_DISC_SOUTH
0x11, //OUTPUT_DISC_SOUTH_SOUTH_WEST
0x19, //OUTPUT_DISC_SOUTH_WEST
0x09, //OUTPUT_DISC_WEST_SOUTH_WEST
0x08, //OUTPUT_DISC_WEST
0x18, //OUTPUT_DISC_WEST_NORTH_WEST
0x1C, //OUTPUT_DISC_NORTH_WEST
0x0C //OUTPUT_DISC_NORTH_NORTH_WEST
};
HandController::HandController(INT32 id, const CHAR* n)
: InputConsumer(id),
name(n)
{
}
HandController::~HandController()
{
}
INT32 HandController::getInputConsumerObjectCount()
{
return 0;
}
InputConsumerObject* HandController::getInputConsumerObject(INT32 i)
{
return NULL;
}
int ds_key_input[16] = {0}; // Set to '1' if pressed... 0 if released
int ds_disc_input[16] = {0}; // Set to '1' if pressed... 0 if released.
void HandController::evaluateInputs()
{
inputValue = 0;
bool keypad_active = false;
// TODO: this is a bit of a hack... setup 2 sets of inputs or don't instantiate the 2nd controller...
if (strcmp(name, "Hand Controller #1") == 0)
{
for (UINT16 i = 0; i < 15; i++)
{
if (ds_key_input[i])
{
if (i <= 11) keypad_active=true;
inputValue |= BUTTON_OUTPUT_VALUES[i];
}
}
// Keypad has priority over disc...
if (!keypad_active)
{
for (UINT16 i = 0; i < 16; i++)
{
if (ds_disc_input[i]) inputValue |= DIRECTION_OUTPUT_VALUES[i];
}
}
}
inputValue = (UINT16)(0xFF ^ inputValue);
}
void HandController::resetInputConsumer()
{
inputValue = 0xFF;
}
void HandController::setOutputValue(UINT16)
{}
UINT16 HandController::getInputValue()
{
return inputValue;
}

View File

@ -0,0 +1,77 @@
#ifndef HANDCONTROLLER_H
#define HANDCONTROLLER_H
#define NUM_HAND_CONTROLLER_OBJECTS 23
#include "AY38914_InputOutput.h"
#include "InputConsumer.h"
class HandController : public AY38914_InputOutput, public InputConsumer
{
public:
HandController(INT32 id, const CHAR* n);
virtual ~HandController();
const CHAR* getName() { return name; }
void resetInputConsumer();
/**
* Poll the controller. This function is invoked by the
* InputConsumerBus just after the Emulator indicates it has entered
* vertical blank.
*/
void evaluateInputs();
//functions to get descriptive info about the input consumer
INT32 getInputConsumerObjectCount();
InputConsumerObject* getInputConsumerObject(INT32 i);
void setOutputValue(UINT16 value);
UINT16 getInputValue();
private:
const CHAR* name;
InputConsumerObject* inputConsumerObjects[NUM_HAND_CONTROLLER_OBJECTS];
UINT16 inputValue;
static const UINT16 BUTTON_OUTPUT_VALUES[15];
static const UINT16 DIRECTION_OUTPUT_VALUES[16];
};
// jeremiah sypult
enum
{
CONTROLLER_DISC_DOWN = 0x01,
CONTROLLER_DISC_RIGHT = 0x02,
CONTROLLER_DISC_UP = 0x04,
CONTROLLER_DISC_LEFT = 0x08,
CONTROLLER_DISC_WIDE = 0x10,
CONTROLLER_DISC_UP_LEFT = 0x1C,
CONTROLLER_DISC_UP_RIGHT = 0x16,
CONTROLLER_DISC_DOWN_LEFT = 0x19,
CONTROLLER_DISC_DOWN_RIGHT = 0x13,
CONTROLLER_KEYPAD_ONE = 0x81,
CONTROLLER_KEYPAD_TWO = 0x41,
CONTROLLER_KEYPAD_THREE = 0x21,
CONTROLLER_KEYPAD_FOUR = 0x82,
CONTROLLER_KEYPAD_FIVE = 0x42,
CONTROLLER_KEYPAD_SIX = 0x22,
CONTROLLER_KEYPAD_SEVEN = 0x84,
CONTROLLER_KEYPAD_EIGHT = 0x44,
CONTROLLER_KEYPAD_NINE = 0x24,
CONTROLLER_KEYPAD_CLEAR = 0x88,
CONTROLLER_KEYPAD_ZERO = 0x48,
CONTROLLER_KEYPAD_ENTER = 0x28,
CONTROLLER_ACTION_TOP = 0xA0,
CONTROLLER_ACTION_BOTTOM_LEFT = 0x60,
CONTROLLER_ACTION_BOTTOM_RIGHT = 0xC0
};
#endif

View File

@ -0,0 +1,42 @@
#ifndef INPUTCONSUMER_H
#define INPUTCONSUMER_H
#include "InputConsumerObject.h"
#include "types.h"
/**
* A InputConsumer is a gaming input device, such as the hand controllers for
* the Intellivision and Atari 5200 or the joysticks and paddles for the
* Atari2600.
*/
class InputConsumer
{
friend class InputConsumerBus;
public:
InputConsumer(INT32 i) : id(i) {}
INT32 getId() { return id; }
virtual const CHAR* getName() = 0;
virtual void resetInputConsumer() = 0;
/**
* Poll the controller. This function is invoked by the
* InputConsumerBus just after the Emulator indicates it has entered
* vertical blank.
*/
virtual void evaluateInputs() = 0;
//functions to get descriptive info about the input consumer
virtual INT32 getInputConsumerObjectCount() = 0;
virtual InputConsumerObject* getInputConsumerObject(INT32 i) = 0;
private:
INT32 id;
};
#endif

View File

@ -0,0 +1,46 @@
#include "stdio.h"
#include "InputConsumerBus.h"
InputConsumerBus::InputConsumerBus()
{
inputConsumerCount = 0;
}
void InputConsumerBus::addInputConsumer(InputConsumer* p)
{
inputConsumers[inputConsumerCount] = p;
inputConsumerCount++;
}
void InputConsumerBus::removeInputConsumer(InputConsumer* p)
{
for (UINT32 i = 0; i < inputConsumerCount; i++) {
if (inputConsumers[i] == p) {
for (UINT32 j = i; j < (inputConsumerCount-1); j++)
inputConsumers[j] = inputConsumers[j+1];
inputConsumerCount--;
return;
}
}
}
void InputConsumerBus::removeAll()
{
while (inputConsumerCount)
removeInputConsumer(inputConsumers[0]);
}
void InputConsumerBus::reset()
{
for (UINT32 i = 0; i < inputConsumerCount; i++)
inputConsumers[i]->resetInputConsumer();
}
void InputConsumerBus::evaluateInputs()
{
//tell each of the input consumers that they may now pull their data from
//the input device
for (UINT32 i = 0; i < inputConsumerCount; i++)
inputConsumers[i]->evaluateInputs();
}

View File

@ -0,0 +1,27 @@
#ifndef INPUTCONSUMERBUS_H
#define INPUTCONSUMERBUS_H
#include "InputConsumer.h"
const INT32 MAX_INPUT_CONSUMERS = 10;
class InputConsumerBus
{
public:
InputConsumerBus();
void reset();
void evaluateInputs();
void addInputConsumer(InputConsumer* ic);
void removeInputConsumer(InputConsumer* ic);
void removeAll();
private:
InputConsumer* inputConsumers[MAX_INPUT_CONSUMERS];
UINT32 inputConsumerCount;
};
#endif

View File

@ -0,0 +1,65 @@
#include <stdio.h>
#include <string.h>
// TODO: jeremiah sypult cross-platform
#if defined( _WIN32 )
#include <dinput.h>
#endif
#include "InputConsumerObject.h"
InputConsumerObject::InputConsumerObject(INT32 i, const CHAR* n, GUID ddg, INT32 doid)
: id(i),
name(n),
defaultDeviceGuid(ddg),
defaultObjectID(doid),
bindingCount(0)
{
memset(producerBindings, 0, sizeof(producerBindings));
memset(objectIDBindings, 0, sizeof(objectIDBindings));
memset(subBindingCounts, 0, sizeof(subBindingCounts));
}
InputConsumerObject::~InputConsumerObject()
{
clearBindings();
}
void InputConsumerObject::addBinding(InputProducer** producers, INT32* objectids, INT32 count)
{
if (bindingCount >= MAX_BINDINGS)
return;
producerBindings[bindingCount] = new InputProducer*[count];
memcpy(producerBindings[bindingCount], producers, sizeof(InputProducer*)*count);
objectIDBindings[bindingCount] = new INT32[count];
memcpy(objectIDBindings[bindingCount], objectids, sizeof(INT32)*count);
subBindingCounts[bindingCount] = count;
bindingCount++;
}
void InputConsumerObject::clearBindings()
{
for (INT32 i = 0; i < bindingCount; i++) {
delete[] producerBindings[i];
delete[] objectIDBindings[i];
}
memset(producerBindings, 0, sizeof(producerBindings));
memset(objectIDBindings, 0, sizeof(objectIDBindings));
memset(subBindingCounts, 0, sizeof(subBindingCounts));
bindingCount = 0;
}
float InputConsumerObject::getInputValue()
{
float value = 0.0f;
for (INT32 i = 0; i < bindingCount; i++) {
float nextValue = 1.0f;
for (INT32 j = 0; j < subBindingCounts[i]; j++) {
float v = producerBindings[i][j]->getValue(objectIDBindings[i][j]);
nextValue = (nextValue < v ? nextValue : v);
}
value = (value != 0 && value > nextValue ? value : nextValue);
}
return value;
}

View File

@ -0,0 +1,53 @@
#ifndef INPUTCONSUMEROBJECT_H
#define INPUTCONSUMEROBJECT_H
#include "InputProducer.h"
#include "types.h"
#define MAX_BINDINGS 10
class InputConsumerObject
{
friend class InputConsumer;
public:
InputConsumerObject(INT32 id, const CHAR* name, GUID defaultDeviceGuid, INT32 defaultObjectID);
virtual ~InputConsumerObject();
INT32 getId() { return id; }
const CHAR* getName() { return name; }
GUID getDefaultDeviceGuid() { return defaultDeviceGuid; }
INT32 getDefaultEnum() { return defaultObjectID; }
INT32 getBindingCount() { return bindingCount; }
INT32 getSubBindingCount(INT32 i) { return subBindingCounts[i]; }
InputProducer* getSubBindingProducer(INT32 i, INT32 j) { return producerBindings[i][j]; }
INT32 getSubBindingEnum(INT32 i, INT32 j) { return objectIDBindings[i][j]; }
void addBinding(InputProducer** producer, INT32* objectid, INT32 count);
void clearBindings();
float getInputValue();
private:
INT32 id;
const CHAR* name;
GUID defaultDeviceGuid;
INT32 defaultObjectID;
InputProducer** producerBindings[MAX_BINDINGS];
INT32* objectIDBindings[MAX_BINDINGS];
INT32 subBindingCounts[MAX_BINDINGS];
INT32 bindingCount;
};
#endif

View File

@ -0,0 +1,38 @@
#ifndef INPUTPRODUCER_H
#define INPUTPRODUCER_H
// TODO: jeremiah sypult cross-platform
#if defined( _WIN32 )
#include <dinput.h>
#endif
#include "types.h"
class InputProducer
{
public:
InputProducer(GUID g) : guid(g) {}
GUID getGuid() { return guid; }
virtual const CHAR* getName() = 0;
// TODO: jeremiah sypult cross-platform
#if defined( _WIN32 )
virtual IDirectInputDevice8* getDevice() = 0;
#endif
virtual void poll() = 0;
virtual INT32 getInputCount() = 0;
virtual const CHAR* getInputName(INT32) = 0;
virtual float getValue(INT32 enumeration) = 0;
virtual BOOL isKeyboardDevice() = 0;
private:
GUID guid;
};
#endif

View File

@ -0,0 +1,60 @@
#include <stdio.h>
#include <string.h>
#include "InputProducerManager.h"
#if defined( _WIN32 )
InputProducerManager::InputProducerManager(HWND w)
: wnd(w)
{
DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&directInput, NULL);
}
#endif
InputProducerManager::~InputProducerManager()
{
#if defined( _WIN32 )
directInput->Release();
#endif
}
#if defined( _WIN32 )
IDirectInput8* InputProducerManager::getDevice()
{
return directInput;
}
#endif
InputProducer* InputProducerManager::acquireInputProducer(GUID deviceGuid)
{
return NULL;
}
INT32 InputProducerManager::getAcquiredInputProducerCount()
{
return (INT32)devices.size();
}
InputProducer* InputProducerManager::getAcquiredInputProducer(INT32 i)
{
return devices[i];
}
void InputProducerManager::pollInputProducers()
{
for (vector<InputProducer*>::iterator it = devices.begin(); it < devices.end(); it++)
(*it)->poll();
}
void InputProducerManager::releaseInputProducers()
{
for (vector<InputProducer*>::iterator it = devices.begin(); it < devices.end(); it++) {
#if defined( _WIN32 )
IDirectInputDevice8* nextDevice = (*it)->getDevice();
nextDevice->Unacquire();
nextDevice->Release();
delete (*it);
#endif
}
devices.clear();
}

View File

@ -0,0 +1,43 @@
#ifndef INPUTPRODUCERMANAGER_H
#define INPUTPRODUCERMANAGER_H
// TODO: jeremiah sypult cross-platform
#if defined( _WIN32 )
#include <windows.h>
#include <dinput.h>
#endif
#include "InputProducer.h"
#include <vector>
using namespace std;
class InputProducerManager
{
public:
#if defined( _WIN32 )
InputProducerManager(HWND wnd);
#endif
virtual ~InputProducerManager();
#if defined( _WIN32 )
IDirectInput8* getDevice();
#endif
InputProducer* acquireInputProducer(GUID deviceGuid);
INT32 getAcquiredInputProducerCount();
InputProducer* getAcquiredInputProducer(INT32 i);
void pollInputProducers();
void releaseInputProducers();
private:
#if defined( _WIN32 )
HWND wnd;
IDirectInput8* directInput;
#endif
vector<InputProducer*> devices;
};
#endif

View File

@ -0,0 +1,336 @@
#include "Intellivision.h"
TYPEDEF_STRUCT_PACK( _IntellivisionState
{
StateHeader header;
StateChunk cpu;
CP1610State cpuState;
StateChunk stic;
AY38900State sticState;
StateChunk psg;
AY38914State psgState;
StateChunk RAM8bit;
RAMState RAM8bitState;
UINT16 RAM8bitImage[RAM8BIT_SIZE];
StateChunk RAM16bit;
RAMState RAM16bitState;
UINT16 RAM16bitImage[RAM16BIT_SIZE];
StateChunk GRAM;
RAMState GRAMState;
UINT16 GRAMImage[GRAM_SIZE];
StateChunk ivoice;
IntellivoiceState ivoiceState;
StateChunk ecs;
ECSState ecsState;
StateChunk eof;
} IntellivisionState; )
/**
* Initializes all of the basic hardware included in the Intellivision
* Master Component as well as the ECS and Intellivoice peripherals.
* This method is called only once when the Intellivision is constructed.
*/
Intellivision::Intellivision()
: Emulator("Intellivision"),
player1Controller(0, "Hand Controller #1"),
player2Controller(1, "Hand Controller #2"),
psg(0x01F0, &player1Controller, &player2Controller),
RAM8bit(RAM8BIT_SIZE, 0x0100, 8),
RAM16bit(RAM16BIT_SIZE, 0x0200, 16),
execROM("Executive ROM", "exec.bin", 0, 2, 0x1000, 0x1000),
grom("GROM", "grom.bin", 0, 1, 0x0800, 0x3000),
gram(),
cpu(&memoryBus, 0x1000, 0x1004),
stic(&memoryBus, &grom, &gram)
{
// define the video pixel dimensions
videoWidth = 160;
videoHeight = 192;
//make the pin connections from the CPU to the STIC
stic.connectPinOut(AY38900_PIN_OUT_SR1, &cpu, CP1610_PIN_IN_INTRM);
stic.connectPinOut(AY38900_PIN_OUT_SR2, &cpu, CP1610_PIN_IN_BUSRQ);
cpu.connectPinOut(CP1610_PIN_OUT_BUSAK, &stic, AY38900_PIN_IN_SST);
//add the player one hand controller
AddInputConsumer(&player1Controller);
//add the player two hand controller
AddInputConsumer(&player2Controller);
//add the 8-bit RAM
AddRAM(&RAM8bit);
//add the 16-bit RAM
AddRAM(&RAM16bit);
//add the executive ROM
AddROM(&execROM);
//add the GROM
AddROM(&grom);
//add the GRAM
AddRAM(&gram);
//add the backtab ram
AddRAM(&stic.backtab);
//add the CPU
AddProcessor(&cpu);
//add the STIC
AddProcessor(&stic);
AddVideoProducer(&stic);
//add the STIC registers
AddRAM(&stic.registers);
//add the PSG
AddProcessor(&psg);
AddAudioProducer(&psg);
//add the PSG registers
AddRAM(&psg.registers);
AddPeripheral(&ecs);
AddPeripheral(&intellivoice);
}
BOOL Intellivision::SaveState(const CHAR* filename)
{
BOOL didSave = FALSE;
IntellivisionState state = {9};
size_t totalStateSize = sizeof(IntellivisionState);
size_t hsize = sizeof(StateHeader);
size_t csize = sizeof(StateChunk);
size_t cpusize = sizeof(CP1610State);
size_t sticsize = sizeof(AY38900State);
size_t psgsize = sizeof(AY38914State);
size_t ivoicesize = sizeof(IntellivoiceState);
size_t ecssize = sizeof(ECSState);
size_t ramsize = sizeof(RAMState);
size_t ram8imgsize = sizeof(state.RAM8bitImage);
size_t ram16imgsize = sizeof(state.RAM16bitImage);
size_t gramimgsize = sizeof(state.GRAMImage);
state.header.emu = FOURCHAR('EMUS');
state.header.state = FOURCHAR('TATE');
state.header.emuID = ID_EMULATOR_BLISS;
state.header.version = FOURCHAR(EMU_STATE_VERSION);
state.header.sys = FOURCHAR('SYS\0');
state.header.sysID = ID_SYSTEM_INTELLIVISION;
state.header.cart = FOURCHAR('CART');
state.header.cartID = currentRip->GetCRC();
state.cpu.id = FOURCHAR('CPU\0');
state.cpu.size = sizeof(CP1610State);
state.cpuState = cpu.getState();
state.stic.id = FOURCHAR('STIC');
state.stic.size = sizeof(AY38900State);
state.sticState = stic.getState();
state.psg.id = FOURCHAR('PSG\0');
state.psg.size = sizeof(AY38914State);
state.psgState = psg.getState();
state.RAM8bit.id = FOURCHAR('RAM0');
state.RAM8bit.size = sizeof(RAMState) + sizeof(state.RAM8bitImage);
state.RAM8bitState = RAM8bit.getState(state.RAM8bitImage);
state.RAM16bit.id = FOURCHAR('RAM1');
state.RAM16bit.size = sizeof(RAMState) + sizeof(state.RAM16bitImage);
state.RAM16bitState = RAM16bit.getState(state.RAM16bitImage);
state.GRAM.id = FOURCHAR('GRAM');
state.GRAM.size = sizeof(RAMState) + sizeof(state.GRAMImage);
state.GRAMState = gram.getState(state.GRAMImage);
// TODO: only if ivoice is used for this cart?
state.ivoice.id = FOURCHAR('VOIC');
state.ivoice.size = sizeof(IntellivoiceState);
state.ivoiceState = intellivoice.getState();
// TODO: only if ecs is used for this cart?
state.ecs.id = FOURCHAR('ECS\0');
state.ecs.size = sizeof(ECSState);
state.ecsState = ecs.getState();
state.eof.id = FOURCHAR('EOF\0');
state.eof.size = sizeof(IntellivisionState);
FILE* file = fopen(filename, "wb");
if (file == NULL) {
printf("Error: Unable to create file %s\n", filename);
didSave = FALSE;
}
if (file != NULL && totalStateSize == fwrite(&state, 1, totalStateSize, file)) {
didSave = TRUE;
} else {
printf("Error: could not write %zu bytes to file %s\n", totalStateSize, filename);
didSave = FALSE;
}
if (file) {
fclose(file);
file = NULL;
}
return didSave;
}
BOOL Intellivision::LoadState(const CHAR* filename)
{
BOOL didLoadState = FALSE;
IntellivisionState state = {9};
size_t totalStateSize = sizeof(IntellivisionState);
FILE* file = fopen(filename, "rb");
if (file == NULL) {
printf("Error: Unable to open file %s\n", filename);
return FALSE;
}
#if 0
// read in the whole file
if (totalStateSize != fread(&state, 1, totalStateSize, file)) {
printf("Error: could not read state (%zu bytes) from file %s\n", totalStateSize, filename);
goto close;
}
#else
BOOL isParsing = FALSE;
StateChunk chunk = {0};
// read in the header
if (sizeof(StateHeader) != fread(&state, 1, sizeof(StateHeader), file)) {
printf("Error: could not read state header (%zu bytes) from file %s\n", totalStateSize, filename);
goto close;
}
// validate file header
if (state.header.emu != FOURCHAR('EMUS') || state.header.state != FOURCHAR('TATE')) {
printf("Error: invalid header in file %s\n", filename);
goto close;
}
if (state.header.emuID != ID_EMULATOR_BLISS) {
printf("Error: invalid emulator ID %x in file %s\n", state.header.emuID, filename);
goto close;
}
if (FOURCHAR(EMU_STATE_VERSION) != FOURCHAR('dev\0') && state.header.version != FOURCHAR('dev\0') && state.header.version != FOURCHAR(EMU_STATE_VERSION)) {
printf("Error: invalid emulator version 0x%08x (expected 0x%08x) in file %s\n", state.header.version, EMU_STATE_VERSION, filename);
goto close;
}
if (state.header.sys != FOURCHAR('SYS\0')) {
printf("Error: expected 'SYS ' chunk in file %s\n", filename);
goto close;
}
if (state.header.sysID != ID_SYSTEM_INTELLIVISION) {
printf("Error: invalid system ID %x in file %s\n", state.header.sysID, filename);
goto close;
}
if (state.header.cart != FOURCHAR('CART')) {
printf("Error: expected 'CART' chunk in file %s\n", filename);
goto close;
}
if (state.header.cartID != 0x00000000 && state.header.cartID != currentRip->GetCRC()) {
printf("Error: cartridge mismatch in file %s\n", filename);
goto close;
}
isParsing = TRUE;
while (isParsing) {
size_t fpos = ftell(file);
if (sizeof(StateChunk) != fread(&chunk, 1, sizeof(StateChunk), file)) {
isParsing = FALSE;
break;
}
switch (chunk.id) {
default:
fpos = ftell(file);
break;
case FOURCHAR('CPU\0'):
if (chunk.size == sizeof(state.cpuState)) {
state.cpu = chunk;
fread(&state.cpuState, 1, state.cpu.size, file);
}
break;
case FOURCHAR('STIC'):
if (chunk.size == sizeof(state.sticState)) {
state.stic = chunk;
fread(&state.sticState, 1, state.stic.size, file);
}
break;
case FOURCHAR('PSG\0'):
if (chunk.size == sizeof(state.psgState)) {
state.psg = chunk;
fread(&state.psgState, 1, state.psg.size, file);
}
break;
case FOURCHAR('RAM0'):
if (chunk.size == sizeof(state.RAM8bitState) + sizeof(state.RAM8bitImage)) {
state.RAM8bit = chunk;
fread(&state.RAM8bitState, 1, state.RAM8bit.size, file);
}
break;
case FOURCHAR('RAM1'):
if (chunk.size == sizeof(state.RAM16bitState) + sizeof(state.RAM16bitImage)) {
state.RAM16bit = chunk;
fread(&state.RAM16bitState, 1, state.RAM16bit.size, file);
}
break;
case FOURCHAR('GRAM'):
if (chunk.size == sizeof(state.GRAMState) + sizeof(state.GRAMImage)) {
state.GRAM = chunk;
fread(&state.GRAMState, 1, state.GRAM.size, file);
}
break;
case FOURCHAR('VOIC'):
// TODO: only if ivoice/ecs is used for this cart?
if (chunk.size == sizeof(state.ivoiceState)) {
state.ivoice = chunk;
fread(&state.ivoiceState, 1, state.ivoice.size, file);
}
break;
case FOURCHAR('ECS\0'):
// TODO: only if ivoice/ecs is used for this cart?
if (chunk.size == sizeof(state.ecsState)) {
state.ecs = chunk;
fread(&state.ecsState, 1, state.ecs.size, file);
}
break;
case FOURCHAR('EOF\0'):
state.eof = chunk;
isParsing = FALSE;
break;
}
}
#endif
didLoadState = TRUE;
cpu.setState(state.cpuState);
stic.setState(state.sticState);
psg.setState(state.psgState);
RAM8bit.setState(state.RAM8bitState, state.RAM8bitImage);
RAM16bit.setState(state.RAM16bitState, state.RAM16bitImage);
gram.setState(state.GRAMState, state.GRAMImage);
intellivoice.setState(state.ivoiceState);
ecs.setState(state.ecsState);
close:
fclose(file);
file = NULL;
end:
return didLoadState;
}

View File

@ -0,0 +1,52 @@
#ifndef INTELLIVISION_H
#define INTELLIVISION_H
#include "Emulator.h"
#include "HandController.h"
#include "ECS.h"
#include "Intellivoice.h"
#include "Emulator.h"
#include "MemoryBus.h"
#include "RAM.h"
#include "ROM.h"
#include "CP1610.h"
#include "AY38900.h"
#include "AY38914.h"
#define RAM8BIT_SIZE 0x00F0
#define RAM16BIT_SIZE 0x0160
class Intellivision : public Emulator
{
public:
Intellivision();
BOOL SaveState(const CHAR* filename);
BOOL LoadState(const CHAR* filename);
private:
//core processors
CP1610 cpu;
AY38900 stic;
AY38914 psg;
//core memories
RAM RAM8bit;
RAM RAM16bit;
ROM execROM;
ROM grom;
GRAM gram;
//hand controllers
HandController player1Controller;
HandController player2Controller;
//the ECS peripheral
ECS ecs;
//the Intellivoice peripheral
Intellivoice intellivoice;
};
#endif

View File

@ -0,0 +1,16 @@
#include "Intellivoice.h"
IntellivoiceState Intellivoice::getState()
{
IntellivoiceState state = {0};
state.sp0256State = sp0256.getState();
return state;
}
void Intellivoice::setState(IntellivoiceState state)
{
sp0256.setState(state.sp0256State);
}

View File

@ -0,0 +1,40 @@
#ifndef INTELLIVOICE_H
#define INTELLIVOICE_H
#include "Memory.h"
#include "Peripheral.h"
#include "types.h"
#include "Processor.h"
#include "SP0256.h"
#include "AudioOutputLine.h"
TYPEDEF_STRUCT_PACK( _IntellivoiceState
{
SP0256State sp0256State;
} IntellivoiceState; )
class Intellivoice : public Peripheral
{
public:
Intellivoice()
: Peripheral("Intellivoice", "Intellivoice")
{
AddProcessor(&sp0256);
AddAudioProducer(&sp0256);
AddRAM(&sp0256.registers);
AddROM(&sp0256.ivoiceROM);
}
UINT32 getProcessorCount();
void getProcessor(INT32 i, Processor** p);
UINT32 getMemoryCount();
void getMemory(INT32 i, Memory** m);
IntellivoiceState getState();
void setState(IntellivoiceState state);
private:
SP0256 sp0256;
};
#endif

204
arm9/source/emucore/MOB.cpp Normal file
View File

@ -0,0 +1,204 @@
#include "MOB.h"
void MOB::reset() {
xLocation = 0;
yLocation = 0;
foregroundColor = 0;
cardNumber = 0;
collisionRegister = 0;
isGrom = FALSE;
isVisible = FALSE;
doubleWidth = FALSE;
doubleYResolution = FALSE;
doubleHeight = FALSE;
quadHeight = FALSE;
flagCollisions = FALSE;
horizontalMirror = FALSE;
verticalMirror = FALSE;
behindForeground = FALSE;
boundingRectangle.x = 0;
boundingRectangle.y = 0;
boundingRectangle.width = 0;
boundingRectangle.height = 0;
shapeChanged = TRUE;
boundsChanged = TRUE;
colorChanged = TRUE;
}
void MOB::setXLocation(INT32 xLocation) {
if (xLocation == this->xLocation)
return;
this->xLocation = xLocation;
boundsChanged = TRUE;
}
void MOB::setYLocation(INT32 yLocation) {
if (yLocation == this->yLocation)
return;
this->yLocation = yLocation;
boundsChanged = TRUE;
}
void MOB::setForegroundColor(INT32 foregroundColor) {
if (foregroundColor == this->foregroundColor)
return;
this->foregroundColor = foregroundColor;
colorChanged = TRUE;
}
void MOB::setCardNumber(INT32 cardNumber) {
if (cardNumber == this->cardNumber)
return;
this->cardNumber = cardNumber;
shapeChanged = TRUE;
}
void MOB::setVisible(BOOL isVisible) {
if (isVisible == this->isVisible)
return;
this->isVisible = isVisible;
}
void MOB::setDoubleWidth(BOOL doubleWidth) {
if (doubleWidth == this->doubleWidth)
return;
this->doubleWidth = doubleWidth;
boundsChanged = TRUE;
shapeChanged = TRUE;
}
void MOB::setDoubleYResolution(BOOL doubleYResolution) {
if (doubleYResolution == this->doubleYResolution)
return;
this->doubleYResolution = doubleYResolution;
boundsChanged = TRUE;
shapeChanged = TRUE;
}
void MOB::setDoubleHeight(BOOL doubleHeight) {
if (doubleHeight == this->doubleHeight)
return;
this->doubleHeight = doubleHeight;
boundsChanged = TRUE;
shapeChanged = TRUE;
}
void MOB::setQuadHeight(BOOL quadHeight) {
if (quadHeight == this->quadHeight)
return;
this->quadHeight = quadHeight;
boundsChanged = TRUE;
shapeChanged = TRUE;
}
void MOB::setFlagCollisions(BOOL flagCollisions) {
if (flagCollisions == this->flagCollisions)
return;
this->flagCollisions = flagCollisions;
}
void MOB::setHorizontalMirror(BOOL horizontalMirror) {
if (horizontalMirror == this->horizontalMirror)
return;
this->horizontalMirror = horizontalMirror;
shapeChanged = TRUE;
}
void MOB::setVerticalMirror(BOOL verticalMirror) {
if (verticalMirror == this->verticalMirror)
return;
this->verticalMirror = verticalMirror;
shapeChanged = TRUE;
}
void MOB::setBehindForeground(BOOL behindForeground) {
if (behindForeground == this->behindForeground)
return;
this->behindForeground = behindForeground;
}
void MOB::setGROM(BOOL grom) {
if (grom == this->isGrom)
return;
this->isGrom = grom;
shapeChanged = TRUE;
}
void MOB::markClean() {
shapeChanged = FALSE;
colorChanged = FALSE;
}
MOBRect* MOB::getBounds() {
if (boundsChanged) {
boundingRectangle.x = xLocation-8;
boundingRectangle.y = yLocation-8;
boundingRectangle.width = 8 * (doubleWidth ? 2 : 1);
boundingRectangle.height = 4 * (quadHeight ? 4 : 1) *
(doubleHeight ? 2 : 1) * (doubleYResolution ? 2 : 1);
boundsChanged = FALSE;
}
return &boundingRectangle;
}
MOBState MOB::getState()
{
MOBState state = {0};
state.xLocation = this->xLocation;;
state.yLocation = this->yLocation;;
state.foregroundColor = this->foregroundColor;
state.cardNumber = this->cardNumber;
state.collisionRegister = this->collisionRegister;
state.isGrom = this->isGrom;
state.isVisible = this->isVisible;
state.doubleWidth = this->doubleWidth;
state.doubleYResolution = this->doubleYResolution;
state.doubleHeight = this->doubleHeight;
state.quadHeight = this->quadHeight;
state.flagCollisions = this->flagCollisions;
state.horizontalMirror = this->horizontalMirror;
state.verticalMirror = this->verticalMirror;
state.behindForeground = this->behindForeground;
return state;
}
void MOB::setState(MOBState state)
{
this->xLocation = state.xLocation;
this->yLocation = state.yLocation;
this->foregroundColor = state.foregroundColor;
this->cardNumber = state.cardNumber;
this->collisionRegister = state.collisionRegister;
this->isGrom = state.isGrom;
this->isVisible = state.isVisible;
this->doubleWidth = state.doubleWidth;
this->doubleYResolution = state.doubleYResolution;
this->doubleHeight = state.doubleHeight;
this->quadHeight = state.quadHeight;
this->flagCollisions = state.flagCollisions;
this->horizontalMirror = state.horizontalMirror;
this->verticalMirror = state.verticalMirror;
this->behindForeground = state.behindForeground;
this->boundsChanged = TRUE;
this->shapeChanged = TRUE;
this->colorChanged = TRUE;
}

81
arm9/source/emucore/MOB.h Normal file
View File

@ -0,0 +1,81 @@
#ifndef SPRITE_H
#define SPRITE_H
#include "MOBRect.h"
#include "types.h"
class AY38900;
class AY38900_Registers;
TYPEDEF_STRUCT_PACK( _MOBState
{
INT32 xLocation;
INT32 yLocation;
INT32 foregroundColor;
INT32 cardNumber;
UINT16 collisionRegister;
INT8 isGrom;
INT8 isVisible;
INT8 doubleWidth;
INT8 doubleYResolution;
INT8 doubleHeight;
INT8 quadHeight;
INT8 flagCollisions;
INT8 horizontalMirror;
INT8 verticalMirror;
INT8 behindForeground;
} MOBState; )
class MOB
{
friend class AY38900;
friend class AY38900_Registers;
private:
MOB() {};
void reset();
void setXLocation(INT32 xLocation);
void setYLocation(INT32 yLocation);
void setForegroundColor(INT32 foregroundColor);
void setCardNumber(INT32 cardNumber);
void setVisible(BOOL isVisible);
void setDoubleWidth(BOOL doubleWidth);
void setDoubleYResolution(BOOL doubleYResolution);
void setDoubleHeight(BOOL doubleHeight);
void setQuadHeight(BOOL quadHeight);
void setFlagCollisions(BOOL flagCollisions);
void setHorizontalMirror(BOOL horizontalMirror);
void setVerticalMirror(BOOL verticalMirror);
void setBehindForeground(BOOL behindForeground);
void setGROM(BOOL grom);
void markClean();
MOBRect* getBounds();
MOBState getState();
void setState(MOBState state);
INT32 xLocation;
INT32 yLocation;
INT32 foregroundColor;
INT32 cardNumber;
UINT16 collisionRegister;
BOOL isGrom;
BOOL isVisible;
BOOL doubleWidth;
BOOL doubleYResolution;
BOOL doubleHeight;
BOOL quadHeight;
BOOL flagCollisions;
BOOL horizontalMirror;
BOOL verticalMirror;
BOOL behindForeground;
BOOL boundsChanged;
BOOL shapeChanged;
BOOL colorChanged;
MOBRect boundingRectangle;
};
#endif

View File

@ -0,0 +1,25 @@
#ifndef RECTANGLE_H
#define RECTANGLE_H
#include "types.h"
class MOBRect
{
public:
BOOL intersects(MOBRect* r) {
return !((r->x + r->width <= x) ||
(r->y + r->height <= y) ||
(r->x >= x + width) ||
(r->y >= y + height));
}
INT32 x;
INT32 y;
INT32 width;
INT32 height;
};
#endif

View File

@ -0,0 +1,26 @@
#ifndef MEMORY_H
#define MEMORY_H
#include "types.h"
class Memory
{
public:
virtual ~Memory() {}
virtual void reset() = 0;
virtual UINT16 getReadSize() = 0;
virtual UINT16 getReadAddress() = 0;
virtual UINT16 getReadAddressMask() = 0;
virtual UINT16 peek(UINT16 location) = 0;
virtual UINT16 getWriteSize() = 0;
virtual UINT16 getWriteAddress() = 0;
virtual UINT16 getWriteAddressMask() = 0;
virtual void poke(UINT16 location, UINT16 value) = 0;
};
#endif

View File

@ -0,0 +1,230 @@
#include <stdio.h>
#include "MemoryBus.h"
MemoryBus::MemoryBus()
{
UINT32 size = 1 << (sizeof(UINT16) << 3);
UINT64 i;
writeableMemoryCounts = new UINT8[size];
memset(writeableMemoryCounts, 0, sizeof(UINT8) * size);
writeableMemorySpace = new Memory**[size];
for (i = 0; i < size; i++)
writeableMemorySpace[i] = new Memory*[MAX_OVERLAPPED_MEMORIES];
readableMemoryCounts = new UINT8[size];
memset(readableMemoryCounts, 0, sizeof(UINT8) * size);
readableMemorySpace = new Memory**[size];
for (i = 0; i < size; i++)
readableMemorySpace[i] = new Memory*[MAX_OVERLAPPED_MEMORIES];
mappedMemoryCount = 0;
}
MemoryBus::~MemoryBus()
{
UINT64 size = 1 << (sizeof(UINT16) << 3);
UINT64 i;
delete[] writeableMemoryCounts;
for (i = 0; i < size; i++)
delete[] writeableMemorySpace[i];
delete[] writeableMemorySpace;
delete[] readableMemoryCounts;
for (i = 0; i < size; i++)
delete[] readableMemorySpace[i];
delete[] readableMemorySpace;
}
void MemoryBus::reset()
{
for (UINT8 i = 0; i < mappedMemoryCount; i++)
mappedMemories[i]->reset();
}
void MemoryBus::addMemory(Memory* m)
{
UINT8 bitCount = sizeof(UINT16)<<3;
UINT8 bitShifts[sizeof(UINT16)<<3];
UINT8 i;
//get the important info
UINT16 readSize = m->getReadSize();
UINT16 readAddress = m->getReadAddress();
UINT16 readAddressMask = m->getReadAddressMask();
UINT16 writeSize = m->getWriteSize();
UINT16 writeAddress = m->getWriteAddress();
UINT16 writeAddressMask = m->getWriteAddressMask();
//add all of the readable locations, if any
if (readAddressMask != 0) {
UINT8 zeroCount = 0;
for (i = 0; i < bitCount; i++) {
if (!(readAddressMask & (1<<i))) {
bitShifts[zeroCount] = (i-zeroCount);
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
for (UINT8 j = 0; j < zeroCount; j++)
orMask |= (i & (1<<j)) << bitShifts[j];
UINT16 nextAddress = readAddress | orMask;
UINT16 nextEnd = nextAddress + readSize - 1;
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
UINT16 memCount = readableMemoryCounts[k];
readableMemorySpace[k][memCount] = m;
readableMemoryCounts[k]++;
}
}
}
//add all of the writeable locations, if any
if (writeAddressMask != 0) {
UINT8 zeroCount = 0;
for (i = 0; i < bitCount; i++) {
if (!(writeAddressMask & (1<<i))) {
bitShifts[zeroCount] = (i-zeroCount);
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
for (UINT8 j = 0; j < zeroCount; j++)
orMask |= (i & (1<<j)) << bitShifts[j];
UINT16 nextAddress = writeAddress | orMask;
UINT16 nextEnd = nextAddress + writeSize - 1;
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
UINT16 memCount = writeableMemoryCounts[k];
writeableMemorySpace[k][memCount] = m;
writeableMemoryCounts[k]++;
}
}
}
//add it to our list of memories
mappedMemories[mappedMemoryCount] = m;
mappedMemoryCount++;
}
void MemoryBus::removeMemory(Memory* m)
{
UINT8 bitCount = sizeof(UINT16)<<3;
UINT8 bitShifts[sizeof(UINT16)<<3];
UINT32 i;
//get the important info
UINT16 readSize = m->getReadSize();
UINT16 readAddress = m->getReadAddress();
UINT16 readAddressMask = m->getReadAddressMask();
UINT16 writeSize = m->getWriteSize();
UINT16 writeAddress = m->getWriteAddress();
UINT16 writeAddressMask = m->getWriteAddressMask();
//add all of the readable locations, if any
if (readAddressMask != 0) {
UINT8 zeroCount = 0;
for (i = 0; i < bitCount; i++) {
if (!(readAddressMask & (1<<i))) {
bitShifts[zeroCount] = (UINT8)(i-zeroCount);
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
for (UINT8 j = 0; j < zeroCount; j++)
orMask |= (i & (1<<j)) << bitShifts[j];
UINT16 nextAddress = readAddress | orMask;
UINT16 nextEnd = nextAddress + readSize - 1;
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
UINT16 memCount = readableMemoryCounts[k];
for (UINT16 n = 0; n < memCount; n++) {
if (readableMemorySpace[k][n] == m) {
for (INT32 l = n; l < (memCount-1); l++) {
readableMemorySpace[k][l] = readableMemorySpace[k][l+1];
}
readableMemorySpace[k][memCount-1] = NULL;
readableMemoryCounts[k]--;
break;
}
}
}
}
}
//add all of the writeable locations, if any
if (writeAddressMask != 0) {
UINT8 zeroCount = 0;
for (i = 0; i < bitCount; i++) {
if (!(writeAddressMask & (1<<i))) {
bitShifts[zeroCount] = (UINT8)(i-zeroCount);
zeroCount++;
}
}
UINT8 combinationCount = (1<<zeroCount);
for (i = 0; i < combinationCount; i++) {
UINT16 orMask = 0;
for (UINT8 j = 0; j < zeroCount; j++)
orMask |= (i & (1<<j)) << bitShifts[j];
UINT16 nextAddress = writeAddress | orMask;
UINT16 nextEnd = nextAddress + writeSize - 1;
for (UINT64 k = nextAddress; k <= nextEnd; k++) {
UINT16 memCount = writeableMemoryCounts[k];
for (UINT16 n = 0; n < memCount; n++) {
if (writeableMemorySpace[k][n] == m) {
for (INT32 l = n; l < (memCount-1); l++) {
writeableMemorySpace[k][l] =
writeableMemorySpace[k][l+1];
}
writeableMemorySpace[k][memCount-1] = NULL;
writeableMemoryCounts[k]--;
break;
}
}
}
}
}
//remove it from our list of memories
for (i = 0; i < mappedMemoryCount; i++) {
if (mappedMemories[i] == m) {
for (UINT32 j = i; j < (UINT32)(mappedMemoryCount-1); j++)
mappedMemories[j] = mappedMemories[j+1];
mappedMemoryCount--;
return;
}
}
}
void MemoryBus::removeAll()
{
while (mappedMemoryCount)
removeMemory(mappedMemories[0]);
}
UINT16 MemoryBus::peek(UINT16 location)
{
UINT8 numMemories = readableMemoryCounts[location];
UINT16 value = 0xFFFF;
for (UINT16 i = 0; i < numMemories; i++)
value &= readableMemorySpace[location][i]->peek(location);
return value;
}
void MemoryBus::poke(UINT16 location, UINT16 value)
{
UINT8 numMemories = writeableMemoryCounts[location];
for (UINT16 i = 0; i < numMemories; i++)
writeableMemorySpace[location][i]->poke(location, value);
}

View File

@ -0,0 +1,46 @@
#ifndef MEMORYBUS_H
#define MEMORYBUS_H
#include <stdio.h>
#include <string.h>
#include "Memory.h"
#define MAX_MAPPED_MEMORIES 20
#define MAX_OVERLAPPED_MEMORIES 3
/**
* Emulates a 64K memory bus which may be composed of 8-bit or 16-bit memory units.
*
* @author Kyle Davis
*/
extern UINT16 r[8];
class MemoryBus
{
public:
MemoryBus();
virtual ~MemoryBus();
void reset();
UINT16 peek(UINT16 location);
inline UINT16 peek_fast(UINT16 location) {return readableMemorySpace[location][0]->peek(location);}
inline UINT16 peek_pc(void) {return readableMemorySpace[r[7]][0]->peek(r[7]);}
void poke(UINT16 location, UINT16 value);
void addMemory(Memory* m);
void removeMemory(Memory* m);
void removeAll();
private:
Memory* mappedMemories[MAX_MAPPED_MEMORIES];
UINT16 mappedMemoryCount;
UINT8* writeableMemoryCounts;
Memory*** writeableMemorySpace;
UINT8* readableMemoryCounts;
Memory*** readableMemorySpace;
};
#endif

View File

@ -0,0 +1,14 @@
#ifndef PALETTE_H
#define PALETTE_H
#include "types.h"
typedef struct _PALETTE
{
UINT16 m_iNumEntries;
UINT32 m_iEntries[256];
} PALETTE;
#endif

View File

@ -0,0 +1,114 @@
#include "Peripheral.h"
void Peripheral::AddProcessor(Processor* p)
{
processors[processorCount] = p;
processorCount++;
}
void Peripheral::RemoveProcessor(Processor* p)
{
for (UINT32 i = 0; i < processorCount; i++) {
if (processors[i] == p) {
for (UINT32 j = i; j < (processorCount-1); j++)
processors[j] = processors[j+1];
processorCount--;
return;
}
}
}
UINT16 Peripheral::GetProcessorCount()
{
return processorCount;
}
Processor* Peripheral::GetProcessor(UINT16 i)
{
return processors[i];
}
void Peripheral::AddRAM(RAM* m)
{
rams[ramCount] = m;
ramCount++;
}
UINT16 Peripheral::GetRAMCount()
{
return ramCount;
}
RAM* Peripheral::GetRAM(UINT16 i)
{
return rams[i];
}
void Peripheral::AddVideoProducer(VideoProducer* vp)
{
videoProducers[videoProducerCount] = vp;
videoProducerCount++;
}
UINT16 Peripheral::GetVideoProducerCount()
{
return videoProducerCount;
}
VideoProducer* Peripheral::GetVideoProducer(UINT16 i)
{
return videoProducers[i];
}
void Peripheral::AddAudioProducer(AudioProducer* ap)
{
audioProducers[audioProducerCount] = ap;
audioProducerCount++;
}
UINT16 Peripheral::GetAudioProducerCount()
{
return audioProducerCount;
}
AudioProducer* Peripheral::GetAudioProducer(UINT16 i)
{
return audioProducers[i];
}
void Peripheral::AddInputConsumer(InputConsumer* ic)
{
inputConsumers[inputConsumerCount] = ic;
inputConsumerCount++;
}
UINT16 Peripheral::GetInputConsumerCount()
{
return inputConsumerCount;
}
InputConsumer* Peripheral::GetInputConsumer(UINT16 i)
{
return inputConsumers[i];
}
void Peripheral::AddROM(ROM* r)
{
printf("ROM Added [%s]\n", r->getName());
roms[romCount] = r;
romCount++;
}
UINT16 Peripheral::GetROMCount()
{
return romCount;
}
ROM* Peripheral::GetROM(UINT16 i)
{
return roms[i];
}

View File

@ -0,0 +1,236 @@
#ifndef PERIPHERAL_H
#define PERIPHERAL_H
#include "Processor.h"
#include "RAM.h"
#include "ROM.h"
#include "AudioProducer.h"
#include "VideoProducer.h"
#include "InputConsumer.h"
#define MAX_COMPONENTS 16
/**
* A peripheral represents a device that contains emulated hardware components, including
* processors and memory units. Each processor or memory unit may optionally also be a
* video producer, audio producer, and/or input consumer. However, some input consumers are
* neither processors or memory units.
*/
class Peripheral
{
public:
/**
* Gets the name of this peripheral.
*
* @return the peripheral name
*/
const char* GetName() { return peripheralName; }
/**
* Gets the short name of this peripheral.
*
* @return the short peripheral name
*/
const char* GetShortName() { return peripheralShortName; }
/**
* Adds a processor to this peripheral.
*
* @param processor the processor to add
*/
void AddProcessor(Processor* processor);
/**
* Removes a processor from this peripheral.
*
* @param processor the processor to remove
*/
void RemoveProcessor(Processor* processor);
/**
* Gets the number of processors in this peripheral.
*
* @return the number of processors
*/
UINT16 GetProcessorCount();
/**
* Gets a pointer to the processor indicated by an index.
*
* @param index the index of the processor to return
* @return a pointer to the processor
*/
Processor* GetProcessor(UINT16 index);
/**
* Adds a RAM unit to this peripheral.
*
* @param ram the RAM unit to add
*/
void AddRAM(RAM* ram);
/**
* Gets the number of RAM units in this peripheral.
*
* @return the number of RAM units
*/
UINT16 GetRAMCount();
/**
* Gets a pointer to the RAM unit indicated by an index.
*
* @param index the index of the RAM unit to return
* @return a pointer to the RAM unit
*/
RAM* GetRAM(UINT16 index);
/**
* Adds a ROM unit to this peripheral.
*
* @param rom the ROM unit to add
*/
void AddROM(ROM* rom);
/**
* Gets the number of ROM units in this peripheral.
*
* @return the number of ROM units
*/
UINT16 GetROMCount();
/**
* Gets a pointer to the ROM unit indicated by an index.
*
* @param index the index of the ROM unit to return
* @return a pointer to the ROM unit
*/
ROM* GetROM(UINT16 index);
/**
* Adds a video producer to this peripheral.
*
* @param vp the video producer to add
*/
void AddVideoProducer(VideoProducer* vp);
/**
* Gets the number of video producers in this peripheral.
*
* @return the number of video producers
*/
UINT16 GetVideoProducerCount();
/**
* Gets a pointer to the video producer indicated by an index.
*
* @param index the index of the video producer to return
* @return a pointer to the video producer
*/
VideoProducer* GetVideoProducer(UINT16 index);
/**
* Adds an audio producer to this peripheral.
*
* @param ap the audio producer to add
*/
void AddAudioProducer(AudioProducer* ap);
/**
* Gets the number of audio producers in this peripheral.
*
* @return the number of audio producers
*/
UINT16 GetAudioProducerCount();
/**
* Gets a pointer to the audio producer indicated by an index.
*
* @param index the index of the audio producer to return
* @return a pointer to the audio producer
*/
AudioProducer* GetAudioProducer(UINT16 index);
/**
* Adds an input consumer to this peripheral.
*
* @param ic the input consumer to add
*/
void AddInputConsumer(InputConsumer*);
/**
* Gets the number of input consumers in this peripheral.
*
* @return the number of input consumers
*/
UINT16 GetInputConsumerCount();
/**
* Gets a pointer to the input consumer indicated by an index.
*
* @param index the index of the input consumer to return
* @return a pointer to the input consumer
*/
InputConsumer* GetInputConsumer(UINT16 index);
protected:
/**
* Constructs a peripheral.
*
* @param name the name of the peripheral
* @param shortName the short name of the peripheral
*/
Peripheral(const CHAR* name, const CHAR* shortName)
: processorCount(0),
videoProducerCount(0),
audioProducerCount(0),
inputConsumerCount(0),
ramCount(0),
romCount(0),
peripheralName(NULL),
peripheralShortName(NULL)
{
if (name) {
peripheralName = new CHAR[strlen(name)+1];
strcpy(peripheralName, name);
}
if (shortName) {
peripheralShortName = new CHAR[strlen(shortName)+1];
strcpy(peripheralShortName, shortName);
}
}
/**
* Destroys the peripheral.
*/
~Peripheral()
{
delete[] peripheralShortName;
delete[] peripheralName;
}
/**
* The peripheral name. The Rip class exposes the periphal name as mutable, so we leave
* it exposed as protected access here. This will probably change in the future.
*/
char* peripheralName;
private:
char* peripheralShortName;
Processor* processors[MAX_COMPONENTS];
UINT16 processorCount;
VideoProducer* videoProducers[MAX_COMPONENTS];
UINT16 videoProducerCount;
AudioProducer* audioProducers[MAX_COMPONENTS];
UINT16 audioProducerCount;
InputConsumer* inputConsumers[MAX_COMPONENTS];
UINT16 inputConsumerCount;
RAM* rams[MAX_COMPONENTS];
UINT16 ramCount;
ROM* roms[MAX_COMPONENTS];
UINT16 romCount;
};
#endif

View File

@ -0,0 +1,49 @@
#include "CP1610.h"
SignalLine nullPin;
Processor::Processor(const char* nm)
: name(nm)
{
for (UINT8 i = 0; i < MAX_PINS; i++) {
pinOut[i] = &nullPin;
pinIn[i] = &nullPin;
}
}
Processor::~Processor()
{
for (UINT8 i = 0; i < MAX_PINS; i++) {
if (pinOut[i] != &nullPin)
delete pinOut[i];
}
}
void Processor::connectPinOut(UINT8 pinOutNum, Processor* targetProcessor,
UINT8 targetPinInNum)
{
if (pinOut[pinOutNum] != &nullPin)
disconnectPinOut(pinOutNum);
if (targetProcessor->pinIn[targetPinInNum] != &nullPin) {
targetProcessor->pinIn[targetPinInNum]->pinOutProcessor->disconnectPinOut(
targetProcessor->pinIn[targetPinInNum]->pinOutNum);
}
pinOut[pinOutNum] = new SignalLine(this, pinOutNum, targetProcessor,
targetPinInNum);
targetProcessor->pinIn[targetPinInNum] = pinOut[pinOutNum];
}
void Processor::disconnectPinOut(UINT8 pinOutNum)
{
if (pinOut[pinOutNum] == &nullPin)
return;
SignalLine* s = pinOut[pinOutNum];
s->pinInProcessor->pinIn[s->pinInNum] = &nullPin;
pinOut[pinOutNum] = &nullPin;
delete s;
}

View File

@ -0,0 +1,61 @@
#ifndef PROCESSOR_H
#define PROCESSOR_H
#include "SignalLine.h"
#include "types.h"
#include "MemoryBus.h"
#define MAX_PINS 16
class ProcessorBus;
class ScheduleQueue;
/**
* An abstract class representing a processor, which is a hardware component
* that requires a clock input.
*/
class Processor
{
friend class ProcessorBus;
public:
virtual ~Processor();
const char* getName() { return name; }
virtual void resetProcessor() = 0;
/**
* Describes the clock speed of this processor. Unlike many emulation
* codebases, this codebase allows a processor to run at any speed
* it prefers, and the ProcessorBus is responsible for scheduling
* execution of each processor based on all of the various processor
* speeds.
*/
virtual INT32 getClockSpeed() = 0;
/**
*
*/
virtual INT32 tick(INT32 i) = 0;
virtual void connectPinOut(UINT8 pinOutNum, Processor* targetProcessor,
UINT8 targetPinInNum);
virtual void disconnectPinOut(UINT8 pinOutNum);
virtual BOOL isIdle() { return FALSE; };
protected:
Processor(const char* name);
const char* name;
SignalLine* pinIn[MAX_PINS];
SignalLine* pinOut[MAX_PINS];
ProcessorBus* processorBus;
ScheduleQueue* scheduleQueue;
};
#endif

View File

@ -0,0 +1,318 @@
#include "ProcessorBus.h"
ProcessorBus::ProcessorBus()
: processorCount(0),
startQueue(NULL),
endQueue(NULL)
{}
ProcessorBus::~ProcessorBus()
{
for (UINT32 i = 0; i < processorCount; i++) {
if (processors[i]->scheduleQueue)
delete processors[i]->scheduleQueue;
}
}
void ProcessorBus::addProcessor(Processor* p)
{
processors[processorCount] = p;
processorCount++;
p->processorBus = this;
p->scheduleQueue = new ScheduleQueue(p);
}
void ProcessorBus::removeProcessor(Processor* p)
{
for (UINT32 i = 0; i < processorCount; i++) {
if (processors[i] == p) {
for (UINT32 j = i; j < (processorCount-1); j++)
processors[j] = processors[j+1];
processorCount--;
delete p->scheduleQueue;
p->scheduleQueue = NULL;
return;
}
}
}
void ProcessorBus::removeAll()
{
while (processorCount)
removeProcessor(processors[0]);
}
void ProcessorBus::reset()
{
if (processorCount == 0)
return;
UINT64 totalClockSpeed = 1;
startQueue = endQueue = NULL;
//reorder the processor queue so that it is in the natural (starting) order
for (UINT32 i = 0; i < processorCount; i++) {
Processor* p = processors[i];
totalClockSpeed = lcm(totalClockSpeed, ((UINT64)p->getClockSpeed()));
ScheduleQueue* nextQueue = p->scheduleQueue;
nextQueue->tick = 0;
if (startQueue == NULL) {
startQueue = nextQueue;
nextQueue->previous = NULL;
nextQueue->next = NULL;
}
else {
endQueue->next = nextQueue;
nextQueue->previous = endQueue;
nextQueue->next = NULL;
}
endQueue = nextQueue;
}
//pre-cache the multiplication factor required to convert each processor's clock speed to
//the common clock speed, and reset each processor
for (UINT32 i = 0; i < processorCount; i++) {
Processor* p = processors[i];
p->scheduleQueue->tickFactor = (totalClockSpeed / ((UINT64)p->getClockSpeed()));
p->resetProcessor();
}
}
void ProcessorBus::run()
{
running = true;
while (running) {
// TODO: jeremiah sypult, saw crash when NULL
if (startQueue->next == NULL) {
break;
}
//tick the processor that is at the head of the queue
int minTicks = (int)((startQueue->next->tick / startQueue->tickFactor) + 1);
startQueue->tick = ((UINT64)startQueue->processor->tick(minTicks)) * startQueue->tickFactor;
//now reschedule the processor for later processing
ScheduleQueue* tmp1 = startQueue;
while (tmp1->next != NULL && startQueue->tick > tmp1->next->tick) {
startQueue->tick -= tmp1->next->tick;
tmp1 = tmp1->next;
}
//reorganize the scheduling queue
ScheduleQueue* queueToShuffle = startQueue;
startQueue = startQueue->next;
queueToShuffle->previous = tmp1;
queueToShuffle->next = tmp1->next;
tmp1->next = queueToShuffle;
if (queueToShuffle->next != NULL) {
queueToShuffle->next->tick -= queueToShuffle->tick;
queueToShuffle->next->previous = queueToShuffle;
}
else
endQueue = queueToShuffle;
}
}
void ProcessorBus::stop()
{
running = false;
}
void ProcessorBus::halt(Processor*)
{
}
void ProcessorBus::unhalt(Processor*)
{
}
void ProcessorBus::pause(Processor* p, int ticks)
{
ScheduleQueue* q = p->scheduleQueue;
UINT64 commonTicks = ((UINT64)ticks) * q->tickFactor;
if (q->next == NULL)
q->tick += commonTicks;
else if (commonTicks <= q->next->tick) {
q->tick += commonTicks;
q->next->tick -= commonTicks;
}
else {
//pull this processor out of the scheduling stream and reschedule it
//add my current ticks to the next guy's delta ticks
q->next->tick += q->tick;
//add the common ticks to my ticks
q->tick += commonTicks;
//have the previous q point to the next q
if (q->previous != NULL) {
q->previous->next = q->next;
q->next->previous = q->previous;
}
reschedule(p->scheduleQueue);
}
}
void ProcessorBus::reschedule(ScheduleQueue* queueToShuffle)
{
//look for where to put this processor in the scheduling queue
ScheduleQueue* tmp1 = queueToShuffle;
while (tmp1->next != NULL && queueToShuffle->tick > tmp1->next->tick) {
queueToShuffle->tick -= tmp1->next->tick;
tmp1 = tmp1->next;
}
//reorganize the scheduling queue
if (queueToShuffle == startQueue)
startQueue = queueToShuffle->next;
queueToShuffle->previous = tmp1;
queueToShuffle->next = tmp1->next;
tmp1->next = queueToShuffle;
if (queueToShuffle->next != NULL) {
queueToShuffle->next->tick -= queueToShuffle->tick;
queueToShuffle->next->previous = queueToShuffle;
}
else
endQueue = queueToShuffle;
}
UINT64 lcm(UINT64 a, UINT64 b) {
//This is an implementation of Euclid's Algorithm for determining
//the greatest common denominator (gcd) of two numbers.
UINT64 m = a;
UINT64 n = b;
UINT64 r = m % n;
while (r != 0) {
m = n;
n = r;
r = m % n;
}
UINT64 gcd = n;
//lcm is determined from gcd through the following equation
return (a/gcd)*b;
}
/*
ProcessorBus::ProcessorBus()
{
processorDebugOn = FALSE;
processorCount = 0;
memset(processors, 0, sizeof(Processor*) * MAX_PROCESSORS);
memset(processorTickFactors, 0, sizeof(INT64) * MAX_PROCESSORS);
memset(processorTicks, 0, sizeof(INT64) * MAX_PROCESSORS);
memset(processorsIdle, 0, sizeof(BOOL) * MAX_PROCESSORS);
}
void ProcessorBus::setAudioMixer(AudioMixer* am)
{
this->audioMixer = am;
}
void ProcessorBus::init()
{
UINT64 totalClockSpeed = 1;
UINT32 i;
for (i = 0; i < processorCount; i++) {
totalClockSpeed = lcm(totalClockSpeed,
((UINT64)processors[i]->getClockSpeed()));
}
for (i = 0; i < processorCount; i++) {
processorsIdle[i] = FALSE;
processorTicks[i] = 0;
processorTickFactors[i] = (totalClockSpeed /
((UINT64)processors[i]->getClockSpeed()));
processors[i]->initProcessor();
}
}
void ProcessorBus::release()
{
for (UINT32 i = 0; i < processorCount; i++)
processors[i]->releaseProcessor();
}
void ProcessorBus::addProcessor(Processor* p)
{
processors[processorCount] = p;
processorCount++;
}
void ProcessorBus::removeProcessor(Processor* p)
{
for (UINT32 i = 0; i < processorCount; i++) {
if (processors[i] == p) {
for (UINT32 j = i; j < (processorCount-1); j++)
processors[j] = processors[j+1];
processorCount--;
return;
}
}
}
void ProcessorBus::removeAll()
{
processorCount = 0;
}
void ProcessorBus::tick()
{
//determine the next tick delta
#ifdef _MSC_VER
UINT64 tickDelta = 0xFFFFFFFFFFFFFFFF;
#else
UINT64 tickDelta = 0xFFFFFFFFFFFFFFFFll;
#endif
UINT32 i;
for (i = 0; i < processorCount; i++) {
//wake up any processors that want to wake up
processorsIdle[i] = (processorsIdle[i] && processors[i]->isIdle());
//if the processor is not idle by this point, use it
//to calculate the tick delta
if (!processorsIdle[i] && (UINT64)processorTicks[i] < tickDelta)
tickDelta = processorTicks[i];
}
//move the audio mixer clock forward by the tick delta amount
audioMixer->clock += tickDelta;
for (i = 0; i < processorCount; i++) {
//skip this processor if it has been idled
if (!processorsIdle[i]) {
processorTicks[i] -= tickDelta;
//if the clock just caught up to the processor, and
//if the processor is not about to go idle, then run it
if (processorTicks[i] == 0) {
if (processors[i]->isIdle())
processorsIdle[i] = TRUE;
else {
processorTicks[i] = (((UINT64)processors[i]->tick()) *
processorTickFactors[i]);
}
}
}
}
}
UINT64 lcm(UINT64 a, UINT64 b) {
//This is an implementation of Euclid's Algorithm for determining
//the greatest common denominator (gcd) of two numbers.
UINT64 m = a;
UINT64 n = b;
UINT64 r = m % n;
while (r != 0) {
m = n;
n = r;
r = m % n;
}
UINT64 gcd = n;
//lcm is determined from gcd through the following equation
return (a/gcd)*b;
}
*/

View File

@ -0,0 +1,65 @@
#ifndef PROCESSORBUS_H
#define PROCESSORBUS_H
#include "Processor.h"
#include "types.h"
#include "AudioMixer.h"
const INT32 MAX_PROCESSORS = 15;
class ScheduleQueue;
class ProcessorBus
{
public:
ProcessorBus();
virtual ~ProcessorBus();
void addProcessor(Processor* p);
void removeProcessor(Processor* p);
void removeAll();
void reset();
void run();
void stop();
void halt(Processor* p);
void unhalt(Processor* p);
void pause(Processor* p, int ticks);
private:
void reschedule(ScheduleQueue*);
UINT32 processorCount;
Processor* processors[MAX_PROCESSORS];
bool running;
ScheduleQueue* startQueue;
ScheduleQueue* endQueue;
};
class ScheduleQueue
{
friend class ProcessorBus;
private:
ScheduleQueue(Processor* p)
: tickFactor(0),
tick(0),
previous(NULL),
next(NULL)
{
this->processor = p;
}
Processor* processor;
UINT64 tickFactor;
UINT64 tick;
ScheduleQueue* previous;
ScheduleQueue* next;
};
UINT64 lcm(UINT64 a, UINT64 b);
#endif

View File

@ -0,0 +1,157 @@
#include <nds.h>
#include "RAM.h"
UINT16 fast_ram[4096] __attribute__((section(".dtcm")));
UINT16 fast_ram_idx = 0;
RAM::RAM(UINT16 size, UINT16 location)
: enabled(TRUE)
{
this->size = size;
this->location = location;
this->readAddressMask = 0xFFFF;
this->writeAddressMask = 0xFFFF;
this->bitWidth = sizeof(UINT16)<<3;
this->trimmer = (UINT16)((1 << (sizeof(UINT16) << 3)) - 1);
//image = new UINT16[size];
image = &fast_ram[fast_ram_idx];
fast_ram_idx += size;
}
RAM::RAM(UINT16 size, UINT16 location, UINT8 bitWidth)
: enabled(TRUE)
{
this->size = size;
this->location = location;
this->readAddressMask = 0xFFFF;
this->writeAddressMask = 0xFFFF;
this->bitWidth = bitWidth;
this->trimmer = (UINT16)((1 << bitWidth) - 1);
//image = new UINT16[size];
image = &fast_ram[fast_ram_idx];
fast_ram_idx += size;
}
RAM::RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask)
: enabled(TRUE)
{
this->size = size;
this->location = location;
this->readAddressMask = readAddressMask;
this->writeAddressMask = writeAddressMask;
this->bitWidth = sizeof(UINT16)<<3;
this->trimmer = (UINT16)((1 << bitWidth) - 1);
//image = new UINT16[size];
image = &fast_ram[fast_ram_idx];
fast_ram_idx += size;
}
RAM::RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask, UINT8 bitWidth)
: enabled(TRUE)
{
this->size = size;
this->location = location;
this->readAddressMask = readAddressMask;
this->writeAddressMask = writeAddressMask;
this->bitWidth = bitWidth;
this->trimmer = (UINT16)((1 << bitWidth) - 1);
//image = new UINT16[size];
image = &fast_ram[fast_ram_idx];
fast_ram_idx += size;
}
RAM::~RAM()
{
//delete[] image;
}
void RAM::reset()
{
enabled = TRUE;
for (UINT16 i = 0; i < size; i++)
image[i] = 0;
}
void RAM::SetEnabled(BOOL b)
{
enabled = b;
}
UINT8 RAM::getBitWidth()
{
return bitWidth;
}
UINT16 RAM::getReadSize()
{
return size;
}
UINT16 RAM::getReadAddress()
{
return location;
}
UINT16 RAM::getReadAddressMask()
{
return readAddressMask;
}
UINT16 RAM::getWriteSize()
{
return size;
}
UINT16 RAM::getWriteAddress()
{
return location;
}
UINT16 RAM::getWriteAddressMask()
{
return writeAddressMask;
}
UINT16 RAM::peek(UINT16 location)
{
return image[(location&readAddressMask)-this->location];
}
void RAM::poke(UINT16 location, UINT16 value)
{
image[(location&writeAddressMask)-this->location] = (value & trimmer);
}
RAMState RAM::getState(UINT16* image)
{
RAMState state = {0};
state.enabled = this->enabled;
state.size = this->size;
state.location = this->location;
state.readAddressMask = this->readAddressMask;
state.writeAddressMask = this->writeAddressMask;
state.bitWidth = this->bitWidth;
state.trimmer = this->trimmer;
if (image != NULL) {
this->getImage(image, 0, this->getImageByteSize());
}
return state;
}
void RAM::setState(RAMState state, UINT16* image)
{
this->enabled = state.enabled;
this->size = state.size;
this->location = state.location;
this->readAddressMask = state.readAddressMask;
this->writeAddressMask = state.writeAddressMask;
this->bitWidth = state.bitWidth;
this->trimmer = state.trimmer;
if (image != NULL) {
this->setImage(image, 0, this->getImageByteSize());
}
}

72
arm9/source/emucore/RAM.h Normal file
View File

@ -0,0 +1,72 @@
#ifndef RAM_H
#define RAM_H
#include <string.h>
#include "Memory.h"
TYPEDEF_STRUCT_PACK( _RAMState
{
INT8 enabled;
UINT8 bitWidth;
UINT16 size;
UINT16 location;
UINT16 readAddressMask;
UINT16 writeAddressMask;
UINT16 trimmer;
} RAMState; )
class RAM : public Memory
{
public:
RAM(UINT16 size, UINT16 location);
RAM(UINT16 size, UINT16 location, UINT8 bitWidth);
RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask);
RAM(UINT16 size, UINT16 location, UINT16 readAddressMask, UINT16 writeAddressMask, UINT8 bitWidth);
virtual ~RAM();
virtual void reset();
UINT8 getBitWidth();
UINT16 getReadSize();
UINT16 getReadAddress();
UINT16 getReadAddressMask();
virtual UINT16 peek(UINT16 location);
UINT16 getWriteSize();
UINT16 getWriteAddress();
UINT16 getWriteAddressMask();
virtual void poke(UINT16 location, UINT16 value);
inline size_t getImageByteSize() {
return size * sizeof(UINT16);
}
void getImage(void* dst, UINT16 offset, UINT16 size) {
memcpy(dst, image + offset, size);
}
void setImage(void* src, UINT16 offset, UINT16 size) {
memcpy(image + offset, src, size);
}
RAMState getState(UINT16* image);
void setState(RAMState state, UINT16* image);
//enabled attributes
void SetEnabled(BOOL b);
BOOL IsEnabled() { return enabled; }
protected:
BOOL enabled;
UINT16 size;
UINT16 location;
UINT16 readAddressMask;
UINT16 writeAddressMask;
private:
UINT8 bitWidth;
UINT16 trimmer;
UINT16* image;
};
#endif

View File

@ -0,0 +1,174 @@
#include <stdio.h>
#include <string.h>
#include "ROM.h"
ROM::ROM(const CHAR* n, const CHAR* f, UINT32 o, UINT8 byteWidth, UINT16 size, UINT16 location, BOOL i)
: enabled(TRUE),
loaded(FALSE),
internal(i)
{
Initialize(n, f, o, byteWidth, size, location, 0xFFFF);
}
ROM::ROM(const CHAR* n, void* image, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readAddressMask)
: enabled(TRUE),
loaded(TRUE),
internal(FALSE)
{
Initialize(n, "", 0, byteWidth, size, location, readAddressMask);
memcpy(this->image, image, size*byteWidth);
}
void ROM::Initialize(const CHAR* n, const CHAR* f, UINT32 o, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readMask)
{
name = new CHAR[strlen(n)+1];
strcpy(name, n);
filename = new CHAR[strlen(f)+1];
strcpy(filename, f);
fileoffset = o;
this->byteWidth = byteWidth;
this->multiByte = (byteWidth > 1) ? 1:0;
this->size = size;
this->location = location;
this->readAddressMask = readMask;
this->image = new UINT8[size*byteWidth];
peekFunc = (byteWidth == 1 ? &ROM::peek1 : (byteWidth == 2 ? &ROM::peek2 :
(byteWidth == 4 ? &ROM::peek4 : &ROM::peekN)));
}
ROM::~ROM()
{
if (name)
delete[] name;
if (filename)
delete[] filename;
if (image)
delete[] image;
}
BOOL ROM::load(const char* filename)
{
return load(filename, 0);
}
BOOL ROM::load(const char* filename, UINT32 offset)
{
FILE* f = fopen(filename, "rb");
if (!f)
return FALSE;
fseek(f, offset, SEEK_SET);
int byteCount = size*byteWidth;
int totalSize = 0;
while (totalSize < byteCount) {
for (UINT8 k = 0; k < byteWidth; k++)
((UINT8*)image)[totalSize+(byteWidth-k-1)] = (UINT8)fgetc(f);
totalSize += byteWidth;
}
fclose(f);
loaded = TRUE;
if (loaded) printf("Successful Load of [%s]\n", filename);
else printf("Unsuccessful Load of [%s]\n", filename);
return TRUE;
}
BOOL ROM::load(void* buffer)
{
UINT8* byteImage = (UINT8*)buffer;
int byteCount = size*byteWidth;
int totalSize = 0;
while (totalSize < byteCount) {
for (UINT8 k = 0; k < byteWidth; k++)
((UINT8*)image)[totalSize+(byteWidth-k-1)] = byteImage[totalSize+k];
totalSize += byteWidth;
}
loaded = TRUE;
return TRUE;
}
void ROM::SetEnabled(BOOL b)
{
enabled = b;
if (enabled)
peekFunc = (byteWidth == 1 ? &ROM::peek1 : (byteWidth == 2 ? &ROM::peek2 :
(byteWidth == 4 ? &ROM::peek4 : &ROM::peekN)));
else
peekFunc = &ROM::peekN;
}
const CHAR* ROM::getName()
{
return name;
}
const CHAR* ROM::getDefaultFileName()
{
return filename;
}
UINT32 ROM::getDefaultFileOffset()
{
return fileoffset;
}
UINT16 ROM::getReadSize()
{
return size;
}
UINT16 ROM::getReadAddress() {
return location;
}
UINT16 ROM::getReadAddressMask()
{
return readAddressMask;
}
UINT16 ROM::getWriteSize()
{
return 0;
}
UINT16 ROM::getWriteAddress() {
return 0;
}
UINT16 ROM::getWriteAddressMask()
{
return 0;
}
UINT8 ROM::getByteWidth()
{
return byteWidth;
}
UINT16 ROM::peek1(UINT16 location)
{
return ((UINT8*)image)[(location&readAddressMask)-this->location];
}
UINT16 ROM::peek2(UINT16 location)
{
return ((UINT16*)image)[(location&readAddressMask)-this->location];
}
UINT16 ROM::peek4(UINT16 location)
{
return (UINT16)((UINT32*)image)[(location&readAddressMask)-this->location];
}
UINT16 ROM::peekN(UINT16)
{
return 0xFFFF;
}
void ROM::poke(UINT16, UINT16)
{
//can't change ROM
}

73
arm9/source/emucore/ROM.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef ROM_H
#define ROM_H
#include "Memory.h"
#include "types.h"
class ROM : public Memory
{
public:
ROM(const CHAR* name, const CHAR* defaultFilename, UINT32 defaultFileOffset, UINT8 byteWidth, UINT16 size, UINT16 location, BOOL internal = FALSE);
ROM(const CHAR* name, void* image, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readAddressMask = 0xFFFF);
virtual ~ROM();
const CHAR* getName();
const CHAR* getDefaultFileName();
UINT32 getDefaultFileOffset();
BOOL load(const CHAR* filename);
BOOL load(const CHAR* filename, UINT32 offset);
BOOL load(void* image);
BOOL isLoaded() { return loaded; }
BOOL isInternal() { return internal; }
//enabled attributes
void SetEnabled(BOOL b);
BOOL IsEnabled() { return enabled; }
//functions to implement the Memory interface
virtual void reset() {}
UINT8 getByteWidth();
UINT16 getReadSize();
UINT16 getReadAddress();
UINT16 getReadAddressMask();
inline virtual UINT16 peek(UINT16 location)
{
if (multiByte) return ((UINT16*)image)[(location)-this->location];
return ((UINT8*)image)[(location)-this->location];
// return (*this.*peekFunc)(location);
}
UINT16 getWriteSize();
UINT16 getWriteAddress();
UINT16 getWriteAddressMask();
virtual void poke(UINT16 location, UINT16 value);
private:
void Initialize(const CHAR* n, const CHAR* f, UINT32 o, UINT8 byteWidth, UINT16 size, UINT16 location, UINT16 readMask);
UINT16 (ROM::*peekFunc)(UINT16);
UINT16 peek1(UINT16 location);
UINT16 peek2(UINT16 location);
UINT16 peek4(UINT16 location);
UINT16 peekN(UINT16 location);
CHAR* name;
CHAR* filename;
UINT32 fileoffset;
UINT8* image;
UINT8 byteWidth;
UINT8 multiByte;
BOOL enabled;
UINT16 size;
UINT16 location;
UINT16 readAddressMask;
BOOL loaded;
BOOL internal;
};
#endif

View File

@ -0,0 +1,24 @@
#include <stdio.h>
#include <string.h>
#include "ROMBanker.h"
ROMBanker::ROMBanker(ROM* r, UINT16 address, UINT16 tm, UINT16 t, UINT16 mm, UINT16 m)
: RAM(1, address, 0, 0xFFFF),
rom(r),
triggerMask(tm),
trigger(t),
matchMask(mm),
match(m)
{}
void ROMBanker::reset()
{
rom->SetEnabled(match == 0);
}
void ROMBanker::poke(UINT16, UINT16 value)
{
if ((value & triggerMask) == trigger)
rom->SetEnabled((value & matchMask) == match);
}

View File

@ -0,0 +1,27 @@
#ifndef ROMBANKER_H
#define ROMBANKER_H
#include "RAM.h"
#include "ROM.h"
#include "types.h"
class ROMBanker : public RAM
{
public:
ROMBanker(ROM* rom, UINT16 address, UINT16 triggerMask, UINT16 trigger, UINT16 matchMask, UINT16 match);
virtual void reset();
virtual void poke(UINT16 location, UINT16 value);
private:
ROM* rom;
UINT16 triggerMask;
UINT16 trigger;
UINT16 matchMask;
UINT16 match;
};
#endif

843
arm9/source/emucore/Rip.cpp Normal file
View File

@ -0,0 +1,843 @@
#include <stdlib.h>
#include <stdio.h>
#include "Rip.h"
#include "RAM.h"
#include "ROM.h"
#include "ROMBanker.h"
#include "CRC32.h"
#define MAX_MEMORY_UNITS 16
#define MAX_STRING_LENGTH 256
#define ROM_TAG_TITLE 0x01
#define ROM_TAG_PUBLISHER 0x02
#define ROM_TAG_RELEASE_DATE 0x05
#define ROM_TAG_COMPATIBILITY 0x06
Rip::Rip(UINT32 systemID)
: Peripheral("", ""),
peripheralCount(0),
targetSystemID(systemID),
crc(0)
{
producer = new CHAR[1];
strcpy(producer, "");
year = new CHAR[1];
strcpy(year, "");
memset(filename, 0, sizeof(filename));
}
Rip::~Rip()
{
for (UINT16 i = 0; i < peripheralCount; i++)
delete[] peripheralNames[i];
UINT16 count = GetROMCount();
for (UINT16 i = 0; i < count; i++)
delete GetROM(i);
delete[] producer;
delete[] year;
}
void Rip::SetName(const CHAR* n)
{
if (this->peripheralName)
delete[] peripheralName;
peripheralName = new CHAR[strlen(n)+1];
strcpy(peripheralName, n);
printf("RIP Peripheral Name [%s]\n", peripheralName);
}
void Rip::SetProducer(const CHAR* p)
{
if (this->producer)
delete[] producer;
producer = new CHAR[strlen(p)+1];
strcpy(producer, p);
}
void Rip::SetYear(const CHAR* y)
{
if (this->year)
delete[] year;
year = new CHAR[strlen(y)+1];
strcpy(year, y);
}
void Rip::AddPeripheralUsage(const CHAR* periphName, PeripheralCompatibility usage)
{
peripheralNames[peripheralCount] = new CHAR[strlen(periphName)+1];
strcpy(peripheralNames[peripheralCount], periphName);
peripheralUsages[peripheralCount] = usage;
peripheralCount++;
}
PeripheralCompatibility Rip::GetPeripheralUsage(const CHAR* periphName)
{
for (UINT16 i = 0; i < peripheralCount; i++) {
if (strcmpi(peripheralNames[i], periphName) == 0)
return peripheralUsages[i];
}
return PERIPH_INCOMPATIBLE;
}
Rip* Rip::LoadA52(const CHAR* filename)
{
Rip* rip = new Rip(ID_SYSTEM_ATARI5200);
if (rip == NULL)
return NULL;
//load the data into the rip
FILE* file = fopen(filename, "rb");
if (file == NULL) {
delete rip;
return NULL;
}
//obtain the file size
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
//add an appropriate ROM to the rip
ROM* rom = new ROM("Cartridge ROM", "", 0, 1, (UINT16)size, (UINT16)(0xC000-size));
rip->AddROM(rom);
//load in the file image
UINT8* image = new UINT8[size];
UINT32 count = 0;
while (count < size)
image[count++] = (UINT8)fgetc(file);
fclose(file);
//parse the file image into the rip
UINT32 offset = 0;
UINT16 romCount = rip->GetROMCount();
for (UINT16 i = 0; i < romCount; i++)
{
if (offset >= size) {
//something is wrong, the file we're trying to load isn't large enough
//getting here indicates a likely incorrect memory map in knowncarts.cfg
delete[] image;
delete rip;
return NULL;
}
ROM* nextRom = rip->GetROM(i);
nextRom->load(image+offset);
offset += nextRom->getByteWidth() * nextRom->getReadSize();
}
delete[] image;
rip->SetFileName(filename);
rip->crc = CRC32::getCrc(filename);
return rip;
}
Rip* Rip::LoadBin(const CHAR* filename, const CHAR* configFile)
{
//determine the crc of the designated file
UINT32 crc = CRC32::getCrc(filename);
Rip* rip = LoadCartridgeConfiguration(configFile, crc);
if (rip == NULL)
return NULL;
else printf("Configuration [%s] loaded successfully\n", configFile);
//load the data into the rip
FILE* file = fopen(filename, "rb");
if (file == NULL) {
delete rip;
return NULL;
} else printf("File [%s] read into memory successfully\n", filename);
//obtain the file size
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
rewind(file);
printf("The file size is [%d] bytes\n", (int)size);
//load in the file image
UINT8* image = new UINT8[size];
UINT32 count = 0;
while (count < size)
image[count++] = (UINT8)fgetc(file);
fclose(file);
printf("Parsing file into RIP format\n");
//parse the file image into the rip
UINT32 offset = 0;
UINT16 romCount = rip->GetROMCount();
for (UINT16 i = 0; i < romCount; i++)
{
if (offset >= size)
{
//something is wrong, the file we're trying to load isn't large enough
//getting here indicates a likely incorrect memory map in knowncarts.cfg
delete[] image;
delete rip;
return NULL;
}
ROM* nextRom = rip->GetROM(i);
printf("Loading ROM segment [%s %d %d]\n", nextRom->getName(), nextRom->getByteWidth(), nextRom->getReadSize());
nextRom->load(image+offset);
offset += nextRom->getByteWidth() * nextRom->getReadSize();
}
printf("Done parsing...\n");
delete[] image;
rip->SetFileName(filename);
rip->crc = CRC32::getCrc(filename);
printf("RIP loaded!\n");
return rip;
}
Rip* Rip::LoadCartridgeConfiguration(const CHAR* configFile, UINT32 crc)
{
CHAR scrc[9];
sprintf(scrc, "%08X", crc);
//find the config that matches this crc
FILE* cfgFile = fopen(configFile, "r");
if (cfgFile == NULL)
return NULL;
Rip* rip = NULL;
BOOL parseSuccess = FALSE;
CHAR nextLine[256];
while (!feof(cfgFile)) {
fgets(nextLine, 256, cfgFile);
//size_t length = strlen(nextLine);
if (strstr(nextLine, scrc) != nextLine) {
if (parseSuccess)
break;
else
continue;
}
CHAR* nextToken;
if ((nextToken = strstr(nextLine, "Info")) != NULL) {
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
if (rip == NULL)
rip = new Rip(ID_SYSTEM_INTELLIVISION);
rip->SetYear(nextToken+1);
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
rip->SetProducer(nextToken+1);
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
rip->SetName(nextToken+1);
parseSuccess = TRUE;
}
else if ((nextToken = strstr(nextLine, "ROM")) != NULL) {
//TODO: check to make sure we don't exceed the maximum number of roms for a Rip
//parse rom bit width
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
//first check to see if this is a banked rom; if there is an equals (=) sign in
//the last field, then we assume we should parse banking
UINT16 triggerAddress, triggerMask, triggerValue, onMask, onValue;
triggerAddress = triggerMask = triggerValue = onMask = onValue = 0;
CHAR* nextEqual = strrchr(nextLine, '=');
if (nextEqual != NULL && nextEqual > nextToken) {
onValue = (UINT16)strtol(nextEqual+1, NULL, 16);
*nextEqual = NULL;
onMask = (UINT16)strtol(nextToken+1, NULL, 16);
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
nextEqual = strrchr(nextLine, '=');
if (nextEqual == NULL || nextEqual < nextToken)
continue;
CHAR* nextComma = strrchr(nextLine, ',');
if (nextComma == NULL || nextComma < nextToken || nextComma > nextEqual)
continue;
triggerValue = (UINT16)strtol(nextEqual+1, NULL, 16);
*nextEqual = NULL;
triggerMask = (UINT16)strtol(nextComma+1, NULL, 16);
*nextComma = NULL;
triggerAddress = (UINT16)strtol(nextToken+1, NULL, 16);
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
}
UINT8 romBitWidth = (UINT8)atoi(nextToken+1);
//parse rom size
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
UINT16 romSize = (UINT16)strtol(nextToken+1, NULL, 16);
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
UINT16 romAddress = (UINT16)strtol(nextToken+1, NULL, 16);
if (rip == NULL)
rip = new Rip(ID_SYSTEM_INTELLIVISION);
ROM* nextRom = new ROM("Cartridge ROM", "", 0, (romBitWidth+7)/8, romSize, romAddress);
rip->AddROM(nextRom);
if (triggerAddress != 0)
rip->AddRAM(new ROMBanker(nextRom, triggerAddress, triggerMask, triggerValue, onMask, onValue));
parseSuccess = TRUE;
}
else if ((nextToken = strstr(nextLine, "RAM")) != NULL) {
//TODO: check to make sure we don't exceed the maximum number of rams for a Rip
//parse ram width
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
UINT8 ramBitWidth = (UINT8)atoi(nextToken+1);
//parse ram size
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
UINT16 ramSize = (UINT16)strtol(nextToken+1, NULL, 16);
//parse ram address
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
UINT16 ramAddress = (UINT16)strtol(nextToken+1, NULL, 16);
if (rip == NULL)
rip = new Rip(ID_SYSTEM_INTELLIVISION);
rip->AddRAM(new RAM(ramSize, ramAddress, ramBitWidth));
parseSuccess = TRUE;
}
else if ((nextToken = strstr(nextLine, "Peripheral")) != NULL) {
//TODO: check to make sure we don't exceed the maximum number of peripherals for a Rip
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
PeripheralCompatibility pc;
if (strcmpi(nextToken+1, "required") != 0)
pc = PERIPH_REQUIRED;
else if (strcmpi(nextToken+1, "optional") != 0)
pc = PERIPH_OPTIONAL;
else
continue;
*nextToken = NULL;
if ((nextToken = strrchr(nextLine, ':')) == NULL)
continue;
if (rip == NULL)
rip = new Rip(ID_SYSTEM_INTELLIVISION);
rip->AddPeripheralUsage(nextToken+1, pc);
parseSuccess = TRUE;
}
}
fclose(cfgFile);
if (rip != NULL && !parseSuccess) {
delete rip;
rip = NULL;
}
return rip;
}
Rip* Rip::LoadRom(const CHAR* filename)
{
FILE* infile = fopen(filename, "rb");
if (infile == NULL) {
return NULL;
}
//read the magic byte (should always be $A8)
int read = fgetc(infile);
if (read != 0xA8) {
fclose(infile);
return NULL;
}
//read the number of ROM segments
int romSegmentCount = fgetc(infile);
read = fgetc(infile);
if ((read ^ 0xFF) != romSegmentCount) {
fclose(infile);
return NULL;
}
Rip* rip = new Rip(ID_SYSTEM_INTELLIVISION);
int i;
for (i = 0; i < romSegmentCount; i++) {
UINT16 start = (UINT16)(fgetc(infile) << 8);
UINT16 end = (UINT16)((fgetc(infile) << 8) | 0xFF);
UINT16 size = (UINT16)((end-start)+1);
//finally, transfer the ROM image
UINT16* romImage = new UINT16[size];
int j;
for (j = 0; j < size; j++) {
int nextbyte = fgetc(infile) << 8;
nextbyte |= fgetc(infile);
romImage[j] = (UINT16)nextbyte;
}
rip->AddROM(new ROM("Cartridge ROM", romImage, 2, size, start, 0xFFFF));
delete[] romImage;
//read the CRC
fgetc(infile); fgetc(infile);
//TODO: validate the CRC16 instead of just skipping it
//int crc16 = (fgetc(infile) << 8) | fgetc(infile);
//...
}
//no support currently for the access tables, so skip them
for (i = 0; i < 16; i++)
fgetc(infile);
//no support currently for the fine address restriction
//tables, so skip them, too
for (i = 0; i < 32; i++)
fgetc(infile);
while ((read = fgetc(infile)) != -1) {
int length = (read & 0x3F);
read = (read & 0xC) >> 6;
for (i = 0; i < read; i++)
length = (length | (fgetc(infile) << ((8*i)+6)));
int type = fgetc(infile);
int crc16;
switch (type) {
case ROM_TAG_TITLE:
{
CHAR* title = new char[length*sizeof(char)];
for (i = 0; i < length; i++) {
read = fgetc(infile);
title[i] = (char)read;
}
crc16 = (fgetc(infile) << 8) | fgetc(infile);
rip->SetName(title);
delete[] title;
}
break;
case ROM_TAG_PUBLISHER:
{
CHAR* publisher = new char[length*sizeof(char)];
for (i = 0; i < length; i++) {
read = fgetc(infile);
publisher[i] = (char)read;
}
crc16 = (fgetc(infile) << 8) | fgetc(infile);
rip->SetProducer(publisher);
delete[] publisher;
}
break;
case ROM_TAG_COMPATIBILITY:
{
read = fgetc(infile);
BOOL requiresECS = ((read & 0xC0) == 0x80);
if (requiresECS)
rip->AddPeripheralUsage("ECS", PERIPH_REQUIRED);
for (i = 0; i < length-1; i++) {
fgetc(infile);
fgetc(infile);
}
fgetc(infile);
fgetc(infile);
}
break;
case ROM_TAG_RELEASE_DATE:
default:
{
for (i = 0; i < length; i++) {
fgetc(infile);
fgetc(infile);
}
fgetc(infile);
fgetc(infile);
}
break;
}
}
fclose(infile);
rip->SetFileName(filename);
rip->crc = CRC32::getCrc(filename);
return rip;
}
Rip* Rip::LoadRip(const CHAR* filename)
{
FILE* file = fopen(filename, "rb");
if (file == NULL)
return NULL;
//first check the magic number
unsigned int nextUINT32 = freadUINT32(file);
if (nextUINT32 != 0x3F383A34) {
fclose(file);
return NULL;
}
nextUINT32 = freadUINT32(file);
if (nextUINT32 != 0x7651B5DA) {
fclose(file);
return NULL;
}
//the magic number is good. this is definitely a RIP file
//start reading the records
Rip* rip = NULL;
unsigned int nextRecordID = freadUINT32(file);
while (!feof(file)) {
unsigned int nextRecordSize = freadUINT32(file);
switch (nextRecordID) {
case ID_HEADER_RECORD:
{
freadUINT16(file); //major file format version
freadUINT16(file); //minor file format version
UINT32 targetSystemID = freadUINT32(file); //target system
rip = new Rip(targetSystemID);
break;
}
/*
case ID_BIOS_COMPAT_RECORD:
tmp1 = ripFile->biosCount;
ripFile->biosCompat[tmp1] =
malloc(sizeof(BiosCompatRecord));
ripFile->biosCompat[tmp1]->periphNum = fgetc(file);
ripFile->biosCompat[tmp1]->biosTypeNum = fgetc(file);
ripFile->biosCompat[tmp1]->biosNum = fgetc(file);
ripFile->biosCompat[tmp1]->compatibility = fgetc(file);
if (ripFile->biosCompat[tmp1]->compatibility > 2)
ripFile->biosCompat[tmp1]->compatibility = 2;
ripFile->biosCount++;
break;
*/
case ID_PERIPH_COMPAT_RECORD:
{
if (!rip)
return NULL;
UINT32 periphID = freadUINT32(file);
PeripheralCompatibility usage = (PeripheralCompatibility)(fgetc(file) & 0x03);
rip->AddPeripheralUsage((periphID == ID_PERIPH_ECS ? "ECS" : "Intellivoice"), usage);
break;
}
case ID_NAME_RECORD:
{
if (!rip)
return NULL;
CHAR name[MAX_STRING_LENGTH];
freadString(file, name, MAX_STRING_LENGTH);
rip->SetName(name);
break;
}
case ID_PRODUCER_RECORD:
{
if (!rip)
return NULL;
CHAR producer[MAX_STRING_LENGTH];
freadString(file, producer, MAX_STRING_LENGTH);
rip->SetProducer(producer);
break;
}
case ID_YEAR_RECORD:
{
if (!rip)
return NULL;
CHAR year[MAX_STRING_LENGTH];
freadString(file, year, MAX_STRING_LENGTH);
rip->SetProducer(year);
break;
}
case ID_RAM_RECORD:
{
if (!rip)
return NULL;
//TODO: handle when we exceed maximum memory units
UINT8 flags = (UINT8)fgetc(file);
BOOL partialReads = !!(flags & 0x80);
BOOL partialWrites = !!(flags & 0x40);
BOOL banked = !!(flags & 0x20);
UINT8 addressByteWidth = (flags & 0x0F)+1;
flags = (UINT8)fgetc(file);
UINT8 dataBitWidth = (flags & 0x7F)+1;
UINT16 address = (UINT16)freadInt(file, addressByteWidth);
UINT16 size = (UINT16)freadInt(file, addressByteWidth);
//RAM reset value unused at this point, so skip it
freadInt(file, (dataBitWidth+7)/8);
UINT16 readMask = 0xFFFF;
if (partialReads)
readMask = (UINT16)freadInt(file, addressByteWidth);
UINT16 writeMask = 0xFFFF;
if (partialWrites)
writeMask = (UINT16)freadInt(file, addressByteWidth);
if (banked) {
//banking descriptors not yet supported, so just need to skip 'em
UINT32 bankingDescriptorCount = freadUINT32(file);
for (UINT32 k = 0; k < bankingDescriptorCount; k++) {
freadInt(file, addressByteWidth); //target address width
freadInt(file, addressByteWidth); //write decoding mask
freadInt(file, (dataBitWidth+7)/8); //reset value
UINT32 dataCount = freadUINT32(file);
for (UINT32 l = 0; l < dataCount; l++)
freadInt(file, (dataBitWidth+7)/8); //data banking match values
}
}
rip->AddRAM(new RAM(size, address, readMask, writeMask, dataBitWidth));
}
case ID_ROM_RECORD:
{
if (!rip)
return NULL;
//TODO: handle when we exceed maximum memory units
UINT8 flags = (UINT8)fgetc(file);
BOOL partialReads = !!(flags & 0x80);
BOOL compressed = !!(flags & 0x40);
BOOL banked = !!(flags & 0x20);
UINT8 addressByteWidth = (flags & 0x0F)+1;
flags = (UINT8)fgetc(file);
UINT8 dataBitWidth = (flags & 0x7F)+1;
UINT16 address = (UINT16)freadInt(file, addressByteWidth);
UINT32 arraySize = freadUINT32(file);
UINT8* romImage = NULL;
if (compressed) {
//TODO: support zlib compressed rom images
for (UINT32 k = 0; k < arraySize; k++)
fgetc(file);
arraySize = 0;
romImage = new UINT8[0];
}
else {
UINT32 dataByteWidth = (dataBitWidth+7)/8;
romImage = new UINT8[arraySize*dataByteWidth];
for (UINT32 k = 0; k < arraySize; k++) {
for (UINT8 l = 0; l < dataByteWidth; l++)
romImage[(k*dataByteWidth)+(dataByteWidth-l-1)] = (UINT8)fgetc(file);
}
}
UINT16 readMask = 0xFFFF;
if (partialReads)
readMask = (UINT16)freadInt(file, addressByteWidth);
if (banked) {
//banking descriptors not yet supported, so just need to skip 'em
UINT32 bankingDescriptorCount = freadUINT32(file);
for (UINT32 k = 0; k < bankingDescriptorCount; k++) {
freadInt(file, addressByteWidth); //target address width
freadInt(file, addressByteWidth); //write decoding mask
freadInt(file, (dataBitWidth+7)/8); //reset value
UINT32 dataCount = freadUINT32(file);
for (UINT32 l = 0; l < dataCount; l++)
freadInt(file, (dataBitWidth+7)/8); //data banking match values
}
}
rip->AddROM(new ROM("Cartridge ROM", (void*)romImage, (dataBitWidth+7)/8, (UINT16)arraySize, address, readMask));
delete[] romImage;
break;
}
default:
{
//unknown record; just skip it
for (UINT32 i = 0; i < nextRecordSize; i++)
fgetc(file);
}
}
nextRecordID = freadUINT32(file);
}
fclose(file);
rip->SetFileName(filename);
rip->crc = CRC32::getCrc(filename);
return rip;
}
BOOL Rip::SaveRip(const CHAR* filename)
{
FILE* file = fopen(filename, "wb");
if (file == NULL) {
printf("Error: Unable to create file %s\n", filename);
return 1;
}
//write the 64-bit magic RIP XBF number
fwriteUINT64(file, RIP_MAGIC_NUMBER);
//write the header record
fwriteUINT32(file, ID_HEADER_RECORD);
//write the header record size in bytes
fwriteUINT32(file, 9);
//write the major RIP revision number
fwriteUINT16(file, RIP_MAJOR_REVISION);
//write the minor RIP revision number
fwriteUINT16(file, RIP_MINOR_REVISION);
//write the system id
fwriteUINT32(file, targetSystemID);
//write the name record
fwriteUINT32(file, ID_NAME_RECORD);
fwriteUINT32(file, (UINT32)(4+strlen(GetName())));
fwriteString(file, GetName());
//write the year record
fwriteUINT32(file, ID_YEAR_RECORD);
fwriteUINT32(file, (UINT32)(4+strlen(year)));
fwriteString(file, year);
//write the producer record
fwriteUINT32(file, ID_PRODUCER_RECORD);
fwriteUINT32(file, (UINT32)(4+strlen(producer)));
fwriteString(file, producer);
//write the peripheral compatibility records
for (UINT16 i = 0; i < peripheralCount; i++) {
fwriteUINT32(file, ID_PERIPH_COMPAT_RECORD);
fwriteUINT32(file, 5);
//these records are hard-coded for Intellivision now, will have to work out something more
//flexible when Atari 5200 support is re-added in the future
fwriteUINT32(file, (strcmpi(peripheralNames[i], "Intellivoice") == 0) ? ID_PERIPH_INTELLIVOICE : ID_PERIPH_ECS);
fputc(peripheralUsages[i], file);
}
//write the RAM records
UINT16 ramCount = GetRAMCount();
for (UINT16 i = 0; i < ramCount; i++) {
RAM* nextMem = GetRAM(i);
fwriteUINT32(file, ID_RAM_RECORD);
UINT16 readMask = nextMem->getReadAddressMask();
UINT16 writeMask = nextMem->getWriteAddressMask();
UINT16 byteWidth = (nextMem->getBitWidth()+7)/8;
//calculate the size of the RAM record
int recordSize = 1 + //flags
1 + //more flags
2 + //address
2 + //size
byteWidth + //reset value
(readMask != 0xFFFF ? 2 : 0) + //read mask
(writeMask != 0xFFFF ? 2 : 0) + //write mask
0; //banking not supported just yet
fwriteUINT32(file, recordSize);
//flags #1
fputc(((readMask != 0xFFFF) ? 0x80 : 0) |
((writeMask != 0xFFFF) ? 0x40 : 0) |
1, file);
//flags #2
fputc(nextMem->getBitWidth()-1, file);
//address
fwriteUINT16(file, nextMem->getReadAddress());
//size
fwriteUINT16(file, nextMem->getReadSize());
//reset value, always zero
for (UINT16 k = 0; k < byteWidth; k++)
fputc(0, file);
//read mask
if (readMask != 0xFFFF)
fwriteUINT16(file, readMask);
//write mask
if (writeMask != 0xFFFF)
fwriteUINT16(file, writeMask);
}
//write the ROM records
UINT16 romCount = GetROMCount();
for (UINT16 i = 0; i < romCount; i++) {
ROM* nextMem = GetROM(i);
fwriteUINT32(file, ID_ROM_RECORD);
//calculate the size of the ROM record
UINT16 readMask = nextMem->getReadAddressMask();
UINT16 byteWidth = nextMem->getByteWidth();
UINT16 memSize = nextMem->getReadSize();
int recordSize = 1 + //flags
1 + //more flags
2 + //address
4 + (byteWidth*memSize) + //ROM image
(readMask != 0xFFFF ? 2 : 0) + //read mask
0; //banking not supported just yet
fwriteUINT32(file, recordSize);
//flags #1
fputc(((readMask != 0xFFFF) ? 0x80 : 0) |
1, file);
//flags #2
fputc((byteWidth*8)-1, file);
//address
UINT16 address = nextMem->getReadAddress();
fwriteUINT16(file, address);
//ROM image
fwriteUINT32(file, memSize);
for (UINT16 j = 0; j < memSize; j++) {
switch (byteWidth) {
case 1:
fputc(nextMem->peek(address+j), file);
break;
case 2:
fwriteUINT16(file, nextMem->peek(address+j));
break;
case 4:
fwriteUINT32(file, nextMem->peek(address+j));
break;
default:
for (UINT8 k = 0; k < byteWidth; k++)
fputc(0, file);
}
}
//read mask
if (readMask != 0xFFFF)
fwriteUINT16(file, readMask);
}
fclose(file);
return 0;
}

87
arm9/source/emucore/Rip.h Normal file
View File

@ -0,0 +1,87 @@
#ifndef RIP_H
#define RIP_H
#include <string.h>
#include <vector>
#include "ripxbf.h"
#include "types.h"
#include "Peripheral.h"
#include "Memory.h"
using namespace std;
#define MAX_BIOSES 16
#define MAX_PERIPHERALS 16
typedef struct _CartridgeConfiguration CartridgeConfiguration;
class Rip : public Peripheral
{
public:
virtual ~Rip();
void SetTargetSystemID(UINT32 t) { this->targetSystemID = t; }
UINT32 GetTargetSystemID() { return targetSystemID; }
void SetName(const CHAR* p);
void SetProducer(const CHAR* p);
const CHAR* GetProducer() { return producer; }
void SetYear(const CHAR* y);
const CHAR* GetYear() { return year; }
PeripheralCompatibility GetPeripheralUsage(const CHAR* periphName);
//load a regular .rip file
static Rip* LoadRip(const CHAR* filename);
//load a raw binary Atari 5200 image of a game
static Rip* LoadA52(const CHAR* filename);
//load a raw binary Intellivision image of a game
static Rip* LoadBin(const CHAR* filename, const CHAR* cfgFilename);
//load a raw binary image contained within a .zip file
static Rip* LoadZip(const CHAR* filename, const CHAR* cfgFilename);
//load an Intellivision .rom file
static Rip* LoadRom(const CHAR* filename);
BOOL SaveRip(const CHAR* filename);
const CHAR* GetFileName() {
return this->filename;
}
UINT32 GetCRC() {
return this->crc;
}
private:
Rip(UINT32 systemID);
//Rip(UINT32 systemID, const CHAR* nme, const CHAR* prducer, const CHAR* yr);
void AddPeripheralUsage(const CHAR* periphName, PeripheralCompatibility usage);
static Rip* LoadCartridgeConfiguration(const CHAR* cfgFile, UINT32 crc);
void SetFileName(const CHAR* fname) {
strncpy(this->filename, fname, sizeof(this->filename));
}
UINT32 targetSystemID;
CHAR* producer;
CHAR* year;
//peripheral compatibility indicators
CHAR* peripheralNames[MAX_PERIPHERALS];
PeripheralCompatibility peripheralUsages[MAX_PERIPHERALS];
UINT32 peripheralCount;
CHAR filename[MAX_PATH];
UINT32 crc;
};
#endif

View File

@ -0,0 +1,956 @@
#include <nds.h>
#include "SP0256.h"
INT32 repeat __attribute__((section(".dtcm")));
INT32 period __attribute__((section(".dtcm")));
INT32 periodCounter __attribute__((section(".dtcm")));
INT32 amplitude __attribute__((section(".dtcm")));
INT8 b[6] __attribute__((section(".dtcm")));
INT8 f[6] __attribute__((section(".dtcm")));
INT32 y[6][2] __attribute__((section(".dtcm")));
INT8 periodInterpolation __attribute__((section(".dtcm")));
INT8 amplitudeInterpolation __attribute__((section(".dtcm")));
UINT16 bitMasks[16] __attribute__((section(".dtcm"))) = {
0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
INT16 qtbl[256] __attribute__((section(".dtcm"))) = {
0, 511, 510, 509, 508, 507, 506, 505,
504, 503, 502, 501, 500, 499, 498, 497,
496, 495, 494, 493, 492, 491, 490, 489,
488, 487, 486, 485, 484, 483, 482, 481,
479, 477, 475, 473, 471, 469, 467, 465,
463, 461, 459, 457, 455, 453, 451, 449,
447, 445, 443, 441, 439, 437, 435, 433,
431, 429, 427, 425, 421, 417, 413, 409,
405, 401, 397, 393, 389, 385, 381, 377,
373, 369, 365, 361, 357, 353, 349, 345,
341, 337, 333, 329, 325, 321, 317, 313,
309, 305, 301, 297, 289, 281, 273, 265,
257, 249, 241, 233, 225, 217, 209, 201,
193, 185, 177, 169, 161, 153, 145, 137,
129, 121, 113, 105, 97, 89, 81, 73,
65, 57, 49, 41, 33, 25, 12, 9,
0, -9, -12, -25, -33, -41, -49, -57,
-65, -73, -81, -89, -97, -105, -113, -121,
-129, -137, -145, -153, -161, -169, -177, -185,
-193, -201, -209, -217, -225, -233, -241, -249,
-257, -265, -273, -281, -289, -297, -301, -305,
-309, -313, -317, -321, -325, -329, -333, -337,
-341, -345, -349, -353, -357, -361, -365, -369,
-373, -377, -381, -385, -389, -393, -397, -401,
-405, -409, -413, -417, -421, -425, -427, -429,
-431, -433, -435, -437, -439, -441, -443, -445,
-447, -449, -451, -453, -455, -457, -459, -461,
-463, -465, -467, -469, -471, -473, -475, -477,
-479, -481, -482, -483, -484, -485, -486, -487,
-488, -489, -490, -491, -492, -493, -494, -495,
-496, -497, -498, -499, -500, -501, -502, -503,
-504, -505, -506, -507, -508, -509, -510, -511
};
SP0256::SP0256()
: Processor("SP0256"),
ivoiceROM("Intellivoice ROM", "ivoice.bin", 0, 1, 0x800, 0x1000, TRUE)
{
registers.init(this);
}
INT32 SP0256::getClockSpeed() {
return 10000;
}
INT32 SP0256::getClocksPerSample() {
return 1;
}
void SP0256::resetProcessor()
{
currentBits = 0;
bitsLeft = 0;
pc = 0;
page = 1;
stack = 0;
mode = 0;
repeatPrefix = 0;
command = 0;
lrqHigh = TRUE;
idle = TRUE;
fifoHead = 0;
fifoSize = 0;
speaking = FALSE;
amplitude = 0;
period = 0;
periodCounter = 0x1;
random = 1;
for (INT32 i = 0; i < 6; i++) {
y[i][0] = 0;
y[i][1] = 0;
}
}
INT32 SP0256::tick(INT32 minimum)
{
if (idle) {
//for (int i = 0; i < minimum; i++)
// audioOutputLine->playSample(0);
return minimum;
}
INT32 totalTicks = 0;
do {
if (!speaking) {
speaking = TRUE;
lrqHigh = TRUE;
pc = 0x1000 | (command << 1);
bitsLeft = 0;
command = 0;
}
//if the speaking filters are empty, fill 'em up
while (!idle && repeat == 0) {
INT32 repeatBefore = repeatPrefix;
decode();
if (repeatBefore != 0)
repeatPrefix = 0;
}
INT32 sample = 0;
if (period == 0) {
if (periodCounter == 0) {
periodCounter = 64;
repeat--;
for (UINT8 j = 0; j < 6; j++)
y[j][0] = y[j][1] = 0;
}
else
periodCounter--;
sample = ((amplitude & 0x1F) << ((amplitude & 0xE0) >> 5));
BOOL noise = ((random & 1) != 0);
random = (random >> 1) ^ (noise ? 0x14000 : 0);
if (!noise)
sample = -sample;
}
else {
if (periodCounter == 0) {
periodCounter = period;
repeat--;
sample = ((amplitude & 0x1F) << ((amplitude & 0xE0) >> 5));
for (INT32 j = 0; j < 6; j++)
y[j][0] = y[j][1] = 0;
}
else
periodCounter--;
}
period = ((period | 0x10000) + periodInterpolation) & 0xFFFF;
amplitude = ((amplitude | 0x10000) + amplitudeInterpolation) & 0xFFFF;
for (INT32 i = 0; i < 6; i++) {
sample += ((qtbl[0x80+b[i]]*y[i][1]) >> 9);
sample += ((qtbl[0x80+f[i]]*y[i][0]) >> 8);
y[i][1] = y[i][0];
y[i][0] = sample;
}
//clamp the sample to a 12-bit range
if (sample > 2047) sample = 2047;
if (sample < -2048) sample = -2048;
audioOutputLine->playSample((INT16)(sample << 4));
totalTicks++;
} while (totalTicks < minimum);
return totalTicks;
}
INT8 SP0256::readDelta(INT32 numBits) {
INT32 value = readBits(numBits);
if ((value & (1 << (numBits - 1))) != 0)
value |= -1 << numBits;
return (INT8)value;
}
INT32 SP0256::readBitsReverse(INT32 numBits)
{
while (bitsLeft < numBits) {
if (pc < 0x1800) {
currentBits |= (ivoiceROM.peek((UINT16)pc) << bitsLeft);
bitsLeft += 8;
pc = (pc+1) & 0xFFFF;
}
else if (pc == 0x1800 && fifoSize > 0) {
currentBits |= (fifoBytes[fifoHead] << bitsLeft);
fifoHead = (fifoHead+1) & 0x3F;
fifoSize--;
bitsLeft += 10;
}
else {
//error, read outside of bounds
currentBits |= (0x03FF << bitsLeft);
bitsLeft += 10;
pc = (pc+1) & 0xFFFF;
}
}
INT32 output = currentBits & bitMasks[numBits-1];
output = flipEndian(output, numBits);
currentBits = currentBits >> numBits;
bitsLeft -= numBits;
return output;
}
INT32 SP0256::readBits(INT32 numBits)
{
while (bitsLeft < numBits) {
if (pc < 0x1800) {
currentBits |= (ivoiceROM.peek((UINT16)pc) << bitsLeft);
bitsLeft += 8;
pc = (pc+1) & 0xFFFF;
}
else if (pc == 0x1800 && fifoSize > 0) {
currentBits |= (fifoBytes[fifoHead] << bitsLeft);
fifoHead = (fifoHead+1) & 0x3F;
fifoSize--;
bitsLeft += 10;
}
else {
//error, read outside of bounds
currentBits |= (0x03FF << bitsLeft);
bitsLeft += 10;
pc = (pc+1) & 0xFFFF;
}
}
INT32 output = currentBits & bitMasks[numBits-1];
currentBits = currentBits >> numBits;
bitsLeft -= numBits;
return output;
}
void SP0256::RTS() {
if (stack == 0) {
if (!lrqHigh) {
pc = 0x1000 | (command << 1);
bitsLeft = 0;
command = 0;
lrqHigh = TRUE;
}
else {
speaking = FALSE;
idle = TRUE;
}
}
else {
pc = stack;
stack = 0;
bitsLeft = 0;
}
}
void SP0256::SETPAGE(INT32 immed4) {
this->page = flipEndian(immed4, 4);
}
void SP0256::LOADALL(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = readBits(8);
period = readBits(8);
//periodCounter = (period == 0 ? 0x100 : period);
b[0] = (INT8)readBits(8);
f[0] = (INT8)readBits(8);
b[1] = (INT8)readBits(8);
f[1] = (INT8)readBits(8);
b[2] = (INT8)readBits(8);
f[2] = (INT8)readBits(8);
b[3] = (INT8)readBits(8);
f[3] = (INT8)readBits(8);
b[4] = (INT8)readBits(8);
f[4] = (INT8)readBits(8);
b[5] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
if ((mode & 0x01) == 0) {
amplitudeInterpolation = 0;
periodInterpolation = 0;
}
else {
amplitudeInterpolation = (INT8)readBits(8);
periodInterpolation = (INT8)readBits(8);
}
}
void SP0256::LOAD_2(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
period = readBits(8);
//periodCounter = (period == 0 ? 0x100 : period);
switch (mode) {
case 0x0:
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
b[5] = 0;
f[5] = 0;
break;
case 0x1:
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
b[5] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
break;
case 0x2:
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
b[4] = (INT8)readBits(8);
f[4] = (INT8)readBits(8);
b[5] = 0;
f[5] = 0;
break;
case 0x3:
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
b[4] = (INT8)readBits(8);
f[4] = (INT8)readBits(8);
b[5] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
break;
}
amplitudeInterpolation = (INT8)
((amplitudeInterpolation & 0xE0) | (readBits(5)));
periodInterpolation = (INT8)
((periodInterpolation & 0xE0) | (readBits(5)));
}
void SP0256::SETMSB_3(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
if (mode == 0x00 || mode == 0x02) {
b[5] = 0;
f[5] = 0;
}
switch (mode) {
case 0x0:
case 0x1:
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
break;
case 0x2:
case 0x3:
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
break;
}
amplitudeInterpolation = (INT8)
((amplitudeInterpolation & 0xE0) | (readBits(5)));
periodInterpolation = (INT8)
((periodInterpolation & 0xE0) | (readBits(5)));
}
void SP0256::LOAD_4(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
period = readBits(8);
//periodCounter = (period == 0 ? 0x100 : period);
b[0] = 0;
f[0] = 0;
b[1] = 0;
f[1] = 0;
b[2] = 0;
f[2] = 0;
switch (mode) {
case 0x0:
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
b[5] = 0;
f[5] = 0;
break;
case 0x1:
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
b[5] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
break;
case 0x2:
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
b[4] = (INT8)readBits(8);
f[4] = (INT8)readBits(8);
b[5] = 0;
f[5] = 0;
break;
case 0x3:
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
b[4] = (INT8)readBits(8);
f[4] = (INT8)readBits(8);
b[5] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
break;
}
amplitudeInterpolation = 0;
periodInterpolation = 0;
}
void SP0256::SETMSB_5(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
period = readBits(8);
//periodCounter = (period == 0 ? 0x100 : period);
if (mode == 0x00 || mode == 0x02) {
b[5] = 0;
f[5] = 0;
}
switch (mode) {
case 0x0:
case 0x1:
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
break;
case 0x2:
case 0x3:
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
break;
}
}
void SP0256::SETMSB_6(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
if (mode == 0x00 || mode == 0x02) {
b[5] = 0;
f[5] = 0;
}
switch (mode) {
case 0x0:
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
b[5] = 0;
f[5] = 0;
break;
case 0x1:
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
f[5] = (INT8)readBits(8);
break;
case 0x2:
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
f[4] = (INT8)readBits(8);
b[5] = 0;
f[5] = 0;
break;
case 0x3:
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
f[4] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
break;
}
}
void SP0256::JMP(INT32 immed4) {
pc = (page << 12) | (flipEndian(immed4, 4) << 8) | readBitsReverse(8);
bitsLeft = 0;
}
void SP0256::SETMODE(INT32 immed4) {
immed4 = flipEndian(immed4, 4);
mode = immed4 & 0x3;
repeatPrefix = (immed4 & 0xC) >> 2;
}
void SP0256::DELTA_9(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (amplitude + 0x10000 + (readDelta(4) << 2))
& 0xFFFF;
period = (period + 0x10000 + readDelta(5)) & 0xFFFF;
//periodCounter = (period == 0 ? 0x100 : period);
switch (mode) {
case 0x0:
b[0] += readDelta(3) << 4;
f[0] += readDelta(3) << 3;
b[1] += readDelta(3) << 4;
f[1] += readDelta(3) << 3;
b[2] += readDelta(3) << 4;
f[2] += readDelta(3) << 3;
b[3] += readDelta(3) << 3;
f[3] += readDelta(4) << 2;
b[4] += readDelta(4) << 1;
f[4] += readDelta(4) << 2;
break;
case 0x1:
b[0] += readDelta(3) << 4;
f[0] += readDelta(3) << 3;
b[1] += readDelta(3) << 4;
f[1] += readDelta(3) << 3;
b[2] += readDelta(3) << 4;
f[2] += readDelta(3) << 3;
b[3] += readDelta(3) << 3;
f[3] += readDelta(4) << 2;
b[4] += readDelta(4) << 1;
f[4] += readDelta(4) << 2;
b[5] += readDelta(5) << 0;
f[5] += readDelta(5) << 0;
break;
case 0x2:
b[0] += readDelta(4) << 2;
f[0] += readDelta(4) << 0;
b[1] += readDelta(4) << 1;
f[1] += readDelta(4) << 2;
b[2] += readDelta(4) << 1;
f[2] += readDelta(4) << 2;
b[3] += readDelta(4) << 1;
f[3] += readDelta(5) << 2;
b[4] += readDelta(5) << 1;
f[4] += readDelta(5) << 1;
break;
case 0x3:
b[0] += readDelta(4) << 2;
f[0] += readDelta(4) << 0;
b[1] += readDelta(4) << 1;
f[1] += readDelta(4) << 2;
b[2] += readDelta(4) << 1;
f[2] += readDelta(4) << 2;
b[3] += readDelta(4) << 1;
f[3] += readDelta(5) << 2;
b[4] += readDelta(5) << 1;
f[4] += readDelta(5) << 1;
b[5] += readDelta(5) << 0;
f[5] += readDelta(5) << 0;
break;
}
}
void SP0256::SETMSB_A(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
switch (mode) {
case 0x0:
case 0x1:
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
break;
case 0x2:
case 0x3:
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
break;
}
}
void SP0256::JSR(INT32 immed4) {
INT32 newpc = (page << 12) | (flipEndian(immed4, 4) << 8) | readBitsReverse(8);
stack = pc;
pc = newpc;
bitsLeft = 0;
}
void SP0256::LOAD_C(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
period = readBits(8);
//periodCounter = (period == 0 ? 0x100 : period);
switch (mode) {
case 0x0:
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
b[5] = 0;
f[5] = 0;
break;
case 0x1:
b[0] = (INT8)((readBits(3) << 4) | (b[0] & 0x0F));
f[0] = (INT8)((readBits(5) << 3) | (f[0] & 0x07));
b[1] = (INT8)((readBits(3) << 4) | (b[1] & 0x0F));
f[1] = (INT8)((readBits(5) << 3) | (f[1] & 0x07));
b[2] = (INT8)((readBits(3) << 4) | (b[2] & 0x0F));
f[2] = (INT8)((readBits(5) << 3) | (f[2] & 0x07));
b[3] = (INT8)((readBits(4) << 3) | (b[3] & 0x07));
f[3] = (INT8)((readBits(6) << 2) | (f[3] & 0x03));
b[4] = (INT8)((readBits(7) << 1) | (b[4] & 0x01));
f[4] = (INT8)((readBits(6) << 2) | (f[4] & 0x03));
b[5] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
break;
case 0x2:
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
b[4] = (INT8)readBits(8);
f[4] = (INT8)readBits(8);
b[5] = 0;
f[5] = 0;
break;
case 0x3:
b[0] = (INT8)((readBits(6) << 1) | (b[0] & 0x01));
f[0] = (INT8)((readBits(6) << 2) | (f[0] & 0x03));
b[1] = (INT8)((readBits(6) << 1) | (b[1] & 0x01));
f[1] = (INT8)((readBits(6) << 2) | (f[1] & 0x03));
b[2] = (INT8)((readBits(6) << 1) | (b[2] & 0x01));
f[2] = (INT8)((readBits(6) << 2) | (f[2] & 0x03));
b[3] = (INT8)((readBits(6) << 1) | (b[3] & 0x01));
f[3] = (INT8)((readBits(7) << 1) | (f[3] & 0x01));
b[4] = (INT8)readBits(8);
f[4] = (INT8)readBits(8);
b[5] = (INT8)readBits(8);
f[5] = (INT8)readBits(8);
break;
}
amplitudeInterpolation = 0;
periodInterpolation = 0;
}
void SP0256::DELTA_D(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (amplitude + 0x10000 + (readDelta(4) << 2))
& 0xFFFF;
period = (period + 0x10000 + readDelta(5)) & 0xFFFF;
//periodCounter = (period == 0 ? 0x100 : period);
switch (mode) {
case 0x0:
b[3] += readDelta(3) << 3;
f[3] += readDelta(4) << 2;
b[4] += readDelta(4) << 1;
f[4] += readDelta(4) << 2;
break;
case 0x1:
b[3] += readDelta(3) << 3;
f[3] += readDelta(4) << 2;
b[4] += readDelta(4) << 1;
f[4] += readDelta(4) << 2;
b[5] += readDelta(5) << 0;
f[5] += readDelta(5) << 0;
break;
case 0x2:
b[3] += readDelta(4) << 1;
f[3] += readDelta(5) << 1;
b[4] += readDelta(5) << 0;
f[4] += readDelta(5) << 0;
break;
case 0x3:
b[3] += readDelta(4) << 1;
f[3] += readDelta(5) << 1;
b[4] += readDelta(5) << 0;
f[4] += readDelta(5) << 0;
b[5] += readDelta(5) << 0;
f[5] += readDelta(5) << 0;
break;
}
}
void SP0256::LOAD_E(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
amplitude = (readBits(6) << 2) | (amplitude & 0x03);
period = readBits(8);
//periodCounter = (period == 0 ? 0x100 : period);
}
void SP0256::PAUSE(INT32 immed4) {
repeat = (repeatPrefix << 4) | immed4;
if (repeat == 0)
return;
//clear everything
amplitude = 0;
period = 0;
for (INT32 j = 0; j < 6; j++) {
b[j] = 0;
f[j] = 0;
}
amplitudeInterpolation = 0;
periodInterpolation = 0;
}
void SP0256::decode() {
INT32 immed4 = readBits(4);
INT32 nextInstruction = readBitsReverse(4);
switch (nextInstruction) {
case 0x0:
if (immed4 == 0)
RTS();
else
SETPAGE(immed4);
break;
case 0x8:
SETMODE(immed4);
break;
case 0x4:
LOAD_4(immed4);
break;
case 0xC:
LOAD_C(immed4);
break;
case 0x2:
LOAD_2(immed4);
break;
case 0xA:
SETMSB_A(immed4);
break;
case 0x6:
SETMSB_6(immed4);
break;
case 0xE:
LOAD_E(immed4);
break;
case 0x1:
LOADALL(immed4);
break;
case 0x9:
DELTA_9(immed4);
break;
case 0x5:
SETMSB_5(immed4);
break;
case 0xD:
DELTA_D(immed4);
break;
case 0x3:
SETMSB_3(immed4);
break;
case 0xB:
JSR(immed4);
break;
case 0x7:
JMP(immed4);
break;
case 0xF:
PAUSE(immed4);
break;
/*
case 0x0:
if (immed4 == 0)
RTS();
else
SETPAGE(immed4);
break;
case 0x1:
SETMODE(immed4);
break;
case 0x2:
LOAD_4(immed4);
break;
case 0x3:
LOAD_C(immed4);
break;
case 0x4:
LOAD_2(immed4);
break;
case 0x5:
SETMSB_A(immed4);
break;
case 0x6:
SETMSB_6(immed4);
break;
case 0x7:
LOAD_E(immed4);
break;
case 0x8:
LOADALL(immed4);
break;
case 0x9:
DELTA_9(immed4);
break;
case 0xA:
SETMSB_5(immed4);
break;
case 0xB:
DELTA_D(immed4);
break;
case 0xC:
SETMSB_3(immed4);
break;
case 0xD:
JSR(immed4);
break;
case 0xE:
JMP(immed4);
break;
case 0xF:
PAUSE(immed4);
break;
*/
}
}
INT32 SP0256::flipEndian(INT32 value, INT32 bits) {
INT32 output = 0;
INT32 bitMask = 1;
for (INT32 i = 0; i < bits; i++) {
INT32 offset = (bits-1)-(i<<1);
if (offset > 0)
output |= (value & bitMask) << offset;
else
output |= (value & bitMask) >> -offset;
bitMask = bitMask << 1;
}
return output;
}
SP0256State SP0256::getState()
{
SP0256State state = {0};
#if 0
state.bitsLeft = this->bitsLeft;
state.currentBits = this->currentBits;
state.pc = this->pc;
state.stack = this->stack;
state.mode = this->mode;
state.repeatPrefix = this->repeatPrefix;
state.page = this->page;
state.command = this->command;
state.idle = this->idle;
state.lrqHigh = this->lrqHigh;
state.speaking = this->speaking;
memcpy(state.fifoBytes, this->fifoBytes, sizeof(this->fifoBytes));
state.fifoHead = this->fifoHead;
state.fifoSize = this->fifoSize;
state.repeat = this->repeat;
state.period = this->period;
state.periodCounter = this->periodCounter;
state.amplitude = this->amplitude;
memcpy(state.b, this->b, sizeof(this->b));
memcpy(state.f, this->f, sizeof(this->f));
memcpy(state.y, this->y, sizeof(this->f));
state.periodInterpolation = this->periodInterpolation;
state.amplitudeInterpolation = this->amplitudeInterpolation;
state.random = this->random;
#endif
return state;
}
void SP0256::setState(SP0256State state)
{
#if 0
this->bitsLeft = state.bitsLeft;
this->currentBits = state.currentBits;
this->pc = state.pc;
this->stack = state.stack;
this->mode = state.mode;
this->repeatPrefix = state.repeatPrefix;
this->page = state.page;
this->command = state.command;
this->idle = state.idle;
this->lrqHigh = state.lrqHigh;
this->speaking = state.speaking;
memcpy(this->fifoBytes, state.fifoBytes, sizeof(this->fifoBytes));
this->fifoHead = state.fifoHead;
this->fifoSize = state.fifoSize;
this->repeat = state.repeat;
this->period = state.period;
this->periodCounter = state.periodCounter;
this->amplitude = state.amplitude;
memcpy(this->b, state.b, sizeof(this->b));
memcpy(this->f, state.f, sizeof(this->f));
memcpy(this->y, state.y, sizeof(this->f));
this->periodInterpolation = state.periodInterpolation;
this->amplitudeInterpolation = state.amplitudeInterpolation;
this->random = state.random;
#endif
}

View File

@ -0,0 +1,125 @@
#ifndef MICROSEQUENCER_H
#define MICROSEQUENCER_H
#include "AudioProducer.h"
#include "SP0256_Registers.h"
#include "types.h"
#include "Processor.h"
#include "ROM.h"
#include "AudioOutputLine.h"
#define FIFO_LOCATION 0x1800
#define FIFO_MAX_SIZE 64
//#define FIFO_END (FIFO_LOCATION + FIFO_MAX_SIZE)
//registers
extern INT32 repeat;
extern INT32 period;
extern INT32 periodCounter;
extern INT32 amplitude;
extern INT8 b[6];
extern INT8 f[6];
extern INT32 y[6][2];
extern INT8 periodInterpolation;
extern INT8 amplitudeInterpolation;
TYPEDEF_STRUCT_PACK( _SP0256State
{
INT32 bitsLeft;
INT32 currentBits;
INT32 pc;
INT32 stack;
INT32 mode;
INT32 repeatPrefix;
INT32 page;
INT32 command;
INT32 repeat;
INT32 period;
INT32 periodCounter;
INT32 amplitude;
INT32 random;
INT32 fifoHead;
INT32 fifoSize;
INT32 fifoBytes[64];
INT32 y[6][2];
INT8 b[6];
INT8 f[6];
INT8 periodInterpolation;
INT8 amplitudeInterpolation;
INT8 idle;
INT8 lrqHigh;
INT8 speaking;
UINT8 _pad6[3];
} SP0256State; )
class SP0256 : public Processor, public AudioProducer
{
friend class SP0256_Registers;
public:
SP0256();
void resetProcessor();
INT32 getClockSpeed();
INT32 getClocksPerSample();
INT32 getSampleRate() { return getClockSpeed(); }
INT32 tick(INT32);
inline BOOL isIdle() { return idle; }
SP0256State getState();
void setState(SP0256State state);
SP0256_Registers registers;
ROM ivoiceROM;
private:
INT8 readDelta(INT32 numBits);
INT32 readBits(INT32 numBits);
INT32 readBitsReverse(INT32 numBits);
void RTS();
void SETPAGE(INT32 immed4);
void LOADALL(INT32 immed4);
void LOAD_2(INT32 immed4);
void SETMSB_3(INT32 immed4);
void LOAD_4(INT32 immed4);
void SETMSB_5(INT32 immed4);
void SETMSB_6(INT32 immed4);
void JMP(INT32 immed4);
void SETMODE(INT32 immed4);
void DELTA_9(INT32 immed4);
void SETMSB_A(INT32 immed4);
void JSR(INT32 immed4);
void LOAD_C(INT32 immed4);
void DELTA_D(INT32 immed4);
void LOAD_E(INT32 immed4);
void PAUSE(INT32 immed4);
void decode();
static INT32 flipEndian(INT32 value, INT32 bits);
INT32 bitsLeft;
INT32 currentBits;
//registers
INT32 pc;
INT32 stack;
INT32 mode;
INT32 repeatPrefix;
INT32 page;
INT32 command;
BOOL idle;
BOOL lrqHigh;
BOOL speaking;
INT32 fifoBytes[64];
INT32 fifoHead;
INT32 fifoSize;
//random number generator
INT32 random;
};
#endif

View File

@ -0,0 +1,51 @@
#include "SP0256.h"
#include "SP0256_Registers.h"
SP0256_Registers::SP0256_Registers()
: RAM(2, 0x0080, 0xFFFF, 0xFFFF)
{}
void SP0256_Registers::init(SP0256* ms)
{
this->ms = ms;
}
void SP0256_Registers::poke(UINT16 location, UINT16 value)
{
switch(location) {
//a poke of any value into $80 means that the SP0256 should
//start speaking
case 0x0080:
if (ms->lrqHigh) {
ms->lrqHigh = FALSE;
ms->command = value & 0xFF;
if (!ms->speaking)
ms->idle = FALSE;
}
break;
//$81 will reset the SP0256 or push an 8-bit value into the queue
case 0x0081:
if (value & 0x0400) {
ms->resetProcessor();
}
else if (ms->fifoSize < FIFO_MAX_SIZE) {
ms->fifoBytes[(ms->fifoHead+ms->fifoSize) & 0x3F] = value;
ms->fifoSize++;
}
break;
}
}
UINT16 SP0256_Registers::peek(UINT16 location) {
switch(location) {
case 0x0080:
return (ms->lrqHigh ? 0x8000 : 0);
case 0x0081:
default:
return (ms->fifoSize == FIFO_MAX_SIZE ? 0x8000 : 0);
}
}

View File

@ -0,0 +1,28 @@
#ifndef MICROSEQUENCER_REGISTERS_H
#define MICROSEQUENCER_REGISTERS_H
#include "types.h"
#include "RAM.h"
class SP0256;
class SP0256_Registers : public RAM
{
friend class SP0256;
public:
void reset() {}
void poke(UINT16 location, UINT16 value);
UINT16 peek(UINT16 location);
private:
SP0256_Registers();
void init(SP0256* ms);
SP0256* ms;
};
#endif

View File

@ -0,0 +1,30 @@
#ifndef SIGNALLINE_H
#define SIGNALLINE_H
#include "types.h"
class Processor;
class SignalLine
{
public:
SignalLine()
{ SignalLine(NULL, 0, NULL, 0); }
SignalLine(Processor* pop, UINT8 pon, Processor* pip, UINT8 pin)
: pinOutProcessor(pop),
pinOutNum(pon),
pinInProcessor(pip),
pinInNum(pin),
isHigh(FALSE) { }
Processor* pinOutProcessor;
UINT8 pinOutNum;
Processor* pinInProcessor;
UINT8 pinInNum;
BOOL isHigh;
};
#endif

View File

@ -0,0 +1,93 @@
#include <stdio.h>
#include <string.h>
#include "VideoBus.h"
VideoBus::VideoBus()
: pixelBuffer(NULL),
pixelBufferSize(0),
pixelBufferRowSize(0),
pixelBufferWidth(0),
pixelBufferHeight(0),
videoProducerCount(0)
{
}
VideoBus::~VideoBus()
{
if (pixelBuffer) {
delete[] pixelBuffer;
}
for (UINT32 i = 0; i < videoProducerCount; i++)
videoProducers[i]->setPixelBuffer(NULL, 0);
}
void VideoBus::addVideoProducer(VideoProducer* p)
{
videoProducers[videoProducerCount] = p;
videoProducers[videoProducerCount]->setPixelBuffer(pixelBuffer, pixelBufferRowSize);
videoProducerCount++;
}
void VideoBus::removeVideoProducer(VideoProducer* p)
{
for (UINT32 i = 0; i < videoProducerCount; i++) {
if (videoProducers[i] == p) {
videoProducers[i]->setPixelBuffer(NULL, 0);
for (UINT32 j = i; j < (videoProducerCount-1); j++)
videoProducers[j] = videoProducers[j+1];
videoProducerCount--;
return;
}
}
}
void VideoBus::removeAll()
{
while (videoProducerCount)
removeVideoProducer(videoProducers[0]);
}
void VideoBus::init(UINT32 width, UINT32 height)
{
VideoBus::release();
pixelBufferWidth = width;
pixelBufferHeight = height;
pixelBufferRowSize = width * sizeof(UINT8);
pixelBufferSize = width * height * sizeof(UINT8);
pixelBuffer = new UINT8[width * height];
printf("VideoBus::init(%d,%d)\n", width, height);
if ( pixelBuffer ) {
memset(pixelBuffer, 0, pixelBufferSize);
}
for (UINT32 i = 0; i < videoProducerCount; i++)
videoProducers[i]->setPixelBuffer(pixelBuffer, pixelBufferRowSize);
}
void VideoBus::render()
{
//tell each of the video producers that they can now output their
//video contents onto the video device
for (UINT32 i = 0; i < videoProducerCount; i++)
videoProducers[i]->render();
}
void VideoBus::release()
{
if (pixelBuffer) {
for (UINT32 i = 0; i < videoProducerCount; i++)
videoProducers[i]->setPixelBuffer(NULL, 0);
pixelBufferWidth = 0;
pixelBufferHeight = 0;
pixelBufferRowSize = 0;
pixelBufferSize = 0;
delete[] pixelBuffer;
pixelBuffer = NULL;
}
}

View File

@ -0,0 +1,37 @@
#ifndef VIDEOBUS_H
#define VIDEOBUS_H
#include "types.h"
#include "VideoProducer.h"
const INT32 MAX_VIDEO_PRODUCERS = 10;
class VideoBus
{
public:
VideoBus();
virtual ~VideoBus();
void addVideoProducer(VideoProducer* ic);
void removeVideoProducer(VideoProducer* ic);
void removeAll();
virtual void init(UINT32 width, UINT32 height);
virtual void render();
virtual void release();
protected:
UINT8* pixelBuffer;
UINT32 pixelBufferSize;
UINT32 pixelBufferRowSize;
UINT32 pixelBufferWidth;
UINT32 pixelBufferHeight;
private:
VideoProducer* videoProducers[MAX_VIDEO_PRODUCERS];
UINT32 videoProducerCount;
};
#endif

View File

@ -0,0 +1,27 @@
#ifndef VIDEOPRODUCER_H
#define VIDEOPRODUCER_H
/**
* This interface is implemented by any piece of hardware that renders graphic
* output.
*/
class VideoProducer
{
public:
/**
* Tells the video producer to render its output. It should *not* flip
* the output onto the screen as that will be done by the video bus
* after all video producers have rendered their output to the back
* buffer.
*
* This function will be called once each time the Emulator indicates
* that it has entered vertical blank.
*/
virtual void setPixelBuffer(UINT8* pixelBuffer, UINT32 rowSize) = 0;
virtual void render() = 0;
};
#endif

View File

@ -0,0 +1,696 @@
D7C78754:Info:4-TRIS (GPL):Joseph Zbiciak:2000
D7C78754:ROM:5000:2000:16
B91488E2:Info:4-TRIS (GPL):Joseph Zbiciak:2001
B91488E2:ROM:5000:2000:16
A60E25FC:Info:ABPA Backgammon:Mattel:1978
A60E25FC:ROM:5000:1000:16
F8B1F2B7:Info:Advanced Dungeons and Dragons:Mattel:1982
F8B1F2B7:ROM:5000:2000:16
16C3B62F:Info:Advanced Dungeons and Dragons - Treasure of Tarmin:Mattel:1982
16C3B62F:ROM:5000:2000:16
11C3BCFA:Info:Adventure (AD&D - Cloudy Mountain):Mattel:1982
11C3BCFA:ROM:5000:2000:16
2C668249:Info:Air Strike:Mattel:1982
2C668249:ROM:5000:1000:16
B45633CF:Info:All-Stars Major League Baseball:Mattel:1980
B45633CF:ROM:5000:2000:16
B45633CF:ROM:D000:1000:16
6F91FBC1:Info:Armor Battle:Mattel:1978
6F91FBC1:ROM:5000:1000:16
00BE8BBA:Info:Astrosmash - Meteor:Mattel:1981
00BE8BBA:ROM:5000:1000:16
FAB2992C:Info:Astrosmash:Mattel:1981
FAB2992C:ROM:5000:1000:16
13FF363C:Info:Atlantis:Imagic:1981
13FF363C:ROM:4800:2000:16
B35C1101:Info:Auto Racing:Mattel:1979
B35C1101:ROM:5000:1000:16
8AD19AB3:Info:B-17 Bomber:Mattel:1981
8AD19AB3:ROM:5000:2000:16
8AD19AB3:ROM:D000:1000:16
8AD19AB3:Peripheral:Intellivoice:Optional
DAB36628:Info:Baseball:Mattel:1978
DAB36628:ROM:5000:1000:16
EAF650CC:Info:BeamRider:Activision:1983
EAF650CC:ROM:5000:2000:16
C047D487:Info:Beauty and the Beast:Imagic:1982
C047D487:ROM:4800:2000:16
B03F739B:Info:Blockade Runner:Interphase:1983
B03F739B:ROM:5000:2000:16
4728C3BD:Info:Blow Out:Mattel:1983
4728C3BD:ROM:5000:1000:16
515E1D7E:Info:Body Slam Super Pro Wrestling:Mattel:1988
515E1D7E:ROM:5000:2000:16
515E1D7E:ROM:9000:2000:16
32697B72:Info:Bomb Squad:Mattel:1982
32697B72:ROM:5000:2000:16
32697B72:ROM:D000:1000:16
32697B72:Peripheral:Intellivoice:Optional
18E08520:Info:Bouncing Pixels (GPL):JRMZ Electronics:1999
18E08520:ROM:5000:0202:16
AB87C16F:Info:Boxing:Mattel:1980
AB87C16F:ROM:5000:1000:16
9F85015B:Info:Brickout!:Mattel:1981
9F85015B:ROM:5000:1000:16
999CCEED:Info:Bump 'N' Jump:Mattel:1982-83
999CCEED:ROM:5000:2000:16
999CCEED:ROM:D000:1000:16
999CCEED:ROM:F000:1000:16
43806375:Info:BurgerTime!:Mattel:1982
43806375:ROM:5000:2000:16
C92BAAE8:Info:BurgerTime! - New Levels Hack:David Harley:2002
C92BAAE8:ROM:5000:2000:16
FA492BBD:Info:Buzz Bombers:Mattel:1982
FA492BBD:ROM:5000:2000:16
43870908:Info:Carnival:Coleco:1982
43870908:ROM:5000:1000:16
D5363B8C:Info:Centipede:Atarisoft:1983
D5363B8C:ROM:6000:2000:16
4CC46A04:Info:Championship Tennis:Nice Ideas:1985
4CC46A04:ROM:5000:2000:16
4CC46A04:ROM:D000:2000:16
36E1D858:Info:Checkers:Mattel:1979
36E1D858:ROM:5000:1000:16
0BF464C6:Info:Chip Shot Super Pro Golf:Mattel:1987
0BF464C6:ROM:5000:2000:16
0BF464C6:ROM:9000:2000:16
47FDD8A8:Info:Choplifter:Mattel:1983
47FDD8A8:ROM:5000:2000:16
47FDD8A8:ROM:D000:2000:16
3289C8BA:Info:Commando:INTV:1987
3289C8BA:ROM:5000:2000:16
3289C8BA:ROM:9000:2000:16
4B23A757:Info:Congo Bongo:Sega:1983
4B23A757:ROM:5000:3000:16
E1EE408F:Info:Crazy Clones:Mattel:1981
E1EE408F:ROM:5000:1000:16
CDC14ED8:Info:Deadly Dogs!:Unknown:1987
CDC14ED8:ROM:5000:1000:16
6802B191:Info:Deep Pockets - Super Pro Pool and Billiards:Realtime:1990
6802B191:ROM:5000:2000:16
6802B191:ROM:9000:2000:16
D8F99AA2:Info:Defender:Atarisoft:1983
D8F99AA2:ROM:5000:3000:16
5E6A8CD8:Info:Demon Attack:Imagic:1982
5E6A8CD8:ROM:4800:2000:16
159AF7F7:Info:Dig Dug:INTV:1987
159AF7F7:ROM:5000:3000:16
159AF7F7:ROM:9000:1000:16
13EE56F1:Info:Diner:INTV:1987
13EE56F1:ROM:5000:2000:16
13EE56F1:ROM:9000:2000:16
C30F61C0:Info:Donkey Kong:Coleco:1982
C30F61C0:ROM:5000:1000:16
6DF61A9F:Info:Donkey Kong Jr:Coleco:1982
6DF61A9F:ROM:5000:2000:16
84BEDCC1:Info:Dracula:Imagic:1982
84BEDCC1:ROM:5000:2000:16
AF8718A1:Info:Dragonfire:Imagic:1982
AF8718A1:ROM:5000:1000:16
3B99B889:Info:Dreadnaught Factor, The:Activision:1983
3B99B889:ROM:5000:2000:16
BF4D0E9B:Info:Dreadnaught Factor, The (Prototype):Activision:1983
BF4D0E9B:ROM:5000:2000:16
20ACE89D:Info:Easter Eggs:Mattel:1981
20ACE89D:ROM:5000:1000:16
54A3FC11:Info:Electric Company - Math Fun:CTW:1978
54A3FC11:ROM:5000:1000:16
C9EAACAB:Info:Electric Company - Word Fun:CTW:1980
C9EAACAB:ROM:5000:1000:16
4221EDE7:Info:Fathom:Imagic:1983
4221EDE7:ROM:5000:2000:16
37222762:Info:Frog Bog:Mattel:1982
37222762:ROM:5000:1000:16
D27495E9:Info:Frogger:Parker Bros:1983
D27495E9:ROM:5000:1000:16
DBCA82C5:Info:Go For The Gold:Mattel:1981
DBCA82C5:ROM:5000:2000:16
291AC826:Info:Grid Shock:Mattel:1982
291AC826:ROM:5000:1000:16
E573863A:Info:Groovy! (GPL):JRMZ Electronics:1999
E573863A:ROM:5000:1E48:16
4B8C5932:Info:Happy Trails:Activision:1983
4B8C5932:ROM:5000:1000:16
120B53A9:Info:Happy Trails (Overdump):Activision:1983
120B53A9:ROM:5000:1000:16
B6A3D4DE:Info:Hard Hat:Mattel:1979
B6A3D4DE:ROM:5000:2000:16
B5C7F25D:Info:Horse Racing:Mattel:1980
B5C7F25D:ROM:5000:1000:16
FF83FF80:Info:Hover Force:Mattel:1986
FF83FF80:ROM:5000:2000:16
FF83FF80:ROM:9000:3000:16
FF83FF80:ROM:D000:1000:16
A3147630:Info:Hypnotic Lights:Mattel:1981
A3147630:ROM:5000:1000:16
4F3E3F69:Info:Ice Trek:Imagic:1983
4F3E3F69:ROM:5000:2000:16
02919024:Info:Intellivision - Intelligent Television Demo:Mattel:1978
02919024:ROM:5000:2000:16
C83EEA4C:Info:Intellivision Test Cartridge and Baseball:Mattel:1978
C83EEA4C:ROM:5000:1000:16
C83EEA4C:ROM:7000:1000:16
985A78ED:Info:IntyOS 0.2 Alpha:Arnauld Chevallier:2003
985A78ED:ROM:5000:1000:16
985A78ED:RAM:D000:1000:16
985A78ED:RAM:F000:1000:16
EE5F1BE2:Info:Jetsons, The - Ways With Words:Mattel:1983
EE5F1BE2:ROM:5000:2000:16
EE5F1BE2:ROM:D000:1000:16
EE5F1BE2:Peripheral:ECS:Required
4422868E:Info:King of the Mountain:Mattel:1982
4422868E:ROM:5000:2000:16
4422868E:ROM:D000:2000:16
8C9819A2:Info:Kool-Aid Man:Mattel:1983
8C9819A2:ROM:5000:2000:16
A6840736:Info:Lady Bug:Coleco:1983
A6840736:ROM:5000:2000:16
3825C25B:Info:Land Battle:Mattel:1982
3825C25B:ROM:5000:2000:16
3825C25B:RAM:D000:400:8
604611C0:Info:Las Vegas Blackjack and Poker:Mattel:1979
604611C0:ROM:5000:1000:16
48D74D3C:Info:Las Vegas Roulette:Mattel:1979
48D74D3C:ROM:5000:1000:16
19360442:Info:League of Light (Prototype Alt1):Activision:1983
19360442:ROM:5000:2000:16
75EE64F6:Info:League of Light (Prototype Alt2):Activision:1983
75EE64F6:ROM:5000:2000:16
B4287B95:Info:League of Light (Prototype):Activision:1983
B4287B95:ROM:5000:2000:16
2C5FD5FA:Info:Learning Fun I - Math Master Factor Fun:INTV:1987
2C5FD5FA:ROM:5000:2000:16
632F6ADF:Info:Learning Fun II - Word Wizard Memory Fun:INTV:1987
632F6ADF:ROM:5000:2000:16
E00D1399:Info:Lock 'N' Chase:Mattel:1982
E00D1399:ROM:5000:2000:16
6B6E80EE:Info:Loco-Motion:Mattel:1982
6B6E80EE:ROM:5000:2000:16
F3B0C759:Info:Magic Carousel:Mattel:1982
F3B0C759:ROM:5000:2000:16
F3B0C759:ROM:D000:2000:16
573B9B6D:Info:Masters of the Universe - The Power of He-Man!:Mattel:1983
573B9B6D:ROM:5000:2000:16
573B9B6D:ROM:D000:1000:16
573B9B6D:ROM:F000:1000:16
7D0F8162:Info:Maze Demo #1 (GPL):JRMZ Electronics:2000
7D0F8162:ROM:5000:016E:16
2138DAD4:Info:Maze Demo #2 (GPL):JRMZ Electronics:2000
2138DAD4:ROM:5000:0175:16
FF68AA22:Info:Melody Blaster:Mattel:1983
FF68AA22:ROM:5000:2000:16
FF68AA22:ROM:D000:1000:16
FF68AA22:Peripheral:ECS:Required
E00E23E7:Info:Mickey's Hello World:Mickey:2000
E00E23E7:ROM:5000:006F:16
E806AD91:Info:Microsurgeon:Imagic:1982
E806AD91:ROM:4800:2000:16
94096229:Info:Minehunter:Ryan Kinnen:2004
94096229:ROM:5000:2000:16
9D57498F:Info:Mind Strike!:Mattel:1982
9D57498F:ROM:5000:2000:16
9D57498F:ROM:D000:1000:16
9D57498F:Peripheral:ECS:Required
6746607B:Info:Minotaur V1.1:Mattel:1981
6746607B:ROM:5000:2000:16
5A4CE519:Info:Minotaur V2:Mattel:1981
5A4CE519:ROM:5000:2000:16
BD731E3C:Info:Minotaur:Mattel:1981
BD731E3C:ROM:5000:2000:16
2F9C93FC:Info:Minotaur (Treasure of Tarmin hack):Mattel:1981
2F9C93FC:ROM:5000:2000:16
11FB9974:Info:Mission X:Mattel:1982
11FB9974:ROM:5000:2000:16
5F6E1AF6:Info:Motocross:Mattel:1982
5F6E1AF6:ROM:5000:2000:16
6B5EA9C4:Info:Mountain Madness Super Pro Skiing:INTV:1987
6B5EA9C4:ROM:5000:2000:16
598662F2:Info:Mouse Trap:Coleco:1982
598662F2:ROM:5000:1000:16
0B50A367:Info:Mr. Basic Meets Bits 'N Bytes (Bad Dump):Mattel:1983
0B50A367:ROM:5000:2000:16
0B50A367:ROM:D000:1000:16
0B50A367:Peripheral:ECS:Required
BEF0B0C7:Info:Mr. Basic Meets Bits 'N Bytes:Mattel:1983
BEF0B0C7:ROM:5000:2000:16
BEF0B0C7:ROM:D000:1000:16
BEF0B0C7:Peripheral:ECS:Required
DBAB54CA:Info:NASL Soccer:Mattel:1979
DBAB54CA:ROM:5000:1000:16
81E7FB8C:Info:NBA Basketball:Mattel:1978
81E7FB8C:ROM:5000:1000:16
4B91CF16:Info:NFL Football:Mattel:1978
4B91CF16:ROM:5000:1000:16
76564A13:Info:NHL Hockey:Mattel:1979
76564A13:ROM:5000:1000:16
7334CD44:Info:Night Stalker:Mattel:1982
7334CD44:ROM:5000:1000:16
5EE2CC2A:Info:Nova Blast:Imagic:1983
5EE2CC2A:ROM:5000:2000:16
E5D1A8D2:Info:Number Jumble:Mattel:1983
E5D1A8D2:ROM:5000:2000:16
E5D1A8D2:ROM:D000:1000:16
E5D1A8D2:ROM:F000:1000:16
A21C31C3:Info:Pac-Man:Atarisoft:1983
A21C31C3:ROM:5000:3000:16
6E4E8EB4:Info:Pac-Man:INTV:1983
6E4E8EB4:ROM:5000:3000:16
169E3584:Info:PBA Bowling:Mattel:1980
169E3584:ROM:5000:1000:16
FF87FAEC:Info:PGA Golf:Mattel:1979
FF87FAEC:ROM:5000:1000:16
D7C5849C:Info:Pinball:Mattel:1981
D7C5849C:ROM:5000:2000:16
D7C5849C:ROM:D000:1000:16
9C75EFCC:Info:Pitfall!:Activision:1982
9C75EFCC:ROM:5000:1000:16
BB939881:Info:Pole Position:INTV:1986
BB939881:ROM:5000:2000:16
BB939881:ROM:9000:2000:16
A982E8D5:Info:Pong:Unknown:1999
A982E8D5:ROM:5000:0800:16
C51464E0:Info:Popeye:Parker Bros:1983
C51464E0:ROM:5000:2000:16
D8C9856A:Info:Q-bert:Parker Bros:1983
D8C9856A:ROM:5000:2000:16
C7BB1B0E:Info:Reversi:Mattel:1984
C7BB1B0E:ROM:5000:1000:16
8910C37A:Info:River Raid:Activision:1982-83
8910C37A:ROM:5000:2000:16
95466AD3:Info:River Raid V1 (Prototype):Activision:1982-83
95466AD3:ROM:5000:2000:16
1682D0B4:Info:Robot Rubble V1 (Prototype) (Overdump):Activision:1983
1682D0B4:ROM:5000:2000:16
7473916D:Info:Robot Rubble V1 (Prototype):Activision:1983
7473916D:ROM:5000:2000:16
A5E28783:Info:Robot Rubble V2 (Prototype):Activision:1983
A5E28783:ROM:5000:2000:16
243B0812:Info:Robot Rubble V3 (Prototype):Activision:1983
243B0812:ROM:5000:2000:16
DCF4B15D:Info:Royal Dealer:Mattel:1981
DCF4B15D:ROM:5000:2000:16
47AA7977:Info:Safecracker:Imagic:1983
47AA7977:ROM:5000:2000:16
6E0882E7:Info:SameGame and Robots:IntelligentVision:2005
6E0882E7:ROM:5000:2000:16
6E0882E7:ROM:D000:1000:16
6E0882E7:ROM:F000:1000:16
12BA58D1:Info:SameGame and Robots (Original):Michael J Hayes:2004
12BA58D1:ROM:5000:2000:16
12BA58D1:ROM:D000:1000:16
12BA58D1:ROM:F000:1000:16
E221808C:Info:Santa's Helper:Mattel:1983
E221808C:ROM:5000:1000:16
E9E3F60D:Info:Scooby Doo's Maze Chase:Mattel/Hanna-Barbera:1983
E9E3F60D:ROM:5000:2000:16
E9E3F60D:Peripheral:ECS:Required
99AE29A9:Info:Sea Battle:Mattel:1980
99AE29A9:ROM:5000:1000:16
E0F0D3DA:Info:Sewer Sam:Interphase:1983
E0F0D3DA:ROM:5000:2000:16
A610406E:Info:Shape Escape:John Doherty:2005
A610406E:ROM:5000:2000:16
2A4C761D:Info:Shark! Shark!:Mattel:1982
2A4C761D:ROM:5000:2000:16
FF7CB79E:Info:Sharp Shot:Mattel:1982
FF7CB79E:ROM:5000:1000:16
800B572F:Info:Slam Dunk Super Pro Basketball:INTV:1987
800B572F:ROM:5000:2000:16
800B572F:ROM:9000:2000:16
BA68FF28:Info:Slap Shot Super Pro Hockey:INTV:1987
BA68FF28:ROM:5000:2000:16
8F959A6E:Info:Snafu:Mattel:1981
8F959A6E:ROM:5000:1000:16
72C2A343:Info:Song Player - Back in the USSR (GPL):Joseph Zbiciak:1999
72C2A343:ROM:5000:2000:16
72C2A343:ROM:9000:1241:16
5E3130E1:Info:Song Player - Copacabana (GPL):Joseph Zbiciak:1999
5E3130E1:ROM:5000:2000:16
5E3130E1:ROM:9000:088F:16
5E3130E1:Peripheral:ECS:Required
C91B1D79:Info:Song Player - Creep (GPL):Joseph Zbiciak:1999
C91B1D79:ROM:5000:1081:16
C91B1D79:Peripheral:ECS:Required
82D2E346:Info:Song Player - Nut March (GPL):Joseph Zbiciak:1999
82D2E346:ROM:5000:1B12:16
82D2E346:Peripheral:ECS:Required
FCF06A8B:Info:Song Player - Nut Reed (GPL):Joseph Zbiciak:1999
FCF06A8B:ROM:5000:145E:16
FCF06A8B:Peripheral:ECS:Required
5914220A:Info:Song Player - Nut Trep (GPL):Joseph Zbiciak:1999
5914220A:ROM:5000:0DC8:16
5914220A:Peripheral:ECS:Required
71F5BE4E:Info:Song Player - Nut Waltz (GPL):Joseph Zbiciak:1999
71F5BE4E:ROM:5000:2000:16
71F5BE4E:ROM:9000:157C:16
71F5BE4E:Peripheral:ECS:Required
437C0E2D:Info:Song Player - Secret Agent Man (GPL):Joseph Zbiciak:1999
437C0E2D:ROM:5000:2000:16
437C0E2D:ROM:9000:15A4:16
437C0E2D:Peripheral:ECS:Required
DA5D77EA:Info:Song Player - Take on Me 3 (GPL):Joseph Zbiciak:1999
DA5D77EA:ROM:5000:12FD:16
DA5D77EA:Peripheral:ECS:Required
10D721CA:Info:Song Player - Take on Me 6 (GPL):Joseph Zbiciak:1999
10D721CA:ROM:5000:1500:16
10D721CA:Peripheral:ECS:Required
CC6F4F90:Info:Song Player - Too Sexy (GPL):Joseph Zbiciak:1999
CC6F4F90:ROM:5000:1AA7:16
CC6F4F90:Peripheral:ECS:Required
E8B8EBA5:Info:Space Armada:Mattel:1981
E8B8EBA5:ROM:5000:1000:16
F95504E0:Info:Space Battle:Mattel:1979
F95504E0:ROM:5000:1000:16
F8EF3E5A:Info:Space Cadet:Mattel:1982
F8EF3E5A:ROM:5000:2000:16
39D3B895:Info:Space Hawk:Mattel:1981
39D3B895:ROM:5000:1000:16
E98B9163:Info:Space Shuttle:Mattel:1983
E98B9163:ROM:5000:2000:16
E98B9163:ROM:D000:3000:16
E98B9163:Peripheral:Intellivoice:Optional
3784DC52:Info:Space Spartans:Mattel:1981
3784DC52:ROM:5000:2000:16
3784DC52:Peripheral:Intellivoice:Optional
A95021FC:Info:Spiker! Super Pro Volleyball:INTV:1988
A95021FC:ROM:5000:2000:16
A95021FC:ROM:9000:2000:16
B745C1CA:Info:Stadium Mud Buggies:INTV:1988
B745C1CA:ROM:5000:2000:16
B745C1CA:ROM:9000:2000:16
2DEACD15:Info:Stampede:Activision:1982
2DEACD15:ROM:5000:1000:16
72E11FCA:Info:Star Strike:Mattel:1981
72E11FCA:ROM:5000:1000:16
D5B0135A:Info:Star Wars - The Empire Strikes Back:Parker Bros:1983
D5B0135A:ROM:5000:1000:16
A03EDF73:Info:Stack Em:Arnauld Chevallier:2004
A03EDF73:ROM:4800:2000:16
66D396C0:Info:Stonix:Arnauld Chevallier:2004
66D396C0:ROM:5000:2000:16
66D396C0:ROM:D000:1000:16
66D396C0:ROM:F000:1000:16
B119027D:Info:Stonix Beta 1.2:Arnauld Chevallier:2003
B119027D:ROM:5000:2000:16
4830F720:Info:Street:Mattel:1981
4830F720:ROM:5000:1000:16
3D9949EA:Info:Sub Hunt:Mattel:1981
3D9949EA:ROM:5000:2000:16
8F7D3069:Info:Super Cobra:Konami:1983
8F7D3069:ROM:5000:2000:16
BAB638F2:Info:Super Masters!:Mattel:1982
BAB638F2:ROM:5000:2000:16
16BFB8EB:Info:Super Pro Decathlon:INTV:1978
16BFB8EB:ROM:5000:2000:16
16BFB8EB:ROM:9000:2000:16
32076E9D:Info:Super Pro Football:INTV:1986
32076E9D:ROM:5000:2000:16
32076E9D:ROM:9000:2000:16
51B82EB7:Info:Super Soccer:Mattel:1983
51B82EB7:ROM:5000:2000:16
51B82EB7:ROM:D000:1000:16
51B82EB7:ROM:F000:1000:16
15E88FCE:Info:Swords and Serpents:Imagic:1982
15E88FCE:ROM:5000:2000:16
1F584A69:Info:Takeover:Mattel:1982
1F584A69:ROM:5000:1000:16
03E9E62E:Info:Tennis:Mattel:1980
03E9E62E:ROM:5000:1000:16
D43FD410:Info:Tetris (GPL):Joseph Zbiciak:2000
D43FD410:ROM:5000:2000:16
F3DF94E0:Info:Thin Ice:Mattel:1983
F3DF94E0:ROM:5000:2000:16
F3DF94E0:ROM:D000:1000:16
F3DF94E0:ROM:F000:1000:16
D6495910:Info:Thin Ice (Prototype):Mattel:1983
D6495910:ROM:5000:2000:16
C1F1CA74:Info:Thunder Castle:Mattel:1982
C1F1CA74:ROM:5000:2000:16
C1F1CA74:ROM:D000:1000:16
C1F1CA74:ROM:F000:1000:16
D1D352A0:Info:Tower of Doom:Mattel:1986
D1D352A0:ROM:5000:2000:16
D1D352A0:ROM:9000:2000:16
D1D352A0:ROM:D000:1000:16
D1D352A0:ROM:F000:1000:16
1AC989E2:Info:Triple Action:Mattel:1981
1AC989E2:ROM:5000:1000:16
095638C0:Info:Triple Challenge:INTV:1986
095638C0:ROM:5000:2000:16
095638C0:ROM:9000:2000:16
095638C0:ROM:C000:0800:16
095638C0:ROM:D000:1000:16
7A558CF5:Info:Tron Maze-A-Tron:Mattel:1981
7A558CF5:ROM:5000:2000:16
CA447BBD:Info:Tron Deadly Discs:Mattel:1981
CA447BBD:ROM:5000:1000:16
07FB9435:Info:Tron Solar Sailer:Mattel:1982
07FB9435:ROM:5000:2000:16
07FB9435:ROM:D000:1000:16
07FB9435:Peripheral:Intellivoice:Optional
6F23A741:Info:Tropical Trouble:Imagic:1982
6F23A741:ROM:5000:2000:16
734F3260:Info:Truckin':Imagic:1983
734F3260:ROM:5000:2000:16
275F3512:Info:Turbo:Coleco:1983
275F3512:ROM:5000:2000:16
6FA698B3:Info:Tutankham:Parker Bros:1983
6FA698B3:ROM:5000:2000:16
F093E801:Info:U.S. Ski Team Skiing:Mattel:1980
F093E801:ROM:5000:1000:16
752FD927:Info:USCF Chess:Mattel:1981
752FD927:ROM:5000:2000:16
752FD927:RAM:D000:400:8
F9E0789E:Info:Utopia:Mattel:1981
F9E0789E:ROM:5000:1000:16
A4A20354:Info:Vectron:Mattel:1982
A4A20354:ROM:5000:2000:16
A4A20354:ROM:D000:1000:16
6EFA67B2:Info:Venture:Coleco:1982
6EFA67B2:ROM:5000:2000:16
F1ED7D27:Info:White Water!:Imagic:1983
F1ED7D27:ROM:5000:2000:16
15D9D27A:Info:World Cup Football:Nice Ideas:1985
15D9D27A:ROM:5000:2000:16
15D9D27A:ROM:D000:1000:16
15D9D27A:ROM:F000:1000:16
C2063C08:Info:World Series Major League Baseball:Mattel:1983
C2063C08:ROM:5000:2000:16
C2063C08:ROM:D000:1000:16
C2063C08:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0001
C2063C08:Peripheral:Intellivoice:Optional
C2063C08:Peripheral:ECS:Required
A12C27E1:Info:World Series Major League Baseball (Bad Dump):Mattel:1983
A12C27E1:ROM:5000:2000:16
A12C27E1:ROM:D000:1000:16
A12C27E1:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
A12C27E1:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
A12C27E1:Peripheral:Intellivoice:Optional
A12C27E1:Peripheral:ECS:Required
24B667B9:Info:Worm Whomper:Activision:1983
24B667B9:ROM:5000:1000:16
15C65DC5:Info:Zaxxon:Coleco:1982
15C65DC5:ROM:5000:2000:16
D89AEC27:Info:Zombie Marbles:John Doherty:2004
D89AEC27:ROM:5000:2000:16

View File

@ -0,0 +1,144 @@
#include <string.h>
#include "ripxbf.h"
UINT64 freadInt(FILE* file, UINT32 size)
{
unsigned int i;
unsigned int ret = 0;
for (i = 0; i < size; i++) {
ret <<= 8;
ret |= fgetc(file);
}
return ret;
}
UINT16 freadUINT16(FILE* file)
{
return (UINT16)freadInt(file, 2);
}
UINT32 freadUINT32(FILE* file)
{
return (UINT32)freadInt(file, 4);
}
UINT64 freadUINT64(FILE* file)
{
return freadInt(file, 8);
}
void freadString(FILE* file, CHAR* out, UINT32 maxLength)
{
unsigned int i;
unsigned char next;
unsigned int completeLength = freadUINT32(file);
if (completeLength+1 < maxLength)
maxLength = completeLength+1;
for (i = 0; i < completeLength; i++) {
next = (unsigned char)fgetc(file);
if (i < (maxLength-1))
out[i] = next;
}
out[maxLength-1] = '\0';
}
void fwriteUINT16(FILE* file, UINT16 num)
{
fputc((num>>8)&0xFF, file);
fputc(num&0xFF, file);
}
void fwriteUINT32(FILE* file, UINT32 num)
{
fputc((num>>24)&0xFF, file);
fputc((num>>16)&0xFF, file);
fputc((num>>8)&0xFF, file);
fputc(num&0xFF, file);
}
void fwriteUINT64(FILE* file, UINT64 num)
{
fputc((int)(num>>56)&0xFF, file);
fputc((int)(num>>48)&0xFF, file);
fputc((int)(num>>40)&0xFF, file);
fputc((int)(num>>32)&0xFF, file);
fputc((int)(num>>24)&0xFF, file);
fputc((int)(num>>16)&0xFF, file);
fputc((int)(num>>8)&0xFF, file);
fputc((int)num&0xFF, file);
}
void fwriteString(FILE* file, const CHAR* s)
{
int i;
int length = (int)strlen(s);
fwriteUINT32(file, length);
for (i = 0; i < length; i++)
fputc(s[i], file);
}
/*
RipSystem SYSTEMS[] =
{
{ ID_SYSTEM_INTELLIVISION,
"Intellivision",
2, 2,
{ { "Master Component",
{ { "Executive ROM",
{ { "Original Executive ROM", 0xCBCE86F7 },
{ "Intellivision 2 Executive ROM", 0 },
{ "Sears Executive ROM", 0 },
{ "GPL Executive ROM", 0 },
0,
},},
{ "Graphics ROM",
{ { "Original GROM", 0x683A4158 },
{ "GPL GROM", 0 },
0,
},},
0,
},},
{ "Entertainment Computer System",
{ { "ECS BIOS",
{ { "Original ECS BIOS", 0xEA790A06 },
},},
0,
},},
{ "Intellivoice",
{ { "Intellivoice BIOS",
{ { "Original Intellivoice BIOS", 0x0DE7579D },
0,
},},
0,
},},
0,
},},
{ ID_SYSTEM_ATARI5200,
"Atari 5200",
2, 1,
{ { "Main Console",
{ { "BIOS",
{ { "Original BIOS", 0x4248D3E3 },
0,
},},
0,
},},
0,
},},
0,
};
RipSystem* getSystem(UINT32 systemID)
{
int i = 0;
while (*((int*)(&SYSTEMS[i])) != 0) {
if (SYSTEMS[i].systemID == systemID)
return &SYSTEMS[i];
i++;
}
return NULL;
}
*/

View File

@ -0,0 +1,120 @@
/**
* This file contains a list of declarations useful for working with
* files in the XBF format.
*
* Author: Kyle Davis
*/
#include <stdio.h>
#include "types.h"
#ifdef __cplusplus
extern "C" {
#endif
//compatibility flags
typedef enum _BiosCompatibility
{
BIOS_PREFERRED = 0,
BIOS_COMPATIBLE = 1,
BIOS_INCOMPATIBLE = 2
} BiosCompatibility;
typedef enum _PeripheralCompatibility
{
PERIPH_REQUIRED = 0,
PERIPH_OPTIONAL = 1,
PERIPH_COMPATIBLE = 2,
PERIPH_INCOMPATIBLE = 3
} PeripheralCompatibility;
UINT64 freadInt(FILE*, UINT32 length);
UINT16 freadUINT16(FILE*);
UINT32 freadUINT32(FILE*);
UINT64 freadUINT64(FILE*);
void freadString(FILE*, CHAR* s, UINT32 maxLength);
void fwriteUINT16(FILE*, UINT16);
void fwriteUINT32(FILE*, UINT32);
void fwriteUINT64(FILE*, UINT64);
void fwriteString(FILE*, const CHAR*);
//the RIP magic number
#define RIP_MAGIC_NUMBER 0x3F383A347651B5DAll
#define RIP_MAJOR_REVISION 1
#define RIP_MINOR_REVISION 0
//record IDs
#define ID_HEADER_RECORD 0xFC41466E
#define ID_BIOS_COMPAT_RECORD 0xC183BF3C
#define ID_NAME_RECORD 0x5ECC1C53
#define ID_PERIPH_COMPAT_RECORD 0xAE4CEDB7
#define ID_PRODUCER_RECORD 0x86596370
#define ID_YEAR_RECORD 0x9199748D
#define ID_RAM_RECORD 0xCF1DC943
#define ID_ROM_RECORD 0xA365AF69
//emulator IDs
#define ID_EMULATOR_BLISS 0xC183BF3C
//system IDs
#define ID_SYSTEM_ATARI5200 0xE4453A0B
#define ID_SYSTEM_INTELLIVISION 0x4AC771F8
#define ID_PERIPH_ECS 0x143D9A97
#define ID_PERIPH_INTELLIVOICE 0x6EFF540A
//bios numbers
#define A5200_P_MASTER_COMPONENT 0
#define A5200_BT_BIOS 0
#define A5200_B_ORIGINAL_BIOS 0
#define INTV_P_MASTER_COMPONENT 0
#define INTV_BT_EXEC 0
#define INTV_B_ORIGINAL_EXEC 0
#define INTV_B_INTY2_EXEC 1
#define INTV_B_SEARS_EXEC 2
#define INTV_B_GPL_EXEC 3
#define INTV_BT_GROM 1
#define INTV_B_ORIGINAL_GROM 0
#define INTV_B_GPL_GROM 1
#define INTV_P_ECS 1
#define INTV_BT_ECS_BIOS 0
#define INTV_B_ORIGINAL_ECS_BIOS 0
#define INTV_P_INTELLIVOICE 2
#define INTV_BT_IVOICE_BIOS 0
#define INTV_B_ORIGINAL_IVOICE_BIOS 0
/*
typedef struct _RipBios
{
CHAR* biosName;
UINT32 biosCRC32;
} RipBios;
typedef struct _RipBiosType
{
CHAR* biosTypeName;
RipBios bioses[16];
} RipBiosType;
typedef struct _RipPeripheral
{
CHAR* peripheralName;
RipBiosType biosTypes[16];
} RipPeripheral;
typedef struct _RipSystem
{
UINT32 systemID;
CHAR* systemName;
UINT8 addressByteWidth;
UINT8 valueByteWidth;
RipPeripheral peripherals[16];
} RipSystem;
RipSystem* getSystem(UINT32 systemID);
*/
#ifdef __cplusplus
}
#endif

174
arm9/source/emucore/types.h Normal file
View File

@ -0,0 +1,174 @@
#ifndef TYPES_H
#define TYPES_H
#ifdef __cplusplus
extern "C" {
#endif
extern int debug1, debug2;
//primitive types
typedef signed char INT8;
typedef unsigned char UINT8;
typedef signed short INT16;
typedef unsigned short UINT16;
typedef signed int INT32;
typedef unsigned int UINT32;
// There is no ANSI standard for 64 bit integers :(
#ifdef _MSC_VER
typedef __int64 INT64; // MS VC++
typedef unsigned __int64 UINT64; // MS VC++
#else
typedef signed long long int INT64; // C99 C++11
typedef unsigned long long int UINT64; // C99 C++11
#endif
typedef char CHAR;
#if !defined(BOOL)
#if defined(__MACH__)
typedef signed char BOOL;
#else
typedef int BOOL;
#endif
#endif
#if !defined(TRUE)
#define TRUE (1)
#endif
#if !defined(FALSE)
#define FALSE (0)
#endif
#if !defined(NULL)
#if defined(__cplusplus)
#define NULL (0)
#else
#define NULL ((void *)0)
#endif
#endif
#define SWAP32BIT(swap) ((((swap) << 24) & 0xFF000000) | \
(((swap) << 8) & 0x00FF0000) | \
(((swap) >> 8) & 0x0000FF00) | \
(((swap) >> 24) & 0x000000FF))
#if !defined(__LITTLE_ENDIAN__) && defined(_WIN32)
#define __LITTLE_ENDIAN__ (1)
#endif
#if defined(__LITTLE_ENDIAN__)
#define FOURCHAR(x) SWAP32BIT((UINT32)(x))
#else
#define FOURCHAR(x) (x)
#endif
#if !defined(TYPEDEF_STRUCT_PACK)
#define TYPEDEF_STRUCT_PACK(_x_) typedef struct __attribute__((__packed__)) _x_
#endif
#include <string.h>
typedef unsigned char UCHAR;
typedef unsigned short USHORT;
#ifndef FLOAT
typedef float FLOAT;
#endif
#ifndef GUID
typedef struct
{
unsigned int data1;
unsigned short data2;
unsigned short data3;
unsigned char data4[8];
} GUID;
#endif
#ifndef ZeroMemory
#define ZeroMemory(ptr,size) memset(ptr, 0, size)
#endif
#ifndef strcmpi
#define strcmpi strcasecmp
#endif
#ifndef MAX_PATH
#define MAX_PATH 256
#endif
// total hack for non-windows
#ifndef GUID_SysKeyboard
#define GUID_SysKeyboard (GUID){0}
#define DIK_NUMPAD7 ((INT32)0x81)
#define DIK_NUMPAD8 ((INT32)0x41)
#define DIK_NUMPAD9 ((INT32)0x21)
#define DIK_NUMPAD4 ((INT32)0x82)
#define DIK_NUMPAD5 ((INT32)0x42)
#define DIK_NUMPAD6 ((INT32)0x22)
#define DIK_NUMPAD1 ((INT32)0x84)
#define DIK_NUMPAD2 ((INT32)0x44)
#define DIK_NUMPAD3 ((INT32)0x24)
#define DIK_NUMPADPERIOD ((INT32)0x88)
#define DIK_NUMPAD0 ((INT32)0x48)
#define DIK_NUMPADENTER ((INT32)0x28)
#define DIK_SPACE ((INT32)0xA0)
#define DIK_LALT ((INT32)0x00)
#define DIK_LCONTROL ((INT32)0x60)
#define DIK_RCONTROL ((INT32)0xC0)
#define DIK_UP ((INT32)0x04)
#define DIK_W ((INT32)0x16)
#define DIK_RIGHT ((INT32)0x02)
#define DIK_S ((INT32)0x13)
#define DIK_DOWN ((INT32)0x01)
#define DIK_A ((INT32)0x19)
#define DIK_LEFT ((INT32)0x08)
#define DIK_Q ((INT32)0x1C)
#define DIK_COMMA ((INT32)0x0)
#define DIK_N ((INT32)0x0)
#define DIK_V ((INT32)0x0)
#define DIK_X ((INT32)0x0)
#define DIK_PERIOD ((INT32)0x0)
#define DIK_M ((INT32)0x0)
#define DIK_B ((INT32)0x0)
#define DIK_C ((INT32)0x0)
#define DIK_Z ((INT32)0x0)
#define DIK_SEMICOLON ((INT32)0x0)
#define DIK_K ((INT32)0x0)
#define DIK_H ((INT32)0x0)
#define DIK_F ((INT32)0x0)
#define DIK_P ((INT32)0x0)
#define DIK_I ((INT32)0x0)
#define DIK_Y ((INT32)0x0)
#define DIK_R ((INT32)0x0)
#define DIK_GRAVE ((INT32)0x0)
#define DIK_TAB ((INT32)0x0)
#define DIK_RETURN ((INT32)0x0)
#define DIK_O ((INT32)0x0)
#define DIK_U ((INT32)0x0)
#define DIK_T ((INT32)0x0)
#define DIK_E ((INT32)0x0)
#define DIK_L ((INT32)0x0)
#define DIK_J ((INT32)0x0)
#define DIK_G ((INT32)0x0)
#define DIK_D ((INT32)0x0)
#define DIK_LSHIFT ((INT32)0x0)
#define DIK_F2 ((INT32)0x0)
#define DI__WTFX ((INT32)0xFA)
#define DI__WTFY ((INT32)0xFB)
#endif
#ifdef __cplusplus
}
#endif
#endif //TYPES_H

40
arm9/source/main.cpp Normal file
View File

@ -0,0 +1,40 @@
#include <nds.h>
#include <fat.h>
#include <stdio.h>
#include "ds_tools.h"
#include "clickNoQuit_wav.h"
#include "clickQuit_wav.h"
int main(int argc, char **argv)
{
// Init sound
consoleDemoInit();
soundEnable();
lcdMainOnTop();
// Init Fat
if (!fatInitDefault())
{
iprintf("Unable to initialize libfat!\n");
return -1;
}
// Init Timer
dsInitTimer();
// Init sound FIFO
dsInstallSoundEmuFIFO();
// Setup the main screen handling
dsInitScreenMain();
// Main loop of emulation
dsMainLoop();
// Free memory to be correct
dsFreeEmu();
return 0;
}

699
knowncarts.cfg Normal file
View File

@ -0,0 +1,699 @@
D7C78754:Info:4-TRIS (GPL):Joseph Zbiciak:2000
D7C78754:ROM:5000:2000:16
B91488E2:Info:4-TRIS (GPL):Joseph Zbiciak:2001
B91488E2:ROM:5000:2000:16
A60E25FC:Info:ABPA Backgammon:Mattel:1978
A60E25FC:ROM:5000:1000:16
F8B1F2B7:Info:Advanced Dungeons and Dragons:Mattel:1982
F8B1F2B7:ROM:5000:2000:16
16C3B62F:Info:Advanced Dungeons and Dragons - Treasure of Tarmin:Mattel:1982
16C3B62F:ROM:5000:2000:16
11C3BCFA:Info:Adventure (AD&D - Cloudy Mountain):Mattel:1982
11C3BCFA:ROM:5000:2000:16
2C668249:Info:Air Strike:Mattel:1982
2C668249:ROM:5000:1000:16
B45633CF:Info:All-Stars Major League Baseball:Mattel:1980
B45633CF:ROM:5000:2000:16
B45633CF:ROM:D000:1000:16
6F91FBC1:Info:Armor Battle:Mattel:1978
6F91FBC1:ROM:5000:1000:16
00BE8BBA:Info:Astrosmash - Meteor:Mattel:1981
00BE8BBA:ROM:5000:1000:16
FAB2992C:Info:Astrosmash:Mattel:1981
FAB2992C:ROM:5000:1000:16
13FF363C:Info:Atlantis:Imagic:1981
13FF363C:ROM:4800:2000:16
B35C1101:Info:Auto Racing:Mattel:1979
B35C1101:ROM:5000:1000:16
8AD19AB3:Info:B-17 Bomber:Mattel:1981
8AD19AB3:ROM:5000:2000:16
8AD19AB3:ROM:D000:1000:16
8AD19AB3:Peripheral:Intellivoice:Optional
DAB36628:Info:Baseball:Mattel:1978
DAB36628:ROM:5000:1000:16
EAF650CC:Info:BeamRider:Activision:1983
EAF650CC:ROM:5000:2000:16
C047D487:Info:Beauty and the Beast:Imagic:1982
C047D487:ROM:4800:2000:16
B03F739B:Info:Blockade Runner:Interphase:1983
B03F739B:ROM:5000:2000:16
4728C3BD:Info:Blow Out:Mattel:1983
4728C3BD:ROM:5000:1000:16
515E1D7E:Info:Body Slam Super Pro Wrestling:Mattel:1988
515E1D7E:ROM:5000:2000:16
515E1D7E:ROM:9000:2000:16
32697B72:Info:Bomb Squad:Mattel:1982
32697B72:ROM:5000:2000:16
32697B72:ROM:D000:1000:16
32697B72:Peripheral:Intellivoice:Optional
18E08520:Info:Bouncing Pixels (GPL):JRMZ Electronics:1999
18E08520:ROM:5000:0202:16
AB87C16F:Info:Boxing:Mattel:1980
AB87C16F:ROM:5000:1000:16
9F85015B:Info:Brickout!:Mattel:1981
9F85015B:ROM:5000:1000:16
999CCEED:Info:Bump 'N' Jump:Mattel:1982-83
999CCEED:ROM:5000:2000:16
999CCEED:ROM:D000:1000:16
999CCEED:ROM:F000:1000:16
43806375:Info:BurgerTime!:Mattel:1982
43806375:ROM:5000:2000:16
C92BAAE8:Info:BurgerTime! - New Levels Hack:David Harley:2002
C92BAAE8:ROM:5000:2000:16
FA492BBD:Info:Buzz Bombers:Mattel:1982
FA492BBD:ROM:5000:2000:16
2A1E0C1C:Info:Buzz Bombers:Mattel:1982
2A1E0C1C:ROM:5000:2000:16
43870908:Info:Carnival:Coleco:1982
43870908:ROM:5000:1000:16
D5363B8C:Info:Centipede:Atarisoft:1983
D5363B8C:ROM:6000:2000:16
4CC46A04:Info:Championship Tennis:Nice Ideas:1985
4CC46A04:ROM:5000:2000:16
4CC46A04:ROM:D000:2000:16
36E1D858:Info:Checkers:Mattel:1979
36E1D858:ROM:5000:1000:16
0BF464C6:Info:Chip Shot Super Pro Golf:Mattel:1987
0BF464C6:ROM:5000:2000:16
0BF464C6:ROM:9000:2000:16
47FDD8A8:Info:Choplifter:Mattel:1983
47FDD8A8:ROM:5000:2000:16
47FDD8A8:ROM:D000:2000:16
3289C8BA:Info:Commando:INTV:1987
3289C8BA:ROM:5000:2000:16
3289C8BA:ROM:9000:2000:16
4B23A757:Info:Congo Bongo:Sega:1983
4B23A757:ROM:5000:3000:16
E1EE408F:Info:Crazy Clones:Mattel:1981
E1EE408F:ROM:5000:1000:16
CDC14ED8:Info:Deadly Dogs!:Unknown:1987
CDC14ED8:ROM:5000:1000:16
6802B191:Info:Deep Pockets - Super Pro Pool and Billiards:Realtime:1990
6802B191:ROM:5000:2000:16
6802B191:ROM:9000:2000:16
D8F99AA2:Info:Defender:Atarisoft:1983
D8F99AA2:ROM:5000:3000:16
5E6A8CD8:Info:Demon Attack:Imagic:1982
5E6A8CD8:ROM:4800:2000:16
159AF7F7:Info:Dig Dug:INTV:1987
159AF7F7:ROM:5000:3000:16
159AF7F7:ROM:9000:1000:16
13EE56F1:Info:Diner:INTV:1987
13EE56F1:ROM:5000:2000:16
13EE56F1:ROM:9000:2000:16
C30F61C0:Info:Donkey Kong:Coleco:1982
C30F61C0:ROM:5000:1000:16
6DF61A9F:Info:Donkey Kong Jr:Coleco:1982
6DF61A9F:ROM:5000:2000:16
84BEDCC1:Info:Dracula:Imagic:1982
84BEDCC1:ROM:5000:2000:16
AF8718A1:Info:Dragonfire:Imagic:1982
AF8718A1:ROM:5000:1000:16
3B99B889:Info:Dreadnaught Factor, The:Activision:1983
3B99B889:ROM:5000:2000:16
BF4D0E9B:Info:Dreadnaught Factor, The (Prototype):Activision:1983
BF4D0E9B:ROM:5000:2000:16
20ACE89D:Info:Easter Eggs:Mattel:1981
20ACE89D:ROM:5000:1000:16
54A3FC11:Info:Electric Company - Math Fun:CTW:1978
54A3FC11:ROM:5000:1000:16
C9EAACAB:Info:Electric Company - Word Fun:CTW:1980
C9EAACAB:ROM:5000:1000:16
4221EDE7:Info:Fathom:Imagic:1983
4221EDE7:ROM:5000:2000:16
37222762:Info:Frog Bog:Mattel:1982
37222762:ROM:5000:1000:16
D27495E9:Info:Frogger:Parker Bros:1983
D27495E9:ROM:5000:1000:16
DBCA82C5:Info:Go For The Gold:Mattel:1981
DBCA82C5:ROM:5000:2000:16
291AC826:Info:Grid Shock:Mattel:1982
291AC826:ROM:5000:1000:16
E573863A:Info:Groovy! (GPL):JRMZ Electronics:1999
E573863A:ROM:5000:1E48:16
4B8C5932:Info:Happy Trails:Activision:1983
4B8C5932:ROM:5000:1000:16
120B53A9:Info:Happy Trails (Overdump):Activision:1983
120B53A9:ROM:5000:1000:16
B6A3D4DE:Info:Hard Hat:Mattel:1979
B6A3D4DE:ROM:5000:2000:16
B5C7F25D:Info:Horse Racing:Mattel:1980
B5C7F25D:ROM:5000:1000:16
FF83FF80:Info:Hover Force:Mattel:1986
FF83FF80:ROM:5000:2000:16
FF83FF80:ROM:9000:3000:16
FF83FF80:ROM:D000:1000:16
A3147630:Info:Hypnotic Lights:Mattel:1981
A3147630:ROM:5000:1000:16
4F3E3F69:Info:Ice Trek:Imagic:1983
4F3E3F69:ROM:5000:2000:16
02919024:Info:Intellivision - Intelligent Television Demo:Mattel:1978
02919024:ROM:5000:2000:16
C83EEA4C:Info:Intellivision Test Cartridge and Baseball:Mattel:1978
C83EEA4C:ROM:5000:1000:16
C83EEA4C:ROM:7000:1000:16
985A78ED:Info:IntyOS 0.2 Alpha:Arnauld Chevallier:2003
985A78ED:ROM:5000:1000:16
985A78ED:RAM:D000:1000:16
985A78ED:RAM:F000:1000:16
EE5F1BE2:Info:Jetsons, The - Ways With Words:Mattel:1983
EE5F1BE2:ROM:5000:2000:16
EE5F1BE2:ROM:D000:1000:16
EE5F1BE2:Peripheral:ECS:Required
4422868E:Info:King of the Mountain:Mattel:1982
4422868E:ROM:5000:2000:16
4422868E:ROM:D000:2000:16
8C9819A2:Info:Kool-Aid Man:Mattel:1983
8C9819A2:ROM:5000:2000:16
A6840736:Info:Lady Bug:Coleco:1983
A6840736:ROM:5000:2000:16
3825C25B:Info:Land Battle:Mattel:1982
3825C25B:ROM:5000:2000:16
3825C25B:RAM:D000:400:8
604611C0:Info:Las Vegas Blackjack and Poker:Mattel:1979
604611C0:ROM:5000:1000:16
48D74D3C:Info:Las Vegas Roulette:Mattel:1979
48D74D3C:ROM:5000:1000:16
19360442:Info:League of Light (Prototype Alt1):Activision:1983
19360442:ROM:5000:2000:16
75EE64F6:Info:League of Light (Prototype Alt2):Activision:1983
75EE64F6:ROM:5000:2000:16
B4287B95:Info:League of Light (Prototype):Activision:1983
B4287B95:ROM:5000:2000:16
2C5FD5FA:Info:Learning Fun I - Math Master Factor Fun:INTV:1987
2C5FD5FA:ROM:5000:2000:16
632F6ADF:Info:Learning Fun II - Word Wizard Memory Fun:INTV:1987
632F6ADF:ROM:5000:2000:16
E00D1399:Info:Lock 'N' Chase:Mattel:1982
E00D1399:ROM:5000:2000:16
6B6E80EE:Info:Loco-Motion:Mattel:1982
6B6E80EE:ROM:5000:2000:16
F3B0C759:Info:Magic Carousel:Mattel:1982
F3B0C759:ROM:5000:2000:16
F3B0C759:ROM:D000:2000:16
573B9B6D:Info:Masters of the Universe - The Power of He-Man!:Mattel:1983
573B9B6D:ROM:5000:2000:16
573B9B6D:ROM:D000:1000:16
573B9B6D:ROM:F000:1000:16
7D0F8162:Info:Maze Demo #1 (GPL):JRMZ Electronics:2000
7D0F8162:ROM:5000:016E:16
2138DAD4:Info:Maze Demo #2 (GPL):JRMZ Electronics:2000
2138DAD4:ROM:5000:0175:16
FF68AA22:Info:Melody Blaster:Mattel:1983
FF68AA22:ROM:5000:2000:16
FF68AA22:ROM:D000:1000:16
FF68AA22:Peripheral:ECS:Required
E00E23E7:Info:Mickey's Hello World:Mickey:2000
E00E23E7:ROM:5000:006F:16
E806AD91:Info:Microsurgeon:Imagic:1982
E806AD91:ROM:4800:2000:16
94096229:Info:Minehunter:Ryan Kinnen:2004
94096229:ROM:5000:2000:16
9D57498F:Info:Mind Strike!:Mattel:1982
9D57498F:ROM:5000:2000:16
9D57498F:ROM:D000:1000:16
9D57498F:Peripheral:ECS:Required
6746607B:Info:Minotaur V1.1:Mattel:1981
6746607B:ROM:5000:2000:16
5A4CE519:Info:Minotaur V2:Mattel:1981
5A4CE519:ROM:5000:2000:16
BD731E3C:Info:Minotaur:Mattel:1981
BD731E3C:ROM:5000:2000:16
2F9C93FC:Info:Minotaur (Treasure of Tarmin hack):Mattel:1981
2F9C93FC:ROM:5000:2000:16
11FB9974:Info:Mission X:Mattel:1982
11FB9974:ROM:5000:2000:16
5F6E1AF6:Info:Motocross:Mattel:1982
5F6E1AF6:ROM:5000:2000:16
6B5EA9C4:Info:Mountain Madness Super Pro Skiing:INTV:1987
6B5EA9C4:ROM:5000:2000:16
598662F2:Info:Mouse Trap:Coleco:1982
598662F2:ROM:5000:1000:16
0B50A367:Info:Mr. Basic Meets Bits 'N Bytes (Bad Dump):Mattel:1983
0B50A367:ROM:5000:2000:16
0B50A367:ROM:D000:1000:16
0B50A367:Peripheral:ECS:Required
BEF0B0C7:Info:Mr. Basic Meets Bits 'N Bytes:Mattel:1983
BEF0B0C7:ROM:5000:2000:16
BEF0B0C7:ROM:D000:1000:16
BEF0B0C7:Peripheral:ECS:Required
DBAB54CA:Info:NASL Soccer:Mattel:1979
DBAB54CA:ROM:5000:1000:16
81E7FB8C:Info:NBA Basketball:Mattel:1978
81E7FB8C:ROM:5000:1000:16
4B91CF16:Info:NFL Football:Mattel:1978
4B91CF16:ROM:5000:1000:16
76564A13:Info:NHL Hockey:Mattel:1979
76564A13:ROM:5000:1000:16
7334CD44:Info:Night Stalker:Mattel:1982
7334CD44:ROM:5000:1000:16
5EE2CC2A:Info:Nova Blast:Imagic:1983
5EE2CC2A:ROM:5000:2000:16
E5D1A8D2:Info:Number Jumble:Mattel:1983
E5D1A8D2:ROM:5000:2000:16
E5D1A8D2:ROM:D000:1000:16
E5D1A8D2:ROM:F000:1000:16
A21C31C3:Info:Pac-Man:Atarisoft:1983
A21C31C3:ROM:5000:3000:16
6E4E8EB4:Info:Pac-Man:INTV:1983
6E4E8EB4:ROM:5000:3000:16
169E3584:Info:PBA Bowling:Mattel:1980
169E3584:ROM:5000:1000:16
FF87FAEC:Info:PGA Golf:Mattel:1979
FF87FAEC:ROM:5000:1000:16
D7C5849C:Info:Pinball:Mattel:1981
D7C5849C:ROM:5000:2000:16
D7C5849C:ROM:D000:1000:16
9C75EFCC:Info:Pitfall!:Activision:1982
9C75EFCC:ROM:5000:1000:16
BB939881:Info:Pole Position:INTV:1986
BB939881:ROM:5000:2000:16
BB939881:ROM:9000:2000:16
A982E8D5:Info:Pong:Unknown:1999
A982E8D5:ROM:5000:0800:16
C51464E0:Info:Popeye:Parker Bros:1983
C51464E0:ROM:5000:2000:16
D8C9856A:Info:Q-bert:Parker Bros:1983
D8C9856A:ROM:5000:2000:16
C7BB1B0E:Info:Reversi:Mattel:1984
C7BB1B0E:ROM:5000:1000:16
8910C37A:Info:River Raid:Activision:1982-83
8910C37A:ROM:5000:2000:16
95466AD3:Info:River Raid V1 (Prototype):Activision:1982-83
95466AD3:ROM:5000:2000:16
1682D0B4:Info:Robot Rubble V1 (Prototype) (Overdump):Activision:1983
1682D0B4:ROM:5000:2000:16
7473916D:Info:Robot Rubble V1 (Prototype):Activision:1983
7473916D:ROM:5000:2000:16
A5E28783:Info:Robot Rubble V2 (Prototype):Activision:1983
A5E28783:ROM:5000:2000:16
243B0812:Info:Robot Rubble V3 (Prototype):Activision:1983
243B0812:ROM:5000:2000:16
DCF4B15D:Info:Royal Dealer:Mattel:1981
DCF4B15D:ROM:5000:2000:16
47AA7977:Info:Safecracker:Imagic:1983
47AA7977:ROM:5000:2000:16
6E0882E7:Info:SameGame and Robots:IntelligentVision:2005
6E0882E7:ROM:5000:2000:16
6E0882E7:ROM:D000:1000:16
6E0882E7:ROM:F000:1000:16
12BA58D1:Info:SameGame and Robots (Original):Michael J Hayes:2004
12BA58D1:ROM:5000:2000:16
12BA58D1:ROM:D000:1000:16
12BA58D1:ROM:F000:1000:16
E221808C:Info:Santa's Helper:Mattel:1983
E221808C:ROM:5000:1000:16
E9E3F60D:Info:Scooby Doo's Maze Chase:Mattel/Hanna-Barbera:1983
E9E3F60D:ROM:5000:2000:16
E9E3F60D:Peripheral:ECS:Required
99AE29A9:Info:Sea Battle:Mattel:1980
99AE29A9:ROM:5000:1000:16
E0F0D3DA:Info:Sewer Sam:Interphase:1983
E0F0D3DA:ROM:5000:2000:16
A610406E:Info:Shape Escape:John Doherty:2005
A610406E:ROM:5000:2000:16
2A4C761D:Info:Shark! Shark!:Mattel:1982
2A4C761D:ROM:5000:2000:16
FF7CB79E:Info:Sharp Shot:Mattel:1982
FF7CB79E:ROM:5000:1000:16
800B572F:Info:Slam Dunk Super Pro Basketball:INTV:1987
800B572F:ROM:5000:2000:16
800B572F:ROM:9000:2000:16
BA68FF28:Info:Slap Shot Super Pro Hockey:INTV:1987
BA68FF28:ROM:5000:2000:16
8F959A6E:Info:Snafu:Mattel:1981
8F959A6E:ROM:5000:1000:16
72C2A343:Info:Song Player - Back in the USSR (GPL):Joseph Zbiciak:1999
72C2A343:ROM:5000:2000:16
72C2A343:ROM:9000:1241:16
5E3130E1:Info:Song Player - Copacabana (GPL):Joseph Zbiciak:1999
5E3130E1:ROM:5000:2000:16
5E3130E1:ROM:9000:088F:16
5E3130E1:Peripheral:ECS:Required
C91B1D79:Info:Song Player - Creep (GPL):Joseph Zbiciak:1999
C91B1D79:ROM:5000:1081:16
C91B1D79:Peripheral:ECS:Required
82D2E346:Info:Song Player - Nut March (GPL):Joseph Zbiciak:1999
82D2E346:ROM:5000:1B12:16
82D2E346:Peripheral:ECS:Required
FCF06A8B:Info:Song Player - Nut Reed (GPL):Joseph Zbiciak:1999
FCF06A8B:ROM:5000:145E:16
FCF06A8B:Peripheral:ECS:Required
5914220A:Info:Song Player - Nut Trep (GPL):Joseph Zbiciak:1999
5914220A:ROM:5000:0DC8:16
5914220A:Peripheral:ECS:Required
71F5BE4E:Info:Song Player - Nut Waltz (GPL):Joseph Zbiciak:1999
71F5BE4E:ROM:5000:2000:16
71F5BE4E:ROM:9000:157C:16
71F5BE4E:Peripheral:ECS:Required
437C0E2D:Info:Song Player - Secret Agent Man (GPL):Joseph Zbiciak:1999
437C0E2D:ROM:5000:2000:16
437C0E2D:ROM:9000:15A4:16
437C0E2D:Peripheral:ECS:Required
DA5D77EA:Info:Song Player - Take on Me 3 (GPL):Joseph Zbiciak:1999
DA5D77EA:ROM:5000:12FD:16
DA5D77EA:Peripheral:ECS:Required
10D721CA:Info:Song Player - Take on Me 6 (GPL):Joseph Zbiciak:1999
10D721CA:ROM:5000:1500:16
10D721CA:Peripheral:ECS:Required
CC6F4F90:Info:Song Player - Too Sexy (GPL):Joseph Zbiciak:1999
CC6F4F90:ROM:5000:1AA7:16
CC6F4F90:Peripheral:ECS:Required
E8B8EBA5:Info:Space Armada:Mattel:1981
E8B8EBA5:ROM:5000:1000:16
F95504E0:Info:Space Battle:Mattel:1979
F95504E0:ROM:5000:1000:16
F8EF3E5A:Info:Space Cadet:Mattel:1982
F8EF3E5A:ROM:5000:2000:16
39D3B895:Info:Space Hawk:Mattel:1981
39D3B895:ROM:5000:1000:16
E98B9163:Info:Space Shuttle:Mattel:1983
E98B9163:ROM:5000:2000:16
E98B9163:ROM:D000:3000:16
E98B9163:Peripheral:Intellivoice:Optional
3784DC52:Info:Space Spartans:Mattel:1981
3784DC52:ROM:5000:2000:16
3784DC52:Peripheral:Intellivoice:Optional
A95021FC:Info:Spiker! Super Pro Volleyball:INTV:1988
A95021FC:ROM:5000:2000:16
A95021FC:ROM:9000:2000:16
B745C1CA:Info:Stadium Mud Buggies:INTV:1988
B745C1CA:ROM:5000:2000:16
B745C1CA:ROM:9000:2000:16
2DEACD15:Info:Stampede:Activision:1982
2DEACD15:ROM:5000:1000:16
72E11FCA:Info:Star Strike:Mattel:1981
72E11FCA:ROM:5000:1000:16
D5B0135A:Info:Star Wars - The Empire Strikes Back:Parker Bros:1983
D5B0135A:ROM:5000:1000:16
A03EDF73:Info:Stack Em:Arnauld Chevallier:2004
A03EDF73:ROM:4800:2000:16
66D396C0:Info:Stonix:Arnauld Chevallier:2004
66D396C0:ROM:5000:2000:16
66D396C0:ROM:D000:1000:16
66D396C0:ROM:F000:1000:16
B119027D:Info:Stonix Beta 1.2:Arnauld Chevallier:2003
B119027D:ROM:5000:2000:16
4830F720:Info:Street:Mattel:1981
4830F720:ROM:5000:1000:16
3D9949EA:Info:Sub Hunt:Mattel:1981
3D9949EA:ROM:5000:2000:16
8F7D3069:Info:Super Cobra:Konami:1983
8F7D3069:ROM:5000:2000:16
BAB638F2:Info:Super Masters!:Mattel:1982
BAB638F2:ROM:5000:2000:16
16BFB8EB:Info:Super Pro Decathlon:INTV:1978
16BFB8EB:ROM:5000:2000:16
16BFB8EB:ROM:9000:2000:16
32076E9D:Info:Super Pro Football:INTV:1986
32076E9D:ROM:5000:2000:16
32076E9D:ROM:9000:2000:16
51B82EB7:Info:Super Soccer:Mattel:1983
51B82EB7:ROM:5000:2000:16
51B82EB7:ROM:D000:1000:16
51B82EB7:ROM:F000:1000:16
15E88FCE:Info:Swords and Serpents:Imagic:1982
15E88FCE:ROM:5000:2000:16
1F584A69:Info:Takeover:Mattel:1982
1F584A69:ROM:5000:1000:16
03E9E62E:Info:Tennis:Mattel:1980
03E9E62E:ROM:5000:1000:16
D43FD410:Info:Tetris (GPL):Joseph Zbiciak:2000
D43FD410:ROM:5000:2000:16
F3DF94E0:Info:Thin Ice:Mattel:1983
F3DF94E0:ROM:5000:2000:16
F3DF94E0:ROM:D000:1000:16
F3DF94E0:ROM:F000:1000:16
D6495910:Info:Thin Ice (Prototype):Mattel:1983
D6495910:ROM:5000:2000:16
C1F1CA74:Info:Thunder Castle:Mattel:1982
C1F1CA74:ROM:5000:2000:16
C1F1CA74:ROM:D000:1000:16
C1F1CA74:ROM:F000:1000:16
D1D352A0:Info:Tower of Doom:Mattel:1986
D1D352A0:ROM:5000:2000:16
D1D352A0:ROM:9000:2000:16
D1D352A0:ROM:D000:1000:16
D1D352A0:ROM:F000:1000:16
1AC989E2:Info:Triple Action:Mattel:1981
1AC989E2:ROM:5000:1000:16
095638C0:Info:Triple Challenge:INTV:1986
095638C0:ROM:5000:2000:16
095638C0:ROM:9000:2000:16
095638C0:ROM:C000:0800:16
095638C0:ROM:D000:1000:16
7A558CF5:Info:Tron Maze-A-Tron:Mattel:1981
7A558CF5:ROM:5000:2000:16
CA447BBD:Info:Tron Deadly Discs:Mattel:1981
CA447BBD:ROM:5000:1000:16
07FB9435:Info:Tron Solar Sailer:Mattel:1982
07FB9435:ROM:5000:2000:16
07FB9435:ROM:D000:1000:16
07FB9435:Peripheral:Intellivoice:Optional
6F23A741:Info:Tropical Trouble:Imagic:1982
6F23A741:ROM:5000:2000:16
734F3260:Info:Truckin':Imagic:1983
734F3260:ROM:5000:2000:16
275F3512:Info:Turbo:Coleco:1983
275F3512:ROM:5000:2000:16
6FA698B3:Info:Tutankham:Parker Bros:1983
6FA698B3:ROM:5000:2000:16
F093E801:Info:U.S. Ski Team Skiing:Mattel:1980
F093E801:ROM:5000:1000:16
752FD927:Info:USCF Chess:Mattel:1981
752FD927:ROM:5000:2000:16
752FD927:RAM:D000:400:8
F9E0789E:Info:Utopia:Mattel:1981
F9E0789E:ROM:5000:1000:16
A4A20354:Info:Vectron:Mattel:1982
A4A20354:ROM:5000:2000:16
A4A20354:ROM:D000:1000:16
6EFA67B2:Info:Venture:Coleco:1982
6EFA67B2:ROM:5000:2000:16
F1ED7D27:Info:White Water!:Imagic:1983
F1ED7D27:ROM:5000:2000:16
15D9D27A:Info:World Cup Football:Nice Ideas:1985
15D9D27A:ROM:5000:2000:16
15D9D27A:ROM:D000:1000:16
15D9D27A:ROM:F000:1000:16
C2063C08:Info:World Series Major League Baseball:Mattel:1983
C2063C08:ROM:5000:2000:16
C2063C08:ROM:D000:1000:16
C2063C08:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
C2063C08:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0001
C2063C08:Peripheral:Intellivoice:Optional
C2063C08:Peripheral:ECS:Required
A12C27E1:Info:World Series Major League Baseball (Bad Dump):Mattel:1983
A12C27E1:ROM:5000:2000:16
A12C27E1:ROM:D000:1000:16
A12C27E1:ROM:E000:1000:16:EFFF,FFF0=EA50:000F=0000
A12C27E1:ROM:F000:1000:16:FFFF,FFF0=FA50:000F=0000
A12C27E1:Peripheral:Intellivoice:Optional
A12C27E1:Peripheral:ECS:Required
24B667B9:Info:Worm Whomper:Activision:1983
24B667B9:ROM:5000:1000:16
15C65DC5:Info:Zaxxon:Coleco:1982
15C65DC5:ROM:5000:2000:16
D89AEC27:Info:Zombie Marbles:John Doherty:2004
D89AEC27:ROM:5000:2000:16

BIN
logo.bmp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 630 B