Browse Source

Initial 3DS port

dirtyrect
asiekierka 3 years ago
parent
commit
b5b462dfee

+ 3
- 0
.gitignore View File

@@ -1,6 +1,8 @@
**/CVS
autom4te.cache/
*.o
*.d
*.bin
/src/Makefile
/src/atari800
/src/config.h
@@ -8,3 +10,4 @@ autom4te.cache/
/src/config.log
/src/config.status
/src/configure


+ 259
- 0
Makefile.3ds View File

@@ -0,0 +1,259 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------

ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif

TOPDIR ?= $(CURDIR)
include $(DEVKITARM)/3ds_rules

#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#
# NO_SMDH: if set to anything, no SMDH file is generated.
# ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional)
# APP_TITLE is the name of the app stored in the SMDH file (Optional)
# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional)
# APP_AUTHOR is the author of the app stored in the SMDH file (Optional)
# ICON is the filename of the icon (.png), relative to the project folder.
# If not set, it attempts to use one of the following (in this order):
# - <Project name>.png
# - icon.png
# - <libctru folder>/default_icon.png
#---------------------------------------------------------------------------------
TARGET := $(notdir $(CURDIR))
BUILD := build
#DATA := data
INCLUDES := src
ROMFS := src/3ds/romfs

APP_TITLE=atari800
APP_DESCRIPTION=\"Atari 8-bit computer emulator\"
APP_AUTHOR=\"atari800 development team\"
ICON = src/3ds/gfx/icon.png

# src/af80.c \
# src/pbi_proto80.c \
# src/xep80.c \
# src/xep80_fonts.c \

GRAPHICS = \
src/3ds/gfx/kbd_mapping.png \


SOURCES = \
src/afile.c \
src/antic.c \
src/artifact.c \
src/atari.c \
src/atari_ntsc/atari_ntsc.c \
src/binload.c \
src/cartridge.c \
src/cassette.c \
src/compfile.c \
src/cfg.c \
src/colours.c \
src/colours_external.c \
src/colours_ntsc.c \
src/colours_pal.c \
src/cpu.c \
src/crc32.c \
src/cycle_map.c \
src/devices.c \
src/emuos.c \
src/esc.c \
src/filter_ntsc.c \
src/gtia.c \
src/ide.c \
src/img_tape.c \
src/input.c \
src/log.c \
src/memory.c \
src/monitor.c \
src/mzpokeysnd.c \
src/pal_blending.c \
src/pbi.c \
src/pbi_bb.c \
src/pbi_mio.c \
src/pbi_scsi.c \
src/pbi_xld.c \
src/pia.c \
src/pokey.c \
src/pokeysnd.c \
src/remez.c \
src/rtime.c \
src/screen.c \
src/sio.c \
src/sndsave.c \
src/sound.c \
src/statesav.c \
src/sysrom.c \
src/ui.c \
src/ui_basic.c \
src/util.c \
src/videomode.c \
src/voicebox.c \
src/votrax.c \
src/votraxsnd.c \
src/3ds/input.c \
src/3ds/main.c \
src/3ds/sound_ndsp.c \
src/3ds/video.c

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft

CFLAGS := -g -Wall -O2 -mword-relocations -D_GNU_SOURCE \
-fomit-frame-pointer -ffunction-sections \
$(ARCH)

CFLAGS += $(INCLUDE) -DARM11 -D_3DS

CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11

ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)

LIBS := -lsfil -lpng -lz -lsf2d -lcitro3d -lctru -lm

#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS := $(CTRULIB) $(DEVKITPRO)/portlibs/3ds $(DEVKITPRO)/portlibs/armv6k


#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------

export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)

export VPATH := $(CURDIR)

export DEPSDIR :=

CFILES := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir))
PNGFILES := $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir))

export LD := $(CC)
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(PNGFILES:.png=.bin.o) \
$(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)


export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD) -I$(DEVKITPRO)/portlibs/3ds/include/SDL2 \
-I$(CURDIR)/src/3ds

export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)

ifeq ($(strip $(ICON)),)
icons := $(wildcard *.png)
ifneq (,$(findstring $(TARGET).png,$(icons)))
export APP_ICON := $(TOPDIR)/$(TARGET).png
else
ifneq (,$(findstring icon.png,$(icons)))
export APP_ICON := $(TOPDIR)/icon.png
endif
endif
else
export APP_ICON := $(TOPDIR)/$(ICON)
endif

ifeq ($(strip $(NO_SMDH)),)
export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh
endif

ifneq ($(ROMFS),)
export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS)
endif

.PHONY: $(BUILD) clean all

#---------------------------------------------------------------------------------
all: $(BUILD)

$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile.3ds

#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf


#---------------------------------------------------------------------------------
else

DEPENDS := $(OFILES:.o=.d)

#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
ifeq ($(strip $(NO_SMDH)),)
$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh
else
$(OUTPUT).3dsx : $(OUTPUT).elf
endif

$(OUTPUT).elf : $(OFILES)

#---------------------------------------------------------------------------------
# you need a rule like this for each extension you use as binary data
#---------------------------------------------------------------------------------
%.bin.o : %.bin
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@$(bin2o)

