├── Makefile ├── SpeccySE.nds ├── arm7 ├── Makefile ├── SpeccySE.elf ├── build │ ├── .map │ ├── emusoundfifo.d │ ├── emusoundfifo.o │ ├── main.d │ └── main.o └── source │ ├── emusoundfifo.c │ └── main.c ├── arm9 ├── Makefile ├── data │ ├── clickNoQuit.wav │ ├── keyclick.wav │ ├── mus_intro.wav │ └── soundbank.bin ├── gfx_data │ ├── cassette.png │ ├── debug_ovl.png │ ├── mainmenu.png │ ├── pdev_bg0.png │ ├── pdev_tbg0.png │ ├── speccy_kbd.png │ └── topscreen.png └── source │ ├── CRC32.c │ ├── CRC32.h │ ├── SpeccySE.c │ ├── SpeccySE.h │ ├── SpeccyUtils.c │ ├── SpeccyUtils.h │ ├── cpu │ ├── ay38910 │ │ ├── AY38910.h │ │ ├── AY38910.i │ │ ├── AY38910.s │ │ ├── AY38910ToDo.txt │ │ ├── History.txt │ │ ├── README.md │ │ └── Version.h │ └── z80 │ │ ├── Z80_interface.h │ │ └── cz80 │ │ ├── Codes.h │ │ ├── CodesCB.h │ │ ├── CodesED.h │ │ ├── CodesXCB.h │ │ ├── CodesXX.h │ │ ├── Tables.c │ │ ├── Tables.h │ │ ├── Z80.c │ │ ├── Z80.h │ │ └── Z80_a.c │ ├── highscore.c │ ├── highscore.h │ ├── lzav.h │ ├── pok.c │ ├── printf.c │ ├── printf.h │ ├── saveload.c │ ├── screenshot.c │ ├── screenshot.h │ ├── soundbank.h │ ├── spectrum.c │ └── tapeload.c ├── logo.bmp ├── png ├── cassette.bmp ├── keyboard.bmp ├── keymap.bmp ├── mainmenu.bmp └── minimenu.bmp └── readme.md /Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | # path to tools - this can be deleted if you set the path in windows 3 | #--------------------------------------------------------------------------------- 4 | #export DEVKITPRO=/opt/devkitpro 5 | #export DEVKITARM=/opt/devkitpro/devkitARM 6 | # 7 | #--------------------------------------------------------------------------------- 8 | .SUFFIXES: 9 | #--------------------------------------------------------------------------------- 10 | ifeq ($(strip $(DEVKITARM)),) 11 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM) 12 | endif 13 | 14 | include $(DEVKITARM)/ds_rules 15 | 16 | export TARGET := SpeccySE 17 | export TOPDIR := $(CURDIR) 18 | export VERSION := 1.6 19 | 20 | ICON := -b $(CURDIR)/logo.bmp "SpeccySE $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/SpeccySE" 21 | 22 | .PHONY: $(TARGET).arm7 $(TARGET).arm9 23 | 24 | .PHONY: arm7/$(TARGET).elf arm9/$(TARGET).elf 25 | 26 | #--------------------------------------------------------------------------------- 27 | # main targets 28 | #--------------------------------------------------------------------------------- 29 | all: $(TARGET).nds 30 | 31 | #--------------------------------------------------------------------------------- 32 | $(TARGET).nds : arm7/$(TARGET).elf arm9/$(TARGET).elf 33 | ndstool -c $(TARGET).nds -7 arm7/$(TARGET).elf -9 arm9/$(TARGET).elf $(ICON) 34 | 35 | #--------------------------------------------------------------------------------- 36 | arm7/$(TARGET).elf: 37 | $(MAKE) -C arm7 38 | 39 | #--------------------------------------------------------------------------------- 40 | arm9/$(TARGET).elf: 41 | $(MAKE) -C arm9 42 | 43 | #--------------------------------------------------------------------------------- 44 | clean: 45 | $(MAKE) -C arm9 clean 46 | $(MAKE) -C arm7 clean 47 | rm -f $(TARGET).nds $(TARGET).arm7 $(TARGET).arm9 48 | -------------------------------------------------------------------------------- /SpeccySE.nds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/SpeccySE.nds -------------------------------------------------------------------------------- /arm7/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | # DATA is a list of directories containing binary files 15 | # all directories are relative to this makefile 16 | #--------------------------------------------------------------------------------- 17 | BUILD := build 18 | SOURCES := source 19 | INCLUDES := include build 20 | DATA := 21 | 22 | #--------------------------------------------------------------------------------- 23 | # options for code generation 24 | #--------------------------------------------------------------------------------- 25 | ARCH := -mthumb-interwork 26 | 27 | CFLAGS := -g -Wall -O2\ 28 | -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer\ 29 | -ffast-math \ 30 | $(ARCH) 31 | 32 | CFLAGS += $(INCLUDE) -DARM7 33 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -fno-rtti 34 | 35 | 36 | ASFLAGS := -g $(ARCH) 37 | LDFLAGS = -specs=ds_arm7.specs -g $(ARCH) -Wl,-Map,$(notdir $*).map 38 | 39 | #LIBS := -ldswifi7 -lmm7 -lnds7 -lmm7 40 | LIBS := -ldswifi7 -lnds7 -lmm7 41 | 42 | #--------------------------------------------------------------------------------- 43 | # list of directories containing libraries, this must be the top level containing 44 | # include and lib 45 | #--------------------------------------------------------------------------------- 46 | LIBDIRS := $(LIBNDS) 47 | 48 | 49 | #--------------------------------------------------------------------------------- 50 | # no real need to edit anything past this point unless you need to add additional 51 | # rules for different file extensions 52 | #--------------------------------------------------------------------------------- 53 | ifneq ($(BUILD),$(notdir $(CURDIR))) 54 | #--------------------------------------------------------------------------------- 55 | 56 | export ARM7ELF := $(CURDIR)/$(TARGET).elf 57 | export DEPSDIR := $(CURDIR)/$(BUILD) 58 | 59 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) 60 | 61 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 62 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 63 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 64 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 65 | 66 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 67 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 68 | 69 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 70 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 71 | -I$(CURDIR)/$(BUILD) 72 | 73 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 74 | 75 | #--------------------------------------------------------------------------------- 76 | # use CXX for linking C++ projects, CC for standard C 77 | #--------------------------------------------------------------------------------- 78 | ifeq ($(strip $(CPPFILES)),) 79 | #--------------------------------------------------------------------------------- 80 | export LD := $(CC) 81 | #--------------------------------------------------------------------------------- 82 | else 83 | #--------------------------------------------------------------------------------- 84 | export LD := $(CXX) 85 | #--------------------------------------------------------------------------------- 86 | endif 87 | #--------------------------------------------------------------------------------- 88 | 89 | .PHONY: $(BUILD) clean 90 | 91 | #--------------------------------------------------------------------------------- 92 | $(BUILD): 93 | @[ -d $@ ] || mkdir -p $@ 94 | @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 95 | 96 | #--------------------------------------------------------------------------------- 97 | clean: 98 | @echo clean ... 99 | @rm -fr $(BUILD) *.elf 100 | 101 | 102 | #--------------------------------------------------------------------------------- 103 | else 104 | 105 | DEPENDS := $(OFILES:.o=.d) 106 | 107 | #--------------------------------------------------------------------------------- 108 | # main targets 109 | #--------------------------------------------------------------------------------- 110 | $(ARM7ELF) : $(OFILES) 111 | @echo linking $(notdir $@) 112 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 113 | 114 | 115 | #--------------------------------------------------------------------------------- 116 | # you need a rule like this for each extension you use as binary data 117 | #--------------------------------------------------------------------------------- 118 | %.bin.o : %.bin 119 | #--------------------------------------------------------------------------------- 120 | @echo $(notdir $<) 121 | @$(bin2o) 122 | 123 | -include $(DEPENDS) 124 | 125 | #--------------------------------------------------------------------------------------- 126 | endif 127 | #--------------------------------------------------------------------------------------- 128 | -------------------------------------------------------------------------------- /arm7/SpeccySE.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm7/SpeccySE.elf -------------------------------------------------------------------------------- /arm7/build/emusoundfifo.d: -------------------------------------------------------------------------------- 1 | emusoundfifo.o: /home/dsb/git/SpeccySE/arm7/source/emusoundfifo.c 2 | -------------------------------------------------------------------------------- /arm7/build/emusoundfifo.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm7/build/emusoundfifo.o -------------------------------------------------------------------------------- /arm7/build/main.d: -------------------------------------------------------------------------------- 1 | main.o: /home/dsb/git/SpeccySE/arm7/source/main.c \ 2 | /opt/devkitpro/libnds/include/nds.h \ 3 | /opt/devkitpro/libnds/include/nds/libversion.h \ 4 | /opt/devkitpro/libnds/include/nds/ndstypes.h \ 5 | /opt/devkitpro/libnds/include/nds/bios.h \ 6 | /opt/devkitpro/libnds/include/nds/ndstypes.h \ 7 | /opt/devkitpro/libnds/include/nds/card.h \ 8 | /opt/devkitpro/libnds/include/nds/ndstypes.h \ 9 | /opt/devkitpro/libnds/include/nds/debug.h \ 10 | /opt/devkitpro/libnds/include/nds/dma.h \ 11 | /opt/devkitpro/libnds/include/nds/interrupts.h \ 12 | /opt/devkitpro/libnds/include/nds/ipc.h \ 13 | /opt/devkitpro/libnds/include/nds/memory.h \ 14 | /opt/devkitpro/libnds/include/nds/system.h \ 15 | /opt/devkitpro/libnds/include/nds/timers.h \ 16 | /opt/devkitpro/libnds/include/nds/fifocommon.h \ 17 | /opt/devkitpro/libnds/include/nds/interrupts.h \ 18 | /opt/devkitpro/libnds/include/nds/touch.h \ 19 | /opt/devkitpro/libnds/include/nds/input.h \ 20 | /opt/devkitpro/libnds/include/nds/sha1.h \ 21 | /opt/devkitpro/libnds/include/nds/arm7/aes.h \ 22 | /opt/devkitpro/libnds/include/nds/arm7/audio.h \ 23 | /opt/devkitpro/libnds/include/nds/arm7/serial.h \ 24 | /opt/devkitpro/libnds/include/nds/bios.h \ 25 | /opt/devkitpro/libnds/include/nds/system.h \ 26 | /opt/devkitpro/libnds/include/nds/arm7/clock.h \ 27 | /opt/devkitpro/libnds/include/nds/arm7/codec.h \ 28 | /opt/devkitpro/libnds/include/nds/memory.h \ 29 | /opt/devkitpro/libnds/include/nds/touch.h \ 30 | /opt/devkitpro/libnds/include/nds/arm7/input.h \ 31 | /opt/devkitpro/libnds/include/nds/arm7/i2c.h \ 32 | /opt/devkitpro/libnds/include/nds/arm7/sdmmc.h \ 33 | /opt/devkitpro/libnds/include/nds/arm7/serial.h \ 34 | /opt/devkitpro/libnds/include/nds/arm7/touch.h \ 35 | /opt/devkitpro/libnds/include/dswifi7.h \ 36 | /opt/devkitpro/libnds/include/dswifi_version.h \ 37 | /opt/devkitpro/libnds/include/maxmod7.h \ 38 | /opt/devkitpro/libnds/include/mm_types.h 39 | /opt/devkitpro/libnds/include/nds.h: 40 | /opt/devkitpro/libnds/include/nds/libversion.h: 41 | /opt/devkitpro/libnds/include/nds/ndstypes.h: 42 | /opt/devkitpro/libnds/include/nds/bios.h: 43 | /opt/devkitpro/libnds/include/nds/ndstypes.h: 44 | /opt/devkitpro/libnds/include/nds/card.h: 45 | /opt/devkitpro/libnds/include/nds/ndstypes.h: 46 | /opt/devkitpro/libnds/include/nds/debug.h: 47 | /opt/devkitpro/libnds/include/nds/dma.h: 48 | /opt/devkitpro/libnds/include/nds/interrupts.h: 49 | /opt/devkitpro/libnds/include/nds/ipc.h: 50 | /opt/devkitpro/libnds/include/nds/memory.h: 51 | /opt/devkitpro/libnds/include/nds/system.h: 52 | /opt/devkitpro/libnds/include/nds/timers.h: 53 | /opt/devkitpro/libnds/include/nds/fifocommon.h: 54 | /opt/devkitpro/libnds/include/nds/interrupts.h: 55 | /opt/devkitpro/libnds/include/nds/touch.h: 56 | /opt/devkitpro/libnds/include/nds/input.h: 57 | /opt/devkitpro/libnds/include/nds/sha1.h: 58 | /opt/devkitpro/libnds/include/nds/arm7/aes.h: 59 | /opt/devkitpro/libnds/include/nds/arm7/audio.h: 60 | /opt/devkitpro/libnds/include/nds/arm7/serial.h: 61 | /opt/devkitpro/libnds/include/nds/bios.h: 62 | /opt/devkitpro/libnds/include/nds/system.h: 63 | /opt/devkitpro/libnds/include/nds/arm7/clock.h: 64 | /opt/devkitpro/libnds/include/nds/arm7/codec.h: 65 | /opt/devkitpro/libnds/include/nds/memory.h: 66 | /opt/devkitpro/libnds/include/nds/touch.h: 67 | /opt/devkitpro/libnds/include/nds/arm7/input.h: 68 | /opt/devkitpro/libnds/include/nds/arm7/i2c.h: 69 | /opt/devkitpro/libnds/include/nds/arm7/sdmmc.h: 70 | /opt/devkitpro/libnds/include/nds/arm7/serial.h: 71 | /opt/devkitpro/libnds/include/nds/arm7/touch.h: 72 | /opt/devkitpro/libnds/include/dswifi7.h: 73 | /opt/devkitpro/libnds/include/dswifi_version.h: 74 | /opt/devkitpro/libnds/include/maxmod7.h: 75 | /opt/devkitpro/libnds/include/mm_types.h: 76 | -------------------------------------------------------------------------------- /arm7/build/main.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm7/build/main.o -------------------------------------------------------------------------------- /arm7/source/emusoundfifo.c: -------------------------------------------------------------------------------- 1 | // Obsoleted with switch to MAXMOD sound library 2 | -------------------------------------------------------------------------------- /arm7/source/main.c: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------- 2 | 3 | default ARM7 core 4 | 5 | Copyright (C) 2005 - 2010 6 | Michael Noland (joat) 7 | Jason Rogers (dovoto) 8 | Dave Murphy (WinterMute) 9 | 10 | This software is provided 'as-is', without any express or implied 11 | warranty. In no event will the authors be held liable for any 12 | damages arising from the use of this software. 13 | 14 | Permission is granted to anyone to use this software for any 15 | purpose, including commercial applications, and to alter it and 16 | redistribute it freely, subject to the following restrictions: 17 | 18 | 1. The origin of this software must not be misrepresented; you 19 | must not claim that you wrote the original software. If you use 20 | this software in a product, an acknowledgment in the product 21 | documentation would be appreciated but is not required. 22 | 23 | 2. Altered source versions must be plainly marked as such, and 24 | must not be misrepresented as being the original software. 25 | 26 | 3. This notice may not be removed or altered from any source 27 | distribution. 28 | 29 | ---------------------------------------------------------------------------------*/ 30 | #include 31 | #include 32 | #include 33 | 34 | extern void mmInstall( int fifo_channel ); 35 | 36 | //--------------------------------------------------------------------------------- 37 | void VblankHandler(void) { 38 | //--------------------------------------------------------------------------------- 39 | //Wifi_Update(); 40 | } 41 | 42 | 43 | //--------------------------------------------------------------------------------- 44 | void VcountHandler() { 45 | //--------------------------------------------------------------------------------- 46 | inputGetAndSend(); 47 | } 48 | 49 | volatile bool exitflag = false; 50 | 51 | //--------------------------------------------------------------------------------- 52 | void powerButtonCB() { 53 | //--------------------------------------------------------------------------------- 54 | exitflag = true; 55 | } 56 | 57 | void mmInstall(int); 58 | 59 | //--------------------------------------------------------------------------------- 60 | int main() { 61 | //--------------------------------------------------------------------------------- 62 | readUserSettings(); 63 | 64 | irqInit(); 65 | // Start the RTC tracking IRQ 66 | initClockIRQ(); 67 | touchInit(); 68 | fifoInit(); 69 | 70 | mmInstall(FIFO_MAXMOD); 71 | 72 | SetYtrigger(80); 73 | 74 | //installWifiFIFO(); 75 | installSoundFIFO(); 76 | 77 | installSystemFIFO(); 78 | 79 | irqSet(IRQ_VCOUNT, VcountHandler); 80 | irqSet(IRQ_VBLANK, VblankHandler); 81 | 82 | irqEnable( IRQ_VBLANK | IRQ_VCOUNT | IRQ_NETWORK); 83 | 84 | setPowerButtonCB(powerButtonCB); 85 | 86 | // Keep the ARM7 mostly idle 87 | while (!exitflag) { 88 | if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) { 89 | exitflag = true; 90 | } 91 | 92 | swiWaitForVBlank(); 93 | } 94 | return 0; 95 | } 96 | -------------------------------------------------------------------------------- /arm9/Makefile: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #--------------------------------------------------------------------------------- 4 | ifeq ($(strip $(DEVKITARM)),) 5 | $(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") 6 | endif 7 | 8 | include $(DEVKITARM)/ds_rules 9 | 10 | #--------------------------------------------------------------------------------- 11 | # BUILD is the directory where object files & intermediate files will be placed 12 | # SOURCES is a list of directories containing source code 13 | # INCLUDES is a list of directories containing extra header files 14 | # DATA is a list of directories containing binary files 15 | # all directories are relative to this makefile 16 | #--------------------------------------------------------------------------------- 17 | BUILD := build 18 | SOURCES := source/cpu/z80 source/cpu/z80/drz80 source/cpu/z80/cz80 source/cpu/tms9918a source/cpu/sn76496 source/cpu/ay38910 source/cpu/m6502 source/cpu/scc source 19 | INCLUDES := include 20 | DATA := data 21 | GRAPHICS := gfx 22 | SPRITES := spr_data 23 | BACKGRD := gfx_data 24 | 25 | #--------------------------------------------------------------------------------- 26 | # options for code generation 27 | #--------------------------------------------------------------------------------- 28 | #ARCH := -mthumb -mthumb-interwork 29 | ARCH := 30 | 31 | CFLAGS := -Wall -Wno-strict-aliasing -Wno-misleading-indentation -O2 -march=armv5te -mtune=arm946e-s -fomit-frame-pointer -ffast-math $(ARCH) -falign-functions=4 -frename-registers -finline-functions 32 | 33 | CFLAGS += $(INCLUDE) -DARM9 34 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions 35 | 36 | ASFLAGS := $(ARCH) -march=armv5te -mtune=arm946e-s -DSCCMULT=32 -DAY_UPSHIFT=2 -DSN_UPSHIFT=2 -DNDS 37 | 38 | LDFLAGS = -specs=ds_arm9.specs $(ARCH) -Wl,-Map,$(notdir $*.map) 39 | 40 | #--------------------------------------------------------------------------------- 41 | # any extra libraries we wish to link with the project 42 | #--------------------------------------------------------------------------------- 43 | LIBS := -ldswifi9 -lfat -lnds9 -lmm9 44 | 45 | #--------------------------------------------------------------------------------- 46 | # list of directories containing libraries, this must be the top level containing 47 | # include and lib 48 | #--------------------------------------------------------------------------------- 49 | LIBDIRS := $(LIBNDS) 50 | 51 | #--------------------------------------------------------------------------------- 52 | # no real need to edit anything past this point unless you need to add additional 53 | # rules for different file extensions 54 | #--------------------------------------------------------------------------------- 55 | ifneq ($(BUILD),$(notdir $(CURDIR))) 56 | #--------------------------------------------------------------------------------- 57 | 58 | export ARM9ELF := $(CURDIR)/$(TARGET).elf 59 | export DEPSDIR := $(CURDIR)/$(BUILD) 60 | 61 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 62 | $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) \ 63 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ 64 | $(foreach dir,$(SPRITES),$(CURDIR)/$(dir)) \ 65 | $(foreach dir,$(BACKGRD),$(CURDIR)/$(dir)) 66 | 67 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 68 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 69 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 70 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 71 | PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) 72 | 73 | OSPECIALS := debug_ovl.o speccy_kbd.o cassette.o mainmenu.o topscreen.o pdev_bg0.o pdev_tbg0.o 74 | 75 | #--------------------------------------------------------------------------------- 76 | # use CXX for linking C++ projects, CC for standard C 77 | #--------------------------------------------------------------------------------- 78 | ifeq ($(strip $(CPPFILES)),) 79 | #--------------------------------------------------------------------------------- 80 | export LD := $(CC) 81 | #--------------------------------------------------------------------------------- 82 | else 83 | #--------------------------------------------------------------------------------- 84 | export LD := $(CXX) 85 | #--------------------------------------------------------------------------------- 86 | endif 87 | #--------------------------------------------------------------------------------- 88 | 89 | export OFILES := $(OSPECIALS) $(addsuffix .o,$(BINFILES)) \ 90 | $(PNGFILES:.png=.o) $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 91 | 92 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 93 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 94 | -I$(CURDIR)/$(BUILD) 95 | 96 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 97 | 98 | .PHONY: $(BUILD) clean 99 | 100 | #--------------------------------------------------------------------------------- 101 | $(BUILD): 102 | @[ -d $@ ] || mkdir -p $@ 103 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 104 | 105 | #--------------------------------------------------------------------------------- 106 | clean: 107 | @echo clean ... 108 | @rm -fr $(BUILD) *.elf *.nds* *.bin 109 | 110 | 111 | #--------------------------------------------------------------------------------- 112 | else 113 | 114 | #--------------------------------------------------------------------------------- 115 | # main targets 116 | #--------------------------------------------------------------------------------- 117 | $(ARM9ELF) : $(OFILES) 118 | @echo linking $(notdir $@) 119 | @$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@ 120 | 121 | #--------------------------------------------------------------------------------- 122 | # you need a rule like this for each extension you use as binary data 123 | #--------------------------------------------------------------------------------- 124 | %.bin.o : %.bin 125 | @echo $(notdir $<) 126 | @$(bin2o) 127 | 128 | %.ROM.o : %.ROM 129 | @echo $(notdir $<) 130 | @$(bin2o) 131 | 132 | %.bmp.o : %.bmp 133 | @echo $(notdir $<) 134 | @$(bin2o) 135 | 136 | %.wav.o : %.wav 137 | @echo $(notdir $<) 138 | @$(bin2o) 139 | 140 | # BG------------------------ 141 | mainmenu.s mainmenu.h : mainmenu.png 142 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 143 | 144 | speccy_kbd.s speccy_kbd.h : speccy_kbd.png 145 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 146 | 147 | cassette.s cassette.h : cassette.png 148 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 149 | 150 | debug_ovl.s debug_ovl.h : debug_ovl.png 151 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 152 | 153 | topscreen.s topscreen.h : topscreen.png 154 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 155 | 156 | pdev_bg0.s pdev_bg0.h : pdev_bg0.png 157 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 158 | 159 | pdev_tbg0.s pdev_tbg0.h : pdev_tbg0.png 160 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 161 | 162 | 163 | -include $(DEPENDS) 164 | 165 | #--------------------------------------------------------------------------------------- 166 | endif 167 | #--------------------------------------------------------------------------------------- 168 | -------------------------------------------------------------------------------- /arm9/data/clickNoQuit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/data/clickNoQuit.wav -------------------------------------------------------------------------------- /arm9/data/keyclick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/data/keyclick.wav -------------------------------------------------------------------------------- /arm9/data/mus_intro.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/data/mus_intro.wav -------------------------------------------------------------------------------- /arm9/data/soundbank.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/data/soundbank.bin -------------------------------------------------------------------------------- /arm9/gfx_data/cassette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/gfx_data/cassette.png -------------------------------------------------------------------------------- /arm9/gfx_data/debug_ovl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/gfx_data/debug_ovl.png -------------------------------------------------------------------------------- /arm9/gfx_data/mainmenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/gfx_data/mainmenu.png -------------------------------------------------------------------------------- /arm9/gfx_data/pdev_bg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/gfx_data/pdev_bg0.png -------------------------------------------------------------------------------- /arm9/gfx_data/pdev_tbg0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/gfx_data/pdev_tbg0.png -------------------------------------------------------------------------------- /arm9/gfx_data/speccy_kbd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/gfx_data/speccy_kbd.png -------------------------------------------------------------------------------- /arm9/gfx_data/topscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/arm9/gfx_data/topscreen.png -------------------------------------------------------------------------------- /arm9/source/CRC32.c: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, its source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave and Marat 7 | // Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #include 12 | #include 13 | #include 14 | #include "SpeccyUtils.h" 15 | #include "CRC32.h" 16 | #include "printf.h" 17 | 18 | #define CRC32_POLY 0x04C11DB7 19 | 20 | const u32 crc32_table[256] = { 21 | 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, // 0 [0x00 .. 0x07] 22 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, // 8 [0x08 .. 0x0F] 23 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, // 16 [0x10 .. 0x17] 24 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, // 24 [0x18 .. 0x1F] 25 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, // 32 [0x20 .. 0x27] 26 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, // 40 [0x28 .. 0x2F] 27 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, // 48 [0x30 .. 0x37] 28 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, // 56 [0x38 .. 0x3F] 29 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, // 64 [0x40 .. 0x47] 30 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, // 72 [0x48 .. 0x4F] 31 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, // 80 [0x50 .. 0x57] 32 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, // 88 [0x58 .. 0x5F] 33 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, // 96 [0x60 .. 0x67] 34 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, // 104 [0x68 .. 0x6F] 35 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, // 112 [0x70 .. 0x77] 36 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, // 120 [0x78 .. 0x7F] 37 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, // 128 [0x80 .. 0x87] 38 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, // 136 [0x88 .. 0x8F] 39 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, // 144 [0x90 .. 0x97] 40 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, // 152 [0x98 .. 0x9F] 41 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, // 160 [0xA0 .. 0xA7] 42 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, // 168 [0xA8 .. 0xAF] 43 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, // 176 [0xB0 .. 0xB7] 44 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, // 184 [0xB8 .. 0xBF] 45 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, // 192 [0xC0 .. 0xC7] 46 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, // 200 [0xC8 .. 0xCF] 47 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, // 208 [0xD0 .. 0xD7] 48 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, // 216 [0xD8 .. 0xDF] 49 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, // 224 [0xE0 .. 0xE7] 50 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, // 232 [0xE8 .. 0xEF] 51 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, // 240 [0xF0 .. 0xF7] 52 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D, // 248 [0xF8 .. 0xFF] 53 | }; 54 | 55 | // -------------------------------------------------- 56 | // Compute the CRC of a memory buffer of any size... 57 | // -------------------------------------------------- 58 | ITCM_CODE u32 getCRC32(u8 *buf, u32 size) 59 | { 60 | u32 crc = 0xFFFFFFFF; 61 | 62 | for (int i=0; i < size; i++) 63 | { 64 | crc = (crc >> 8) ^ crc32_table[(crc & 0xFF) ^ (u8)buf[i]]; 65 | } 66 | 67 | return ~crc; 68 | } 69 | 70 | 71 | // ------------------------------------------------------------------------------------ 72 | // Read the file in and compute CRC... it's a bit slow but good enough and accurate! 73 | // When this routine finishes, the file will be read into ROM_Memory[] 74 | // ------------------------------------------------------------------------------------ 75 | ITCM_CODE u32 getFileCrc(const char* filename) 76 | { 77 | u32 crc1 = 0; 78 | u32 crc2 = 1; 79 | int bytesRead1 = 0; 80 | int bytesRead2 = 1; 81 | 82 | // -------------------------------------------------------------------------------------------- 83 | // I've seen some rare issues with reading files from the SD card on a DSi so we're doing 84 | // this slow and careful - we will read twice and ensure that we get the same CRC both 85 | // times in order for us to declare that this is a valid read. When we're done, the game 86 | // ROM will be placed in the ROM_Memory[] and will be ready for use by the rest of the system. 87 | // -------------------------------------------------------------------------------------------- 88 | do 89 | { 90 | // Read #1 91 | file_size = 0; 92 | crc1 = 0xFFFFFFFF; 93 | FILE* file = fopen(filename, "rb"); 94 | while ((bytesRead1 = fread(ROM_Memory, 1, MAX_TAPE_SIZE, file)) > 0) 95 | { 96 | file_size += bytesRead1; 97 | for (int i=0; i < bytesRead1; i++) 98 | { 99 | crc1 = (crc1 >> 8) ^ crc32_table[(crc1 & 0xFF) ^ (u8)ROM_Memory[i]]; 100 | } 101 | } 102 | fclose(file); 103 | 104 | // Read #2 105 | crc2 = 0xFFFFFFFF; 106 | FILE* file2 = fopen(filename, "rb"); 107 | while ((bytesRead2 = fread(ROM_Memory, 1, MAX_TAPE_SIZE, file2)) > 0) 108 | { 109 | for (int i=0; i < bytesRead2; i++) 110 | { 111 | crc2 = (crc2 >> 8) ^ crc32_table[(crc2 & 0xFF) ^ (u8)ROM_Memory[i]]; 112 | } 113 | } 114 | fclose(file2); 115 | } while (crc1 != crc2); 116 | 117 | return ~crc1; 118 | } 119 | -------------------------------------------------------------------------------- /arm9/source/CRC32.h: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, it's source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition), 7 | // Alekmaul (original port) and Marat Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. 10 | // ===================================================================================== 11 | 12 | 13 | #ifndef CRC32_H 14 | #define CRC32_H 15 | #include 16 | 17 | u32 getFileCrc(const char* filename); 18 | u32 getCRC32(u8 *buf, u32 size); 19 | 20 | #endif 21 | 22 | -------------------------------------------------------------------------------- /arm9/source/SpeccySE.h: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, its source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave and Marat 7 | // Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #ifndef _SPECCYSE_H_ 12 | #define _SPECCYSE_H_ 13 | 14 | #include 15 | #include 16 | 17 | extern u32 debug[0x10]; 18 | extern u32 DX, DY; 19 | 20 | // These are the various special icons/menu operations 21 | #define MENU_CHOICE_NONE 0x00 22 | #define MENU_CHOICE_RESET_GAME 0x01 23 | #define MENU_CHOICE_END_GAME 0x02 24 | #define MENU_CHOICE_SAVE_GAME 0x03 25 | #define MENU_CHOICE_LOAD_GAME 0x04 26 | #define MENU_CHOICE_HI_SCORE 0x05 27 | #define MENU_CHOICE_DEFINE_KEYS 0x06 28 | #define MENU_CHOICE_POKE_MEMORY 0x07 29 | #define MENU_CHOICE_CASSETTE 0x08 30 | #define MENU_CHOICE_MENU 0xFF // Special brings up a mini-menu of choices 31 | 32 | // ------------------------------------------------------------------------------ 33 | // Joystick UP, RIGHT, LEFT, DOWN and the FIRE button for the Kempston Joystick. 34 | // Designed specifically so each has its own bit so we can press more than one 35 | // direction/fire at the same time. Keyboard keys are grafted onto this below. 36 | // ------------------------------------------------------------------------------ 37 | #define JST_UP 0x0001 38 | #define JST_RIGHT 0x0002 39 | #define JST_DOWN 0x0004 40 | #define JST_LEFT 0x0008 41 | #define JST_FIRE 0x0010 42 | #define JST_FIRE2 0x0020 43 | 44 | // ----------------------------------------------------------------------------------- 45 | // And these are meta keys for mapping NDS keys to keyboard keys (many of the computer 46 | // games don't use joystick inputs and so need to map to keyboard keys...) 47 | // ----------------------------------------------------------------------------------- 48 | #define META_KBD_A 0xF001 49 | #define META_KBD_B 0xF002 50 | #define META_KBD_C 0xF003 51 | #define META_KBD_D 0xF004 52 | #define META_KBD_E 0xF005 53 | #define META_KBD_F 0xF006 54 | #define META_KBD_G 0xF007 55 | #define META_KBD_H 0xF008 56 | #define META_KBD_I 0xF009 57 | #define META_KBD_J 0xF00A 58 | #define META_KBD_K 0xF00B 59 | #define META_KBD_L 0xF00C 60 | #define META_KBD_M 0xF00D 61 | #define META_KBD_N 0xF00E 62 | #define META_KBD_O 0xF00F 63 | #define META_KBD_P 0xF010 64 | #define META_KBD_Q 0xF011 65 | #define META_KBD_R 0xF012 66 | #define META_KBD_S 0xF013 67 | #define META_KBD_T 0xF014 68 | #define META_KBD_U 0xF015 69 | #define META_KBD_V 0xF016 70 | #define META_KBD_W 0xF017 71 | #define META_KBD_X 0xF018 72 | #define META_KBD_Y 0xF019 73 | #define META_KBD_Z 0xF01A 74 | 75 | #define META_KBD_0 0xF01B 76 | #define META_KBD_1 0xF01C 77 | #define META_KBD_2 0xF01D 78 | #define META_KBD_3 0xF01E 79 | #define META_KBD_4 0xF01F 80 | #define META_KBD_5 0xF020 81 | #define META_KBD_6 0xF021 82 | #define META_KBD_7 0xF022 83 | #define META_KBD_8 0xF023 84 | #define META_KBD_9 0xF024 85 | 86 | #define META_KBD_SHIFT 0xF025 87 | #define META_KBD_SYMBOL 0xF026 88 | #define META_KBD_SPACE 0xF029 89 | #define META_KBD_RETURN 0xF02A 90 | 91 | #define MAX_KEY_OPTIONS 46 92 | 93 | // ----------------------------- 94 | // For the Full Keyboard... 95 | // ----------------------------- 96 | #define KBD_KEY_SYMBOL 1 97 | #define KBD_KEY_SHIFT 2 98 | #define KBD_KEY_SFTDIR 3 99 | #define KBD_KEY_SYMDIR 4 100 | #define KBD_KEY_RET 13 101 | 102 | // What format is the input file? 103 | #define MODE_TAP 1 104 | #define MODE_TZX 2 105 | #define MODE_RES1 3 106 | #define MODE_RES2 4 107 | #define MODE_SNA 5 108 | #define MODE_Z80 6 109 | #define MODE_ROM 7 110 | #define MODE_ZX81 8 111 | 112 | #define WAITVBL swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); 113 | 114 | // ------------------------------------------------------------------------- 115 | // This massive patch table consumes 256K (64 x 4 byte function pointers) 116 | // to allow us faster access to patch routines for tape edge detection. 117 | // We put it in LCD VRAM as this is slightly faster access on the DS/DSi. 118 | // 99% of this massive array will be zeroes but we don't have another use 119 | // for it and it does help speed up the patch lookup - so why not?! 120 | // ------------------------------------------------------------------------- 121 | typedef u8 (*patchFunc)(void); 122 | #define PatchLookup ((patchFunc*)0x06860000) 123 | 124 | extern u8 speccy_mode; 125 | extern u8 kbd_keys_pressed; 126 | extern u8 kbd_keys[12]; 127 | extern u16 emuFps; 128 | extern u16 emuActFrames; 129 | extern u16 timingFrames; 130 | extern char initial_file[]; 131 | extern char initial_path[]; 132 | extern u16 nds_key; 133 | extern u8 kbd_key; 134 | extern u16 vusCptVBL; 135 | extern u16 keyCoresp[MAX_KEY_OPTIONS]; 136 | extern u8 soundEmuPause; 137 | extern int bg0, bg1, bg0b, bg1b; 138 | extern u32 last_file_size; 139 | extern u8 zx_special_key; 140 | extern u32 zx_current_line; 141 | extern u8 last_line_drawn; 142 | extern u16 num_blocks_available; 143 | extern u16 current_block; 144 | extern u8 tape_state; 145 | extern u32 current_block_data_idx; 146 | extern u32 tape_bytes_processed; 147 | extern u32 header_pulses; 148 | extern u16 current_bit; 149 | extern u32 current_bytes_this_block; 150 | extern u8 custom_pulse_idx; 151 | extern u8 handle_last_bits; 152 | extern u16 loop_counter; 153 | extern u16 loop_block; 154 | extern u32 next_edge1; 155 | extern u32 next_edge2; 156 | extern u8 give_up_counter; 157 | extern u32 last_edge; 158 | extern s32 beeper_vol; 159 | extern u16 beeper_on_pulses; 160 | extern u16 beeper_off_pulses; 161 | extern u8 bottom_screen; 162 | extern char *loader_type; 163 | extern u8 bZX81EmuFound; 164 | extern u8 backgroundRenderScreen; 165 | extern int8 currentBrightness; 166 | extern uint16 dimDampen; 167 | extern u8 rom_special_bank; 168 | extern u8 dandanator_cmd; 169 | extern u8 dandanator_data1; 170 | extern u8 dandanator_data2; 171 | extern u8 zx_ula_plus_enabled; 172 | extern u8 zx_ula_plus_group; 173 | extern u8 zx_ula_plus_palette_reg; 174 | extern u8 zx_ula_plus_palette[64]; 175 | extern void BottomScreenOptions(void); 176 | extern void BottomScreenCassette(void); 177 | extern void BottomScreenKeyboard(void); 178 | extern void PauseSound(void); 179 | extern void UnPauseSound(void); 180 | extern void ResetStatusFlags(void); 181 | extern void ReadFileCRCAndConfig(void); 182 | extern void DisplayStatusLine(bool bForce); 183 | extern void CassetteInsert(char *filename); 184 | extern void ResetSpectrum(void); 185 | extern void processDirectAudio(void); 186 | extern u8 speccyTapePosition(void); 187 | extern void tape_frame(void); 188 | extern void apply_ula_plus_palette(void); 189 | extern void debug_init(); 190 | extern void debug_save(); 191 | extern void debug_printf(const char * str, ...); 192 | 193 | #endif // _SPECCYSE_H_ 194 | -------------------------------------------------------------------------------- /arm9/source/SpeccyUtils.h: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, its source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave and Marat 7 | // Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #ifndef _SPECCY_UTILS_H_ 12 | #define _SPECCY_UTILS_H_ 13 | #include 14 | #include "SpeccySE.h" 15 | #include "cpu/z80/Z80_interface.h" 16 | #include "cpu/ay38910/AY38910.h" 17 | 18 | #define MAX_FILES 1024 19 | #define MAX_FILENAME_LEN 160 20 | #define MAX_TAPE_SIZE (640*1024) // 640K is big enough for any .TAP/.TZX or Snapshot 21 | 22 | #define MAX_CONFIGS 4096 23 | #define CONFIG_VERSION 0x0007 24 | 25 | #define SPECCY_FILE 0x01 26 | #define DIRECTORY 0x02 27 | 28 | #define ID_SHM_CANCEL 0x00 29 | #define ID_SHM_YES 0x01 30 | #define ID_SHM_NO 0x02 31 | 32 | #define DPAD_NORMAL 0 33 | #define DPAD_DIAGONALS 1 34 | #define DPAD_SLIDE_N_GLIDE 2 35 | 36 | extern char last_path[MAX_FILENAME_LEN]; 37 | extern char last_file[MAX_FILENAME_LEN]; 38 | 39 | typedef struct { 40 | char szName[MAX_FILENAME_LEN+1]; 41 | u8 uType; 42 | u32 uCrc; 43 | } FISpeccy; 44 | 45 | 46 | extern u32 file_size; 47 | 48 | typedef struct 49 | { 50 | char description[33]; 51 | u16 block_id; 52 | } TapePositionTable_t; 53 | 54 | extern TapePositionTable_t TapePositionTable[]; 55 | 56 | struct __attribute__((__packed__)) GlobalConfig_t 57 | { 58 | u16 config_ver; 59 | u32 bios_checksums; 60 | char szLastFile[MAX_FILENAME_LEN+1]; 61 | char szLastPath[MAX_FILENAME_LEN+1]; 62 | char reserved1[MAX_FILENAME_LEN+1]; 63 | char reserved2[MAX_FILENAME_LEN+1]; 64 | u8 showFPS; 65 | u8 lastDir; 66 | u8 defMachine; 67 | u8 brightness; 68 | u8 defULAplus; 69 | u8 global_04; 70 | u8 global_05; 71 | u8 global_06; 72 | u8 global_07; 73 | u8 global_08; 74 | u8 global_09; 75 | u8 global_10; 76 | u8 global_11; 77 | u8 compressed; 78 | u8 debugger; 79 | u32 config_checksum; 80 | }; 81 | 82 | struct __attribute__((__packed__)) Config_t 83 | { 84 | u32 game_crc; 85 | u8 keymap[12]; 86 | u8 autoStop; 87 | u8 autoFire; 88 | u8 tapeSpeed; 89 | u8 dpad; 90 | u8 autoLoad; 91 | u8 machine; 92 | u8 gameSpeed; 93 | u8 ULAplus; 94 | u8 ULAtiming; 95 | u8 reserved4; 96 | u8 reserved5; 97 | u8 reserved6; 98 | u8 reserved7; 99 | u8 reserved8; 100 | u8 reserved9; 101 | u8 reserved10; 102 | }; 103 | 104 | extern struct Config_t myConfig; 105 | extern struct GlobalConfig_t myGlobalConfig; 106 | 107 | extern u8 last_special_key; 108 | extern u8 last_special_key_dampen; 109 | 110 | extern u8 ContendMap[4]; 111 | 112 | extern u16 JoyState; 113 | 114 | extern u32 file_crc; 115 | extern u8 bFirstTime; 116 | extern u8 show_tape_counter; 117 | 118 | extern u8 BufferedKeys[32]; 119 | extern u8 BufferedKeysWriteIdx; 120 | extern u8 BufferedKeysReadIdx; 121 | extern u16 keyboard_interrupt; 122 | extern u16 joystick_interrupt; 123 | extern u8 zx_force_128k_mode; 124 | extern u8 bFlash; 125 | extern u32 flash_timer; 126 | 127 | extern u8 portFE, portFD; 128 | extern u8 zx_AY_enabled; 129 | extern u8 zx_128k_mode; 130 | extern u8 zx_ScreenRendering; 131 | extern u8 tape_play_skip_frame; 132 | 133 | extern u8 SpectrumBios[0x4000]; 134 | extern u8 SpectrumBios128[0x8000]; 135 | extern u8 ZX81Emulator[0x4000]; 136 | 137 | extern u8 ROM_Memory[MAX_TAPE_SIZE]; 138 | extern u8 RAM_Memory[0x10000]; 139 | extern u8 RAM_Memory128[0x20000]; 140 | 141 | extern u8 *MemoryMap[4]; 142 | extern AY38910 myAY; 143 | 144 | extern FISpeccy gpFic[MAX_FILES]; 145 | extern int uNbRoms; 146 | extern int ucGameAct; 147 | extern int ucGameChoice; 148 | extern u8 CompressBuffer[]; 149 | extern u8 cpu_contended_delay_128[228]; 150 | extern u8 cpu_contended_delay_48[224]; 151 | 152 | extern void LoadConfig(void); 153 | extern u8 showMessage(char *szCh1, char *szCh2); 154 | extern void speccySEFindFiles(u8 bTapeOnly); 155 | extern void speccySEChangeOptions(void); 156 | extern void DSPrint(int iX,int iY,int iScr,char *szMessage); 157 | extern u32 crc32 (unsigned int crc, const unsigned char *buf, unsigned int len); 158 | extern void FadeToColor(unsigned char ucSens, unsigned short ucBG, unsigned char ucScr, unsigned char valEnd, unsigned char uWait); 159 | extern u8 speccySELoadFile(u8 bTapeOnly); 160 | extern void DisplayFileName(void); 161 | extern void DisplayFileNameCassette(void); 162 | extern u32 ReadFileCarefully(char *filename, u8 *buf, u32 buf_size, u32 buf_offset); 163 | extern u8 loadgame(const char *path); 164 | extern u8 spectrumInit(char *szGame); 165 | extern void spectrumSetPalette(void); 166 | extern void spectrumRun(void); 167 | extern void tape_search_for_loader(void); 168 | extern void tape_detect_loading(void); 169 | extern u8 cpu_readport_speccy(register unsigned short Port); 170 | extern void cpu_writeport_speccy(register unsigned short Port,register unsigned char Value); 171 | extern void speccy_decompress_z80(int romSize); 172 | extern void speccy_reset(void); 173 | extern u32 speccy_run(void); 174 | extern u8 tape_pulse(void); 175 | extern void tape_reset(void); 176 | extern void tape_patch(void); 177 | extern void tape_stop(void); 178 | extern void tape_play(void); 179 | extern void tape_position(u8 newPos); 180 | extern u8 tape_find_positions(void); 181 | extern u8 tape_is_playing(void); 182 | extern void tape_parse_blocks(int tapeSize); 183 | extern void getfile_crc(const char *path); 184 | extern void spectrumLoadState(); 185 | extern void spectrumSaveState(); 186 | extern void intro_logo(void); 187 | extern void BufferKey(u8 key); 188 | extern void ProcessBufferedKeys(void); 189 | extern void SpeccySEChangeKeymap(void); 190 | extern void pok_select(void); 191 | extern void pok_init(); 192 | 193 | #endif // _SPECCY_UTILS_H_ 194 | -------------------------------------------------------------------------------- /arm9/source/cpu/ay38910/AY38910.h: -------------------------------------------------------------------------------- 1 | // 2 | // AY38910.h 3 | // AY-3-8910 / YM2149 sound chip emulator for arm32. 4 | // 5 | // Created by Fredrik Ahlström on 2006-03-07. 6 | // Copyright © 2006-2024 Fredrik Ahlström. All rights reserved. 7 | // 8 | 9 | #ifndef AY38910_HEADER 10 | #define AY38910_HEADER 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | typedef struct { 17 | u16 ch0Freq; 18 | u16 ch0Addr; 19 | u16 ch1Freq; 20 | u16 ch1Addr; 21 | u16 ch2Freq; 22 | u16 ch2Addr; 23 | u16 ch3Freq; 24 | u16 ch3Addr; 25 | 26 | u32 ayRng; 27 | u32 ayEnvFreq; 28 | u8 ayChState; 29 | u8 ayChDisable; 30 | u8 ayEnvType; 31 | u8 ayEnvAddr; 32 | u32 ayOldSample; 33 | u16 *ayEnvVolumePtr; 34 | 35 | u8 ayAttChg; 36 | u8 ayRegIndex; 37 | u8 ayPadding1[2]; 38 | s16 ayCalculatedVolumes[8]; 39 | u8 ayPortAOut; 40 | u8 ayPortBOut; 41 | u8 ayPortAIn; 42 | u8 ayPortBIn; 43 | u8 ayRegs[16]; 44 | void *ayPortAInFptr; 45 | void *ayPortBInFptr; 46 | void *ayPortAOutFptr; 47 | void *ayPortBOutFptr; 48 | 49 | } AY38910; 50 | 51 | /** 52 | * Reset/initialize AY38910 chip. 53 | * @param *chip: The AY38910 chip. 54 | */ 55 | void ay38910Reset(AY38910 *chip); 56 | 57 | /** 58 | * Saves the state of the AY38910 chip to the destination. 59 | * @param *destination: Where to save the state. 60 | * @param *chip: The AY38910 chip to save. 61 | * @return The size of the state. 62 | */ 63 | int ay38910SaveState(void *dest, const AY38910 *chip); 64 | 65 | /** 66 | * Loads the state of the AY38910 chip from the source. 67 | * @param *chip: The AY38910 chip to load a state into. 68 | * @param *source: Where to load the state from. 69 | * @return The size of the state. 70 | */ 71 | int ay38910LoadState(AY38910 *chip, const void *source); 72 | 73 | /** 74 | * Gets the state size of a AY38910. 75 | * @return The size of the state. 76 | */ 77 | int ay38910GetStateSize(void); 78 | 79 | /** 80 | * Renders count amount of samples, clocks the chip the same amount. 81 | * Internal oversampling can be set by defining AY_UPSHIFT to a number. 82 | * @param count: Number of samples to render. 83 | * @param *dest: Pointer to buffer where sound is rendered. 84 | * @param *chip: The AY38910 chip. 85 | */ 86 | void ay38910Mixer(int count, s16 *dest, AY38910 *chip); 87 | 88 | /** 89 | * Write index/register value to the AY38910 chip 90 | * @param index: index to write. 91 | * @param *chip: The AY38910 chip. 92 | */ 93 | void ay38910IndexW(u8 index, AY38910 *chip); 94 | 95 | /** 96 | * Write data value to the selected index/register or IO-port in the AY38910 chip 97 | * @param value: value to write. 98 | * @param *chip: The AY38910 chip. 99 | */ 100 | void ay38910DataW(u8 value, AY38910 *chip); 101 | 102 | /** 103 | * Read data from the selected index/register in the AY38910 chip 104 | * @param *chip: The AY38910 chip. 105 | * @return The value in the selected index/register or IO-port. 106 | */ 107 | u8 ay38910DataR(AY38910 *chip); 108 | 109 | #ifdef __cplusplus 110 | } // extern "C" 111 | #endif 112 | 113 | #endif // AY38910_HEADER 114 | -------------------------------------------------------------------------------- /arm9/source/cpu/ay38910/AY38910.i: -------------------------------------------------------------------------------- 1 | ;@ 2 | ;@ AY38910.i 3 | ;@ ASM header for the AY-3-8910 / YM2149 sound chip emulator for arm32. 4 | ;@ 5 | ;@ Created by Fredrik Ahlström on 2006-03-07. 6 | ;@ Copyright © 2006-2024 Fredrik Ahlström. All rights reserved. 7 | ;@ 8 | 9 | #if !__ASSEMBLER__ 10 | #error This header file is only for use in assembly files! 11 | #endif 12 | 13 | ;@ AY38910.s 14 | .struct 0 15 | ayCh0Freq: .short 0 16 | ayCh0Addr: .short 0 17 | ayCh1Freq: .short 0 18 | ayCh1Addr: .short 0 19 | ayCh2Freq: .short 0 20 | ayCh2Addr: .short 0 21 | ayCh3Freq: .short 0 22 | ayCh3Addr: .short 0 23 | 24 | ayRng: .long 0 25 | ayEnvFreq: .long 0 26 | ayChState: .byte 0 ;@ Which channels are high/low 27 | ayChDisable: .byte 0 28 | ayEnvType: .byte 0 29 | ayEnvAddr: .byte 0 30 | ayOldSample: .long 0 31 | ayEnvVolumePtr: .long 0 32 | 33 | ayAttChg: .byte 0 34 | ayRegIndex: .byte 0 35 | ayPadding1: .space 2 36 | 37 | ayCalculatedVolumes: 38 | .space 8*2 39 | ayPortAOut: .byte 0 40 | ayPortBOut: .byte 0 41 | ayPortAIn: .byte 0 42 | ayPortBIn: .byte 0 43 | ayRegs: .space 16 44 | ayPortAInFptr: .long 0 45 | ayPortBInFptr: .long 0 46 | ayPortAOutFptr: .long 0 47 | ayPortBOutFptr: .long 0 48 | 49 | aySize: 50 | 51 | ;@---------------------------------------------------------------------------- 52 | 53 | -------------------------------------------------------------------------------- /arm9/source/cpu/ay38910/AY38910.s: -------------------------------------------------------------------------------- 1 | ;@ 2 | ;@ AY38910.s 3 | ;@ AY-3-8910 / YM2149 sound chip emulator for arm32. 4 | ;@ 5 | ;@ Created by Fredrik Ahlström on 2006-03-07. 6 | ;@ Copyright © 2006-2024 Fredrik Ahlström. All rights reserved. 7 | ;@ 8 | #ifdef __arm__ 9 | 10 | #include "AY38910.i" 11 | 12 | .global ay38910Reset 13 | .global ay38910SaveState 14 | .global ay38910LoadState 15 | .global ay38910GetStateSize 16 | .global ay38910Mixer 17 | .global ay38910IndexW 18 | .global ay38910DataW 19 | .global ay38910DataR 20 | 21 | .equ NSEED, 0x10000 ;@ Noise Seed 22 | .equ WFEED, 0x12000 ;@ White Noise Feedback, according to MAME. 23 | .equ WFEED3, 0x14000 ;@ White Noise Feedback for AY-3-8930, according to MAME. 24 | 25 | #ifdef AY_UPSHIFT 26 | .equ USHIFT, AY_UPSHIFT 27 | #else 28 | .equ USHIFT, 0 29 | #endif 30 | #ifdef AYFILTER 31 | .equ FSHIFT, AYFILTER+USHIFT 32 | #else 33 | .equ FSHIFT, 1+USHIFT 34 | #endif 35 | 36 | #define AYNOISEADD 0x08000000 37 | #define AYTONEADD 0x00100000 38 | #define AYENVADD 0x00010000 39 | 40 | .syntax unified 41 | .arm 42 | 43 | #ifdef NDS 44 | .section .itcm ;@ For the NDS 45 | #elif GBA 46 | .section .iwram, "ax", %progbits ;@ For the GBA 47 | #else 48 | .section .text 49 | #endif 50 | .align 2 51 | ;@---------------------------------------------------------------------------- 52 | ;@ r0 = mix length. 53 | ;@ r1 = mixerbuffer. 54 | ;@ r2 = ayptr 55 | ;@ r3 -> r6 = pos+freq. 56 | ;@ r7 = noise generator. 57 | ;@ r8 = envelope freq 58 | ;@ r9 = envelope addr, envelope type, ch disable, ch state. 59 | ;@ r10 = mixer reg. 60 | ;@ r11 = pointer to attenuation table. 61 | ;@ r12 = ch state/scrap 62 | ;@ lr = envelope volume 63 | ;@---------------------------------------------------------------------------- 64 | ay38910Mixer: ;@ r0=len, r1=dest, ayptr=r2=pointer to struct 65 | .type ay38910Mixer STT_FUNC 66 | ;@---------------------------------------------------------------------------- 67 | #ifdef AY_UPSHIFT 68 | mov r0,r0,lsl#USHIFT 69 | #endif 70 | stmfd sp!,{r4-r11,lr} 71 | ldmia r2,{r3-r12} ;@ Load freq,addr,rng,env 72 | tst r12,#0xff 73 | blne calculateVolumes 74 | ;@---------------------------------------------------------------------------- 75 | mixLoop: 76 | sub r10,r10,r10,lsr#FSHIFT-USHIFT 77 | innerMixLoop: 78 | adds r3,r3,#AYTONEADD 79 | subcs r3,r3,r3,lsl#20 80 | eorcs r9,r9,#0x0000001 ;@ Channel A 81 | adds r4,r4,#AYTONEADD 82 | subcs r4,r4,r4,lsl#20 83 | eorcs r9,r9,#0x00000002 ;@ Channel B 84 | adds r5,r5,#AYTONEADD 85 | subcs r5,r5,r5,lsl#20 86 | eorcs r9,r9,#0x00000004 ;@ Channel C 87 | 88 | adds r6,r6,#AYNOISEADD 89 | subcs r6,r6,r6,lsl#27 90 | orrcs r9,r9,#0x00000038 ;@ Clear noise channel. 91 | movscs r7,r7,lsr#1 92 | eorcs r7,r7,#WFEED 93 | eorcs r9,r9,#0x00000038 ;@ Noise channel. 94 | 95 | adds r8,r8,#AYENVADD 96 | subcs r8,r8,r8,lsl#16 97 | addcs r9,r9,#0x08000000 98 | tst r9,r9,lsl#15 ;@ Envelope Hold 99 | bicmi r9,r9,#0x78000000 100 | orr r12,r9,r9,lsr#10 ;@ Channels disable. 101 | and r12,r12,r12,lsr#3 ;@ Noise disable. 102 | mov r12,r12,lsl#29 103 | add lr,r2,r12,lsr#28 104 | ldrh lr,[lr,#ayCalculatedVolumes] 105 | add r10,r10,lr 106 | 107 | and lr,r9,r9,lsl#14 ;@ Envelope Alternate (allready flipped from Hold) 108 | eors lr,lr,r9,lsl#13 ;@ Envelope Attack 109 | and lr,r9,#0x78000000 110 | eorpl lr,lr,#0x78000000 111 | 112 | ands r12,r12,r9,lsl#22 ;@ Check if any channels use envelope 113 | ldrne lr,[r11,lr,lsr#25] 114 | addmi r10,r10,lr 115 | movs r12,r12,lsl#2 116 | addcs r10,r10,lr 117 | addmi r10,r10,lr 118 | 119 | subs r0,r0,#1 120 | #ifdef AY_UPSHIFT 121 | tst r0,#(1< 5 | 6 | #include "./cz80/Z80.h" 7 | 8 | #define word u16 9 | #define byte u8 10 | 11 | extern Z80 CPU; 12 | 13 | extern void Trap_Bad_Ops(char *prefix, byte I, word W); 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/Codes.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SpeccySE Z80 CPU 3 | * 4 | * Note: Most of this file is from the ColEm emulator core by Marat Fayzullin 5 | * but heavily modified for specific NDS use. If you want to use this 6 | * code, you are advised to seek out the much more portable ColEm core 7 | * and contact Marat. 8 | * 9 | ******************************************************************************/ 10 | 11 | /** Z80: portable Z80 emulator *******************************/ 12 | /** **/ 13 | /** Codes.h **/ 14 | /** **/ 15 | /** This file contains implementation for the main table of **/ 16 | /** Z80 commands. It is included from Z80.c. **/ 17 | /** **/ 18 | /** Copyright (C) Marat Fayzullin 1994-2021 **/ 19 | /** You are not allowed to distribute this software **/ 20 | /** commercially. Please, notify me, if you make any **/ 21 | /** changes to this file. **/ 22 | /*************************************************************/ 23 | 24 | 25 | // ---------------------------------------------------------------------------------------- 26 | // For the jump instructions, the Cycle[] table builds in assuming the jump WILL be taken 27 | // which is true about 95% of the time. If the jump is not taken, we compensate ICount. 28 | // ---------------------------------------------------------------------------------------- 29 | case JR_NZ: if(CPU.AF.B.l&Z_FLAG) {J_ADJ; RdZ80(CPU.PC.W++);} else { M_JR; T_INC(5); } break; //12:435, 7:43 30 | case JR_NC: if(CPU.AF.B.l&C_FLAG) {J_ADJ; RdZ80(CPU.PC.W++);} else { M_JR; T_INC(5); } break; //12:435, 7:43 31 | case JR_Z: if(CPU.AF.B.l&Z_FLAG) { M_JR; T_INC(5); } else {J_ADJ; RdZ80(CPU.PC.W++);} break; //12:435, 7:43 32 | case JR_C: if(CPU.AF.B.l&C_FLAG) { M_JR; T_INC(5); } else {J_ADJ; RdZ80(CPU.PC.W++);} break; //12:435, 7:43 33 | 34 | case JP_NZ: if(CPU.AF.B.l&Z_FLAG) { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } else { M_JP; } break; //10:433 35 | case JP_NC: if(CPU.AF.B.l&C_FLAG) { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } else { M_JP; } break; //10:433 36 | case JP_PO: if(CPU.AF.B.l&P_FLAG) { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } else { M_JP; } break; //10:433 37 | case JP_P: if(CPU.AF.B.l&S_FLAG) { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } else { M_JP; } break; //10:433 38 | case JP_Z: if(CPU.AF.B.l&Z_FLAG) { M_JP; } else { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } break; //10:433 39 | case JP_C: if(CPU.AF.B.l&C_FLAG) { M_JP; } else { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } break; //10:433 40 | case JP_PE: if(CPU.AF.B.l&P_FLAG) { M_JP; } else { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } break; //10:433 41 | case JP_M: if(CPU.AF.B.l&S_FLAG) { M_JP; } else { PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2; } break; //10:433 42 | 43 | // ----------------------------------------------------------------------------------------- 44 | // For the RET instructions, the Cycle[] table builds in assuming the return will NOT be 45 | // taken and so we must consume the additional cycles if the condition proves to be TRUE... 46 | // ----------------------------------------------------------------------------------------- 47 | case RET_NZ: T_INC(1); if(!(CPU.AF.B.l&Z_FLAG)) { R_ADJ;M_RET; } break; //11:533, 5:5 48 | case RET_NC: T_INC(1); if(!(CPU.AF.B.l&C_FLAG)) { R_ADJ;M_RET; } break; //11:533, 5:5 49 | case RET_PO: T_INC(1); if(!(CPU.AF.B.l&P_FLAG)) { R_ADJ;M_RET; } break; //11:533, 5:5 50 | case RET_P: T_INC(1); if(!(CPU.AF.B.l&S_FLAG)) { R_ADJ;M_RET; } break; //11:533, 5:5 51 | case RET_Z: T_INC(1); if(CPU.AF.B.l&Z_FLAG) { R_ADJ;M_RET; } break; //11:533, 5:5 52 | case RET_C: T_INC(1); if(CPU.AF.B.l&C_FLAG) { R_ADJ;M_RET; } break; //11:533, 5:5 53 | case RET_PE: T_INC(1); if(CPU.AF.B.l&P_FLAG) { R_ADJ;M_RET; } break; //11:533, 5:5 54 | case RET_M: T_INC(1); if(CPU.AF.B.l&S_FLAG) { R_ADJ;M_RET; } break; //11:533, 5:5 55 | 56 | case CALL_NZ: if(CPU.AF.B.l&Z_FLAG) {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} else { C_ADJ;M_CALL; } break; //17:43433, 10:433 57 | case CALL_NC: if(CPU.AF.B.l&C_FLAG) {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} else { C_ADJ;M_CALL; } break; //17:43433, 10:433 58 | case CALL_PO: if(CPU.AF.B.l&P_FLAG) {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} else { C_ADJ;M_CALL; } break; //17:43433, 10:433 59 | case CALL_P: if(CPU.AF.B.l&S_FLAG) {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} else { C_ADJ;M_CALL; } break; //17:43433, 10:433 60 | case CALL_Z: if(CPU.AF.B.l&Z_FLAG) { C_ADJ;M_CALL; } else {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} break; //17:43433, 10:433 61 | case CALL_C: if(CPU.AF.B.l&C_FLAG) { C_ADJ;M_CALL; } else {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} break; //17:43433, 10:433 62 | case CALL_PE: if(CPU.AF.B.l&P_FLAG) { C_ADJ;M_CALL; } else {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} break; //17:43433, 10:433 63 | case CALL_M: if(CPU.AF.B.l&S_FLAG) { C_ADJ;M_CALL; } else {PhantomRdZ80(CPU.PC.W);PhantomRdZ80(CPU.PC.W); CPU.PC.W+=2;} break; //17:43433, 10:433 64 | 65 | case ADD_B: M_ADD(CPU.BC.B.h);break; //4:4 66 | case ADD_C: M_ADD(CPU.BC.B.l);break; //4:4 67 | case ADD_D: M_ADD(CPU.DE.B.h);break; //4:4 68 | case ADD_E: M_ADD(CPU.DE.B.l);break; //4:4 69 | case ADD_H: M_ADD(CPU.HL.B.h);break; //4:4 70 | case ADD_L: M_ADD(CPU.HL.B.l);break; //4:4 71 | case ADD_A: M_ADD(CPU.AF.B.h);break; //4:4 72 | case ADD_xHL: I=RdZ80(CPU.HL.W);M_ADD(I);break; //7:43 73 | case ADD_BYTE: I=RdZ80(CPU.PC.W++);M_ADD(I);break; //7:43 74 | 75 | case SUB_B: M_SUB(CPU.BC.B.h);break; //4:4 76 | case SUB_C: M_SUB(CPU.BC.B.l);break; //4:4 77 | case SUB_D: M_SUB(CPU.DE.B.h);break; //4:4 78 | case SUB_E: M_SUB(CPU.DE.B.l);break; //4:4 79 | case SUB_H: M_SUB(CPU.HL.B.h);break; //4:4 80 | case SUB_L: M_SUB(CPU.HL.B.l);break; //4:4 81 | case SUB_A: CPU.AF.B.h=0;CPU.AF.B.l=N_FLAG|Z_FLAG;break; //4:4 82 | case SUB_xHL: I=RdZ80(CPU.HL.W);M_SUB(I);break; //7:43 83 | case SUB_BYTE: I=RdZ80(CPU.PC.W++);M_SUB(I);break; //7:43 84 | 85 | case AND_B: M_AND(CPU.BC.B.h);break; //4:4 86 | case AND_C: M_AND(CPU.BC.B.l);break; //4:4 87 | case AND_D: M_AND(CPU.DE.B.h);break; //4:4 88 | case AND_E: M_AND(CPU.DE.B.l);break; //4:4 89 | case AND_H: M_AND(CPU.HL.B.h);break; //4:4 90 | case AND_L: M_AND(CPU.HL.B.l);break; //4:4 91 | case AND_A: M_AND(CPU.AF.B.h);break; //4:4 92 | case AND_xHL: I=RdZ80(CPU.HL.W);M_AND(I);break; //7:43 93 | case AND_BYTE: I=RdZ80(CPU.PC.W++);M_AND(I);break; //7:43 94 | 95 | case OR_B: M_OR(CPU.BC.B.h);break; //4:4 96 | case OR_C: M_OR(CPU.BC.B.l);break; //4:4 97 | case OR_D: M_OR(CPU.DE.B.h);break; //4:4 98 | case OR_E: M_OR(CPU.DE.B.l);break; //4:4 99 | case OR_H: M_OR(CPU.HL.B.h);break; //4:4 100 | case OR_L: M_OR(CPU.HL.B.l);break; //4:4 101 | case OR_A: M_OR(CPU.AF.B.h);break; //4:4 102 | case OR_xHL: I=RdZ80(CPU.HL.W);M_OR(I);break; //7:43 103 | case OR_BYTE: I=RdZ80(CPU.PC.W++);M_OR(I);break; //7:43 104 | 105 | case ADC_B: M_ADC(CPU.BC.B.h);break; //4:4 106 | case ADC_C: M_ADC(CPU.BC.B.l);break; //4:4 107 | case ADC_D: M_ADC(CPU.DE.B.h);break; //4:4 108 | case ADC_E: M_ADC(CPU.DE.B.l);break; //4:4 109 | case ADC_H: M_ADC(CPU.HL.B.h);break; //4:4 110 | case ADC_L: M_ADC(CPU.HL.B.l);break; //4:4 111 | case ADC_A: M_ADC(CPU.AF.B.h);break; //4:4 112 | case ADC_xHL: I=RdZ80(CPU.HL.W);M_ADC(I);break; //7:43 113 | case ADC_BYTE: I=RdZ80(CPU.PC.W++);M_ADC(I);break; //7:43 114 | 115 | case SBC_B: M_SBC(CPU.BC.B.h);break; //4:4 116 | case SBC_C: M_SBC(CPU.BC.B.l);break; //4:4 117 | case SBC_D: M_SBC(CPU.DE.B.h);break; //4:4 118 | case SBC_E: M_SBC(CPU.DE.B.l);break; //4:4 119 | case SBC_H: M_SBC(CPU.HL.B.h);break; //4:4 120 | case SBC_L: M_SBC(CPU.HL.B.l);break; //4:4 121 | case SBC_A: M_SBC(CPU.AF.B.h);break; //4:4 122 | case SBC_xHL: I=RdZ80(CPU.HL.W);M_SBC(I);break; //7:43 123 | case SBC_BYTE: I=RdZ80(CPU.PC.W++);M_SBC(I);break; //7:43 124 | 125 | case XOR_B: M_XOR(CPU.BC.B.h);break; //4:4 126 | case XOR_C: M_XOR(CPU.BC.B.l);break; //4:4 127 | case XOR_D: M_XOR(CPU.DE.B.h);break; //4:4 128 | case XOR_E: M_XOR(CPU.DE.B.l);break; //4:4 129 | case XOR_H: M_XOR(CPU.HL.B.h);break; //4:4 130 | case XOR_L: M_XOR(CPU.HL.B.l);break; //4:4 131 | case XOR_A: CPU.AF.B.h=0;CPU.AF.B.l=P_FLAG|Z_FLAG;break; //4:4 132 | case XOR_xHL: I=RdZ80(CPU.HL.W);M_XOR(I);break; //7:43 133 | case XOR_BYTE: I=RdZ80(CPU.PC.W++);M_XOR(I);break; //7:43 134 | 135 | case CP_B: M_CP(CPU.BC.B.h);break; //4:4 136 | case CP_C: M_CP(CPU.BC.B.l);break; //4:4 137 | case CP_D: M_CP(CPU.DE.B.h);break; //4:4 138 | case CP_E: M_CP(CPU.DE.B.l);break; //4:4 139 | case CP_H: M_CP(CPU.HL.B.h);break; //4:4 140 | case CP_L: M_CP(CPU.HL.B.l);break; //4:4 141 | case CP_A: CPU.AF.B.l=N_FLAG|Z_FLAG;break; //4:4 142 | case CP_xHL: I=RdZ80(CPU.HL.W);M_CP(I);break; //7:43 143 | case CP_BYTE: I=RdZ80(CPU.PC.W++);M_CP(I);break; //7:43 144 | 145 | case LD_BC_WORD: M_LDWORD(BC);break; //10:433 146 | case LD_DE_WORD: M_LDWORD(DE);break; //10:433 147 | case LD_HL_WORD: M_LDWORD(HL);break; //10:433 148 | case LD_SP_WORD: M_LDWORD(SP);break; //10:433 149 | 150 | case LD_PC_HL: CPU.PC.W=CPU.HL.W;JumpZ80(CPU.PC.W);break; //4:4 151 | case LD_SP_HL: CPU.SP.W=CPU.HL.W; T_INC(2); break; //6:6 152 | case LD_A_xBC: CPU.AF.B.h=RdZ80(CPU.BC.W);break; //7:43 153 | case LD_A_xDE: CPU.AF.B.h=RdZ80(CPU.DE.W);break; //7:43 154 | 155 | case ADD_HL_BC: M_ADDW(HL,BC);T_INC(7);break; //11:443 156 | case ADD_HL_DE: M_ADDW(HL,DE);T_INC(7);break; //11:443 157 | case ADD_HL_HL: M_ADDW(HL,HL);T_INC(7);break; //11:443 158 | case ADD_HL_SP: M_ADDW(HL,SP);T_INC(7);break; //11:443 159 | 160 | case DEC_BC: CPU.BC.W--; T_INC(2); break; // 6:6 161 | case DEC_DE: CPU.DE.W--; T_INC(2); break; // 6:6 162 | case DEC_HL: CPU.HL.W--; T_INC(2); break; // 6:6 163 | case DEC_SP: CPU.SP.W--; T_INC(2); break; // 6:6 164 | 165 | case INC_BC: CPU.BC.W++; T_INC(2); break; // 6:6 166 | case INC_DE: CPU.DE.W++; T_INC(2); break; // 6:6 167 | case INC_HL: CPU.HL.W++; T_INC(2); break; // 6:6 168 | case INC_SP: CPU.SP.W++; T_INC(2); break; // 6:6 169 | 170 | case DEC_B: M_DEC(CPU.BC.B.h); break; //4:4 171 | case DEC_C: M_DEC(CPU.BC.B.l); break; //4:4 172 | case DEC_D: M_DEC(CPU.DE.B.h); break; //4:4 173 | case DEC_E: M_DEC(CPU.DE.B.l); break; //4:4 174 | case DEC_H: M_DEC(CPU.HL.B.h); break; //4:4 175 | case DEC_L: M_DEC(CPU.HL.B.l); break; //4:4 176 | case DEC_A: //4:4 177 | if (PatchLookup[CPU.PC.W]) (void)PatchLookup[CPU.PC.W](); // Tape pre-delay speedup... 178 | else { M_DEC(CPU.AF.B.h); } 179 | break; 180 | case DEC_xHL: I=RdZ80(CPU.HL.W);M_DEC(I);T_INC(1);WrZ80(CPU.HL.W,I);break; //11:443 181 | 182 | case INC_B: M_INC(CPU.BC.B.h); break; //4:4 183 | case INC_C: M_INC(CPU.BC.B.l); break; //4:4 184 | case INC_D: M_INC(CPU.DE.B.h); break; //4:4 185 | case INC_E: M_INC(CPU.DE.B.l); break; //4:4 186 | case INC_H: M_INC(CPU.HL.B.h); break; //4:4 187 | case INC_L: M_INC(CPU.HL.B.l); break; //4:4 188 | case INC_A: M_INC(CPU.AF.B.h); break; //4:4 189 | case INC_xHL: I=RdZ80(CPU.HL.W);M_INC(I);T_INC(1);WrZ80(CPU.HL.W,I);break; //11:443 190 | 191 | case RLCA: // 4:4 192 | I=CPU.AF.B.h&0x80? C_FLAG:0; 193 | CPU.AF.B.h=(CPU.AF.B.h<<1)|I; 194 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 195 | break; 196 | case RLA: // 4:4 197 | I=CPU.AF.B.h&0x80? C_FLAG:0; 198 | CPU.AF.B.h=(CPU.AF.B.h<<1)|(CPU.AF.B.l&C_FLAG); 199 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 200 | break; 201 | case RRCA: // 4:4 202 | I=CPU.AF.B.h&0x01; 203 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(I? 0x80:0); 204 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 205 | break; 206 | case RRA: // 4:4 207 | I=CPU.AF.B.h&0x01; 208 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(CPU.AF.B.l&C_FLAG? 0x80:0); 209 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 210 | break; 211 | 212 | case RST00: T_INC(1); M_RST(0x0000);break; //11:533 213 | case RST08: T_INC(1); M_RST(0x0008);break; //11:533 214 | case RST10: T_INC(1); M_RST(0x0010);break; //11:533 215 | case RST18: T_INC(1); M_RST(0x0018);break; //11:533 216 | case RST20: T_INC(1); M_RST(0x0020);break; //11:533 217 | case RST28: T_INC(1); M_RST(0x0028);break; //11:533 218 | case RST30: T_INC(1); M_RST(0x0030);break; //11:533 219 | case RST38: T_INC(1); M_RST(0x0038);break; //11:533 220 | 221 | case PUSH_BC: T_INC(1); M_PUSH(BC);break; //11:533 222 | case PUSH_DE: T_INC(1); M_PUSH(DE);break; //11:533 223 | case PUSH_HL: T_INC(1); M_PUSH(HL);break; //11:533 224 | case PUSH_AF: T_INC(1); M_PUSH(AF);break; //11:533 225 | 226 | case POP_BC: M_POP(BC);break; //10:433 227 | case POP_DE: M_POP(DE);break; //10:433 228 | case POP_HL: M_POP(HL);break; //10:433 229 | case POP_AF: M_POP(AF);break; //10:433 230 | 231 | case DJNZ: // 13:535, 8:53 232 | if (PatchLookup[CPU.PC.W]) (void)PatchLookup[CPU.PC.W](); // Tape pre-load speedup... 233 | T_INC(1); 234 | if(--CPU.BC.B.h) { M_JR; T_INC(5); } else {J_ADJ; PhantomRdZ80(CPU.PC.W); CPU.PC.W++;} break; 235 | 236 | case JP: M_JP; break; //10:433 237 | case JR: M_JR; T_INC(5); break; //12:435 238 | case CALL: M_CALL; break; //17:43433 239 | case RET: M_RET; break; //10:433 240 | case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break; //4:4 241 | case CPL: CPU.AF.B.h=~CPU.AF.B.h;S(N_FLAG|H_FLAG);break; //4:4 242 | case NOP: break; //4:4 243 | case OUTA: I=RdZ80(CPU.PC.W++);OutZ80(I|(CPU.AF.W&0xFF00),CPU.AF.B.h);break; //11:434 244 | case INA: I=RdZ80(CPU.PC.W++);CPU.AF.B.h=InZ80(I|(CPU.AF.W&0xFF00));break; //11:434 245 | 246 | case HALT: //4:4 247 | CPU.TStates = RunToCycles; // We're just waiting for an interrupt... so just skip ahead. This is often how a ZX game waits for the next frame. 248 | CPU.PC.W--; 249 | CPU.IFF|=IFF_HALT; 250 | break; 251 | 252 | case DI: //4:4 253 | CPU.IFF&=~(IFF_1|IFF_2|IFF_EI); 254 | break; 255 | 256 | case EI: //4:4 257 | if(!(CPU.IFF&(IFF_1|IFF_EI))) 258 | { 259 | CPU.IFF|=IFF_2|IFF_EI; 260 | EI_Enable(); 261 | } 262 | break; 263 | 264 | case CCF: //4:4 265 | CPU.AF.B.l^=C_FLAG;R(N_FLAG|H_FLAG); 266 | CPU.AF.B.l|=CPU.AF.B.l&C_FLAG? 0:H_FLAG; 267 | break; 268 | 269 | case EXX: //4:4 270 | J.W=CPU.BC.W;CPU.BC.W=CPU.BC1.W;CPU.BC1.W=J.W; 271 | J.W=CPU.DE.W;CPU.DE.W=CPU.DE1.W;CPU.DE1.W=J.W; 272 | J.W=CPU.HL.W;CPU.HL.W=CPU.HL1.W;CPU.HL1.W=J.W; 273 | break; 274 | 275 | case EX_DE_HL: J.W=CPU.DE.W;CPU.DE.W=CPU.HL.W;CPU.HL.W=J.W;break; //4:4 276 | case EX_AF_AF: J.W=CPU.AF.W;CPU.AF.W=CPU.AF1.W;CPU.AF1.W=J.W;break; //4:4 277 | 278 | case LD_B_B: CPU.BC.B.h=CPU.BC.B.h;break; //4:4 279 | case LD_C_B: CPU.BC.B.l=CPU.BC.B.h;break; //4:4 280 | case LD_D_B: CPU.DE.B.h=CPU.BC.B.h;break; //4:4 281 | case LD_E_B: CPU.DE.B.l=CPU.BC.B.h;break; //4:4 282 | case LD_H_B: CPU.HL.B.h=CPU.BC.B.h;break; //4:4 283 | case LD_L_B: CPU.HL.B.l=CPU.BC.B.h;break; //4:4 284 | case LD_A_B: CPU.AF.B.h=CPU.BC.B.h;break; //4:4 285 | case LD_xHL_B: WrZ80(CPU.HL.W,CPU.BC.B.h);break; //7:43 286 | 287 | case LD_B_C: CPU.BC.B.h=CPU.BC.B.l;break; //4:4 288 | case LD_C_C: CPU.BC.B.l=CPU.BC.B.l;break; //4:4 289 | case LD_D_C: CPU.DE.B.h=CPU.BC.B.l;break; //4:4 290 | case LD_E_C: CPU.DE.B.l=CPU.BC.B.l;break; //4:4 291 | case LD_H_C: CPU.HL.B.h=CPU.BC.B.l;break; //4:4 292 | case LD_L_C: CPU.HL.B.l=CPU.BC.B.l;break; //4:4 293 | case LD_A_C: CPU.AF.B.h=CPU.BC.B.l;break; //4:4 294 | case LD_xHL_C: WrZ80(CPU.HL.W,CPU.BC.B.l);break; //7:43 295 | 296 | case LD_B_D: CPU.BC.B.h=CPU.DE.B.h;break; //4:4 297 | case LD_C_D: CPU.BC.B.l=CPU.DE.B.h;break; //4:4 298 | case LD_D_D: CPU.DE.B.h=CPU.DE.B.h;break; //4:4 299 | case LD_E_D: CPU.DE.B.l=CPU.DE.B.h;break; //4:4 300 | case LD_H_D: CPU.HL.B.h=CPU.DE.B.h;break; //4:4 301 | case LD_L_D: CPU.HL.B.l=CPU.DE.B.h;break; //4:4 302 | case LD_A_D: CPU.AF.B.h=CPU.DE.B.h;break; //4:4 303 | case LD_xHL_D: WrZ80(CPU.HL.W,CPU.DE.B.h);break; //7:43 304 | 305 | case LD_B_E: CPU.BC.B.h=CPU.DE.B.l;break; //4:4 306 | case LD_C_E: CPU.BC.B.l=CPU.DE.B.l;break; //4:4 307 | case LD_D_E: CPU.DE.B.h=CPU.DE.B.l;break; //4:4 308 | case LD_E_E: CPU.DE.B.l=CPU.DE.B.l;break; //4:4 309 | case LD_H_E: CPU.HL.B.h=CPU.DE.B.l;break; //4:4 310 | case LD_L_E: CPU.HL.B.l=CPU.DE.B.l;break; //4:4 311 | case LD_A_E: CPU.AF.B.h=CPU.DE.B.l;break; //4:4 312 | case LD_xHL_E: WrZ80(CPU.HL.W,CPU.DE.B.l);break; //7:43 313 | 314 | case LD_B_H: CPU.BC.B.h=CPU.HL.B.h;break; //4:4 315 | case LD_C_H: CPU.BC.B.l=CPU.HL.B.h;break; //4:4 316 | case LD_D_H: CPU.DE.B.h=CPU.HL.B.h;break; //4:4 317 | case LD_E_H: CPU.DE.B.l=CPU.HL.B.h;break; //4:4 318 | case LD_H_H: CPU.HL.B.h=CPU.HL.B.h;break; //4:4 319 | case LD_L_H: CPU.HL.B.l=CPU.HL.B.h;break; //4:4 320 | case LD_A_H: CPU.AF.B.h=CPU.HL.B.h;break; //4:4 321 | case LD_xHL_H: WrZ80(CPU.HL.W,CPU.HL.B.h);break; //7:43 322 | 323 | case LD_B_L: CPU.BC.B.h=CPU.HL.B.l;break; //4:4 324 | case LD_C_L: CPU.BC.B.l=CPU.HL.B.l;break; //4:4 325 | case LD_D_L: CPU.DE.B.h=CPU.HL.B.l;break; //4:4 326 | case LD_E_L: CPU.DE.B.l=CPU.HL.B.l;break; //4:4 327 | case LD_H_L: CPU.HL.B.h=CPU.HL.B.l;break; //4:4 328 | case LD_L_L: CPU.HL.B.l=CPU.HL.B.l;break; //4:4 329 | case LD_A_L: CPU.AF.B.h=CPU.HL.B.l;break; //4:4 330 | case LD_xHL_L: WrZ80(CPU.HL.W,CPU.HL.B.l);break; //7:43 331 | 332 | case LD_B_A: CPU.BC.B.h=CPU.AF.B.h;break; //4:4 333 | case LD_C_A: CPU.BC.B.l=CPU.AF.B.h;break; //4:4 334 | case LD_D_A: CPU.DE.B.h=CPU.AF.B.h;break; //4:4 335 | case LD_E_A: CPU.DE.B.l=CPU.AF.B.h;break; //4:4 336 | case LD_H_A: CPU.HL.B.h=CPU.AF.B.h;break; //4:4 337 | case LD_L_A: CPU.HL.B.l=CPU.AF.B.h;break; //4:4 338 | case LD_A_A: CPU.AF.B.h=CPU.AF.B.h;break; //4:4 339 | case LD_xHL_A: WrZ80(CPU.HL.W,CPU.AF.B.h);break; //7:43 340 | 341 | case LD_xBC_A: WrZ80(CPU.BC.W,CPU.AF.B.h);break; //7:43 342 | case LD_xDE_A: WrZ80(CPU.DE.W,CPU.AF.B.h);break; //7:43 343 | 344 | case LD_B_xHL: CPU.BC.B.h=RdZ80(CPU.HL.W);break; //7:43 345 | case LD_C_xHL: CPU.BC.B.l=RdZ80(CPU.HL.W);break; //7:43 346 | case LD_D_xHL: CPU.DE.B.h=RdZ80(CPU.HL.W);break; //7:43 347 | case LD_E_xHL: CPU.DE.B.l=RdZ80(CPU.HL.W);break; //7:43 348 | case LD_H_xHL: CPU.HL.B.h=RdZ80(CPU.HL.W);break; //7:43 349 | case LD_L_xHL: CPU.HL.B.l=RdZ80(CPU.HL.W);break; //7:43 350 | case LD_A_xHL: CPU.AF.B.h=RdZ80(CPU.HL.W);break; //7:43 351 | 352 | case LD_B_BYTE: CPU.BC.B.h=RdZ80(CPU.PC.W++);break; //7:43 353 | case LD_C_BYTE: CPU.BC.B.l=RdZ80(CPU.PC.W++);break; //7:43 354 | case LD_D_BYTE: CPU.DE.B.h=RdZ80(CPU.PC.W++);break; //7:43 355 | case LD_E_BYTE: CPU.DE.B.l=RdZ80(CPU.PC.W++);break; //7:43 356 | case LD_H_BYTE: CPU.HL.B.h=RdZ80(CPU.PC.W++);break; //7:43 357 | case LD_L_BYTE: CPU.HL.B.l=RdZ80(CPU.PC.W++);break; //7:43 358 | case LD_A_BYTE: CPU.AF.B.h=RdZ80(CPU.PC.W++);break; //7:43 359 | case LD_xHL_BYTE: WrZ80(CPU.HL.W,RdZ80(CPU.PC.W++));break; //10:433 360 | 361 | case LD_xWORD_HL: //16:43333 362 | J.B.l=RdZ80(CPU.PC.W++); 363 | J.B.h=RdZ80(CPU.PC.W++); 364 | WrZ80(J.W++,CPU.HL.B.l); 365 | WrZ80(J.W,CPU.HL.B.h); 366 | break; 367 | 368 | case LD_HL_xWORD: //16:43333 369 | J.B.l=RdZ80(CPU.PC.W++); 370 | J.B.h=RdZ80(CPU.PC.W++); 371 | CPU.HL.B.l=RdZ80(J.W++); 372 | CPU.HL.B.h=RdZ80(J.W); 373 | break; 374 | 375 | case LD_A_xWORD: //13:4333 376 | J.B.l=RdZ80(CPU.PC.W++); 377 | J.B.h=RdZ80(CPU.PC.W++); 378 | CPU.AF.B.h=RdZ80(J.W); 379 | break; 380 | 381 | case LD_xWORD_A: //13:4333 382 | J.B.l=RdZ80(CPU.PC.W++); 383 | J.B.h=RdZ80(CPU.PC.W++); 384 | WrZ80(J.W,CPU.AF.B.h); 385 | break; 386 | 387 | case EX_HL_xSP: //19:43435 388 | J.B.l=RdZ80(CPU.SP.W);WrZ80(CPU.SP.W++,CPU.HL.B.l);T_INC(1); 389 | J.B.h=RdZ80(CPU.SP.W);WrZ80(CPU.SP.W--,CPU.HL.B.h);T_INC(2); 390 | CPU.HL.W=J.W; 391 | break; 392 | 393 | case DAA: //4:4 394 | J.W=CPU.AF.B.h; 395 | if(CPU.AF.B.l&C_FLAG) J.W|=256; 396 | if(CPU.AF.B.l&H_FLAG) J.W|=512; 397 | if(CPU.AF.B.l&N_FLAG) J.W|=1024; 398 | CPU.AF.W=DAATable[J.W]; 399 | break; 400 | 401 | default: 402 | if(CPU.TrapBadOps) Trap_Bad_Ops("Z80", I, CPU.PC.W-1); 403 | break; 404 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesCB.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SpeccySE Z80 CPU 3 | * 4 | * Note: Most of this file is from the ColEm emulator core by Marat Fayzullin 5 | * but heavily modified for specific NDS use. If you want to use this 6 | * code, you are advised to seek out the much more portable ColEm core 7 | * and contact Marat. 8 | * 9 | ******************************************************************************/ 10 | 11 | /** Z80: portable Z80 emulator *******************************/ 12 | /** **/ 13 | /** CodesCB.h **/ 14 | /** **/ 15 | /** This file contains implementation for the CB table of **/ 16 | /** Z80 commands. It is included from Z80.c. **/ 17 | /** **/ 18 | /** Copyright (C) Marat Fayzullin 1994-2021 **/ 19 | /** You are not allowed to distribute this software **/ 20 | /** commercially. Please, notify me, if you make any **/ 21 | /** changes to this file. **/ 22 | /*************************************************************/ 23 | 24 | case RLC_B: M_RLC(CPU.BC.B.h);break; case RLC_C: M_RLC(CPU.BC.B.l);break; //8:44 25 | case RLC_D: M_RLC(CPU.DE.B.h);break; case RLC_E: M_RLC(CPU.DE.B.l);break; 26 | case RLC_H: M_RLC(CPU.HL.B.h);break; case RLC_L: M_RLC(CPU.HL.B.l);break; 27 | case RLC_A: M_RLC(CPU.AF.B.h);break; 28 | 29 | case RRC_B: M_RRC(CPU.BC.B.h);break; case RRC_C: M_RRC(CPU.BC.B.l);break; //8:44 30 | case RRC_D: M_RRC(CPU.DE.B.h);break; case RRC_E: M_RRC(CPU.DE.B.l);break; 31 | case RRC_H: M_RRC(CPU.HL.B.h);break; case RRC_L: M_RRC(CPU.HL.B.l);break; 32 | case RRC_A: M_RRC(CPU.AF.B.h);break; 33 | 34 | case RL_B: M_RL(CPU.BC.B.h);break; case RL_C: M_RL(CPU.BC.B.l);break; //8:44 35 | case RL_D: M_RL(CPU.DE.B.h);break; case RL_E: M_RL(CPU.DE.B.l);break; 36 | case RL_H: M_RL(CPU.HL.B.h);break; case RL_L: M_RL(CPU.HL.B.l);break; 37 | case RL_A: M_RL(CPU.AF.B.h);break; 38 | 39 | case RR_B: M_RR(CPU.BC.B.h);break; case RR_C: M_RR(CPU.BC.B.l);break; //8:44 40 | case RR_D: M_RR(CPU.DE.B.h);break; case RR_E: M_RR(CPU.DE.B.l);break; 41 | case RR_H: M_RR(CPU.HL.B.h);break; case RR_L: M_RR(CPU.HL.B.l);break; 42 | case RR_A: M_RR(CPU.AF.B.h);break; 43 | 44 | case SLA_B: M_SLA(CPU.BC.B.h);break; case SLA_C: M_SLA(CPU.BC.B.l);break; //8:44 45 | case SLA_D: M_SLA(CPU.DE.B.h);break; case SLA_E: M_SLA(CPU.DE.B.l);break; 46 | case SLA_H: M_SLA(CPU.HL.B.h);break; case SLA_L: M_SLA(CPU.HL.B.l);break; 47 | case SLA_A: M_SLA(CPU.AF.B.h);break; 48 | 49 | case SRA_B: M_SRA(CPU.BC.B.h);break; case SRA_C: M_SRA(CPU.BC.B.l);break; //8:44 50 | case SRA_D: M_SRA(CPU.DE.B.h);break; case SRA_E: M_SRA(CPU.DE.B.l);break; 51 | case SRA_H: M_SRA(CPU.HL.B.h);break; case SRA_L: M_SRA(CPU.HL.B.l);break; 52 | case SRA_A: M_SRA(CPU.AF.B.h);break; 53 | 54 | case SLL_B: M_SLL(CPU.BC.B.h);break; case SLL_C: M_SLL(CPU.BC.B.l);break; //8:44 55 | case SLL_D: M_SLL(CPU.DE.B.h);break; case SLL_E: M_SLL(CPU.DE.B.l);break; 56 | case SLL_H: M_SLL(CPU.HL.B.h);break; case SLL_L: M_SLL(CPU.HL.B.l);break; 57 | case SLL_A: M_SLL(CPU.AF.B.h);break; 58 | 59 | case SRL_B: M_SRL(CPU.BC.B.h);break; case SRL_C: M_SRL(CPU.BC.B.l);break; //8:44 60 | case SRL_D: M_SRL(CPU.DE.B.h);break; case SRL_E: M_SRL(CPU.DE.B.l);break; 61 | case SRL_H: M_SRL(CPU.HL.B.h);break; case SRL_L: M_SRL(CPU.HL.B.l);break; 62 | case SRL_A: M_SRL(CPU.AF.B.h);break; 63 | 64 | case RLC_xHL: I=RdZ80(CPU.HL.W); M_RLC(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 65 | case RRC_xHL: I=RdZ80(CPU.HL.W); M_RRC(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 66 | case RL_xHL: I=RdZ80(CPU.HL.W); M_RL(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 67 | case RR_xHL: I=RdZ80(CPU.HL.W); M_RR(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 68 | case SLA_xHL: I=RdZ80(CPU.HL.W); M_SLA(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 69 | case SRA_xHL: I=RdZ80(CPU.HL.W); M_SRA(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 70 | case SLL_xHL: I=RdZ80(CPU.HL.W); M_SLL(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 71 | case SRL_xHL: I=RdZ80(CPU.HL.W); M_SRL(I); T_INC(1); WrZ80(CPU.HL.W,I);break; //15:4443 72 | 73 | 74 | case BIT0_B: M_BIT(0,CPU.BC.B.h);break; case BIT0_C: M_BIT(0,CPU.BC.B.l);break; //8:44 75 | case BIT0_D: M_BIT(0,CPU.DE.B.h);break; case BIT0_E: M_BIT(0,CPU.DE.B.l);break; 76 | case BIT0_H: M_BIT(0,CPU.HL.B.h);break; case BIT0_L: M_BIT(0,CPU.HL.B.l);break; 77 | case BIT0_A: M_BIT(0,CPU.AF.B.h);break; 78 | 79 | case BIT1_B: M_BIT(1,CPU.BC.B.h);break; case BIT1_C: M_BIT(1,CPU.BC.B.l);break; //8:44 80 | case BIT1_D: M_BIT(1,CPU.DE.B.h);break; case BIT1_E: M_BIT(1,CPU.DE.B.l);break; 81 | case BIT1_H: M_BIT(1,CPU.HL.B.h);break; case BIT1_L: M_BIT(1,CPU.HL.B.l);break; 82 | case BIT1_A: M_BIT(1,CPU.AF.B.h);break; 83 | 84 | case BIT2_B: M_BIT(2,CPU.BC.B.h);break; case BIT2_C: M_BIT(2,CPU.BC.B.l);break; //8:44 85 | case BIT2_D: M_BIT(2,CPU.DE.B.h);break; case BIT2_E: M_BIT(2,CPU.DE.B.l);break; 86 | case BIT2_H: M_BIT(2,CPU.HL.B.h);break; case BIT2_L: M_BIT(2,CPU.HL.B.l);break; 87 | case BIT2_A: M_BIT(2,CPU.AF.B.h);break; 88 | 89 | case BIT3_B: M_BIT(3,CPU.BC.B.h);break; case BIT3_C: M_BIT(3,CPU.BC.B.l);break; //8:44 90 | case BIT3_D: M_BIT(3,CPU.DE.B.h);break; case BIT3_E: M_BIT(3,CPU.DE.B.l);break; 91 | case BIT3_H: M_BIT(3,CPU.HL.B.h);break; case BIT3_L: M_BIT(3,CPU.HL.B.l);break; 92 | case BIT3_A: M_BIT(3,CPU.AF.B.h);break; 93 | 94 | case BIT4_B: M_BIT(4,CPU.BC.B.h);break; case BIT4_C: M_BIT(4,CPU.BC.B.l);break; //8:44 95 | case BIT4_D: M_BIT(4,CPU.DE.B.h);break; case BIT4_E: M_BIT(4,CPU.DE.B.l);break; 96 | case BIT4_H: M_BIT(4,CPU.HL.B.h);break; case BIT4_L: M_BIT(4,CPU.HL.B.l);break; 97 | case BIT4_A: M_BIT(4,CPU.AF.B.h);break; 98 | 99 | case BIT5_B: M_BIT(5,CPU.BC.B.h);break; case BIT5_C: M_BIT(5,CPU.BC.B.l);break; //8:44 100 | case BIT5_D: M_BIT(5,CPU.DE.B.h);break; case BIT5_E: M_BIT(5,CPU.DE.B.l);break; 101 | case BIT5_H: M_BIT(5,CPU.HL.B.h);break; case BIT5_L: M_BIT(5,CPU.HL.B.l);break; 102 | case BIT5_A: M_BIT(5,CPU.AF.B.h);break; 103 | 104 | case BIT6_B: M_BIT(6,CPU.BC.B.h);break; case BIT6_C: M_BIT(6,CPU.BC.B.l);break; //8:44 105 | case BIT6_D: M_BIT(6,CPU.DE.B.h);break; case BIT6_E: M_BIT(6,CPU.DE.B.l);break; 106 | case BIT6_H: M_BIT(6,CPU.HL.B.h);break; case BIT6_L: M_BIT(6,CPU.HL.B.l);break; 107 | case BIT6_A: M_BIT(6,CPU.AF.B.h);break; 108 | 109 | case BIT7_B: M_BIT(7,CPU.BC.B.h);break; case BIT7_C: M_BIT(7,CPU.BC.B.l);break; //8:44 110 | case BIT7_D: M_BIT(7,CPU.DE.B.h);break; case BIT7_E: M_BIT(7,CPU.DE.B.l);break; 111 | case BIT7_H: M_BIT(7,CPU.HL.B.h);break; case BIT7_L: M_BIT(7,CPU.HL.B.l);break; 112 | case BIT7_A: M_BIT(7,CPU.AF.B.h);break; 113 | 114 | case BIT0_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(0,I);break; //12:444 115 | case BIT1_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(1,I);break; //12:444 116 | case BIT2_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(2,I);break; //12:444 117 | case BIT3_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(3,I);break; //12:444 118 | case BIT4_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(4,I);break; //12:444 119 | case BIT5_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(5,I);break; //12:444 120 | case BIT6_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(6,I);break; //12:444 121 | case BIT7_xHL: I=RdZ80(CPU.HL.W); T_INC(1); M_BIT(7,I);break; //12:444 122 | 123 | 124 | case RES0_B: M_RES(0,CPU.BC.B.h);break; case RES0_C: M_RES(0,CPU.BC.B.l);break; //8:44 125 | case RES0_D: M_RES(0,CPU.DE.B.h);break; case RES0_E: M_RES(0,CPU.DE.B.l);break; 126 | case RES0_H: M_RES(0,CPU.HL.B.h);break; case RES0_L: M_RES(0,CPU.HL.B.l);break; 127 | case RES0_A: M_RES(0,CPU.AF.B.h);break; 128 | 129 | case RES1_B: M_RES(1,CPU.BC.B.h);break; case RES1_C: M_RES(1,CPU.BC.B.l);break; //8:44 130 | case RES1_D: M_RES(1,CPU.DE.B.h);break; case RES1_E: M_RES(1,CPU.DE.B.l);break; 131 | case RES1_H: M_RES(1,CPU.HL.B.h);break; case RES1_L: M_RES(1,CPU.HL.B.l);break; 132 | case RES1_A: M_RES(1,CPU.AF.B.h);break; 133 | 134 | case RES2_B: M_RES(2,CPU.BC.B.h);break; case RES2_C: M_RES(2,CPU.BC.B.l);break; //8:44 135 | case RES2_D: M_RES(2,CPU.DE.B.h);break; case RES2_E: M_RES(2,CPU.DE.B.l);break; 136 | case RES2_H: M_RES(2,CPU.HL.B.h);break; case RES2_L: M_RES(2,CPU.HL.B.l);break; 137 | case RES2_A: M_RES(2,CPU.AF.B.h);break; 138 | 139 | case RES3_B: M_RES(3,CPU.BC.B.h);break; case RES3_C: M_RES(3,CPU.BC.B.l);break; //8:44 140 | case RES3_D: M_RES(3,CPU.DE.B.h);break; case RES3_E: M_RES(3,CPU.DE.B.l);break; 141 | case RES3_H: M_RES(3,CPU.HL.B.h);break; case RES3_L: M_RES(3,CPU.HL.B.l);break; 142 | case RES3_A: M_RES(3,CPU.AF.B.h);break; 143 | 144 | case RES4_B: M_RES(4,CPU.BC.B.h);break; case RES4_C: M_RES(4,CPU.BC.B.l);break; //8:44 145 | case RES4_D: M_RES(4,CPU.DE.B.h);break; case RES4_E: M_RES(4,CPU.DE.B.l);break; 146 | case RES4_H: M_RES(4,CPU.HL.B.h);break; case RES4_L: M_RES(4,CPU.HL.B.l);break; 147 | case RES4_A: M_RES(4,CPU.AF.B.h);break; 148 | 149 | case RES5_B: M_RES(5,CPU.BC.B.h);break; case RES5_C: M_RES(5,CPU.BC.B.l);break; //8:44 150 | case RES5_D: M_RES(5,CPU.DE.B.h);break; case RES5_E: M_RES(5,CPU.DE.B.l);break; 151 | case RES5_H: M_RES(5,CPU.HL.B.h);break; case RES5_L: M_RES(5,CPU.HL.B.l);break; 152 | case RES5_A: M_RES(5,CPU.AF.B.h);break; 153 | 154 | case RES6_B: M_RES(6,CPU.BC.B.h);break; case RES6_C: M_RES(6,CPU.BC.B.l);break; //8:44 155 | case RES6_D: M_RES(6,CPU.DE.B.h);break; case RES6_E: M_RES(6,CPU.DE.B.l);break; 156 | case RES6_H: M_RES(6,CPU.HL.B.h);break; case RES6_L: M_RES(6,CPU.HL.B.l);break; 157 | case RES6_A: M_RES(6,CPU.AF.B.h);break; 158 | 159 | case RES7_B: M_RES(7,CPU.BC.B.h);break; case RES7_C: M_RES(7,CPU.BC.B.l);break; //8:44 160 | case RES7_D: M_RES(7,CPU.DE.B.h);break; case RES7_E: M_RES(7,CPU.DE.B.l);break; 161 | case RES7_H: M_RES(7,CPU.HL.B.h);break; case RES7_L: M_RES(7,CPU.HL.B.l);break; 162 | case RES7_A: M_RES(7,CPU.AF.B.h);break; 163 | 164 | case RES0_xHL: I=RdZ80(CPU.HL.W); M_RES(0,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 165 | case RES1_xHL: I=RdZ80(CPU.HL.W); M_RES(1,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 166 | case RES2_xHL: I=RdZ80(CPU.HL.W); M_RES(2,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 167 | case RES3_xHL: I=RdZ80(CPU.HL.W); M_RES(3,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 168 | case RES4_xHL: I=RdZ80(CPU.HL.W); M_RES(4,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 169 | case RES5_xHL: I=RdZ80(CPU.HL.W); M_RES(5,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 170 | case RES6_xHL: I=RdZ80(CPU.HL.W); M_RES(6,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 171 | case RES7_xHL: I=RdZ80(CPU.HL.W); M_RES(7,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 172 | 173 | 174 | case SET0_B: M_SET(0,CPU.BC.B.h);break; case SET0_C: M_SET(0,CPU.BC.B.l);break; //8:44 175 | case SET0_D: M_SET(0,CPU.DE.B.h);break; case SET0_E: M_SET(0,CPU.DE.B.l);break; 176 | case SET0_H: M_SET(0,CPU.HL.B.h);break; case SET0_L: M_SET(0,CPU.HL.B.l);break; 177 | case SET0_A: M_SET(0,CPU.AF.B.h);break; 178 | 179 | case SET1_B: M_SET(1,CPU.BC.B.h);break; case SET1_C: M_SET(1,CPU.BC.B.l);break; //8:44 180 | case SET1_D: M_SET(1,CPU.DE.B.h);break; case SET1_E: M_SET(1,CPU.DE.B.l);break; 181 | case SET1_H: M_SET(1,CPU.HL.B.h);break; case SET1_L: M_SET(1,CPU.HL.B.l);break; 182 | case SET1_A: M_SET(1,CPU.AF.B.h);break; 183 | 184 | case SET2_B: M_SET(2,CPU.BC.B.h);break; case SET2_C: M_SET(2,CPU.BC.B.l);break; //8:44 185 | case SET2_D: M_SET(2,CPU.DE.B.h);break; case SET2_E: M_SET(2,CPU.DE.B.l);break; 186 | case SET2_H: M_SET(2,CPU.HL.B.h);break; case SET2_L: M_SET(2,CPU.HL.B.l);break; 187 | case SET2_A: M_SET(2,CPU.AF.B.h);break; 188 | 189 | case SET3_B: M_SET(3,CPU.BC.B.h);break; case SET3_C: M_SET(3,CPU.BC.B.l);break; //8:44 190 | case SET3_D: M_SET(3,CPU.DE.B.h);break; case SET3_E: M_SET(3,CPU.DE.B.l);break; 191 | case SET3_H: M_SET(3,CPU.HL.B.h);break; case SET3_L: M_SET(3,CPU.HL.B.l);break; 192 | case SET3_A: M_SET(3,CPU.AF.B.h);break; 193 | 194 | case SET4_B: M_SET(4,CPU.BC.B.h);break; case SET4_C: M_SET(4,CPU.BC.B.l);break; //8:44 195 | case SET4_D: M_SET(4,CPU.DE.B.h);break; case SET4_E: M_SET(4,CPU.DE.B.l);break; 196 | case SET4_H: M_SET(4,CPU.HL.B.h);break; case SET4_L: M_SET(4,CPU.HL.B.l);break; 197 | case SET4_A: M_SET(4,CPU.AF.B.h);break; 198 | 199 | case SET5_B: M_SET(5,CPU.BC.B.h);break; case SET5_C: M_SET(5,CPU.BC.B.l);break; //8:44 200 | case SET5_D: M_SET(5,CPU.DE.B.h);break; case SET5_E: M_SET(5,CPU.DE.B.l);break; 201 | case SET5_H: M_SET(5,CPU.HL.B.h);break; case SET5_L: M_SET(5,CPU.HL.B.l);break; 202 | case SET5_A: M_SET(5,CPU.AF.B.h);break; 203 | 204 | case SET6_B: M_SET(6,CPU.BC.B.h);break; case SET6_C: M_SET(6,CPU.BC.B.l);break; //8:44 205 | case SET6_D: M_SET(6,CPU.DE.B.h);break; case SET6_E: M_SET(6,CPU.DE.B.l);break; 206 | case SET6_H: M_SET(6,CPU.HL.B.h);break; case SET6_L: M_SET(6,CPU.HL.B.l);break; 207 | case SET6_A: M_SET(6,CPU.AF.B.h);break; 208 | 209 | case SET7_B: M_SET(7,CPU.BC.B.h);break; case SET7_C: M_SET(7,CPU.BC.B.l);break; //8:44 210 | case SET7_D: M_SET(7,CPU.DE.B.h);break; case SET7_E: M_SET(7,CPU.DE.B.l);break; 211 | case SET7_H: M_SET(7,CPU.HL.B.h);break; case SET7_L: M_SET(7,CPU.HL.B.l);break; 212 | case SET7_A: M_SET(7,CPU.AF.B.h);break; 213 | 214 | case SET0_xHL: I=RdZ80(CPU.HL.W); M_SET(0,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 215 | case SET1_xHL: I=RdZ80(CPU.HL.W); M_SET(1,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 216 | case SET2_xHL: I=RdZ80(CPU.HL.W); M_SET(2,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 217 | case SET3_xHL: I=RdZ80(CPU.HL.W); M_SET(3,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 218 | case SET4_xHL: I=RdZ80(CPU.HL.W); M_SET(4,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 219 | case SET5_xHL: I=RdZ80(CPU.HL.W); M_SET(5,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 220 | case SET6_xHL: I=RdZ80(CPU.HL.W); M_SET(6,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 221 | case SET7_xHL: I=RdZ80(CPU.HL.W); M_SET(7,I); T_INC(1); WrZ80(CPU.HL.W,I);break; // 15:4443 222 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesED.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SpeccySE Z80 CPU 3 | * 4 | * Note: Most of this file is from the ColEm emulator core by Marat Fayzullin 5 | * but heavily modified for specific NDS use. If you want to use this 6 | * code, you are advised to seek out the much more portable ColEm core 7 | * and contact Marat. 8 | * 9 | ******************************************************************************/ 10 | 11 | /** Z80: portable Z80 emulator *******************************/ 12 | /** **/ 13 | /** CodesED.h **/ 14 | /** **/ 15 | /** This file contains implementation for the ED table of **/ 16 | /** Z80 commands. It is included from Z80.c. **/ 17 | /** **/ 18 | /** Copyright (C) Marat Fayzullin 1994-2021 **/ 19 | /** You are not allowed to distribute this software **/ 20 | /** commercially. Please, notify me, if you make any **/ 21 | /** changes to this file. **/ 22 | /*************************************************************/ 23 | 24 | /** This is a special patch for emulating BIOS calls: ********/ 25 | //case DB_FE: PatchZ80(&CPU);break; 26 | /*************************************************************/ 27 | 28 | case ADC_HL_BC: M_ADCW(BC); T_INC(7); break; //15:4443 29 | case ADC_HL_DE: M_ADCW(DE); T_INC(7); break; //15:4443 30 | case ADC_HL_HL: M_ADCW(HL); T_INC(7); break; //15:4443 31 | case ADC_HL_SP: M_ADCW(SP); T_INC(7); break; //15:4443 32 | 33 | case SBC_HL_BC: M_SBCW(BC); T_INC(7); break; //15:4443 34 | case SBC_HL_DE: M_SBCW(DE); T_INC(7); break; //15:4443 35 | case SBC_HL_HL: M_SBCW(HL); T_INC(7); break; //15:4443 36 | case SBC_HL_SP: M_SBCW(SP); T_INC(7); break; //15:4443 37 | 38 | case LD_xWORDe_HL: //20:443333 39 | J.B.l=RdZ80(CPU.PC.W++); 40 | J.B.h=RdZ80(CPU.PC.W++); 41 | WrZ80(J.W++,CPU.HL.B.l); 42 | WrZ80(J.W,CPU.HL.B.h); 43 | break; 44 | 45 | case LD_xWORDe_DE: //20:443333 46 | J.B.l=RdZ80(CPU.PC.W++); 47 | J.B.h=RdZ80(CPU.PC.W++); 48 | WrZ80(J.W++,CPU.DE.B.l); 49 | WrZ80(J.W,CPU.DE.B.h); 50 | break; 51 | 52 | case LD_xWORDe_BC: //20:443333 53 | J.B.l=RdZ80(CPU.PC.W++); 54 | J.B.h=RdZ80(CPU.PC.W++); 55 | WrZ80(J.W++,CPU.BC.B.l); 56 | WrZ80(J.W,CPU.BC.B.h); 57 | break; 58 | 59 | case LD_xWORDe_SP: //20:443333 60 | J.B.l=RdZ80(CPU.PC.W++); 61 | J.B.h=RdZ80(CPU.PC.W++); 62 | WrZ80(J.W++,CPU.SP.B.l); 63 | WrZ80(J.W,CPU.SP.B.h); 64 | break; 65 | 66 | case LD_HL_xWORDe: //20:443333 67 | J.B.l=RdZ80(CPU.PC.W++); 68 | J.B.h=RdZ80(CPU.PC.W++); 69 | CPU.HL.B.l=RdZ80(J.W++); 70 | CPU.HL.B.h=RdZ80(J.W); 71 | break; 72 | 73 | case LD_DE_xWORDe: //20:443333 74 | J.B.l=RdZ80(CPU.PC.W++); 75 | J.B.h=RdZ80(CPU.PC.W++); 76 | CPU.DE.B.l=RdZ80(J.W++); 77 | CPU.DE.B.h=RdZ80(J.W); 78 | break; 79 | 80 | case LD_BC_xWORDe: //20:443333 81 | J.B.l=RdZ80(CPU.PC.W++); 82 | J.B.h=RdZ80(CPU.PC.W++); 83 | CPU.BC.B.l=RdZ80(J.W++); 84 | CPU.BC.B.h=RdZ80(J.W); 85 | break; 86 | 87 | case LD_SP_xWORDe: //20:443333 88 | J.B.l=RdZ80(CPU.PC.W++); 89 | J.B.h=RdZ80(CPU.PC.W++); 90 | CPU.SP.B.l=RdZ80(J.W++); 91 | CPU.SP.B.h=RdZ80(J.W); 92 | break; 93 | 94 | case RRD: //18:44343 95 | I=RdZ80(CPU.HL.W); 96 | J.B.l=(I>>4)|(CPU.AF.B.h<<4); 97 | T_INC(4); 98 | WrZ80(CPU.HL.W,J.B.l); 99 | CPU.AF.B.h=(I&0x0F)|(CPU.AF.B.h&0xF0); 100 | CPU.AF.B.l=PZSTable[CPU.AF.B.h]|(CPU.AF.B.l&C_FLAG); 101 | break; 102 | 103 | case RLD: //18:44343 104 | I=RdZ80(CPU.HL.W); 105 | J.B.l=(I<<4)|(CPU.AF.B.h&0x0F); 106 | T_INC(4); 107 | WrZ80(CPU.HL.W,J.B.l); 108 | CPU.AF.B.h=(I>>4)|(CPU.AF.B.h&0xF0); 109 | CPU.AF.B.l=PZSTable[CPU.AF.B.h]|(CPU.AF.B.l&C_FLAG); 110 | break; 111 | 112 | case LD_A_I: //9:45 113 | CPU.AF.B.h=CPU.I; 114 | CPU.AF.B.l=(CPU.AF.B.l&C_FLAG)|(CPU.IFF&IFF_2? P_FLAG:0)|ZSTable[CPU.AF.B.h]; 115 | T_INC(1); 116 | break; 117 | 118 | case LD_A_R: //9:45 119 | CPU.AF.B.h=(CPU.R&0x7F) | CPU.R_HighBit; // The R is a 7-bit refresh counter with a 'secret' flag at the high bit that a few odd games take advantage of 120 | CPU.AF.B.l=(CPU.AF.B.l&C_FLAG)|(CPU.IFF&IFF_2? P_FLAG:0)|ZSTable[CPU.AF.B.h]; 121 | T_INC(1); 122 | break; 123 | 124 | case LD_I_A: CPU.I=CPU.AF.B.h; T_INC(1); break; // 9:45 125 | case LD_R_A: CPU.R=CPU.AF.B.h;CPU.R_HighBit = (CPU.R & 0x80); T_INC(1); break; // 9:45 126 | 127 | case IM_0: CPU.IFF&=~(IFF_IM1|IFF_IM2);break; //8:44 128 | case IM_1: CPU.IFF=(CPU.IFF&~IFF_IM2)|IFF_IM1;break; //8:44 129 | case IM_2: CPU.IFF=(CPU.IFF&~IFF_IM1)|IFF_IM2;break; //8:44 130 | 131 | case RETI: 132 | case RETN: if(CPU.IFF&IFF_2) CPU.IFF|=IFF_1; else CPU.IFF&=~IFF_1; //8:44 133 | M_RET;break; 134 | 135 | case NEG: I=CPU.AF.B.h;CPU.AF.B.h=0;M_SUB(I);break; //8:44 136 | 137 | case IN_B_xC: M_IN(CPU.BC.B.h);break; //12:444 138 | case IN_C_xC: M_IN(CPU.BC.B.l);break; //12:444 139 | case IN_D_xC: M_IN(CPU.DE.B.h);break; //12:444 140 | case IN_E_xC: M_IN(CPU.DE.B.l);break; //12:444 141 | case IN_H_xC: M_IN(CPU.HL.B.h);break; //12:444 142 | case IN_L_xC: M_IN(CPU.HL.B.l);break; //12:444 143 | case IN_A_xC: M_IN(CPU.AF.B.h);break; //12:444 144 | case IN_F_xC: M_IN(J.B.l);break; //12:444 145 | 146 | case OUT_xC_B: OutZ80(CPU.BC.W,CPU.BC.B.h);break; //12:444 147 | case OUT_xC_C: OutZ80(CPU.BC.W,CPU.BC.B.l);break; //12:444 148 | case OUT_xC_D: OutZ80(CPU.BC.W,CPU.DE.B.h);break; //12:444 149 | case OUT_xC_E: OutZ80(CPU.BC.W,CPU.DE.B.l);break; //12:444 150 | case OUT_xC_H: OutZ80(CPU.BC.W,CPU.HL.B.h);break; //12:444 151 | case OUT_xC_L: OutZ80(CPU.BC.W,CPU.HL.B.l);break; //12:444 152 | case OUT_xC_A: OutZ80(CPU.BC.W,CPU.AF.B.h);break; //12:444 153 | case OUT_xC_F: OutZ80(CPU.BC.W,0);break; //12:444 154 | 155 | case INI: //16:4543 156 | T_INC(1); 157 | I = InZ80(CPU.BC.W); 158 | WrZ80(CPU.HL.W++,I); 159 | --CPU.BC.B.h; 160 | CPU.AF.B.l=(I&0x80 ? N_FLAG:0)|(CPU.BC.B.h? 0:Z_FLAG); 161 | break; 162 | 163 | case INIR: //21:45435, 16:4543 164 | T_INC(1); 165 | I = InZ80(CPU.BC.W); 166 | WrZ80(CPU.HL.W++,I); 167 | if(--CPU.BC.B.h) { CPU.AF.B.l=N_FLAG; CPU.PC.W-=2; T_INC(5); } // N_FLAG is not correct here but will be corrected when loop exits below. Nothing relies on the intermediate value. 168 | else { CPU.AF.B.l=Z_FLAG|(I&0x80 ? N_FLAG:0); J_ADJ;} 169 | break; 170 | 171 | case IND: //16:4543 172 | T_INC(1); 173 | I = InZ80(CPU.BC.W); 174 | WrZ80(CPU.HL.W--,I); 175 | --CPU.BC.B.h; 176 | CPU.AF.B.l=(I&0x80 ? N_FLAG:0)|(CPU.BC.B.h? 0:Z_FLAG); 177 | break; 178 | 179 | case INDR: //21:45435, 16:4543 180 | T_INC(1); 181 | I = InZ80(CPU.BC.W); 182 | WrZ80(CPU.HL.W--,I); 183 | if(!--CPU.BC.B.h) { CPU.AF.B.l=N_FLAG; CPU.PC.W-=2; T_INC(5); } // N_FLAG is not correct here but will be corrected when loop exits below. Nothing relies on the intermediate value. 184 | else { CPU.AF.B.l=Z_FLAG|(I&0x80 ? N_FLAG:0); J_ADJ;} 185 | break; 186 | 187 | case OUTI: //16:4534 188 | T_INC(1); 189 | --CPU.BC.B.h; 190 | I=RdZ80(CPU.HL.W++); 191 | OutZ80(CPU.BC.W,I); 192 | CPU.AF.B.l = (CPU.AF.B.l & S_FLAG) | (I&0x80 ? N_FLAG:0) | (CPU.BC.B.h ? 0 : Z_FLAG) | (CPU.HL.B.l + I > 255 ? (C_FLAG | H_FLAG) : 0); 193 | break; 194 | 195 | case OTIR: // 21:45345, 16:4534 196 | T_INC(1); 197 | --CPU.BC.B.h; 198 | I=RdZ80(CPU.HL.W++); 199 | OutZ80(CPU.BC.W,I); 200 | if(CPU.BC.B.h) 201 | { 202 | CPU.AF.B.l=N_FLAG|(CPU.HL.B.l+I>255? (C_FLAG|H_FLAG):0); // N_FLAG is not correct here but will be corrected when loop exits below. Nothing relies on the intermediate value. 203 | CPU.PC.W-=2; 204 | T_INC(5); 205 | } 206 | else 207 | { 208 | CPU.AF.B.l=(CPU.AF.B.l & S_FLAG) | Z_FLAG | (I&0x80 ? N_FLAG:0) | (CPU.HL.B.l+I>255? (C_FLAG|H_FLAG):0); 209 | J_ADJ; 210 | } 211 | break; 212 | 213 | case OUTD: //16:4534 214 | --CPU.BC.B.h; 215 | T_INC(1); 216 | I=RdZ80(CPU.HL.W--); 217 | OutZ80(CPU.BC.W,I); 218 | CPU.AF.B.l=(CPU.AF.B.l & S_FLAG) | (I&0x80 ? N_FLAG:0) | (CPU.BC.B.h? 0:Z_FLAG) | (CPU.HL.B.l+I>255? (C_FLAG|H_FLAG):0); 219 | break; 220 | 221 | case OTDR: // 21:45345, 16:4534 222 | --CPU.BC.B.h; 223 | T_INC(1); 224 | I=RdZ80(CPU.HL.W--); 225 | OutZ80(CPU.BC.W,I); 226 | if(CPU.BC.B.h) 227 | { 228 | T_INC(5); 229 | CPU.AF.B.l=N_FLAG|(CPU.HL.B.l+I>255? (C_FLAG|H_FLAG):0); // N_FLAG is not correct here but will be corrected when loop exits below. Nothing relies on the intermediate value. 230 | CPU.PC.W-=2; 231 | } 232 | else 233 | { 234 | CPU.AF.B.l=(CPU.AF.B.l & S_FLAG) | Z_FLAG | (I&0x80 ? N_FLAG:0) | (CPU.HL.B.l+I>255? (C_FLAG|H_FLAG):0); 235 | J_ADJ; 236 | } 237 | break; 238 | 239 | case LDI: // 16:4435 240 | WrZ80(CPU.DE.W++,RdZ80(CPU.HL.W++)); 241 | --CPU.BC.W; 242 | CPU.AF.B.l=(CPU.AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(CPU.BC.W? P_FLAG:0); 243 | T_INC(2); 244 | break; 245 | 246 | case LDIR: // 21:44355, 16:4435 247 | WrZ80(CPU.DE.W++,RdZ80(CPU.HL.W++)); 248 | if(--CPU.BC.W) 249 | { 250 | CPU.AF.B.l=(CPU.AF.B.l&~(H_FLAG|P_FLAG))|N_FLAG; 251 | CPU.PC.W-=2; 252 | T_INC(7); 253 | } 254 | else 255 | { 256 | CPU.AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); 257 | J_ADJ; 258 | T_INC(2); 259 | } 260 | break; 261 | 262 | case LDD: //16:4435 263 | WrZ80(CPU.DE.W--,RdZ80(CPU.HL.W--)); 264 | --CPU.BC.W; 265 | CPU.AF.B.l=(CPU.AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(CPU.BC.W? P_FLAG:0); 266 | T_INC(2); 267 | break; 268 | 269 | case LDDR: //21:44355, 16:4435 270 | WrZ80(CPU.DE.W--,RdZ80(CPU.HL.W--)); 271 | CPU.AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); 272 | if(--CPU.BC.W) 273 | { 274 | CPU.AF.B.l=(CPU.AF.B.l&~(H_FLAG|P_FLAG))|N_FLAG; 275 | CPU.PC.W-=2; 276 | T_INC(7); 277 | } 278 | else 279 | { 280 | CPU.AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); 281 | J_ADJ; 282 | T_INC(2); 283 | } 284 | break; 285 | 286 | case CPI: // 16:4435 287 | I=RdZ80(CPU.HL.W++); 288 | J.B.l=CPU.AF.B.h-I; 289 | --CPU.BC.W; 290 | CPU.AF.B.l = 291 | N_FLAG|(CPU.AF.B.l&C_FLAG)|ZSTable[J.B.l]| 292 | ((CPU.AF.B.h^I^J.B.l)&H_FLAG)|(CPU.BC.W? P_FLAG:0); 293 | T_INC(5); 294 | break; 295 | 296 | case CPIR: //21:44355, 16:4435 297 | I=RdZ80(CPU.HL.W++); 298 | J.B.l=CPU.AF.B.h-I; 299 | if(--CPU.BC.W&&J.B.l) { T_INC(10); CPU.PC.W-=2; } else { T_INC(5); J_ADJ;} 300 | CPU.AF.B.l = 301 | N_FLAG|(CPU.AF.B.l&C_FLAG)|ZSTable[J.B.l]| 302 | ((CPU.AF.B.h^I^J.B.l)&H_FLAG)|(CPU.BC.W? P_FLAG:0); 303 | break; 304 | 305 | case CPD: // 16:4435 306 | I=RdZ80(CPU.HL.W--); 307 | J.B.l=CPU.AF.B.h-I; 308 | --CPU.BC.W; 309 | T_INC(5); 310 | CPU.AF.B.l = 311 | N_FLAG|(CPU.AF.B.l&C_FLAG)|ZSTable[J.B.l]| 312 | ((CPU.AF.B.h^I^J.B.l)&H_FLAG)|(CPU.BC.W? P_FLAG:0); 313 | break; 314 | 315 | case CPDR: // 21:44355, 16:4435 316 | I=RdZ80(CPU.HL.W--); 317 | J.B.l=CPU.AF.B.h-I; 318 | if(--CPU.BC.W&&J.B.l) { T_INC(10); CPU.PC.W-=2; } else { T_INC(5); J_ADJ;} 319 | CPU.AF.B.l = 320 | N_FLAG|(CPU.AF.B.l&C_FLAG)|ZSTable[J.B.l]| 321 | ((CPU.AF.B.h^I^J.B.l)&H_FLAG)|(CPU.BC.W? P_FLAG:0); 322 | break; 323 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesXCB.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SpeccySE Z80 CPU 3 | * 4 | * Note: Most of this file is from the ColEm emulator core by Marat Fayzullin 5 | * but heavily modified for specific NDS use. If you want to use this 6 | * code, you are advised to seek out the much more portable ColEm core 7 | * and contact Marat. 8 | * 9 | ******************************************************************************/ 10 | 11 | /** Z80: portable Z80 emulator *******************************/ 12 | /** **/ 13 | /** CodesXCB.h **/ 14 | /** **/ 15 | /** This file contains implementation for FD/DD-CB tables **/ 16 | /** of Z80 commands. It is included from Z80.c. **/ 17 | /** **/ 18 | /** Copyright (C) Marat Fayzullin 1994-2021 **/ 19 | /** You are not allowed to distribute this software **/ 20 | /** commercially. Please, notify me, if you make any **/ 21 | /** changes to this file. **/ 22 | /*************************************************************/ 23 | 24 | case BIT0_B: case BIT0_C: case BIT0_D: case BIT0_E: 25 | case BIT0_H: case BIT0_L: case BIT0_A: 26 | case BIT0_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(0,I);break; // 20:44354 27 | 28 | case BIT1_B: case BIT1_C: case BIT1_D: case BIT1_E: 29 | case BIT1_H: case BIT1_L: case BIT1_A: 30 | case BIT1_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(1,I);break; // 20:44354 31 | 32 | case BIT2_B: case BIT2_C: case BIT2_D: case BIT2_E: 33 | case BIT2_H: case BIT2_L: case BIT2_A: 34 | case BIT2_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(2,I);break; // 20:44354 35 | 36 | case BIT3_B: case BIT3_C: case BIT3_D: case BIT3_E: 37 | case BIT3_H: case BIT3_L: case BIT3_A: 38 | case BIT3_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(3,I);break; // 20:44354 39 | 40 | case BIT4_B: case BIT4_C: case BIT4_D: case BIT4_E: 41 | case BIT4_H: case BIT4_L: case BIT4_A: 42 | case BIT4_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(4,I);break; // 20:44354 43 | 44 | case BIT5_B: case BIT5_C: case BIT5_D: case BIT5_E: 45 | case BIT5_H: case BIT5_L: case BIT5_A: 46 | case BIT5_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(5,I);break; // 20:44354 47 | 48 | case BIT6_B: case BIT6_C: case BIT6_D: case BIT6_E: 49 | case BIT6_H: case BIT6_L: case BIT6_A: 50 | case BIT6_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(6,I);break; // 20:44354 51 | 52 | case BIT7_B: case BIT7_C: case BIT7_D: case BIT7_E: 53 | case BIT7_H: case BIT7_L: case BIT7_A: 54 | case BIT7_xHL: T_INC(1); I=RdZ80(J.W); T_INC(1); M_BIT(7,I);break; // 20:44354 55 | 56 | case RLC_xHL: T_INC(1); I=RdZ80(J.W); M_RLC(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 57 | case RRC_xHL: T_INC(1); I=RdZ80(J.W); M_RRC(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 58 | case RL_xHL: T_INC(1); I=RdZ80(J.W); M_RL(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 59 | case RR_xHL: T_INC(1); I=RdZ80(J.W); M_RR(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 60 | case SLA_xHL: T_INC(1); I=RdZ80(J.W); M_SLA(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 61 | case SRA_xHL: T_INC(1); I=RdZ80(J.W); M_SRA(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 62 | case SLL_xHL: T_INC(1); I=RdZ80(J.W); M_SLL(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 63 | case SRL_xHL: T_INC(1); I=RdZ80(J.W); M_SRL(I); T_INC(1); WrZ80(J.W,I);break; //23:443543 64 | 65 | case RES0_xHL: T_INC(1); I=RdZ80(J.W); M_RES(0,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 66 | case RES1_xHL: T_INC(1); I=RdZ80(J.W); M_RES(1,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 67 | case RES2_xHL: T_INC(1); I=RdZ80(J.W); M_RES(2,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 68 | case RES3_xHL: T_INC(1); I=RdZ80(J.W); M_RES(3,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 69 | case RES4_xHL: T_INC(1); I=RdZ80(J.W); M_RES(4,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 70 | case RES5_xHL: T_INC(1); I=RdZ80(J.W); M_RES(5,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 71 | case RES6_xHL: T_INC(1); I=RdZ80(J.W); M_RES(6,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 72 | case RES7_xHL: T_INC(1); I=RdZ80(J.W); M_RES(7,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 73 | 74 | case SET0_xHL: T_INC(1); I=RdZ80(J.W); M_SET(0,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 75 | case SET1_xHL: T_INC(1); I=RdZ80(J.W); M_SET(1,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 76 | case SET2_xHL: T_INC(1); I=RdZ80(J.W); M_SET(2,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 77 | case SET3_xHL: T_INC(1); I=RdZ80(J.W); M_SET(3,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 78 | case SET4_xHL: T_INC(1); I=RdZ80(J.W); M_SET(4,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 79 | case SET5_xHL: T_INC(1); I=RdZ80(J.W); M_SET(5,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 80 | case SET6_xHL: T_INC(1); I=RdZ80(J.W); M_SET(6,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 81 | case SET7_xHL: T_INC(1); I=RdZ80(J.W); M_SET(7,I); T_INC(1); WrZ80(J.W,I);break; //23:443543 82 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesXX.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SpeccySE Z80 CPU 3 | * 4 | * Note: Most of this file is from the ColEm emulator core by Marat Fayzullin 5 | * but heavily modified for specific NDS use. If you want to use this 6 | * code, you are advised to seek out the much more portable ColEm core 7 | * and contact Marat. 8 | * 9 | ******************************************************************************/ 10 | 11 | /** Z80: portable Z80 emulator *******************************/ 12 | /** **/ 13 | /** CodesXX.h **/ 14 | /** **/ 15 | /** This file contains implementation for FD/DD tables of **/ 16 | /** Z80 commands. It is included from Z80.c. **/ 17 | /** **/ 18 | /** Copyright (C) Marat Fayzullin 1994-2021 **/ 19 | /** You are not allowed to distribute this software **/ 20 | /** commercially. Please, notify me, if you make any **/ 21 | /** changes to this file. **/ 22 | /*************************************************************/ 23 | 24 | case ADD_B: M_ADD(CPU.BC.B.h);break; 25 | case ADD_C: M_ADD(CPU.BC.B.l);break; 26 | case ADD_D: M_ADD(CPU.DE.B.h);break; 27 | case ADD_E: M_ADD(CPU.DE.B.l);break; 28 | case ADD_H: M_ADD(CPU.XX.B.h);break; 29 | case ADD_L: M_ADD(CPU.XX.B.l);break; 30 | case ADD_A: M_ADD(CPU.AF.B.h);break; 31 | case ADD_BYTE: I=RdZ80(CPU.PC.W++);M_ADD(I);break; 32 | 33 | case SUB_B: M_SUB(CPU.BC.B.h);break; 34 | case SUB_C: M_SUB(CPU.BC.B.l);break; 35 | case SUB_D: M_SUB(CPU.DE.B.h);break; 36 | case SUB_E: M_SUB(CPU.DE.B.l);break; 37 | case SUB_H: M_SUB(CPU.XX.B.h);break; 38 | case SUB_L: M_SUB(CPU.XX.B.l);break; 39 | case SUB_A: CPU.AF.B.h=0;CPU.AF.B.l=N_FLAG|Z_FLAG;break; 40 | case SUB_BYTE: I=RdZ80(CPU.PC.W++);M_SUB(I);break; 41 | 42 | case AND_B: M_AND(CPU.BC.B.h);break; 43 | case AND_C: M_AND(CPU.BC.B.l);break; 44 | case AND_D: M_AND(CPU.DE.B.h);break; 45 | case AND_E: M_AND(CPU.DE.B.l);break; 46 | case AND_H: M_AND(CPU.XX.B.h);break; 47 | case AND_L: M_AND(CPU.XX.B.l);break; 48 | case AND_A: M_AND(CPU.AF.B.h);break; 49 | case AND_BYTE: I=RdZ80(CPU.PC.W++);M_AND(I);break; 50 | 51 | case OR_B: M_OR(CPU.BC.B.h);break; 52 | case OR_C: M_OR(CPU.BC.B.l);break; 53 | case OR_D: M_OR(CPU.DE.B.h);break; 54 | case OR_E: M_OR(CPU.DE.B.l);break; 55 | case OR_H: M_OR(CPU.XX.B.h);break; 56 | case OR_L: M_OR(CPU.XX.B.l);break; 57 | case OR_A: M_OR(CPU.AF.B.h);break; 58 | case OR_BYTE: I=RdZ80(CPU.PC.W++);M_OR(I);break; 59 | 60 | case ADC_B: M_ADC(CPU.BC.B.h);break; 61 | case ADC_C: M_ADC(CPU.BC.B.l);break; 62 | case ADC_D: M_ADC(CPU.DE.B.h);break; 63 | case ADC_E: M_ADC(CPU.DE.B.l);break; 64 | case ADC_H: M_ADC(CPU.XX.B.h);break; 65 | case ADC_L: M_ADC(CPU.XX.B.l);break; 66 | case ADC_A: M_ADC(CPU.AF.B.h);break; 67 | case ADC_BYTE: I=RdZ80(CPU.PC.W++);M_ADC(I);break; 68 | 69 | case SBC_B: M_SBC(CPU.BC.B.h);break; 70 | case SBC_C: M_SBC(CPU.BC.B.l);break; 71 | case SBC_D: M_SBC(CPU.DE.B.h);break; 72 | case SBC_E: M_SBC(CPU.DE.B.l);break; 73 | case SBC_H: M_SBC(CPU.XX.B.h);break; 74 | case SBC_L: M_SBC(CPU.XX.B.l);break; 75 | case SBC_A: M_SBC(CPU.AF.B.h);break; 76 | case SBC_BYTE: I=RdZ80(CPU.PC.W++);M_SBC(I);break; 77 | 78 | case XOR_B: M_XOR(CPU.BC.B.h);break; 79 | case XOR_C: M_XOR(CPU.BC.B.l);break; 80 | case XOR_D: M_XOR(CPU.DE.B.h);break; 81 | case XOR_E: M_XOR(CPU.DE.B.l);break; 82 | case XOR_H: M_XOR(CPU.XX.B.h);break; 83 | case XOR_L: M_XOR(CPU.XX.B.l);break; 84 | case XOR_A: CPU.AF.B.h=0;CPU.AF.B.l=P_FLAG|Z_FLAG;break; 85 | case XOR_BYTE: I=RdZ80(CPU.PC.W++);M_XOR(I);break; 86 | 87 | case CP_B: M_CP(CPU.BC.B.h);break; 88 | case CP_C: M_CP(CPU.BC.B.l);break; 89 | case CP_D: M_CP(CPU.DE.B.h);break; 90 | case CP_E: M_CP(CPU.DE.B.l);break; 91 | case CP_H: M_CP(CPU.XX.B.h);break; 92 | case CP_L: M_CP(CPU.XX.B.l);break; 93 | case CP_A: CPU.AF.B.l=N_FLAG|Z_FLAG;break; 94 | case CP_BYTE: I=RdZ80(CPU.PC.W++);M_CP(I);break; 95 | 96 | case ADD_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_ADD(I);break; //19:44353 97 | case SUB_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_SUB(I);break; //19:44353 98 | case AND_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_AND(I);break; //19:44353 99 | case OR_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_OR(I); break; //19:44353 100 | case ADC_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_ADC(I);break; //19:44353 101 | case SBC_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_SBC(I);break; //19:44353 102 | case XOR_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_XOR(I);break; //19:44353 103 | case CP_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); I=RdZ80(CPU.XX.W+(offset)K); M_CP(I); break; //19:44353 104 | 105 | case LD_BC_WORD: M_LDWORD(BC);break; 106 | case LD_DE_WORD: M_LDWORD(DE);break; 107 | case LD_HL_WORD: M_LDWORD(XX);break; 108 | case LD_SP_WORD: M_LDWORD(SP);break; 109 | 110 | case LD_PC_HL: CPU.PC.W=CPU.XX.W;JumpZ80(CPU.PC.W);break; 111 | case LD_SP_HL: CPU.SP.W=CPU.XX.W;break; 112 | case LD_A_xBC: CPU.AF.B.h=RdZ80(CPU.BC.W);break; 113 | case LD_A_xDE: CPU.AF.B.h=RdZ80(CPU.DE.W);break; 114 | 115 | case ADD_HL_BC: M_ADDW(XX,BC);T_INC(7);break; //15:4443 116 | case ADD_HL_DE: M_ADDW(XX,DE);T_INC(7);break; //15:4443 117 | case ADD_HL_HL: M_ADDW(XX,XX);T_INC(7);break; //15:4443 118 | case ADD_HL_SP: M_ADDW(XX,SP);T_INC(7);break; //15:4443 119 | 120 | case DEC_BC: CPU.BC.W--;T_INC(2);break; 121 | case DEC_DE: CPU.DE.W--;T_INC(2);break; 122 | case DEC_HL: CPU.XX.W--;T_INC(2);break; 123 | case DEC_SP: CPU.SP.W--;T_INC(2);break; 124 | 125 | case INC_BC: CPU.BC.W++;T_INC(2);break; 126 | case INC_DE: CPU.DE.W++;T_INC(2);break; 127 | case INC_HL: CPU.XX.W++;T_INC(2);break; 128 | case INC_SP: CPU.SP.W++;T_INC(2);break; 129 | 130 | case DEC_B: M_DEC(CPU.BC.B.h);break; 131 | case DEC_C: M_DEC(CPU.BC.B.l);break; 132 | case DEC_D: M_DEC(CPU.DE.B.h);break; 133 | case DEC_E: M_DEC(CPU.DE.B.l);break; 134 | case DEC_H: M_DEC(CPU.XX.B.h);break; 135 | case DEC_L: M_DEC(CPU.XX.B.l);break; 136 | case DEC_A: M_DEC(CPU.AF.B.h);break; 137 | case DEC_xHL: K=RdZ80(CPU.PC.W++); T_INC(2); I=RdZ80(CPU.XX.W+(offset)K); //23:443543 138 | M_DEC(I); T_INC(1); 139 | WrZ80(CPU.XX.W+(offset)K,I); 140 | break; 141 | 142 | case INC_B: M_INC(CPU.BC.B.h);break; 143 | case INC_C: M_INC(CPU.BC.B.l);break; 144 | case INC_D: M_INC(CPU.DE.B.h);break; 145 | case INC_E: M_INC(CPU.DE.B.l);break; 146 | case INC_H: M_INC(CPU.XX.B.h);break; 147 | case INC_L: M_INC(CPU.XX.B.l);break; 148 | case INC_A: M_INC(CPU.AF.B.h);break; 149 | case INC_xHL: K=RdZ80(CPU.PC.W++); T_INC(2); I=RdZ80(CPU.XX.W+(offset)K); //23:443543 150 | M_INC(I); T_INC(1); 151 | WrZ80(CPU.XX.W+(offset)K,I); 152 | break; 153 | case RLCA: 154 | I=(CPU.AF.B.h&0x80? C_FLAG:0); 155 | CPU.AF.B.h=(CPU.AF.B.h<<1)|I; 156 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 157 | break; 158 | case RLA: 159 | I=(CPU.AF.B.h&0x80? C_FLAG:0); 160 | CPU.AF.B.h=(CPU.AF.B.h<<1)|(CPU.AF.B.l&C_FLAG); 161 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 162 | break; 163 | case RRCA: 164 | I=CPU.AF.B.h&0x01; 165 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(I? 0x80:0); 166 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 167 | break; 168 | case RRA: 169 | I=CPU.AF.B.h&0x01; 170 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(CPU.AF.B.l&C_FLAG? 0x80:0); 171 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 172 | break; 173 | 174 | case RST00: M_RST(0x0000);break; 175 | case RST08: M_RST(0x0008);break; 176 | case RST10: M_RST(0x0010);break; 177 | case RST18: M_RST(0x0018);break; 178 | case RST20: M_RST(0x0020);break; 179 | case RST28: M_RST(0x0028);break; 180 | case RST30: M_RST(0x0030);break; 181 | case RST38: M_RST(0x0038);break; 182 | 183 | case PUSH_BC: M_PUSH(BC);break; 184 | case PUSH_DE: M_PUSH(DE);break; 185 | case PUSH_HL: T_INC(1); M_PUSH(XX);break; 186 | case PUSH_AF: M_PUSH(AF);break; 187 | 188 | case POP_BC: M_POP(BC);break; 189 | case POP_DE: M_POP(DE);break; 190 | case POP_HL: M_POP(XX);break; 191 | case POP_AF: M_POP(AF);break; 192 | 193 | case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break; 194 | case CPL: CPU.AF.B.h=~CPU.AF.B.h;S(N_FLAG|H_FLAG);break; 195 | case NOP: break; 196 | case OUTA: I=RdZ80(CPU.PC.W++);OutZ80(I|(CPU.AF.W&0xFF00),CPU.AF.B.h);break; 197 | case INA: I=RdZ80(CPU.PC.W++);CPU.AF.B.h=InZ80(I|(CPU.AF.W&0xFF00));break; 198 | 199 | case EX_DE_HL: J.W=CPU.DE.W;CPU.DE.W=CPU.HL.W;CPU.HL.W=J.W;break; //8:44 200 | case EX_AF_AF: J.W=CPU.AF.W;CPU.AF.W=CPU.AF1.W;CPU.AF1.W=J.W;break; //8:44 201 | 202 | case LD_B_B: CPU.BC.B.h=CPU.BC.B.h;break; //8:44 203 | case LD_C_B: CPU.BC.B.l=CPU.BC.B.h;break; //8:44 204 | case LD_D_B: CPU.DE.B.h=CPU.BC.B.h;break; //8:44 205 | case LD_E_B: CPU.DE.B.l=CPU.BC.B.h;break; //8:44 206 | case LD_H_B: CPU.XX.B.h=CPU.BC.B.h;break; //8:44 207 | case LD_L_B: CPU.XX.B.l=CPU.BC.B.h;break; //8:44 208 | case LD_A_B: CPU.AF.B.h=CPU.BC.B.h;break; //8:44 209 | case LD_xHL_B: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++);T_INC(5);WrZ80(J.W,CPU.BC.B.h);break;//19:44353 210 | 211 | case LD_B_C: CPU.BC.B.h=CPU.BC.B.l;break; //8:44 212 | case LD_C_C: CPU.BC.B.l=CPU.BC.B.l;break; //8:44 213 | case LD_D_C: CPU.DE.B.h=CPU.BC.B.l;break; //8:44 214 | case LD_E_C: CPU.DE.B.l=CPU.BC.B.l;break; //8:44 215 | case LD_H_C: CPU.XX.B.h=CPU.BC.B.l;break; //8:44 216 | case LD_L_C: CPU.XX.B.l=CPU.BC.B.l;break; //8:44 217 | case LD_A_C: CPU.AF.B.h=CPU.BC.B.l;break; //8:44 218 | case LD_xHL_C: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++);T_INC(5);WrZ80(J.W,CPU.BC.B.l);break;//19:44353 219 | 220 | case LD_B_D: CPU.BC.B.h=CPU.DE.B.h;break; 221 | case LD_C_D: CPU.BC.B.l=CPU.DE.B.h;break; 222 | case LD_D_D: CPU.DE.B.h=CPU.DE.B.h;break; 223 | case LD_E_D: CPU.DE.B.l=CPU.DE.B.h;break; 224 | case LD_H_D: CPU.XX.B.h=CPU.DE.B.h;break; 225 | case LD_L_D: CPU.XX.B.l=CPU.DE.B.h;break; 226 | case LD_A_D: CPU.AF.B.h=CPU.DE.B.h;break; 227 | case LD_xHL_D: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++);T_INC(5);WrZ80(J.W,CPU.DE.B.h);break;//19:44353 228 | 229 | case LD_B_E: CPU.BC.B.h=CPU.DE.B.l;break; 230 | case LD_C_E: CPU.BC.B.l=CPU.DE.B.l;break; 231 | case LD_D_E: CPU.DE.B.h=CPU.DE.B.l;break; 232 | case LD_E_E: CPU.DE.B.l=CPU.DE.B.l;break; 233 | case LD_H_E: CPU.XX.B.h=CPU.DE.B.l;break; 234 | case LD_L_E: CPU.XX.B.l=CPU.DE.B.l;break; 235 | case LD_A_E: CPU.AF.B.h=CPU.DE.B.l;break; 236 | case LD_xHL_E: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++);T_INC(5);WrZ80(J.W,CPU.DE.B.l);break;//19:44353 237 | 238 | case LD_B_H: CPU.BC.B.h=CPU.XX.B.h;break; 239 | case LD_C_H: CPU.BC.B.l=CPU.XX.B.h;break; 240 | case LD_D_H: CPU.DE.B.h=CPU.XX.B.h;break; 241 | case LD_E_H: CPU.DE.B.l=CPU.XX.B.h;break; 242 | case LD_H_H: CPU.XX.B.h=CPU.XX.B.h;break; 243 | case LD_L_H: CPU.XX.B.l=CPU.XX.B.h;break; 244 | case LD_A_H: CPU.AF.B.h=CPU.XX.B.h;break; 245 | case LD_xHL_H: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++);T_INC(5);WrZ80(J.W,CPU.HL.B.h);break;//19:44353 246 | 247 | case LD_B_L: CPU.BC.B.h=CPU.XX.B.l;break; 248 | case LD_C_L: CPU.BC.B.l=CPU.XX.B.l;break; 249 | case LD_D_L: CPU.DE.B.h=CPU.XX.B.l;break; 250 | case LD_E_L: CPU.DE.B.l=CPU.XX.B.l;break; 251 | case LD_H_L: CPU.XX.B.h=CPU.XX.B.l;break; 252 | case LD_L_L: CPU.XX.B.l=CPU.XX.B.l;break; 253 | case LD_A_L: CPU.AF.B.h=CPU.XX.B.l;break; 254 | case LD_xHL_L: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++);T_INC(5); WrZ80(J.W,CPU.HL.B.l);break;//19:44353 255 | 256 | case LD_B_A: CPU.BC.B.h=CPU.AF.B.h;break; 257 | case LD_C_A: CPU.BC.B.l=CPU.AF.B.h;break; 258 | case LD_D_A: CPU.DE.B.h=CPU.AF.B.h;break; 259 | case LD_E_A: CPU.DE.B.l=CPU.AF.B.h;break; 260 | case LD_H_A: CPU.XX.B.h=CPU.AF.B.h;break; 261 | case LD_L_A: CPU.XX.B.l=CPU.AF.B.h;break; 262 | case LD_A_A: CPU.AF.B.h=CPU.AF.B.h;break; 263 | case LD_xHL_A: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++); T_INC(5); WrZ80(J.W,CPU.AF.B.h);break;//19:44353 264 | 265 | case LD_xBC_A: WrZ80(CPU.BC.W,CPU.AF.B.h);break; 266 | case LD_xDE_A: WrZ80(CPU.DE.W,CPU.AF.B.h);break; 267 | 268 | case LD_B_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); CPU.BC.B.h=RdZ80(CPU.XX.W+(offset)K); break; //19:44353 269 | case LD_C_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); CPU.BC.B.l=RdZ80(CPU.XX.W+(offset)K); break; //19:44353 270 | case LD_D_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); CPU.DE.B.h=RdZ80(CPU.XX.W+(offset)K); break; //19:44353 271 | case LD_E_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); CPU.DE.B.l=RdZ80(CPU.XX.W+(offset)K); break; //19:44353 272 | case LD_H_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); CPU.HL.B.h=RdZ80(CPU.XX.W+(offset)K); break; //19:44353 273 | case LD_L_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); CPU.HL.B.l=RdZ80(CPU.XX.W+(offset)K); break; //19:44353 274 | case LD_A_xHL: K=RdZ80(CPU.PC.W++); T_INC(5); CPU.AF.B.h=RdZ80(CPU.XX.W+(offset)K); break; //19:44353 275 | 276 | case LD_B_BYTE: CPU.BC.B.h=RdZ80(CPU.PC.W++);break; 277 | case LD_C_BYTE: CPU.BC.B.l=RdZ80(CPU.PC.W++);break; 278 | case LD_D_BYTE: CPU.DE.B.h=RdZ80(CPU.PC.W++);break; 279 | case LD_E_BYTE: CPU.DE.B.l=RdZ80(CPU.PC.W++);break; 280 | case LD_H_BYTE: CPU.XX.B.h=RdZ80(CPU.PC.W++);break; 281 | case LD_L_BYTE: CPU.XX.B.l=RdZ80(CPU.PC.W++);break; 282 | case LD_A_BYTE: CPU.AF.B.h=RdZ80(CPU.PC.W++);break; 283 | case LD_xHL_BYTE: J.W=CPU.XX.W+(offset)RdZ80(CPU.PC.W++); T_INC(2); WrZ80(J.W,RdZ80(CPU.PC.W++));break; 284 | 285 | case LD_xWORD_HL: 286 | J.B.l=RdZ80(CPU.PC.W++); 287 | J.B.h=RdZ80(CPU.PC.W++); 288 | WrZ80(J.W++,CPU.XX.B.l); 289 | WrZ80(J.W,CPU.XX.B.h); 290 | break; 291 | 292 | case LD_HL_xWORD: 293 | J.B.l=RdZ80(CPU.PC.W++); 294 | J.B.h=RdZ80(CPU.PC.W++); 295 | CPU.XX.B.l=RdZ80(J.W++); 296 | CPU.XX.B.h=RdZ80(J.W); 297 | break; 298 | 299 | case LD_A_xWORD: 300 | J.B.l=RdZ80(CPU.PC.W++); 301 | J.B.h=RdZ80(CPU.PC.W++); 302 | CPU.AF.B.h=RdZ80(J.W); 303 | break; 304 | 305 | case LD_xWORD_A: 306 | J.B.l=RdZ80(CPU.PC.W++); 307 | J.B.h=RdZ80(CPU.PC.W++); 308 | WrZ80(J.W,CPU.AF.B.h); 309 | break; 310 | 311 | case EX_HL_xSP: //23:443435 312 | J.B.l=RdZ80(CPU.SP.W);WrZ80(CPU.SP.W++,CPU.XX.B.l);T_INC(1); 313 | J.B.h=RdZ80(CPU.SP.W);T_INC(2);WrZ80(CPU.SP.W--,CPU.XX.B.h); 314 | CPU.XX.W=J.W; 315 | break; 316 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/Tables.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SpeccySE Z80 CPU 3 | * 4 | * Note: Most of this file is from the ColEm emulator core by Marat Fayzullin 5 | * but heavily modified for specific NDS use. If you want to use this 6 | * code, you are advised to seek out the much more portable ColEm core 7 | * and contact Marat. 8 | * 9 | ******************************************************************************/ 10 | 11 | /** Z80: portable Z80 emulator *******************************/ 12 | /** **/ 13 | /** Tables.h **/ 14 | /** **/ 15 | /** This file contains tables of used by Z80 emulation to **/ 16 | /** compute SIGN,ZERO, PARITY flags, and decimal correction **/ 17 | /** There are also timing tables for Z80 opcodes. This file **/ 18 | /** is included from Z80.c. **/ 19 | /** **/ 20 | /** Copyright (C) Marat Fayzullin 1994-2021 **/ 21 | /** You are not allowed to distribute this software **/ 22 | /** commercially. Please, notify me, if you make any **/ 23 | /** changes to this file. **/ 24 | /*************************************************************/ 25 | 26 | extern const byte Cycles_NoM1Wait[256]; 27 | extern const byte CyclesCB[256]; 28 | extern const byte CyclesED[256]; 29 | extern const byte CyclesXX[256]; 30 | extern const byte CyclesXXCB[256]; 31 | extern const byte ZSTable[256]; 32 | extern const byte ZSTable_INC[256]; 33 | extern const byte ZSTable_DEC[256]; 34 | extern const byte PZSTable[256]; 35 | extern const byte PZSHTable_BIT[129]; 36 | extern const word DAATable[2048]; 37 | 38 | enum Codes 39 | { 40 | NOP, LD_BC_WORD, LD_xBC_A, INC_BC, INC_B, DEC_B, LD_B_BYTE, RLCA, // 0x00 41 | EX_AF_AF, ADD_HL_BC, LD_A_xBC, DEC_BC, INC_C, DEC_C, LD_C_BYTE, RRCA, // 0x08 42 | DJNZ, LD_DE_WORD, LD_xDE_A, INC_DE, INC_D, DEC_D, LD_D_BYTE, RLA, // 0x10 43 | JR, ADD_HL_DE, LD_A_xDE, DEC_DE, INC_E, DEC_E, LD_E_BYTE, RRA, // 0x18 44 | JR_NZ, LD_HL_WORD, LD_xWORD_HL, INC_HL, INC_H, DEC_H, LD_H_BYTE, DAA, // 0x20 45 | JR_Z, ADD_HL_HL, LD_HL_xWORD, DEC_HL, INC_L, DEC_L, LD_L_BYTE, CPL, // 0x28 46 | JR_NC, LD_SP_WORD, LD_xWORD_A, INC_SP, INC_xHL, DEC_xHL, LD_xHL_BYTE, SCF, // 0x30 47 | JR_C, ADD_HL_SP, LD_A_xWORD, DEC_SP, INC_A, DEC_A, LD_A_BYTE, CCF, // 0x38 48 | LD_B_B, LD_B_C, LD_B_D, LD_B_E, LD_B_H, LD_B_L, LD_B_xHL, LD_B_A, // 0x40 49 | LD_C_B, LD_C_C, LD_C_D, LD_C_E, LD_C_H, LD_C_L, LD_C_xHL, LD_C_A, // 0x48 50 | LD_D_B, LD_D_C, LD_D_D, LD_D_E, LD_D_H, LD_D_L, LD_D_xHL, LD_D_A, // 0x50 51 | LD_E_B, LD_E_C, LD_E_D, LD_E_E, LD_E_H, LD_E_L, LD_E_xHL, LD_E_A, // 0x58 52 | LD_H_B, LD_H_C, LD_H_D, LD_H_E, LD_H_H, LD_H_L, LD_H_xHL, LD_H_A, // 0x60 53 | LD_L_B, LD_L_C, LD_L_D, LD_L_E, LD_L_H, LD_L_L, LD_L_xHL, LD_L_A, // 0x68 54 | LD_xHL_B, LD_xHL_C, LD_xHL_D, LD_xHL_E, LD_xHL_H, LD_xHL_L, HALT, LD_xHL_A, // 0x70 55 | LD_A_B, LD_A_C, LD_A_D, LD_A_E, LD_A_H, LD_A_L, LD_A_xHL, LD_A_A, // 0x78 56 | ADD_B, ADD_C, ADD_D, ADD_E, ADD_H, ADD_L, ADD_xHL, ADD_A, // 0x80 57 | ADC_B, ADC_C, ADC_D, ADC_E, ADC_H, ADC_L, ADC_xHL, ADC_A, // 0x88 58 | SUB_B, SUB_C, SUB_D, SUB_E, SUB_H, SUB_L, SUB_xHL, SUB_A, // 0x90 59 | SBC_B, SBC_C, SBC_D, SBC_E, SBC_H, SBC_L, SBC_xHL, SBC_A, // 0x98 60 | AND_B, AND_C, AND_D, AND_E, AND_H, AND_L, AND_xHL, AND_A, // 0xA0 61 | XOR_B, XOR_C, XOR_D, XOR_E, XOR_H, XOR_L, XOR_xHL, XOR_A, // 0xA8 62 | OR_B, OR_C, OR_D, OR_E, OR_H, OR_L, OR_xHL, OR_A, // 0xB0 63 | CP_B, CP_C, CP_D, CP_E, CP_H, CP_L, CP_xHL, CP_A, // 0xB8 64 | RET_NZ, POP_BC, JP_NZ, JP, CALL_NZ, PUSH_BC, ADD_BYTE, RST00, // 0xC0 65 | RET_Z, RET, JP_Z, PFX_CB, CALL_Z, CALL, ADC_BYTE, RST08, // 0xC8 66 | RET_NC, POP_DE, JP_NC, OUTA, CALL_NC, PUSH_DE, SUB_BYTE, RST10, // 0xD0 67 | RET_C, EXX, JP_C, INA, CALL_C, PFX_DD, SBC_BYTE, RST18, // 0xD8 68 | RET_PO, POP_HL, JP_PO, EX_HL_xSP, CALL_PO, PUSH_HL, AND_BYTE, RST20, // 0xE0 69 | RET_PE, LD_PC_HL, JP_PE, EX_DE_HL, CALL_PE, PFX_ED, XOR_BYTE, RST28, // 0xE8 70 | RET_P, POP_AF, JP_P, DI, CALL_P, PUSH_AF, OR_BYTE, RST30, // 0xF0 71 | RET_M, LD_SP_HL, JP_M, EI, CALL_M, PFX_FD, CP_BYTE, RST38 // 0xF8 72 | }; 73 | 74 | enum CodesCB 75 | { 76 | RLC_B, RLC_C, RLC_D, RLC_E, RLC_H, RLC_L, RLC_xHL, RLC_A, // 0x00 77 | RRC_B, RRC_C, RRC_D, RRC_E, RRC_H, RRC_L, RRC_xHL, RRC_A, // 0x08 78 | RL_B, RL_C, RL_D, RL_E, RL_H, RL_L, RL_xHL, RL_A, // 0x10 79 | RR_B, RR_C, RR_D, RR_E, RR_H, RR_L, RR_xHL, RR_A, // 0x18 80 | SLA_B, SLA_C, SLA_D, SLA_E, SLA_H, SLA_L, SLA_xHL, SLA_A, // 0x20 81 | SRA_B, SRA_C, SRA_D, SRA_E, SRA_H, SRA_L, SRA_xHL, SRA_A, // 0x28 82 | SLL_B, SLL_C, SLL_D, SLL_E, SLL_H, SLL_L, SLL_xHL, SLL_A, // 0x30 83 | SRL_B, SRL_C, SRL_D, SRL_E, SRL_H, SRL_L, SRL_xHL, SRL_A, // 0x38 84 | BIT0_B, BIT0_C, BIT0_D, BIT0_E, BIT0_H, BIT0_L, BIT0_xHL, BIT0_A, // 0x40 85 | BIT1_B, BIT1_C, BIT1_D, BIT1_E, BIT1_H, BIT1_L, BIT1_xHL, BIT1_A, // 0x48 86 | BIT2_B, BIT2_C, BIT2_D, BIT2_E, BIT2_H, BIT2_L, BIT2_xHL, BIT2_A, // 0x50 87 | BIT3_B, BIT3_C, BIT3_D, BIT3_E, BIT3_H, BIT3_L, BIT3_xHL, BIT3_A, // 0x58 88 | BIT4_B, BIT4_C, BIT4_D, BIT4_E, BIT4_H, BIT4_L, BIT4_xHL, BIT4_A, // 0x60 89 | BIT5_B, BIT5_C, BIT5_D, BIT5_E, BIT5_H, BIT5_L, BIT5_xHL, BIT5_A, // 0x68 90 | BIT6_B, BIT6_C, BIT6_D, BIT6_E, BIT6_H, BIT6_L, BIT6_xHL, BIT6_A, // 0x70 91 | BIT7_B, BIT7_C, BIT7_D, BIT7_E, BIT7_H, BIT7_L, BIT7_xHL, BIT7_A, // 0x78 92 | RES0_B, RES0_C, RES0_D, RES0_E, RES0_H, RES0_L, RES0_xHL, RES0_A, // 0x80 93 | RES1_B, RES1_C, RES1_D, RES1_E, RES1_H, RES1_L, RES1_xHL, RES1_A, // 0x88 94 | RES2_B, RES2_C, RES2_D, RES2_E, RES2_H, RES2_L, RES2_xHL, RES2_A, // 0x90 95 | RES3_B, RES3_C, RES3_D, RES3_E, RES3_H, RES3_L, RES3_xHL, RES3_A, // 0x98 96 | RES4_B, RES4_C, RES4_D, RES4_E, RES4_H, RES4_L, RES4_xHL, RES4_A, // 0xA0 97 | RES5_B, RES5_C, RES5_D, RES5_E, RES5_H, RES5_L, RES5_xHL, RES5_A, // 0xA8 98 | RES6_B, RES6_C, RES6_D, RES6_E, RES6_H, RES6_L, RES6_xHL, RES6_A, // 0xB0 99 | RES7_B, RES7_C, RES7_D, RES7_E, RES7_H, RES7_L, RES7_xHL, RES7_A, // 0xB8 100 | SET0_B, SET0_C, SET0_D, SET0_E, SET0_H, SET0_L, SET0_xHL, SET0_A, // 0xC0 101 | SET1_B, SET1_C, SET1_D, SET1_E, SET1_H, SET1_L, SET1_xHL, SET1_A, // 0xC8 102 | SET2_B, SET2_C, SET2_D, SET2_E, SET2_H, SET2_L, SET2_xHL, SET2_A, // 0xD0 103 | SET3_B, SET3_C, SET3_D, SET3_E, SET3_H, SET3_L, SET3_xHL, SET3_A, // 0xD8 104 | SET4_B, SET4_C, SET4_D, SET4_E, SET4_H, SET4_L, SET4_xHL, SET4_A, // 0xE0 105 | SET5_B, SET5_C, SET5_D, SET5_E, SET5_H, SET5_L, SET5_xHL, SET5_A, // 0xE8 106 | SET6_B, SET6_C, SET6_D, SET6_E, SET6_H, SET6_L, SET6_xHL, SET6_A, // 0xF0 107 | SET7_B, SET7_C, SET7_D, SET7_E, SET7_H, SET7_L, SET7_xHL, SET7_A // 0xF8 108 | }; 109 | 110 | enum CodesED 111 | { 112 | DB_00, DB_01, DB_02, DB_03, DB_04, DB_05, DB_06, DB_07, // 0x00 113 | DB_08, DB_09, DB_0A, DB_0B, DB_0C, DB_0D, DB_0E, DB_0F, // 0x08 114 | DB_10, DB_11, DB_12, DB_13, DB_14, DB_15, DB_16, DB_17, // 0x10 115 | DB_18, DB_19, DB_1A, DB_1B, DB_1C, DB_1D, DB_1E, DB_1F, // 0x18 116 | DB_20, DB_21, DB_22, DB_23, DB_24, DB_25, DB_26, DB_27, // 0x20 117 | DB_28, DB_29, DB_2A, DB_2B, DB_2C, DB_2D, DB_2E, DB_2F, // 0x28 118 | DB_30, DB_31, DB_32, DB_33, DB_34, DB_35, DB_36, DB_37, // 0x30 119 | DB_38, DB_39, DB_3A, DB_3B, DB_3C, DB_3D, DB_3E, DB_3F, // 0x38 120 | IN_B_xC, OUT_xC_B, SBC_HL_BC, LD_xWORDe_BC, NEG, RETN, IM_0, LD_I_A, // 0x40 121 | IN_C_xC, OUT_xC_C, ADC_HL_BC, LD_BC_xWORDe, DB_4C, RETI, DB_, LD_R_A, // 0x48 122 | IN_D_xC, OUT_xC_D, SBC_HL_DE, LD_xWORDe_DE, DB_54, DB_55, IM_1, LD_A_I, // 0x50 123 | IN_E_xC, OUT_xC_E, ADC_HL_DE, LD_DE_xWORDe, DB_5C, DB_5D, IM_2, LD_A_R, // 0x58 124 | IN_H_xC, OUT_xC_H, SBC_HL_HL, LD_xWORDe_HL, DB_64, DB_65, DB_66, RRD, // 0x60 125 | IN_L_xC, OUT_xC_L, ADC_HL_HL, LD_HL_xWORDe, DB_6C, DB_6D, DB_6E, RLD, // 0x68 126 | IN_F_xC, OUT_xC_F, SBC_HL_SP, LD_xWORDe_SP, DB_74, DB_75, DB_76, DB_77, // 0x70 127 | IN_A_xC, OUT_xC_A, ADC_HL_SP, LD_SP_xWORDe, DB_7C, DB_7D, DB_7E, DB_7F, // 0x78 128 | DB_80, DB_81, DB_82, DB_83, DB_84, DB_85, DB_86, DB_87, // 0x80 129 | DB_88, DB_89, DB_8A, DB_8B, DB_8C, DB_8D, DB_8E, DB_8F, // 0x88 130 | DB_90, DB_91, DB_92, DB_93, DB_94, DB_95, DB_96, DB_97, // 0x90 131 | DB_98, DB_99, DB_9A, DB_9B, DB_9C, DB_9D, DB_9E, DB_9F, // 0x98 132 | LDI, CPI, INI, OUTI, DB_A4, DB_A5, DB_A6, DB_A7, // 0xA0 133 | LDD, CPD, IND, OUTD, DB_AC, DB_AD, DB_AE, DB_AF, // 0xA8 134 | LDIR, CPIR, INIR, OTIR, DB_B4, DB_B5, DB_B6, DB_B7, // 0xB0 135 | LDDR, CPDR, INDR, OTDR, DB_BC, DB_BD, DB_BE, DB_BF, // 0xB8 136 | DB_C0, DB_C1, DB_C2, DB_C3, DB_C4, DB_C5, DB_C6, DB_C7, // 0xC0 137 | DB_C8, DB_C9, DB_CA, DB_CB, DB_CC, DB_CD, DB_CE, DB_CF, // 0xC8 138 | DB_D0, DB_D1, DB_D2, DB_D3, DB_D4, DB_D5, DB_D6, DB_D7, // 0xD0 139 | DB_D8, DB_D9, DB_DA, DB_DB, DB_DC, DB_DD, DB_DE, DB_DF, // 0xD8 140 | DB_E0, DB_E1, DB_E2, DB_E3, DB_E4, DB_E5, DB_E6, DB_E7, // 0xE0 141 | DB_E8, DB_E9, DB_EA, DB_EB, DB_EC, DB_ED, DB_EE, DB_EF, // 0xE8 142 | DB_F0, DB_F1, DB_F2, DB_F3, DB_F4, DB_F5, DB_F6, DB_F7, // 0xF0 143 | DB_F8, DB_F9, DB_FA, DB_FB, DB_FC, DB_FD, DB_FE, DB_FF // 0xF8 144 | }; 145 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/Z80.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SpeccySE Z80 CPU 3 | * 4 | * Note: Most of this file is from the ColEm emulator core by Marat Fayzullin 5 | * but heavily modified for specific NDS use. If you want to use this 6 | * code, you are advised to seek out the much more portable ColEm core 7 | * and contact Marat. 8 | * 9 | ******************************************************************************/ 10 | 11 | /** Z80: portable Z80 emulator *******************************/ 12 | /** **/ 13 | /** Z80.h **/ 14 | /** **/ 15 | /** This file contains declarations relevant to emulation **/ 16 | /** of Z80 CPU. **/ 17 | /** **/ 18 | /** Copyright (C) Marat Fayzullin 1994-2021 **/ 19 | /** You are not allowed to distribute this software **/ 20 | /** commercially. Please, notify me, if you make any **/ 21 | /** changes to this file. **/ 22 | /*************************************************************/ 23 | #ifndef Z80_H 24 | #define Z80_H 25 | 26 | #ifdef __cplusplus 27 | extern "C" { 28 | #endif 29 | 30 | //#define ZEXALL_TEST /* Uncomment this to run the ZEXALL Z80 instruction test */ 31 | 32 | #define CYCLES_PER_SCANLINE_48 224 33 | #define CYCLES_PER_SCANLINE_128 228 34 | 35 | #define SCANLINES_PER_FRAME_128 311 36 | #define SCANLINES_PER_FRAME_48 312 37 | 38 | #define CONTENTION_START_CYCLE_48 14335 39 | #define CONTENTION_START_CYCLE_128 14361 40 | 41 | /* Compilation options: */ 42 | #define LSB_FIRST /* Compile for low-endian CPU */ 43 | #define EXECZ80 /* Call Z80 each scanline */ 44 | 45 | /* LoopZ80() may return: */ 46 | #define INT_RST00 0x00C7 /* RST 00h */ 47 | #define INT_RST08 0x00CF /* RST 08h */ 48 | #define INT_RST10 0x00D7 /* RST 10h */ 49 | #define INT_RST18 0x00DF /* RST 18h */ 50 | #define INT_RST20 0x00E7 /* RST 20h */ 51 | #define INT_RST28 0x00EF /* RST 28h */ 52 | #define INT_RST30 0x00F7 /* RST 30h */ 53 | #define INT_RST38 0x00FF /* RST 38h */ 54 | #define INT_IRQ INT_RST38 /* Default IRQ opcode is FFh */ 55 | #define INT_NMI 0xFFFD /* Non-maskable interrupt */ 56 | #define INT_NONE 0xFFFF /* No interrupt required */ 57 | #define INT_QUIT 0xFFFE /* Exit the emulation */ 58 | 59 | /* Bits in Z80 F register: */ 60 | #define S_FLAG 0x80 /* 1: Result negative */ 61 | #define Z_FLAG 0x40 /* 1: Result is zero */ 62 | #define H_FLAG 0x10 /* 1: Halfcarry/Halfborrow */ 63 | #define P_FLAG 0x04 /* 1: Result is even */ 64 | #define V_FLAG 0x04 /* 1: Overflow occured */ 65 | #define N_FLAG 0x02 /* 1: Subtraction occured */ 66 | #define C_FLAG 0x01 /* 1: Carry/Borrow occured */ 67 | 68 | /* Bits in IFF flip-flops: */ 69 | #define IFF_1 0x01 /* IFF1 flip-flop */ 70 | #define IFF_IM1 0x02 /* 1: IM1 mode */ 71 | #define IFF_IM2 0x04 /* 1: IM2 mode */ 72 | #define IFF_2 0x08 /* IFF2 flip-flop */ 73 | #define IFF_EI 0x20 /* 1: EI pending */ 74 | #define IFF_HALT 0x80 /* 1: CPU HALTed */ 75 | 76 | /** Simple Datatypes *****************************************/ 77 | /** NOTICE: sizeof(byte)=1 and sizeof(word)=2 **/ 78 | /*************************************************************/ 79 | #ifndef BYTE_TYPE_DEFINED 80 | #define BYTE_TYPE_DEFINED 81 | typedef unsigned char byte; 82 | #endif 83 | #ifndef WORD_TYPE_DEFINED 84 | #define WORD_TYPE_DEFINED 85 | typedef unsigned short word; 86 | #endif 87 | typedef signed char offset; 88 | 89 | // We only support LSB_FIRST for the DS hardware 90 | typedef union 91 | { 92 | struct { byte l,h; } B; 93 | word W; 94 | } pair; 95 | 96 | 97 | typedef struct 98 | { 99 | pair PC, SP; /* Program Counter and Stack Pointer */ 100 | pair AF,BC,DE,HL,IX,IY; /* Main registers */ 101 | pair AF1,BC1,DE1,HL1; /* Shadow registers */ 102 | byte IFF,I; /* Interrupt registers */ 103 | word IRequest; /* Set to address of pending IRQ */ 104 | byte IAutoReset; /* Set to 1 to autom. reset IRequest */ 105 | byte TrapBadOps; /* Set to 1 to warn of illegal opcodes */ 106 | byte Trace; /* Set Trace=1 to start tracing */ 107 | byte R_HighBit; /* Used to preserve the high bit for R */ 108 | u32 R; /* Refresh register - masked on read */ 109 | u32 TStates; /* Total CPU Cycles - reset each frame */ 110 | u32 TStates_IRequest; /* TStates of the last INT Request */ 111 | word EI_Delay; /* Enable Interrupt instruction delay */ 112 | u32 Reserved; /* For future use... */ 113 | } Z80; 114 | 115 | extern u8 accurate_emulation; 116 | 117 | void ExecZ80_Speccy_128(u32 RunToCycles); 118 | void ExecZ80_Speccy_48(u32 RunToCycles); 119 | 120 | /** ResetZ80() ***********************************************/ 121 | /** This function can be used to reset the registers before **/ 122 | /** starting execution with RunZ80(). It sets registers to **/ 123 | /** their initial values. **/ 124 | /*************************************************************/ 125 | void ResetZ80(register Z80 *R); 126 | 127 | /** ExecZ80() ************************************************/ 128 | /** This function will execute given number of Z80 cycles. **/ 129 | /** It will then return the number of cycles left, possibly **/ 130 | /** negative, and current register values in R. **/ 131 | /*************************************************************/ 132 | #ifdef EXECZ80 133 | void ExecZ80_Speccy(u32 RunToCycles); 134 | #endif 135 | 136 | /** IntZ80() *************************************************/ 137 | /** This function will generate interrupt of given vector. **/ 138 | /*************************************************************/ 139 | void IntZ80(register Z80 *R,register word Vector); 140 | 141 | /** InZ80()/OutZ80() *****************************************/ 142 | /** Z80 emulation calls these functions to read/write from **/ 143 | /** I/O ports. There can be 65536 I/O ports, but only first **/ 144 | /** 256 are usually used. **/ 145 | /************************************ TO BE WRITTEN BY USER **/ 146 | void OutZ80(register word Port,register byte Value); 147 | byte InZ80(register word Port); 148 | 149 | /** PatchZ80() ***********************************************/ 150 | /** Z80 emulation calls this function when it encounters a **/ 151 | /** special patch command (ED FE) provided for user needs. **/ 152 | /** For example, it can be called to emulate BIOS calls, **/ 153 | /** such as disk and tape access. Replace it with an empty **/ 154 | /** macro for no patching. **/ 155 | /************************************ TO BE WRITTEN BY USER **/ 156 | void PatchZ80(register Z80 *R); 157 | 158 | /** JumpZ80() ************************************************/ 159 | /** Z80 emulation calls this function when it executes a **/ 160 | /** JP, JR, CALL, RST, or RET. You can use JumpZ80() to **/ 161 | /** trap these opcodes and switch memory layout. **/ 162 | /************************************ TO BE WRITTEN BY USER **/ 163 | #ifndef JUMPZ80 164 | #define JumpZ80(PC) 165 | #else 166 | void JumpZ80(word PC); 167 | #endif 168 | 169 | #ifdef __cplusplus 170 | } 171 | #endif 172 | #endif /* Z80_H */ 173 | -------------------------------------------------------------------------------- /arm9/source/highscore.h: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, it's source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition), 7 | // Alekmaul (original port) and Marat Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. 10 | // ===================================================================================== 11 | 12 | #ifndef __HIGHSCORE_H 13 | #define __HIGHSCORE_H 14 | 15 | #include 16 | 17 | extern void highscore_init(void); 18 | extern void highscore_save(void); 19 | extern void highscore_display(u32 crc); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /arm9/source/pok.c: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, its source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave and Marat 7 | // Fayzullin (Z80 core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "SpeccySE.h" 22 | #include "CRC32.h" 23 | #include "cpu/z80/Z80_interface.h" 24 | #include "SpeccyUtils.h" 25 | #include "printf.h" 26 | 27 | // ----------------------------------------------------------------------------- 28 | // I've seen a few rare POKEs that are massive - e.g. Jet Set Willy has a near 29 | // re-write of a routine to change the jumping and Jet-Pac RX has almost 13K 30 | // worth of patches (to a 16K game!) ... To support these ultra large poke 31 | // possibilities, we allocate a large pool of POKs that give the system up to 32 | // 16K worth of memory pokes. This should be enough for even the biggest POKs. 33 | // ----------------------------------------------------------------------------- 34 | #define MAX_POKES 64 // No more than this numbber of POKEs 35 | #define MAX_POK_MEM (16*1024) // Our big list of POKs can contain up to 16K worth of pokes 36 | 37 | u16 pok_mem[MAX_POK_MEM]; // List of memory areas to poke 38 | u8 pok_val[MAX_POK_MEM]; // List of values to poke into pok_mem[] - 256 is special (means ask user) 39 | u8 pok_bank[MAX_POK_MEM]; // List of memory banks (for 128K Spectrum) in which to poke - usually '8' (no bank) but could be a 128K bank. High bit means ask for poke value 40 | 41 | typedef struct 42 | { 43 | char pok_name[31]; // Poke Name - cut off at 31 chars plus NULL 44 | u8 pok_applied; // 1 if the poke has been applied already 45 | u16 poke_idx_start; // Where is this POK start in our big list? 46 | u16 poke_idx_end; // The last index to POK in our big list? 47 | } Poke_t; 48 | 49 | Poke_t Pokes[MAX_POKES]; // This holds all our POKEs for the current game 50 | 51 | char szLoadFile[256]; 52 | char szLine[256]; 53 | u32 last_file_crc_poke_read; 54 | u16 last_pok_mem_idx; 55 | 56 | inline void WrZ80(word A, byte value) {if (A & 0xC000) MemoryMap[(A)>>14][A] = value;} 57 | 58 | void pok_init() 59 | { 60 | memset(Pokes, 0x00, sizeof(Pokes)); 61 | memset(pok_mem, 0x00, sizeof(pok_mem)); 62 | memset(pok_val, 0x00, sizeof(pok_val)); 63 | memset(pok_bank, 0x00, sizeof(pok_bank)); 64 | last_pok_mem_idx = 0; // Index into our big 16K table of POKs 65 | 66 | last_file_crc_poke_read = 0x00000000; 67 | } 68 | 69 | void pok_apply(u8 sel) 70 | { 71 | Pokes[sel].pok_applied = 1; 72 | for (u16 j=Pokes[sel].poke_idx_start; j 0) 269 | { 270 | sprintf(tmp, "%-31s", Pokes[offset+sel].pok_name); 271 | DSPrint(1,4+sel,0,tmp); 272 | sel--; 273 | sprintf(tmp, "%-31s", Pokes[offset+sel].pok_name); 274 | DSPrint(1,4+sel,2,tmp); 275 | WAITVBL;WAITVBL; 276 | } 277 | else 278 | { 279 | if (offset > 0) 280 | { 281 | offset -= POKES_PER_SCREEN; 282 | screen_max = ((max-offset) < POKES_PER_SCREEN ? (max-offset):POKES_PER_SCREEN); 283 | sel = POKES_PER_SCREEN-1; 284 | for (u8 i=0; i < POKES_PER_SCREEN; i++) 285 | { 286 | if (i < screen_max) 287 | { 288 | sprintf(tmp, "%-31s", Pokes[offset+i].pok_name); 289 | DSPrint(1,4+i,(i==sel) ? 2:0,tmp); 290 | if (Pokes[offset+i].pok_applied) DSPrint(0,4+i,2,"@"); else DSPrint(0,4+i,0," "); 291 | } 292 | else 293 | { 294 | DSPrint(0,4+i,0," "); 295 | DSPrint(0,4+i,0," "); 296 | } 297 | } 298 | WAITVBL;WAITVBL;WAITVBL; 299 | } 300 | } 301 | } 302 | } 303 | } 304 | 305 | while (keysCurrent()) 306 | { 307 | WAITVBL;WAITVBL; 308 | } 309 | 310 | return; 311 | } 312 | -------------------------------------------------------------------------------- /arm9/source/printf.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // \author (c) Marco Paland (info@paland.com) 3 | // 2014-2019, PALANDesign Hannover, Germany 4 | // 5 | // \license The MIT License (MIT) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | // \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on 26 | // embedded systems with a very limited resources. 27 | // Use this instead of bloated standard/newlib printf. 28 | // These routines are thread safe and reentrant. 29 | // 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | #ifndef _PRINTF_H_ 33 | #define _PRINTF_H_ 34 | 35 | #include 36 | #include 37 | 38 | 39 | #ifdef __cplusplus 40 | extern "C" { 41 | #endif 42 | 43 | #define PRINTF_DISABLE_SUPPORT_FLOAT 44 | #define PRINTF_DISABLE_SUPPORT_EXPONENTIAL 45 | #define PRINTF_DISABLE_SUPPORT_LONG_LONG 46 | #define PRINTF_DISABLE_SUPPORT_PTRDIFF_T 47 | 48 | /** 49 | * Output a character to a custom device like UART, used by the printf() function 50 | * This function is declared here only. You have to write your custom implementation somewhere 51 | * \param character Character to output 52 | */ 53 | void _putchar(char character); 54 | 55 | 56 | /** 57 | * Tiny printf implementation 58 | * You have to implement _putchar if you use printf() 59 | * To avoid conflicts with the regular printf() API it is overridden by macro defines 60 | * and internal underscore-appended functions like printf_() are used 61 | * \param format A string that specifies the format of the output 62 | * \return The number of characters that are written into the array, not counting the terminating null character 63 | */ 64 | #define printf printf_ 65 | int printf_(const char* format, ...); 66 | 67 | 68 | /** 69 | * Tiny sprintf implementation 70 | * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! 71 | * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! 72 | * \param format A string that specifies the format of the output 73 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 74 | */ 75 | #define sprintf sprintf_ 76 | int sprintf_(char* buffer, const char* format, ...); 77 | 78 | 79 | /** 80 | * Tiny snprintf/vsnprintf implementation 81 | * \param buffer A pointer to the buffer where to store the formatted string 82 | * \param count The maximum number of characters to store in the buffer, including a terminating null character 83 | * \param format A string that specifies the format of the output 84 | * \param va A value identifying a variable arguments list 85 | * \return The number of characters that COULD have been written into the buffer, not counting the terminating 86 | * null character. A value equal or larger than count indicates truncation. Only when the returned value 87 | * is non-negative and less than count, the string has been completely written. 88 | */ 89 | #define snprintf snprintf_ 90 | #define vsnprintf vsnprintf_ 91 | int snprintf_(char* buffer, size_t count, const char* format, ...); 92 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); 93 | 94 | 95 | /** 96 | * Tiny vprintf implementation 97 | * \param format A string that specifies the format of the output 98 | * \param va A value identifying a variable arguments list 99 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 100 | */ 101 | #define vprintf vprintf_ 102 | int vprintf_(const char* format, va_list va); 103 | 104 | 105 | /** 106 | * printf with output function 107 | * You may use this as dynamic alternative to printf() with its fixed _putchar() output 108 | * \param out An output function which takes one character and an argument pointer 109 | * \param arg An argument pointer for user data passed to output function 110 | * \param format A string that specifies the format of the output 111 | * \return The number of characters that are sent to the output function, not counting the terminating null character 112 | */ 113 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); 114 | 115 | 116 | #ifdef __cplusplus 117 | } 118 | #endif 119 | 120 | 121 | #endif // _PRINTF_H_ 122 | -------------------------------------------------------------------------------- /arm9/source/saveload.c: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, its source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave (Phoenix-Edition), 7 | // Alekmaul (original port) and Marat Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "SpeccySE.h" 21 | #include "CRC32.h" 22 | #include "cpu/z80/Z80_interface.h" 23 | #include "SpeccyUtils.h" 24 | #include "printf.h" 25 | 26 | #include "lzav.h" 27 | 28 | #define SPECCY_SAVE_VER 0x000A // Change this if the basic format of the .SAV file changes. Invalidates older .sav files. 29 | 30 | // ----------------------------------------------------------------------------------------------------- 31 | // Since the main MemoryMap[] can point to differt things (RAM, ROM, BIOS, etc) and since we can't rely 32 | // on the memory being in the same spot on subsequent versions of the emulator... we need to save off 33 | // the type and the offset so that we can patch it back together when we load back a saved state. 34 | // ----------------------------------------------------------------------------------------------------- 35 | struct RomOffset 36 | { 37 | u8 type; 38 | u32 offset; 39 | }; 40 | 41 | struct RomOffset Offsets[4]; 42 | 43 | #define TYPE_ROM 0 44 | #define TYPE_RAM 1 45 | #define TYPE_RAM128 2 46 | #define TYPE_BIOS 3 47 | #define TYPE_BIOS128 4 48 | #define TYPE_OTHER 5 49 | 50 | /********************************************************************************* 51 | * Save the current state - save everything we need to a single .sav file. 52 | ********************************************************************************/ 53 | static char szLoadFile[256]; // We build the filename out of the base filename and tack on .sav, .ee, etc. 54 | static char tmpStr[32]; 55 | 56 | u8 CompressBuffer[(150+32)*1024]; // Big enough to handle compression of even full 128K games - we also steal this memory for screen snapshot use 57 | 58 | #pragma GCC diagnostic push 59 | #pragma GCC diagnostic ignored "-Warray-bounds" 60 | 61 | u8 spare[300]; 62 | 63 | void spectrumSaveState() 64 | { 65 | size_t retVal; 66 | 67 | memset(spare, 0x00, sizeof(spare)); 68 | 69 | // Return to the original path 70 | chdir(initial_path); 71 | 72 | // Init filename = romname and SAV in place of ROM 73 | DIR* dir = opendir("sav"); 74 | if (dir) closedir(dir); // Directory exists... close it out and move on. 75 | else mkdir("sav", 0777); // Otherwise create the directory... 76 | sprintf(szLoadFile,"sav/%s", initial_file); 77 | 78 | int len = strlen(szLoadFile); 79 | szLoadFile[len-3] = 's'; 80 | szLoadFile[len-2] = 'a'; 81 | szLoadFile[len-1] = 'v'; 82 | 83 | strcpy(tmpStr,"SAVING..."); 84 | DSPrint(4,0,0,tmpStr); 85 | 86 | FILE *handle = fopen(szLoadFile, "wb+"); 87 | if (handle != NULL) 88 | { 89 | // Write Version 90 | u16 save_ver = SPECCY_SAVE_VER; 91 | retVal = fwrite(&save_ver, sizeof(u16), 1, handle); 92 | 93 | // Write Last Directory Path / Tape File 94 | retVal = fwrite(&last_path, sizeof(last_path), 1, handle); 95 | retVal = fwrite(&last_file, sizeof(last_file), 1, handle); 96 | 97 | // Write CZ80 CPU 98 | retVal = fwrite(&CPU, sizeof(CPU), 1, handle); 99 | 100 | // Write AY Chip info 101 | u8 ay_save_buffer[64]; // The AY save state is only like 16 bytes... so this is more than enough... 102 | ay38910SaveState(ay_save_buffer, &myAY); 103 | retVal = fwrite(ay_save_buffer, sizeof(ay_save_buffer), 1, handle); 104 | 105 | // And the Memory Map - we must only save offsets so that this is generic when we change code and memory shifts... 106 | for (u8 i=0; i<4; i++) 107 | { 108 | // ------------------------------------------------------------------------------- 109 | // This is the base address where the Memory Map is pointing to... (the maps are 110 | // all offset by chunks of 16K to provide faster reading/writing in Z80.c) 111 | // ------------------------------------------------------------------------------- 112 | u8 *ptr = MemoryMap[i] + (i*0x4000); 113 | 114 | if ((ptr >= SpectrumBios) && (ptr < SpectrumBios+sizeof(SpectrumBios))) 115 | { 116 | Offsets[i].type = TYPE_BIOS; 117 | Offsets[i].offset = ptr - SpectrumBios; 118 | } 119 | else if ((ptr >= SpectrumBios128) && (ptr < SpectrumBios+sizeof(SpectrumBios128))) 120 | { 121 | Offsets[i].type = TYPE_BIOS128; 122 | Offsets[i].offset = ptr - SpectrumBios128; 123 | } 124 | else if ((ptr >= RAM_Memory) && (ptr < RAM_Memory+sizeof(RAM_Memory))) 125 | { 126 | Offsets[i].type = TYPE_RAM; 127 | Offsets[i].offset = ptr - RAM_Memory; 128 | } 129 | else if ((ptr >= RAM_Memory128) && (ptr < RAM_Memory128+sizeof(RAM_Memory128))) 130 | { 131 | Offsets[i].type = TYPE_RAM128; 132 | Offsets[i].offset = ptr - RAM_Memory128; 133 | } 134 | else if ((ptr >= ROM_Memory) && (ptr < ROM_Memory+sizeof(ROM_Memory))) 135 | { 136 | Offsets[i].type = TYPE_ROM; 137 | Offsets[i].offset = ptr - ROM_Memory; 138 | } 139 | else 140 | { 141 | Offsets[i].type = TYPE_OTHER; 142 | Offsets[i].offset = (u32)MemoryMap[i]; 143 | } 144 | } 145 | if (retVal) retVal = fwrite(Offsets, sizeof(Offsets),1, handle); 146 | 147 | // And now a bunch of ZX Spectrum related vars... 148 | if (retVal) retVal = fwrite(&portFE, sizeof(portFE), 1, handle); 149 | if (retVal) retVal = fwrite(&portFD, sizeof(portFD), 1, handle); 150 | if (retVal) retVal = fwrite(&zx_AY_enabled, sizeof(zx_AY_enabled), 1, handle); 151 | if (retVal) retVal = fwrite(&flash_timer, sizeof(flash_timer), 1, handle); 152 | if (retVal) retVal = fwrite(&bFlash, sizeof(bFlash), 1, handle); 153 | if (retVal) retVal = fwrite(&zx_128k_mode, sizeof(zx_128k_mode), 1, handle); 154 | if (retVal) retVal = fwrite(&zx_ScreenRendering, sizeof(zx_ScreenRendering), 1, handle); 155 | if (retVal) retVal = fwrite(&zx_current_line, sizeof(zx_current_line), 1, handle); 156 | if (retVal) retVal = fwrite(&last_line_drawn, sizeof(last_line_drawn), 1, handle); 157 | if (retVal) retVal = fwrite(&emuActFrames, sizeof(emuActFrames), 1, handle); 158 | if (retVal) retVal = fwrite(&timingFrames, sizeof(timingFrames), 1, handle); 159 | if (retVal) retVal = fwrite(&num_blocks_available, sizeof(num_blocks_available), 1, handle); 160 | if (retVal) retVal = fwrite(¤t_block, sizeof(current_block), 1, handle); 161 | if (retVal) retVal = fwrite(&tape_state, sizeof(tape_state), 1, handle); 162 | if (retVal) retVal = fwrite(¤t_block_data_idx, sizeof(current_block_data_idx), 1, handle); 163 | if (retVal) retVal = fwrite(&tape_bytes_processed, sizeof(tape_bytes_processed), 1, handle); 164 | if (retVal) retVal = fwrite(&header_pulses, sizeof(header_pulses), 1, handle); 165 | if (retVal) retVal = fwrite(¤t_bit, sizeof(current_bit), 1, handle); 166 | if (retVal) retVal = fwrite(¤t_bytes_this_block, sizeof(current_bytes_this_block), 1, handle); 167 | if (retVal) retVal = fwrite(&handle_last_bits, sizeof(handle_last_bits), 1, handle); 168 | if (retVal) retVal = fwrite(&custom_pulse_idx, sizeof(custom_pulse_idx), 1, handle); 169 | if (retVal) retVal = fwrite(&bFirstTime, sizeof(bFirstTime), 1, handle); 170 | if (retVal) retVal = fwrite(&loop_counter, sizeof(loop_counter), 1, handle); 171 | if (retVal) retVal = fwrite(&loop_block, sizeof(loop_block), 1, handle); 172 | if (retVal) retVal = fwrite(&last_edge, sizeof(last_edge), 1, handle); 173 | if (retVal) retVal = fwrite(&give_up_counter, sizeof(give_up_counter), 1, handle); 174 | if (retVal) retVal = fwrite(&next_edge1, sizeof(next_edge1), 1, handle); 175 | if (retVal) retVal = fwrite(&next_edge2, sizeof(next_edge2), 1, handle); 176 | if (retVal) retVal = fwrite(&tape_play_skip_frame, sizeof(tape_play_skip_frame), 1, handle); 177 | if (retVal) retVal = fwrite(&rom_special_bank, sizeof(rom_special_bank), 1, handle); 178 | if (retVal) retVal = fwrite(&dandanator_cmd, sizeof(dandanator_cmd), 1, handle); 179 | if (retVal) retVal = fwrite(&dandanator_data1, sizeof(dandanator_data1), 1, handle); 180 | if (retVal) retVal = fwrite(&dandanator_data2, sizeof(dandanator_data2), 1, handle); 181 | if (retVal) retVal = fwrite(&zx_ula_plus_enabled, sizeof(zx_ula_plus_enabled), 1, handle); 182 | if (retVal) retVal = fwrite(&zx_ula_plus_group, sizeof(zx_ula_plus_group), 1, handle); 183 | if (retVal) retVal = fwrite(&zx_ula_plus_palette_reg, sizeof(zx_ula_plus_palette_reg), 1, handle); 184 | if (retVal) retVal = fwrite(&zx_ula_plus_palette, sizeof(zx_ula_plus_palette), 1, handle); 185 | if (retVal) retVal = fwrite(ContendMap, sizeof(ContendMap), 1, handle); 186 | if (retVal) retVal = fwrite(spare, 300, 1, handle); 187 | 188 | // Save Z80 Memory Map... either 48K or 128K 189 | u8 *ptr = (zx_128k_mode ? RAM_Memory128 : (RAM_Memory+0x4000)); 190 | u32 mem_size = (zx_128k_mode ? 0x20000 : 0xC000); 191 | 192 | // ------------------------------------------------------------------- 193 | // Compress the RAM data using 'high' compression ratio... it's 194 | // still quite fast for such small memory buffers and often shrinks 195 | // 48K games down under 32K and 128K games down closer to 64K. 196 | // ------------------------------------------------------------------- 197 | int max_len = lzav_compress_bound_hi( mem_size ); 198 | int comp_len = lzav_compress_hi( ptr, CompressBuffer, mem_size, max_len ); 199 | 200 | if (retVal) retVal = fwrite(&comp_len, sizeof(comp_len), 1, handle); 201 | if (retVal) retVal = fwrite(&CompressBuffer, comp_len, 1, handle); 202 | 203 | strcpy(tmpStr, (retVal ? "OK ":"ERR")); 204 | DSPrint(13,0,0,tmpStr); 205 | WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL; 206 | DSPrint(4,0,0," "); 207 | DisplayStatusLine(true); 208 | } 209 | else 210 | { 211 | strcpy(tmpStr,"Error opening SAV file ..."); 212 | } 213 | fclose(handle); 214 | } 215 | 216 | 217 | /********************************************************************************* 218 | * Load the current state - read everything back from the .sav file. 219 | ********************************************************************************/ 220 | void spectrumLoadState() 221 | { 222 | size_t retVal; 223 | 224 | // Return to the original path 225 | chdir(initial_path); 226 | 227 | // Init filename = romname and .SAV in place of ROM 228 | sprintf(szLoadFile,"sav/%s", initial_file); 229 | int len = strlen(szLoadFile); 230 | 231 | szLoadFile[len-3] = 's'; 232 | szLoadFile[len-2] = 'a'; 233 | szLoadFile[len-1] = 'v'; 234 | 235 | FILE* handle = fopen(szLoadFile, "rb"); 236 | if (handle != NULL) 237 | { 238 | strcpy(tmpStr,"LOADING..."); 239 | DSPrint(4,0,0,tmpStr); 240 | 241 | // Read Version 242 | u16 save_ver = 0xBEEF; 243 | retVal = fread(&save_ver, sizeof(u16), 1, handle); 244 | 245 | if (save_ver == SPECCY_SAVE_VER) 246 | { 247 | // Read Last Directory Path / Tape File 248 | if (retVal) retVal = fread(&last_path, sizeof(last_path), 1, handle); 249 | if (retVal) retVal = fread(&last_file, sizeof(last_file), 1, handle); 250 | 251 | // ---------------------------------------------------------------- 252 | // If the last known file was a tap file (.tap or .tzx) we want to 253 | // reload that as the user might have swapped tapes to side 2, etc. 254 | // ---------------------------------------------------------------- 255 | if ( (strcasecmp(strrchr(last_file, '.'), ".tap") == 0) || (strcasecmp(strrchr(last_file, '.'), ".tzx") == 0) ) 256 | { 257 | chdir(last_path); 258 | CassetteInsert(last_file); 259 | } 260 | 261 | // Load CZ80 CPU 262 | if (retVal) retVal = fread(&CPU, sizeof(CPU), 1, handle); 263 | 264 | // Load AY Chip info 265 | u8 ay_save_buffer[64]; // The AY save state is only like 16 bytes... so this is more than enough... 266 | retVal = fread(ay_save_buffer, sizeof(ay_save_buffer), 1, handle); 267 | ay38910LoadState(&myAY, ay_save_buffer); 268 | 269 | // Load back the Memory Map - these were saved as offsets so we must reconstruct actual pointers 270 | if (retVal) retVal = fread(Offsets, sizeof(Offsets),1, handle); 271 | for (u8 i=0; i<4; i++) 272 | { 273 | if (Offsets[i].type == TYPE_BIOS) 274 | { 275 | MemoryMap[i] = (u8 *) (SpectrumBios + Offsets[i].offset - (i*0x4000)); 276 | } 277 | else if (Offsets[i].type == TYPE_BIOS128) 278 | { 279 | MemoryMap[i] = (u8 *) (SpectrumBios128 + Offsets[i].offset - (i*0x4000)); 280 | } 281 | else if (Offsets[i].type == TYPE_RAM) 282 | { 283 | MemoryMap[i] = (u8 *) (RAM_Memory + Offsets[i].offset - (i*0x4000)); 284 | } 285 | else if (Offsets[i].type == TYPE_RAM128) 286 | { 287 | MemoryMap[i] = (u8 *) (RAM_Memory128 + Offsets[i].offset - (i*0x4000)); 288 | } 289 | else if (Offsets[i].type == TYPE_ROM) 290 | { 291 | MemoryMap[i] = (u8 *) (ROM_Memory + Offsets[i].offset - (i*0x4000)); 292 | } 293 | else // TYPE_OTHER - this is just a pointer to memory 294 | { 295 | MemoryMap[i] = (u8 *) (Offsets[i].offset); 296 | } 297 | } 298 | } 299 | else retVal = 0; 300 | 301 | // And now a bunch of ZX Spectrum related vars... 302 | if (retVal) retVal = fread(&portFE, sizeof(portFE), 1, handle); 303 | if (retVal) retVal = fread(&portFD, sizeof(portFD), 1, handle); 304 | if (retVal) retVal = fread(&zx_AY_enabled, sizeof(zx_AY_enabled), 1, handle); 305 | if (retVal) retVal = fread(&flash_timer, sizeof(flash_timer), 1, handle); 306 | if (retVal) retVal = fread(&bFlash, sizeof(bFlash), 1, handle); 307 | if (retVal) retVal = fread(&zx_128k_mode, sizeof(zx_128k_mode), 1, handle); 308 | if (retVal) retVal = fread(&zx_ScreenRendering, sizeof(zx_ScreenRendering), 1, handle); 309 | if (retVal) retVal = fread(&zx_current_line, sizeof(zx_current_line), 1, handle); 310 | if (retVal) retVal = fread(&last_line_drawn, sizeof(last_line_drawn), 1, handle); 311 | if (retVal) retVal = fread(&emuActFrames, sizeof(emuActFrames), 1, handle); 312 | if (retVal) retVal = fread(&timingFrames, sizeof(timingFrames), 1, handle); 313 | if (retVal) retVal = fread(&num_blocks_available, sizeof(num_blocks_available), 1, handle); 314 | if (retVal) retVal = fread(¤t_block, sizeof(current_block), 1, handle); 315 | if (retVal) retVal = fread(&tape_state, sizeof(tape_state), 1, handle); 316 | if (retVal) retVal = fread(¤t_block_data_idx, sizeof(current_block_data_idx), 1, handle); 317 | if (retVal) retVal = fread(&tape_bytes_processed, sizeof(tape_bytes_processed), 1, handle); 318 | if (retVal) retVal = fread(&header_pulses, sizeof(header_pulses), 1, handle); 319 | if (retVal) retVal = fread(¤t_bit, sizeof(current_bit), 1, handle); 320 | if (retVal) retVal = fread(¤t_bytes_this_block, sizeof(current_bytes_this_block), 1, handle); 321 | if (retVal) retVal = fread(&handle_last_bits, sizeof(handle_last_bits), 1, handle); 322 | if (retVal) retVal = fread(&custom_pulse_idx, sizeof(custom_pulse_idx), 1, handle); 323 | if (retVal) retVal = fread(&bFirstTime, sizeof(bFirstTime), 1, handle); 324 | if (retVal) retVal = fread(&loop_counter, sizeof(loop_counter), 1, handle); 325 | if (retVal) retVal = fread(&loop_block, sizeof(loop_block), 1, handle); 326 | if (retVal) retVal = fread(&last_edge, sizeof(last_edge), 1, handle); 327 | if (retVal) retVal = fread(&give_up_counter, sizeof(give_up_counter), 1, handle); 328 | if (retVal) retVal = fread(&next_edge1, sizeof(next_edge1), 1, handle); 329 | if (retVal) retVal = fread(&next_edge2, sizeof(next_edge2), 1, handle); 330 | if (retVal) retVal = fread(&tape_play_skip_frame, sizeof(tape_play_skip_frame), 1, handle); 331 | if (retVal) retVal = fread(&rom_special_bank, sizeof(rom_special_bank), 1, handle); 332 | if (retVal) retVal = fread(&dandanator_cmd, sizeof(dandanator_cmd), 1, handle); 333 | if (retVal) retVal = fread(&dandanator_data1, sizeof(dandanator_data1), 1, handle); 334 | if (retVal) retVal = fread(&dandanator_data2, sizeof(dandanator_data2), 1, handle); 335 | if (retVal) retVal = fread(&zx_ula_plus_enabled, sizeof(zx_ula_plus_enabled), 1, handle); 336 | if (retVal) retVal = fread(&zx_ula_plus_group, sizeof(zx_ula_plus_group), 1, handle); 337 | if (retVal) retVal = fread(&zx_ula_plus_palette_reg, sizeof(zx_ula_plus_palette_reg), 1, handle); 338 | if (retVal) retVal = fread(&zx_ula_plus_palette, sizeof(zx_ula_plus_palette), 1, handle); 339 | if (retVal) retVal = fread(ContendMap, sizeof(ContendMap), 1, handle); 340 | if (retVal) retVal = fread(spare, 300, 1, handle); 341 | 342 | if (zx_ula_plus_enabled) 343 | { 344 | apply_ula_plus_palette(); 345 | } 346 | 347 | // Load Z80 Memory Map... either 48K or 128K 348 | int comp_len = 0; 349 | if (retVal) retVal = fread(&comp_len, sizeof(comp_len), 1, handle); 350 | if (retVal) retVal = fread(&CompressBuffer, comp_len, 1, handle); 351 | 352 | if (retVal) 353 | { 354 | u8 *dest_memory = (zx_128k_mode ? RAM_Memory128 : (RAM_Memory+0x4000)); 355 | u32 mem_size = (zx_128k_mode ? 0x20000 : 0xC000); 356 | 357 | // ------------------------------------------------------------------ 358 | // Decompress the previously compressed RAM and put it back into the 359 | // right memory location... this is quite fast all things considered. 360 | // ------------------------------------------------------------------ 361 | (void)lzav_decompress( CompressBuffer, dest_memory, comp_len, mem_size ); 362 | } 363 | 364 | strcpy(tmpStr, (retVal ? "OK ":"ERR")); 365 | DSPrint(13,0,0,tmpStr); 366 | 367 | WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL; 368 | DSPrint(4,0,0," "); 369 | DisplayStatusLine(true); 370 | } 371 | else 372 | { 373 | DSPrint(4,0,0,"NO SAVED GAME"); 374 | WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL; 375 | DSPrint(4,0,0," "); 376 | } 377 | 378 | fclose(handle); 379 | } 380 | 381 | #pragma GCC diagnostic pop 382 | 383 | // End of file 384 | -------------------------------------------------------------------------------- /arm9/source/screenshot.c: -------------------------------------------------------------------------------- 1 | // ===================================================================================== 2 | // Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 3 | // 4 | // Copying and distribution of this emulator, its source code and associated 5 | // readme files, with or without modification, are permitted in any medium without 6 | // royalty provided this copyright notice is used and wavemotion-dave and 7 | // Marat Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SpeccySE emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | 12 | // Borrowed from Godemode9i from Rocket Robz 13 | // Used with permission April 2023 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #include "screenshot.h" 22 | #include "printf.h" 23 | #include "SpeccyUtils.h" 24 | 25 | void write16(void *address, u16 value) { 26 | 27 | u8* first = (u8*)address; 28 | u8* second = first + 1; 29 | 30 | *first = value & 0xff; 31 | *second = value >> 8; 32 | } 33 | 34 | void write32(void *address, u32 value) { 35 | 36 | u8* first = (u8*)address; 37 | u8* second = first + 1; 38 | u8* third = first + 2; 39 | u8* fourth = first + 3; 40 | 41 | *first = value & 0xff; 42 | *second = (value >> 8) & 0xff; 43 | *third = (value >> 16) & 0xff; 44 | *fourth = (value >> 24) & 0xff; 45 | } 46 | 47 | bool screenshotbmp(const char* filename) { 48 | FILE *file = fopen(filename, "wb"); 49 | 50 | if(!file) return false; 51 | 52 | REG_DISPCAPCNT = DCAP_BANK(DCAP_BANK_VRAM_B) | DCAP_SIZE(DCAP_SIZE_256x192) | DCAP_ENABLE; 53 | while(REG_DISPCAPCNT & DCAP_ENABLE); 54 | 55 | // --------------------------------------------------------- 56 | // The screenshot requires a bit less than 100K of memory... 57 | // We steal this from the compression buffer which is not 58 | // otherwise used except when save/loading save states. 59 | // --------------------------------------------------------- 60 | u8 *temp = (u8*)CompressBuffer; 61 | 62 | HEADER *header= (HEADER*)temp; 63 | INFOHEADER *infoheader = (INFOHEADER*)(temp + sizeof(HEADER)); 64 | 65 | write16(&header->type, 0x4D42); 66 | write32(&header->size, 256 * 192 * 2 + sizeof(INFOHEADER) + sizeof(HEADER)); 67 | write32(&header->reserved1, 0); 68 | write32(&header->reserved2, 0); 69 | write32(&header->offset, sizeof(INFOHEADER) + sizeof(HEADER)); 70 | 71 | write32(&infoheader->size, sizeof(INFOHEADER)); 72 | write32(&infoheader->width, 256); 73 | write32(&infoheader->height, 192); 74 | write16(&infoheader->planes, 1); 75 | write16(&infoheader->bits, 16); 76 | write32(&infoheader->compression, 3); 77 | write32(&infoheader->imagesize, 256 * 192 * 2); 78 | write32(&infoheader->xresolution, 2835); 79 | write32(&infoheader->yresolution, 2835); 80 | write32(&infoheader->ncolours, 0); 81 | write32(&infoheader->importantcolours, 0); 82 | write32(&infoheader->redBitmask, 0xF800); 83 | write32(&infoheader->greenBitmask, 0x07E0); 84 | write32(&infoheader->blueBitmask, 0x001F); 85 | write32(&infoheader->reserved, 0); 86 | 87 | u16 *ptr = (u16*)(temp + sizeof(HEADER) + sizeof(INFOHEADER)); 88 | for(int y = 0; y < 192; y++) { 89 | for(int x = 0; x < 256; x++) { 90 | u16 color = VRAM_B[256 * 191 - y * 256 + x]; 91 | *(ptr++) = ((color >> 10) & 0x1F) | (color & (0x1F << 5)) << 1 | ((color & 0x1F) << 11); 92 | } 93 | } 94 | 95 | DC_FlushAll(); 96 | fwrite(temp, 1, 256 * 192 * 2 + sizeof(INFOHEADER) + sizeof(HEADER), file); 97 | fclose(file); 98 | return true; 99 | } 100 | 101 | 102 | char snapPath[64]; 103 | bool screenshot(void) 104 | { 105 | time_t unixTime = time(NULL); 106 | struct tm* timeStruct = gmtime((const time_t *)&unixTime); 107 | 108 | sprintf(snapPath, "SNAP-%02d-%02d-%04d-%02d-%02d-%02d.bmp", timeStruct->tm_mday, timeStruct->tm_mon+1, timeStruct->tm_year+1900, timeStruct->tm_hour, timeStruct->tm_min, timeStruct->tm_sec); 109 | 110 | // Take top screenshot 111 | if(!screenshotbmp(snapPath)) 112 | return false; 113 | 114 | return true; 115 | } 116 | 117 | // End of file 118 | -------------------------------------------------------------------------------- /arm9/source/screenshot.h: -------------------------------------------------------------------------------- 1 | // Borrowed from GodMode9i from Rocket Robz 2 | #ifndef SCREENSHOT_H 3 | #define SCREENSHOT_H 4 | #include 5 | 6 | extern bool screenshot(void); 7 | 8 | typedef struct { 9 | u16 type; /* Magic identifier */ 10 | u32 size; /* File size in bytes */ 11 | u16 reserved1, reserved2; 12 | u32 offset; /* Offset to image data, bytes */ 13 | } PACKED HEADER; 14 | 15 | typedef struct { 16 | u32 size; /* Header size in bytes */ 17 | u32 width, height; /* Width and height of image */ 18 | u16 planes; /* Number of colour planes */ 19 | u16 bits; /* Bits per pixel */ 20 | u32 compression; /* Compression type */ 21 | u32 imagesize; /* Image size in bytes */ 22 | u32 xresolution, yresolution; /* Pixels per meter */ 23 | u32 ncolours; /* Number of colours */ 24 | u32 importantcolours; /* Important colours */ 25 | u32 redBitmask; /* Red bitmask */ 26 | u32 greenBitmask; /* Green bitmask */ 27 | u32 blueBitmask; /* Blue bitmask */ 28 | u32 reserved; 29 | } PACKED INFOHEADER; 30 | 31 | #endif // SCREENSHOT_H 32 | -------------------------------------------------------------------------------- /arm9/source/soundbank.h: -------------------------------------------------------------------------------- 1 | #define SFX_CLICKNOQUIT 0 2 | #define SFX_KEYCLICK 1 3 | #define SFX_MUS_INTRO 2 4 | #define MSL_NSONGS 0 5 | #define MSL_NSAMPS 3 6 | #define MSL_BANKSIZE 3 7 | -------------------------------------------------------------------------------- /logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/logo.bmp -------------------------------------------------------------------------------- /png/cassette.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/png/cassette.bmp -------------------------------------------------------------------------------- /png/keyboard.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/png/keyboard.bmp -------------------------------------------------------------------------------- /png/keymap.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/png/keymap.bmp -------------------------------------------------------------------------------- /png/mainmenu.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/png/mainmenu.bmp -------------------------------------------------------------------------------- /png/minimenu.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SpeccySE/d5b3639ed373410467172214a285505b13167203/png/minimenu.bmp -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # SpeccySE 2 | ![image](./arm9/gfx_data/pdev_bg0.png) 3 | 4 | SpeccySE is a ZX Spectrum 48K / 128K Emulator for the DS/DSi 5 | 6 | To run requires one or both of the original ZX Spectrum BIOS ROMs. 7 | Place 48.ROM and 128.ROM (exactly so named) into the same directory 8 | as the emulator or else in /roms/bios or /data/bios 9 | 10 | Features : 11 | ----------------------- 12 | * Loads .TAP files up to 512K total length (can swap tapes mid-game) 13 | * Loads .TZX files up to 512K total length (can swap tapes mid-game) 14 | * Loads .Z80 snapshots (V1, V2 and V3 formats, 48K or 128K) 15 | * Loads .SNA snapshots (48K only) 16 | * Loads .ROM files (16K diagnostics ROMs or 512K Dandanator ROMs) 17 | * Loads .PRG files directly into memory and executes them (use Cart menu) 18 | * Loads .P files for ZX81 emulation (see below) 19 | * Supports .POK files (same name as base game and stored in POK subdir) 20 | * Kempston and Sinclair joystick support 21 | * Fully configurable keys for the 12 NDS keys to any combination of joystick/keyboard 22 | * Save and Restore states so you can pick up where you left off 23 | * ULAPlus support for enhanced 64 color mode (from a palette of 256 colors) 24 | * Slide-n-Glide style Joystick configuration to make climbing ladders in games like Chuckie-Egg more forgiving (try it - you'll like it!) 25 | * High Score saving for 10 scores with initials, date/time. 26 | * Solid Z80 core that passes the ZEXDOC test suite (covering everything but not undocumented flags). 27 | * Minimal design asthetic - pick game, play game. Runs unpached from your SD card via TWL++ or similar. 28 | 29 | Copyright : 30 | ----------------------- 31 | SpeccySE is Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 32 | 33 | As long as there is no commercial use (i.e. no profit is made), 34 | copying and distribution of this emulator, it's source code 35 | and associated readme files, with or without modification, 36 | are permitted in any medium without royalty provided this 37 | copyright notice is used and wavemotion-dave (SpeccySE), 38 | and Marat Fayzullin (Z80 core) are thanked profusely. 39 | 40 | The sound driver (ay38910) are libraries from FluBBa (Fredrik Ahlström) 41 | and those copyrights remain his. 42 | 43 | Royalty Free Music for the opening jingle provided by Anvish Parker 44 | 45 | lzav compression (for save states) is Copyright (c) 2023-2025 Aleksey 46 | Vaneev and used by permission of the generous MIT license. 47 | 48 | The Sinclair logo is used without permission but with the maximum 49 | of respect and love. 50 | 51 | The SpeccySE emulator is offered as-is, without any warranty. 52 | 53 | Special Thanks : 54 | ----------------------- 55 | Thanks to Flubba for the SN76496, AY38910 and SCC sound cores. You can seek out his latest and greatest at https://github.com/FluBBaOfWard 56 | 57 | Also thanks to Marat Fayzullin, as the author of ColEM and Speccy - which is where the CZ80 CPU core came from. 58 | 59 | And Sir Clive. 60 | 61 | How do I run this thing? : 62 | ----------------------- 63 | That's a bit beyond what I can help with in this readme... but if you have a DSi (with an SD card slot on the right-hand side of the handheld), 64 | then you're in luck. Google 'DSi Camera Exploit' and 'Twilight Menu++' and you'll be on the right track. If you have an older DS handheld, you'll 65 | probably have to use a flash/multi cart such as one of the R4 clones. 66 | 67 | ZX Spectrum BIOS ROMS : 68 | ----------------------- 69 | The emulator does not include any proprietary BIOS ROMs but you will 70 | need them to play anything. There are two ZX Spectrum BIOS ROMs you 71 | will need - they must be exactly so named (rename as needed) and placed 72 | into the same directory as the emulator or else /ROMS/BIOS (that's where 73 | the cool kids keep them): 74 | 75 | ``` 76 | * 48.ROM with CRC32 of ddee531f 77 | * 128.ROM with CRC32 of 2cbe8995 78 | ``` 79 | 80 | Use of any other non-standard ZX Spectrum roms is likely to end in tears. 81 | 82 | The ZX Keyboard : 83 | ----------------------- 84 | The emulator has a built-in virtual touch keyboard that works reasonably well 85 | except that the touch screen is not multi-touch (like your phone). So you 86 | can only press on one area of the screen at a time. To make the SYMBOL and 87 | SHIFT keys work, when you press those buttons, you will see a little white 88 | or yellow indicator at the top of the screen indicating that this button 89 | is a symbol/shift button and it will wait for the _next_ button to be pressed 90 | and use it in combination with the symbol/shift. So if you want to type the 91 | quote mark ("), you would press and release Symbol, then press the letter P. 92 | 93 | ![image](./png/keyboard.bmp) 94 | 95 | Emulator Use : 96 | ----------------------- 97 | The emulator is fairly straightforward to navigatge. The main menu lets you 98 | select the game you wish to play (.TAP, .TZX or .Z80). Once you've picked 99 | a game, the title will show at the bottom along with the size and CRC (which 100 | isn't all that important but I like to see it). Then you can play the game or 101 | you can change the settings for a game (define keys or set specific game 102 | options). Each game allows you to save off a configuration that is specific 103 | to that game - so each game can have its own custom key settings, etc. 104 | 105 | When you're playing the game, there are two button that bring up additional 106 | menus. The cassette icon will bring up some options for dealing with the 107 | cassette (tape) player. Usually the tape will auto-start and auto-stop but 108 | sometimes you have to override what's happening with the emulation. You can 109 | also use this menu to swap in a 'Side B' or 'Tape 2' for the current game. 110 | 111 | The other menu is the 'Mini Menu' which allows you to quit the current game, 112 | save/load the game state and set some high scores for the game being played. 113 | 114 | ![image](./png/mainmenu.bmp) 115 | ![image](./png/cassette.bmp) 116 | ![image](./png/minimenu.bmp) 117 | 118 | Key Mapping : 119 | ----------------------- 120 | Each game can have a custom set of keys mapped to the 12 DS/DSi keys (yes 121 | that includes START, SELECT and the L/R shoulder buttons). By default, 122 | the DPad and 'A' button is set to the Kempston standard. 123 | 124 | ![image](./png/keymap.bmp) 125 | 126 | Joystick Support : 127 | ----------------------- 128 | The emulator has support for the Kempston and Sinclair (67890) joysticks but 129 | really any keyboard key can be mapped to any one of the 12 NDS buttons 130 | so you should be able to configure things exactly as desired. When using 131 | the 'REDEFINE KEYS' menu, you can press the NDS 'X' button to toggle between 132 | a number of commonly used preset keys for various ZX games (QAOP, ZXM, etc). 133 | By default, the configuration for any game is set to use the Kempston joystick. 134 | 135 | Also be aware that there is a D-PAD option that can be set to 'SLIDE-N-GLIDE' 136 | for games that are often unforgiving using a joystick. If you've ever played 137 | Chuckie Egg on a keybaord you know that it's pinpoint percise... but with 138 | a joystick, it can be a bit frustrating trying to find the exact spot to 139 | transition from Left/Right to Up/Down to climb a ladder. This new joy mode 140 | will hold the L/R or U/D for a fraction of a frame while the transition 141 | is made. This allows for buttery smooth (relatively speaking) transitions 142 | on the ladders. It's likely other games will benefit from this mode - but 143 | Chuckie Egg is the reason I put it into the emulator. 144 | 145 | Game Options / Global Options : 146 | ----------------------- 147 | There are a number of options you can tweak on a per-game basis as well 148 | as a few global options that apply to the emulator in general. The most 149 | useful of the global options is to select your starting directory. The 150 | default is to start in /roms/speccy - you can have as many subdirectories 151 | under that as you wish. The emulator can support a file listing of up 152 | to 2000 files with names no longer than 160 characters (so please keep 153 | your filenames on the shorter side... although the emulator can scroll 154 | the filename, there only about 30 characters can be shown on the screen 155 | at a time). 156 | 157 | One option that is of particular note is the ability to run the game 158 | at a speed other than normal 100%. Some games were designed to run 159 | a bit too fast to be enjoyable. Other games were a bit too slow. Using 160 | this optional adjustment, you can run a game anywhere from 80% of full 161 | speed (slower than normal) to 120% (faster than normal). The sound driver 162 | should auto-adjust and while the music / sounds will sound faster/slower, 163 | it should match the core emulation speed perfectly. This can be adjusted 164 | on a per-game basis. 165 | 166 | As for the per-game options, you can set things like the auto fire 167 | for the joystick and the aforementioned Slide-n-Glide mode of joystick d-pad 168 | handling. One of the more useful per-game options is to decide how you 169 | want to load the game - using a 48K Spectrum or the upgraded 128K Spectrum. 170 | You can also force a load as 128K spectrum by pressing the NDS Y-Button 171 | when loading. If you don't understand an option - don't touch it. You 172 | have been duly warned! 173 | 174 | 175 | Tape Support : 176 | ----------------------- 177 | The emulator supports .Z80 snapshots but of more use is the .TAP and 178 | .TZX tape support. The .TAP format is fully supported and the .TZX is 179 | reasonably supported minus some of the more complicated blocks - most 180 | software never uses those specialized blocks. As with any old tape-based 181 | software, sometimes the .TAP or .TZX files are a bit dodgy - so if one 182 | version of a tape doesn't work, go find another and it will probably 183 | load up and play properly. 184 | 185 | Speaking of loading - I decided not to optimize away the loading screens 186 | but they are greatly accelerated. Most games load at 10-15x the original 187 | speeds... meaning a 48K game should load in under 15 seconds and a full 188 | 128K game might take a half-minute or so... Enjoy the loading screens - they 189 | were part of the charm of the original system. 190 | 191 | You can press the Cassette Icon to swap in another tape or set the tape 192 | position manually. Most games just figure it out - and the auto-play 193 | and auto-stop of tapes should be working _reasonably_ well. You can 194 | override this as needed. While the tape is playing, most of the keyboard 195 | handling is disabled to gain maximum speed - so if you find that the 196 | auto tape stop isn't working, press the Cassette Icon and manually stop 197 | the tape. 198 | 199 | Lastly - when you look for tape files on the internet, you will often 200 | find several tape images for the same game. Some tape dumps are dubious 201 | and some tape dumps don't load properly with all emulators. Often times 202 | an alternate "[a]" version will load. Usually one tape image dump is 203 | as good as any other - but keep searching and put yourself together a 204 | library of known good working images for Speccy-SE. 205 | 206 | ROM Support : 207 | ----------------------- 208 | The emulator allows you to load a .ROM file directly into the same memory 209 | location as the BIOS (+0000 to +4000). The emulator supports 16K BIOS "replacement" 210 | files and 512K banked Dandanator files (e.g. Sword of Ianna). The 16K BIOS replacement 211 | mode is mainly used to load diagnostic test programs such as the amazing RETROLEUM DIAGROM. 212 | 213 | ZX81 Support : 214 | ----------------------- 215 | The emulator supports the Paul Farrow ZX81 emulator for the ZX 128k machines. 216 | 217 | http://www.fruitcake.plus.com/Sinclair/Interface2/Cartridges/Interface2_RC_New_ZX81.htm 218 | 219 | To make this work, download the 16K Interface ROM for the emulator - either Edition 2 220 | or Edition 3 (do not use Edition 1 or the 'bugfix version' as neither will work properly 221 | with SpeccySE). Take the Edition 2 or 3 ROM file exactly as Paul named it and place it 222 | in the same directory you put your 48.ROM Spectrum BASIC/BIOS file. This will now let 223 | you load and run .P files directly. When you pick the game, it will automatically insert 224 | the keystrokes needed to get the emulator running. This takes about 10 seconds... 225 | don't touch any virtual keys until the ZX81 game is fully loaded. 226 | 227 | If the game loads but shows something like 0/0 at the bottom, it's a BASIC game that 228 | has been loaded and you should press the 'R' virtual key to enter the RUN command 229 | and press ENTER... this will get the game going. 230 | 231 | Paul's emulator works with most ZX81 .P games but there are a few that won't run 232 | as they do some unusual things that the emulator can't handle. You can read more about 233 | it on his website listed above. 234 | 235 | POK Support : 236 | ----------------------- 237 | The emulator supports .pok files. The .pok file should have the same base 238 | filename as the game you are playing and must be stored in a pok subdirectory. 239 | 240 | So if you have a roms directory, make a pok subdirectory and place your .pok 241 | file there. If properly named, you will see a list of all possible pokes when 242 | you select the 'POKE MEMORY' menu option. 243 | 244 | Memory Pokes remain in effect until you reset or reload the game. There is no 245 | other way to reverse the Memory Poke that has been done. If you are using a tape 246 | (.TAP or .TZX) you should wait for the game to load before applying the memory 247 | poke. Use at your own risk (oh... you can't really damage anything but the poke 248 | might not work the way you expect if you do it at the wrong time). 249 | 250 | Known Issues : 251 | ----------------------- 252 | * Not all Dandanator compilation games run properly - support is preliminary (but good enough for the few games that really need it). 253 | * Gandalf DLX does not run correctly. Timing is tight on that game and the accuracy of Speccy-SE is not up to the task. 254 | * Arcadia has some strange jittering of the player ship even when you don't touch keys. Cause unknown. 255 | * TRD disk files are not supported yet. Most games have TAP or Dandanator alternatives - but not all. 256 | 257 | Why? : 258 | ----------------------- 259 | There was never a need for this emulator to exist. ZXDS is the defacto standard of 260 | accuracy and features for a ZX Spectrum emulator on the DS. Why does this exist? 261 | Mainly because as an American who got hooked on a Spectrum in recent months, I got 262 | curious as to the workings. As a developer who had a number of DS/DSi emulators 263 | under my belt, the best way for me to learn the ins-and-outs of the system was to 264 | put together an emulator for the system. The design was kept very simple - and has 265 | the benefit of running directly from SD card via TWL++ or Unlaunch or similar. But 266 | really if you're looking for world-class ZX emulation for your DS/DSi handheld, 267 | you're likely going to want ZXDS. 268 | 269 | Version History : 270 | ----------------------- 271 | Version 1.6 - 27-Oct-2025 by wavemotion-dave 272 | * Revamped Z80 CPU core to provide more accurate timing and memory contention/floating bus. Multi-color games (aka Nirvana+, BiFrost, etc) now play and look reasonably correct and CPU speed is generally correct. 273 | * Fix for AY music not restoring properly on some Load States. 274 | * Smoother beeper sound for improved fidelity. 275 | * Added Kempston 2nd Fire button which can be mapped in. 276 | * Default machine is now the ZX Spectrum 128K but it will revert to 48K for common games with compatibility issues. 277 | * Other minor cleanups and improvements as time permitted. 278 | 279 | Version 1.5 - 20-Oct-2025 by wavemotion-dave 280 | * Added ULAplus support for games that support the extended color palette. 281 | * Improved beeper sound accuracy. 282 | * Fixed potential Z80 core memory stack issue - fixes a couple of games that were crashing. 283 | * Other minor cleanups and improvements under the hood. 284 | 285 | Version 1.4a - 15-Oct-2025 by wavemotion-dave 286 | * Fixed Shift and Symbol so they are truly temporary. 287 | * Improved memory contention timing. 288 | * Improved .POK support to handle much larger POK memory lists. 289 | * Added more resolution to the CPU speed options. 290 | * Added Dandanator .ROM support up to 512K banked. 291 | * Added diagonal D-Pad handling as a configurable option. 292 | * CPU Core speedup for 10% speed gain (helps with DS-Lite). 293 | * Fixed WSAD key mapping defaults (S and A were swapped). 294 | * Other minor improvements and fixes under the hood. 295 | * 1.4a Hotfix! Fixes crash in some 128K games. Sorry! 296 | 297 | Version 1.3 - 10-Sep-2025 by wavemotion-dave 298 | * Increased number of configuration game slots to 4096 299 | * Increased number of high-score slots to 1500 300 | * Fix and improvements for auto-tape handling so games load more reliably 301 | * Fix for Save/Load states for 128K games (some games would not load back properly) 302 | * Added ability to dim the keyboard screen in-game (set in Global Options) 303 | * Keyboard graphic replaced the word 'MENU' with a graphical menu icon 304 | * Fix when redefining keys so that it more cleanly remembers previous settings 305 | * Minor tweak to main menu and cassette menu handling to avoid screen garbage character 306 | * Refactored memory for tape loading to free up additional resources for future expansion of the emulator 307 | 308 | Version 1.2 - 07-Sep-2025 by wavemotion-dave 309 | * Improved ZX81 support for direct loading of .P files 310 | * New global option for machine type (48K vs 128K) 311 | * New main icon to better reflect the design aesthetics 312 | 313 | Version 1.1 - 30-Apr-2025 by wavemotion-dave 314 | * Double buffer video on DSi/XL/LL for reduced tearing 315 | * Rebranded 'Chuckie Egg-Style' joystick handling to 'Slide-n-Glide' 316 | * Minor cleanups as time permitted 317 | 318 | Version 1.0 - 14-Apr-2025 by wavemotion-dave 319 | * First official release of Speccy-SE! 320 | 321 | --------------------------------------------------------------------------------