├── Makefile ├── SugarDS.nds ├── arm7 ├── Makefile └── source │ ├── emusoundfifo.c │ └── main.c ├── arm9 ├── Makefile ├── data │ ├── clickNoQuit.wav │ ├── floppy3.wav │ ├── keyclick.wav │ ├── mus_intro.wav │ └── soundbank.bin ├── gfx_data │ ├── cpc_kbd.png │ ├── cpc_numpad.png │ ├── debug_ovl.png │ ├── mainmenu.png │ ├── splash.png │ ├── splash_top.png │ ├── topscreen.png │ └── topscreen_alt.png └── source │ ├── AmsUtils.c │ ├── AmsUtils.h │ ├── BIOS.c │ ├── CRC32.c │ ├── CRC32.h │ ├── SugarDS.c │ ├── SugarDS.h │ ├── amsdos.c │ ├── amsdos.h │ ├── amstrad.c │ ├── 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.h │ │ ├── Z80.c │ │ └── Z80.h │ ├── crtc.c │ ├── fdc.c │ ├── fdc.h │ ├── lzav.h │ ├── printf.c │ ├── printf.h │ ├── saveload.c │ └── soundbank.h ├── logo.bmp ├── png ├── global.png ├── keyboard.png ├── keymap.png ├── mainmenu.png ├── minimenu.png └── options.png ├── readme.md └── techdocs ├── Amstrad CRTC - ACCC1.8-EN.pdf └── Z80_CPC_Timings_cheat_sheet.20230709.pdf /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 := SugarDS 17 | export TOPDIR := $(CURDIR) 18 | export VERSION := 1.3 19 | 20 | ICON := -b $(CURDIR)/logo.bmp "SugarDS $(VERSION);wavemotion-dave;https://github.com/wavemotion-dave/SugarDS" 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 | -------------------------------------------------------------------------------- /SugarDS.nds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/SugarDS.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/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 -DAY_UPSHIFT=1 -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 cpc_kbd.o mainmenu.o topscreen.o splash.o splash_top.o topscreen_alt.o cpc_numpad.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 | cpc_kbd.s cpc_kbd.h : cpc_kbd.png 145 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 146 | 147 | cpc_numpad.s cpc_numpad.h : cpc_numpad.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 | topscreen_alt.s topscreen_alt.h : topscreen_alt.png 157 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 158 | 159 | splash.s splash.h : splash.png 160 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 161 | 162 | splash_top.s splash_top.h : splash_top.png 163 | grit $^ -o $@ -gt -mrt -mR8 -mLs -gzl -mzl 164 | 165 | 166 | -include $(DEPENDS) 167 | 168 | #--------------------------------------------------------------------------------------- 169 | endif 170 | #--------------------------------------------------------------------------------------- 171 | -------------------------------------------------------------------------------- /arm9/data/clickNoQuit.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/data/clickNoQuit.wav -------------------------------------------------------------------------------- /arm9/data/floppy3.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/data/floppy3.wav -------------------------------------------------------------------------------- /arm9/data/keyclick.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/data/keyclick.wav -------------------------------------------------------------------------------- /arm9/data/mus_intro.wav: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/data/mus_intro.wav -------------------------------------------------------------------------------- /arm9/data/soundbank.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/data/soundbank.bin -------------------------------------------------------------------------------- /arm9/gfx_data/cpc_kbd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/cpc_kbd.png -------------------------------------------------------------------------------- /arm9/gfx_data/cpc_numpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/cpc_numpad.png -------------------------------------------------------------------------------- /arm9/gfx_data/debug_ovl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/debug_ovl.png -------------------------------------------------------------------------------- /arm9/gfx_data/mainmenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/mainmenu.png -------------------------------------------------------------------------------- /arm9/gfx_data/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/splash.png -------------------------------------------------------------------------------- /arm9/gfx_data/splash_top.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/splash_top.png -------------------------------------------------------------------------------- /arm9/gfx_data/topscreen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/topscreen.png -------------------------------------------------------------------------------- /arm9/gfx_data/topscreen_alt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/arm9/gfx_data/topscreen_alt.png -------------------------------------------------------------------------------- /arm9/source/AmsUtils.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 SugarDS emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #ifndef _AMSUTILS_H_ 12 | #define _AMSUTILS_H_ 13 | #include 14 | #include "SugarDS.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_ROM_SIZE (1024*1024) // 1024K is big enough for any disk / cart / snapshot 21 | 22 | #define MAX_CONFIGS 890 23 | #define CONFIG_VERSION 0x0006 24 | 25 | #define AMSTRAD_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 | #define CRTC_DRV_STANDARD 0 37 | #define CRTC_DRV_ADVANCED 1 38 | 39 | extern char last_path[MAX_FILENAME_LEN]; 40 | extern char last_file[MAX_FILENAME_LEN]; 41 | 42 | extern u32 pre_inked_mode0[256]; 43 | extern u32 pre_inked_mode1[256]; 44 | extern u32 pre_inked_mode2a[256]; 45 | extern u32 pre_inked_mode2b[256]; 46 | extern u32 pre_inked_mode2c[256]; 47 | 48 | typedef struct 49 | { 50 | char szName[MAX_FILENAME_LEN+1]; 51 | u8 uType; 52 | u32 uCrc; 53 | } FIAmstrad; 54 | 55 | extern u32 file_size; 56 | 57 | struct __attribute__((__packed__)) GlobalConfig_t 58 | { 59 | u16 config_ver; 60 | u32 bios_checksums; 61 | char szLastFile[MAX_FILENAME_LEN+1]; 62 | char szLastPath[MAX_FILENAME_LEN+1]; 63 | char reserved1[MAX_FILENAME_LEN+1]; 64 | char reserved2[MAX_FILENAME_LEN+1]; 65 | u8 showFPS; 66 | u8 lastDir; 67 | u8 diskROM; 68 | u8 splashType; 69 | u8 keyboardDim; 70 | u8 global_04; 71 | u8 global_05; 72 | u8 global_06; 73 | u8 global_07; 74 | u8 global_08; 75 | u8 global_09; 76 | u8 global_10; 77 | u8 global_11; 78 | u8 global_12; 79 | u8 debugger; 80 | u32 config_checksum; 81 | }; 82 | 83 | struct __attribute__((__packed__)) Config_t 84 | { 85 | u32 game_crc; 86 | u8 keymap[10]; 87 | u8 autoFire; 88 | u8 r52IntVsync; 89 | u8 jitter; 90 | u8 dpad; 91 | u8 autoLoad; 92 | u8 gameSpeed; 93 | u8 autoSize; 94 | u8 cpuAdjust; 95 | u8 waveDirect; 96 | u8 screenTop; 97 | u8 mode2mode; 98 | u8 diskWrite; 99 | u8 crtcDriver; 100 | u8 reserved7; 101 | u8 reserved8; 102 | u8 reserved9; 103 | s8 offsetX; 104 | s8 offsetY; 105 | s16 scaleX; 106 | s16 scaleY; 107 | }; 108 | 109 | extern struct Config_t myConfig; 110 | extern struct GlobalConfig_t myGlobalConfig; 111 | 112 | extern u8 last_special_key; 113 | extern u8 last_special_key_dampen; 114 | 115 | extern u16 JoyState; // Joystick / Paddle management 116 | 117 | extern u32 file_crc; 118 | extern u8 bFirstTime; 119 | 120 | extern u8 BufferedKeys[32]; 121 | extern u8 BufferedKeysWriteIdx; 122 | extern u8 BufferedKeysReadIdx; 123 | 124 | extern u8 portA, portB, portC, portDIR; 125 | 126 | extern u8 ROM_Memory[MAX_ROM_SIZE]; 127 | extern u8 RAM_Memory[0x20000]; // 64K plus an expanded 512K 128 | 129 | extern u8 *MemoryMapR[4]; 130 | extern u8 *MemoryMapW[4]; 131 | extern AY38910 myAY; 132 | 133 | extern FIAmstrad gpFic[MAX_FILES]; 134 | extern int uNbRoms; 135 | extern int ucGameAct; 136 | extern int ucGameChoice; 137 | 138 | extern void LoadConfig(void); 139 | extern u8 showMessage(char *szCh1, char *szCh2); 140 | extern void sugarDSFindFiles(); 141 | extern void sugarDSChangeOptions(void); 142 | extern u8 sugarDSLoadFile(u8 bTapeOnly); 143 | extern void DSPrint(int iX,int iY,int iScr,char *szMessage); 144 | extern u32 crc32 (unsigned int crc, const unsigned char *buf, unsigned int len); 145 | extern void FadeToColor(unsigned char ucSens, unsigned short ucBG, unsigned char ucScr, unsigned char valEnd, unsigned char uWait); 146 | extern void DisplayFileName(void); 147 | extern u32 ReadFileCarefully(char *filename, u8 *buf, u32 buf_size, u32 buf_offset); 148 | extern u8 loadgame(const char *path); 149 | extern u8 AmstradInit(char *szGame); 150 | extern void amstrad_set_palette(void); 151 | extern void amstrad_emulate(void); 152 | extern u8 cpu_readport_ams(register unsigned short Port); 153 | extern void amstrad_reset(void); 154 | extern u32 amstrad_run(void); 155 | extern void getfile_crc(const char *path); 156 | extern void amstradLoadState(); 157 | extern void amstradSaveState(); 158 | extern void intro_logo(void); 159 | extern void BufferKey(u8 key); 160 | extern void BufferKeys(char *keys); 161 | extern void ProcessBufferedKeys(void); 162 | extern void SugarDSChangeKeymap(void); 163 | 164 | #endif // _AMSUTILS_H_ 165 | -------------------------------------------------------------------------------- /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 SugarDS emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #include 12 | #include 13 | #include 14 | #include "AmsUtils.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 | 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 | 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_ROM_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_ROM_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 SugarDS 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/SugarDS.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 SugarDS emulator is offered as-is, without any warranty. Please see readme.md 10 | // ===================================================================================== 11 | #ifndef _SUGARDS_H_ 12 | #define _SUGARDS_H_ 13 | 14 | #include 15 | #include 16 | #include "printf.h" 17 | 18 | extern u32 debug[0x10]; 19 | extern u32 DX, DY; 20 | 21 | extern u8 MMR; 22 | extern u8 RMR; 23 | extern u8 PENR; 24 | extern u8 INK[17]; 25 | extern u8 CRTC[0x20]; 26 | extern u8 CRT_Idx; 27 | extern u32 R52; 28 | extern u32 border_color; 29 | extern u32 last_frame_mode2; 30 | extern u32 last_frame_mode01; 31 | extern u8 last_frame_crtc1; 32 | extern int8 currentBrightness; 33 | extern u8 ram_highwater; 34 | extern u8 sna_last_motor; 35 | extern u8 sna_last_track; 36 | 37 | 38 | // These are the various special icons/menu operations 39 | #define MENU_CHOICE_NONE 0x00 40 | #define MENU_CHOICE_RESET_GAME 0x01 41 | #define MENU_CHOICE_END_GAME 0x02 42 | #define MENU_CHOICE_SAVE_GAME 0x03 43 | #define MENU_CHOICE_LOAD_GAME 0x04 44 | #define MENU_CHOICE_DEFINE_KEYS 0x05 45 | #define MENU_CHOICE_CONFIG_GAME 0x06 46 | #define MENU_CHOICE_SWAP_DISK 0x07 47 | #define MENU_CHOICE_TOGGLE_KBD 0xFE // Toggle Keyboard for Keypad 48 | #define MENU_CHOICE_MENU 0xFF // Special brings up a mini-menu of choices 49 | 50 | // ------------------------------------------------------------------------------ 51 | // Joystick UP, RIGHT, LEFT, DOWN and FIRE 1+2 buttons for the Amstrad Joystick. 52 | // Designed specifically so each has its own bit so we can press more than one 53 | // direction/fire at the same time. Keyboard keys are grafted onto this below. 54 | // ------------------------------------------------------------------------------ 55 | #define JST_UP 0x0001 56 | #define JST_RIGHT 0x0002 57 | #define JST_DOWN 0x0004 58 | #define JST_LEFT 0x0008 59 | #define JST_FIRE 0x0010 60 | #define JST_FIRE2 0x0020 61 | #define JST_FIRE3 0x0040 62 | 63 | // ----------------------------------------------------------------------------------- 64 | // And these are meta keys for mapping NDS keys to keyboard keys (many of the computer 65 | // games don't use joystick inputs and so need to map to keyboard keys...) 66 | // ----------------------------------------------------------------------------------- 67 | #define META_KBD_A 0xF001 68 | #define META_KBD_B 0xF002 69 | #define META_KBD_C 0xF003 70 | #define META_KBD_D 0xF004 71 | #define META_KBD_E 0xF005 72 | #define META_KBD_F 0xF006 73 | #define META_KBD_G 0xF007 74 | #define META_KBD_H 0xF008 75 | #define META_KBD_I 0xF009 76 | #define META_KBD_J 0xF00A 77 | #define META_KBD_K 0xF00B 78 | #define META_KBD_L 0xF00C 79 | #define META_KBD_M 0xF00D 80 | #define META_KBD_N 0xF00E 81 | #define META_KBD_O 0xF00F 82 | #define META_KBD_P 0xF010 83 | #define META_KBD_Q 0xF011 84 | #define META_KBD_R 0xF012 85 | #define META_KBD_S 0xF013 86 | #define META_KBD_T 0xF014 87 | #define META_KBD_U 0xF015 88 | #define META_KBD_V 0xF016 89 | #define META_KBD_W 0xF017 90 | #define META_KBD_X 0xF018 91 | #define META_KBD_Y 0xF019 92 | #define META_KBD_Z 0xF01A 93 | 94 | #define META_KBD_0 0xF01B 95 | #define META_KBD_1 0xF01C 96 | #define META_KBD_2 0xF01D 97 | #define META_KBD_3 0xF01E 98 | #define META_KBD_4 0xF01F 99 | #define META_KBD_5 0xF020 100 | #define META_KBD_6 0xF021 101 | #define META_KBD_7 0xF022 102 | #define META_KBD_8 0xF023 103 | #define META_KBD_9 0xF024 104 | 105 | #define META_KBD_SHIFT 0xF025 106 | #define META_KBD_PERIOD 0xF026 107 | #define META_KBD_COMMA 0xF027 108 | #define META_KBD_COLON 0xF028 109 | #define META_KBD_SEMI 0xF029 110 | #define META_KBD_ATSIGN 0xF02A 111 | #define META_KBD_SLASH 0xF02B 112 | #define META_KBD_SPACE 0xF02C 113 | #define META_KBD_RETURN 0xF02D 114 | #define META_KBD_F1 0xF02E 115 | #define META_KBD_F2 0xF02F 116 | #define META_KBD_F3 0xF030 117 | #define META_KBD_F4 0xF031 118 | #define META_KBD_CURS_UP 0xF032 119 | #define META_KBD_CURS_DN 0xF033 120 | #define META_KBD_CURS_LF 0xF034 121 | #define META_KBD_CURS_RT 0xF035 122 | #define META_KBD_CURS_CPY 0xF036 123 | 124 | #define META_KBD_PAN_UP16 0xF037 125 | #define META_KBD_PAN_UP24 0xF038 126 | #define META_KBD_PAN_UP32 0xF039 127 | #define META_KBD_PAN_DN16 0xF03A 128 | #define META_KBD_PAN_DN24 0xF03B 129 | #define META_KBD_PAN_DN32 0xF03C 130 | #define META_KBD_ESCAPE 0xF03D 131 | 132 | #define MAX_KEY_OPTIONS 68 133 | 134 | // ----------------------------- 135 | // For the Full Keyboard... 136 | // ----------------------------- 137 | #define KBD_KEY_SFT 1 138 | #define KBD_KEY_DEL 2 139 | #define KBD_KEY_CAPS 3 140 | #define KBD_KEY_CTL 4 141 | #define KBD_KEY_TAB 5 142 | #define KBD_KEY_CUP 6 143 | #define KBD_KEY_CRT 7 144 | #define KBD_KEY_CDN 8 145 | #define KBD_KEY_CLT 9 146 | #define KBD_KEY_CPY 10 147 | #define KBD_KEY_BSL 11 148 | #define KBD_KEY_RET 13 149 | 150 | #define KBD_KEY_F0 14 151 | #define KBD_KEY_F1 15 152 | #define KBD_KEY_F2 16 153 | #define KBD_KEY_F3 17 154 | #define KBD_KEY_F4 18 155 | #define KBD_KEY_F5 19 156 | #define KBD_KEY_F6 20 157 | #define KBD_KEY_F7 21 158 | #define KBD_KEY_F8 22 159 | #define KBD_KEY_F9 23 160 | #define KBD_KEY_FDOT 24 161 | #define KBD_KEY_FENT 25 162 | #define KBD_KEY_CLR 26 163 | 164 | #define KBD_KEY_ESC 27 165 | 166 | // What format is the input file? 167 | #define MODE_DSK 1 168 | #define MODE_CPR 2 169 | #define MODE_DAN 3 170 | #define MODE_SNA 4 171 | #define MODE_MEG 5 172 | 173 | #define WAITVBL swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); swiWaitForVBlank(); 174 | 175 | extern unsigned char BASIC_6128[16384]; 176 | extern unsigned char OS_6128[16384]; 177 | extern unsigned char AMSDOS[16384]; 178 | extern unsigned char PARADOS[16384]; 179 | extern unsigned char MEGALOAD[40377]; 180 | 181 | extern u8 DISK_IMAGE_BUFFER[]; 182 | 183 | extern u8 CRTC[]; 184 | extern u8 CRT_Idx; 185 | 186 | extern u32 scanline_count; 187 | 188 | extern u8 MMR; 189 | extern u8 RMR; 190 | extern u8 PENR; 191 | extern u8 UROM; 192 | 193 | extern u8 DAN_Zone0; 194 | extern u8 DAN_Zone1; 195 | extern u16 DAN_Config; 196 | 197 | extern u8 INK[17]; 198 | extern u32 border_color; 199 | extern u8 CRTC[0x20]; 200 | extern u8 CRT_Idx; 201 | extern u8 inks_changed; 202 | extern u16 refresh_tstates; 203 | extern u8 ink_map[256]; 204 | 205 | extern u32 HCC; 206 | extern u32 HSC; 207 | extern u32 VCC; 208 | extern u32 VSC; 209 | extern u32 VLC; 210 | extern u32 R52; 211 | extern u32 VTAC; 212 | extern u8 DISPEN; 213 | 214 | extern int current_ds_line; 215 | extern u32 vsync_plus_two; 216 | extern u32 r12_screen_offset; 217 | extern u8 vsync_off_count; 218 | extern u8 *cpc_ScreenPage; 219 | extern u16 escapeClause; 220 | extern u32 raster_counter; 221 | extern u8 vSyncSeen; 222 | extern u8 display_disable_in; 223 | 224 | extern u8 floppy_sound; 225 | extern u8 floppy_action; 226 | 227 | extern char initial_file[]; 228 | extern char initial_path[]; 229 | 230 | extern u8 amstrad_mode; 231 | extern u8 kbd_keys_pressed; 232 | extern u8 kbd_keys[12]; 233 | extern u16 emuFps; 234 | extern u16 emuActFrames; 235 | extern u16 timingFrames; 236 | extern u16 nds_key; 237 | extern u8 kbd_key; 238 | extern u16 vusCptVBL; 239 | extern u16 keyCoresp[MAX_KEY_OPTIONS]; 240 | extern u16 NDS_keyMap[]; 241 | extern u8 soundEmuPause; 242 | extern int bg0, bg1, bg0b, bg1b; 243 | extern u32 last_file_size; 244 | extern u8 b32K_Mode; 245 | 246 | extern u8 SugarDSChooseGame(u8 bDiskOnly); 247 | extern void CartLoad(void); 248 | extern void ConfigureMemory(void); 249 | extern void compute_pre_inked(u8 mode); 250 | extern void SugarDSGameOptions(bool bIsGlobal); 251 | extern void processDirectAudio(void); 252 | extern u8 crtc_render_screen_line(void); 253 | extern void crtc_reset(void); 254 | extern void crtc_r52_int(void); 255 | extern void BottomScreenOptions(void); 256 | extern void TopScreenOptions(void); 257 | extern void TopScreenImage(void); 258 | extern void BottomScreenKeyboard(void); 259 | extern void ReadFileCRCAndConfig(void); 260 | extern void DisplayStatusLine(bool bForce); 261 | extern void DiskInsert(char *filename, u8 bForceRead); 262 | extern void ResetAmstrad(void); 263 | extern void MaxBrightness(void); 264 | extern void debug_init(); 265 | extern void debug_save(); 266 | extern void debug_printf(const char * str, ...); 267 | 268 | #endif // _SUGARDS_H_ 269 | -------------------------------------------------------------------------------- /arm9/source/amsdos.h: -------------------------------------------------------------------------------- 1 | // SugarDS is Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 2 | // 3 | // Bits of pieces of this emulator have been glued and attached from a large number of sources - along with a healthy amount of 4 | // code by this author to pull it all together. Although it was hard to trace everythign to the original sources, I believe all 5 | // sources have released their material under the GNU General Public License and, as such, the SugarDS emulator follows suit. 6 | // 7 | // Previous contributions to this codebase: 8 | // 9 | // CrocoDS: CPC Emulator for the DS - Copyright (c) 2013 Miguel Vanhove (Kyuran) 10 | // Win-CPC: Amstrad CPC Emulator - Copyright (c) 2012 Ludovic Deplanque. 11 | // Caprice32: Amstrad CPC Emulator - Copyright (c) 1997-2004 Ulrich Doewich. 12 | // Arnold: Amstrad CPC Emulator - Copyright (c) 1995-2002, 2007 Andreas Micklei and Kevin Thacker 13 | // 14 | // As far as I'm concerned, you can use this code in whatever way suits you provided you continue to release the sources under 15 | // the original copyright notice (see below) which appeared to be the intention of all the pioneers who came before me. 16 | // 17 | // Original Copyright Notice 18 | // This program is free software; you can redistribute it and/or modify 19 | // it under the terms of the GNU General Public License as published by 20 | // the Free Software Foundation; either version 2 of the License, or 21 | // (at your option) any later version. 22 | // 23 | // This program is distributed in the hope that it will be useful, 24 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | // GNU General Public License for more details. 27 | // 28 | // You should have received a copy of the GNU General Public License 29 | // along with this program; if not, write to the Free Software 30 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 31 | 32 | #ifndef __AMSDOS_HEADER_INCLUDED__ 33 | #define __AMSDOS_HEADER_INCLUDED__ 34 | 35 | #ifndef _BOOL 36 | #define _BOOL 37 | typedef u8 BOOL; 38 | #endif 39 | 40 | 41 | /* BASIC parameters to describe an AMSDOS format. A CP/M based format */ 42 | typedef struct 43 | { 44 | int nFirstSectorId; /* id of first sector. it is assumed all sectors 45 | are numbered sequentially */ 46 | int nReservedTracks; /* number of complete reserved tracks */ 47 | int nSectorsPerTrack; /* number of sectors per track. It is assumed that 48 | all tracks have the same number of sectors */ 49 | } AMSDOS_FORMAT; 50 | 51 | typedef struct 52 | { 53 | int nTrack; /* physical track number */ 54 | int nSector; /* physical sector id */ 55 | int nSide; /* physical side */ 56 | } AMSDOS_TRACK_SECTOR_SIDE; 57 | 58 | typedef struct 59 | { 60 | unsigned char UserNumber; /* user number */ 61 | unsigned char Filename[8]; /* name part of filename */ 62 | unsigned char Extension[3]; /* extension part of filename */ 63 | unsigned char Extent; /* 16K extent of file */ 64 | unsigned char unused[2]; /* not used */ 65 | unsigned char LengthInRecords; /* length of this extent in records */ 66 | unsigned char Blocks[16]; /* blocks used by this directory entry; 8-bit or 16-bit values */ 67 | } amsdos_directory_entry; 68 | 69 | 70 | typedef struct 71 | { 72 | unsigned char Unused1; 73 | unsigned char Filename[8]; 74 | unsigned char Extension[3]; 75 | unsigned char Unused2[6]; 76 | unsigned char FileType; 77 | unsigned char LengthLow; 78 | unsigned char LengthHigh; 79 | unsigned char LocationLow; 80 | unsigned char LocationHigh; 81 | unsigned char FirstBlockFlag; 82 | unsigned char LogicalLengthLow; 83 | unsigned char LogicalLengthHigh; 84 | unsigned char ExecutionAddressLow; 85 | unsigned char ExecutionAddressHigh; 86 | unsigned char DataLengthLow; 87 | unsigned char DataLengthMid; 88 | unsigned char DataLengthHigh; 89 | unsigned char ChecksumLow; 90 | unsigned char ChecksumHigh; 91 | } AMSDOS_HEADER; 92 | 93 | unsigned int AMSDOS_CalculateChecksum(const unsigned char *pHeader); 94 | BOOL AMSDOS_HasAmsdosHeader(const unsigned char *pHeader); 95 | 96 | /* returns TRUE if the ch is a valid filename character, FALSE otherwise. 97 | A valid filename character is a character which can be typed by the user and one 98 | which, when used in a typed filename and is present on the disc, can then be loaded by 99 | AMSDOS */ 100 | BOOL AMSDOS_IsValidFilenameCharacter(char ch); 101 | 102 | 103 | BOOL AMSDOS_GetFilenameThatQualifiesForAutorun(amsdos_directory_entry *entry); 104 | 105 | enum 106 | { 107 | AUTORUN_OK, /* found a valid autorun method */ 108 | AUTORUN_NOT_POSSIBLE, /* auto-run is not possible; no suitable files found and |CPM will not work */ 109 | AUTORUN_TOO_MANY_POSSIBILITIES, /* too many files qualify for auto-run and it is not possible to 110 | identify the correct one */ 111 | AUTORUN_NO_FILES_QUALIFY, /* no files qualify for auto-run */ 112 | AUTORUN_FAILURE_READING_DIRECTORY, /* failed to read directory */ 113 | }; 114 | 115 | int AMSDOS_GenerateAutorunCommand(char *AutorunCommand); 116 | 117 | 118 | #endif 119 | -------------------------------------------------------------------------------- /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 | * SugarDS 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 | // For the jump instructions, the Cycle[] table builds in assuming the jump WILL be taken 26 | // which is true about 95% of the time. If the jump is not taken, we compensate TStates. 27 | // ---------------------------------------------------------------------------------------- 28 | case JR_NZ: if(CPU.AF.B.l&Z_FLAG) {CPU.TStates-=4; CPU.PC.W++;} else { M_JR; } break; 29 | case JR_NC: if(CPU.AF.B.l&C_FLAG) {CPU.TStates-=4; CPU.PC.W++;} else { M_JR; } break; 30 | case JR_Z: if(CPU.AF.B.l&Z_FLAG) { M_JR; } else {CPU.TStates-=4; CPU.PC.W++;} break; 31 | case JR_C: if(CPU.AF.B.l&C_FLAG) { M_JR; } else {CPU.TStates-=4; CPU.PC.W++;} break; 32 | 33 | case JP_NZ: if(CPU.AF.B.l&Z_FLAG) CPU.PC.W+=2; else { M_JP; } break; 34 | case JP_NC: if(CPU.AF.B.l&C_FLAG) CPU.PC.W+=2; else { M_JP; } break; 35 | case JP_PO: if(CPU.AF.B.l&P_FLAG) CPU.PC.W+=2; else { M_JP; } break; 36 | case JP_P: if(CPU.AF.B.l&S_FLAG) CPU.PC.W+=2; else { M_JP; } break; 37 | case JP_Z: if(CPU.AF.B.l&Z_FLAG) { M_JP; } else CPU.PC.W+=2; break; 38 | case JP_C: if(CPU.AF.B.l&C_FLAG) { M_JP; } else CPU.PC.W+=2; break; 39 | case JP_PE: if(CPU.AF.B.l&P_FLAG) { M_JP; } else CPU.PC.W+=2; break; 40 | case JP_M: if(CPU.AF.B.l&S_FLAG) { M_JP; } else CPU.PC.W+=2; break; 41 | 42 | // ----------------------------------------------------------------------------------------- 43 | // For the RET instructions, the Cycle[] table builds in assuming the return will NOT be 44 | // taken and so we must consume the additional cycles if the condition proves to be TRUE... 45 | // ----------------------------------------------------------------------------------------- 46 | case RET_NZ: if(!(CPU.AF.B.l&Z_FLAG)) { CPU.TStates+=8;M_RET; } break; 47 | case RET_NC: if(!(CPU.AF.B.l&C_FLAG)) { CPU.TStates+=8;M_RET; } break; 48 | case RET_PO: if(!(CPU.AF.B.l&P_FLAG)) { CPU.TStates+=8;M_RET; } break; 49 | case RET_P: if(!(CPU.AF.B.l&S_FLAG)) { CPU.TStates+=8;M_RET; } break; 50 | case RET_Z: if(CPU.AF.B.l&Z_FLAG) { CPU.TStates+=8;M_RET; } break; 51 | case RET_C: if(CPU.AF.B.l&C_FLAG) { CPU.TStates+=8;M_RET; } break; 52 | case RET_PE: if(CPU.AF.B.l&P_FLAG) { CPU.TStates+=8;M_RET; } break; 53 | case RET_M: if(CPU.AF.B.l&S_FLAG) { CPU.TStates+=8;M_RET; } break; 54 | 55 | case CALL_NZ: if(CPU.AF.B.l&Z_FLAG) CPU.PC.W+=2; else { CPU.TStates+=8;M_CALL; } break; 56 | case CALL_NC: if(CPU.AF.B.l&C_FLAG) CPU.PC.W+=2; else { CPU.TStates+=8;M_CALL; } break; 57 | case CALL_PO: if(CPU.AF.B.l&P_FLAG) CPU.PC.W+=2; else { CPU.TStates+=8;M_CALL; } break; 58 | case CALL_P: if(CPU.AF.B.l&S_FLAG) CPU.PC.W+=2; else { CPU.TStates+=8;M_CALL; } break; 59 | case CALL_Z: if(CPU.AF.B.l&Z_FLAG) { CPU.TStates+=8;M_CALL; } else CPU.PC.W+=2; break; 60 | case CALL_C: if(CPU.AF.B.l&C_FLAG) { CPU.TStates+=8;M_CALL; } else CPU.PC.W+=2; break; 61 | case CALL_PE: if(CPU.AF.B.l&P_FLAG) { CPU.TStates+=8;M_CALL; } else CPU.PC.W+=2; break; 62 | case CALL_M: if(CPU.AF.B.l&S_FLAG) { CPU.TStates+=8;M_CALL; } else CPU.PC.W+=2; break; 63 | 64 | case ADD_B: M_ADD(CPU.BC.B.h);break; 65 | case ADD_C: M_ADD(CPU.BC.B.l);break; 66 | case ADD_D: M_ADD(CPU.DE.B.h);break; 67 | case ADD_E: M_ADD(CPU.DE.B.l);break; 68 | case ADD_H: M_ADD(CPU.HL.B.h);break; 69 | case ADD_L: M_ADD(CPU.HL.B.l);break; 70 | case ADD_A: M_ADD(CPU.AF.B.h);break; 71 | case ADD_xHL: I=RdZ80(CPU.HL.W);M_ADD(I);break; 72 | case ADD_BYTE: I=OpZ80(CPU.PC.W++);M_ADD(I);break; 73 | 74 | case SUB_B: M_SUB(CPU.BC.B.h);break; 75 | case SUB_C: M_SUB(CPU.BC.B.l);break; 76 | case SUB_D: M_SUB(CPU.DE.B.h);break; 77 | case SUB_E: M_SUB(CPU.DE.B.l);break; 78 | case SUB_H: M_SUB(CPU.HL.B.h);break; 79 | case SUB_L: M_SUB(CPU.HL.B.l);break; 80 | case SUB_A: CPU.AF.B.h=0;CPU.AF.B.l=N_FLAG|Z_FLAG;break; 81 | case SUB_xHL: I=RdZ80(CPU.HL.W);M_SUB(I);break; 82 | case SUB_BYTE: I=OpZ80(CPU.PC.W++);M_SUB(I);break; 83 | 84 | case AND_B: M_AND(CPU.BC.B.h);break; 85 | case AND_C: M_AND(CPU.BC.B.l);break; 86 | case AND_D: M_AND(CPU.DE.B.h);break; 87 | case AND_E: M_AND(CPU.DE.B.l);break; 88 | case AND_H: M_AND(CPU.HL.B.h);break; 89 | case AND_L: M_AND(CPU.HL.B.l);break; 90 | case AND_A: M_AND(CPU.AF.B.h);break; 91 | case AND_xHL: I=RdZ80(CPU.HL.W);M_AND(I);break; 92 | case AND_BYTE: I=OpZ80(CPU.PC.W++);M_AND(I);break; 93 | 94 | case OR_B: M_OR(CPU.BC.B.h);break; 95 | case OR_C: M_OR(CPU.BC.B.l);break; 96 | case OR_D: M_OR(CPU.DE.B.h);break; 97 | case OR_E: M_OR(CPU.DE.B.l);break; 98 | case OR_H: M_OR(CPU.HL.B.h);break; 99 | case OR_L: M_OR(CPU.HL.B.l);break; 100 | case OR_A: M_OR(CPU.AF.B.h);break; 101 | case OR_xHL: I=RdZ80(CPU.HL.W);M_OR(I);break; 102 | case OR_BYTE: I=OpZ80(CPU.PC.W++);M_OR(I);break; 103 | 104 | case ADC_B: M_ADC(CPU.BC.B.h);break; 105 | case ADC_C: M_ADC(CPU.BC.B.l);break; 106 | case ADC_D: M_ADC(CPU.DE.B.h);break; 107 | case ADC_E: M_ADC(CPU.DE.B.l);break; 108 | case ADC_H: M_ADC(CPU.HL.B.h);break; 109 | case ADC_L: M_ADC(CPU.HL.B.l);break; 110 | case ADC_A: M_ADC(CPU.AF.B.h);break; 111 | case ADC_xHL: I=RdZ80(CPU.HL.W);M_ADC(I);break; 112 | case ADC_BYTE: I=OpZ80(CPU.PC.W++);M_ADC(I);break; 113 | 114 | case SBC_B: M_SBC(CPU.BC.B.h);break; 115 | case SBC_C: M_SBC(CPU.BC.B.l);break; 116 | case SBC_D: M_SBC(CPU.DE.B.h);break; 117 | case SBC_E: M_SBC(CPU.DE.B.l);break; 118 | case SBC_H: M_SBC(CPU.HL.B.h);break; 119 | case SBC_L: M_SBC(CPU.HL.B.l);break; 120 | case SBC_A: M_SBC(CPU.AF.B.h);break; 121 | case SBC_xHL: I=RdZ80(CPU.HL.W);M_SBC(I);break; 122 | case SBC_BYTE: I=OpZ80(CPU.PC.W++);M_SBC(I);break; 123 | 124 | case XOR_B: M_XOR(CPU.BC.B.h);break; 125 | case XOR_C: M_XOR(CPU.BC.B.l);break; 126 | case XOR_D: M_XOR(CPU.DE.B.h);break; 127 | case XOR_E: M_XOR(CPU.DE.B.l);break; 128 | case XOR_H: M_XOR(CPU.HL.B.h);break; 129 | case XOR_L: M_XOR(CPU.HL.B.l);break; 130 | case XOR_A: CPU.AF.B.h=0;CPU.AF.B.l=P_FLAG|Z_FLAG;break; 131 | case XOR_xHL: I=RdZ80(CPU.HL.W);M_XOR(I);break; 132 | case XOR_BYTE: I=OpZ80(CPU.PC.W++);M_XOR(I);break; 133 | 134 | case CP_B: M_CP(CPU.BC.B.h);break; 135 | case CP_C: M_CP(CPU.BC.B.l);break; 136 | case CP_D: M_CP(CPU.DE.B.h);break; 137 | case CP_E: M_CP(CPU.DE.B.l);break; 138 | case CP_H: M_CP(CPU.HL.B.h);break; 139 | case CP_L: M_CP(CPU.HL.B.l);break; 140 | case CP_A: CPU.AF.B.l=N_FLAG|Z_FLAG;break; 141 | case CP_xHL: I=RdZ80(CPU.HL.W);M_CP(I);break; 142 | case CP_BYTE: I=OpZ80(CPU.PC.W++);M_CP(I);break; 143 | 144 | case LD_BC_WORD: M_LDWORD(BC);break; 145 | case LD_DE_WORD: M_LDWORD(DE);break; 146 | case LD_HL_WORD: M_LDWORD(HL);break; 147 | case LD_SP_WORD: M_LDWORD(SP);break; 148 | 149 | case LD_PC_HL: CPU.PC.W=CPU.HL.W;JumpZ80(CPU.PC.W);break; 150 | case LD_SP_HL: CPU.SP.W=CPU.HL.W;break; 151 | case LD_A_xBC: CPU.AF.B.h=RdZ80(CPU.BC.W);break; 152 | case LD_A_xDE: CPU.AF.B.h=RdZ80(CPU.DE.W);break; 153 | 154 | case ADD_HL_BC: M_ADDW(HL,BC);break; 155 | case ADD_HL_DE: M_ADDW(HL,DE);break; 156 | case ADD_HL_HL: M_ADDW(HL,HL);break; 157 | case ADD_HL_SP: M_ADDW(HL,SP);break; 158 | 159 | case DEC_BC: CPU.BC.W--;break; 160 | case DEC_DE: CPU.DE.W--;break; 161 | case DEC_HL: CPU.HL.W--;break; 162 | case DEC_SP: CPU.SP.W--;break; 163 | 164 | case INC_BC: CPU.BC.W++;break; 165 | case INC_DE: CPU.DE.W++;break; 166 | case INC_HL: CPU.HL.W++;break; 167 | case INC_SP: CPU.SP.W++;break; 168 | 169 | case DEC_B: M_DEC(CPU.BC.B.h);break; 170 | case DEC_C: M_DEC(CPU.BC.B.l);break; 171 | case DEC_D: M_DEC(CPU.DE.B.h);break; 172 | case DEC_E: M_DEC(CPU.DE.B.l);break; 173 | case DEC_H: M_DEC(CPU.HL.B.h);break; 174 | case DEC_L: M_DEC(CPU.HL.B.l);break; 175 | case DEC_A: M_DEC(CPU.AF.B.h);break; 176 | case DEC_xHL: I=RdZ80(CPU.HL.W);M_DEC(I);WrZ80(CPU.HL.W,I);break; 177 | 178 | case INC_B: M_INC(CPU.BC.B.h);break; 179 | case INC_C: M_INC(CPU.BC.B.l);break; 180 | case INC_D: M_INC(CPU.DE.B.h);break; 181 | case INC_E: M_INC(CPU.DE.B.l);break; 182 | case INC_H: M_INC(CPU.HL.B.h);break; 183 | case INC_L: M_INC(CPU.HL.B.l);break; 184 | case INC_A: M_INC(CPU.AF.B.h);break; 185 | case INC_xHL: I=RdZ80(CPU.HL.W);M_INC(I);WrZ80(CPU.HL.W,I);break; 186 | 187 | case RLCA: 188 | I=CPU.AF.B.h&0x80? C_FLAG:0; 189 | CPU.AF.B.h=(CPU.AF.B.h<<1)|I; 190 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 191 | break; 192 | case RLA: 193 | I=CPU.AF.B.h&0x80? C_FLAG:0; 194 | CPU.AF.B.h=(CPU.AF.B.h<<1)|(CPU.AF.B.l&C_FLAG); 195 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 196 | break; 197 | case RRCA: 198 | I=CPU.AF.B.h&0x01; 199 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(I? 0x80:0); 200 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 201 | break; 202 | case RRA: 203 | I=CPU.AF.B.h&0x01; 204 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(CPU.AF.B.l&C_FLAG? 0x80:0); 205 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 206 | break; 207 | 208 | case RST00: M_RST(0x0000);break; 209 | case RST08: M_RST(0x0008);break; 210 | case RST10: M_RST(0x0010);break; 211 | case RST18: M_RST(0x0018);break; 212 | case RST20: M_RST(0x0020);break; 213 | case RST28: M_RST(0x0028);break; 214 | case RST30: M_RST(0x0030);break; 215 | case RST38: M_RST(0x0038);break; 216 | 217 | case PUSH_BC: M_PUSH(BC);break; 218 | case PUSH_DE: M_PUSH(DE);break; 219 | case PUSH_HL: M_PUSH(HL);break; 220 | case PUSH_AF: M_PUSH(AF);break; 221 | 222 | case POP_BC: M_POP(BC);break; 223 | case POP_DE: M_POP(DE);break; 224 | case POP_HL: M_POP(HL);break; 225 | case POP_AF: M_POP(AF);break; 226 | 227 | case DJNZ: 228 | if(--CPU.BC.B.h) { M_JR; } else {CPU.TStates-=4; CPU.PC.W++;} break; 229 | 230 | case JP: M_JP;break; 231 | case JR: M_JR;break; 232 | case CALL: M_CALL;break; 233 | case RET: M_RET;break; 234 | case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break; 235 | case CPL: CPU.AF.B.h=~CPU.AF.B.h;S(N_FLAG|H_FLAG);break; 236 | case NOP: break; 237 | case OUTA: I=OpZ80(CPU.PC.W++);OutZ80(I|(CPU.AF.W&0xFF00),CPU.AF.B.h);break; 238 | case INA: I=OpZ80(CPU.PC.W++);CPU.AF.B.h=InZ80(I|(CPU.AF.W&0xFF00));break; 239 | 240 | case HALT: 241 | CPU.PC.W--; 242 | CPU.IFF|=IFF_HALT; 243 | break; 244 | 245 | case DI: 246 | CPU.IFF&=~(IFF_1|IFF_2|IFF_EI); 247 | break; 248 | 249 | case EI: 250 | if(!(CPU.IFF&(IFF_1|IFF_EI))) 251 | { 252 | CPU.IFF|=IFF_2|IFF_EI; 253 | EI_Enable(); 254 | } 255 | break; 256 | 257 | case CCF: 258 | CPU.AF.B.l^=C_FLAG;R(N_FLAG|H_FLAG); 259 | CPU.AF.B.l|=CPU.AF.B.l&C_FLAG? 0:H_FLAG; 260 | break; 261 | 262 | case EXX: 263 | J.W=CPU.BC.W;CPU.BC.W=CPU.BC1.W;CPU.BC1.W=J.W; 264 | J.W=CPU.DE.W;CPU.DE.W=CPU.DE1.W;CPU.DE1.W=J.W; 265 | J.W=CPU.HL.W;CPU.HL.W=CPU.HL1.W;CPU.HL1.W=J.W; 266 | break; 267 | 268 | case EX_DE_HL: J.W=CPU.DE.W;CPU.DE.W=CPU.HL.W;CPU.HL.W=J.W;break; 269 | case EX_AF_AF: J.W=CPU.AF.W;CPU.AF.W=CPU.AF1.W;CPU.AF1.W=J.W;break; 270 | 271 | case LD_B_B: CPU.BC.B.h=CPU.BC.B.h;break; 272 | case LD_C_B: CPU.BC.B.l=CPU.BC.B.h;break; 273 | case LD_D_B: CPU.DE.B.h=CPU.BC.B.h;break; 274 | case LD_E_B: CPU.DE.B.l=CPU.BC.B.h;break; 275 | case LD_H_B: CPU.HL.B.h=CPU.BC.B.h;break; 276 | case LD_L_B: CPU.HL.B.l=CPU.BC.B.h;break; 277 | case LD_A_B: CPU.AF.B.h=CPU.BC.B.h;break; 278 | case LD_xHL_B: WrZ80(CPU.HL.W,CPU.BC.B.h);break; 279 | 280 | case LD_B_C: CPU.BC.B.h=CPU.BC.B.l;break; 281 | case LD_C_C: CPU.BC.B.l=CPU.BC.B.l;break; 282 | case LD_D_C: CPU.DE.B.h=CPU.BC.B.l;break; 283 | case LD_E_C: CPU.DE.B.l=CPU.BC.B.l;break; 284 | case LD_H_C: CPU.HL.B.h=CPU.BC.B.l;break; 285 | case LD_L_C: CPU.HL.B.l=CPU.BC.B.l;break; 286 | case LD_A_C: CPU.AF.B.h=CPU.BC.B.l;break; 287 | case LD_xHL_C: WrZ80(CPU.HL.W,CPU.BC.B.l);break; 288 | 289 | case LD_B_D: CPU.BC.B.h=CPU.DE.B.h;break; 290 | case LD_C_D: CPU.BC.B.l=CPU.DE.B.h;break; 291 | case LD_D_D: CPU.DE.B.h=CPU.DE.B.h;break; 292 | case LD_E_D: CPU.DE.B.l=CPU.DE.B.h;break; 293 | case LD_H_D: CPU.HL.B.h=CPU.DE.B.h;break; 294 | case LD_L_D: CPU.HL.B.l=CPU.DE.B.h;break; 295 | case LD_A_D: CPU.AF.B.h=CPU.DE.B.h;break; 296 | case LD_xHL_D: WrZ80(CPU.HL.W,CPU.DE.B.h);break; 297 | 298 | case LD_B_E: CPU.BC.B.h=CPU.DE.B.l;break; 299 | case LD_C_E: CPU.BC.B.l=CPU.DE.B.l;break; 300 | case LD_D_E: CPU.DE.B.h=CPU.DE.B.l;break; 301 | case LD_E_E: CPU.DE.B.l=CPU.DE.B.l;break; 302 | case LD_H_E: CPU.HL.B.h=CPU.DE.B.l;break; 303 | case LD_L_E: CPU.HL.B.l=CPU.DE.B.l;break; 304 | case LD_A_E: CPU.AF.B.h=CPU.DE.B.l;break; 305 | case LD_xHL_E: WrZ80(CPU.HL.W,CPU.DE.B.l);break; 306 | 307 | case LD_B_H: CPU.BC.B.h=CPU.HL.B.h;break; 308 | case LD_C_H: CPU.BC.B.l=CPU.HL.B.h;break; 309 | case LD_D_H: CPU.DE.B.h=CPU.HL.B.h;break; 310 | case LD_E_H: CPU.DE.B.l=CPU.HL.B.h;break; 311 | case LD_H_H: CPU.HL.B.h=CPU.HL.B.h;break; 312 | case LD_L_H: CPU.HL.B.l=CPU.HL.B.h;break; 313 | case LD_A_H: CPU.AF.B.h=CPU.HL.B.h;break; 314 | case LD_xHL_H: WrZ80(CPU.HL.W,CPU.HL.B.h);break; 315 | 316 | case LD_B_L: CPU.BC.B.h=CPU.HL.B.l;break; 317 | case LD_C_L: CPU.BC.B.l=CPU.HL.B.l;break; 318 | case LD_D_L: CPU.DE.B.h=CPU.HL.B.l;break; 319 | case LD_E_L: CPU.DE.B.l=CPU.HL.B.l;break; 320 | case LD_H_L: CPU.HL.B.h=CPU.HL.B.l;break; 321 | case LD_L_L: CPU.HL.B.l=CPU.HL.B.l;break; 322 | case LD_A_L: CPU.AF.B.h=CPU.HL.B.l;break; 323 | case LD_xHL_L: WrZ80(CPU.HL.W,CPU.HL.B.l);break; 324 | 325 | case LD_B_A: CPU.BC.B.h=CPU.AF.B.h;break; 326 | case LD_C_A: CPU.BC.B.l=CPU.AF.B.h;break; 327 | case LD_D_A: CPU.DE.B.h=CPU.AF.B.h;break; 328 | case LD_E_A: CPU.DE.B.l=CPU.AF.B.h;break; 329 | case LD_H_A: CPU.HL.B.h=CPU.AF.B.h;break; 330 | case LD_L_A: CPU.HL.B.l=CPU.AF.B.h;break; 331 | case LD_A_A: CPU.AF.B.h=CPU.AF.B.h;break; 332 | case LD_xHL_A: WrZ80(CPU.HL.W,CPU.AF.B.h);break; 333 | 334 | case LD_xBC_A: WrZ80(CPU.BC.W,CPU.AF.B.h);break; 335 | case LD_xDE_A: WrZ80(CPU.DE.W,CPU.AF.B.h);break; 336 | 337 | case LD_B_xHL: CPU.BC.B.h=RdZ80(CPU.HL.W);break; 338 | case LD_C_xHL: CPU.BC.B.l=RdZ80(CPU.HL.W);break; 339 | case LD_D_xHL: CPU.DE.B.h=RdZ80(CPU.HL.W);break; 340 | case LD_E_xHL: CPU.DE.B.l=RdZ80(CPU.HL.W);break; 341 | case LD_H_xHL: CPU.HL.B.h=RdZ80(CPU.HL.W);break; 342 | case LD_L_xHL: CPU.HL.B.l=RdZ80(CPU.HL.W);break; 343 | case LD_A_xHL: CPU.AF.B.h=RdZ80(CPU.HL.W);break; 344 | 345 | case LD_B_BYTE: CPU.BC.B.h=OpZ80(CPU.PC.W++);break; 346 | case LD_C_BYTE: CPU.BC.B.l=OpZ80(CPU.PC.W++);break; 347 | case LD_D_BYTE: CPU.DE.B.h=OpZ80(CPU.PC.W++);break; 348 | case LD_E_BYTE: CPU.DE.B.l=OpZ80(CPU.PC.W++);break; 349 | case LD_H_BYTE: CPU.HL.B.h=OpZ80(CPU.PC.W++);break; 350 | case LD_L_BYTE: CPU.HL.B.l=OpZ80(CPU.PC.W++);break; 351 | case LD_xHL_BYTE: WrZ80(CPU.HL.W,OpZ80(CPU.PC.W++));break; 352 | 353 | case LD_A_BYTE: 354 | CPU.AF.B.h=OpZ80(CPU.PC.W++); 355 | break; 356 | 357 | case LD_xWORD_HL: 358 | J.B.l=OpZ80(CPU.PC.W++); 359 | J.B.h=OpZ80(CPU.PC.W++); 360 | WrZ80(J.W++,CPU.HL.B.l); 361 | WrZ80(J.W,CPU.HL.B.h); 362 | break; 363 | 364 | case LD_HL_xWORD: 365 | J.B.l=OpZ80(CPU.PC.W++); 366 | J.B.h=OpZ80(CPU.PC.W++); 367 | CPU.HL.B.l=RdZ80(J.W++); 368 | CPU.HL.B.h=RdZ80(J.W); 369 | break; 370 | 371 | case LD_A_xWORD: 372 | J.B.l=OpZ80(CPU.PC.W++); 373 | J.B.h=OpZ80(CPU.PC.W++); 374 | CPU.AF.B.h=RdZ80(J.W); 375 | break; 376 | 377 | case LD_xWORD_A: 378 | J.B.l=OpZ80(CPU.PC.W++); 379 | J.B.h=OpZ80(CPU.PC.W++); 380 | WrZ80(J.W,CPU.AF.B.h); 381 | break; 382 | 383 | case EX_HL_xSP: 384 | J.B.l=RdZ80(CPU.SP.W);WrZ80(CPU.SP.W++,CPU.HL.B.l); 385 | J.B.h=RdZ80(CPU.SP.W);WrZ80(CPU.SP.W--,CPU.HL.B.h); 386 | CPU.HL.W=J.W; 387 | break; 388 | 389 | case DAA: 390 | J.W=CPU.AF.B.h; 391 | if(CPU.AF.B.l&C_FLAG) J.W|=256; 392 | if(CPU.AF.B.l&H_FLAG) J.W|=512; 393 | if(CPU.AF.B.l&N_FLAG) J.W|=1024; 394 | CPU.AF.W=DAATable[J.W]; 395 | break; 396 | 397 | default: 398 | if(CPU.TrapBadOps) Trap_Bad_Ops("Z80", I, CPU.PC.W-1); 399 | break; 400 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesCB.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SugarDS 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; 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_xHL: I=RdZ80(CPU.HL.W);M_RLC(I);WrZ80(CPU.HL.W,I);break; 28 | case RLC_A: M_RLC(CPU.AF.B.h);break; 29 | 30 | case RRC_B: M_RRC(CPU.BC.B.h);break; case RRC_C: M_RRC(CPU.BC.B.l);break; 31 | case RRC_D: M_RRC(CPU.DE.B.h);break; case RRC_E: M_RRC(CPU.DE.B.l);break; 32 | case RRC_H: M_RRC(CPU.HL.B.h);break; case RRC_L: M_RRC(CPU.HL.B.l);break; 33 | case RRC_xHL: I=RdZ80(CPU.HL.W);M_RRC(I);WrZ80(CPU.HL.W,I);break; 34 | case RRC_A: M_RRC(CPU.AF.B.h);break; 35 | 36 | case RL_B: M_RL(CPU.BC.B.h);break; case RL_C: M_RL(CPU.BC.B.l);break; 37 | case RL_D: M_RL(CPU.DE.B.h);break; case RL_E: M_RL(CPU.DE.B.l);break; 38 | case RL_H: M_RL(CPU.HL.B.h);break; case RL_L: M_RL(CPU.HL.B.l);break; 39 | case RL_xHL: I=RdZ80(CPU.HL.W);M_RL(I);WrZ80(CPU.HL.W,I);break; 40 | case RL_A: M_RL(CPU.AF.B.h);break; 41 | 42 | case RR_B: M_RR(CPU.BC.B.h);break; case RR_C: M_RR(CPU.BC.B.l);break; 43 | case RR_D: M_RR(CPU.DE.B.h);break; case RR_E: M_RR(CPU.DE.B.l);break; 44 | case RR_H: M_RR(CPU.HL.B.h);break; case RR_L: M_RR(CPU.HL.B.l);break; 45 | case RR_xHL: I=RdZ80(CPU.HL.W);M_RR(I);WrZ80(CPU.HL.W,I);break; 46 | case RR_A: M_RR(CPU.AF.B.h);break; 47 | 48 | case SLA_B: M_SLA(CPU.BC.B.h);break; case SLA_C: M_SLA(CPU.BC.B.l);break; 49 | case SLA_D: M_SLA(CPU.DE.B.h);break; case SLA_E: M_SLA(CPU.DE.B.l);break; 50 | case SLA_H: M_SLA(CPU.HL.B.h);break; case SLA_L: M_SLA(CPU.HL.B.l);break; 51 | case SLA_xHL: I=RdZ80(CPU.HL.W);M_SLA(I);WrZ80(CPU.HL.W,I);break; 52 | case SLA_A: M_SLA(CPU.AF.B.h);break; 53 | 54 | case SRA_B: M_SRA(CPU.BC.B.h);break; case SRA_C: M_SRA(CPU.BC.B.l);break; 55 | case SRA_D: M_SRA(CPU.DE.B.h);break; case SRA_E: M_SRA(CPU.DE.B.l);break; 56 | case SRA_H: M_SRA(CPU.HL.B.h);break; case SRA_L: M_SRA(CPU.HL.B.l);break; 57 | case SRA_xHL: I=RdZ80(CPU.HL.W);M_SRA(I);WrZ80(CPU.HL.W,I);break; 58 | case SRA_A: M_SRA(CPU.AF.B.h);break; 59 | 60 | case SLL_B: M_SLL(CPU.BC.B.h);break; case SLL_C: M_SLL(CPU.BC.B.l);break; 61 | case SLL_D: M_SLL(CPU.DE.B.h);break; case SLL_E: M_SLL(CPU.DE.B.l);break; 62 | case SLL_H: M_SLL(CPU.HL.B.h);break; case SLL_L: M_SLL(CPU.HL.B.l);break; 63 | case SLL_xHL: I=RdZ80(CPU.HL.W);M_SLL(I);WrZ80(CPU.HL.W,I);break; 64 | case SLL_A: M_SLL(CPU.AF.B.h);break; 65 | 66 | case SRL_B: M_SRL(CPU.BC.B.h);break; case SRL_C: M_SRL(CPU.BC.B.l);break; 67 | case SRL_D: M_SRL(CPU.DE.B.h);break; case SRL_E: M_SRL(CPU.DE.B.l);break; 68 | case SRL_H: M_SRL(CPU.HL.B.h);break; case SRL_L: M_SRL(CPU.HL.B.l);break; 69 | case SRL_xHL: I=RdZ80(CPU.HL.W);M_SRL(I);WrZ80(CPU.HL.W,I);break; 70 | case SRL_A: M_SRL(CPU.AF.B.h);break; 71 | 72 | case BIT0_B: M_BIT(0,CPU.BC.B.h);break; case BIT0_C: M_BIT(0,CPU.BC.B.l);break; 73 | case BIT0_D: M_BIT(0,CPU.DE.B.h);break; case BIT0_E: M_BIT(0,CPU.DE.B.l);break; 74 | case BIT0_H: M_BIT(0,CPU.HL.B.h);break; case BIT0_L: M_BIT(0,CPU.HL.B.l);break; 75 | case BIT0_xHL: I=RdZ80(CPU.HL.W);M_BIT(0,I);break; 76 | case BIT0_A: M_BIT(0,CPU.AF.B.h);break; 77 | 78 | case BIT1_B: M_BIT(1,CPU.BC.B.h);break; case BIT1_C: M_BIT(1,CPU.BC.B.l);break; 79 | case BIT1_D: M_BIT(1,CPU.DE.B.h);break; case BIT1_E: M_BIT(1,CPU.DE.B.l);break; 80 | case BIT1_H: M_BIT(1,CPU.HL.B.h);break; case BIT1_L: M_BIT(1,CPU.HL.B.l);break; 81 | case BIT1_xHL: I=RdZ80(CPU.HL.W);M_BIT(1,I);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; 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_xHL: I=RdZ80(CPU.HL.W);M_BIT(2,I);break; 88 | case BIT2_A: M_BIT(2,CPU.AF.B.h);break; 89 | 90 | case BIT3_B: M_BIT(3,CPU.BC.B.h);break; case BIT3_C: M_BIT(3,CPU.BC.B.l);break; 91 | case BIT3_D: M_BIT(3,CPU.DE.B.h);break; case BIT3_E: M_BIT(3,CPU.DE.B.l);break; 92 | case BIT3_H: M_BIT(3,CPU.HL.B.h);break; case BIT3_L: M_BIT(3,CPU.HL.B.l);break; 93 | case BIT3_xHL: I=RdZ80(CPU.HL.W);M_BIT(3,I);break; 94 | case BIT3_A: M_BIT(3,CPU.AF.B.h);break; 95 | 96 | case BIT4_B: M_BIT(4,CPU.BC.B.h);break; case BIT4_C: M_BIT(4,CPU.BC.B.l);break; 97 | case BIT4_D: M_BIT(4,CPU.DE.B.h);break; case BIT4_E: M_BIT(4,CPU.DE.B.l);break; 98 | case BIT4_H: M_BIT(4,CPU.HL.B.h);break; case BIT4_L: M_BIT(4,CPU.HL.B.l);break; 99 | case BIT4_xHL: I=RdZ80(CPU.HL.W);M_BIT(4,I);break; 100 | case BIT4_A: M_BIT(4,CPU.AF.B.h);break; 101 | 102 | case BIT5_B: M_BIT(5,CPU.BC.B.h);break; case BIT5_C: M_BIT(5,CPU.BC.B.l);break; 103 | case BIT5_D: M_BIT(5,CPU.DE.B.h);break; case BIT5_E: M_BIT(5,CPU.DE.B.l);break; 104 | case BIT5_H: M_BIT(5,CPU.HL.B.h);break; case BIT5_L: M_BIT(5,CPU.HL.B.l);break; 105 | case BIT5_xHL: I=RdZ80(CPU.HL.W);M_BIT(5,I);break; 106 | case BIT5_A: M_BIT(5,CPU.AF.B.h);break; 107 | 108 | case BIT6_B: M_BIT(6,CPU.BC.B.h);break; case BIT6_C: M_BIT(6,CPU.BC.B.l);break; 109 | case BIT6_D: M_BIT(6,CPU.DE.B.h);break; case BIT6_E: M_BIT(6,CPU.DE.B.l);break; 110 | case BIT6_H: M_BIT(6,CPU.HL.B.h);break; case BIT6_L: M_BIT(6,CPU.HL.B.l);break; 111 | case BIT6_xHL: I=RdZ80(CPU.HL.W);M_BIT(6,I);break; 112 | case BIT6_A: M_BIT(6,CPU.AF.B.h);break; 113 | 114 | case BIT7_B: M_BIT(7,CPU.BC.B.h);break; case BIT7_C: M_BIT(7,CPU.BC.B.l);break; 115 | case BIT7_D: M_BIT(7,CPU.DE.B.h);break; case BIT7_E: M_BIT(7,CPU.DE.B.l);break; 116 | case BIT7_H: M_BIT(7,CPU.HL.B.h);break; case BIT7_L: M_BIT(7,CPU.HL.B.l);break; 117 | case BIT7_xHL: I=RdZ80(CPU.HL.W);M_BIT(7,I);break; 118 | case BIT7_A: M_BIT(7,CPU.AF.B.h);break; 119 | 120 | case RES0_B: M_RES(0,CPU.BC.B.h);break; case RES0_C: M_RES(0,CPU.BC.B.l);break; 121 | case RES0_D: M_RES(0,CPU.DE.B.h);break; case RES0_E: M_RES(0,CPU.DE.B.l);break; 122 | case RES0_H: M_RES(0,CPU.HL.B.h);break; case RES0_L: M_RES(0,CPU.HL.B.l);break; 123 | case RES0_xHL: I=RdZ80(CPU.HL.W);M_RES(0,I);WrZ80(CPU.HL.W,I);break; 124 | case RES0_A: M_RES(0,CPU.AF.B.h);break; 125 | 126 | case RES1_B: M_RES(1,CPU.BC.B.h);break; case RES1_C: M_RES(1,CPU.BC.B.l);break; 127 | case RES1_D: M_RES(1,CPU.DE.B.h);break; case RES1_E: M_RES(1,CPU.DE.B.l);break; 128 | case RES1_H: M_RES(1,CPU.HL.B.h);break; case RES1_L: M_RES(1,CPU.HL.B.l);break; 129 | case RES1_xHL: I=RdZ80(CPU.HL.W);M_RES(1,I);WrZ80(CPU.HL.W,I);break; 130 | case RES1_A: M_RES(1,CPU.AF.B.h);break; 131 | 132 | case RES2_B: M_RES(2,CPU.BC.B.h);break; case RES2_C: M_RES(2,CPU.BC.B.l);break; 133 | case RES2_D: M_RES(2,CPU.DE.B.h);break; case RES2_E: M_RES(2,CPU.DE.B.l);break; 134 | case RES2_H: M_RES(2,CPU.HL.B.h);break; case RES2_L: M_RES(2,CPU.HL.B.l);break; 135 | case RES2_xHL: I=RdZ80(CPU.HL.W);M_RES(2,I);WrZ80(CPU.HL.W,I);break; 136 | case RES2_A: M_RES(2,CPU.AF.B.h);break; 137 | 138 | case RES3_B: M_RES(3,CPU.BC.B.h);break; case RES3_C: M_RES(3,CPU.BC.B.l);break; 139 | case RES3_D: M_RES(3,CPU.DE.B.h);break; case RES3_E: M_RES(3,CPU.DE.B.l);break; 140 | case RES3_H: M_RES(3,CPU.HL.B.h);break; case RES3_L: M_RES(3,CPU.HL.B.l);break; 141 | case RES3_xHL: I=RdZ80(CPU.HL.W);M_RES(3,I);WrZ80(CPU.HL.W,I);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; 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_xHL: I=RdZ80(CPU.HL.W);M_RES(4,I);WrZ80(CPU.HL.W,I);break; 148 | case RES4_A: M_RES(4,CPU.AF.B.h);break; 149 | 150 | case RES5_B: M_RES(5,CPU.BC.B.h);break; case RES5_C: M_RES(5,CPU.BC.B.l);break; 151 | case RES5_D: M_RES(5,CPU.DE.B.h);break; case RES5_E: M_RES(5,CPU.DE.B.l);break; 152 | case RES5_H: M_RES(5,CPU.HL.B.h);break; case RES5_L: M_RES(5,CPU.HL.B.l);break; 153 | case RES5_xHL: I=RdZ80(CPU.HL.W);M_RES(5,I);WrZ80(CPU.HL.W,I);break; 154 | case RES5_A: M_RES(5,CPU.AF.B.h);break; 155 | 156 | case RES6_B: M_RES(6,CPU.BC.B.h);break; case RES6_C: M_RES(6,CPU.BC.B.l);break; 157 | case RES6_D: M_RES(6,CPU.DE.B.h);break; case RES6_E: M_RES(6,CPU.DE.B.l);break; 158 | case RES6_H: M_RES(6,CPU.HL.B.h);break; case RES6_L: M_RES(6,CPU.HL.B.l);break; 159 | case RES6_xHL: I=RdZ80(CPU.HL.W);M_RES(6,I);WrZ80(CPU.HL.W,I);break; 160 | case RES6_A: M_RES(6,CPU.AF.B.h);break; 161 | 162 | case RES7_B: M_RES(7,CPU.BC.B.h);break; case RES7_C: M_RES(7,CPU.BC.B.l);break; 163 | case RES7_D: M_RES(7,CPU.DE.B.h);break; case RES7_E: M_RES(7,CPU.DE.B.l);break; 164 | case RES7_H: M_RES(7,CPU.HL.B.h);break; case RES7_L: M_RES(7,CPU.HL.B.l);break; 165 | case RES7_xHL: I=RdZ80(CPU.HL.W);M_RES(7,I);WrZ80(CPU.HL.W,I);break; 166 | case RES7_A: M_RES(7,CPU.AF.B.h);break; 167 | 168 | case SET0_B: M_SET(0,CPU.BC.B.h);break; case SET0_C: M_SET(0,CPU.BC.B.l);break; 169 | case SET0_D: M_SET(0,CPU.DE.B.h);break; case SET0_E: M_SET(0,CPU.DE.B.l);break; 170 | case SET0_H: M_SET(0,CPU.HL.B.h);break; case SET0_L: M_SET(0,CPU.HL.B.l);break; 171 | case SET0_xHL: I=RdZ80(CPU.HL.W);M_SET(0,I);WrZ80(CPU.HL.W,I);break; 172 | case SET0_A: M_SET(0,CPU.AF.B.h);break; 173 | 174 | case SET1_B: M_SET(1,CPU.BC.B.h);break; case SET1_C: M_SET(1,CPU.BC.B.l);break; 175 | case SET1_D: M_SET(1,CPU.DE.B.h);break; case SET1_E: M_SET(1,CPU.DE.B.l);break; 176 | case SET1_H: M_SET(1,CPU.HL.B.h);break; case SET1_L: M_SET(1,CPU.HL.B.l);break; 177 | case SET1_xHL: I=RdZ80(CPU.HL.W);M_SET(1,I);WrZ80(CPU.HL.W,I);break; 178 | case SET1_A: M_SET(1,CPU.AF.B.h);break; 179 | 180 | case SET2_B: M_SET(2,CPU.BC.B.h);break; case SET2_C: M_SET(2,CPU.BC.B.l);break; 181 | case SET2_D: M_SET(2,CPU.DE.B.h);break; case SET2_E: M_SET(2,CPU.DE.B.l);break; 182 | case SET2_H: M_SET(2,CPU.HL.B.h);break; case SET2_L: M_SET(2,CPU.HL.B.l);break; 183 | case SET2_xHL: I=RdZ80(CPU.HL.W);M_SET(2,I);WrZ80(CPU.HL.W,I);break; 184 | case SET2_A: M_SET(2,CPU.AF.B.h);break; 185 | 186 | case SET3_B: M_SET(3,CPU.BC.B.h);break; case SET3_C: M_SET(3,CPU.BC.B.l);break; 187 | case SET3_D: M_SET(3,CPU.DE.B.h);break; case SET3_E: M_SET(3,CPU.DE.B.l);break; 188 | case SET3_H: M_SET(3,CPU.HL.B.h);break; case SET3_L: M_SET(3,CPU.HL.B.l);break; 189 | case SET3_xHL: I=RdZ80(CPU.HL.W);M_SET(3,I);WrZ80(CPU.HL.W,I);break; 190 | case SET3_A: M_SET(3,CPU.AF.B.h);break; 191 | 192 | case SET4_B: M_SET(4,CPU.BC.B.h);break; case SET4_C: M_SET(4,CPU.BC.B.l);break; 193 | case SET4_D: M_SET(4,CPU.DE.B.h);break; case SET4_E: M_SET(4,CPU.DE.B.l);break; 194 | case SET4_H: M_SET(4,CPU.HL.B.h);break; case SET4_L: M_SET(4,CPU.HL.B.l);break; 195 | case SET4_xHL: I=RdZ80(CPU.HL.W);M_SET(4,I);WrZ80(CPU.HL.W,I);break; 196 | case SET4_A: M_SET(4,CPU.AF.B.h);break; 197 | 198 | case SET5_B: M_SET(5,CPU.BC.B.h);break; case SET5_C: M_SET(5,CPU.BC.B.l);break; 199 | case SET5_D: M_SET(5,CPU.DE.B.h);break; case SET5_E: M_SET(5,CPU.DE.B.l);break; 200 | case SET5_H: M_SET(5,CPU.HL.B.h);break; case SET5_L: M_SET(5,CPU.HL.B.l);break; 201 | case SET5_xHL: I=RdZ80(CPU.HL.W);M_SET(5,I);WrZ80(CPU.HL.W,I);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; 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_xHL: I=RdZ80(CPU.HL.W);M_SET(6,I);WrZ80(CPU.HL.W,I);break; 208 | case SET6_A: M_SET(6,CPU.AF.B.h);break; 209 | 210 | case SET7_B: M_SET(7,CPU.BC.B.h);break; case SET7_C: M_SET(7,CPU.BC.B.l);break; 211 | case SET7_D: M_SET(7,CPU.DE.B.h);break; case SET7_E: M_SET(7,CPU.DE.B.l);break; 212 | case SET7_H: M_SET(7,CPU.HL.B.h);break; case SET7_L: M_SET(7,CPU.HL.B.l);break; 213 | case SET7_xHL: I=RdZ80(CPU.HL.W);M_SET(7,I);WrZ80(CPU.HL.W,I);break; 214 | case SET7_A: M_SET(7,CPU.AF.B.h);break; 215 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesED.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SugarDS 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);break; 29 | case ADC_HL_DE: M_ADCW(DE);break; 30 | case ADC_HL_HL: M_ADCW(HL);break; 31 | case ADC_HL_SP: M_ADCW(SP);break; 32 | 33 | case SBC_HL_BC: M_SBCW(BC);break; 34 | case SBC_HL_DE: M_SBCW(DE);break; 35 | case SBC_HL_HL: M_SBCW(HL);break; 36 | case SBC_HL_SP: M_SBCW(SP);break; 37 | 38 | case LD_xWORDe_HL: 39 | J.B.l=OpZ80(CPU.PC.W++); 40 | J.B.h=OpZ80(CPU.PC.W++); 41 | WrZ80(J.W++,CPU.HL.B.l); 42 | WrZ80(J.W,CPU.HL.B.h); 43 | break; 44 | case LD_xWORDe_DE: 45 | J.B.l=OpZ80(CPU.PC.W++); 46 | J.B.h=OpZ80(CPU.PC.W++); 47 | WrZ80(J.W++,CPU.DE.B.l); 48 | WrZ80(J.W,CPU.DE.B.h); 49 | break; 50 | case LD_xWORDe_BC: 51 | J.B.l=OpZ80(CPU.PC.W++); 52 | J.B.h=OpZ80(CPU.PC.W++); 53 | WrZ80(J.W++,CPU.BC.B.l); 54 | WrZ80(J.W,CPU.BC.B.h); 55 | break; 56 | case LD_xWORDe_SP: 57 | J.B.l=OpZ80(CPU.PC.W++); 58 | J.B.h=OpZ80(CPU.PC.W++); 59 | WrZ80(J.W++,CPU.SP.B.l); 60 | WrZ80(J.W,CPU.SP.B.h); 61 | break; 62 | 63 | case LD_HL_xWORDe: 64 | J.B.l=OpZ80(CPU.PC.W++); 65 | J.B.h=OpZ80(CPU.PC.W++); 66 | CPU.HL.B.l=RdZ80(J.W++); 67 | CPU.HL.B.h=RdZ80(J.W); 68 | break; 69 | case LD_DE_xWORDe: 70 | J.B.l=OpZ80(CPU.PC.W++); 71 | J.B.h=OpZ80(CPU.PC.W++); 72 | CPU.DE.B.l=RdZ80(J.W++); 73 | CPU.DE.B.h=RdZ80(J.W); 74 | break; 75 | case LD_BC_xWORDe: 76 | J.B.l=OpZ80(CPU.PC.W++); 77 | J.B.h=OpZ80(CPU.PC.W++); 78 | CPU.BC.B.l=RdZ80(J.W++); 79 | CPU.BC.B.h=RdZ80(J.W); 80 | break; 81 | case LD_SP_xWORDe: 82 | J.B.l=OpZ80(CPU.PC.W++); 83 | J.B.h=OpZ80(CPU.PC.W++); 84 | CPU.SP.B.l=RdZ80(J.W++); 85 | CPU.SP.B.h=RdZ80(J.W); 86 | break; 87 | 88 | case RRD: 89 | I=RdZ80(CPU.HL.W); 90 | J.B.l=(I>>4)|(CPU.AF.B.h<<4); 91 | WrZ80(CPU.HL.W,J.B.l); 92 | CPU.AF.B.h=(I&0x0F)|(CPU.AF.B.h&0xF0); 93 | CPU.AF.B.l=PZSTable[CPU.AF.B.h]|(CPU.AF.B.l&C_FLAG); 94 | break; 95 | case RLD: 96 | I=RdZ80(CPU.HL.W); 97 | J.B.l=(I<<4)|(CPU.AF.B.h&0x0F); 98 | WrZ80(CPU.HL.W,J.B.l); 99 | CPU.AF.B.h=(I>>4)|(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 LD_A_I: 104 | CPU.AF.B.h=CPU.I; 105 | CPU.AF.B.l=(CPU.AF.B.l&C_FLAG)|(CPU.IFF&IFF_2? P_FLAG:0)|ZSTable[CPU.AF.B.h]; 106 | break; 107 | 108 | case LD_A_R: 109 | 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 110 | CPU.AF.B.l=(CPU.AF.B.l&C_FLAG)|(CPU.IFF&IFF_2? P_FLAG:0)|ZSTable[CPU.AF.B.h]; 111 | break; 112 | 113 | case LD_I_A: CPU.I=CPU.AF.B.h;break; 114 | case LD_R_A: CPU.R=CPU.AF.B.h;CPU.R_HighBit = (CPU.R & 0x80); break; 115 | 116 | case IM_0: CPU.IFF&=~(IFF_IM1|IFF_IM2);break; 117 | case IM_1: CPU.IFF=(CPU.IFF&~IFF_IM2)|IFF_IM1;break; 118 | case IM_2: CPU.IFF=(CPU.IFF&~IFF_IM1)|IFF_IM2;break; 119 | 120 | case RETI: 121 | case RETN: if(CPU.IFF&IFF_2) CPU.IFF|=IFF_1; else CPU.IFF&=~IFF_1; 122 | M_RET;break; 123 | 124 | case NEG: I=CPU.AF.B.h;CPU.AF.B.h=0;M_SUB(I);break; 125 | 126 | case IN_B_xC: M_IN(CPU.BC.B.h);break; 127 | case IN_C_xC: M_IN(CPU.BC.B.l);break; 128 | case IN_D_xC: M_IN(CPU.DE.B.h);break; 129 | case IN_E_xC: M_IN(CPU.DE.B.l);break; 130 | case IN_H_xC: M_IN(CPU.HL.B.h);break; 131 | case IN_L_xC: M_IN(CPU.HL.B.l);break; 132 | case IN_A_xC: M_IN(CPU.AF.B.h);break; 133 | case IN_F_xC: M_IN(J.B.l);break; 134 | 135 | case OUT_xC_B: OutZ80(CPU.BC.W,CPU.BC.B.h);break; 136 | case OUT_xC_C: OutZ80(CPU.BC.W,CPU.BC.B.l);break; 137 | case OUT_xC_D: OutZ80(CPU.BC.W,CPU.DE.B.h);break; 138 | case OUT_xC_E: OutZ80(CPU.BC.W,CPU.DE.B.l);break; 139 | case OUT_xC_H: OutZ80(CPU.BC.W,CPU.HL.B.h);break; 140 | case OUT_xC_L: OutZ80(CPU.BC.W,CPU.HL.B.l);break; 141 | case OUT_xC_A: OutZ80(CPU.BC.W,CPU.AF.B.h);break; 142 | case OUT_xC_F: OutZ80(CPU.BC.W,0);break; 143 | 144 | case INI: 145 | I = InZ80(CPU.BC.W); 146 | WrZ80(CPU.HL.W++,I); 147 | --CPU.BC.B.h; 148 | CPU.AF.B.l=(I&0x80 ? N_FLAG:0)|(CPU.BC.B.h? 0:Z_FLAG); 149 | break; 150 | 151 | case INIR: 152 | I = InZ80(CPU.BC.W); 153 | WrZ80(CPU.HL.W++,I); 154 | if(--CPU.BC.B.h) { CPU.AF.B.l=N_FLAG; CPU.PC.W-=2; } // N_FLAG is not correct here but will be corrected when loop exits below. Nothing relies on the intermediate value. 155 | else { CPU.AF.B.l=Z_FLAG|(I&0x80 ? N_FLAG:0); CPU.TStates-=4;} 156 | break; 157 | 158 | case IND: 159 | I = InZ80(CPU.BC.W); 160 | WrZ80(CPU.HL.W--,I); 161 | --CPU.BC.B.h; 162 | CPU.AF.B.l=(I&0x80 ? N_FLAG:0)|(CPU.BC.B.h? 0:Z_FLAG); 163 | break; 164 | 165 | case INDR: 166 | I = InZ80(CPU.BC.W); 167 | WrZ80(CPU.HL.W--,I); 168 | if(!--CPU.BC.B.h) { CPU.AF.B.l=N_FLAG; CPU.PC.W-=2; } // N_FLAG is not correct here but will be corrected when loop exits below. Nothing relies on the intermediate value. 169 | else { CPU.AF.B.l=Z_FLAG|(I&0x80 ? N_FLAG:0); CPU.TStates-=4;} 170 | break; 171 | 172 | case OUTI: 173 | --CPU.BC.B.h; 174 | I=RdZ80(CPU.HL.W++); 175 | OutZ80(CPU.BC.W,I); 176 | 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); 177 | break; 178 | 179 | case OTIR: 180 | --CPU.BC.B.h; 181 | I=RdZ80(CPU.HL.W++); 182 | OutZ80(CPU.BC.W,I); 183 | if(CPU.BC.B.h) 184 | { 185 | 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. 186 | CPU.PC.W-=2; 187 | } 188 | else 189 | { 190 | 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); 191 | CPU.TStates-=4; 192 | } 193 | break; 194 | 195 | case OUTD: 196 | --CPU.BC.B.h; 197 | I=RdZ80(CPU.HL.W--); 198 | OutZ80(CPU.BC.W,I); 199 | 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); 200 | break; 201 | 202 | case OTDR: 203 | --CPU.BC.B.h; 204 | I=RdZ80(CPU.HL.W--); 205 | OutZ80(CPU.BC.W,I); 206 | if(CPU.BC.B.h) 207 | { 208 | 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. 209 | CPU.PC.W-=2; 210 | } 211 | else 212 | { 213 | 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); 214 | CPU.TStates-=4; 215 | } 216 | break; 217 | 218 | case LDI: 219 | WrZ80(CPU.DE.W++,RdZ80(CPU.HL.W++)); 220 | --CPU.BC.W; 221 | CPU.AF.B.l=(CPU.AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(CPU.BC.W? P_FLAG:0); 222 | break; 223 | 224 | case LDIR: 225 | WrZ80(CPU.DE.W++,RdZ80(CPU.HL.W++)); 226 | if(--CPU.BC.W) 227 | { 228 | CPU.AF.B.l=(CPU.AF.B.l&~(H_FLAG|P_FLAG))|N_FLAG; 229 | CPU.PC.W-=2; 230 | } 231 | else 232 | { 233 | CPU.AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); 234 | CPU.TStates-=4; 235 | } 236 | break; 237 | 238 | case LDD: 239 | WrZ80(CPU.DE.W--,RdZ80(CPU.HL.W--)); 240 | --CPU.BC.W; 241 | CPU.AF.B.l=(CPU.AF.B.l&~(N_FLAG|H_FLAG|P_FLAG))|(CPU.BC.W? P_FLAG:0); 242 | break; 243 | 244 | case LDDR: 245 | WrZ80(CPU.DE.W--,RdZ80(CPU.HL.W--)); 246 | CPU.AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); 247 | if(--CPU.BC.W) 248 | { 249 | CPU.AF.B.l=(CPU.AF.B.l&~(H_FLAG|P_FLAG))|N_FLAG; 250 | CPU.PC.W-=2; 251 | } 252 | else 253 | { 254 | CPU.AF.B.l&=~(N_FLAG|H_FLAG|P_FLAG); 255 | CPU.TStates-=4; 256 | } 257 | break; 258 | 259 | case CPI: 260 | I=RdZ80(CPU.HL.W++); 261 | J.B.l=CPU.AF.B.h-I; 262 | --CPU.BC.W; 263 | CPU.AF.B.l = 264 | N_FLAG|(CPU.AF.B.l&C_FLAG)|ZSTable[J.B.l]| 265 | ((CPU.AF.B.h^I^J.B.l)&H_FLAG)|(CPU.BC.W? P_FLAG:0); 266 | break; 267 | 268 | case CPIR: 269 | I=RdZ80(CPU.HL.W++); 270 | J.B.l=CPU.AF.B.h-I; 271 | if(--CPU.BC.W&&J.B.l) { CPU.PC.W-=2; } else {CPU.TStates-=4;} 272 | CPU.AF.B.l = 273 | N_FLAG|(CPU.AF.B.l&C_FLAG)|ZSTable[J.B.l]| 274 | ((CPU.AF.B.h^I^J.B.l)&H_FLAG)|(CPU.BC.W? P_FLAG:0); 275 | break; 276 | 277 | case CPD: 278 | I=RdZ80(CPU.HL.W--); 279 | J.B.l=CPU.AF.B.h-I; 280 | --CPU.BC.W; 281 | CPU.AF.B.l = 282 | N_FLAG|(CPU.AF.B.l&C_FLAG)|ZSTable[J.B.l]| 283 | ((CPU.AF.B.h^I^J.B.l)&H_FLAG)|(CPU.BC.W? P_FLAG:0); 284 | break; 285 | 286 | case CPDR: 287 | I=RdZ80(CPU.HL.W--); 288 | J.B.l=CPU.AF.B.h-I; 289 | if(--CPU.BC.W&&J.B.l) { CPU.PC.W-=2; } else {CPU.TStates-=4;} 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 | break; 294 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesXCB.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SugarDS 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 RLC_xHL: I=RdZ80(J.W);M_RLC(I);WrZ80(J.W,I);break; 25 | case RRC_xHL: I=RdZ80(J.W);M_RRC(I);WrZ80(J.W,I);break; 26 | case RL_xHL: I=RdZ80(J.W);M_RL(I);WrZ80(J.W,I);break; 27 | case RR_xHL: I=RdZ80(J.W);M_RR(I);WrZ80(J.W,I);break; 28 | case SLA_xHL: I=RdZ80(J.W);M_SLA(I);WrZ80(J.W,I);break; 29 | case SRA_xHL: I=RdZ80(J.W);M_SRA(I);WrZ80(J.W,I);break; 30 | case SLL_xHL: I=RdZ80(J.W);M_SLL(I);WrZ80(J.W,I);break; 31 | case SRL_xHL: I=RdZ80(J.W);M_SRL(I);WrZ80(J.W,I);break; 32 | 33 | case BIT0_B: case BIT0_C: case BIT0_D: case BIT0_E: 34 | case BIT0_H: case BIT0_L: case BIT0_A: 35 | case BIT0_xHL: I=RdZ80(J.W);M_BIT(0,I);break; 36 | case BIT1_B: case BIT1_C: case BIT1_D: case BIT1_E: 37 | case BIT1_H: case BIT1_L: case BIT1_A: 38 | case BIT1_xHL: I=RdZ80(J.W);M_BIT(1,I);break; 39 | case BIT2_B: case BIT2_C: case BIT2_D: case BIT2_E: 40 | case BIT2_H: case BIT2_L: case BIT2_A: 41 | case BIT2_xHL: I=RdZ80(J.W);M_BIT(2,I);break; 42 | case BIT3_B: case BIT3_C: case BIT3_D: case BIT3_E: 43 | case BIT3_H: case BIT3_L: case BIT3_A: 44 | case BIT3_xHL: I=RdZ80(J.W);M_BIT(3,I);break; 45 | case BIT4_B: case BIT4_C: case BIT4_D: case BIT4_E: 46 | case BIT4_H: case BIT4_L: case BIT4_A: 47 | case BIT4_xHL: I=RdZ80(J.W);M_BIT(4,I);break; 48 | case BIT5_B: case BIT5_C: case BIT5_D: case BIT5_E: 49 | case BIT5_H: case BIT5_L: case BIT5_A: 50 | case BIT5_xHL: I=RdZ80(J.W);M_BIT(5,I);break; 51 | case BIT6_B: case BIT6_C: case BIT6_D: case BIT6_E: 52 | case BIT6_H: case BIT6_L: case BIT6_A: 53 | case BIT6_xHL: I=RdZ80(J.W);M_BIT(6,I);break; 54 | case BIT7_B: case BIT7_C: case BIT7_D: case BIT7_E: 55 | case BIT7_H: case BIT7_L: case BIT7_A: 56 | case BIT7_xHL: I=RdZ80(J.W);M_BIT(7,I);break; 57 | 58 | case RES0_xHL: I=RdZ80(J.W);M_RES(0,I);WrZ80(J.W,I);break; 59 | case RES1_xHL: I=RdZ80(J.W);M_RES(1,I);WrZ80(J.W,I);break; 60 | case RES2_xHL: I=RdZ80(J.W);M_RES(2,I);WrZ80(J.W,I);break; 61 | case RES3_xHL: I=RdZ80(J.W);M_RES(3,I);WrZ80(J.W,I);break; 62 | case RES4_xHL: I=RdZ80(J.W);M_RES(4,I);WrZ80(J.W,I);break; 63 | case RES5_xHL: I=RdZ80(J.W);M_RES(5,I);WrZ80(J.W,I);break; 64 | case RES6_xHL: I=RdZ80(J.W);M_RES(6,I);WrZ80(J.W,I);break; 65 | case RES7_xHL: I=RdZ80(J.W);M_RES(7,I);WrZ80(J.W,I);break; 66 | 67 | case SET0_xHL: I=RdZ80(J.W);M_SET(0,I);WrZ80(J.W,I);break; 68 | case SET1_xHL: I=RdZ80(J.W);M_SET(1,I);WrZ80(J.W,I);break; 69 | case SET2_xHL: I=RdZ80(J.W);M_SET(2,I);WrZ80(J.W,I);break; 70 | case SET3_xHL: I=RdZ80(J.W);M_SET(3,I);WrZ80(J.W,I);break; 71 | case SET4_xHL: I=RdZ80(J.W);M_SET(4,I);WrZ80(J.W,I);break; 72 | case SET5_xHL: I=RdZ80(J.W);M_SET(5,I);WrZ80(J.W,I);break; 73 | case SET6_xHL: I=RdZ80(J.W);M_SET(6,I);WrZ80(J.W,I);break; 74 | case SET7_xHL: I=RdZ80(J.W);M_SET(7,I);WrZ80(J.W,I);break; 75 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/CodesXX.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SugarDS 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_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_ADD(I);break; 32 | case ADD_BYTE: I=OpZ80(CPU.PC.W++);M_ADD(I);break; 33 | 34 | case SUB_B: M_SUB(CPU.BC.B.h);break; 35 | case SUB_C: M_SUB(CPU.BC.B.l);break; 36 | case SUB_D: M_SUB(CPU.DE.B.h);break; 37 | case SUB_E: M_SUB(CPU.DE.B.l);break; 38 | case SUB_H: M_SUB(CPU.XX.B.h);break; 39 | case SUB_L: M_SUB(CPU.XX.B.l);break; 40 | case SUB_A: CPU.AF.B.h=0;CPU.AF.B.l=N_FLAG|Z_FLAG;break; 41 | case SUB_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_SUB(I);break; 42 | case SUB_BYTE: I=OpZ80(CPU.PC.W++);M_SUB(I);break; 43 | 44 | case AND_B: M_AND(CPU.BC.B.h);break; 45 | case AND_C: M_AND(CPU.BC.B.l);break; 46 | case AND_D: M_AND(CPU.DE.B.h);break; 47 | case AND_E: M_AND(CPU.DE.B.l);break; 48 | case AND_H: M_AND(CPU.XX.B.h);break; 49 | case AND_L: M_AND(CPU.XX.B.l);break; 50 | case AND_A: M_AND(CPU.AF.B.h);break; 51 | case AND_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_AND(I);break; 52 | case AND_BYTE: I=OpZ80(CPU.PC.W++);M_AND(I);break; 53 | 54 | case OR_B: M_OR(CPU.BC.B.h);break; 55 | case OR_C: M_OR(CPU.BC.B.l);break; 56 | case OR_D: M_OR(CPU.DE.B.h);break; 57 | case OR_E: M_OR(CPU.DE.B.l);break; 58 | case OR_H: M_OR(CPU.XX.B.h);break; 59 | case OR_L: M_OR(CPU.XX.B.l);break; 60 | case OR_A: M_OR(CPU.AF.B.h);break; 61 | case OR_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_OR(I);break; 62 | case OR_BYTE: I=OpZ80(CPU.PC.W++);M_OR(I);break; 63 | 64 | case ADC_B: M_ADC(CPU.BC.B.h);break; 65 | case ADC_C: M_ADC(CPU.BC.B.l);break; 66 | case ADC_D: M_ADC(CPU.DE.B.h);break; 67 | case ADC_E: M_ADC(CPU.DE.B.l);break; 68 | case ADC_H: M_ADC(CPU.XX.B.h);break; 69 | case ADC_L: M_ADC(CPU.XX.B.l);break; 70 | case ADC_A: M_ADC(CPU.AF.B.h);break; 71 | case ADC_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_ADC(I);break; 72 | case ADC_BYTE: I=OpZ80(CPU.PC.W++);M_ADC(I);break; 73 | 74 | case SBC_B: M_SBC(CPU.BC.B.h);break; 75 | case SBC_C: M_SBC(CPU.BC.B.l);break; 76 | case SBC_D: M_SBC(CPU.DE.B.h);break; 77 | case SBC_E: M_SBC(CPU.DE.B.l);break; 78 | case SBC_H: M_SBC(CPU.XX.B.h);break; 79 | case SBC_L: M_SBC(CPU.XX.B.l);break; 80 | case SBC_A: M_SBC(CPU.AF.B.h);break; 81 | case SBC_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_SBC(I);break; 82 | case SBC_BYTE: I=OpZ80(CPU.PC.W++);M_SBC(I);break; 83 | 84 | case XOR_B: M_XOR(CPU.BC.B.h);break; 85 | case XOR_C: M_XOR(CPU.BC.B.l);break; 86 | case XOR_D: M_XOR(CPU.DE.B.h);break; 87 | case XOR_E: M_XOR(CPU.DE.B.l);break; 88 | case XOR_H: M_XOR(CPU.XX.B.h);break; 89 | case XOR_L: M_XOR(CPU.XX.B.l);break; 90 | case XOR_A: CPU.AF.B.h=0;CPU.AF.B.l=P_FLAG|Z_FLAG;break; 91 | case XOR_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_XOR(I);break; 92 | case XOR_BYTE: I=OpZ80(CPU.PC.W++);M_XOR(I);break; 93 | 94 | case CP_B: M_CP(CPU.BC.B.h);break; 95 | case CP_C: M_CP(CPU.BC.B.l);break; 96 | case CP_D: M_CP(CPU.DE.B.h);break; 97 | case CP_E: M_CP(CPU.DE.B.l);break; 98 | case CP_H: M_CP(CPU.XX.B.h);break; 99 | case CP_L: M_CP(CPU.XX.B.l);break; 100 | case CP_A: CPU.AF.B.l=N_FLAG|Z_FLAG;break; 101 | case CP_xHL: I=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));M_CP(I);break; 102 | case CP_BYTE: I=OpZ80(CPU.PC.W++);M_CP(I);break; 103 | 104 | case LD_BC_WORD: M_LDWORD(BC);break; 105 | case LD_DE_WORD: M_LDWORD(DE);break; 106 | case LD_HL_WORD: M_LDWORD(XX);break; 107 | case LD_SP_WORD: M_LDWORD(SP);break; 108 | 109 | case LD_PC_HL: CPU.PC.W=CPU.XX.W;JumpZ80(CPU.PC.W);break; 110 | case LD_SP_HL: CPU.SP.W=CPU.XX.W;break; 111 | case LD_A_xBC: CPU.AF.B.h=RdZ80(CPU.BC.W);break; 112 | case LD_A_xDE: CPU.AF.B.h=RdZ80(CPU.DE.W);break; 113 | 114 | case ADD_HL_BC: M_ADDW(XX,BC);break; 115 | case ADD_HL_DE: M_ADDW(XX,DE);break; 116 | case ADD_HL_HL: M_ADDW(XX,XX);break; 117 | case ADD_HL_SP: M_ADDW(XX,SP);break; 118 | 119 | case DEC_BC: CPU.BC.W--;break; 120 | case DEC_DE: CPU.DE.W--;break; 121 | case DEC_HL: CPU.XX.W--;break; 122 | case DEC_SP: CPU.SP.W--;break; 123 | 124 | case INC_BC: CPU.BC.W++;break; 125 | case INC_DE: CPU.DE.W++;break; 126 | case INC_HL: CPU.XX.W++;break; 127 | case INC_SP: CPU.SP.W++;break; 128 | 129 | case DEC_B: M_DEC(CPU.BC.B.h);break; 130 | case DEC_C: M_DEC(CPU.BC.B.l);break; 131 | case DEC_D: M_DEC(CPU.DE.B.h);break; 132 | case DEC_E: M_DEC(CPU.DE.B.l);break; 133 | case DEC_H: M_DEC(CPU.XX.B.h);break; 134 | case DEC_L: M_DEC(CPU.XX.B.l);break; 135 | case DEC_A: M_DEC(CPU.AF.B.h);break; 136 | case DEC_xHL: I=RdZ80(CPU.XX.W+(offset)RdZ80(CPU.PC.W));M_DEC(I); 137 | WrZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++),I); 138 | break; 139 | 140 | case INC_B: M_INC(CPU.BC.B.h);break; 141 | case INC_C: M_INC(CPU.BC.B.l);break; 142 | case INC_D: M_INC(CPU.DE.B.h);break; 143 | case INC_E: M_INC(CPU.DE.B.l);break; 144 | case INC_H: M_INC(CPU.XX.B.h);break; 145 | case INC_L: M_INC(CPU.XX.B.l);break; 146 | case INC_A: M_INC(CPU.AF.B.h);break; 147 | case INC_xHL: I=RdZ80(CPU.XX.W+(offset)RdZ80(CPU.PC.W));M_INC(I); 148 | WrZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++),I); 149 | break; 150 | 151 | case RLCA: 152 | I=(CPU.AF.B.h&0x80? C_FLAG:0); 153 | CPU.AF.B.h=(CPU.AF.B.h<<1)|I; 154 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 155 | break; 156 | case RLA: 157 | I=(CPU.AF.B.h&0x80? C_FLAG:0); 158 | CPU.AF.B.h=(CPU.AF.B.h<<1)|(CPU.AF.B.l&C_FLAG); 159 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 160 | break; 161 | case RRCA: 162 | I=CPU.AF.B.h&0x01; 163 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(I? 0x80:0); 164 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 165 | break; 166 | case RRA: 167 | I=CPU.AF.B.h&0x01; 168 | CPU.AF.B.h=(CPU.AF.B.h>>1)|(CPU.AF.B.l&C_FLAG? 0x80:0); 169 | CPU.AF.B.l=(CPU.AF.B.l&~(C_FLAG|N_FLAG|H_FLAG))|I; 170 | break; 171 | 172 | case RST00: M_RST(0x0000);break; 173 | case RST08: M_RST(0x0008);break; 174 | case RST10: M_RST(0x0010);break; 175 | case RST18: M_RST(0x0018);break; 176 | case RST20: M_RST(0x0020);break; 177 | case RST28: M_RST(0x0028);break; 178 | case RST30: M_RST(0x0030);break; 179 | case RST38: M_RST(0x0038);break; 180 | 181 | case PUSH_BC: M_PUSH(BC);break; 182 | case PUSH_DE: M_PUSH(DE);break; 183 | case PUSH_HL: M_PUSH(XX);break; 184 | case PUSH_AF: M_PUSH(AF);break; 185 | 186 | case POP_BC: M_POP(BC);break; 187 | case POP_DE: M_POP(DE);break; 188 | case POP_HL: M_POP(XX);break; 189 | case POP_AF: M_POP(AF);break; 190 | 191 | case SCF: S(C_FLAG);R(N_FLAG|H_FLAG);break; 192 | case CPL: CPU.AF.B.h=~CPU.AF.B.h;S(N_FLAG|H_FLAG);break; 193 | case NOP: break; 194 | case OUTA: I=OpZ80(CPU.PC.W++);OutZ80(I|(CPU.AF.W&0xFF00),CPU.AF.B.h);break; 195 | case INA: I=OpZ80(CPU.PC.W++);CPU.AF.B.h=InZ80(I|(CPU.AF.W&0xFF00));break; 196 | 197 | case EX_DE_HL: J.W=CPU.DE.W;CPU.DE.W=CPU.HL.W;CPU.HL.W=J.W;break; 198 | case EX_AF_AF: J.W=CPU.AF.W;CPU.AF.W=CPU.AF1.W;CPU.AF1.W=J.W;break; 199 | 200 | case LD_B_B: CPU.BC.B.h=CPU.BC.B.h;break; 201 | case LD_C_B: CPU.BC.B.l=CPU.BC.B.h;break; 202 | case LD_D_B: CPU.DE.B.h=CPU.BC.B.h;break; 203 | case LD_E_B: CPU.DE.B.l=CPU.BC.B.h;break; 204 | case LD_H_B: CPU.XX.B.h=CPU.BC.B.h;break; 205 | case LD_L_B: CPU.XX.B.l=CPU.BC.B.h;break; 206 | case LD_A_B: CPU.AF.B.h=CPU.BC.B.h;break; 207 | case LD_xHL_B: J.W=CPU.XX.W+(offset)OpZ80(CPU.PC.W++); 208 | WrZ80(J.W,CPU.BC.B.h);break; 209 | 210 | case LD_B_C: CPU.BC.B.h=CPU.BC.B.l;break; 211 | case LD_C_C: CPU.BC.B.l=CPU.BC.B.l;break; 212 | case LD_D_C: CPU.DE.B.h=CPU.BC.B.l;break; 213 | case LD_E_C: CPU.DE.B.l=CPU.BC.B.l;break; 214 | case LD_H_C: CPU.XX.B.h=CPU.BC.B.l;break; 215 | case LD_L_C: CPU.XX.B.l=CPU.BC.B.l;break; 216 | case LD_A_C: CPU.AF.B.h=CPU.BC.B.l;break; 217 | case LD_xHL_C: J.W=CPU.XX.W+(offset)OpZ80(CPU.PC.W++); 218 | WrZ80(J.W,CPU.BC.B.l);break; 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)OpZ80(CPU.PC.W++); 228 | WrZ80(J.W,CPU.DE.B.h);break; 229 | 230 | case LD_B_E: CPU.BC.B.h=CPU.DE.B.l;break; 231 | case LD_C_E: CPU.BC.B.l=CPU.DE.B.l;break; 232 | case LD_D_E: CPU.DE.B.h=CPU.DE.B.l;break; 233 | case LD_E_E: CPU.DE.B.l=CPU.DE.B.l;break; 234 | case LD_H_E: CPU.XX.B.h=CPU.DE.B.l;break; 235 | case LD_L_E: CPU.XX.B.l=CPU.DE.B.l;break; 236 | case LD_A_E: CPU.AF.B.h=CPU.DE.B.l;break; 237 | case LD_xHL_E: J.W=CPU.XX.W+(offset)OpZ80(CPU.PC.W++); 238 | WrZ80(J.W,CPU.DE.B.l);break; 239 | 240 | case LD_B_H: CPU.BC.B.h=CPU.XX.B.h;break; 241 | case LD_C_H: CPU.BC.B.l=CPU.XX.B.h;break; 242 | case LD_D_H: CPU.DE.B.h=CPU.XX.B.h;break; 243 | case LD_E_H: CPU.DE.B.l=CPU.XX.B.h;break; 244 | case LD_H_H: CPU.XX.B.h=CPU.XX.B.h;break; 245 | case LD_L_H: CPU.XX.B.l=CPU.XX.B.h;break; 246 | case LD_A_H: CPU.AF.B.h=CPU.XX.B.h;break; 247 | case LD_xHL_H: J.W=CPU.XX.W+(offset)OpZ80(CPU.PC.W++); 248 | WrZ80(J.W,CPU.HL.B.h);break; 249 | 250 | case LD_B_L: CPU.BC.B.h=CPU.XX.B.l;break; 251 | case LD_C_L: CPU.BC.B.l=CPU.XX.B.l;break; 252 | case LD_D_L: CPU.DE.B.h=CPU.XX.B.l;break; 253 | case LD_E_L: CPU.DE.B.l=CPU.XX.B.l;break; 254 | case LD_H_L: CPU.XX.B.h=CPU.XX.B.l;break; 255 | case LD_L_L: CPU.XX.B.l=CPU.XX.B.l;break; 256 | case LD_A_L: CPU.AF.B.h=CPU.XX.B.l;break; 257 | case LD_xHL_L: J.W=CPU.XX.W+(offset)OpZ80(CPU.PC.W++); 258 | WrZ80(J.W,CPU.HL.B.l);break; 259 | 260 | case LD_B_A: CPU.BC.B.h=CPU.AF.B.h;break; 261 | case LD_C_A: CPU.BC.B.l=CPU.AF.B.h;break; 262 | case LD_D_A: CPU.DE.B.h=CPU.AF.B.h;break; 263 | case LD_E_A: CPU.DE.B.l=CPU.AF.B.h;break; 264 | case LD_H_A: CPU.XX.B.h=CPU.AF.B.h;break; 265 | case LD_L_A: CPU.XX.B.l=CPU.AF.B.h;break; 266 | case LD_A_A: CPU.AF.B.h=CPU.AF.B.h;break; 267 | case LD_xHL_A: J.W=CPU.XX.W+(offset)OpZ80(CPU.PC.W++); 268 | WrZ80(J.W,CPU.AF.B.h);break; 269 | 270 | case LD_xBC_A: WrZ80(CPU.BC.W,CPU.AF.B.h);break; 271 | case LD_xDE_A: WrZ80(CPU.DE.W,CPU.AF.B.h);break; 272 | 273 | case LD_B_xHL: CPU.BC.B.h=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));break; 274 | case LD_C_xHL: CPU.BC.B.l=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));break; 275 | case LD_D_xHL: CPU.DE.B.h=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));break; 276 | case LD_E_xHL: CPU.DE.B.l=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));break; 277 | case LD_H_xHL: CPU.HL.B.h=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));break; 278 | case LD_L_xHL: CPU.HL.B.l=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));break; 279 | case LD_A_xHL: CPU.AF.B.h=RdZ80(CPU.XX.W+(offset)OpZ80(CPU.PC.W++));break; 280 | 281 | case LD_B_BYTE: CPU.BC.B.h=OpZ80(CPU.PC.W++);break; 282 | case LD_C_BYTE: CPU.BC.B.l=OpZ80(CPU.PC.W++);break; 283 | case LD_D_BYTE: CPU.DE.B.h=OpZ80(CPU.PC.W++);break; 284 | case LD_E_BYTE: CPU.DE.B.l=OpZ80(CPU.PC.W++);break; 285 | case LD_H_BYTE: CPU.XX.B.h=OpZ80(CPU.PC.W++);break; 286 | case LD_L_BYTE: CPU.XX.B.l=OpZ80(CPU.PC.W++);break; 287 | case LD_A_BYTE: CPU.AF.B.h=OpZ80(CPU.PC.W++);break; 288 | case LD_xHL_BYTE: J.W=CPU.XX.W+(offset)OpZ80(CPU.PC.W++); 289 | WrZ80(J.W,OpZ80(CPU.PC.W++));break; 290 | 291 | case LD_xWORD_HL: 292 | J.B.l=OpZ80(CPU.PC.W++); 293 | J.B.h=OpZ80(CPU.PC.W++); 294 | WrZ80(J.W++,CPU.XX.B.l); 295 | WrZ80(J.W,CPU.XX.B.h); 296 | break; 297 | 298 | case LD_HL_xWORD: 299 | J.B.l=OpZ80(CPU.PC.W++); 300 | J.B.h=OpZ80(CPU.PC.W++); 301 | CPU.XX.B.l=RdZ80(J.W++); 302 | CPU.XX.B.h=RdZ80(J.W); 303 | break; 304 | 305 | case LD_A_xWORD: 306 | J.B.l=OpZ80(CPU.PC.W++); 307 | J.B.h=OpZ80(CPU.PC.W++); 308 | CPU.AF.B.h=RdZ80(J.W); 309 | break; 310 | 311 | case LD_xWORD_A: 312 | J.B.l=OpZ80(CPU.PC.W++); 313 | J.B.h=OpZ80(CPU.PC.W++); 314 | WrZ80(J.W,CPU.AF.B.h); 315 | break; 316 | 317 | case EX_HL_xSP: 318 | J.B.l=RdZ80(CPU.SP.W);WrZ80(CPU.SP.W++,CPU.XX.B.l); 319 | J.B.h=RdZ80(CPU.SP.W);WrZ80(CPU.SP.W--,CPU.XX.B.h); 320 | CPU.XX.W=J.W; 321 | break; 322 | -------------------------------------------------------------------------------- /arm9/source/cpu/z80/cz80/Z80.h: -------------------------------------------------------------------------------- 1 | /****************************************************************************** 2 | * SugarDS 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 | /* Compilation options: */ 33 | #define LSB_FIRST /* Compile for low-endian CPU */ 34 | #define EXECZ80 /* Call Z80 each scanline */ 35 | 36 | /* LoopZ80() may return: */ 37 | #define INT_RST00 0x00C7 /* RST 00h */ 38 | #define INT_RST08 0x00CF /* RST 08h */ 39 | #define INT_RST10 0x00D7 /* RST 10h */ 40 | #define INT_RST18 0x00DF /* RST 18h */ 41 | #define INT_RST20 0x00E7 /* RST 20h */ 42 | #define INT_RST28 0x00EF /* RST 28h */ 43 | #define INT_RST30 0x00F7 /* RST 30h */ 44 | #define INT_RST38 0x00FF /* RST 38h */ 45 | #define INT_IRQ INT_RST38 /* Default IRQ opcode is FFh */ 46 | #define INT_NMI 0xFFFD /* Non-maskable interrupt */ 47 | #define INT_NONE 0xFFFF /* No interrupt required */ 48 | #define INT_QUIT 0xFFFE /* Exit the emulation */ 49 | 50 | /* Bits in Z80 F register: */ 51 | #define S_FLAG 0x80 /* 1: Result negative */ 52 | #define Z_FLAG 0x40 /* 1: Result is zero */ 53 | #define H_FLAG 0x10 /* 1: Halfcarry/Halfborrow */ 54 | #define P_FLAG 0x04 /* 1: Result is even */ 55 | #define V_FLAG 0x04 /* 1: Overflow occured */ 56 | #define N_FLAG 0x02 /* 1: Subtraction occured */ 57 | #define C_FLAG 0x01 /* 1: Carry/Borrow occured */ 58 | 59 | /* Bits in IFF flip-flops: */ 60 | #define IFF_1 0x01 /* IFF1 flip-flop */ 61 | #define IFF_IM1 0x02 /* 1: IM1 mode */ 62 | #define IFF_IM2 0x04 /* 1: IM2 mode */ 63 | #define IFF_2 0x08 /* IFF2 flip-flop */ 64 | #define IFF_EI 0x20 /* 1: EI pending */ 65 | #define IFF_HALT 0x80 /* 1: CPU HALTed */ 66 | 67 | /** Simple Datatypes *****************************************/ 68 | /** NOTICE: sizeof(byte)=1 and sizeof(word)=2 **/ 69 | /*************************************************************/ 70 | #ifndef BYTE_TYPE_DEFINED 71 | #define BYTE_TYPE_DEFINED 72 | typedef unsigned char byte; 73 | #endif 74 | #ifndef WORD_TYPE_DEFINED 75 | #define WORD_TYPE_DEFINED 76 | typedef unsigned short word; 77 | #endif 78 | typedef signed char offset; 79 | 80 | // We only support LSB_FIRST for the DS hardware 81 | typedef union 82 | { 83 | struct { byte l,h; } B; 84 | word W; 85 | } pair; 86 | 87 | // Special for the PC to avoid mask - 2% speedup! 88 | typedef union 89 | { 90 | struct { byte l,h, zz, xx; } B; 91 | u32 W; 92 | } Dpair; 93 | 94 | typedef struct 95 | { 96 | Dpair PC; /* Program Counter */ 97 | pair AF,BC,DE,HL,IX,IY,SP; /* Main registers */ 98 | pair AF1,BC1,DE1,HL1; /* Shadow registers */ 99 | byte IFF,I; /* Interrupt registers */ 100 | word IRequest; /* Set to address of pending IRQ */ 101 | byte IAutoReset; /* Set to 1 to autom. reset IRequest */ 102 | byte TrapBadOps; /* Set to 1 to warn of illegal opcodes */ 103 | byte Trace; /* Set Trace=1 to start tracing */ 104 | byte R_HighBit; /* Used to preserve the high bit for R */ 105 | u32 R; /* Refresh register - masked on read */ 106 | u32 TStates; /* Total CPU Cycles - reset 256 frames */ 107 | word EI_Delay; /* Enable Interrupt instruction delay */ 108 | u32 Target; /* CPU Target cycle to attain */ 109 | } Z80; 110 | 111 | 112 | /** ResetZ80() ***********************************************/ 113 | /** This function can be used to reset the registers before **/ 114 | /** starting execution with RunZ80(). It sets registers to **/ 115 | /** their initial values. **/ 116 | /*************************************************************/ 117 | void ResetZ80(register Z80 *R); 118 | 119 | /** ExecZ80() ************************************************/ 120 | /** This function will execute given number of Z80 cycles. **/ 121 | /** It will then return the number of cycles left, possibly **/ 122 | /** negative, and current register values in R. **/ 123 | /*************************************************************/ 124 | #ifdef EXECZ80 125 | void ExecZ80(u32 RunToCycles); 126 | #endif 127 | 128 | /** IntZ80() *************************************************/ 129 | /** This function will generate interrupt of given vector. **/ 130 | /*************************************************************/ 131 | void IntZ80(register Z80 *R,register word Vector); 132 | 133 | /** InZ80()/OutZ80() *****************************************/ 134 | /** Z80 emulation calls these functions to read/write from **/ 135 | /** I/O ports. There can be 65536 I/O ports, but only first **/ 136 | /** 256 are usually used. **/ 137 | /************************************ TO BE WRITTEN BY USER **/ 138 | void OutZ80(register word Port,register byte Value); 139 | byte InZ80(register word Port); 140 | 141 | /** PatchZ80() ***********************************************/ 142 | /** Z80 emulation calls this function when it encounters a **/ 143 | /** special patch command (ED FE) provided for user needs. **/ 144 | /** For example, it can be called to emulate BIOS calls, **/ 145 | /** such as disk and tape access. Replace it with an empty **/ 146 | /** macro for no patching. **/ 147 | /************************************ TO BE WRITTEN BY USER **/ 148 | void PatchZ80(register Z80 *R); 149 | 150 | /** JumpZ80() ************************************************/ 151 | /** Z80 emulation calls this function when it executes a **/ 152 | /** JP, JR, CALL, RST, or RET. You can use JumpZ80() to **/ 153 | /** trap these opcodes and switch memory layout. **/ 154 | /************************************ TO BE WRITTEN BY USER **/ 155 | #ifndef JUMPZ80 156 | #define JumpZ80(PC) 157 | #else 158 | void JumpZ80(word PC); 159 | #endif 160 | 161 | #ifdef __cplusplus 162 | } 163 | #endif 164 | #endif /* Z80_H */ 165 | -------------------------------------------------------------------------------- /arm9/source/fdc.c: -------------------------------------------------------------------------------- 1 | // SugarDS is Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 2 | // 3 | // Bits of pieces of this emulator have been glued and attached from a large number of sources - along with a healthy amount of 4 | // code by this author to pull it all together. Although it was hard to trace everythign to the original sources, I believe all 5 | // sources have released their material under the GNU General Public License and, as such, the SugarDS emulator follows suit. 6 | // 7 | // Previous contributions to this codebase: 8 | // 9 | // CrocoDS: CPC Emulator for the DS - Copyright (c) 2013 Miguel Vanhove (Kyuran) 10 | // Win-CPC: Amstrad CPC Emulator - Copyright (c) 2012 Ludovic Deplanque. 11 | // Caprice32: Amstrad CPC Emulator - Copyright (c) 1997-2004 Ulrich Doewich. 12 | // Arnold: Amstrad CPC Emulator - Copyright (c) 1995-2002, 2007 Andreas Micklei and Kevin Thacker 13 | // 14 | // As far as I'm concerned, you can use this code in whatever way suits you provided you continue to release the sources under 15 | // the original copyright notice (see below) which appeared to be the intention of all the pioneers who came before me. 16 | // 17 | // Original Copyright Notice 18 | // This program is free software; you can redistribute it and/or modify 19 | // it under the terms of the GNU General Public License as published by 20 | // the Free Software Foundation; either version 2 of the License, or 21 | // (at your option) any later version. 22 | // 23 | // This program is distributed in the hope that it will be useful, 24 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | // GNU General Public License for more details. 27 | // 28 | // You should have received a copy of the GNU General Public License 29 | // along with this program; if not, write to the Free Software 30 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 31 | 32 | #include 33 | #include "SugarDS.h" 34 | #include "fdc.h" 35 | 36 | // Status Bits 37 | #define STATUS_CB 0x10 38 | #define STATUS_EXM 0x20 39 | #define STATUS_DIO 0x40 40 | #define STATUS_RQM 0x80 41 | 42 | // ST0 43 | #define ST0_HD 0x04 44 | #define ST0_NR 0x08 45 | #define ST0_SE 0x20 46 | #define ST0_IC1 0x40 47 | #define ST0_IC2 0x80 48 | 49 | // ST1 50 | #define ST1_ND 0x04 51 | #define ST1_EN 0x80 52 | 53 | // ST3 54 | #define ST3_HD 0x04 55 | #define ST3_TS 0x08 56 | #define ST3_T0 0x10 57 | #define ST3_RY 0x20 58 | 59 | typedef int ( * pfctFDC )( int ); 60 | 61 | FDC_t fdc; 62 | 63 | u8 DISK_IMAGE_BUFFER[896*1024]; // Big enough for any 3" or 3.5" disk format 64 | 65 | int SeekSector( int *pos ) 66 | { 67 | floppy_sound = 2; 68 | floppy_action = 0; 69 | 70 | *pos = 0; 71 | for ( int i = 0; i < fdc.CurrTrackDatasDSK[fdc.Side].NbSect; i++ ) 72 | { 73 | if ( (fdc.CurrTrackDatasDSK[fdc.Side].Sect[ i ].C == fdc.C) && 74 | (fdc.CurrTrackDatasDSK[fdc.Side].Sect[ i ].H == fdc.H) && 75 | (fdc.CurrTrackDatasDSK[fdc.Side].Sect[ i ].R == fdc.R) && 76 | (fdc.CurrTrackDatasDSK[fdc.Side].Sect[ i ].N == fdc.N) ) 77 | { 78 | fdc.sector_index = (i + 1) % fdc.CurrTrackDatasDSK[fdc.Side].NbSect; 79 | return( ( UBYTE )i ); 80 | } 81 | else 82 | { 83 | *pos += fdc.CurrTrackDatasDSK[fdc.Side].Sect[ i ].SectSize; 84 | } 85 | } 86 | 87 | fdc.ST0 |= ST0_IC1; 88 | fdc.ST1 |= ST1_ND; 89 | return( -1 ); 90 | } 91 | 92 | 93 | void ReadCHRN( void ) 94 | { 95 | fdc.C = fdc.CurrTrackDatasDSK[fdc.Side].Sect[ fdc.sector_index ].C; 96 | fdc.H = fdc.CurrTrackDatasDSK[fdc.Side].Sect[ fdc.sector_index ].H; 97 | fdc.R = fdc.CurrTrackDatasDSK[fdc.Side].Sect[ fdc.sector_index ].R; 98 | fdc.N = fdc.CurrTrackDatasDSK[fdc.Side].Sect[ fdc.sector_index ].N; 99 | if ( ++fdc.sector_index == fdc.CurrTrackDatasDSK[fdc.Side].NbSect ) 100 | { 101 | fdc.sector_index = 0; 102 | } 103 | } 104 | 105 | 106 | static void SetST0( void ) 107 | { 108 | fdc.ST0 = 0; // drive 00 (A:) 109 | 110 | if ( !fdc.Motor || fdc.Drive || !fdc.Image ) 111 | { 112 | fdc.ST0 |= ST0_IC1 | ST0_NR; // Not ready... No Motor, or No Drive or No Disk Image 113 | } 114 | 115 | if (fdc.Side) 116 | { 117 | fdc.ST0 |= ST0_HD; 118 | } 119 | else 120 | { 121 | fdc.ST0 &= ~ST0_HD; 122 | } 123 | 124 | // Status 1 and 2 will get filled in as we progress 125 | fdc.ST1 = 0; 126 | fdc.ST2 = 0; 127 | } 128 | 129 | static int Nothing( int val ) 130 | { 131 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 132 | fdc.state = 0; 133 | fdc.ST0 = ST0_IC2; 134 | return( fdc.ST0 ); 135 | } 136 | 137 | static int ReadST0( int val ) 138 | { 139 | if (!fdc.Inter) 140 | { 141 | fdc.ST0 = ST0_IC2; 142 | } 143 | else 144 | { 145 | fdc.Inter = 0; 146 | if (fdc.Busy) 147 | { 148 | fdc.ST0 = ST0_SE; 149 | fdc.Busy = 0; 150 | } 151 | else 152 | { 153 | fdc.ST0 |= ST0_IC1 | ST0_IC2; 154 | } 155 | 156 | if (fdc.Side) 157 | { 158 | fdc.ST0 |= ST0_HD; 159 | } 160 | else 161 | { 162 | fdc.ST0 &= ~ST0_HD; 163 | } 164 | } 165 | 166 | if (fdc.Motor && fdc.Image && !fdc.Drive) 167 | { 168 | fdc.ST0 &= ~ST0_NR; 169 | } 170 | else 171 | { 172 | fdc.ST0 |= ST0_NR; 173 | if ( !fdc.Image ) 174 | { 175 | fdc.ST0 |= ( ST0_IC1 | ST0_IC2 ); 176 | } 177 | } 178 | 179 | if (fdc.state++ == 1) 180 | { 181 | fdc.Status |= STATUS_DIO; 182 | return( fdc.ST0 ); 183 | } 184 | 185 | fdc.state = 0; 186 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 187 | fdc.ST0 &= ~ST0_IC1 & ~ST0_IC2; 188 | fdc.ST1 &= ~ST1_ND; 189 | return( fdc.C ); 190 | } 191 | 192 | static int ReadST3( int val ) 193 | { 194 | if ( fdc.state++ == 1 ) 195 | { 196 | fdc.Drive = val & 3; 197 | fdc.Side = (val >> 2) & 1; 198 | fdc.Status |= STATUS_DIO; 199 | return( 0 ); 200 | } 201 | 202 | fdc.state = 0; 203 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 204 | 205 | if ( fdc.Motor && !fdc.Drive && fdc.Image) 206 | { 207 | fdc.ST3 |= ST3_RY; // Drive ready 208 | } 209 | else 210 | { 211 | fdc.ST3 &= ~ST3_RY; // Drive not ready 212 | } 213 | 214 | if ( fdc.Side ) 215 | { 216 | fdc.ST3 |= ST3_HD; 217 | } 218 | else 219 | { 220 | fdc.ST3 &= ~ST3_HD; 221 | } 222 | 223 | return( fdc.ST3 ); 224 | } 225 | 226 | 227 | static int Specify( int val ) 228 | { 229 | if ( fdc.state++ == 1 ) 230 | { 231 | return( 0 ); 232 | } 233 | 234 | fdc.state = 0; 235 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 236 | return( 0 ); 237 | } 238 | 239 | 240 | 241 | static int ReadID( int val ) 242 | { 243 | switch( fdc.state++ ) 244 | { 245 | case 1 : 246 | fdc.Drive = val & 3; 247 | fdc.Side = (val >> 2) & 1; 248 | fdc.Status |= STATUS_DIO; 249 | fdc.Inter = 1; 250 | break; 251 | 252 | case 2 : 253 | return( fdc.ST0 ); 254 | 255 | case 3 : 256 | return( fdc.ST1 ); 257 | 258 | case 4 : 259 | return( fdc.ST2 ); 260 | 261 | case 5 : 262 | ReadCHRN(); 263 | return( fdc.C ); 264 | 265 | case 6 : 266 | return( fdc.H ); 267 | 268 | case 7 : 269 | return( fdc.R ); 270 | 271 | case 8 : 272 | fdc.state = 0; 273 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 274 | return( fdc.N ); 275 | } 276 | return( 0 ); 277 | } 278 | 279 | 280 | 281 | static int FormatTrack( int val ) 282 | { 283 | floppy_sound = 2; 284 | floppy_action = 1; 285 | 286 | fdc.state = 0; 287 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 288 | return( 0 ); 289 | } 290 | 291 | 292 | static int Scan( int val ) 293 | { 294 | fdc.state = 0; 295 | return( 0 ); 296 | } 297 | 298 | void ChangeCurrTrack( int newTrack ) 299 | { 300 | ULONG Pos = 0; 301 | 302 | // Set status before we modify newTrack below 303 | if (newTrack == 0) 304 | { 305 | fdc.ST3 |= ST3_T0; // We are on track 0 306 | } 307 | else 308 | { 309 | fdc.ST3 &= ~ST3_T0; // We are not on track 0 310 | } 311 | 312 | if ( fdc.Side ) 313 | { 314 | fdc.ST3 |= ST3_HD; // Current Head is 1 (side 1) 315 | } 316 | else 317 | { 318 | fdc.ST3 &= ~ST3_HD; // Current Head is 0 (side 0) 319 | } 320 | 321 | // --------------------------------------------------------------------- 322 | // If we are double-sided... handle the math for tracks. This gets us 323 | // to the right track for side 0 and we might read in side 1 as well. 324 | // --------------------------------------------------------------------- 325 | newTrack = (newTrack * fdc.DiskInfo.NumHeads); 326 | 327 | // ----------------------------------------------------------------------------- 328 | // We cache the track info for both sides of the disk if we are double sided... 329 | // ----------------------------------------------------------------------------- 330 | for (int head=0;head> 2) & 1; 364 | SetST0(); 365 | fdc.Status |= STATUS_EXM; 366 | break; 367 | 368 | case 2 : 369 | ChangeCurrTrack( fdc.C = val ); 370 | fdc.state = 0; 371 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO & ~STATUS_EXM; 372 | fdc.Busy = 1; 373 | fdc.Inter = 1; 374 | break; 375 | } 376 | return( 0 ); 377 | } 378 | 379 | 380 | static int MoveTrack0( int val ) 381 | { 382 | fdc.Drive = val & 3; 383 | fdc.Side = (val >> 2) & 1; 384 | ChangeCurrTrack( fdc.C = 0 ); 385 | fdc.state = 0; 386 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO & ~STATUS_EXM; 387 | SetST0(); 388 | fdc.Busy = 1; 389 | fdc.Inter = 1; 390 | return( 0 ); 391 | } 392 | 393 | static int ReadData( int val ) 394 | { 395 | switch( fdc.state++ ) 396 | { 397 | case 1 : 398 | fdc.Drive = val & 3; 399 | fdc.Side = (val >> 2) & 1; 400 | SetST0(); 401 | break; 402 | 403 | case 2 : 404 | fdc.C = val; 405 | break; 406 | 407 | case 3 : 408 | fdc.H = val; 409 | break; 410 | 411 | case 4 : 412 | fdc.R = val; 413 | break; 414 | 415 | case 5 : 416 | fdc.N = val; 417 | break; 418 | 419 | case 6 : 420 | fdc.EOT = val; 421 | break; 422 | 423 | case 7 : 424 | fdc.rd_sect = SeekSector( &fdc.rd_newPos ); 425 | if (fdc.rd_sect != -1) 426 | { 427 | fdc.ST1 = fdc.CurrTrackDatasDSK[fdc.Side].Sect[fdc.rd_sect].ST1 & 0x25; // Grab the ST1 field from the sector info 428 | fdc.ST2 = fdc.CurrTrackDatasDSK[fdc.Side].Sect[fdc.rd_sect].ST1 & 0x61; // Grab the ST2 field from the sector info 429 | 430 | if (fdc.CurrTrackDatasDSK[fdc.Side].Sect[fdc.rd_sect].N) 431 | { 432 | fdc.rd_SectorSize = 128 << fdc.CurrTrackDatasDSK[fdc.Side].Sect[fdc.rd_sect].N; 433 | } 434 | else 435 | { 436 | fdc.rd_SectorSize = fdc.CurrTrackDatasDSK[fdc.Side].Sect[fdc.rd_sect].SectSize; 437 | } 438 | 439 | if (fdc.DiskInfo.TrackSize != 0) // If we are a standard (non-Extended) disk... 440 | fdc.rd_cntdata = ( fdc.rd_sect * fdc.CurrTrackDatasDSK[fdc.Side].SectSize ) << 8; 441 | else 442 | fdc.rd_cntdata = fdc.rd_newPos; 443 | } 444 | break; 445 | 446 | case 8 : 447 | fdc.Status |= STATUS_DIO | STATUS_EXM; 448 | break; 449 | 450 | case 9 : 451 | if ( ! ( fdc.ST0 & ST0_IC1 ) ) 452 | { 453 | if ( --fdc.rd_SectorSize ) 454 | { 455 | fdc.state--; 456 | } 457 | else 458 | { 459 | if ( fdc.R++ < fdc.EOT ) 460 | fdc.state = 7; 461 | else 462 | fdc.Status &= ~STATUS_EXM; 463 | } 464 | return( fdc.ImgDsk[ fdc.PosData[fdc.Side] + fdc.rd_cntdata++ ] ); 465 | } 466 | fdc.Status &= ~STATUS_EXM; 467 | return( 0 ); 468 | 469 | case 10 : 470 | return( fdc.ST0 ); 471 | 472 | case 11 : 473 | return( fdc.ST1 | ST1_EN ); 474 | 475 | case 12 : 476 | return( fdc.ST2 ); 477 | 478 | case 13 : 479 | return( fdc.C ); 480 | 481 | case 14 : 482 | return( fdc.H ); 483 | 484 | case 15 : 485 | return( fdc.R ); 486 | 487 | case 16 : 488 | fdc.state = 0; 489 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 490 | return( fdc.N ); 491 | } 492 | return( 0 ); 493 | } 494 | 495 | static int WriteData( int val ) 496 | { 497 | switch( fdc.state++ ) 498 | { 499 | case 1 : 500 | fdc.Drive = val & 3; 501 | fdc.Side = (val >> 2) & 1; 502 | SetST0(); 503 | break; 504 | 505 | case 2 : 506 | fdc.C = val; 507 | break; 508 | 509 | case 3 : 510 | fdc.H = val; 511 | break; 512 | 513 | case 4 : 514 | fdc.R = val; 515 | break; 516 | 517 | case 5 : 518 | fdc.N = val; 519 | break; 520 | 521 | case 6 : 522 | fdc.EOT = val; 523 | break; 524 | 525 | case 7 : 526 | fdc.wr_sect = SeekSector( &fdc.wr_newPos ); 527 | if (fdc.wr_sect != -1) 528 | { 529 | if (fdc.CurrTrackDatasDSK[fdc.Side].Sect[ fdc.wr_sect ].N) 530 | { 531 | fdc.wr_SectorSize = 128 << fdc.CurrTrackDatasDSK[fdc.Side].Sect[ fdc.wr_sect ].N; 532 | } 533 | else 534 | { 535 | fdc.wr_SectorSize = fdc.CurrTrackDatasDSK[fdc.Side].Sect[fdc.wr_sect].SectSize; 536 | } 537 | 538 | 539 | if (fdc.DiskInfo.TrackSize != 0) // If we are a standard (non-Extended) disk... 540 | fdc.wr_cntdata = ( fdc.wr_sect * fdc.CurrTrackDatasDSK[fdc.Side].SectSize ) << 8; 541 | else 542 | fdc.wr_cntdata = fdc.wr_newPos; 543 | 544 | } 545 | break; 546 | 547 | case 8 : 548 | fdc.Status |= STATUS_DIO | STATUS_EXM; 549 | break; 550 | 551 | case 9 : 552 | if ( ! ( fdc.ST0 & ST0_IC1 ) ) 553 | { 554 | floppy_sound = 2; 555 | floppy_action = 1; 556 | 557 | fdc.dirty_counter = 2; 558 | fdc.bDirtyFlags[(fdc.PosData[fdc.Side] + fdc.wr_cntdata) / 4096] = 1; 559 | 560 | fdc.ImgDsk[ fdc.PosData[fdc.Side] + fdc.wr_cntdata++ ] = ( UBYTE )val; 561 | if ( --fdc.wr_SectorSize ) 562 | { 563 | fdc.state--; 564 | } 565 | else 566 | { 567 | if ( fdc.R++ < fdc.EOT ) 568 | fdc.state = 7; 569 | else 570 | fdc.Status &= ~STATUS_EXM; 571 | } 572 | return( 0 ); 573 | } 574 | fdc.Status &= ~STATUS_EXM; 575 | return( 0 ); 576 | 577 | case 10 : 578 | if ( ! ( fdc.ST0 & ST0_IC1 ) ) 579 | { 580 | fdc.FlagWrite = 1; 581 | } 582 | return( fdc.ST0 ); 583 | 584 | case 11 : 585 | return( fdc.ST1 ); 586 | 587 | case 12 : 588 | return( fdc.ST2 ); 589 | 590 | case 13 : 591 | return( fdc.C ); 592 | 593 | case 14 : 594 | return( fdc.H ); 595 | 596 | case 15 : 597 | return( fdc.R ); 598 | 599 | case 16 : 600 | fdc.state = 0; 601 | fdc.Status &= ~STATUS_CB & ~STATUS_DIO; 602 | return( fdc.N ); 603 | } 604 | return( 0 ); 605 | } 606 | 607 | pfctFDC fdc_func_lookup[] = 608 | { 609 | Nothing, // 0x00 610 | Nothing, // 0x01 611 | Nothing, // 0x02 612 | Specify, // 0x03 613 | ReadST3, // 0x04 614 | WriteData, // 0x05 615 | ReadData, // 0x06 616 | MoveTrack0, // 0x07 617 | ReadST0, // 0x08 618 | WriteData, // 0x09 619 | ReadID, // 0x0A 620 | Nothing, // 0x0B 621 | ReadData, // 0x0C 622 | FormatTrack,// 0x0D 623 | Nothing, // 0x0E 624 | MoveTrack, // 0x0F 625 | Nothing, // 0x10 626 | Scan, // 0x11 627 | Nothing, // 0x12 628 | Nothing, // 0x13 629 | Nothing, // 0x14 630 | Nothing, // 0x15 631 | Nothing, // 0x16 632 | Nothing, // 0x17 633 | Nothing, // 0x18 634 | Nothing, // 0x19 635 | Nothing, // 0x1A 636 | Nothing, // 0x1B 637 | Nothing, // 0x1C 638 | Nothing, // 0x1D 639 | Nothing, // 0x1E 640 | Nothing, // 0x1F 641 | }; 642 | 643 | void FDC_frame(void) 644 | { 645 | if (fdc.ReadyIn) 646 | { 647 | if (--fdc.ReadyIn == 0) 648 | { 649 | fdc.Image=1; 650 | } 651 | 652 | if (fdc.Motor && fdc.Image && !fdc.Drive) 653 | { 654 | fdc.ST0 &= ~ST0_NR; 655 | fdc.ST0 &= ~ST0_IC1 & ~ST0_IC2; 656 | } 657 | else 658 | { 659 | fdc.ST0 |= ST0_NR; 660 | if ( !fdc.Image ) 661 | { 662 | fdc.ST0 |= ( ST0_IC1 | ST0_IC2 ); 663 | } 664 | } 665 | 666 | } 667 | } 668 | 669 | int ReadFDC( int port ) 670 | { 671 | if (port & 1) 672 | { 673 | return( fdc_func_lookup[fdc.function](port) ); 674 | } 675 | 676 | return( fdc.Status ); 677 | } 678 | 679 | void WriteFDC( int port, int val ) 680 | { 681 | if (port == 0xFB7F) 682 | { 683 | if (fdc.state) 684 | { 685 | fdc_func_lookup[fdc.function](val); 686 | } 687 | else 688 | { 689 | fdc.Status |= STATUS_CB; 690 | fdc.state = 1; 691 | fdc.function = (val & 0x1F); 692 | 693 | switch( fdc.function ) 694 | { 695 | case 0x03 : 696 | // Specify 697 | break; 698 | 699 | case 0x04 : 700 | // Read ST3 701 | break; 702 | 703 | case 0x05 : 704 | // Write data 705 | break; 706 | 707 | case 0x06 : 708 | // Reading data 709 | break; 710 | 711 | case 0x07 : 712 | // Track head movement 0 713 | break; 714 | 715 | case 0x08 : 716 | // Read ST0, track 717 | fdc.Status |= STATUS_DIO; 718 | break; 719 | 720 | case 0x09 : 721 | // Write data 722 | break; 723 | 724 | case 0x0A : 725 | // Read Field ID 726 | break; 727 | 728 | case 0x0C : 729 | // Read Data 730 | break; 731 | 732 | case 0x0D : 733 | // Track formatting 734 | break; 735 | 736 | case 0x0F : 737 | // Head movement 738 | break; 739 | 740 | case 0x11 : 741 | // Scan 742 | break; 743 | 744 | default : 745 | fdc.Status |= STATUS_DIO; 746 | } 747 | } 748 | } 749 | else 750 | { 751 | if (port == 0xFA7E) 752 | { 753 | fdc.Motor = val & 1; 754 | } 755 | } 756 | } 757 | 758 | void ResetFDC( void ) 759 | { 760 | // Start with a blank slate... 761 | memset(&fdc, 0x00, sizeof(fdc)); 762 | 763 | fdc.Drive = 0; 764 | fdc.Side = 0; 765 | fdc.sector_index = 0; 766 | fdc.Status = STATUS_RQM; 767 | fdc.ST0 = ST0_SE; 768 | fdc.ST1 = 0; 769 | fdc.ST2 = 0; 770 | fdc.ST3 = 0; 771 | fdc.Busy = 0; 772 | fdc.Inter = 0; 773 | fdc.state = 0; 774 | fdc.Motor = 0; 775 | fdc.ReadyIn = 0; 776 | } 777 | 778 | // -------------------------------------------------------------- 779 | // This is called when a disk is inserted into the emulated 780 | // CPC machine. Only one disk drive (A: or Drive 0) is emulated. 781 | // -------------------------------------------------------------- 782 | void ReadDiskMem(u8 *rom, u32 romsize) 783 | { 784 | // -------------------------- 785 | // Eject current disk image 786 | // -------------------------- 787 | if (fdc.Image!=0) fdc.Image = 0; 788 | 789 | // ---------------------------------------------------- 790 | // And read in the new disk image into the FDC buffers 791 | // ---------------------------------------------------- 792 | fdc.disk_size=romsize-sizeof(fdc.DiskInfo); 793 | 794 | fdc.ImgDsk=(u8*)DISK_IMAGE_BUFFER; 795 | 796 | memcpy(&fdc.DiskInfo, rom, sizeof(fdc.DiskInfo)); 797 | memcpy(fdc.ImgDsk, rom+sizeof(fdc.DiskInfo), fdc.disk_size); 798 | 799 | // --------------------------------------------------------------------------- 800 | // Setting ReadyIn here will mark the status as 'Not Ready' for 12 frames 801 | // as there are some games that monitor the status to see if the disk has 802 | // actually been ejected and swapped for another disk. Orion Prime does this. 803 | // --------------------------------------------------------------------------- 804 | fdc.ReadyIn = 12; 805 | fdc.FlagWrite=0; 806 | 807 | // -------------------------------------------------------------------------------------------- 808 | // Note: there is some confusion as to whether two sides should have the bit set or reset. 809 | // The CPC wiki says this signal is inverted and so does the French Floppy Guide so that's 810 | // what we're going with here. Basically we clear the TWO SIDES signal in ST3 if the disk 811 | // we have loaded indicates it has more than one side. 812 | // -------------------------------------------------------------------------------------------- 813 | if (fdc.DiskInfo.NumHeads > 1) 814 | { 815 | fdc.ST3 &= ~ST3_TS; // Clear Two Sides signal (inverted means two-sided drive) 816 | } 817 | else 818 | { 819 | fdc.ST3 |= ST3_TS; // Set Two Sides signal (inverted means one-sided drive) 820 | } 821 | 822 | // ------------------------------------------------------ 823 | // A new disk so seek to track zero to get us started... 824 | // ------------------------------------------------------ 825 | ChangeCurrTrack(0); 826 | } 827 | -------------------------------------------------------------------------------- /arm9/source/fdc.h: -------------------------------------------------------------------------------- 1 | // SugarDS is Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 2 | // 3 | // Bits of pieces of this emulator have been glued and attached from a large number of sources - along with a healthy amount of 4 | // code by this author to pull it all together. Although it was hard to trace everythign to the original sources, I believe all 5 | // sources have released their material under the GNU General Public License and, as such, the SugarDS emulator follows suit. 6 | // 7 | // Previous contributions to this codebase: 8 | // 9 | // CrocoDS: CPC Emulator for the DS - Copyright (c) 2013 Miguel Vanhove (Kyuran) 10 | // Win-CPC: Amstrad CPC Emulator - Copyright (c) 2012 Ludovic Deplanque. 11 | // Caprice32: Amstrad CPC Emulator - Copyright (c) 1997-2004 Ulrich Doewich. 12 | // Arnold: Amstrad CPC Emulator - Copyright (c) 1995-2002, 2007 Andreas Micklei and Kevin Thacker 13 | // 14 | // As far as I'm concerned, you can use this code in whatever way suits you provided you continue to release the sources under 15 | // the original copyright notice (see below) which appeared to be the intention of all the pioneers who came before me. 16 | // 17 | // Original Copyright Notice 18 | // This program is free software; you can redistribute it and/or modify 19 | // it under the terms of the GNU General Public License as published by 20 | // the Free Software Foundation; either version 2 of the License, or 21 | // (at your option) any later version. 22 | // 23 | // This program is distributed in the hope that it will be useful, 24 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | // GNU General Public License for more details. 27 | // 28 | // You should have received a copy of the GNU General Public License 29 | // along with this program; if not, write to the Free Software 30 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 31 | 32 | #ifndef FDC_H 33 | #define FDC_H 34 | 35 | typedef unsigned short USHORT; 36 | typedef signed short SHORT; 37 | typedef unsigned char UBYTE; 38 | typedef unsigned long ULONG; 39 | 40 | #ifndef _BOOL 41 | #define _BOOL 42 | typedef u8 BOOL; 43 | #endif 44 | 45 | void ChangeCurrTrack( int newTrack ); 46 | void ReadCHRN( void ); 47 | int SeekSector( int * pos ); 48 | int ReadFDC( int port ); 49 | void WriteFDC( int Port, int val ); 50 | void ResetFDC( void ); 51 | void EjectDiskFDC( void ); 52 | void ReadDiskMem(u8 *rom, u32 romsize); 53 | void FDC_frame(void); 54 | 55 | #pragma pack(1) 56 | typedef struct 57 | { 58 | char debut[ 0x30 ]; // "MV - CPCEMU Disk-File\r\nDisk-Info\r\n" or "EXTENDED CPC DSK File\r\nDisk-Info\r\n" 59 | UBYTE NumTracks; 60 | UBYTE NumHeads; 61 | SHORT TrackSize; // For non-Extended disks. 0x1300 = 256 + ( 512 * NumberOfSectors ) 62 | UBYTE TrackSizes[ 0xCC ]; // For Extended Disks 63 | } CPCEMUHeader; 64 | 65 | typedef struct 66 | { 67 | UBYTE C; // track 68 | UBYTE H; // head (side) 69 | UBYTE R; // sect ID 70 | UBYTE N; // sect size 71 | UBYTE ST1; // FDC Status ST1 72 | UBYTE ST2; // FDC Status ST2 73 | SHORT SectSize; // Size of sectors 74 | } CPCEMUSect; 75 | 76 | typedef struct 77 | { 78 | char ID[ 0x10 ]; // "Track-Info\r\n" 79 | UBYTE Track; 80 | UBYTE Head; 81 | SHORT Unused; 82 | UBYTE SectSize; // 2 83 | UBYTE NbSect; // 9 84 | UBYTE Gap3; // 0x4E 85 | UBYTE PadByte; // 0xE5 86 | CPCEMUSect Sect[ 29 ]; 87 | } CPCEMUTrack; 88 | #pragma pack() 89 | 90 | 91 | typedef struct 92 | { 93 | int disk_size; 94 | int state; 95 | CPCEMUHeader DiskInfo; 96 | CPCEMUTrack CurrTrackDatasDSK[2]; // For 2 heads/sides 97 | int PosData[2]; 98 | UBYTE FlagWrite; 99 | UBYTE Image; 100 | UBYTE DriveBusy; 101 | UBYTE Status; 102 | UBYTE ST0; 103 | UBYTE ST1; 104 | UBYTE ST2; 105 | UBYTE ST3; 106 | UBYTE C; 107 | UBYTE H; 108 | UBYTE R; 109 | UBYTE N; 110 | UBYTE Drive; 111 | UBYTE Side; 112 | UBYTE EOT; 113 | UBYTE Busy; 114 | UBYTE Inter; 115 | UBYTE Motor; 116 | UBYTE sector_index; 117 | UBYTE function; 118 | UBYTE dirty_counter; 119 | UBYTE ReadyIn; 120 | int rd_sect; 121 | int rd_cntdata; 122 | int rd_newPos; 123 | int rd_SectorSize; 124 | int wr_sect; 125 | int wr_cntdata; 126 | int wr_newPos; 127 | int wr_SectorSize; 128 | u8 bDirtyFlags[256]; // one flag for each of 256 possible 4K SD flash blocks (1024K max) 129 | u8 *ImgDsk; 130 | } FDC_t; 131 | 132 | extern FDC_t fdc; 133 | 134 | #endif // FDC_H 135 | -------------------------------------------------------------------------------- /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 and Marat 7 | // Fayzullin (ColEM core) are thanked profusely. 8 | // 9 | // The SugarDS 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 "SugarDS.h" 21 | #include "CRC32.h" 22 | #include "cpu/z80/Z80_interface.h" 23 | #include "AmsUtils.h" 24 | #include "printf.h" 25 | #include "fdc.h" 26 | #include "lzav.h" 27 | 28 | #define SUGAR_SAVE_VER 0x0004 // Change this if the basic format of the .SAV file changes. Invalidates older .sav files. 29 | 30 | /********************************************************************************* 31 | * Save the current state - save everything we need to a single .sav file. 32 | ********************************************************************************/ 33 | u8 spare[256] = {0x00}; // We keep some spare bytes so we can use them in the future without changing the structure 34 | 35 | static char szLoadFile[256]; // We build the filename out of the base filename and tack on .sav, .ee, etc. 36 | static char tmpStr[32]; // For various screen status strings 37 | 38 | u8 CompressBuffer[150*1024]; // Big enough to handle compression of even full 128K games 39 | 40 | void amstradSaveState() 41 | { 42 | size_t retVal; 43 | 44 | // Return to the original path 45 | chdir(initial_path); 46 | 47 | // Init filename = romname and SAV in place of ROM 48 | DIR* dir = opendir("sav"); 49 | if (dir) closedir(dir); // Directory exists... close it out and move on. 50 | else mkdir("sav", 0777); // Otherwise create the directory... 51 | sprintf(szLoadFile,"sav/%s", initial_file); 52 | 53 | int len = strlen(szLoadFile); 54 | szLoadFile[len-3] = 's'; 55 | szLoadFile[len-2] = 'a'; 56 | szLoadFile[len-1] = 'v'; 57 | 58 | strcpy(tmpStr,"SAVING..."); 59 | DSPrint(18,0,0,tmpStr); 60 | 61 | FILE *handle = fopen(szLoadFile, "wb+"); 62 | if (handle != NULL) 63 | { 64 | // Write Version 65 | u16 save_ver = SUGAR_SAVE_VER; 66 | retVal = fwrite(&save_ver, sizeof(u16), 1, handle); 67 | 68 | // Write Last Directory Path / Disk File 69 | if (retVal) retVal = fwrite(last_path, sizeof(last_path), 1, handle); 70 | if (retVal) retVal = fwrite(last_file, sizeof(last_file), 1, handle); 71 | 72 | // Write CZ80 CPU 73 | if (retVal) retVal = fwrite(&CPU, sizeof(CPU), 1, handle); 74 | 75 | // Write AY Chip info 76 | if (retVal) retVal = fwrite(&myAY, sizeof(myAY), 1, handle); 77 | 78 | // Write the FDC floppy struct 79 | if (retVal) retVal = fwrite(&fdc, sizeof(fdc), 1, handle); 80 | 81 | // Write CRTC info 82 | if (retVal) retVal = fwrite(CRTC, sizeof(CRTC), 1, handle); 83 | if (retVal) retVal = fwrite(&CRT_Idx, sizeof(CRT_Idx), 1, handle); 84 | 85 | // And a bunch more CRTC and Amstrad misc stuff... 86 | if (retVal) retVal = fwrite(&HCC, sizeof(HCC), 1, handle); 87 | if (retVal) retVal = fwrite(&HSC, sizeof(HSC), 1, handle); 88 | if (retVal) retVal = fwrite(&VCC, sizeof(VCC), 1, handle); 89 | if (retVal) retVal = fwrite(&VSC, sizeof(VSC), 1, handle); 90 | if (retVal) retVal = fwrite(&VLC, sizeof(VLC), 1, handle); 91 | if (retVal) retVal = fwrite(&R52, sizeof(R52), 1, handle); 92 | if (retVal) retVal = fwrite(&R52, sizeof(R52), 1, handle); 93 | if (retVal) retVal = fwrite(&VTAC, sizeof(VTAC), 1, handle); 94 | if (retVal) retVal = fwrite(&DISPEN, sizeof(DISPEN), 1, handle); 95 | 96 | if (retVal) retVal = fwrite(¤t_ds_line, sizeof(current_ds_line), 1, handle); 97 | if (retVal) retVal = fwrite(&vsync_plus_two, sizeof(vsync_plus_two), 1, handle); 98 | if (retVal) retVal = fwrite(&r12_screen_offset, sizeof(r12_screen_offset), 1, handle); 99 | if (retVal) retVal = fwrite(&raster_counter, sizeof(raster_counter), 1, handle); 100 | if (retVal) retVal = fwrite(&vsync_off_count, sizeof(vsync_off_count), 1, handle); 101 | if (retVal) retVal = fwrite(&escapeClause, sizeof(escapeClause), 1, handle); 102 | if (retVal) retVal = fwrite(&vSyncSeen, sizeof(vSyncSeen), 1, handle); 103 | if (retVal) retVal = fwrite(&display_disable_in,sizeof(display_disable_in), 1, handle); 104 | if (retVal) retVal = fwrite(&scanline_count, sizeof(scanline_count), 1, handle); 105 | if (retVal) retVal = fwrite(&b32K_Mode, sizeof(b32K_Mode), 1, handle); 106 | 107 | if (retVal) retVal = fwrite(&MMR, sizeof(MMR), 1, handle); 108 | if (retVal) retVal = fwrite(&RMR, sizeof(RMR), 1, handle); 109 | if (retVal) retVal = fwrite(&PENR, sizeof(PENR), 1, handle); 110 | if (retVal) retVal = fwrite(&UROM, sizeof(UROM), 1, handle); 111 | 112 | if (retVal) retVal = fwrite(&border_color, sizeof(border_color), 1, handle); 113 | if (retVal) retVal = fwrite(INK, sizeof(INK), 1, handle); 114 | if (retVal) retVal = fwrite(ink_map, sizeof(ink_map), 1, handle); 115 | if (retVal) retVal = fwrite(&inks_changed, sizeof(inks_changed), 1, handle); 116 | if (retVal) retVal = fwrite(&refresh_tstates, sizeof(refresh_tstates), 1, handle); 117 | 118 | if (retVal) retVal = fwrite(&portA, sizeof(portA), 1, handle); 119 | if (retVal) retVal = fwrite(&portB, sizeof(portB), 1, handle); 120 | if (retVal) retVal = fwrite(&portC, sizeof(portC), 1, handle); 121 | 122 | if (retVal) retVal = fwrite(&DAN_Zone0, sizeof(DAN_Zone0), 1, handle); 123 | if (retVal) retVal = fwrite(&DAN_Zone1, sizeof(DAN_Zone1), 1, handle); 124 | if (retVal) retVal = fwrite(&DAN_Config, sizeof(DAN_Config), 1, handle); 125 | 126 | if (retVal) retVal = fwrite(&portDIR, sizeof(portDIR), 1, handle); 127 | if (retVal) retVal = fwrite(spare, 255, 1, handle); 128 | 129 | // The RAM highwater tells us how many extra RAM banks were utilized 130 | if (retVal) retVal = fwrite(&ram_highwater, sizeof(ram_highwater), 1, handle); 131 | 132 | // ------------------------------------------------------------------- 133 | // Save Z80 Memory Map... All 128K of it! 134 | // 135 | // Compress the RAM data using 'high' compression ratio... it's 136 | // still quite fast for such small memory buffers and often shrinks 137 | // 128K of memory down to less than 32K (or 64K at worst). 138 | // ------------------------------------------------------------------- 139 | int max_len = lzav_compress_bound_hi( 0x20000 ); 140 | int comp_len = lzav_compress_hi( RAM_Memory, CompressBuffer, 0x20000, max_len ); 141 | 142 | if (retVal) retVal = fwrite(&comp_len, sizeof(comp_len), 1, handle); 143 | if (retVal) retVal = fwrite(&CompressBuffer, comp_len, 1, handle); 144 | 145 | if (ram_highwater) // If we used more than one extra 64K bank... we need to save those 146 | { 147 | u8 *upper_ram_block = 0; 148 | for (u8 block=1; block<=ram_highwater; block++) 149 | { 150 | switch (block) 151 | { 152 | case 1: upper_ram_block = ROM_Memory+0xF0000; break; 153 | case 2: upper_ram_block = ROM_Memory+0xE0000; break; 154 | case 3: upper_ram_block = ROM_Memory+0xD0000; break; 155 | case 4: upper_ram_block = ROM_Memory+0xC0000; break; 156 | case 5: upper_ram_block = ROM_Memory+0xB0000; break; 157 | case 6: upper_ram_block = ROM_Memory+0xA0000; break; 158 | case 7: upper_ram_block = ROM_Memory+0x90000; break; 159 | } 160 | 161 | int max_len = lzav_compress_bound_hi( 0x10000 ); 162 | int comp_len = lzav_compress_hi( upper_ram_block, CompressBuffer, 0x10000, max_len ); 163 | 164 | if (retVal) retVal = fwrite(&comp_len, sizeof(comp_len), 1, handle); 165 | if (retVal) retVal = fwrite(&CompressBuffer, comp_len, 1, handle); 166 | } 167 | } 168 | 169 | strcpy(tmpStr, (retVal ? "OK ":"ERR")); 170 | DSPrint(27,0,0,tmpStr); 171 | WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL; 172 | DSPrint(18,0,0," "); 173 | DisplayStatusLine(true); 174 | } 175 | else { 176 | strcpy(tmpStr,"Error opening SAV file ..."); 177 | } 178 | fclose(handle); 179 | } 180 | 181 | 182 | /********************************************************************************* 183 | * Load the current state - read everything back from the .sav file. 184 | ********************************************************************************/ 185 | void amstradLoadState() 186 | { 187 | size_t retVal; 188 | 189 | // Return to the original path 190 | chdir(initial_path); 191 | 192 | // Init filename = romname and .SAV in place of ROM 193 | sprintf(szLoadFile,"sav/%s", initial_file); 194 | int len = strlen(szLoadFile); 195 | 196 | szLoadFile[len-3] = 's'; 197 | szLoadFile[len-2] = 'a'; 198 | szLoadFile[len-1] = 'v'; 199 | 200 | FILE* handle = fopen(szLoadFile, "rb"); 201 | if (handle != NULL) 202 | { 203 | strcpy(tmpStr,"LOADING..."); 204 | DSPrint(18,0,0,tmpStr); 205 | 206 | // Read Version 207 | u16 save_ver = 0xBEEF; 208 | retVal = fread(&save_ver, sizeof(u16), 1, handle); 209 | 210 | if (save_ver == SUGAR_SAVE_VER) 211 | { 212 | // Read Last Directory Path / Disk File 213 | if (retVal) retVal = fread(last_path, sizeof(last_path), 1, handle); 214 | if (retVal) retVal = fread(last_file, sizeof(last_file), 1, handle); 215 | 216 | // ---------------------------------------------------------------- 217 | // If the last known file was a disk file we want to reload it. 218 | // ---------------------------------------------------------------- 219 | if ( (strcasecmp(strrchr(last_file, '.'), ".dsk") == 0) ) 220 | { 221 | chdir(last_path); 222 | DiskInsert(last_file, true); 223 | } 224 | 225 | // Read CZ80 CPU 226 | if (retVal) retVal = fread(&CPU, sizeof(CPU), 1, handle); 227 | 228 | // Read AY Chip info 229 | if (retVal) retVal = fread(&myAY, sizeof(myAY), 1, handle); 230 | 231 | // Read the FDC floppy struct 232 | if (retVal) retVal = fread(&fdc, sizeof(fdc), 1, handle); 233 | if (fdc.ImgDsk) fdc.ImgDsk = DISK_IMAGE_BUFFER; 234 | 235 | // Read CRTC info 236 | if (retVal) retVal = fread(CRTC, sizeof(CRTC), 1, handle); 237 | if (retVal) retVal = fread(&CRT_Idx, sizeof(CRT_Idx), 1, handle); 238 | 239 | // And a bunch more CRTC and Amstrad misc stuff... 240 | if (retVal) retVal = fread(&HCC, sizeof(HCC), 1, handle); 241 | if (retVal) retVal = fread(&HSC, sizeof(HSC), 1, handle); 242 | if (retVal) retVal = fread(&VCC, sizeof(VCC), 1, handle); 243 | if (retVal) retVal = fread(&VSC, sizeof(VSC), 1, handle); 244 | if (retVal) retVal = fread(&VLC, sizeof(VLC), 1, handle); 245 | if (retVal) retVal = fread(&R52, sizeof(R52), 1, handle); 246 | if (retVal) retVal = fread(&R52, sizeof(R52), 1, handle); 247 | if (retVal) retVal = fread(&VTAC, sizeof(VTAC), 1, handle); 248 | if (retVal) retVal = fread(&DISPEN, sizeof(DISPEN), 1, handle); 249 | 250 | if (retVal) retVal = fread(¤t_ds_line, sizeof(current_ds_line), 1, handle); 251 | if (retVal) retVal = fread(&vsync_plus_two, sizeof(vsync_plus_two), 1, handle); 252 | if (retVal) retVal = fread(&r12_screen_offset, sizeof(r12_screen_offset), 1, handle); 253 | if (retVal) retVal = fread(&raster_counter, sizeof(raster_counter), 1, handle); 254 | if (retVal) retVal = fread(&vsync_off_count, sizeof(vsync_off_count), 1, handle); 255 | if (retVal) retVal = fread(&escapeClause, sizeof(escapeClause), 1, handle); 256 | if (retVal) retVal = fread(&vSyncSeen, sizeof(vSyncSeen), 1, handle); 257 | if (retVal) retVal = fread(&display_disable_in,sizeof(display_disable_in), 1, handle); 258 | if (retVal) retVal = fread(&scanline_count, sizeof(scanline_count), 1, handle); 259 | if (retVal) retVal = fread(&b32K_Mode, sizeof(b32K_Mode), 1, handle); 260 | 261 | if (retVal) retVal = fread(&MMR, sizeof(MMR), 1, handle); 262 | if (retVal) retVal = fread(&RMR, sizeof(RMR), 1, handle); 263 | if (retVal) retVal = fread(&PENR, sizeof(PENR), 1, handle); 264 | if (retVal) retVal = fread(&UROM, sizeof(UROM), 1, handle); 265 | 266 | if (retVal) retVal = fread(&border_color, sizeof(border_color), 1, handle); 267 | if (retVal) retVal = fread(INK, sizeof(INK), 1, handle); 268 | if (retVal) retVal = fread(ink_map, sizeof(ink_map), 1, handle); 269 | if (retVal) retVal = fread(&inks_changed, sizeof(inks_changed), 1, handle); 270 | if (retVal) retVal = fread(&refresh_tstates, sizeof(refresh_tstates), 1, handle); 271 | 272 | if (retVal) retVal = fread(&portA, sizeof(portA), 1, handle); 273 | if (retVal) retVal = fread(&portB, sizeof(portB), 1, handle); 274 | if (retVal) retVal = fread(&portC, sizeof(portC), 1, handle); 275 | 276 | if (retVal) retVal = fread(&DAN_Zone0, sizeof(DAN_Zone0), 1, handle); 277 | if (retVal) retVal = fread(&DAN_Zone1, sizeof(DAN_Zone1), 1, handle); 278 | if (retVal) retVal = fread(&DAN_Config, sizeof(DAN_Config), 1, handle); 279 | 280 | if (retVal) retVal = fread(&portDIR, sizeof(portDIR), 1, handle); 281 | if (retVal) retVal = fread(spare, 255, 1, handle); 282 | 283 | // The RAM highwater tells us how many extra RAM banks were utilized 284 | if (retVal) retVal = fread(&ram_highwater, sizeof(ram_highwater), 1, handle); 285 | 286 | // Load Z80 Memory Map... all 128K of it! 287 | int comp_len = 0; 288 | if (retVal) retVal = fread(&comp_len, sizeof(comp_len), 1, handle); 289 | if (retVal) retVal = fread(&CompressBuffer, comp_len, 1, handle); 290 | 291 | // ------------------------------------------------------------------ 292 | // Decompress the previously compressed RAM and put it back into the 293 | // right memory location... this is quite fast all things considered. 294 | // ------------------------------------------------------------------ 295 | (void)lzav_decompress( CompressBuffer, RAM_Memory, comp_len, 0x20000 ); 296 | 297 | if (ram_highwater) // If we used more than one extra 64K bank... we need to save those 298 | { 299 | u8 *upper_ram_block = 0; 300 | for (u8 block=1; block<=ram_highwater; block++) 301 | { 302 | int comp_len = 0; 303 | if (retVal) retVal = fread(&comp_len, sizeof(comp_len), 1, handle); 304 | if (retVal) retVal = fread(&CompressBuffer, comp_len, 1, handle); 305 | 306 | switch (block) 307 | { 308 | case 1: upper_ram_block = ROM_Memory+0xF0000; break; 309 | case 2: upper_ram_block = ROM_Memory+0xE0000; break; 310 | case 3: upper_ram_block = ROM_Memory+0xD0000; break; 311 | case 4: upper_ram_block = ROM_Memory+0xC0000; break; 312 | case 5: upper_ram_block = ROM_Memory+0xB0000; break; 313 | case 6: upper_ram_block = ROM_Memory+0xA0000; break; 314 | case 7: upper_ram_block = ROM_Memory+0x90000; break; 315 | } 316 | 317 | (void)lzav_decompress( CompressBuffer, upper_ram_block, comp_len, 0x10000 ); 318 | } 319 | } 320 | 321 | 322 | // And put the memory pointers back in place... 323 | ConfigureMemory(); 324 | compute_pre_inked(0); 325 | compute_pre_inked(1); 326 | compute_pre_inked(2); 327 | 328 | strcpy(tmpStr, (retVal ? "OK ":"ERR")); 329 | DSPrint(27,0,0,tmpStr); 330 | 331 | WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL; 332 | DSPrint(18,0,0," "); 333 | DisplayStatusLine(true); 334 | } 335 | 336 | fclose(handle); 337 | } 338 | else 339 | { 340 | DSPrint(18,0,0,"NO SAVED GAME"); 341 | WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL;WAITVBL; 342 | DSPrint(18,0,0," "); 343 | } 344 | } 345 | 346 | // End of file 347 | -------------------------------------------------------------------------------- /arm9/source/soundbank.h: -------------------------------------------------------------------------------- 1 | #define SFX_CLICKNOQUIT 0 2 | #define SFX_FLOPPY3 1 3 | #define SFX_KEYCLICK 2 4 | #define SFX_MUS_INTRO 3 5 | #define MSL_NSONGS 0 6 | #define MSL_NSAMPS 4 7 | #define MSL_BANKSIZE 4 8 | -------------------------------------------------------------------------------- /logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/logo.bmp -------------------------------------------------------------------------------- /png/global.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/png/global.png -------------------------------------------------------------------------------- /png/keyboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/png/keyboard.png -------------------------------------------------------------------------------- /png/keymap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/png/keymap.png -------------------------------------------------------------------------------- /png/mainmenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/png/mainmenu.png -------------------------------------------------------------------------------- /png/minimenu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/png/minimenu.png -------------------------------------------------------------------------------- /png/options.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/png/options.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # SugarDS 2 | ![image](./arm9/gfx_data/splash.png) 3 | ![image](./png/keyboard.png) 4 | 5 | SugarDS is an Amstrad CPC 646 and 6128 Emulator for the DS/DSi 6 | 7 | The Amstrad CPC was released in 1984 and competed with the ZX Spectrum and C64 8 | in the UK and Eastern EU. Although a latecomer to the market, the solid engineering 9 | "all-in-one" design gathered support. There are still many fans of the system today 10 | and plenty of great homebrew games that fully take advantage of the system strengths. 11 | 12 | This emulator is not perfect - but it should be capable enough to render most games 13 | playable on the tiny handheld so you can get your Amstrad gaming on-the-go! 14 | 15 | Features : 16 | ----------------------- 17 | * Emulates CPC 464 (64K) and CPC 6128 (128K) with 512K of extended RAM available. 18 | * Loads .SNA and .DSK files up to 1024K total length (single and double sided). 19 | * Plus2CPC Cartridge Support to load .CPR files up to 512K (note, this is not a plus/GX4000 emulator but will handle cart files provided they don't require plus-features). 20 | * Partial Dandanator Cartridge Support - Enough for Sword of Ianna and Los Amores de Brunilda. Rename files to .dan to load into the emulator properly. 21 | * Emulates CRTC Type 3 roughly - with provisions to handle split screen, rupture, smooth vertical scroll and a reasonable facsimile of smooth horizontal scroll. 22 | * Full button mapping - supporting all 3 possible joystick buttons of the Amstrad as well as mapping buttons to keyboard keys. 23 | * Full touch-screen Amstrad keyboard styled after the colorful CPC 464. 24 | * Save / Load state so you can pick up where you left off. 25 | * Full support for the Spanish CPC 472 machine with the extra 8K of memory! :) 26 | 27 | Copyright : 28 | ----------------------- 29 | SugarDS is Copyright (c) 2025 Dave Bernazzani (wavemotion-dave) 30 | 31 | Bits of pieces of this emulator have been glued and attached from 32 | a large number of sources - along with a healthy amount of code by 33 | this author to pull it all together. Although it was hard to trace 34 | everything to the original sources, I believe all sources have 35 | released their material under the GNU General Public License and, 36 | as such, the SugarDS emulator follows suit. 37 | 38 | If I've misrepresented any previous authors work here, please 39 | contact me and I'll put it right. 40 | 41 | * CrocoDS: CPC Emulator for the DS - Copyright (c) 2013 Miguel Vanhove (Kyuran) 42 | * Win-CPC: Amstrad CPC Emulator - Copyright (c) 2012 Ludovic Deplanque. 43 | * Caprice32: Amstrad CPC Emulator - Copyright (c) 1997-2004 Ulrich Doewich. 44 | * Arnold: Amstrad CPC Emulator - Copyright (c) 1995-2002, 2007 Andreas Micklei and Kevin Thacker 45 | 46 | As far as I'm concerned, you can use this code in whatever way suits you provided you 47 | continue to release the sources under the original copyright notice (see below) which 48 | appeared to be the intention of all the pioneers who came before me. 49 | 50 | The sound driver (ay38910) are libraries from FluBBa (Fredrik Ahlström) 51 | and those copyrights remain his. 52 | 53 | Royalty Free Music for the opening jingle provided by Anvish Parker 54 | 55 | lzav compression (for save states) is Copyright (c) 2023-2025 Aleksey 56 | Vaneev and used by permission of the generous MIT license. 57 | 58 | The Amstrad CPC logo is used without permission but with the maximum 59 | of respect and love. Thank you Alan. 60 | 61 | The SugarDS emulator is offered as-is, without any warranty. 62 | 63 | 64 | BIOS Files : 65 | ----------------------- 66 | Following in the footsteps of virtually all other Amstrad CPC emulators, the BIOS 67 | files are included in the emulator and don't need to be sourced by the user. This 68 | is according to a note from Cliff Lawson: 69 | 70 | "If you are the author of such an emulator then you don't need to write and ask me for 71 | Amstrad's permission to distribute copies of the CPC ROMs. Amstrad's stance on this is 72 | that we are happy for you to redistribute copies of our copyrighted code as long as 73 | a) copyright messages are not changed and 74 | b) either in the program or the documentation you acknowledge that "Amstrad has kindly 75 | given it's permission for it's copyrighted material to be redistributed but Amstrad 76 | retains it's copyright." 77 | 78 | So the Amstrad CPC BIOS files are still copyrighted by Amstrad - in whatever form 79 | that may exist. If you are in an official capacity as the copyright owner of the 80 | BIOS files and wish these stripped from the emulator, please contact me and I'm 81 | happy to do so! Otherwise - many thanks for the indirect permission to use them. 82 | 83 | 84 | ## Original Copyright Notice for the Software (not BIOS files) 85 | ``` 86 | This program is free software; you can redistribute it and/or modify 87 | it under the terms of the GNU General Public License as published by 88 | the Free Software Foundation; either version 2 of the License, or 89 | (at your option) any later version. 90 | 91 | This program is distributed in the hope that it will be useful, 92 | but WITHOUT ANY WARRANTY; without even the implied warranty of 93 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 94 | GNU General Public License for more details. 95 | 96 | You should have received a copy of the GNU General Public License 97 | along with this program; if not, write to the Free Software 98 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 99 | ``` 100 | 101 | Main Menu : 102 | ----------------------- 103 | After the emulator launches (unless you've directly launched a game via Twilight Menu++), you will be 104 | presented with the main menu screen. From here you can load up a disk or cart file to play. 105 | 106 | ![image](./png/mainmenu.png) 107 | 108 | Filenames can be no longer than 160 characters (and the DS can only display 32 at a time and will scroll 109 | the title of a game as needed) - so please keep your filenames on the shorter side. You can have no more 110 | than 1024 game files in a directory - but can have as many directories as you want. 111 | 112 | 113 | Configuration : 114 | ----------------------- 115 | There is quite a few configuration options that you can explore. Some options are global for the emulator 116 | and some are specific to one game. Please note that the options are associated with the filename (e.g. your 117 | .dsk file on the SD card) of the game you are playing. If you change the filename, the options will have 118 | to be re-entered. 119 | 120 | ![image](./png/options.png) 121 | ![image](./png/global.png) 122 | 123 | When you change options, you must hit the START button on the DS to save out the new configuration to your SD card. 124 | Otherwise the options will only work for this game play session. 125 | 126 | If you are playing a game like Robocop, Chase HQ or Manic Miner which hits the AY sound chip hard to produce "speech" or 127 | similar digitizied effects, you should set the **Sound Driver** to 'WAVE DIRECT'. This is a bit more taxing on the emulator 128 | but it will render speech and other digitized effects quite well. 129 | 130 | Of primary importance to gameplay are these two: **R52 vSync** and **CPU Adjust**. 131 | 132 | Normally you shouldn't touch either adjustment... unless the game is not running correctly. In that case, try the following: 133 | 134 | * If the game is running slower than on real hardware (e.g. Dizzy III which slows down when you move) then adjust the R52 vSync to 'Forgiving'. 135 | * If the game has minor graphical glitches - say a stray line (e.g. Sword of Ianna on screen transitions) then try a CPU Adjust of -1 or -2 at most. 136 | 137 | Because the emulator is doing line-based (vs cycle-based) emulation, the accuracy is only to that of a scanline and sometimes these small tweaks are 138 | necessary to get games running as close as possible to real hardware. 139 | 140 | A number of commercial games will be auto-recognized and will have some tweaks automatically selected so they run as close to perfect as I can get them. 141 | 142 | Mode 2 (up to 640 horizontal pixels) is a bitch for the poor little DS with only 256 pixel resolution. To that end, we have a mode 2 setting called 143 | 'PAN+SCAN' which renders the screen much bigger but requires that you press the upper left/right (where the AMSTRAD logo is) of the touch screen to 144 | scroll left/right. This will allow games like Orion Prime to be playable so you can actually read the emails you're getting in-game. 145 | 146 | One option that can be handy for certian ladder or maze games is the D-Pad "Slide-n-Glide" which was designed originally for my ZX Spectrum emulator and 147 | specifically for Chuckie Egg. Sometimes with climbing/maze games it's hard to make the exact turn onto a ladder. With 'Slide-n-Glide', the controls will be 148 | more forgiving by continuing to move in the Left/Right or Up/Down direction for a few more frames while another direction is pressed. This makes it much (much!) 149 | easier to navigate onto and off of ladders in games like Chuckie Egg... Maze Games (pacman, etc) also benefit. 150 | 151 | Key Mapping : 152 | ----------------------- 153 | Any of the non shoulder buttons can be mapped to any joystick button and/or keyboard key. 154 | 155 | ![image](./png/keymap.png) 156 | 157 | The shoulder buttons are special: 158 | 159 | Shoulder button L + D-Pad for offset 160 | Shoulder button R + D-Pad for scale (turn off auto-scale) 161 | 162 | It's critical that you use the L/R buttons to shift/scale the screen as the Amstrad 163 | CPC will often utilize more pixels than the DS has resolution (192 vertical pixels) 164 | so you will be forced to either compress (squash) the screen or else position the 165 | screen carefully and map one of the buttons to PAN UP or PAN DOWN the screen briefly. 166 | This works really well for games that show status or score at the top or bottom of 167 | the screen but otherwise doesn't really affect the main gameplay area. 168 | 169 | DISK Support : 170 | ----------------------- 171 | .DSK files up to the maximum allowed by 3.5" drives using PARADOS is roughly 720K. Most 172 | disks should auto-load but if your disk does not, it should provide a catalog of the 173 | possible filenames that could be used to run the program. One trick is to include 174 | the command you want to run in the filename of the .DSK file itself. That helps the 175 | auto-type detection algorithm. To force a very specific run command, place the name 176 | of the Amstrad CPC file you wish to run in double brackets like this: 177 | 178 | "Orion Prime 3_5 Inch Disk [[ORION]].dsk" 179 | 180 | This when that .dsk file is loaded, the emulator will sense what's between the double 181 | brackets and issue the proper RUN "ORION" command 182 | 183 | Note that sometimes one disk version of a game won't load properly but a different version will. 184 | Keep looking - you're very likely to find a version that will load and play correctly. Such is 185 | life with emulation and potentially dodgy disk dumps. 186 | 187 | Cartridge Support : 188 | ----------------------- 189 | Although .CPR cartridges up to 512K are supported, this is not a CPC+ (plus) emulator. 190 | So games like ALCON 2020 work fine... as do any other .CPR games that do not specifically 191 | utilize the GX4000 or Amstrad CPC+ (plus) graphics capabilities. 192 | 193 | Dandanator Support : 194 | ----------------------- 195 | Mainly to run two games - Sword of Ianna and Los Amores de Brunilda. Rename those .rom 196 | files as .dan files so that they will be loaded as Dandanator files within the SugarDS 197 | emulator. Note that we do not support Flash writes on these carts - but the games 198 | themselves should be playable and you can use the normal emulator save/load states 199 | to save your progress. 200 | 201 | SNA Support : 202 | ----------------------- 203 | Memory snapshots are supported for both 64K and 128K machines as well as expanded 576K machines. 204 | You should strongly prefer to use .DSK or .CPR (or .DAN) files as snapshots cannot save data nor can they multi-load 205 | and the .dsk emulation is fast enough that the difference between a disk load and a snapshot load is just a few 206 | extra seconds. Think about how long it took to load stuff from cassette/disk when we were kids ... we're so spoiled now! 207 | 208 | Known Issues : 209 | ----------------------- 210 | * Pinball Dreams has graphical glitches on the opening lead-in screens... gameplay is better. 211 | * R-Type Reloaded 128K does not load correctly except for the 3-disk version which does work (despite some loading screen issues - when the screen shows horizontal lines, insert disk 2). 212 | * Megablasters has issues with the emulated CRTC type detection and won't start except for one version which I've added a patch for: The 2020 ENGLISH Re-Release version (4 disks). 213 | * Enlightenment (aka Druid 2) has major graphical glitching. Cause is likely inaccurate CRTC emulation. 214 | * Imperial Mahjongg does not run. Cause is likely inaccurate CRTC emulation. 215 | * Turrican 128K works fine with the two disk version but the single disk version has issues. 216 | 217 | Version History : 218 | ----------------------- 219 | Version 1.3 - 13-Sep-2025 by wavemotion-dave 220 | * Use [[CPM]] in title of .dsk file to launch game via |cpm 221 | * Improved FDC emulation so games like BAT load 222 | * Improved PPI emulation so keyboard scanning works in games like Barbarian 223 | * Fixed the map keys handling so changing the first key slot doesn't always revert back to 'A' 224 | * Other minor improvements and tweaks under the hood. 225 | 226 | Version 1.2 - 22-Jun-2025 by wavemotion-dave 227 | * Less pops clicks when going in/out of selecting games. 228 | * Cleaner/Faster Disk Writes (less pause, better "DISK WRITE" notification) 229 | * Improved Z80 timing - found a few more instructions that needed timing tweaks. 230 | * Improved CRTC emulation - fixed regression on Pinball Dreams, etc. Back to emulation of Type 3. 231 | * Fix for two-sided drive signal for FDC (nothing seemed to be affected by this... but better to be accurate). 232 | * Improved pan/scan for Mode 2 - auto-center and smoother scroll. 233 | * Improved offset handling - cleaner 1 pixel move and faster press-and-hold. 234 | * Added ESC as a possible key map. 235 | 236 | Version 1.1 - 18-Jun-2025 by wavemotion-dave 237 | * New 'Advanced' CRTC driver that renders Prehistorik II and Super Cauldron (among others) playable. Should auto-detect. 238 | * Megablasters 2020 Re-release (ENGLISH) is now supported - start by loading Disk A (Disk 0). 239 | * SNA snapshots can now be up to 576K of RAM memory. 240 | * Improved Mode 2 driver to better render graphics on the small screen. 241 | * Improved Mode 0/1 driver so we don't swap too quickly between modes (less screen flash/shifts). 242 | * Improved all CRT rendering so we have less graphical issues especially when moving from screen to screen. Games like Monty on the Run are good examples of how clean this is now. 243 | * Lots of other little cleanups and improvements as time permitted. 244 | 245 | Version 1.0 - 13-Jun-2025 by wavemotion-dave 246 | * Improved Z80 / CRTC timing so more games run more correctly. 247 | * Improved Mode 2 rendering so it's a little better positioned 'compressed' on the DS screen. 248 | * Improved default key mapping that maps Y button to Joystick Fire 2 (used by many homebrews). 249 | * Another round of improvements for FDC handling of two-sided disks. Orion Prime no longer warns of disk issues, Batman Forever 3.5" loads. 250 | * Fixed the sound mute handler so that there are less frequent pops/clicks when loading up new games. 251 | * Improved auto-load detection - more disks load the correct file more often. 252 | * Lots of small cleanups and commenting of the code. 253 | 254 | Version 0.9 - 08-Jun-2025 by wavemotion-dave 255 | * Fix disk write-back so it doesn't potentially corrupt a .dsk file! Sorry about that. 256 | * Improved save/load state so it preserves Dandanator carts and Extended Memory > 128K. 257 | * More robust CRTC handling to fix games like Hypernoid Zero, Galactic Tomb 128K and Bomb Jack Extra Sugar. 258 | * You can now put [[cmd]] in the title of the .dsk file to force a RUN command. 259 | * Other cleanups, minor timing improvements and fixes as time allowed. 260 | 261 | Version 0.8 - 06-Jun-2025 by wavemotion-dave 262 | * Tweaks to the Z80 core timing to get it closer to real Amstrad performance. Fewer graphical glitches in games. 263 | * Improved two-sided disk support. 264 | * Memory expansion up to 512K is now supported - Mighty Steel Fighters now runs. 265 | * Dandanator support for cart-banking (only - no EEPROM writes). 266 | * Screen dimming of bottom screen added. 267 | * Other minor cleanups and fixes as time allowed. 268 | 269 | Version 0.7 - 04-Jun-2025 by wavemotion-dave 270 | * Double sided disks now supported. Orion Prime in 3.5" floppy works! 271 | * Disks now auto-persist back to the SD card when written. 272 | * CPU Z80 timing improved - more games run more correctly. 273 | * Better auto-filename support for launching disk games. 274 | * Number pad added - press the number pad icon on the main keyboard. 275 | * Mode 2 support improved - use PAN or COMPRESSED mode and upper screen region (the Amstrad Logo area) to pan. 276 | * New Amstrad Croc top screen available - use Global Settings. 277 | * Improved auto-scale in the X (horizontal) direction. 278 | * Minor tweaks and bug fixes as time allowed. 279 | 280 | Version 0.6 - 02-Jun-2025 by wavemotion-dave 281 | * Cartridge .CPR support up to 512K 282 | * Disk support is now up to 3.5" 80-track maximums (720K) 283 | * Multi-disk support added - you can swap disks mid-game via the menu 284 | * Cleanup of Z80 timings so more games run more correctly with fewer graphical glitching 285 | 286 | Version 0.5 - 01-Jun-2025 by wavemotion-dave 287 | * First public beta. Enjoy! 288 | -------------------------------------------------------------------------------- /techdocs/Amstrad CRTC - ACCC1.8-EN.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/techdocs/Amstrad CRTC - ACCC1.8-EN.pdf -------------------------------------------------------------------------------- /techdocs/Z80_CPC_Timings_cheat_sheet.20230709.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wavemotion-dave/SugarDS/b46dc4cf91de97a77272791a88d5b478a7fed933/techdocs/Z80_CPC_Timings_cheat_sheet.20230709.pdf --------------------------------------------------------------------------------