#---------------------------------------------------------------------------------
%.bin: %.png
#---------------------------------------------------------------------------------
@echo $(notdir $<)
@convert $< rgba:$@

#---------------------------------------------------------------------------------
# rules for assembling GPU shaders
#---------------------------------------------------------------------------------
define shader-as
$(eval CURBIN := $(patsubst %.shbin.o,%.shbin,$(notdir $@)))
picasso -o $(CURBIN) $1
bin2s $(CURBIN) | $(AS) -o $@
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h
echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h
echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h
endef

%.shbin.o : %.v.pica %.g.pica
@echo $(notdir $^)
@$(call shader-as,$^)

%.shbin.o : %.v.pica
@echo $(notdir $<)
@$(call shader-as,$<)

%.shbin.o : %.shlist
@echo $(notdir $<)
@$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file)))

-include $(DEPENDS)

#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

+ 559
- 0
src/3ds/config.h View File

@@ -0,0 +1,559 @@
/* config.h. Generated from config.h.in by configure. */
/* config.h.in. Generated from configure.ac by autoheader. */

/* Define if building universal (internal helper macro) */
/* #undef AC_APPLE_UNIVERSAL_BUILD */

/* The Austin Franklin 80 column card. */
// #define AF80 1

/* Target: Android */
/* #undef ANDROID */

/* Target: standard I/O. */
/* #undef BASIC */

/* Define to use buffered debug output. */
/* #undef BUFFERED_LOG */

/* Define to allow sound clipping. */
// #define CLIP_SOUND 1
#undef CLIP_SOUND

/* Define to 1 if the `closedir' function returns void instead of `int'. */
/* #undef CLOSEDIR_VOID */

/* Define to allow console sound (keyboard clicks). */
#define CONSOLE_SOUND 1

/* Define to activate crash menu after CIM instruction. */
#define CRASH_MENU 1

/* Define to disable bitmap graphics emulation in CURSES target. */
/* #undef CURSES_BASIC */

/* Alternate config filename due to 8+3 fs limit. */
#define DEFAULT_CFG_NAME "/3ds/atari800/atari800.cfg"

/* Target: Windows with DirectX. */
/* #undef DIRECTX */

/* Define to use dirty screen partial repaints. */
/* #undef DIRTYRECT */

/* Define to use back slash as directory separator. */
/* #undef DIR_SEP_BACKSLASH */

/* Target: DOS VGA. */
/* #undef DOSVGA */

/* Define to enable DOS style drives support. */
/* #undef DOS_DRIVES */

/* Define to enable event recording. */
#define EVENT_RECORDING 1

/* Target: Atari Falcon system. */
/* #undef FALCON */

/* Define to use m68k assembler CPU core for Falcon target. */
/* #undef FALCON_CPUASM */

/* Use SDL for graphics and input. */
/* #undef GUI_SDL */

/* Define to 1 if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1

/* Define to 1 if you have the `atexit' function. */
#define HAVE_ATEXIT 1

/* Define to 1 if you have the `chmod' function. */
/* #undef HAVE_CHMOD */

/* Define to 1 if you have the `clock' function. */
#define HAVE_CLOCK 1

/* Define to 1 if you have the <direct.h> header file. */
/* #undef HAVE_DIRECT_H */

/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
*/
#define HAVE_DIRENT_H 1

/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
/* #undef HAVE_DOPRNT */

/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1

/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1

/* Define to 1 if you have the `fdopen' function. */
#define HAVE_FDOPEN 1

/* Define to 1 if you have the `fflush' function. */
#define HAVE_FFLUSH 1

/* Define to 1 if you have the <file.h> header file. */
/* #undef HAVE_FILE_H */

/* Define to 1 if you have the `floor' function. */
#define HAVE_FLOOR 1

/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
/* #undef HAVE_FSEEKO */

/* Define to 1 if you have the `fstat' function. */
#define HAVE_FSTAT 1

/* Define to 1 if you have the `getcwd' function. */
#define HAVE_GETCWD 1

/* Define to 1 if you have the `gethostbyaddr' function. */
/* #undef HAVE_GETHOSTBYADDR */

/* Define to 1 if you have the `gethostbyname' function. */
/* #undef HAVE_GETHOSTBYNAME */

/* Define to 1 if you have the `gettimeofday' function. */
#define HAVE_GETTIMEOFDAY 1

/* Define to 1 if you have the `inet_ntoa' function. */
#define HAVE_INET_NTOA 1

/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1

/* Define to 1 if you have the `gem' library (-lgem). */
/* #undef HAVE_LIBGEM */

/* Define to 1 if you have the `png' library (-lpng). */
#define HAVE_LIBPNG 1

/* Define to 1 if you have the `z' library (-lz). */
#define HAVE_LIBZ 1

/* Define to 1 if you have the `localtime' function. */
#define HAVE_LOCALTIME 1

/* Define to 1 if you have the `memmove' function. */
#define HAVE_MEMMOVE 1

/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1

/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET 1

/* Define to 1 if you have the `mkdir' function. */
#define HAVE_MKDIR 1

