From 111d186dd2224d2da1bdc20f91776c3578f7db90 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Wed, 1 Nov 2023 21:37:36 +0000 Subject: [PATCH 1/8] Initial Nintendo DS port --- Makefile | 32 +++ arch/ArcemConfig.c | 11 +- arch/dbugsys.h | 17 ++ armdefs.h | 2 +- c99.h | 18 ++ dagstandalone.c | 10 +- hostfs.c | 4 + nds/ControlPane.c | 57 +++++ nds/ControlPane.h | 13 + nds/DispKbd.c | 364 +++++++++++++++++++++++++++ nds/KeyTable.h | 107 ++++++++ nds/arc.bmp | Bin 0 -> 630 bytes nds/arm7/main.c | 97 +++++++ nds/filecalls.c | 181 +++++++++++++ nds/filecalls_internal.h | 17 ++ nds/main.c | 40 +++ support_modules/modes/ArcemModes,ffa | Bin 2896 -> 3092 bytes support_modules/modes/MakeModes,ffb | Bin 31952 -> 34178 bytes support_modules/modes/ModeGen,ffb | Bin 7922 -> 7929 bytes support_modules/modes/README | 2 + 20 files changed, 965 insertions(+), 7 deletions(-) create mode 100644 nds/ControlPane.c create mode 100644 nds/ControlPane.h create mode 100644 nds/DispKbd.c create mode 100644 nds/KeyTable.h create mode 100644 nds/arc.bmp create mode 100644 nds/arm7/main.c create mode 100644 nds/filecalls.c create mode 100644 nds/filecalls_internal.h create mode 100644 nds/main.c diff --git a/Makefile b/Makefile index ed2083f..9750973 100644 --- a/Makefile +++ b/Makefile @@ -180,6 +180,38 @@ riscpkg: $(TARGET) mkdir ArcEm/Apps/Misc/hostfs endif +ifeq (${SYSTEM},nds) +CC=arm-none-eabi-gcc +LD=$(CC) +ARM9_ARCH = -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s +CFLAGS += $(ARM9_ARCH) -ffunction-sections -fdata-sections -DSYSTEM_nds -DARM9 -DUSE_FAKEMAIN -DNO_OPEN64 -isystem $(DEVKITPRO)/libnds/include -Wno-cast-align -Wno-format +LDFLAGS += -specs=ds_arm9.specs -g $(ARM9_ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libnds/lib +LIBS += -lfilesystem -lfat -lnds9 +OBJS += nds/main.o +ifneq ($(DEBUG),yes) +CFLAGS += -DNDEBUG +endif + +TARGET = ArcEm.elf +all: ArcEm.nds + +%.nds: %.elf %.arm7.elf nds/arc.bmp + mkdir -p romfs/extnrom + cp support_modules/*/*,ffa romfs/extnrom + ndstool -c $@ -9 $< -7 $*.arm7.elf -b nds/arc.bmp "ArcEm;Archimedes Emulator;WIP" -d romfs + +ARM7_ARCH = -mthumb -mthumb-interwork -march=armv4t -mtune=arm7tdmi +ARM7_CFLAGS = $(ARM7_ARCH) -Os -ffunction-sections -fdata-sections -DARM7 -isystem $(DEVKITPRO)/libnds/include +ARM7_LDFLAGS = -specs=ds_arm7.specs -g $(ARM7_ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libnds/lib +ARM7_LIBS = -lnds7 + +ArcEm.arm7.elf: nds/arm7/main.arm7.o + $(LD) $(ARM7_LDFLAGS) $^ $(ARM7_LIBS) -o $@ + +%.arm7.o: %.c + $(CC) $(ARM7_CFLAGS) -o $@ -c $< +endif + ifeq (${SYSTEM},SDL) SDL_CONFIG=sdl2-config CFLAGS += -DSYSTEM_SDL -DUSE_FAKEMAIN $(shell $(SDL_CONFIG) --cflags) diff --git a/arch/ArcemConfig.c b/arch/ArcemConfig.c index 6766100..dee98e8 100644 --- a/arch/ArcemConfig.c +++ b/arch/ArcemConfig.c @@ -76,7 +76,11 @@ void ArcemConfig_SetupDefaults(ArcemConfig *pConfig) #if defined(EXTNROM_SUPPORT) /* The default directory is extnrom in the current working directory */ +#ifdef SYSTEM_nds + pConfig->sEXTNDirectory = arcemconfig_StringDuplicate("nitro:/extnrom"); +#else pConfig->sEXTNDirectory = arcemconfig_StringDuplicate("extnrom"); +#endif /* If we've run out of memory this early, something is very wrong */ if(NULL == pConfig->sEXTNDirectory) { ControlPane_Error(EXIT_FAILURE,"Failed to allocate memory for initial configuration. Please free up more memory.\n"); @@ -239,6 +243,7 @@ void ArcemConfig_ParseCommandLine(ArcemConfig *pConfig, int argc, char *argv[]) { unsigned int uValue; int iArgument = 0; +#ifndef SYSTEM_nds char sHelpString[] = "Arcem \n" " Where options are one or more of the following\n" @@ -270,6 +275,7 @@ void ArcemConfig_ParseCommandLine(ArcemConfig *pConfig, int argc, char *argv[]) " --menukeys - Specify which key numbers open the tweak menu\n" #endif /* SYSTEM_riscos_single */ ; +#endif /* No commandline arguments? */ if(0 == argc) { @@ -290,6 +296,7 @@ void ArcemConfig_ParseCommandLine(ArcemConfig *pConfig, int argc, char *argv[]) iArgument = 1; while(iArgument < argc) { +#ifndef SYSTEM_nds if(0 == strcmp("--version", argv[iArgument])) { printf("Arcem %s\n", Version); @@ -300,7 +307,9 @@ void ArcemConfig_ParseCommandLine(ArcemConfig *pConfig, int argc, char *argv[]) exit(EXIT_SUCCESS); } - else if(0 == strcmp("--config", argv[iArgument])) { + else +#endif + if(0 == strcmp("--config", argv[iArgument])) { if(iArgument+1 < argc) { /* Is there a following argument? */ ini_parse(argv[iArgument + 1], ArcemConfig_Handler, pConfig); iArgument += 2; diff --git a/arch/dbugsys.h b/arch/dbugsys.h index 874a01d..e756f40 100644 --- a/arch/dbugsys.h +++ b/arch/dbugsys.h @@ -9,6 +9,7 @@ #ifndef _DBUGSYS_H_ #define _DBUGSYS_H_ +#include "c99.h" #include #include @@ -26,6 +27,21 @@ #undef DEBUG_HDC63463 #undef DEBUG_CONFIG +#ifdef SYSTEM_nds +#undef IOC_WARN +#undef WARN +#undef WARN_MEMC +#undef WARN_I2C +#undef WARN_DATA +#undef WARN_DMAWRITE +#undef WARN_DMAREAD +#undef WARN_INTS +#undef WARN_VIDC +#undef WARN_KEYBOARD +#undef WARN_FDC1772 +#undef WARN_HDC63463 +#undef WARN_CONFIG +#else #define IOC_WARN #define WARN #define WARN_MEMC @@ -39,6 +55,7 @@ #define WARN_FDC1772 #define WARN_HDC63463 #define WARN_CONFIG +#endif #define dbug_stdout printf diff --git a/armdefs.h b/armdefs.h index 0dbe41c..7557954 100644 --- a/armdefs.h +++ b/armdefs.h @@ -269,7 +269,7 @@ struct ARMul_State { }; -#ifdef AMIGA +#if defined(AMIGA) || defined(SYSTEM_nds) extern void *state_alloc(int s); extern void state_free(void *p); #else diff --git a/c99.h b/c99.h index 641b2e5..37ba810 100644 --- a/c99.h +++ b/c99.h @@ -64,4 +64,22 @@ typedef unsigned char bool; #define inline __inline #endif +#ifdef SYSTEM_nds +/* Use integer only versions of printf and scanf to reduce the executable size */ +#include + +#define printf iprintf +#define fprintf fiprintf +#define sprintf siprintf +#define snprintf sniprintf + +#define vprintf viprintf +#define vfprintf vfiprintf +#define vsprintf vsiprintf +#define vsnprintf vsniprintf + +#define sscanf siscanf +#define fscanf fiscanf +#endif + #endif diff --git a/dagstandalone.c b/dagstandalone.c index 05ad6fc..539d8f8 100644 --- a/dagstandalone.c +++ b/dagstandalone.c @@ -39,6 +39,7 @@ /**************************************************************/ #ifndef _WIN32 #ifndef AMIGA +#ifndef SYSTEM_nds static void dagstandalone_handlesignal(int sig) { dbug("Terminate ARMulator - excecution\n"); #ifdef BENCHMARKEXIT @@ -53,6 +54,7 @@ static void dagstandalone_handlesignal(int sig) { } #endif #endif +#endif static void InitFail(int exitcode, char const *which) { ControlPane_Error(exitcode,"%s interface failed to initialise. Exiting\n", @@ -68,15 +70,12 @@ static void InitFail(int exitcode, char const *which) { * */ void dagstandalone(ArcemConfig *pConfig) { + ARMul_State *emu_state = NULL; #ifndef _WIN32 #ifndef AMIGA +#ifndef SYSTEM_nds struct sigaction action; -#endif -#endif - ARMul_State *emu_state = NULL; -#ifndef _WIN32 -#ifndef AMIGA /* Setup a signal handler for SIGUSR1 */ action.sa_handler = dagstandalone_handlesignal; sigemptyset (&action.sa_mask); @@ -84,6 +83,7 @@ static void InitFail(int exitcode, char const *which) { sigaction(SIGUSR1, &action, (struct sigaction *) 0); #endif +#endif #endif ARMul_EmulateInit(); diff --git a/hostfs.c b/hostfs.c index 5df0f85..f12f30d 100644 --- a/hostfs.c +++ b/hostfs.c @@ -221,6 +221,9 @@ dbug_hostfs(const char *format, ...) } #endif +#ifdef SYSTEM_nds +static inline void warn_hostfs(const char *format, ...) {} +#else static void warn_hostfs(const char *format, ...) { @@ -230,6 +233,7 @@ warn_hostfs(const char *format, ...) vfprintf(stderr, format, ap); va_end(ap); } +#endif static void path_construct(ARMul_State *state, const char *old_path, const char *ro_path, diff --git a/nds/ControlPane.c b/nds/ControlPane.c new file mode 100644 index 0000000..61ec1e8 --- /dev/null +++ b/nds/ControlPane.c @@ -0,0 +1,57 @@ +/* Redraw and other services for the control pane */ +/* (c) David Alan Gilbert 1995 - see Readme file for copying info */ + + +#include "armdefs.h" +#include "archio.h" +#include "armarc.h" +#include "ControlPane.h" +#include "../arch/keyboard.h" + +#include +#include + +#include + +bool hasKeyboard = false; + +void ControlPane_Init(ARMul_State *state) +{ + videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE); + vramSetBankH(VRAM_H_SUB_BG); + +#ifndef NDEBUG + scanKeys(); + + int held = keysHeld(); + if (held & KEY_SELECT) { + consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); + } else +#endif + { + Keyboard *keyboard = keyboardInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x512, 15, 0, false, true); + keyboard->OnKeyPressed = OnKeyPressed; + keyboard->OnKeyReleased = OnKeyReleased; + keyboardShow(); + hasKeyboard = true; + } +} + +void ControlPane_Error(int code,const char *fmt,...) +{ + va_list args; + va_start(args,fmt); + + /* Log it */ + vprintf(fmt,args); + + while(1) { + swiWaitForVBlank(); + scanKeys(); + if (keysDown() & KEY_START) + break; + } + + /* Quit */ + exit(code); +} diff --git a/nds/ControlPane.h b/nds/ControlPane.h new file mode 100644 index 0000000..d47315d --- /dev/null +++ b/nds/ControlPane.h @@ -0,0 +1,13 @@ +/* (c) David Alan Gilbert 1995 - see Readme file for copying info */ +#ifndef CONTROLPANE_HEADER +#define CONTROLPANE_HEADER + +void ControlPane_Init(ARMul_State *state); + +/* Report an error and exit */ +void ControlPane_Error(int code,const char *fmt,...); + +void OnKeyPressed(int key); +void OnKeyReleased(int key); + +#endif diff --git a/nds/DispKbd.c b/nds/DispKbd.c new file mode 100644 index 0000000..b3746c3 --- /dev/null +++ b/nds/DispKbd.c @@ -0,0 +1,364 @@ +/* (c) David Alan Gilbert 1995-1999 - see Readme file for copying info + Nintendo DS version by Cameron Cawley, 2020-2023 */ +/* Display and keyboard interface for the Arc emulator */ + +#include + +#include "../armdefs.h" +#include "armarc.h" +#include "../arch/dbugsys.h" +#include "../arch/keyboard.h" +#include "displaydev.h" +#include "../armemu.h" +#include "ControlPane.h" + +#include + +#include "KeyTable.h" + +ARMul_State nds_statestr DTCM_BSS; +void *state_alloc(int s) { return &nds_statestr; } +void state_free(void *p) {} + +static inline s32 calculate_scale(s32 width, s32 height) { + const s32 screenAspect = intToFixed(SCREEN_WIDTH, 8) / SCREEN_HEIGHT; + s32 rectAspect = intToFixed(width, 8) / height; + + s32 scaleFactor; + if (screenAspect > rectAspect) + scaleFactor = intToFixed(SCREEN_HEIGHT, 8) / height; + else + scaleFactor = intToFixed(SCREEN_WIDTH, 8) / width; + + return scaleFactor; +} + +static inline u16 ConvertPhysToColour(int phys) +{ + /* Convert to 5-bit component values */ + int r = (phys & 0x00f) << 1; + int g = (phys & 0x0f0) >> 3; + int b = (phys & 0xf00) >> 7; + /* May want to tweak this a bit at some point? */ + r |= r>>4; + g |= g>>4; + b |= b>>4; + return RGB15(r, g, b); +} + +static void RefreshMouse(ARMul_State *state); + +/*-----------------------------------------------------------------------------*/ +/* Palettised display code */ +#define PDD_Name(x) pdd_##x +#define PDD_MonitorWidth 1024 +#define PDD_MonitorHeight 512 +#define PDD_BgSize BgSize_B8_1024x512 + +static int background; + +static s32 xscale = intToFixed(1, 8), yscale = intToFixed(1, 8); +static s32 xoffset = 0, yoffset = 0; + +/** + * This uses an intermediate buffer since cache hits in main RAM are faster than VRAM writes. + * It would have been nice to put this into TCM, but that would prevent it from being used for DMA. + */ +static ARMword RowBuffer[PDD_MonitorWidth/4] ALIGN(8); + +typedef struct { + ARMword *src; + uint8_t *dst; + unsigned int count; +} PDD_Row; + + +static void PDD_Name(Host_ChangeMode)(ARMul_State *state,int width,int height,int depth,int hz); + +static inline void PDD_Name(Host_SetPaletteEntry)(ARMul_State *state,int i,uint_fast16_t phys) +{ + BG_PALETTE[i] = ConvertPhysToColour(phys); +} + +static inline void PDD_Name(Host_SetCursorPaletteEntry)(ARMul_State *state,int i,uint_fast16_t phys) +{ + // TODO: Implement this! +} + +static inline void PDD_Name(Host_SetBorderColour)(ARMul_State *state,uint_fast16_t phys) +{ + // TODO: Implement this! +} + +static inline PDD_Row PDD_Name(Host_BeginRow)(ARMul_State *state,int row,int offset,int *alignment) +{ + PDD_Row drow; + drow.dst = ((uint8_t *)bgGetGfxPtr(background)) + (row * PDD_MonitorWidth) + offset; + drow.src = RowBuffer; + drow.count = 0; + *alignment = 0; + return drow; +} + +static inline void PDD_Name(Host_EndRow)(ARMul_State *state,PDD_Row *row) +{ + while (dmaBusy(3)); +} + +static inline ARMword *PDD_Name(Host_BeginUpdate)(ARMul_State *state,PDD_Row *row,unsigned int count,int *outoffset) +{ + row->count = count; + *outoffset = 0; + return row->src; +} + +static inline void PDD_Name(Host_EndUpdate)(ARMul_State *state,PDD_Row *row) +{ + unsigned int count = row->count; + + DC_FlushRange(row->src, count>>3); + while (dmaBusy(3)); + dmaCopyWordsAsynch(3, row->src, row->dst, count>>3); + + row->src += count>>5; +} + +static inline void PDD_Name(Host_AdvanceRow)(ARMul_State *state,PDD_Row *row,unsigned int count) +{ + row->dst += count>>3; +} + +static inline void PDD_Name(Host_PollDisplay)(ARMul_State *state) +{ + RefreshMouse(state); + oamUpdate(&oamMain); + bgUpdate(); +} + +static inline void PDD_Name(Host_DrawBorderRect)(ARMul_State *state,int x,int y,int width,int height) +{ + // TODO: Implement this! +} + +#include "../arch/paldisplaydev.c" + +static void PDD_Name(Host_ChangeMode)(ARMul_State *state,int width,int height,int depth,int hz) +{ + s32 xs, ys; + + if((width > PDD_MonitorWidth) || (height > PDD_MonitorHeight)) + { + warn("Mode %dx%d too big\n",width,height); + DC.ModeChanged = 1; + return; + } + + HD.Width = width; + HD.Height = height; + HD.XScale = 1; + HD.YScale = 1; + + /* Calculate expansion params */ + if(depth == 3) + { + /* No expansion */; + HD.ExpandTable = NULL; + } + else + { + /* Expansion! */ + static ARMword expandtable[256] DTCM_BSS; + HD.ExpandFactor = (3-depth); + HD.ExpandTable = expandtable; + GenExpandTable(HD.ExpandTable,1<= height*2) { + xscale = yscale = calculate_scale(width, height * 2); + yscale *= 2; + } else if (height >= width) { + xscale = yscale = calculate_scale(width * 2, height); + xscale *= 2; + } else { + xscale = yscale = calculate_scale(width, height); + } + + xs = (1<<16) / xscale; + ys = (1<<16) / yscale; + + xoffset = (SCREEN_WIDTH - fixedToInt(width * xscale, 8)) >> 1; + yoffset = (SCREEN_HEIGHT - fixedToInt(height * yscale, 8)) >> 1; + + bgSet(background, 0, xs, ys, -xoffset << 8, -yoffset << 8, 0, 0); + oamRotateScale(&oamMain, 0, 0, xs, ys); + + /* Screen is expected to be cleared */ + dmaFillHalfWords(0, bgGetGfxPtr(background), PDD_MonitorWidth * PDD_MonitorHeight); +} + + +/*-----------------------------------------------------------------------------*/ + +typedef struct { u16 data[8][2]; } Tile; +typedef struct { Tile data[8][4]; } Sprite; +Sprite *cursorData; +int oldHeight = 64; + +static inline u16 Convert2bppTo4bpp(u8 byte) { + return (byte & 0x03) | ((byte & 0x0C) << 2) | ((byte & 0x30) << 4) | ((byte & 0xC0) << 6); +} + +/*-----------------------------------------------------------------------------*/ +/* Refresh the mouse's image */ +static void RefreshMouse(ARMul_State *state) { + int x = 0, y = 0, i = 0; + int HorizPos = 0, VertPos = 0; + int Height = ((int)VIDC.Vert_CursorEnd - (int)VIDC.Vert_CursorStart)*HD.YScale; + if (Height < 0) Height = 0; + + DisplayDev_GetCursorPos(state,&HorizPos,&VertPos); + HorizPos = fixedToInt(HorizPos * xscale, 8); + VertPos = fixedToInt(VertPos * yscale, 8); + + if (Height > 64) Height = 64; + if (VertPos < 0) VertPos = 0; + + /* TODO: This might not be as fast as it could be */ + u8 *src = ((u8 *)MEMC.PhysRam) + (MEMC.Cinit * 16); + for (y = 0; y < Height; y++) { + int ytile = y / 8; + int ydata = y % 8; + for (x = 0; x < 32; x += 8) { + int xtile = x / 8; + cursorData->data[ytile][xtile].data[ydata][0] = Convert2bppTo4bpp(*src++); + cursorData->data[ytile][xtile].data[ydata][1] = Convert2bppTo4bpp(*src++); + } + } + + if (oldHeight > Height) { + for (y = Height; y < oldHeight; y++) { + int ytile = y / 8; + int ydata = y % 8; + for (x = 0; x < 32; x += 8) { + int xtile = x / 8; + cursorData->data[ytile][xtile].data[ydata][0] = 0; + cursorData->data[ytile][xtile].data[ydata][1] = 0; + } + } + } + oldHeight = Height; + + /* Cursor palette */ + SPRITE_PALETTE[0] = 0; + for(i = 0; i < 3; i++) { + SPRITE_PALETTE[i + 1] = ConvertPhysToColour(VIDC.CursorPalette[i]); + } + + oamSet(&oamMain, 0, HorizPos, VertPos, 0, 0, SpriteSize_32x64, SpriteColorFormat_16Color, + cursorData, -1, false, false, false, false, false); +}; /* RefreshMouse */ + +/*-----------------------------------------------------------------------------*/ +int +DisplayDev_Init(ARMul_State *state) +{ + /* Setup display and cursor bitmaps */ + videoSetMode(MODE_6_2D | DISPLAY_BG2_ACTIVE); + + vramSetPrimaryBanks(VRAM_A_MAIN_BG,VRAM_B_MAIN_BG,VRAM_C_MAIN_BG,VRAM_D_MAIN_BG); + background = bgInit(2, BgType_Bmp8, PDD_BgSize, 0, 0); + + vramSetBankE(VRAM_E_MAIN_SPRITE); + oamInit(&oamMain, SpriteMapping_1D_32, false); + cursorData = (Sprite *)oamAllocateGfx(&oamMain, SpriteSize_32x64, SpriteColorFormat_16Color); + + ControlPane_Init(state); + + return DisplayDev_Set(state,&PDD_DisplayDev); +} + +/*-----------------------------------------------------------------------------*/ +static void ProcessKey(ARMul_State *state, int key, bool up) {; + const dvk_to_arch_key *ktak; + for (ktak = dvk_to_arch_key_map; ktak->sym; ktak++) { + if (ktak->sym == key) { + keyboard_key_changed(&KBD, ktak->kid, up); + return; + } + } + dbug_kbd("ProcessKey: unknown key: keysym=%u\n", key); +} + +void OnKeyPressed(int key) { + ProcessKey(&nds_statestr, key, false); +} + +void OnKeyReleased(int key) { + ProcessKey(&nds_statestr, key, true); +} + +static void ProcessButtons(ARMul_State *state, int pressed, int released) { + const button_to_arch_key *btak; + for (btak = button_to_arch_key_map; btak->sym; btak++) { + if ((pressed & btak->sym) && btak->kid != 0) + keyboard_key_changed(&KBD, btak->kid, 0); + if ((released & btak->sym) && btak->kid != 0) + keyboard_key_changed(&KBD, btak->kid, 1); + } +}; /* ProcessButtons */ + +touchPosition oldTouch; +bool touchDown = false; + +static void ProcessRelativeTouch(ARMul_State *state) { + int newMouseX, newMouseY, xdiff, ydiff; + touchPosition touch; + + touchRead(&touch); + xdiff = (touch.px - oldTouch.px) << 1; + ydiff = (touch.py - oldTouch.py) << 1; + + if (xdiff > 63) + xdiff = 63; + if (xdiff < -63) + xdiff = -63; + + if (ydiff > 63) + ydiff = 63; + if (ydiff < -63) + ydiff = -63; + + oldTouch.px += xdiff >> 1; + oldTouch.py += ydiff >> 1; + + KBD.MouseXCount = xdiff & 127; + KBD.MouseYCount = -ydiff & 127; +}; /* ProcessRelativeTouch */ + +/*-----------------------------------------------------------------------------*/ +int +Kbd_PollHostKbd(ARMul_State *state) +{ + scanKeys(); + + int pressed = keysDown(); + int released = keysUp(); + int held = keysHeld(); + ProcessButtons(state, pressed, released); + + if (pressed & KEY_TOUCH) { + touchRead(&oldTouch); + if (oldTouch.py <= 112) + touchDown = true; + } else if (released & KEY_TOUCH) { + touchDown = false; + } + + if (touchDown) + ProcessRelativeTouch(state); + + keyboardUpdate(); + + return 0; +} diff --git a/nds/KeyTable.h b/nds/KeyTable.h new file mode 100644 index 0000000..a105933 --- /dev/null +++ b/nds/KeyTable.h @@ -0,0 +1,107 @@ +/* Virtual Key codes */ + +#include + +typedef struct { + int sym; + arch_key_id kid; +} button_to_arch_key; + +/* TODO: Provide a GUI for remapping the buttons */ +static const button_to_arch_key button_to_arch_key_map[] = { + { KEY_Y, ARCH_KEY_left }, + { KEY_B, ARCH_KEY_down }, + { KEY_A, ARCH_KEY_right }, + { KEY_X, ARCH_KEY_up }, + { KEY_L, ARCH_KEY_shift_r }, + { KEY_R, ARCH_KEY_control_r }, + { KEY_LEFT, ARCH_KEY_button_1 }, + { KEY_DOWN, ARCH_KEY_button_2 }, + { KEY_RIGHT, ARCH_KEY_button_3 }, + { KEY_UP, ARCH_KEY_space }, + { 0, 0 } +}; + +#include + +typedef struct { + int sym; + arch_key_id kid; + bool isShift; +} dvk_to_arch_key; + +#define X(sym, kid) { sym, ARCH_KEY_ ## kid, false }, +#define C(sym, shift, kid) { sym, ARCH_KEY_ ## kid, false }, { shift, ARCH_KEY_ ## kid, true }, +static const dvk_to_arch_key dvk_to_arch_key_map[] = { + X(DVK_FOLD, escape) + X(DVK_MENU, f12) + + C('`', '~', grave) + C('1', '!', 1) + C('2', '@', 2) + C('3', '#', 3) + C('4', '$', 4) + C('5', '%', 5) + C('6', '^', 6) + C('7', '&', 7) + C('8', '*', 8) + C('9', '(', 9) + C('0', ')', 0) + C('-', '_', minus) + C('=', '+', equal) + X(DVK_BACKSPACE, backspace) + + X(DVK_TAB, tab) + C('q', 'Q', q) + C('w', 'W', w) + C('e', 'E', e) + C('r', 'R', r) + C('t', 'T', t) + C('y', 'Y', y) + C('u', 'U', u) + C('i', 'I', i) + C('o', 'O', o) + C('p', 'P', p) + C('[', '{', bracket_l) + C(']', '}', bracket_r) + C('\\', '|', backslash) + + X(DVK_CTRL, control_l) + C('a', 'A', a) + C('s', 'S', s) + C('d', 'D', d) + C('f', 'F', f) + C('g', 'G', g) + C('h', 'H', h) + C('j', 'J', j) + C('k', 'K', k) + C('l', 'L', l) + C(';', ':', semicolon) + C('\'', '"', apostrophe) + X(DVK_ENTER, return) + + X(DVK_SHIFT, shift_l) + C('z', 'Z', z) + C('x', 'X', x) + C('c', 'C', c) + C('v', 'V', v) + C('b', 'B', b) + C('n', 'N', n) + C('m', 'M', m) + C(',', '<', comma) + C('.', '>', period) + C('/', '?', slash) + + X(DVK_CAPS, caps_lock) + X(DVK_ALT, alt_l) + X(DVK_SPACE, space) + + X(DVK_UP, up) + X(DVK_LEFT, left) + X(DVK_DOWN, down) + X(DVK_RIGHT, right) + + { 0, 0, false }, +}; +#undef C +#undef X diff --git a/nds/arc.bmp b/nds/arc.bmp new file mode 100644 index 0000000000000000000000000000000000000000..4a47b0eea470fff4c3de92fc147ef474cbf25d31 GIT binary patch literal 630 zcmZvZKWG#|6vp433SO5j(hG~>h(%7OS}g(+lEuS-#X=z1&h4exCUCJ6a=JI>t}ref zS&Li~#2m*8Rue}otPY7_vm()Hg04Yfo0xiiZ|+Jz_Rsvj?|ZMAJNH^;Flynqitn}Q zTY}4Y`oC&#PXLa7!~4S#T>QO&(B6YZ3TWlZo#*WbvR8^ciw^Vu}j`T=^xc_X^w zd0wi~Gr1o>n!iD~{JF3gxyvSuoA zb(GXah(?<+Ct~r7oy1iFxxr9_^XjXlF2^AcGJCNoib@|@nSmxlKJRZ33x9`mwonvy zpA(OTj~i>06Zg8p4{@X6z*VXzL>PwlfcimQDJi<>G#%;_zmsEuVuMTjhE-2?kT(}i v{zg#)d7II^tI&{2N+}}N=XsrSqfVRcg@N0}lq9!0@tz2#ca6V%neP4{YQ7>i literal 0 HcmV?d00001 diff --git a/nds/arm7/main.c b/nds/arm7/main.c new file mode 100644 index 0000000..3d5da45 --- /dev/null +++ b/nds/arm7/main.c @@ -0,0 +1,97 @@ +/*--------------------------------------------------------------------------------- + + default ARM7 core + + Copyright (C) 2005 - 2010 + Michael Noland (joat) + Jason Rogers (dovoto) + Dave Murphy (WinterMute) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + +---------------------------------------------------------------------------------*/ + +/** + * Modified for ArcEm to save space, since we don't need maxmod or libdswifi. + */ + +#include + +//--------------------------------------------------------------------------------- +void VblankHandler(void) { +//--------------------------------------------------------------------------------- +} + + +//--------------------------------------------------------------------------------- +void VcountHandler() { +//--------------------------------------------------------------------------------- + inputGetAndSend(); +} + +volatile bool exitflag = false; + +//--------------------------------------------------------------------------------- +void powerButtonCB() { +//--------------------------------------------------------------------------------- + exitflag = true; +} + +//--------------------------------------------------------------------------------- +int main() { +//--------------------------------------------------------------------------------- + // clear sound registers + dmaFillWords(0, (void*)0x04000400, 0x100); + + REG_SOUNDCNT |= SOUND_ENABLE; + writePowerManagement(PM_CONTROL_REG, ( readPowerManagement(PM_CONTROL_REG) & ~PM_SOUND_MUTE ) | PM_SOUND_AMP ); + powerOn(POWER_SOUND); + + readUserSettings(); + ledBlink(0); + + irqInit(); + // Start the RTC tracking IRQ + initClockIRQ(); + fifoInit(); + touchInit(); + + SetYtrigger(80); + + installSoundFIFO(); + + installSystemFIFO(); + + irqSet(IRQ_VCOUNT, VcountHandler); + irqSet(IRQ_VBLANK, VblankHandler); + + irqEnable( IRQ_VBLANK | IRQ_VCOUNT ); + + setPowerButtonCB(powerButtonCB); + + // Keep the ARM7 mostly idle + while (!exitflag) { + if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) { + exitflag = true; + } + swiWaitForVBlank(); + } + return 0; +} diff --git a/nds/filecalls.c b/nds/filecalls.c new file mode 100644 index 0000000..a3b1b73 --- /dev/null +++ b/nds/filecalls.c @@ -0,0 +1,181 @@ +/* filecalls.c posix implimentatation of the abstracted interface to accesing host + OS file and Directory functions. + Copyright (c) 2005 Peter Howkins, covered under the GNU GPL see file COPYING for more + details */ +/* ansi includes */ +#include +#include +#include +#include + +/* posix includes */ +#include +#include +#include + +/* application includes */ +#include "dbugsys.h" +#include "filecalls.h" + +static bool File_GetInfo(const char *sPath, FileInfo *phFileInfo); + +/** + * Directory_Open + * + * Open a directory so that it's contents can be scanned + * + * @param sPath Location of directory to scan + * @param hDir Pointer to a Directory struct to fill in + * @returns true on success false on failure + */ +bool Directory_Open(const char *sPath, Directory *hDirectory) +{ + assert(sPath); + assert(*sPath); + assert(hDirectory); + + hDirectory->sPathLen = strlen(sPath); + hDirectory->sPath = malloc(hDirectory->sPathLen + 1); + + if(NULL == hDirectory->sPath) { + return false; + } else { + strcpy(hDirectory->sPath, sPath); + } + + hDirectory->hDir = opendir(sPath); + + if(NULL == hDirectory->hDir) { + return false; + } else { + return true; + } +} + +/** + * Directory_Close + * + * Close a previously opened Directory + * + * @param hDirectory Directory to close + */ +void Directory_Close(Directory hDirectory) +{ + closedir(hDirectory.hDir); + free(hDirectory.sPath); +} + +/** + * Directory_GetNextEntry + * + * Get the next entry in a directory + * + * @param hDirectory pointer to Directory to get entry from + * @returns String of filename or NULL on EndOfDirectory + */ +char *Directory_GetNextEntry(Directory *hDirectory, FileInfo *phFileInfo) +{ + struct dirent *phDirEntry; + + assert(hDirectory); + + phDirEntry = readdir(hDirectory->hDir); + if(!phDirEntry) { + return NULL; + } + + if (phFileInfo) { + phFileInfo->bIsRegularFile = false; + phFileInfo->bIsDirectory = false; + +#ifdef _DIRENT_HAVE_D_TYPE + if (phDirEntry->d_type == DT_REG || phDirEntry->d_type == DT_DIR) { + phFileInfo->bIsRegularFile = (phDirEntry->d_type == DT_REG); + phFileInfo->bIsDirectory = (phDirEntry->d_type == DT_DIR); + } else +#endif + { + char *path = Directory_GetFullPath(hDirectory, phDirEntry->d_name); + if (path) { + File_GetInfo(path, phFileInfo); + free(path); + } + } + } + + return phDirEntry->d_name; +} + +/** + * Directory_GetFullPath + * + * Get the full path of a file in a directory + * + * @param hDirectory pointer to Directory to get the base path from + * @returns String of the full path or NULL on EndOfDirectory + */ +char *Directory_GetFullPath(Directory *hDirectory, const char *leaf) { + size_t len = hDirectory->sPathLen + strlen(leaf) + 1; + char *path = malloc(len + 1); + if (!path) { + return NULL; + } + + strcpy(path, hDirectory->sPath); + strcat(path, "/"); + strcat(path, leaf); + return path; +} + +/** + * File_OpenAppData + * + * Open the specified file in the application data directory + * + * @param sName Name of file to open + * @param sMode Mode to open the file with + * @returns File handle or NULL on failure + */ +FILE *File_OpenAppData(const char *sName, const char *sMode) +{ + return NULL; +} + +/** + * File_GetInfo + * + * Fills in lots of useful info about the passed in file + * + * @param sPath Path to file to check + * @param phFileInfo pointer to FileInfo struct to fill in + * @returns false on failure true on success + */ +static bool File_GetInfo(const char *sPath, FileInfo *phFileInfo) +{ + struct stat hEntryInfo; + + assert(sPath); + assert(phFileInfo); + + if (stat(sPath, &hEntryInfo) != 0) { + warn("Warning: could not stat() entry \'%s\': %s\n", + sPath, strerror(errno)); + return false; + } + + /* Initialise components */ + phFileInfo->bIsRegularFile = false; + phFileInfo->bIsDirectory = false; + + if (S_ISREG(hEntryInfo.st_mode)) { + phFileInfo->bIsRegularFile = true; + } + + if (S_ISDIR(hEntryInfo.st_mode)) { + phFileInfo->bIsDirectory = true; + } + + /* Success! */ + return true; +} + diff --git a/nds/filecalls_internal.h b/nds/filecalls_internal.h new file mode 100644 index 0000000..0c67167 --- /dev/null +++ b/nds/filecalls_internal.h @@ -0,0 +1,17 @@ +/* filecalls_internal.h + Copyright (c) 2005 Peter Howkins, covered under the GNU GPL see file COPYING for more + details */ + +#ifndef __FILECALLS_INTERNAL_H +#define __FILECALLS_INTERNAL_H + +#include +#include + +struct Directory_s { + DIR *hDir; + char *sPath; + size_t sPathLen; +}; + +#endif /* __FILECALLS_H */ diff --git a/nds/main.c b/nds/main.c new file mode 100644 index 0000000..09f81b2 --- /dev/null +++ b/nds/main.c @@ -0,0 +1,40 @@ +#include "../dagstandalone.h" +#include "../prof.h" + +#include "../arch/ArcemConfig.h" +#include "../arch/ControlPane.h" + +#include +#include + +static ArcemConfig hArcemConfig; + +int main(int argc,char *argv[]) { + Prof_Init(); + + if (!nitroFSInit(NULL)) { + ControlPane_Error(EXIT_FAILURE, "Failed to initialise filesystem"); + } + + // Setup the default values for the config system + ArcemConfig_SetupDefaults(&hArcemConfig); + + // Parse the config file to overrule the defaults + ArcemConfig_ParseConfigFile(&hArcemConfig); + + // Parse any commandline arguments given to the program + // to overrule the defaults + ArcemConfig_ParseCommandLine(&hArcemConfig, argc, argv); + + if (isDSiMode()) { + if (hArcemConfig.eMemSize > MemSize_4M) + hArcemConfig.eMemSize = MemSize_4M; + } else { + if (hArcemConfig.eMemSize > MemSize_1M) + hArcemConfig.eMemSize = MemSize_1M; + } + + dagstandalone(&hArcemConfig); + + return EXIT_SUCCESS; +} diff --git a/support_modules/modes/ArcemModes,ffa b/support_modules/modes/ArcemModes,ffa index bff864afa76b23ed53c5d9efcf90df6523352338..b83306b53cc12f6795bd4a64a6b87799d923b545 100755 GIT binary patch delta 337 zcmW;IElfgD7{>7j?ga&OGcdh{c{j=pZrmN`WEPIjU@)5~Zt8HujWL2#{0IgE;W~&0 z0>MCF!(edpHYG}tV5{ExFedw=JI^SF+{@}wvC~mpjAVlz`v=+lGj%{- z$WS&MkykSQb&u2CuWWvEox74`jWB~Mgf{atTFfhNmG}VO#t`aOQiYWnTp}N2#`*^v CXf|sA delta 201 zcmWO0tqwr}0LAg+erIQAJNxJ(vdM-WJDJJZ#c|ipq@8W4zAU(;pI2&0TH}EswecOlaR*y&spgY< zxQg$%kM}t5XM>;kjE6YpkrDxEgq!$)C-{i1pftrFyb3C=86m}iFU1^>a4#e+@D;y8 Qmx}A=*_}-D(lE-tKjhaSCjbBd diff --git a/support_modules/modes/MakeModes,ffb b/support_modules/modes/MakeModes,ffb index 3183f8d4bcfc9a13368935f3dceca97f31944874..4e66907144efa428da29897b97c21294eb7dd285 100755 GIT binary patch literal 34178 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%0Aq2FfKxP+&(If3y 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 literal 7922 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 bxRqMY>y>|v;R?b?t1YMF?HTLuRv-E=oo-lZ diff --git a/support_modules/modes/README b/support_modules/modes/README index 1d13496..143815b 100755 --- a/support_modules/modes/README +++ b/support_modules/modes/README @@ -39,6 +39,8 @@ PDA style modes (I wanted to see what RISC OS would look like on an iPaq) 124 240 320 4 16 125 240 320 8 256 +126 256 192 8 256 + Developing and assembling ------------------------- From 83ead714022a67873126321f7289608511ade70b Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Tue, 7 Nov 2023 23:19:55 +0000 Subject: [PATCH 2/8] Add an initial GUI for the DS port --- Makefile | 10 +- arch/dbugsys.h | 2 +- hostfs.c | 2 +- nds/ControlPane.c | 272 ++++++++++++++++++++++++++++++++++++++++++++-- nds/ControlPane.h | 7 +- nds/DispKbd.c | 83 +++++--------- nds/KeyTable.h | 251 ++++++++++++++++++++++++++---------------- nds/img/bg.grit | 17 +++ nds/img/bg.png | Bin 0 -> 439 bytes nds/img/keys.grit | 14 +++ nds/img/keys.png | Bin 0 -> 1719 bytes 11 files changed, 498 insertions(+), 160 deletions(-) create mode 100644 nds/img/bg.grit create mode 100644 nds/img/bg.png create mode 100644 nds/img/keys.grit create mode 100644 nds/img/keys.png diff --git a/Makefile b/Makefile index 9750973..af78428 100644 --- a/Makefile +++ b/Makefile @@ -182,12 +182,13 @@ endif ifeq (${SYSTEM},nds) CC=arm-none-eabi-gcc +AS=arm-none-eabi-as LD=$(CC) ARM9_ARCH = -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s CFLAGS += $(ARM9_ARCH) -ffunction-sections -fdata-sections -DSYSTEM_nds -DARM9 -DUSE_FAKEMAIN -DNO_OPEN64 -isystem $(DEVKITPRO)/libnds/include -Wno-cast-align -Wno-format LDFLAGS += -specs=ds_arm9.specs -g $(ARM9_ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libnds/lib LIBS += -lfilesystem -lfat -lnds9 -OBJS += nds/main.o +OBJS += nds/main.o nds/img/bg.o nds/img/keys.o ifneq ($(DEBUG),yes) CFLAGS += -DNDEBUG endif @@ -200,6 +201,13 @@ all: ArcEm.nds cp support_modules/*/*,ffa romfs/extnrom ndstool -c $@ -9 $< -7 $*.arm7.elf -b nds/arc.bmp "ArcEm;Archimedes Emulator;WIP" -d romfs +%.s %.h: %.png %.grit + grit $< -fts -o$* +%.s %.h: %.bmp %.grit + grit $< -fts -o$* + +nds/ControlPane.o: nds/KeyTable.h nds/img/bg.h nds/img/keys.h + ARM7_ARCH = -mthumb -mthumb-interwork -march=armv4t -mtune=arm7tdmi ARM7_CFLAGS = $(ARM7_ARCH) -Os -ffunction-sections -fdata-sections -DARM7 -isystem $(DEVKITPRO)/libnds/include ARM7_LDFLAGS = -specs=ds_arm7.specs -g $(ARM7_ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libnds/lib diff --git a/arch/dbugsys.h b/arch/dbugsys.h index e756f40..d9c151a 100644 --- a/arch/dbugsys.h +++ b/arch/dbugsys.h @@ -27,7 +27,7 @@ #undef DEBUG_HDC63463 #undef DEBUG_CONFIG -#ifdef SYSTEM_nds +#if defined(SYSTEM_nds) && defined(NDEBUG) #undef IOC_WARN #undef WARN #undef WARN_MEMC diff --git a/hostfs.c b/hostfs.c index f12f30d..3c677fe 100644 --- a/hostfs.c +++ b/hostfs.c @@ -221,7 +221,7 @@ dbug_hostfs(const char *format, ...) } #endif -#ifdef SYSTEM_nds +#if defined(SYSTEM_nds) && defined(NDEBUG) static inline void warn_hostfs(const char *format, ...) {} #else static void diff --git a/nds/ControlPane.c b/nds/ControlPane.c index 61ec1e8..088375c 100644 --- a/nds/ControlPane.c +++ b/nds/ControlPane.c @@ -8,32 +8,83 @@ #include "ControlPane.h" #include "../arch/keyboard.h" +#include "KeyTable.h" + +#include "img/bg.h" +#include "img/keys.h" + #include #include #include -bool hasKeyboard = false; +enum { + DRAG_NONE, + DRAG_MOUSE +}; + +static int old_px = -1; +static int old_py = -1; +static int drag_mode = DRAG_NONE; + +static bool keys_caps = false; +static arch_key_id key_pressed = -1; + +static bool has_console = false; +static bool has_keyboard = false; + +static void ControlPane_InitKeyboard(ARMul_State *state); + +static void draw_floppy_leds(unsigned int leds) +{ + unsigned int floppy; + + for (floppy = 0; floppy < 4; floppy++) { + BG_PALETTE_SUB[15 - floppy] = (leds & (1 << floppy)) ? RGB8(0xff, 0xbb, 0x00) : RGB8(0x99, 0x99, 0x99); + } +} + +static void draw_floppy(unsigned int floppy, bool inserted) { + if (inserted) { + BG_PALETTE_SUB[10 - (floppy * 2)] = RGB8(0xff, 0xbb, 0x00); + BG_PALETTE_SUB[11 - (floppy * 2)] = RGB8(0xdd, 0x00, 0x00); + } else { + BG_PALETTE_SUB[10 - (floppy * 2)] = 0; + BG_PALETTE_SUB[11 - (floppy * 2)] = 0; + } +} + +/*----------------------------------------------------------------------------*/ void ControlPane_Init(ARMul_State *state) { videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE); vramSetBankH(VRAM_H_SUB_BG); + vramSetBankI(VRAM_I_SUB_SPRITE); + oamInit(&oamSub, SpriteMapping_1D_128, false); #ifndef NDEBUG scanKeys(); int held = keysHeld(); if (held & KEY_SELECT) { - consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); - } else + consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); + has_console = true; + } #endif + + if (!has_console) { - Keyboard *keyboard = keyboardInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x512, 15, 0, false, true); - keyboard->OnKeyPressed = OnKeyPressed; - keyboard->OnKeyReleased = OnKeyReleased; - keyboardShow(); - hasKeyboard = true; + BGCTRL_SUB[0] = BG_TILE_BASE(1) | BG_MAP_BASE(0) | BG_COLOR_16 | BG_32x32; + + decompress(bgTiles, (void *)CHAR_BASE_BLOCK_SUB(1), LZ77Vram); + decompress(bgMap, (void *)SCREEN_BASE_BLOCK_SUB(0), LZ77Vram); + dmaCopy(bgPal, BG_PALETTE_SUB, bgPalLen); + + ControlPane_InitKeyboard(state); + + FDC_SetLEDsChangeFunc(draw_floppy_leds); + ControlPane_Redraw(); } } @@ -42,6 +93,9 @@ void ControlPane_Error(int code,const char *fmt,...) va_list args; va_start(args,fmt); + if (!has_console) + consoleDemoInit(); + /* Log it */ vprintf(fmt,args); @@ -55,3 +109,205 @@ void ControlPane_Error(int code,const char *fmt,...) /* Quit */ exit(code); } + +/*----------------------------------------------------------------------------*/ + +static void ControlPane_UpdateKeyboardLEDs(uint8_t leds); + +static void ControlPane_InitKeyboard(ARMul_State *state) +{ + static const u16 keysPal[] = { + /* 0: Not pressed, shift off, leds off */ + 0x5FBD,0x6F7B,0x5EF7,0x7FFF,0x39CE,0x4E73,0x5EF7,0x0000, + 0x0000,0x0000,0x6F7B,0x39CE,0x5FBD,0x022A,0x02FF,0x7EE0, + /* 1: Not pressed, shift off, leds on */ + 0x5FBD,0x6F7B,0x5EF7,0x7FFF,0x39CE,0x4E73,0x5EF7,0x0000, + 0x0000,0x0000,0x6F7B,0x0320,0x5FBD,0x022A,0x02FF,0x7EE0, + /* 2: Not pressed, shift on, leds off */ + 0x5FBD,0x6F7B,0x5EF7,0x7FFF,0x39CE,0x4E73,0x5EF7,0x0000, + 0x6F7B,0x0000,0x0000,0x39CE,0x5FBD,0x022A,0x02FF,0x7EE0, + /* 3: Not pressed, shift on, leds on */ + 0x5FBD,0x6F7B,0x5EF7,0x7FFF,0x39CE,0x4E73,0x5EF7,0x0000, + 0x6F7B,0x0000,0x0000,0x0320,0x5FBD,0x022A,0x02FF,0x7EE0, + /* 4: Pressed, shift off, leds off */ + 0x5FBD,0x6F7B,0x7FFF,0x5EF7,0x5EF7,0x4E73,0x39CE,0x0000, + 0x0000,0x0000,0x6F7B,0x39CE,0x5FBD,0x022A,0x02FF,0x7EE0, + /* 5: Pressed, shift off, leds on */ + 0x5FBD,0x6F7B,0x7FFF,0x5EF7,0x5EF7,0x4E73,0x39CE,0x0000, + 0x0000,0x0000,0x6F7B,0x0320,0x5FBD,0x022A,0x02FF,0x7EE0, + /* 6: Pressed, shift on, leds off */ + 0x5FBD,0x6F7B,0x7FFF,0x5EF7,0x5EF7,0x4E73,0x39CE,0x0000, + 0x6F7B,0x0000,0x0000,0x39CE,0x5FBD,0x022A,0x02FF,0x7EE0, + /* 7: Pressed, shift on, leds on */ + 0x5FBD,0x6F7B,0x7FFF,0x5EF7,0x5EF7,0x4E73,0x39CE,0x0000, + 0x6F7B,0x0000,0x0000,0x0320,0x5FBD,0x022A,0x02FF,0x7EE0 + }; + int i; + + /* We manage sprite VRAM manually here instead of using oamAllocateGfx() */ + decompress(keysTiles, SPRITE_GFX_SUB, LZ77Vram); + dmaCopy(keysPal, SPRITE_PALETTE_SUB, sizeof(keysPal)); + + KBD.leds_changed = ControlPane_UpdateKeyboardLEDs; + + has_keyboard = true; +} + +static void ControlPane_UpdateKeyboardLEDs(uint8_t leds) +{ + keys_caps = (leds & KBD_LED_CAPSLOCK); +} + +static bool ControlPane_ClickKeyboard(ARMul_State *state, int px, int py) +{ + const dvk_to_vkeybd *ktvk; + for (ktvk = dvk_to_vkeybd_map; ktvk->sprite; ktvk++) { + uint width = ((ktvk->sprite) >> 8) * 16; + uint height = 16; + + if (px >= ktvk->x && px < ktvk->x + width && + py >= ktvk->y && py < ktvk->y + height) { + keyboard_key_changed(&KBD, ktvk->kid, 0); + key_pressed = ktvk->kid; + return true; + } + } + return false; +} + +static void ControlPane_ReleaseKeyboard(ARMul_State *state) +{ + if (key_pressed != -1) { + keyboard_key_changed(&KBD, key_pressed, 1); + key_pressed = -1; + } +} + +static void ControlPane_DrawKeyboard(void) +{ + const dvk_to_vkeybd *ktvk; + uint i = 0; + + for (ktvk = dvk_to_vkeybd_map; ktvk->sprite; ktvk++) { + uint sprite = (ktvk->sprite) & 0xFF; + uint width = (ktvk->sprite) >> 8; + uint x = ktvk->x, y = ktvk->y; + uint palette = 0; + + if (keys_caps) palette |= 1; + if (ktvk->kid == key_pressed) palette |= 4; + + do { + oamSet(&oamSub, i++, x, y, 0, palette, SpriteSize_16x16, SpriteColorFormat_16Color, + &SPRITE_GFX_SUB[sprite++ * 64], -1, false, false, false, false, false); + x += 16; + } while (--width); + } +} + +/*----------------------------------------------------------------------------*/ + +static void ControlPane_ClickFloppy(ARMul_State *state, int drive) +{ + const char *err; + char tmp[256]; + + if (FDC_IsFloppyInserted(drive)) { + err = FDC_EjectFloppy(drive); + if (err == NULL) + draw_floppy(drive, false); + /* TODO: Report warning if this fails */ + } else { + sprintf(tmp, "FloppyImage%d", drive); + err = FDC_InsertFloppy(drive, tmp); + if (err == NULL) + draw_floppy(drive, true); + /* TODO: Report warning if this fails */ + } +} + +/*----------------------------------------------------------------------------*/ + +static void ControlPane_ClickTouchpad(ARMul_State *state, int px, int py) +{ + drag_mode = DRAG_MOUSE; + old_px = px; + old_py = py; +} + +static void ControlPane_DragTouchpad(ARMul_State *state, int px, int py) +{ + int newMouseX, newMouseY, xdiff, ydiff; + + xdiff = (px - old_px) << 2; + ydiff = (py - old_py) << 2; + + if (xdiff > 63) + xdiff = 63; + if (xdiff < -63) + xdiff = -63; + + if (ydiff > 63) + ydiff = 63; + if (ydiff < -63) + ydiff = -63; + + old_px += xdiff >> 2; + old_py += ydiff >> 2; + + KBD.MouseXCount = xdiff & 127; + KBD.MouseYCount = -ydiff & 127; +} + +/*----------------------------------------------------------------------------*/ + +bool ControlPane_ProcessTouchPressed(ARMul_State *state, int px, int py) +{ + if (has_keyboard && ControlPane_ClickKeyboard(state, px, py)) + return true; + + if (py > 183 || has_console) { + int drive = 3 - (px / 64); + ControlPane_ClickFloppy(state, drive); + return true; + } else if (py < 78) { + ControlPane_ClickTouchpad(state, px, py); + return true; + } + + return false; +} + +bool ControlPane_ProcessTouchHeld(ARMul_State *state, int px, int py) +{ + if (drag_mode == DRAG_MOUSE) { + ControlPane_DragTouchpad(state, px, py); + return true; + } + + return false; +} + +bool ControlPane_ProcessTouchReleased(ARMul_State *state) +{ + bool retval = false; + + ControlPane_ReleaseKeyboard(state); + + if (drag_mode != DRAG_NONE) { + drag_mode = DRAG_NONE; + old_px = -1; + old_py = -1; + retval = true; + } + + return false; +} + +/*----------------------------------------------------------------------------*/ + +void ControlPane_Redraw(void) +{ + ControlPane_DrawKeyboard(); + oamUpdate(&oamSub); +} diff --git a/nds/ControlPane.h b/nds/ControlPane.h index d47315d..25f69d1 100644 --- a/nds/ControlPane.h +++ b/nds/ControlPane.h @@ -7,7 +7,10 @@ void ControlPane_Init(ARMul_State *state); /* Report an error and exit */ void ControlPane_Error(int code,const char *fmt,...); -void OnKeyPressed(int key); -void OnKeyReleased(int key); +bool ControlPane_ProcessTouchPressed(ARMul_State *state, int px, int py); +bool ControlPane_ProcessTouchHeld(ARMul_State *state, int px, int py); +bool ControlPane_ProcessTouchReleased(ARMul_State *state); + +void ControlPane_Redraw(void); #endif diff --git a/nds/DispKbd.c b/nds/DispKbd.c index b3746c3..8375299 100644 --- a/nds/DispKbd.c +++ b/nds/DispKbd.c @@ -14,8 +14,6 @@ #include -#include "KeyTable.h" - ARMul_State nds_statestr DTCM_BSS; void *state_alloc(int s) { return &nds_statestr; } void state_free(void *p) {} @@ -133,6 +131,7 @@ static inline void PDD_Name(Host_PollDisplay)(ARMul_State *state) RefreshMouse(state); oamUpdate(&oamMain); bgUpdate(); + ControlPane_Redraw(); } static inline void PDD_Name(Host_DrawBorderRect)(ARMul_State *state,int x,int y,int width,int height) @@ -279,24 +278,26 @@ DisplayDev_Init(ARMul_State *state) } /*-----------------------------------------------------------------------------*/ -static void ProcessKey(ARMul_State *state, int key, bool up) {; - const dvk_to_arch_key *ktak; - for (ktak = dvk_to_arch_key_map; ktak->sym; ktak++) { - if (ktak->sym == key) { - keyboard_key_changed(&KBD, ktak->kid, up); - return; - } - } - dbug_kbd("ProcessKey: unknown key: keysym=%u\n", key); -} - -void OnKeyPressed(int key) { - ProcessKey(&nds_statestr, key, false); -} -void OnKeyReleased(int key) { - ProcessKey(&nds_statestr, key, true); -} +typedef struct { + int sym; + arch_key_id kid; +} button_to_arch_key; + +/* TODO: Provide a GUI for remapping the buttons */ +static const button_to_arch_key button_to_arch_key_map[] = { + { KEY_Y, ARCH_KEY_left }, + { KEY_B, ARCH_KEY_down }, + { KEY_A, ARCH_KEY_right }, + { KEY_X, ARCH_KEY_up }, + { KEY_L, ARCH_KEY_shift_r }, + { KEY_R, ARCH_KEY_control_r }, + { KEY_LEFT, ARCH_KEY_button_1 }, + { KEY_DOWN, ARCH_KEY_button_2 }, + { KEY_RIGHT, ARCH_KEY_button_3 }, + { KEY_UP, ARCH_KEY_space }, + { 0, 0 } +}; static void ProcessButtons(ARMul_State *state, int pressed, int released) { const button_to_arch_key *btak; @@ -308,38 +309,11 @@ static void ProcessButtons(ARMul_State *state, int pressed, int released) { } }; /* ProcessButtons */ -touchPosition oldTouch; -bool touchDown = false; - -static void ProcessRelativeTouch(ARMul_State *state) { - int newMouseX, newMouseY, xdiff, ydiff; - touchPosition touch; - - touchRead(&touch); - xdiff = (touch.px - oldTouch.px) << 1; - ydiff = (touch.py - oldTouch.py) << 1; - - if (xdiff > 63) - xdiff = 63; - if (xdiff < -63) - xdiff = -63; - - if (ydiff > 63) - ydiff = 63; - if (ydiff < -63) - ydiff = -63; - - oldTouch.px += xdiff >> 1; - oldTouch.py += ydiff >> 1; - - KBD.MouseXCount = xdiff & 127; - KBD.MouseYCount = -ydiff & 127; -}; /* ProcessRelativeTouch */ - /*-----------------------------------------------------------------------------*/ int Kbd_PollHostKbd(ARMul_State *state) { + touchPosition touch; scanKeys(); int pressed = keysDown(); @@ -348,17 +322,14 @@ Kbd_PollHostKbd(ARMul_State *state) ProcessButtons(state, pressed, released); if (pressed & KEY_TOUCH) { - touchRead(&oldTouch); - if (oldTouch.py <= 112) - touchDown = true; + touchRead(&touch); + ControlPane_ProcessTouchPressed(state, touch.px, touch.py); + } else if (held & KEY_TOUCH) { + touchRead(&touch); + ControlPane_ProcessTouchHeld(state, touch.px, touch.py); } else if (released & KEY_TOUCH) { - touchDown = false; + ControlPane_ProcessTouchReleased(state); } - if (touchDown) - ProcessRelativeTouch(state); - - keyboardUpdate(); - return 0; } diff --git a/nds/KeyTable.h b/nds/KeyTable.h index a105933..bc64c19 100644 --- a/nds/KeyTable.h +++ b/nds/KeyTable.h @@ -1,107 +1,176 @@ /* Virtual Key codes */ -#include - typedef struct { - int sym; arch_key_id kid; -} button_to_arch_key; + unsigned short sprite; + short x; + short y; +} dvk_to_vkeybd; -/* TODO: Provide a GUI for remapping the buttons */ -static const button_to_arch_key button_to_arch_key_map[] = { - { KEY_Y, ARCH_KEY_left }, - { KEY_B, ARCH_KEY_down }, - { KEY_A, ARCH_KEY_right }, - { KEY_X, ARCH_KEY_up }, - { KEY_L, ARCH_KEY_shift_r }, - { KEY_R, ARCH_KEY_control_r }, - { KEY_LEFT, ARCH_KEY_button_1 }, - { KEY_DOWN, ARCH_KEY_button_2 }, - { KEY_RIGHT, ARCH_KEY_button_3 }, - { KEY_UP, ARCH_KEY_space }, - { 0, 0 } -}; +enum { + spr_f1 = 0 | (1 << 8), + spr_f2 = 1 | (1 << 8), + spr_f3 = 2 | (1 << 8), + spr_f4 = 3 | (1 << 8), + spr_f5 = 4 | (1 << 8), + spr_f6 = 5 | (1 << 8), + spr_f7 = 6 | (1 << 8), + spr_f8 = 7 | (1 << 8), + spr_f9 = 8 | (1 << 8), + spr_f10 = 9 | (1 << 8), + spr_f11 = 10 | (1 << 8), + spr_f12 = 11 | (1 << 8), + spr_up = 12 | (1 << 8), + spr_down = 13 | (1 << 8), + spr_left = 14 | (1 << 8), + spr_right = 15 | (1 << 8), -#include + spr_shift_l = 16 | (3 << 8), + spr_shift_r = spr_shift_l, + spr_caps_lock = 19 | (2 << 8), + spr_tab = 21 | (2 << 8), + spr_escape = 23 | (1 << 8), + spr_alt_l = 24 | (2 << 8), + spr_alt_r = spr_alt_l, + spr_return = 26 | (2 << 8), + spr_control_r = 28 | (2 << 8), + spr_control_l = 30 | (2 << 8), -typedef struct { - int sym; - arch_key_id kid; - bool isShift; -} dvk_to_arch_key; + spr_backspace = 32 | (1 << 8), + spr_space = 33 | (8 << 8), + spr_backslash = 41 | (2 << 8), + spr_grave = 43 | (1 << 8), + spr_1 = 44 | (1 << 8), + spr_2 = 45 | (1 << 8), + spr_3 = 46 | (1 << 8), + spr_4 = 47 | (1 << 8), -#define X(sym, kid) { sym, ARCH_KEY_ ## kid, false }, -#define C(sym, shift, kid) { sym, ARCH_KEY_ ## kid, false }, { shift, ARCH_KEY_ ## kid, true }, -static const dvk_to_arch_key dvk_to_arch_key_map[] = { - X(DVK_FOLD, escape) - X(DVK_MENU, f12) + spr_5 = 48 | (1 << 8), + spr_6 = 49 | (1 << 8), + spr_7 = 50 | (1 << 8), + spr_8 = 51 | (1 << 8), + spr_9 = 52 | (1 << 8), + spr_0 = 53 | (1 << 8), + spr_minus = 54 | (1 << 8), + spr_equal = 55 | (1 << 8), + spr_sterling = 56 | (1 << 8), + spr_q = 57 | (1 << 8), + spr_w = 58 | (1 << 8), + spr_e = 59 | (1 << 8), + spr_r = 60 | (1 << 8), + spr_t = 61 | (1 << 8), + spr_y = 62 | (1 << 8), + spr_u = 63 | (1 << 8), + + spr_i = 64 | (1 << 8), + spr_o = 65 | (1 << 8), + spr_p = 66 | (1 << 8), + spr_bracket_l = 67 | (1 << 8), + spr_bracket_r = 68 | (1 << 8), + spr_a = 69 | (1 << 8), + spr_s = 70 | (1 << 8), + spr_d = 71 | (1 << 8), + spr_f = 72 | (1 << 8), + spr_g = 73 | (1 << 8), + spr_h = 74 | (1 << 8), + spr_j = 75 | (1 << 8), + spr_k = 76 | (1 << 8), + spr_l = 77 | (1 << 8), + spr_semicolon = 78 | (1 << 8), + spr_apostrophe = 79 | (1 << 8), + + + spr_z = 80 | (1 << 8), + spr_x = 81 | (1 << 8), + spr_c = 82 | (1 << 8), + spr_v = 83 | (1 << 8), + spr_b = 84 | (1 << 8), + spr_n = 85 | (1 << 8), + spr_m = 86 | (1 << 8), + spr_comma = 87 | (1 << 8), + spr_period = 88 | (1 << 8), + spr_slash = 89 | (1 << 8), +}; - C('`', '~', grave) - C('1', '!', 1) - C('2', '@', 2) - C('3', '#', 3) - C('4', '$', 4) - C('5', '%', 5) - C('6', '^', 6) - C('7', '&', 7) - C('8', '*', 8) - C('9', '(', 9) - C('0', ')', 0) - C('-', '_', minus) - C('=', '+', equal) - X(DVK_BACKSPACE, backspace) +#define X(kid, x, y) { ARCH_KEY_ ## kid, spr_ ## kid, x, y } +static const dvk_to_vkeybd dvk_to_vkeybd_map[] = { + X(escape, 1, 165-(5*17)), + X(f1, 30+(0*17), 165-(5*17)), + X(f2, 30+(1*17), 165-(5*17)), + X(f3, 30+(2*17), 165-(5*17)), + X(f4, 30+(3*17), 165-(5*17)), + X(f5, 41+(4*17), 165-(5*17)), + X(f6, 41+(5*17), 165-(5*17)), + X(f7, 41+(6*17), 165-(5*17)), + X(f8, 41+(7*17), 165-(5*17)), + X(f9, 52+(8*17), 165-(5*17)), + X(f10, 52+(9*17), 165-(5*17)), + X(f11, 52+(10*17), 165-(5*17)), + X(f12, 52+(11*17), 165-(5*17)), - X(DVK_TAB, tab) - C('q', 'Q', q) - C('w', 'W', w) - C('e', 'E', e) - C('r', 'R', r) - C('t', 'T', t) - C('y', 'Y', y) - C('u', 'U', u) - C('i', 'I', i) - C('o', 'O', o) - C('p', 'P', p) - C('[', '{', bracket_l) - C(']', '}', bracket_r) - C('\\', '|', backslash) + X(grave, 1+(0*17), 167-(4*17)), + X(1, 1+(1*17), 167-(4*17)), + X(2, 1+(2*17), 167-(4*17)), + X(3, 1+(3*17), 167-(4*17)), + X(4, 1+(4*17), 167-(4*17)), + X(5, 1+(5*17), 167-(4*17)), + X(6, 1+(6*17), 167-(4*17)), + X(7, 1+(7*17), 167-(4*17)), + X(8, 1+(8*17), 167-(4*17)), + X(9, 1+(9*17), 167-(4*17)), + X(0, 1+(10*17), 167-(4*17)), + X(minus, 1+(11*17), 167-(4*17)), + X(equal, 1+(12*17), 167-(4*17)), + X(sterling, 1+(13*17), 167-(4*17)), + X(backspace, 1+(14*17), 167-(4*17)), - X(DVK_CTRL, control_l) - C('a', 'A', a) - C('s', 'S', s) - C('d', 'D', d) - C('f', 'F', f) - C('g', 'G', g) - C('h', 'H', h) - C('j', 'J', j) - C('k', 'K', k) - C('l', 'L', l) - C(';', ':', semicolon) - C('\'', '"', apostrophe) - X(DVK_ENTER, return) + X(tab, 1, 167-(3*17)), + X(q, 27+(0*17), 167-(3*17)), + X(w, 27+(1*17), 167-(3*17)), + X(e, 27+(2*17), 167-(3*17)), + X(r, 27+(3*17), 167-(3*17)), + X(t, 27+(4*17), 167-(3*17)), + X(y, 27+(5*17), 167-(3*17)), + X(u, 27+(6*17), 167-(3*17)), + X(i, 27+(7*17), 167-(3*17)), + X(o, 27+(8*17), 167-(3*17)), + X(p, 27+(9*17), 167-(3*17)), + X(bracket_l, 27+(10*17), 167-(3*17)), + X(bracket_r, 27+(11*17), 167-(3*17)), + X(backslash, 27+(12*17), 167-(3*17)), - X(DVK_SHIFT, shift_l) - C('z', 'Z', z) - C('x', 'X', x) - C('c', 'C', c) - C('v', 'V', v) - C('b', 'B', b) - C('n', 'N', n) - C('m', 'M', m) - C(',', '<', comma) - C('.', '>', period) - C('/', '?', slash) + X(control_l, 1, 167-(2*17)), + X(a, 35+(0*17), 167-(2*17)), + X(s, 35+(1*17), 167-(2*17)), + X(d, 35+(2*17), 167-(2*17)), + X(f, 35+(3*17), 167-(2*17)), + X(g, 35+(4*17), 167-(2*17)), + X(h, 35+(5*17), 167-(2*17)), + X(j, 35+(6*17), 167-(2*17)), + X(k, 35+(7*17), 167-(2*17)), + X(l, 35+(8*17), 167-(2*17)), + X(semicolon, 35+(9*17), 167-(2*17)), + X(apostrophe, 35+(10*17), 167-(2*17)), + X(return, 36+(11*17), 167-(2*17)), - X(DVK_CAPS, caps_lock) - X(DVK_ALT, alt_l) - X(DVK_SPACE, space) + X(shift_l, 1, 167-(1*17)), + X(z, 43+(0*17), 167-(1*17)), + X(x, 43+(1*17), 167-(1*17)), + X(c, 43+(2*17), 167-(1*17)), + X(v, 43+(3*17), 167-(1*17)), + X(b, 43+(4*17), 167-(1*17)), + X(n, 43+(5*17), 167-(1*17)), + X(m, 43+(6*17), 167-(1*17)), + X(comma, 43+(7*17), 167-(1*17)), + X(period, 43+(8*17), 167-(1*17)), + X(slash, 43+(9*17), 167-(1*17)), + X(shift_r, 44+(10*17), 167-(1*17)), - X(DVK_UP, up) - X(DVK_LEFT, left) - X(DVK_DOWN, down) - X(DVK_RIGHT, right) + X(caps_lock, 1, 167-(0*17)), + X(alt_l, 47, 167-(0*17)), + X(space, 73, 167-(0*17)), + X(alt_r, 192, 167-(0*17)), + X(control_r, 231, 167-(0*17)), - { 0, 0, false }, + { 0, 0, 0, 0 } }; -#undef C -#undef X diff --git a/nds/img/bg.grit b/nds/img/bg.grit new file mode 100644 index 0000000..617dce0 --- /dev/null +++ b/nds/img/bg.grit @@ -0,0 +1,17 @@ +# graphics in tile format +-gt + +# tile reduction by tiles, palette and hflip/vflip +-mRtf + +# graphics bit depth is 4 (16 color) +-gB4 + +# include palette data +-p + +# map layout standard bg format +-mLs + +# use lz77 compression +-gzl -mzl diff --git a/nds/img/bg.png b/nds/img/bg.png new file mode 100644 index 0000000000000000000000000000000000000000..3ef09fd355f697a8a2fc0b86f638a6c9c21c7b7b GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0y~yU<5K54zMr-Ny)}w#*I3d4s4p2~}#5JPCv9u&3zlb5oGuTf3JH4eVVxu#@pc3Smi%>gbT`f$5_!rL~kx!un--*0{rzAbwB zlvk04r>_VoI5aRYGO=(FU^HX}zWVq1ss&R}?23eW_Z@7Sey#3!`k2w>V7cJ=-=L6! z0|Tb3-S-dN+ZC?=&$asdyj8i`cPIKkYWi&X%{lw}ME|7yF-iY(WvxGXzPXFVdQ I&MBb@0PAR?3jhEB literal 0 HcmV?d00001 diff --git a/nds/img/keys.grit b/nds/img/keys.grit new file mode 100644 index 0000000..6745630 --- /dev/null +++ b/nds/img/keys.grit @@ -0,0 +1,14 @@ +# exclude map data +-m! + +# graphics bit depth is 4 (16 color) +-gB4 + +# exclude palette data +-p! + +# metatile is 2x2 tiles (16x16 pixels) +-Mw2 -Mh2 + +# use lz77 compression +-gzl diff --git a/nds/img/keys.png b/nds/img/keys.png new file mode 100644 index 0000000000000000000000000000000000000000..c677cfc7967a37bfe410190cb79353d3a0165c72 GIT binary patch literal 1719 zcmV;o21xmdP)EaE4d6q8TYA+wp(q92UYpD21?NvtCwMujf(A4(-hu0dk(hZbVQr7vh*M68L)T&ml zU#*)<015$A9Z$>?*0HX!p9-}bMk&<3tn0>>Ev}9M8Uj$b1r1ohfi|Eul$AoQV_joC z_jAv=VH|)T&X?`@DzgP@1!zue0k4ouovfI*hRPaE4;DzbAOX-;RviJXrp`~q_34(? zCjgpg<+v3Y3#e1hmG}bdrp`H`9R?=WN_!t@v<@vm&Y1eZ!{7Hyui^jxBm{YXmL`Cw zNkMTrl)sB2sy|mg*Dq}^GVPoXqyTSMme2J|+lx#)IbkS&`hl)1f1K%;wgW)Yeg(ik zSaxUoV*vcwcoN{Re+fW83c!ag|HJ>IfplU4?S&@_5)K=F-T4{=C<4&%t6l-P1^|?g z9?I7>4FjmUiC30bpy3s|aGU_B6+q$MDF#?;C?8M`$^Njx#6=7O@KMFCFYg0B9nb_| zJB9!{1c1yU1fZH=3t$vavI4kXcHP0izAIV4ZJUpBI<f5^b)rIw96vJ_l4%4lMBN4x$r2@Em|g97GxM16@~sKi4m5e=joaS%5#1j+e@p z>N)mj+BrVIyxuHs+~Osvpze?HvqAZ0GvSr3&?5q z6U${Dy&eXz09=#r0^p`P_5lVM0BD9SC`U8h+X8Yp2XGjt&;n&QjCb|{J4c%VC|dv+ zpiDj>7qq~`-U0+D_e1NoF>Uk~$l?2)1HUH##^v43@&W*>yawf$OPb^J?Et$J;3X-a zfB4$C{V08P+wU1!0hGAHvZV*0T#Yj(5G4S# zCIX-{UKm{Aujhw+)Vz)Va07K~@#f(rLuEa;3w2|1rJQv^^A2#yQ! z`N0k6z+xreZr{gi#_75*b`U)q;L5oDC|&HHEL%RXy#?+TJHwrg<2mZGi-Qrhul?Xe zle3AQ=aUb|UBi7F0oc1DT0rLF^bT(O!O@wvQ{F&#KB{K`K|lz6I0b+o5F~|F)JFhV zFEPqd{AU1)egnmp5%UUso&eU{G6Gcb7YvT$BkdJ`Sil5jiTh*TQ1x>kh4GRAI*|id zoiGLHG5#N000!>j1cWRQXF36Z>9bpK8URzN6o4n3XrjaiI3>e=2L$NNc?(e77Hmq9 zeG6!U68lLrL;zx$BT!217>MRM+JfZ$q~!F|?{ya^EG}Em_Y+$_u;l}f%m<3k%H8Ap zrvdKmRKFnr-{a{T&G&o^uj3+e*KZ29POZ<~WC1zl<9!_8xqgvLbT{OD!r%2i55U*% zk%CK?1SgDs_>ET@_}a}YCriLzKyI)A-hKstKq%XMet_|Q7)xCLOwFgcGR zzE;Qaof8iH0C8jifBnA23Ds2UF()cVAi{(h4_i=9 zzxW*JzRN-MY=C>m_ZtE37vDG8WRp!c*<_PVHrZs8O*YwNlTAJ;{{f-wx*SkmG~fUL N002ovPDHLkV1g9;0PO$( literal 0 HcmV?d00001 From c2152e075391e7daf1fb5b9215dad8033234e5a9 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Tue, 30 Jan 2024 21:56:22 +0000 Subject: [PATCH 3/8] Add DS builds to GitHub Actions --- .github/workflows/ci.yml | 14 ++++++++++++++ Makefile | 4 ++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2e6e18c..82075ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,3 +132,17 @@ jobs: with: name: arcem-${{ matrix.amiga.host }} path: ./arcem + + build-nds: + name: Nintendo DS + runs-on: ubuntu-latest + container: devkitpro/devkitarm:20241104 + + steps: + - uses: actions/checkout@v3 + - name: Build + run: make SYSTEM=nds + - uses: actions/upload-artifact@v3 + with: + name: arcem-nds + path: ./ArcEm.nds diff --git a/Makefile b/Makefile index af78428..ed826f0 100644 --- a/Makefile +++ b/Makefile @@ -181,8 +181,8 @@ riscpkg: $(TARGET) endif ifeq (${SYSTEM},nds) -CC=arm-none-eabi-gcc -AS=arm-none-eabi-as +CC=$(DEVKITARM)/bin/arm-none-eabi-gcc +AS=$(DEVKITARM)/bin/arm-none-eabi-as LD=$(CC) ARM9_ARCH = -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s CFLAGS += $(ARM9_ARCH) -ffunction-sections -fdata-sections -DSYSTEM_nds -DARM9 -DUSE_FAKEMAIN -DNO_OPEN64 -isystem $(DEVKITPRO)/libnds/include -Wno-cast-align -Wno-format From b24325b9f293dcbaf5a6ff8547cca1dc452eb225 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sun, 14 Apr 2024 13:38:39 +0100 Subject: [PATCH 4/8] Reduce executable size for DS when extnrom support is disabled --- Makefile | 9 ++++++++- nds/main.c | 10 ++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ed826f0..1161f17 100644 --- a/Makefile +++ b/Makefile @@ -187,7 +187,10 @@ LD=$(CC) ARM9_ARCH = -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s CFLAGS += $(ARM9_ARCH) -ffunction-sections -fdata-sections -DSYSTEM_nds -DARM9 -DUSE_FAKEMAIN -DNO_OPEN64 -isystem $(DEVKITPRO)/libnds/include -Wno-cast-align -Wno-format LDFLAGS += -specs=ds_arm9.specs -g $(ARM9_ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libnds/lib -LIBS += -lfilesystem -lfat -lnds9 +ifeq (${EXTNROM_SUPPORT},yes) +LIBS += -lfilesystem +endif +LIBS += -lfat -lnds9 OBJS += nds/main.o nds/img/bg.o nds/img/keys.o ifneq ($(DEBUG),yes) CFLAGS += -DNDEBUG @@ -197,9 +200,13 @@ TARGET = ArcEm.elf all: ArcEm.nds %.nds: %.elf %.arm7.elf nds/arc.bmp +ifeq (${EXTNROM_SUPPORT},yes) mkdir -p romfs/extnrom cp support_modules/*/*,ffa romfs/extnrom ndstool -c $@ -9 $< -7 $*.arm7.elf -b nds/arc.bmp "ArcEm;Archimedes Emulator;WIP" -d romfs +else + ndstool -c $@ -9 $< -7 $*.arm7.elf -b nds/arc.bmp "ArcEm;Archimedes Emulator;WIP" +endif %.s %.h: %.png %.grit grit $< -fts -o$* diff --git a/nds/main.c b/nds/main.c index 09f81b2..1eb4d1b 100644 --- a/nds/main.c +++ b/nds/main.c @@ -5,16 +5,26 @@ #include "../arch/ControlPane.h" #include +#if defined(EXTNROM_SUPPORT) #include +#else +#include +#endif static ArcemConfig hArcemConfig; int main(int argc,char *argv[]) { Prof_Init(); +#if defined(EXTNROM_SUPPORT) if (!nitroFSInit(NULL)) { ControlPane_Error(EXIT_FAILURE, "Failed to initialise filesystem"); } +#else + if (!fatInitDefault()) { + ControlPane_Error(EXIT_FAILURE, "Failed to initialise filesystem"); + } +#endif // Setup the default values for the config system ArcemConfig_SetupDefaults(&hArcemConfig); From 25f8f4949ccd2413c84bb3f211c25280f0aaa51d Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sun, 14 Apr 2024 14:31:34 +0100 Subject: [PATCH 5/8] Speed up 32-bit aligned display transfers with the DS port --- arch/paldisplaydev.c | 109 +++++++++++++++++++++++++++++++++++++++++-- nds/DispKbd.c | 7 +++ 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/arch/paldisplaydev.c b/arch/paldisplaydev.c index 21bbcba..b80c67d 100644 --- a/arch/paldisplaydev.c +++ b/arch/paldisplaydev.c @@ -108,6 +108,12 @@ void PDD_Name(Host_EndUpdate)(ARMul_State *state,PDD_Row *row) - End updating the region of the row + ARMword *PDD_Name(Host_TransferUpdate)(ARMul_State *state,PDD_Row *row, + unsigned int count,const ARMword *src) + - Write 'count' bits of the row to the screen. + - 'count' will always be a multiple of 32. + - This is only used in DS builds at the moment. + void PDD_Name(Host_AdvanceRow)(ARMul_State *state,PDD_Row *row, unsigned int count) - Advance the row pointer by 'count' bits @@ -211,7 +217,8 @@ struct PDD_Name(DisplayInfo) { #define ROWFUNC_FORCE 0x1 /* Force row to be fully redrawn */ #define ROWFUNC_UPDATED 0x2 /* Flag used to indicate whether anything was done */ -#define ROWFUNC_UNALIGNED 0x4 /* Flag that gets set if we know we can't use the byte-aligned rowfuncs */ +#define ROWFUNC_UNALIGNED_BYTE 0x4 /* Flag that gets set if we know we can't use the byte-aligned rowfuncs */ +#define ROWFUNC_UNALIGNED_WORD 0x8 /* Flag that gets set if we know we can't use the word-aligned rowfuncs */ /* @@ -303,6 +310,51 @@ static inline int PDD_Name(RowFunc1XSameByteAligned)(ARMul_State *state,PDD_Row return (flags & ROWFUNC_UPDATED); } +static inline int PDD_Name(RowFunc1XSameWordAligned)(ARMul_State *state,PDD_Row drow,int flags) +{ + uint32_t Vptr = DC.Vptr>>5; + uint32_t Vstart = MEMC.Vstart<<2; + uint32_t Vend = (MEMC.Vend+1)<<2; /* Point to pixel after end */ + const ARMword *RAM = MEMC.PhysRam; + int Remaining = DC.BitWidth>>5; + + /* Sanity checks to avoid looping forever */ + if((Vptr >= Vend) || (Vstart >= Vend)) + return 0; + if(Vptr >= Vend) + Vptr = Vstart; + + /* Process the row */ + while(Remaining > 0) + { + uint32_t FlagsOffset = Vptr/(UPDATEBLOCKSIZE/4); + int Available = MIN(Remaining,MIN(((FlagsOffset+1)*(UPDATEBLOCKSIZE/4))-Vptr,Vend-Vptr)); + + if((flags & ROWFUNC_FORCE) || (HD.UpdateFlags[FlagsOffset] != MEMC.UpdateFlags[FlagsOffset])) + { + /* Process the pixels in this region, stopping at end of row/update block/Vend */ +#ifndef SYSTEM_nds + int outoffset; + ARMword *out = PDD_Name(Host_BeginUpdate)(state,&drow,Available<<5,&outoffset); + EndianWordCpy(out+(outoffset>>5),RAM+Vptr,Available); + PDD_Name(Host_EndUpdate)(state,&drow); +#else + PDD_Name(Host_TransferUpdate)(state,&drow,Available<<5,RAM+Vptr); +#endif + flags |= ROWFUNC_UPDATED; + } + PDD_Name(Host_AdvanceRow)(state,&drow,Available<<5); + Vptr += Available; + Remaining -= Available; + if(Vptr >= Vend) + Vptr = Vstart; + } + + DC.Vptr = Vptr<<5; + + return (flags & ROWFUNC_UPDATED); +} + /* Row output via ExpandTable @@ -430,6 +482,45 @@ static inline void PDD_Name(RowFunc1XSameByteAlignedNoFlags)(ARMul_State *state, DC.Vptr = Vptr<<3; } +static inline void PDD_Name(RowFunc1XSameWordAlignedNoFlags)(ARMul_State *state,PDD_Row drow) +{ + uint32_t Vptr = DC.Vptr>>5; + uint32_t Vstart = MEMC.Vstart<<2; + uint32_t Vend = (MEMC.Vend+1)<<2; /* Point to pixel after end */ + const ARMword *RAM = MEMC.PhysRam; + int Remaining = DC.BitWidth>>5; + + /* Sanity checks to avoid looping forever */ + if((Vptr >= Vend) || (Vstart >= Vend)) + return; + if(Vptr >= Vend) + Vptr = Vstart; + + /* Process the row */ + while(Remaining > 0) + { + int Available = MIN(Remaining,Vend-Vptr); + + /* Process the pixels in this region, stopping at end of row/update block/Vend */ +#ifndef SYSTEM_nds + int outoffset; + ARMword *out = PDD_Name(Host_BeginUpdate)(state,&drow,Available<<5,&outoffset); + EndianWordCpy(out+(outoffset>>5),RAM+Vptr,Available); + PDD_Name(Host_EndUpdate)(state,&drow); +#else + PDD_Name(Host_TransferUpdate)(state,&drow,Available<<5,RAM+Vptr); +#endif + + PDD_Name(Host_AdvanceRow)(state,&drow,Available<<5); + Vptr += Available; + Remaining -= Available; + if(Vptr >= Vend) + Vptr = Vstart; + } + + DC.Vptr = Vptr<<5; +} + /* Row output via ExpandTable @@ -708,7 +799,9 @@ static void PDD_Name(EventFunc)(ARMul_State *state,CycleCount nowtime) /* We can test these values once here, so that it's only output alignment that we need to worry about during the loop */ if((DC.Vptr & 0x7) || ((Width*BPP)&0x7)) - flags |= ROWFUNC_UNALIGNED; + flags |= ROWFUNC_UNALIGNED_WORD | ROWFUNC_UNALIGNED_BYTE; + else if((DC.Vptr & 0x31) || ((Width*BPP)&0x31)) + flags |= ROWFUNC_UNALIGNED_WORD; if(DisplayDev_UseUpdateFlags) { @@ -732,7 +825,11 @@ static void PDD_Name(EventFunc)(ARMul_State *state,CycleCount nowtime) { updated = PDD_Name(RowFuncExpandTable)(state,hrow,flags); } - else if(!(flags & ROWFUNC_UNALIGNED) && !(alignment & 0x7)) + else if(!(flags & ROWFUNC_UNALIGNED_WORD) && !(alignment & 0x31)) + { + updated = PDD_Name(RowFunc1XSameWordAligned)(state,hrow,flags); + } + else if(!(flags & ROWFUNC_UNALIGNED_BYTE) && !(alignment & 0x7)) { updated = PDD_Name(RowFunc1XSameByteAligned)(state,hrow,flags); } @@ -783,7 +880,11 @@ static void PDD_Name(EventFunc)(ARMul_State *state,CycleCount nowtime) { PDD_Name(RowFuncExpandTableNoFlags)(state,hrow); } - else if(!(flags & ROWFUNC_UNALIGNED) && !(alignment & 0x7)) + else if(!(flags & ROWFUNC_UNALIGNED_WORD) && !(alignment & 0x31)) + { + PDD_Name(RowFunc1XSameWordAlignedNoFlags)(state,hrow); + } + else if(!(flags & ROWFUNC_UNALIGNED_BYTE) && !(alignment & 0x7)) { PDD_Name(RowFunc1XSameByteAlignedNoFlags)(state,hrow); } diff --git a/nds/DispKbd.c b/nds/DispKbd.c index 8375299..2e2dc2a 100644 --- a/nds/DispKbd.c +++ b/nds/DispKbd.c @@ -121,6 +121,13 @@ static inline void PDD_Name(Host_EndUpdate)(ARMul_State *state,PDD_Row *row) row->src += count>>5; } +static inline void PDD_Name(Host_TransferUpdate)(ARMul_State *state,PDD_Row *row,unsigned int count,const ARMword *src) +{ + DC_FlushRange(src, count>>3); + while (dmaBusy(3)); + dmaCopyWordsAsynch(3, src, row->dst, count>>3); +} + static inline void PDD_Name(Host_AdvanceRow)(ARMul_State *state,PDD_Row *row,unsigned int count) { row->dst += count>>3; From 278761c77a5c50008cd9707dc7e306e567e5c51f Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Sat, 11 May 2024 18:20:23 +0100 Subject: [PATCH 6/8] Implement message boxes for the DS port --- Makefile | 4 +- nds/ControlPane.c | 437 ++++++++++++++++++++++++++++++++++++++++++---- nds/img/bg.grit | 3 + nds/img/font.grit | 14 ++ nds/img/font.png | Bin 0 -> 1743 bytes 5 files changed, 423 insertions(+), 35 deletions(-) create mode 100644 nds/img/font.grit create mode 100644 nds/img/font.png diff --git a/Makefile b/Makefile index 1161f17..ba5cc00 100644 --- a/Makefile +++ b/Makefile @@ -191,7 +191,7 @@ ifeq (${EXTNROM_SUPPORT},yes) LIBS += -lfilesystem endif LIBS += -lfat -lnds9 -OBJS += nds/main.o nds/img/bg.o nds/img/keys.o +OBJS += nds/main.o nds/img/bg.o nds/img/keys.o nds/img/font.o ifneq ($(DEBUG),yes) CFLAGS += -DNDEBUG endif @@ -213,7 +213,7 @@ endif %.s %.h: %.bmp %.grit grit $< -fts -o$* -nds/ControlPane.o: nds/KeyTable.h nds/img/bg.h nds/img/keys.h +nds/ControlPane.o: nds/KeyTable.h nds/img/bg.h nds/img/font.h nds/img/keys.h ARM7_ARCH = -mthumb -mthumb-interwork -march=armv4t -mtune=arm7tdmi ARM7_CFLAGS = $(ARM7_ARCH) -Os -ffunction-sections -fdata-sections -DARM7 -isystem $(DEVKITPRO)/libnds/include diff --git a/nds/ControlPane.c b/nds/ControlPane.c index 088375c..2b42b97 100644 --- a/nds/ControlPane.c +++ b/nds/ControlPane.c @@ -11,6 +11,7 @@ #include "KeyTable.h" #include "img/bg.h" +#include "img/font.h" #include "img/keys.h" #include @@ -20,9 +21,47 @@ enum { DRAG_NONE, - DRAG_MOUSE + DRAG_MOUSE, + DRAG_WINDOW_1, + DRAG_WINDOW_2, + DRAG_WINDOW_3 }; +enum { + SIDEL = 1, + SIDER = 1 | TILE_FLIP_H, + SIDET = 2, + SIDEB = 2 | TILE_FLIP_V, + BARV = 3, + BARH = 4, + CORNERTL = 5, + CORNERTR = 5 | TILE_FLIP_H, + CORNERBL = 5 | TILE_FLIP_V, + CORNERBR = 5 | TILE_FLIP_H | TILE_FLIP_V, + PIPET = 7, + PIPEB = 7 | TILE_FLIP_V, + PIPEL = 8, + PIPER = 8 | TILE_FLIP_H, + PIPEIT = 9, + PIPEIB = 9 | TILE_FLIP_V, + PIPEIL = 10, + PIPEIR = 10 | TILE_FLIP_H, + PIPEC = 11, + + CLOSE = 0x84, + DOWN = 0x8a, + UP = 0x8b, + ELLIPSIS = 0x8c +}; + +typedef struct { + int px, py, pw, ph; + int bx, by, bw, bh; + int closex; + int layer; + u16 *map; +} Window; + static int old_px = -1; static int old_py = -1; static int drag_mode = DRAG_NONE; @@ -32,8 +71,14 @@ static arch_key_id key_pressed = -1; static bool has_console = false; static bool has_keyboard = false; +static bool has_windows = false; + +static Window windows[3]; static void ControlPane_InitKeyboard(ARMul_State *state); +static void ControlPane_InitWindows(void); + +static Window *ControlPane_MessageBox(int layer, const char *title, const char *message); static void draw_floppy_leds(unsigned int leds) { @@ -58,7 +103,12 @@ static void draw_floppy(unsigned int floppy, bool inserted) { void ControlPane_Init(ARMul_State *state) { - videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE); + static bool init = false; + if (init) + return; + init = true; + + videoSetModeSub(MODE_0_2D | DISPLAY_BG3_ACTIVE); vramSetBankH(VRAM_H_SUB_BG); vramSetBankI(VRAM_I_SUB_SPRITE); oamInit(&oamSub, SpriteMapping_1D_128, false); @@ -68,42 +118,62 @@ void ControlPane_Init(ARMul_State *state) int held = keysHeld(); if (held & KEY_SELECT) { - consoleInit(NULL, 1, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); + consoleInit(NULL, 3, BgType_Text4bpp, BgSize_T_256x256, 15, 0, false, true); has_console = true; } #endif if (!has_console) { - BGCTRL_SUB[0] = BG_TILE_BASE(1) | BG_MAP_BASE(0) | BG_COLOR_16 | BG_32x32; + BGCTRL_SUB[3] = BG_TILE_BASE(0) | BG_MAP_BASE(5) | BG_COLOR_16 | BG_32x32; - decompress(bgTiles, (void *)CHAR_BASE_BLOCK_SUB(1), LZ77Vram); - decompress(bgMap, (void *)SCREEN_BASE_BLOCK_SUB(0), LZ77Vram); + decompress(bgTiles, (void*)(CHAR_BASE_BLOCK_SUB(0) + (0x100 * 32)), LZ77Vram); + decompress(bgMap, (void *)SCREEN_BASE_BLOCK_SUB(5), LZ77Vram); dmaCopy(bgPal, BG_PALETTE_SUB, bgPalLen); + ControlPane_InitWindows(); ControlPane_InitKeyboard(state); - FDC_SetLEDsChangeFunc(draw_floppy_leds); + if (state) + FDC_SetLEDsChangeFunc(draw_floppy_leds); ControlPane_Redraw(); } } void ControlPane_Error(int code,const char *fmt,...) { + char msg[256]; + Window *w; va_list args; va_start(args,fmt); - if (!has_console) - consoleDemoInit(); + ControlPane_Init(NULL); - /* Log it */ - vprintf(fmt,args); +#ifndef NDEBUG + if (has_console) { + /* Log it */ + vprintf(fmt,args); + va_end(args); + + while(1) { + swiWaitForVBlank(); + scanKeys(); + if (keysDown() & KEY_START) + break; + } - while(1) { + /* Quit */ + exit(code); + } +#endif + + vsnprintf(msg, 256, fmt, args); + va_end(args); + + w = ControlPane_MessageBox(0, "Error", msg); + while (w->layer >= 0) { swiWaitForVBlank(); - scanKeys(); - if (keysDown() & KEY_START) - break; + Kbd_PollHostKbd(NULL); } /* Quit */ @@ -112,6 +182,283 @@ void ControlPane_Error(int code,const char *fmt,...) /*----------------------------------------------------------------------------*/ +static void ControlPane_TextDrawChar(Window *window, u16 c, int x, int y) +{ + x += window->bx; + y += window->by; + window->map[x + y * 32] = (1 << 12) | c; +} + +static void ControlPane_TextDrawString(Window *window, const char *c, int x, int y, int w, bool centred) +{ + u16 *ptr, *last; + size_t len = strlen(c); + + x += window->bx; + y += window->by; + + ptr = window->map + (y * 32) + x; + last = ptr + w - 1; + + if (len < w && centred) + ptr += (w - len) / 2; + + while (*c) { + if (ptr == last && c[1] != 0) { + *ptr++ = (1 << 12) | ELLIPSIS; + break; + } + + *ptr++ = (1 << 12) | *c++; + } +} + +static void ControlPane_TextDrawBlock(Window *window, const u16 *c, int x, int y, int w, int h) +{ + int i, j; + x += window->bx; + y += window->by; + + for (i = y; i < y + h; i++) { + for (j = x; j < x + w; j++) { + window->map[(i * 32) + j] = (1 << 12) | *c++; + } + } +} + +static void ControlPane_TextDrawLineH(Window *window, u16 c, int x, int y, int w) +{ + int i; + x += window->bx; + y += window->by; + + for (i = x; i < x + w; i++) { + window->map[(y * 32) + i] = (1 << 12) | c; + } +} + +static void ControlPane_TextDrawLineV(Window *window, u16 c, int x, int y, int h) +{ + int i; + x += window->bx; + y += window->by; + + for (i = y; i < y + h; i++) { + window->map[(i * 32) + x] = (1 << 12) | c; + } +} + +static Window *ControlPane_CreateWindow(int layer, int w, int h, const char *title, bool scroll) +{ + static const u16 TL[1*3] = { + CORNERTL, + SIDEL, + PIPEL + }; + static const u16 BL[1*1] = { + CORNERBL + }; + static const u16 TR[3*3] = { + PIPET, SIDET, CORNERTR, + BARV, CLOSE, SIDER, + PIPEIB, BARH, PIPER + }; + static const u16 BR[1*1] = { + CORNERBR + }; + static const u16 TR_S[3*5] = { + PIPET, SIDET, CORNERTR, + BARV, CLOSE, SIDER, + PIPEC, BARH, PIPER, + + BARV, UP, SIDER, + PIPEIL, BARH, PIPER + }; + static const u16 BR_S[3*3] = { + PIPEIL, BARH, PIPER, + BARV, DOWN, SIDER, + PIPEB, SIDEB, CORNERBR + }; + vu16 *scrollXY = REG_BGOFFSETS_SUB + (layer * 2); + Window *window; + int i, mapbase; + + mapbase = 6 + (layer * 4); + BGCTRL_SUB[layer] = BG_TILE_BASE(0) | BG_MAP_BASE(mapbase) | BG_COLOR_16 | BG_64x64; + window = &windows[layer]; + window->map = (u16 *)SCREEN_BASE_BLOCK_SUB(mapbase); + window->layer = layer; + window->pw = (w + (scroll ? 4 : 2)) * 8; + window->ph = (h + 4) * 8; + window->px = (256 - window->pw) / 2; + window->py = (192 - window->ph) / 2; + window->bx = 1; + window->by = 3; + window->bw = w; + window->bh = h; + + dmaFillHalfWords(1<<12, window->map, 32*32*2); + + /* Left hand side */ + ControlPane_TextDrawBlock(window, TL, -1, -3, 1, 3); + ControlPane_TextDrawLineV(window, SIDEL, -1, 0, h); + ControlPane_TextDrawBlock(window, BL, -1, h, 1, 1); + + /* Middle */ + ControlPane_TextDrawLineH(window, SIDET, 0, -3, w); + ControlPane_TextDrawLineH(window, ' ', 0, -2, w); + ControlPane_TextDrawLineH(window, BARH, 0, -1, w); + for (i = 0; i < h; i++) + ControlPane_TextDrawLineH(window, ' ', 0, i, w); + ControlPane_TextDrawLineH(window, SIDEB, 0, h, w); + + + if (scroll) { + /* Title */ + ControlPane_TextDrawString(window, title, 0, -2, w, true); + + /* Right hand side */ + ControlPane_TextDrawBlock(window, TR_S, w + 0, -3, 3, 5); + ControlPane_TextDrawLineV(window, BARV, w + 0, 2, h - 3); + ControlPane_TextDrawLineV(window, ' ', w + 1, 2, h - 3); + ControlPane_TextDrawLineV(window, SIDER, w + 2, 2, h - 3); + ControlPane_TextDrawBlock(window, BR_S, w + 0, h - 2, 3, 3); + + window->closex = 1 + w; + } else { + /* Title */ + ControlPane_TextDrawString(window, title, 0, -2, w - 2, true); + + /* Right hand side */ + ControlPane_TextDrawBlock(window, TR, w - 2, -3, 3, 3); + ControlPane_TextDrawLineV(window, SIDER, w, 0, h); + ControlPane_TextDrawBlock(window, BR, w, h, 1, 1); + + window->closex = 1 + w - 2; + } + + scrollXY[0] = 512 - window->px; + scrollXY[1] = 512 - window->py; + + videoBgEnableSub(window->layer); + + return window; +} + +static void ControlPane_CloseWindow(Window *window) +{ + videoBgDisableSub(window->layer); + memset(window, 0, sizeof(Window)); + window->layer = -1; +} + +static void ControlPane_InitWindows(void) +{ + int i; + + decompress(fontTiles, (void *)CHAR_BASE_BLOCK_SUB(0), LZ77Vram); + dmaCopy(fontPal, BG_PALETTE_SUB + 16, fontPalLen); + + for (i = 0; i < sizeof(windows)/sizeof(*windows); i++) { + ControlPane_CloseWindow(&windows[i]); + } + + has_windows = true; +} + +static bool ControlPane_ClickWindow(ARMul_State *state, int px, int py) +{ + Window *w; + int i; + + for (i = 0; i < sizeof(windows)/sizeof(*windows); i++) { + w = &windows[i]; + /* Is the window open? */ + if (w->layer < 0) + continue; + + /* Are the co-ordinates within the window? */ + if (!(px >= w->px && px < w->px + w->pw && py >= w->py && py < w->py + w->ph)) + continue; + + /* Handle clicking on the title bar */ + if (py < w->py + (8 * w->by)) { + if (px > w->px + (8 * w->closex)) { + ControlPane_CloseWindow(w); + } else { + drag_mode = DRAG_WINDOW_1 + i; + old_px = px; + old_py = py; + } + } + + return true; + } + return false; +} + +static bool ControlPane_DragWindow(ARMul_State *state, int px, int py) +{ + int newMouseX, newMouseY, xdiff, ydiff; + Window *w = &windows[drag_mode - DRAG_WINDOW_1]; + vu16 *scrollXY = REG_BGOFFSETS_SUB + (w->layer * 2); + + xdiff = (px - old_px); + ydiff = (py - old_py); + + w->px += xdiff; + w->py += ydiff; + scrollXY[0] = 512 - w->px; + scrollXY[1] = 512 - w->py; + + old_px = px; + old_py = py; + return true; +} + +/*----------------------------------------------------------------------------*/ + +static Window *ControlPane_MessageBox(int layer, const char *title, const char *message) +{ + char line[17], *msg, *token, *saveptr; + size_t linepos = 0, toklen; + Window *w; + int y = 0; + + w = ControlPane_CreateWindow(layer, 16, 6, title, false); + + msg = strdup(message); + memset(line, 0, sizeof(line)); + + token = strtok_r(msg, " ", &saveptr); + while (token != NULL) { + toklen = strlen(token); + if (linepos + toklen + 1 > 16) { + ControlPane_TextDrawString(w, line, 0, y, 16, true); + memset(line, 0, sizeof(line)); + linepos = 0; + y++; + } + + if (linepos > 0) { + strcat(line, " "); + linepos += toklen; + } + + strcat(line, token); + linepos += toklen + 1; + token = strtok_r(NULL, " ", &saveptr); + } + + if (linepos > 0) + ControlPane_TextDrawString(w, line, 0, y, 16, true); + free(msg); + + return w; +} + +/*----------------------------------------------------------------------------*/ + static void ControlPane_UpdateKeyboardLEDs(uint8_t leds); static void ControlPane_InitKeyboard(ARMul_State *state) @@ -148,7 +495,8 @@ static void ControlPane_InitKeyboard(ARMul_State *state) decompress(keysTiles, SPRITE_GFX_SUB, LZ77Vram); dmaCopy(keysPal, SPRITE_PALETTE_SUB, sizeof(keysPal)); - KBD.leds_changed = ControlPane_UpdateKeyboardLEDs; + if (state) + KBD.leds_changed = ControlPane_UpdateKeyboardLEDs; has_keyboard = true; } @@ -161,6 +509,10 @@ static void ControlPane_UpdateKeyboardLEDs(uint8_t leds) static bool ControlPane_ClickKeyboard(ARMul_State *state, int px, int py) { const dvk_to_vkeybd *ktvk; + + if (!state) + return false; + for (ktvk = dvk_to_vkeybd_map; ktvk->sprite; ktvk++) { uint width = ((ktvk->sprite) >> 8) * 16; uint height = 16; @@ -178,7 +530,8 @@ static bool ControlPane_ClickKeyboard(ARMul_State *state, int px, int py) static void ControlPane_ReleaseKeyboard(ARMul_State *state) { if (key_pressed != -1) { - keyboard_key_changed(&KBD, key_pressed, 1); + if (state) + keyboard_key_changed(&KBD, key_pressed, 1); key_pressed = -1; } } @@ -198,7 +551,7 @@ static void ControlPane_DrawKeyboard(void) if (ktvk->kid == key_pressed) palette |= 4; do { - oamSet(&oamSub, i++, x, y, 0, palette, SpriteSize_16x16, SpriteColorFormat_16Color, + oamSet(&oamSub, i++, x, y, 3, palette, SpriteSize_16x16, SpriteColorFormat_16Color, &SPRITE_GFX_SUB[sprite++ * 64], -1, false, false, false, false, false); x += 16; } while (--width); @@ -207,35 +560,44 @@ static void ControlPane_DrawKeyboard(void) /*----------------------------------------------------------------------------*/ -static void ControlPane_ClickFloppy(ARMul_State *state, int drive) +static bool ControlPane_ClickFloppy(ARMul_State *state, int drive) { const char *err; char tmp[256]; + if (!state) + return false; + if (FDC_IsFloppyInserted(drive)) { err = FDC_EjectFloppy(drive); if (err == NULL) draw_floppy(drive, false); - /* TODO: Report warning if this fails */ + else + ControlPane_MessageBox(1, "Error", err); } else { sprintf(tmp, "FloppyImage%d", drive); err = FDC_InsertFloppy(drive, tmp); if (err == NULL) draw_floppy(drive, true); - /* TODO: Report warning if this fails */ + else + ControlPane_MessageBox(1, "Error", err); } + return true; } /*----------------------------------------------------------------------------*/ -static void ControlPane_ClickTouchpad(ARMul_State *state, int px, int py) +static bool ControlPane_ClickTouchpad(ARMul_State *state, int px, int py) { + if (!state) + return false; drag_mode = DRAG_MOUSE; old_px = px; old_py = py; + return true; } -static void ControlPane_DragTouchpad(ARMul_State *state, int px, int py) +static bool ControlPane_DragTouchpad(ARMul_State *state, int px, int py) { int newMouseX, newMouseY, xdiff, ydiff; @@ -255,24 +617,29 @@ static void ControlPane_DragTouchpad(ARMul_State *state, int px, int py) old_px += xdiff >> 2; old_py += ydiff >> 2; - KBD.MouseXCount = xdiff & 127; - KBD.MouseYCount = -ydiff & 127; + if (state) { + KBD.MouseXCount = xdiff & 127; + KBD.MouseYCount = -ydiff & 127; + } + return true; } /*----------------------------------------------------------------------------*/ bool ControlPane_ProcessTouchPressed(ARMul_State *state, int px, int py) { + if (has_windows && ControlPane_ClickWindow(state, px, py)) + return true; if (has_keyboard && ControlPane_ClickKeyboard(state, px, py)) return true; - if (py > 183 || has_console) { + if (has_console) { + return ControlPane_ClickTouchpad(state, px, py); + } else if (py > 183) { int drive = 3 - (px / 64); - ControlPane_ClickFloppy(state, drive); - return true; + return ControlPane_ClickFloppy(state, drive); } else if (py < 78) { - ControlPane_ClickTouchpad(state, px, py); - return true; + return ControlPane_ClickTouchpad(state, px, py); } return false; @@ -280,9 +647,13 @@ bool ControlPane_ProcessTouchPressed(ARMul_State *state, int px, int py) bool ControlPane_ProcessTouchHeld(ARMul_State *state, int px, int py) { - if (drag_mode == DRAG_MOUSE) { - ControlPane_DragTouchpad(state, px, py); - return true; + switch (drag_mode) { + case DRAG_MOUSE: + return ControlPane_DragTouchpad(state, px, py); + case DRAG_WINDOW_1: + case DRAG_WINDOW_2: + case DRAG_WINDOW_3: + return ControlPane_DragWindow(state, px, py); } return false; diff --git a/nds/img/bg.grit b/nds/img/bg.grit index 617dce0..6ed2268 100644 --- a/nds/img/bg.grit +++ b/nds/img/bg.grit @@ -13,5 +13,8 @@ # map layout standard bg format -mLs +# offset the bg tiles to fit alongside the font tiles +-ma256 + # use lz77 compression -gzl -mzl diff --git a/nds/img/font.grit b/nds/img/font.grit new file mode 100644 index 0000000..fa7eb42 --- /dev/null +++ b/nds/img/font.grit @@ -0,0 +1,14 @@ +# graphics in tile format +-gt + +# exclude map data +-m! + +# graphics bit depth is 4 (16 color) +-gB4 + +# include palette data +-p + +# use lz77 compression +-gzl diff --git a/nds/img/font.png b/nds/img/font.png new file mode 100644 index 0000000000000000000000000000000000000000..75b9988aeb7ddde2b178be05696cc0efd22a2639 GIT binary patch literal 1743 zcmV;=1~B=FP)^Bt5sQL0-wbd|55K#?<<=zjwscRuC_OAg6-=>+5XK2Q!Z`RE z;JrQLV>~+s9S7>Se~zQw3xIwF{cnIjp91*n>&M?5V2EZSwwG~DWY_Xc&IRD(*Z&c~ z#T+WU#B2HbQiVqViV^Px80xSaAsw&BF>c;-Zl8Yq_y(^GiGKk6JH)!@%mDq@FYNE$ z;qN~`e;9_j=PUrPuLAJ-=ZE2%d(Q3C_wOOWLjYgCJgLF}I1Ko(5#a!M%8eF49SML& zjF7~WMLiJzJ3Cf@Bf>h450wb?QI3uUp!1JqRtMnO`5CSN6cWgHmOx%4yQhChK>+;B zxsm~f1OUg>JUR6Yu$6$!27aTnJG*`|l`VGYg14%`*FzN~pN5LvYU;zi2hDCIv$hy2 z^wqQ9pAh)f!wak{+eh{8&?DDXr8gv)RPcB@0MG$)#Gl(h?)$T_L9%r90!j>o7tpVZ7vRaG^(799OqzEv#{1c|HTwvswGZ>muk_FKe6|xZ*0ON$jw-rGAibf;_VAKhU3S}&{ z0U(%dAO@9yh0Hlqk!+%unJm$m{3rlsFO=&1;K8l1kwhU&DU|Uo6Dr|ED5(S%fCYGQ zKvE$^qDPtVp}JSfeGqWCy&3lMp|z-3)6u<)u@0s1on;@a0AxT|0oM5;RM<%{1B9-V z4WPz{2iVPgkji?et2XbA;!z%UFU(y6=^lW@_rnehpt?&oI=$~1sQ?Uh{R8S?YC(yNKxE4+ToFqZ=p{JIHQhcVa#9M>}K)1%j$_EnU zj6qZAg7tifr962fkg&7nqtWj$*tKVphtdA`K3#d0zf=qPeTB3KK+SA}9-Q?J1KH3FlVFmq(yUNzrOq zYN!1JS+zU!ShRuUHz#yjfR2!u0l-g5jHtlPKGKr> zb0T)FJ-lI+8cmv7a9yp}Jtj)Yg2s1y3Ci4S2v~$^AW`oBQaXEklQ!dYTO@yPm7)lC z>qu|3wsqmOta;yrd7N&6%tK24W;1UB+-!kt79MHLh;2rU(&epvZ4VcKi@B|hxf+*z za8rN4>maKBjSiJP(wA5O(oHY!($W@iiU;eQ&tk#Ldzxu87_4kc&db6UE5Oa#t#kRe#l{)H=Du%K$wm~^&8Y2yXS2^@HlSD!F5%3(%NyHx{e5yDi7xqI?wxMsgSiG? z@xf&}2O~{mZFRR<&-&~=lgc0=OMoYXwv2RpI@4x*bi)T%5?t8F$Mbw({y*h|T`WLs z;5J|SZ{opPq%%H9E0){an}rYj{}MKXWQlM|`wcD#L%a0zdSR4y&PWLRX!LF4kl-xt lG4_^XKrrNEd=MLx@E>ERA1tt;8At#C002ovPDHLkV1j^MFg5@H literal 0 HcmV?d00001 From 064524cce84be5ca34c65dd58ef2633230c8770d Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Thu, 26 Dec 2024 20:21:07 +0000 Subject: [PATCH 7/8] Switch to CMake for the DS port The custom ARM7 binary has also been removed. --- .github/workflows/ci.yml | 6 ++- CMakeLists.txt | 45 ++++++++++++++++++- Makefile | 47 ------------------- nds/ControlPane.c | 25 ++++++----- nds/arm7/main.c | 97 ---------------------------------------- nds/img/keys.grit | 4 +- 6 files changed, 63 insertions(+), 161 deletions(-) delete mode 100644 nds/arm7/main.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 82075ba..1d07050 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,9 +140,11 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Configure + run: $DEVKITPRO/portlibs/nds/bin/arm-none-eabi-cmake -B build/ -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} . - name: Build - run: make SYSTEM=nds + run: cmake --build build/ --config ${{env.BUILD_TYPE}} --parallel - uses: actions/upload-artifact@v3 with: name: arcem-nds - path: ./ArcEm.nds + path: ./build/ArcEm.nds diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e9132a..bd81ffd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,15 @@ set(ARCEM_X_SOURCES X/pseudo.c X/true.c ) +set(ARCEM_NDS_SOURCES + nds/ControlPane.c + nds/ControlPane.h + nds/DispKbd.c + nds/filecalls.c + nds/filecalls_internal.h + nds/KeyTable.h + nds/main.c +) set(ARCEM_VC_SOURCES vc/dirent.h ) @@ -83,16 +92,25 @@ set(ARCEM_WIN_SOURCES win/win.c win/win.h ) +set(ARCEM_EXTNROM_MODULES + support_modules/hostfs/hostfs,ffa + support_modules/hostfs/hostfsfiler,ffa + support_modules/modes/ArcemModes,ffa + support_modules/scrollwheel/scrollwheel,ffa + support_modules/support/support,ffa +) if(WIN32) set(DEFAULT_SYSTEM "win") +elseif(NINTENDO_DS) + set(DEFAULT_SYSTEM "nds") elseif(UNIX AND NOT APPLE AND NOT HAIKU) set(DEFAULT_SYSTEM "X") else() set(DEFAULT_SYSTEM "SDL2") endif() -set(SYSTEM ${DEFAULT_SYSTEM} CACHE STRING "System to compile for. Options: X SDL2 SDL1 win") -set_property(CACHE SYSTEM PROPERTY STRINGS X SDL2 SDL1 win) +set(SYSTEM ${DEFAULT_SYSTEM} CACHE STRING "System to compile for. Options: X SDL2 SDL1 nds win") +set_property(CACHE SYSTEM PROPERTY STRINGS X SDL2 SDL1 nds win) option(EXTNROM_SUPPORT "Build with Extension ROM support" ON) if(EXTNROM_SUPPORT) @@ -146,6 +164,19 @@ elseif(${SYSTEM} STREQUAL "X") find_package(Threads REQUIRED) target_link_libraries(Threads::Threads) endif() +elseif(${SYSTEM} STREQUAL "nds") + add_executable(arcem ${ARCEM_SOURCES} ${ARCEM_ARCH_SOURCES} ${ARCEM_INIH_SOURCES} ${ARCEM_NDS_SOURCES}) + target_include_directories(arcem PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/nds) + target_compile_definitions(arcem PRIVATE SYSTEM_nds USE_FAKEMAIN NO_OPEN64) + + target_compile_options(arcem PRIVATE -mthumb -mthumb-interwork) + target_link_options(arcem PRIVATE -Wl,--gc-sections -mthumb -mthumb-interwork) + + grit_add_binary_target(bg nds/img/bg.png) + grit_add_binary_target(font nds/img/font.png NO_MAP) + grit_add_binary_target(keys nds/img/keys.png NO_MAP) + dkp_add_embedded_binary_library(grit_data bg font keys) + target_link_libraries(arcem PRIVATE grit_data filesystem fat) elseif(${SYSTEM} STREQUAL "win") option(SOUND_SUPPORT "Build with sound support" ON) if(SOUND_SUPPORT) @@ -169,6 +200,15 @@ elseif(APPLE) OUTPUT_NAME "ArcEm" MACOSX_BUNDLE TRUE ) +elseif(NINTENDO_DS) + file(COPY ${ARCEM_EXTNROM_MODULES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/nitrofs/extnrom) + set_target_properties(arcem PROPERTIES OUTPUT_NAME "ArcEm") + nds_create_rom(arcem + SUBTITLE1 "Archimedes Emulator" + SUBTITLE2 "WIP" + ICON nds/arc.bmp + NITROFS ${CMAKE_CURRENT_BINARY_DIR}/nitrofs + ) endif() target_include_directories(arcem PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/arch) @@ -194,6 +234,7 @@ source_group(src FILES ${ARCEM_SOURCES}) source_group(src\\arch FILES ${ARCEM_ARCH_SOURCES}) source_group(src\\X FILES ${ARCEM_X_SOURCES}) source_group(src\\SDL FILES ${ARCEM_SDL_SOURCES}) +source_group(src\\nds FILES ${ARCEM_NDS_SOURCES}) source_group(src\\vc FILES ${ARCEM_VC_SOURCES}) source_group(src\\win FILES ${ARCEM_WIN_SOURCES}) source_group(libs\\inih FILES ${ARCEM_INIH_SOURCES}) diff --git a/Makefile b/Makefile index ba5cc00..ed2083f 100644 --- a/Makefile +++ b/Makefile @@ -180,53 +180,6 @@ riscpkg: $(TARGET) mkdir ArcEm/Apps/Misc/hostfs endif -ifeq (${SYSTEM},nds) -CC=$(DEVKITARM)/bin/arm-none-eabi-gcc -AS=$(DEVKITARM)/bin/arm-none-eabi-as -LD=$(CC) -ARM9_ARCH = -mthumb -mthumb-interwork -march=armv5te -mtune=arm946e-s -CFLAGS += $(ARM9_ARCH) -ffunction-sections -fdata-sections -DSYSTEM_nds -DARM9 -DUSE_FAKEMAIN -DNO_OPEN64 -isystem $(DEVKITPRO)/libnds/include -Wno-cast-align -Wno-format -LDFLAGS += -specs=ds_arm9.specs -g $(ARM9_ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libnds/lib -ifeq (${EXTNROM_SUPPORT},yes) -LIBS += -lfilesystem -endif -LIBS += -lfat -lnds9 -OBJS += nds/main.o nds/img/bg.o nds/img/keys.o nds/img/font.o -ifneq ($(DEBUG),yes) -CFLAGS += -DNDEBUG -endif - -TARGET = ArcEm.elf -all: ArcEm.nds - -%.nds: %.elf %.arm7.elf nds/arc.bmp -ifeq (${EXTNROM_SUPPORT},yes) - mkdir -p romfs/extnrom - cp support_modules/*/*,ffa romfs/extnrom - ndstool -c $@ -9 $< -7 $*.arm7.elf -b nds/arc.bmp "ArcEm;Archimedes Emulator;WIP" -d romfs -else - ndstool -c $@ -9 $< -7 $*.arm7.elf -b nds/arc.bmp "ArcEm;Archimedes Emulator;WIP" -endif - -%.s %.h: %.png %.grit - grit $< -fts -o$* -%.s %.h: %.bmp %.grit - grit $< -fts -o$* - -nds/ControlPane.o: nds/KeyTable.h nds/img/bg.h nds/img/font.h nds/img/keys.h - -ARM7_ARCH = -mthumb -mthumb-interwork -march=armv4t -mtune=arm7tdmi -ARM7_CFLAGS = $(ARM7_ARCH) -Os -ffunction-sections -fdata-sections -DARM7 -isystem $(DEVKITPRO)/libnds/include -ARM7_LDFLAGS = -specs=ds_arm7.specs -g $(ARM7_ARCH) -Wl,--gc-sections -L$(DEVKITPRO)/libnds/lib -ARM7_LIBS = -lnds7 - -ArcEm.arm7.elf: nds/arm7/main.arm7.o - $(LD) $(ARM7_LDFLAGS) $^ $(ARM7_LIBS) -o $@ - -%.arm7.o: %.c - $(CC) $(ARM7_CFLAGS) -o $@ -c $< -endif - ifeq (${SYSTEM},SDL) SDL_CONFIG=sdl2-config CFLAGS += -DSYSTEM_SDL -DUSE_FAKEMAIN $(shell $(SDL_CONFIG) --cflags) diff --git a/nds/ControlPane.c b/nds/ControlPane.c index 2b42b97..9fe9b70 100644 --- a/nds/ControlPane.c +++ b/nds/ControlPane.c @@ -10,9 +10,12 @@ #include "KeyTable.h" -#include "img/bg.h" -#include "img/font.h" -#include "img/keys.h" +#include "bg_gfx.h" +#include "bg_map.h" +#include "bg_pal.h" +#include "font_gfx.h" +#include "font_pal.h" +#include "keys_gfx.h" #include #include @@ -127,9 +130,9 @@ void ControlPane_Init(ARMul_State *state) { BGCTRL_SUB[3] = BG_TILE_BASE(0) | BG_MAP_BASE(5) | BG_COLOR_16 | BG_32x32; - decompress(bgTiles, (void*)(CHAR_BASE_BLOCK_SUB(0) + (0x100 * 32)), LZ77Vram); - decompress(bgMap, (void *)SCREEN_BASE_BLOCK_SUB(5), LZ77Vram); - dmaCopy(bgPal, BG_PALETTE_SUB, bgPalLen); + decompress(bg_gfx, (void*)(CHAR_BASE_BLOCK_SUB(0) + (0x100 * 32)), LZ77Vram); + decompress(bg_map, (void *)SCREEN_BASE_BLOCK_SUB(5), LZ77Vram); + dmaCopy(bg_pal, BG_PALETTE_SUB, bg_pal_size); ControlPane_InitWindows(); ControlPane_InitKeyboard(state); @@ -356,8 +359,8 @@ static void ControlPane_InitWindows(void) { int i; - decompress(fontTiles, (void *)CHAR_BASE_BLOCK_SUB(0), LZ77Vram); - dmaCopy(fontPal, BG_PALETTE_SUB + 16, fontPalLen); + decompress(font_gfx, (void *)CHAR_BASE_BLOCK_SUB(0), LZ77Vram); + dmaCopy(font_pal, BG_PALETTE_SUB + 16, font_pal_size); for (i = 0; i < sizeof(windows)/sizeof(*windows); i++) { ControlPane_CloseWindow(&windows[i]); @@ -463,7 +466,7 @@ static void ControlPane_UpdateKeyboardLEDs(uint8_t leds); static void ControlPane_InitKeyboard(ARMul_State *state) { - static const u16 keysPal[] = { + static const u16 keys_pal[] = { /* 0: Not pressed, shift off, leds off */ 0x5FBD,0x6F7B,0x5EF7,0x7FFF,0x39CE,0x4E73,0x5EF7,0x0000, 0x0000,0x0000,0x6F7B,0x39CE,0x5FBD,0x022A,0x02FF,0x7EE0, @@ -492,8 +495,8 @@ static void ControlPane_InitKeyboard(ARMul_State *state) int i; /* We manage sprite VRAM manually here instead of using oamAllocateGfx() */ - decompress(keysTiles, SPRITE_GFX_SUB, LZ77Vram); - dmaCopy(keysPal, SPRITE_PALETTE_SUB, sizeof(keysPal)); + decompress(keys_gfx, SPRITE_GFX_SUB, LZ77Vram); + dmaCopy(keys_pal, SPRITE_PALETTE_SUB, sizeof(keys_pal)); if (state) KBD.leds_changed = ControlPane_UpdateKeyboardLEDs; diff --git a/nds/arm7/main.c b/nds/arm7/main.c deleted file mode 100644 index 3d5da45..0000000 --- a/nds/arm7/main.c +++ /dev/null @@ -1,97 +0,0 @@ -/*--------------------------------------------------------------------------------- - - default ARM7 core - - Copyright (C) 2005 - 2010 - Michael Noland (joat) - Jason Rogers (dovoto) - Dave Murphy (WinterMute) - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any - damages arising from the use of this software. - - Permission is granted to anyone to use this software for any - purpose, including commercial applications, and to alter it and - redistribute it freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you - must not claim that you wrote the original software. If you use - this software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - - 2. Altered source versions must be plainly marked as such, and - must not be misrepresented as being the original software. - - 3. This notice may not be removed or altered from any source - distribution. - ----------------------------------------------------------------------------------*/ - -/** - * Modified for ArcEm to save space, since we don't need maxmod or libdswifi. - */ - -#include - -//--------------------------------------------------------------------------------- -void VblankHandler(void) { -//--------------------------------------------------------------------------------- -} - - -//--------------------------------------------------------------------------------- -void VcountHandler() { -//--------------------------------------------------------------------------------- - inputGetAndSend(); -} - -volatile bool exitflag = false; - -//--------------------------------------------------------------------------------- -void powerButtonCB() { -//--------------------------------------------------------------------------------- - exitflag = true; -} - -//--------------------------------------------------------------------------------- -int main() { -//--------------------------------------------------------------------------------- - // clear sound registers - dmaFillWords(0, (void*)0x04000400, 0x100); - - REG_SOUNDCNT |= SOUND_ENABLE; - writePowerManagement(PM_CONTROL_REG, ( readPowerManagement(PM_CONTROL_REG) & ~PM_SOUND_MUTE ) | PM_SOUND_AMP ); - powerOn(POWER_SOUND); - - readUserSettings(); - ledBlink(0); - - irqInit(); - // Start the RTC tracking IRQ - initClockIRQ(); - fifoInit(); - touchInit(); - - SetYtrigger(80); - - installSoundFIFO(); - - installSystemFIFO(); - - irqSet(IRQ_VCOUNT, VcountHandler); - irqSet(IRQ_VBLANK, VblankHandler); - - irqEnable( IRQ_VBLANK | IRQ_VCOUNT ); - - setPowerButtonCB(powerButtonCB); - - // Keep the ARM7 mostly idle - while (!exitflag) { - if ( 0 == (REG_KEYINPUT & (KEY_SELECT | KEY_START | KEY_L | KEY_R))) { - exitflag = true; - } - swiWaitForVBlank(); - } - return 0; -} diff --git a/nds/img/keys.grit b/nds/img/keys.grit index 6745630..cf7fe60 100644 --- a/nds/img/keys.grit +++ b/nds/img/keys.grit @@ -4,8 +4,8 @@ # graphics bit depth is 4 (16 color) -gB4 -# exclude palette data --p! +# include palette data +-p # metatile is 2x2 tiles (16x16 pixels) -Mw2 -Mh2 From ef11e690b6947ba1331a215279a308126cd06ff7 Mon Sep 17 00:00:00 2001 From: Cameron Cawley Date: Fri, 27 Dec 2024 18:30:32 +0000 Subject: [PATCH 8/8] Support building the DS port with Calico --- CMakeLists.txt | 26 ++++++++++++++++++++------ nds/ControlPane.c | 23 ++++++++++++++++++----- nds/DispKbd.c | 9 +++++++++ nds/img/bg.grit | 3 --- 4 files changed, 47 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bd81ffd..08cf100 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,6 +177,10 @@ elseif(${SYSTEM} STREQUAL "nds") grit_add_binary_target(keys nds/img/keys.png NO_MAP) dkp_add_embedded_binary_library(grit_data bg font keys) target_link_libraries(arcem PRIVATE grit_data filesystem fat) + + if(CALICO_ROOT) + target_compile_definitions(arcem PRIVATE -D__CALICO__) + endif() elseif(${SYSTEM} STREQUAL "win") option(SOUND_SUPPORT "Build with sound support" ON) if(SOUND_SUPPORT) @@ -203,12 +207,22 @@ elseif(APPLE) elseif(NINTENDO_DS) file(COPY ${ARCEM_EXTNROM_MODULES} DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/nitrofs/extnrom) set_target_properties(arcem PROPERTIES OUTPUT_NAME "ArcEm") - nds_create_rom(arcem - SUBTITLE1 "Archimedes Emulator" - SUBTITLE2 "WIP" - ICON nds/arc.bmp - NITROFS ${CMAKE_CURRENT_BINARY_DIR}/nitrofs - ) + if(CALICO_ROOT) + nds_create_rom(arcem + ARM7 lykoi + SUBTITLE1 "Archimedes Emulator" + SUBTITLE2 "WIP using Calico" + ICON nds/arc.bmp + NITROFS ${CMAKE_CURRENT_BINARY_DIR}/nitrofs + ) + else() + nds_create_rom(arcem + SUBTITLE1 "Archimedes Emulator" + SUBTITLE2 "WIP" + ICON nds/arc.bmp + NITROFS ${CMAKE_CURRENT_BINARY_DIR}/nitrofs + ) + endif() endif() target_include_directories(arcem PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/arch) diff --git a/nds/ControlPane.c b/nds/ControlPane.c index 9fe9b70..1c64def 100644 --- a/nds/ControlPane.c +++ b/nds/ControlPane.c @@ -130,8 +130,8 @@ void ControlPane_Init(ARMul_State *state) { BGCTRL_SUB[3] = BG_TILE_BASE(0) | BG_MAP_BASE(5) | BG_COLOR_16 | BG_32x32; - decompress(bg_gfx, (void*)(CHAR_BASE_BLOCK_SUB(0) + (0x100 * 32)), LZ77Vram); - decompress(bg_map, (void *)SCREEN_BASE_BLOCK_SUB(5), LZ77Vram); + dmaCopy(bg_gfx, (void *)(CHAR_BASE_BLOCK_SUB(0) + (0x100 * 32)), bg_gfx_size); + dmaCopy(bg_map, (void *)SCREEN_BASE_BLOCK_SUB(5), bg_map_size); dmaCopy(bg_pal, BG_PALETTE_SUB, bg_pal_size); ControlPane_InitWindows(); @@ -158,7 +158,12 @@ void ControlPane_Error(int code,const char *fmt,...) vprintf(fmt,args); va_end(args); - while(1) { +#ifdef __CALICO__ + while(pmMainLoop()) +#else + while(1) +#endif + { swiWaitForVBlank(); scanKeys(); if (keysDown() & KEY_START) @@ -174,7 +179,15 @@ void ControlPane_Error(int code,const char *fmt,...) va_end(args); w = ControlPane_MessageBox(0, "Error", msg); - while (w->layer >= 0) { + +#ifdef __CALICO__ + while(pmMainLoop()) +#else + while(1) +#endif + { + if (w->layer < 0) + break; swiWaitForVBlank(); Kbd_PollHostKbd(NULL); } @@ -300,7 +313,7 @@ static Window *ControlPane_CreateWindow(int layer, int w, int h, const char *tit window->bw = w; window->bh = h; - dmaFillHalfWords(1<<12, window->map, 32*32*2); + dmaFillHalfWords(1<<12, window->map, 64*64*2); /* Left hand side */ ControlPane_TextDrawBlock(window, TL, -1, -3, 1, 3); diff --git a/nds/DispKbd.c b/nds/DispKbd.c index 2e2dc2a..70dd5b1 100644 --- a/nds/DispKbd.c +++ b/nds/DispKbd.c @@ -200,7 +200,11 @@ static void PDD_Name(Host_ChangeMode)(ARMul_State *state,int width,int height,in oamRotateScale(&oamMain, 0, 0, xs, ys); /* Screen is expected to be cleared */ +#ifdef __CALICO__ + memset(bgGetGfxPtr(background), 0, PDD_MonitorWidth * PDD_MonitorHeight); +#else dmaFillHalfWords(0, bgGetGfxPtr(background), PDD_MonitorWidth * PDD_MonitorHeight); +#endif } @@ -320,6 +324,11 @@ static void ProcessButtons(ARMul_State *state, int pressed, int released) { int Kbd_PollHostKbd(ARMul_State *state) { +#ifdef __CALICO__ + if (!pmMainLoop()) + exit(0); +#endif + touchPosition touch; scanKeys(); diff --git a/nds/img/bg.grit b/nds/img/bg.grit index 6ed2268..df0e0c3 100644 --- a/nds/img/bg.grit +++ b/nds/img/bg.grit @@ -15,6 +15,3 @@ # offset the bg tiles to fit alongside the font tiles -ma256 - -# use lz77 compression --gzl -mzl