/* Define to 1 if you have the `mkstemp' function. */
#define HAVE_MKSTEMP 1

/* Define to 1 if you have the `mktemp' function. */
#define HAVE_MKTEMP 1

/* Define to 1 if you have the `modf' function. */
#define HAVE_MODF 1

/* Define to 1 if you have the `nanosleep' function. */
/* #undef HAVE_NANOSLEEP */

/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
/* #undef HAVE_NDIR_H */

/* Define to 1 if you have the <netdb.h> header file. */
#define HAVE_NETDB_H 1

/* Define to 1 if you have the <netinet/in.h> header file. */
#define HAVE_NETINET_IN_H 1

/* Define to 1 if you have the `opendir' function. */
#define HAVE_OPENDIR 1

/* Support for OpenGL graphics acceleration. */
/* #undef HAVE_OPENGL */

/* Define to 1 if you have the `rename' function. */
#define HAVE_RENAME 1

/* Define to 1 if you have the `rewind' function. */
#define HAVE_REWIND 1

/* Define to 1 if you have the `rmdir' function. */
#define HAVE_RMDIR 1

/* Define to 1 if you have the `select' function. */
#define HAVE_SELECT 1

/* Define to 1 if you have the `signal' function. */
/* #undef HAVE_SIGNAL */

/* Define to 1 if you have the <signal.h> header file. */
#define HAVE_SIGNAL_H 1

/* Define to 1 if you have the `snprintf' function. */
#define HAVE_SNPRINTF 1

/* Define to 1 if you have the `socket' function. */
#define HAVE_SOCKET 1

/* Define to 1 if you have the `stat' function. */
#define HAVE_STAT 1

/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */

/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1

/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1

/* Define to 1 if you have the `strcasecmp' function. */
#define HAVE_STRCASECMP 1

/* Define to 1 if you have the `strchr' function. */
#define HAVE_STRCHR 1

/* Define to 1 if you have the `strdup' function. */
#define HAVE_STRDUP 1

/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR 1

/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1

/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1

/* Define to 1 if you have the `strncpy' function. */
#define HAVE_STRNCPY 1

/* Define to 1 if you have the `strrchr' function. */
#define HAVE_STRRCHR 1

/* Define to 1 if you have the `strstr' function. */
#define HAVE_STRSTR 1

/* Define to 1 if you have the `strtol' function. */
#define HAVE_STRTOL 1

/* Define to 1 if you have the `system' function. */
#define HAVE_SYSTEM 1

/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_DIR_H */

/* Define to 1 if you have the <sys/ioctl.h> header file. */
/* #undef HAVE_SYS_IOCTL_H */

/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
*/
/* #undef HAVE_SYS_NDIR_H */

/* Define to 1 if you have the <sys/select.h> header file. */
#define HAVE_SYS_SELECT_H 1

/* Define to 1 if you have the <sys/socket.h> header file. */
#define HAVE_SYS_SOCKET_H 1

/* Define to 1 if you have the <sys/soundcard.h> header file. */
/* #undef HAVE_SYS_SOUNDCARD_H */

/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1

/* Define to 1 if you have the <sys/time.h> header file. */
#define HAVE_SYS_TIME_H 1

/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1

/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1

/* Define to 1 if you have the `time' function. */
#define HAVE_TIME 1

/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1

/* Define to 1 if you have the `tmpfile' function. */
#define HAVE_TMPFILE 1

/* Define to 1 if you have the `tmpnam' function. */
#define HAVE_TMPNAM 1

/* Define to 1 if you have the `uclock' function. */
/* #undef HAVE_UCLOCK */

/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1

/* Define to 1 if you have the <unixio.h> header file. */
/* #undef HAVE_UNIXIO_H */

/* Define to 1 if you have the `unlink' function. */
#define HAVE_UNLINK 1

/* Define to 1 if you have the `usleep' function. */
#define HAVE_USLEEP 1

/* Define to 1 if you have the `vprintf' function. */
#define HAVE_VPRINTF 1

/* Define to 1 if you have the `vsnprintf' function. */
#define HAVE_VSNPRINTF 1

/* Define to 1 if you have the <windows.h> header file. */
/* #undef HAVE_WINDOWS_H */

/* Define to 1 if you have the <winsock2.h> header file. */
/* #undef HAVE_WINSOCK2_H */

/* Define to 1 if you have the `_mkdir' function. */
/* #undef HAVE__MKDIR */

/* Define to add IDE harddisk emulation. */
#define IDE 1

/* Define to allow sound interpolation. */
#define INTERPOLATE_SOUND 1

/* Define to use LINUX joystick. */
/* #undef LINUX_JOYSTICK */

/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
#define LSTAT_FOLLOWS_SLASHED_SYMLINK 1

/* Define if mkdir takes only one argument. */
/* #undef MKDIR_TAKES_ONE_ARG */

/* Define to activate assembler in monitor. */
// #define MONITOR_ASSEMBLER 1

/* Define to activate code breakpoints and execution history. */
// #define MONITOR_BREAK 1

/* Define to activate user-defined breakpoints. */
/* #undef MONITOR_BREAKPOINTS */

/* Define to activate hints in disassembler. */
// #define MONITOR_HINTS 1

/* Define to activate 6502 opcode profiling. */
/* #undef MONITOR_PROFILE */

/* Define to activate readline support in monitor. */
/* #undef MONITOR_READLINE */

/* Define to activate TRACE command in monitor. */
/* #undef MONITOR_TRACE */

/* Target: X11 with Motif. */
/* #undef MOTIF */

/* Define to allow color changes inside a scanline. */
#define NEW_CYCLE_EXACT 1

/* Define to use nonlinear POKEY mixing. */
#define NONLINEAR_MIXING 1

/* Use NTSC video filter. */
#define NTSC_FILTER 1

/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "pstehlik@sophics.cz"

/* Define to the full name of this package. */
#define PACKAGE_NAME "Atari800"

/* Define to the full name and version of this package. */
#define PACKAGE_STRING "Atari800 3.1.0"

/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "atari800"

/* Define to the home page for this package. */
#define PACKAGE_URL ""

/* Define to the version of this package. */
#define PACKAGE_VERSION "3.1.0"

/* Define to use page-based attribute array. */
/* #undef PAGED_ATTRIB */

/* Use accurate PAL color blending. */
#define PAL_BLENDING 1

/* Define to emulate the Black Box. */
#define PBI_BB 1

/* Define to emulate the MIO board. */
#define PBI_MIO 1

/* A prototype 80 column card for the 1090 expansion box. */
// #define PBI_PROTO80 1

/* Define to emulate the 1400XL/1450XLD. */
#define PBI_XLD 1

/* Platform-specific mapping of RGB palette to display surface. */
#define PLATFORM_MAP_PALETTE 1

/* Target: Sony PlayStation 2. */
/* #undef PS2 */

/* Define as the return type of signal handlers (`int' or `void'). */
#define RETSIGTYPE void

/* Target: Raspberry Pi. */
/* #undef RPI */

/* Define to use R: device. */
/* #undef R_IO_DEVICE */

/* Define to use IP network connection with the R: device. */
/* #undef R_NETWORK */

/* Define to use the host serial port with the R: device. */
/* #undef R_SERIAL */

/* Target: SDL library. */
/* #undef SDL */

/* Define to the type of arg 1 for `select'. */
#define SELECT_TYPE_ARG1 int

/* Define to the type of args 2, 3 and 4 for `select'. */
#define SELECT_TYPE_ARG234 (fd_set *)

/* Define to the type of arg 5 for `select'. */
#define SELECT_TYPE_ARG5 (struct timeval *)

/* Define to allow serial in/out sound. */
/* #undef SERIO_SOUND */

/* Target: X11 with shared memory extensions. */
/* #undef SHM */

/* Define to activate sound support. */
#define SOUND 1

/* Platform updates sound buffer by callback function. */
#define SOUND_CALLBACK 1

/* Use new sound API. */
#define SOUND_THIN_API 1

/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1

/* Define to allow stereo sound. */
#define STEREO_SOUND 1

/* Can change video modes on the fly. */
#define SUPPORTS_CHANGE_VIDEOMODE 1

/* Save additional config file options. */
/* #define SUPPORTS_PLATFORM_CONFIGSAVE 1 */

/* Additional config file options. */
/* #define SUPPORTS_PLATFORM_CONFIGURE 1 */

/* Update the Palette if it changed. */
#define SUPPORTS_PLATFORM_PALETTEUPDATE 1

/* Platform-specific sleep function. */
#define SUPPORTS_PLATFORM_SLEEP 1

/* Platform-specific time function. */
#define SUPPORTS_PLATFORM_TIME 1

/* Can display the screen rotated sideways. */
/* #undef SUPPORTS_ROTATE_VIDEOMODE */

/* Reinitialise the sound system. */
#define SUPPORTS_SOUND_REINIT 1

/* Define to use synchronized sound. */
#define SYNCHRONIZED_SOUND 1

/* Alternate system-wide config file for non-Unix OS. */
/* #undef SYSTEM_WIDE_CFG_FILE */

/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1

/* Define to 1 if your <sys/time.h> declares `struct tm'. */
/* #undef TM_IN_SYS_TIME */

/* Target: Curses-compatible library. */
/* #undef USE_CURSES */

/* Define for using cursor/ctrl keys for keyboard joystick. */
/* #undef USE_CURSORBLOCK */

/* Target: Ncurses library. */
/* #undef USE_NCURSES */

/* Define to enable on-screen keyboard. */
/* #undef USE_UI_BASIC_ONSCREEN_KEYBOARD */

/* Define to use very slow computer support (faster -refresh). */
/* #undef VERY_SLOW */

/* Define to emulate the Alien Group Voice Box. */
#define VOICEBOX 1

/* Define to allow volume only sound. */
/* #undef VOL_ONLY_SOUND */

/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
/* #undef WORDS_BIGENDIAN */

/* Define if unaligned word access is ok. */
#define WORDS_UNALIGNED_OK 1

/* Target: Standard X11. */
/* #undef X11 */

/* Emulate the XEP80. */
// #define XEP80_EMULATION 1

/* Target: X11 with XView. */
/* #undef XVIEW */

/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */

/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
/* #undef _LARGEFILE_SOURCE */

/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */

/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */

/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#define inline __inline__
#endif

/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

/* Define to empty if the keyword `volatile' does not work. Warning: valid
code using `volatile' can become incorrect without. Disable with care. */
/* #undef volatile */

BIN
src/3ds/gfx/icon.png View File


BIN
src/3ds/gfx/kbd_mapping.png View File


+ 199
- 0
src/3ds/input.c View File

@@ -0,0 +1,199 @@
/*
* 3ds/input.c - Nintendo 3DS input device support
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2016 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <3ds.h>

#include "config.h"
#include "akey.h"
#include "input.h"
#include "log.h"
#include "platform.h"
#include "ui.h"

#include "kbd_mapping_bin.h"

int key_control;

int N3DS_IsControlPressed()
{
return key_control;
}

void PLATFORM_SetJoystickKey(int joystick, int direction, int value)
{
}

void PLATFORM_GetJoystickKeyName(int joystick, int direction, char *buffer, int bufsize)
{
}

int PLATFORM_GetRawKey(void)
{
return 0;
}

int PLATFORM_Keyboard(void)
{
u32 kDown, kHeld, kUp;
u32* kMapping;
touchPosition pos;
int posPixel;

hidScanInput();
kDown = hidKeysDown();
kHeld = hidKeysHeld();
kUp = hidKeysUp();

if (UI_is_active)
{
if (kDown & KEY_A)
return AKEY_RETURN;
if (kDown & KEY_B)
return AKEY_ESCAPE;
if (kDown & KEY_X)
return AKEY_SPACE;
if (kDown & KEY_Y)
return AKEY_BACKSPACE;
if (kHeld & KEY_UP)
return AKEY_UP;
if (kHeld & KEY_LEFT)
return AKEY_LEFT;
if (kHeld & KEY_RIGHT)
return AKEY_RIGHT;
if (kHeld & KEY_DOWN)
return AKEY_DOWN;
if (kDown & KEY_L)
return AKEY_COLDSTART;
if (kDown & KEY_R)
return AKEY_WARMSTART;
}

INPUT_key_consol = INPUT_CONSOL_NONE;

if (kHeld & KEY_START)
INPUT_key_consol &= ~INPUT_CONSOL_START;
if (kHeld & KEY_SELECT)
INPUT_key_consol &= ~INPUT_CONSOL_SELECT;
if (kHeld & KEY_R)
INPUT_key_consol &= ~INPUT_CONSOL_OPTION;
if (kHeld & KEY_B)
return AKEY_RETURN;
if (kHeld & KEY_Y)
return AKEY_SPACE;
if (kHeld & KEY_L)
return AKEY_UI;
if (kHeld & KEY_DUP)
return AKEY_UP;
if (kHeld & KEY_DLEFT)
return AKEY_LEFT;
if (kHeld & KEY_DRIGHT)
return AKEY_RIGHT;
if (kHeld & KEY_DDOWN)
return AKEY_DOWN;

if ((kDown | kHeld) & KEY_TOUCH)
{
hidTouchRead(&pos);
kMapping = (u32*) kbd_mapping_bin;
if (pos.px >= 0 && pos.px < 320 && pos.py >= 0 && pos.py < 240)
{
posPixel = kMapping[pos.py * 320 + pos.px] & 0xFFFFFF;
if (kDown & KEY_TOUCH)
{
if ((posPixel & 0xff00ff) == 0)
{
int val = (posPixel >> 10) | (INPUT_key_shift != 0 ? AKEY_SHFT : 0)
| (key_control != 0 ? AKEY_CTRL : 0);

if (INPUT_key_shift != 0 || key_control != 0)
{
INPUT_key_shift = 0;
key_control = 0;
PLATFORM_DisplayScreen();
}

return val;
}

if (posPixel == 0xff00ff || posPixel == 0x7f007f)
if (INPUT_key_shift != 0 || key_control != 0)
{
INPUT_key_shift = 0;
key_control = 0;
PLATFORM_DisplayScreen();
}

if (posPixel == 0x8080ff)
{
key_control = 1;
PLATFORM_DisplayScreen();
}
if (posPixel == 0xa0a0ff)
{
INPUT_key_shift = 1;
PLATFORM_DisplayScreen();
}
if (posPixel == 0xe0e0ff)
return AKEY_BREAK;
}

if (posPixel == 0x2020ff)
INPUT_key_consol &= ~INPUT_CONSOL_START;
if (posPixel == 0x4040ff)
INPUT_key_consol &= ~INPUT_CONSOL_SELECT;
if (posPixel == 0x6060ff)
INPUT_key_consol &= ~INPUT_CONSOL_OPTION;
}
}

return AKEY_NONE;
}

int PLATFORM_PORT(int num)
{
int ret = 0xff;
if (num == 0) {
hidScanInput();
u32 kDown = hidKeysHeld();
if (kDown & KEY_CPAD_LEFT)
ret &= 0xf0 | INPUT_STICK_LEFT;
if (kDown & KEY_CPAD_RIGHT)
ret &= 0xf0 | INPUT_STICK_RIGHT;
if (kDown & KEY_CPAD_UP)
ret &= 0xf0 | INPUT_STICK_FORWARD;
if (kDown & KEY_CPAD_DOWN)
ret &= 0xf0 | INPUT_STICK_BACK;
}
return ret;
}

int PLATFORM_TRIG(int num)
{
if (num == 0) {
hidScanInput();
if (hidKeysHeld() & KEY_A)
return 0;
}
return 1;
}

+ 117
- 0
src/3ds/main.c View File

@@ -0,0 +1,117 @@
/*
* 3ds/main.c - Nintendo 3DS port main code
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2016 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <3ds.h>
#include <sf2d.h>
#include <stdio.h>
#include <string.h>

/* Atari800 includes */
#include "atari.h"
#include "config.h"
#include "../input.h"
#include "log.h"
#include "monitor.h"
#include "platform.h"
#include "pokeysnd.h"
#ifdef SOUND
#include "../sound.h"
#endif
#include "videomode.h"

static bool PLATFORM_IsNew3DS;

int PLATFORM_Configure(char *option, char *parameters)
{
return 0;
}

void PLATFORM_ConfigSave(FILE *fp)
{

}

int PLATFORM_Initialise(int *argc, char *argv[])
{
return TRUE;
}

void PLATFORM_Sleep(double s)
{
if (s > 0) {
svcSleepThread(s * 1e9);
}
}

double PLATFORM_Time(void)
{
return osGetTime() * 1e-3;
}

int PLATFORM_Exit(int run_monitor)
{
Log_flushlog();

if (run_monitor) {
return 1;
} else {
sf2d_fini();
ptmSysmExit();
romfsExit();
}

return 0;
}

int main(int argc, char **argv)
{
romfsInit();

ptmSysmInit();
osSetSpeedupEnable(1);

sf2d_init();
// consoleInit(GFX_BOTTOM, NULL);

// sane defaults...
PLATFORM_IsNew3DS = PTMSYSM_CheckNew3DS();
POKEYSND_enable_new_pokey = PLATFORM_IsNew3DS;

if (!Atari800_Initialise(&argc, argv))
{
printf("Atari initialisation failed!");
return 0;
}

while (aptMainLoop()) {
INPUT_key_code = PLATFORM_Keyboard();
Atari800_Frame();
if (Atari800_display_screen)
PLATFORM_DisplayScreen();
}
}

/*
vim:ts=4:sw=4:
*/

BIN
src/3ds/romfs/kbd_ctrl_pressed.png View File


BIN
src/3ds/romfs/kbd_display.png View File


BIN
src/3ds/romfs/kbd_shift_pressed.png View File


+ 138
- 0
src/3ds/sound_ndsp.c View File

@@ -0,0 +1,138 @@
/*
* 3ds/sound_ndsp.c - Nintendo 3DS NDSP audio backend
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2016 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <3ds.h>
#include <stdlib.h>
#include <string.h>

#include "atari.h"
#include "log.h"
#include "platform.h"
#include "sound.h"

int N3DS_soundFreq;
ndspWaveBuf N3DS_audioBuf;
u8* N3DS_audioData;
u32 N3DS_bufferSize, N3DS_sampleSize, N3DS_lastPos;
Sound_setup_t *N3DS_sound;

void N3DS_ClearAudioData(void);

int PLATFORM_SoundSetup(Sound_setup_t *setup)
{
setup->sample_size = 1;

if (setup->buffer_frames == 0)
{
setup->buffer_frames = 4096;
}

N3DS_bufferSize = setup->buffer_frames;
N3DS_sampleSize = setup->sample_size * setup->channels;

N3DS_audioData = (u8*) linearAlloc(N3DS_bufferSize * 2 * N3DS_sampleSize);
N3DS_ClearAudioData();

ndspInit();

N3DS_sound = setup;
PLATFORM_SoundContinue();

return TRUE;
}

void N3DS_SoundCallback(void* dud)
{
u32 pos = ndspChnGetSamplePos(0);
if (pos >= N3DS_bufferSize && N3DS_lastPos < N3DS_bufferSize)
{
Sound_Callback(&N3DS_audioData[0], N3DS_bufferSize * N3DS_sampleSize);
for(int i = 0; i < N3DS_bufferSize * N3DS_sampleSize; i++)
N3DS_audioData[i] ^= 0x80;
}
else if (pos < N3DS_bufferSize && N3DS_lastPos >= N3DS_bufferSize)
{
Sound_Callback(&N3DS_audioData[N3DS_bufferSize * N3DS_sampleSize], N3DS_bufferSize * N3DS_sampleSize);
for(int i = N3DS_bufferSize * N3DS_sampleSize; i < N3DS_bufferSize * N3DS_sampleSize * 2; i++)
N3DS_audioData[i] ^= 0x80;
}
N3DS_lastPos = pos;
}

void N3DS_ClearAudioData(void)
{
memset(N3DS_audioData, 0, N3DS_bufferSize * 2 * N3DS_sampleSize);
DSP_FlushDataCache(N3DS_audioData, N3DS_bufferSize * 2 * N3DS_sampleSize);
N3DS_lastPos = 0;
}

void PLATFORM_SoundLock(void)
{
// TODO
}

void PLATFORM_SoundUnlock(void)
{
// TODO
}

void PLATFORM_SoundExit(void)
{
linearFree(N3DS_audioData);
ndspExit();
}

void PLATFORM_SoundPause(void)
{
ndspChnWaveBufClear(0);
N3DS_ClearAudioData();
}

void PLATFORM_SoundContinue(void)
{
float mix[12];
memset(mix, 0, sizeof(mix));
mix[0] = mix[1] = 1.0f;

ndspSetOutputMode(N3DS_sound->channels == 2 ? NDSP_OUTPUT_STEREO : NDSP_OUTPUT_MONO);
ndspSetOutputCount(1);
ndspSetMasterVol(1.0f);
ndspSetCallback(N3DS_SoundCallback, N3DS_audioData);

memset(&N3DS_audioBuf, 0, sizeof(ndspWaveBuf));
ndspChnReset(0);
ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE);
ndspChnSetRate(0, N3DS_sound->freq);
ndspChnSetFormat(0, NDSP_CHANNELS(N3DS_sound->channels) | NDSP_ENCODING(N3DS_sound->sample_size == 2 ? NDSP_ENCODING_PCM16 : NDSP_ENCODING_PCM8));
ndspChnSetMix(0, mix);

N3DS_audioBuf.data_vaddr = N3DS_audioData;
N3DS_audioBuf.nsamples = N3DS_bufferSize * 2;
N3DS_audioBuf.looping = true;
N3DS_audioBuf.status = NDSP_WBUF_FREE;

N3DS_ClearAudioData();

ndspChnWaveBufAdd(0, &N3DS_audioBuf);
}

+ 215
- 0
src/3ds/video.c View File

@@ -0,0 +1,215 @@
/*
* 3ds/video.c - Nintendo 3DS video backend
*
* Copyright (c) 2001-2002 Jacek Poplawski
* Copyright (C) 2001-2016 Atari800 development team (see DOC/CREDITS)
*
* This file is part of the Atari800 emulator project which emulates
* the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
*
* Atari800 is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Atari800 is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Atari800; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include <3ds.h>
#include <sf2d.h>
#include <sfil.h>

#include "artifact.h"
#include "atari.h"
#include "colours.h"
#include "config.h"
#include "filter_ntsc.h"
#include "input.h"
#include "log.h"
#ifdef PAL_BLENDING
#include "pal_blending.h"
#endif /* PAL_BLENDING */
#include "platform.h"
#include "screen.h"
#include "util.h"
#include "videomode.h"

int texInitialized = 0;
sf2d_texture *tex, *kbd_display, *kbd_ctrl_pressed, *kbd_shift_pressed;
u32 *texBuf;
VIDEOMODE_MODE_t N3DS_VIDEO_mode;
int ctable[256];

void PLATFORM_PaletteUpdate(void)
{
#ifdef PAL_BLENDING
if (N3DS_VIDEO_mode == VIDEOMODE_MODE_NORMAL && ARTIFACT_mode == ARTIFACT_PAL_BLEND)
PAL_BLENDING_UpdateLookup();
#endif
N3DS_VIDEO_PaletteUpdate();
}

void N3DS_VIDEO_PaletteUpdate()
{
int i;

for (i = 0; i < 256; i++)
{
ctable[i] = Colours_table[i] << 8 | 0xFF;
}
}

void PLATFORM_GetPixelFormat(PLATFORM_pixel_format_t *format)
{
format->bpp = 32;
format->rmask = 0xFF000000;
format->gmask = 0x00FF0000;
format->bmask = 0x0000FF00;
}

void PLATFORM_MapRGB(void *dest, int const *palette, int size)
{
int i;
u32* target = (u32*) dest;
for (i = 0; i < 256; i++)
{
target[i] = (palette[i] << 8) | 0xFF;
}
}

static void UpdateNtscFilter(VIDEOMODE_MODE_t mode)
{

}

void PLATFORM_SetVideoMode(VIDEOMODE_resolution_t const *res, int windowed, VIDEOMODE_MODE_t mode, int rotate90)
{
N3DS_VIDEO_mode = mode;
N3DS_InitTexture();

PLATFORM_PaletteUpdate();
memset(texBuf, 0, tex->tex.width * tex->tex.height * 4);
PLATFORM_DisplayScreen();
}

VIDEOMODE_resolution_t *PLATFORM_AvailableResolutions(unsigned int *size)
{
VIDEOMODE_resolution_t *resolutions;
resolutions = Util_malloc(1 * sizeof(VIDEOMODE_resolution_t));
resolutions[0].width = 400;
resolutions[0].height = 240;
*size = 1;
return resolutions;
}

VIDEOMODE_resolution_t *PLATFORM_DesktopResolution(void)
{
VIDEOMODE_resolution_t *resolutions;
resolutions = Util_malloc(1 * sizeof(VIDEOMODE_resolution_t));
resolutions[0].width = 400;
resolutions[0].height = 240;
return resolutions;
}

int PLATFORM_SupportsVideomode(VIDEOMODE_MODE_t mode, int stretch, int rotate90)
{
if (rotate90 != 0)
return false;

return mode == VIDEOMODE_MODE_NORMAL;
}

int PLATFORM_WindowMaximised(void)
{
return 1;
}

void N3DS_RenderNormal(u8 *src, u32 *dest)
{
int x, y;
int spitch = Screen_WIDTH - VIDEOMODE_src_width;
int dpitch = 512 - VIDEOMODE_src_width;

for (y = 0; y < VIDEOMODE_src_height; y++) {
for (x = 0; x < VIDEOMODE_src_width; x++) {
*(dest++) = ctable[*(src++)];
}
src += spitch;
dest += dpitch;
}
}

void N3DS_InitTexture(void)
{
if (texInitialized == 0)
{
sf2d_swapbuffers();
sf2d_set_3D(0);

tex = sf2d_create_texture(512, 256, TEXFMT_RGBA8, SF2D_PLACE_RAM);
texBuf = linearAlloc(512 * 256 * 4);

kbd_display = sfil_load_PNG_file("romfs:/kbd_display.png", SF2D_PLACE_RAM);
kbd_ctrl_pressed = sfil_load_PNG_file("romfs:/kbd_ctrl_pressed.png", SF2D_PLACE_RAM);
kbd_shift_pressed = sfil_load_PNG_file("romfs:/kbd_shift_pressed.png", SF2D_PLACE_RAM);
texInitialized = 1;
}
}

void PLATFORM_DisplayScreen(void)
{
u8 *src;
u32 *dest;
float xs, ys;

src = (u8*) Screen_atari;
src += Screen_WIDTH * VIDEOMODE_src_offset_top + VIDEOMODE_src_offset_left;
dest = texBuf;

N3DS_InitTexture();

#ifdef PAL_BLENDING
if (N3DS_VIDEO_mode == VIDEOMODE_MODE_NORMAL && ARTIFACT_mode == ARTIFACT_PAL_BLEND)
PAL_BLENDING_Blit32(dest, src, tex->tex.width, VIDEOMODE_src_width, VIDEOMODE_src_height, VIDEOMODE_src_offset_top % 2);
else
#endif
N3DS_RenderNormal(src, dest);

sf2d_start_frame(GFX_TOP, GFX_LEFT);
tex->tiled = 0;
sf2d_texture_tile32_hardware(tex, texBuf, 512, 256);
if (VIDEOMODE_dest_width <= 400 && VIDEOMODE_dest_height <= 240 && VIDEOMODE_src_width == VIDEOMODE_dest_width && VIDEOMODE_src_height == VIDEOMODE_dest_height)
sf2d_draw_texture_part(tex,
(400 - VIDEOMODE_dest_width) / 2, (240 - VIDEOMODE_dest_height) / 2,
0, 0, VIDEOMODE_dest_width, VIDEOMODE_dest_height
);
else
{
xs = (float) VIDEOMODE_dest_width / VIDEOMODE_src_width;
ys = (float) VIDEOMODE_dest_height / VIDEOMODE_src_height;
sf2d_draw_texture_part_scale(tex,
(400 - VIDEOMODE_dest_width) / 2, (240 - VIDEOMODE_dest_height) / 2,
0, 0, VIDEOMODE_src_width, VIDEOMODE_src_height,
xs, ys
);
}
sf2d_end_frame();

/* Keyboard rendering */
sf2d_start_frame(GFX_BOTTOM, GFX_LEFT);
sf2d_draw_texture(kbd_display, 0, 0);
if (INPUT_key_shift != 0)
sf2d_draw_texture(kbd_shift_pressed, 0, 0);
if (N3DS_IsControlPressed() != 0)
sf2d_draw_texture(kbd_ctrl_pressed, 0, 0);
sf2d_end_frame();

sf2d_swapbuffers();
}

+ 8
- 0
src/3ds/video.h View File

@@ -0,0 +1,8 @@
#ifndef 3DS_VIDEO_H_
#define 3DS_VIDEO_H_

#include <stdio.h>
#include "config.h"
#include "videomode.h"

#endif /* 3DS_VIDEO_H_ */

+ 5
- 0
src/atari.c View File

@@ -424,6 +424,11 @@ int Atari800_Initialise(int *argc, char *argv[])
}
*argc = j;
}

#ifdef _3DS
SYSROM_FindInDir("/3ds/atari800", FALSE);
#endif

#ifndef ANDROID
got_config = CFG_LoadConfig(rtconfig_filename);
#else

+ 1
- 1
src/ui.c View File

@@ -4060,7 +4060,7 @@ void UI_Run(void)
UI_MENU_ACTION(UI_MENU_MONITOR, "About AtariDC"),
#elif defined(DIRECTX)
UI_MENU_ACTION_ACCEL(UI_MENU_MONITOR, monitor_label, "F8"),
#else
#elif !defined(_3DS)
UI_MENU_ACTION_ACCEL(UI_MENU_MONITOR, "Enter Monitor", "F8"),
#endif
UI_MENU_ACTION_ACCEL(UI_MENU_ABOUT, "About the Emulator", "Alt+A"),

Loading…
Cancel
Save