From 1952c74fb31a60428e79a458b48edeb066663f91 Mon Sep 17 00:00:00 2001 From: yosiokat Date: Mon, 29 Oct 2007 11:02:25 +0000 Subject: [PATCH] =?UTF-8?q?systemMenu=5FRED=E3=81=AE=E8=BF=BD=E5=8A=A0?= =?UTF-8?q?=E3=80=82=EF=BC=88=E3=81=BE=E3=81=A0=E3=81=BE=E3=81=A8=E3=82=82?= =?UTF-8?q?=E3=81=AB=E5=8B=95=E3=81=8B=E3=81=AA=E3=81=84=E3=80=82=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: file:///Users/lillianskinner/Downloads/platinum/twl/TwlIPL/trunk@72 b08762b0-b915-fc4b-9d8c-17b2551a87ff --- build/Makefile | 1 - build/buildtools/commondefs.sysmenu | 95 + build/buildtools/modulerules.sysmenu | 30 + build/libraries_sysmenu/Makefile | 30 + build/libraries_sysmenu/acsign/ARM9/Makefile | 56 + .../acsign/ARM9/include/acmemory.h | 36 + .../acsign/ARM9/include/bn.h | 1136 ++++++++++++ .../acsign/ARM9/include/bn_lcl.h | 356 ++++ .../acsign/ARM9/include/bn_thx.h | 317 ++++ .../acsign/ARM9/include/md5.h | 73 + .../acsign/ARM9/include/r_error.h | 226 +++ .../acsign/ARM9/include/r_stdiag.h | 98 + .../acsign/ARM9/include/r_types.h | 257 +++ .../acsign/ARM9/include/sha.h | 105 ++ .../acsign/ARM9/include/sha1.h | 90 + .../acsign/ARM9/include/sha_locl.h | 290 +++ .../acsign/ARM9/src/acmemory.c | 306 ++++ .../acsign/ARM9/src/acsign.c | 453 +++++ .../acsign/ARM9/src/acsign_util.c | 111 ++ .../acsign/ARM9/src/bn_add.c | 320 ++++ .../acsign/ARM9/src/bn_asm.c | 525 ++++++ .../acsign/ARM9/src/bn_comba.c | 450 +++++ .../acsign/ARM9/src/bn_div.c | 381 ++++ .../acsign/ARM9/src/bn_ex_str.c | 453 +++++ .../acsign/ARM9/src/bn_exp.c | 172 ++ .../acsign/ARM9/src/bn_fm_w.c | 79 + .../acsign/ARM9/src/bn_gcd.c | 245 +++ .../acsign/ARM9/src/bn_lib.c | 1095 +++++++++++ .../acsign/ARM9/src/bn_lsh.c | 128 ++ .../acsign/ARM9/src/bn_m_exp.c | 299 +++ .../libraries_sysmenu/acsign/ARM9/src/bn_me.c | 267 +++ .../acsign/ARM9/src/bn_mont.c | 247 +++ .../acsign/ARM9/src/bn_ms_w.c | 137 ++ .../acsign/ARM9/src/bn_mul.c | 795 ++++++++ .../acsign/ARM9/src/bn_r_exp.c | 150 ++ .../acsign/ARM9/src/bn_rec.c | 249 +++ .../acsign/ARM9/src/bn_recp.c | 218 +++ .../acsign/ARM9/src/bn_rsh.c | 139 ++ .../acsign/ARM9/src/bn_sqr.c | 289 +++ .../acsign/ARM9/src/bn_wdiv.c | 116 ++ .../acsign/ARM9/src/bn_word.c | 238 +++ .../libraries_sysmenu/acsign/ARM9/src/main.c | 320 ++++ build/libraries_sysmenu/acsign/ARM9/src/md5.c | 412 +++++ .../libraries_sysmenu/acsign/ARM9/src/sha1.c | 470 +++++ .../acsign/ARM9/src/sha1dgst.c | 786 ++++++++ build/libraries_sysmenu/acsign/Makefile | 29 + .../libraries_sysmenu/mb_loader/ARM7/Makefile | 52 + .../libraries_sysmenu/mb_loader/ARM9/Makefile | 51 + build/libraries_sysmenu/mb_loader/Makefile | 29 + .../mb_loader/common/src/mb_loader.c | 312 ++++ build/libraries_sysmenu/sysmenu/ARM9/MakeCrt0 | 46 + build/libraries_sysmenu/sysmenu/ARM9/Makefile | 52 + .../sysmenu/ARM9/include/sysmenu_card.h | 248 +++ .../sysmenu/ARM9/include/sysmenu_define.h | 50 + .../libraries_sysmenu/sysmenu/ARM9/src/cmn.c | 250 +++ .../libraries_sysmenu/sysmenu/ARM9/src/crt1.c | 559 ++++++ .../sysmenu/ARM9/src/gameBoot.c | 247 +++ .../sysmenu/ARM9/src/ninLogoFunc.c | 168 ++ .../sysmenu/ARM9/src/nitroSettingsEx.c | 582 ++++++ .../sysmenu/ARM9/src/sysmenu_card.c | 253 +++ .../sysmenu/ARM9/src/sysmenu_lib.c | 721 ++++++++ .../sysmenu/ARM9/src/sysmenu_util.c | 172 ++ build/libraries_sysmenu/sysmenu/Makefile | 31 + build/systemMenu_RED/ARM9/ARM9-TS.lsf | 70 + build/systemMenu_RED/ARM9/Makefile | 81 + .../ARM9/data/NTR_IPL_font_l.NFTR | Bin 0 -> 181128 bytes .../ARM9/data/NTR_IPL_font_m.NFTR | Bin 0 -> 107180 bytes .../ARM9/data/NTR_IPL_font_s.NFTR | Bin 0 -> 79924 bytes .../systemMenu_RED/ARM9/data/sound_data.sadl | 8 + .../systemMenu_RED/ARM9/data/sound_data.sdat | Bin 0 -> 16160 bytes build/systemMenu_RED/ARM9/font/f12han.dat | Bin 0 -> 10528 bytes build/systemMenu_RED/ARM9/font/f12han_map.bmp | Bin 0 -> 43454 bytes build/systemMenu_RED/ARM9/font/f12zen.dat | Bin 0 -> 190632 bytes build/systemMenu_RED/ARM9/font/f12zen_map.bmp | Bin 0 -> 276926 bytes build/systemMenu_RED/ARM9/main.rsf | 147 ++ .../systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.c | 102 ++ .../systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.h | 36 + .../src/DS_DownloadPlay/DS_DownloadPlay.c | 1618 +++++++++++++++++ .../src/DS_DownloadPlay/DS_DownloadPlay.h | 37 + .../ARM9/src/DS_Setting/AgbLcdSel.c | 131 ++ .../ARM9/src/DS_Setting/DS_Setting.c | 128 ++ .../ARM9/src/DS_Setting/DS_Setting.h | 90 + .../ARM9/src/DS_Setting/autoBoot.c | 131 ++ .../systemMenu_RED/ARM9/src/DS_Setting/font.c | 1030 +++++++++++ .../systemMenu_RED/ARM9/src/DS_Setting/font.h | 93 + .../ARM9/src/DS_Setting/langSelect.c | 141 ++ .../systemMenu_RED/ARM9/src/DS_Setting/misc.c | 384 ++++ .../systemMenu_RED/ARM9/src/DS_Setting/misc.h | 103 ++ .../ARM9/src/DS_Setting/myChar.c | 684 +++++++ .../ARM9/src/DS_Setting/myFontequ.h | 335 ++++ .../ARM9/src/DS_Setting/ownerInfo.c | 1077 +++++++++++ .../ARM9/src/DS_Setting/rtcSet.c | 553 ++++++ .../ARM9/src/DS_Setting/settingMenu.c | 308 ++++ .../ARM9/src/DS_Setting/tpCalib.c | 516 ++++++ .../ARM9/src/DS_Setting/unicode.c | 567 ++++++ .../ARM9/src/DS_Setting/unicode.h | 40 + build/systemMenu_RED/ARM9/src/Logo/logoData.c | 204 +++ build/systemMenu_RED/ARM9/src/Logo/logoDemo.c | 130 ++ build/systemMenu_RED/ARM9/src/Logo/logoDemo.h | 36 + build/systemMenu_RED/ARM9/src/launcher.c | 244 +++ build/systemMenu_RED/ARM9/src/main.c | 409 +++++ build/systemMenu_RED/ARM9/src/main.h | 183 ++ build/systemMenu_RED/ARM9/src/mainFunc.c | 626 +++++++ build/systemMenu_RED/Makefile | 30 + include/sysmenu.h | 33 + include/sysmenu/acsign.h | 35 + include/sysmenu/acsign/ARM9/acsign.h | 59 + include/sysmenu/acsign/ARM9/acsign_util.h | 37 + include/sysmenu/banner.h | 111 ++ include/sysmenu/machineSettings.h | 32 + .../machineSettings/common/nitroSettings.h | 490 +++++ include/sysmenu/mb_loader.h | 32 + include/sysmenu/mb_loader/common/mb_loader.h | 86 + include/sysmenu/memorymap.h | 34 + include/sysmenu/mmap.h | 57 + include/sysmenu/rom_header.h | 175 ++ include/sysmenu/sysmenu_lib.h | 35 + include/sysmenu/sysmenu_lib/ARM9/cmn.h | 54 + .../sysmenu/sysmenu_lib/ARM9/sysmenu_api.h | 94 + include/sysmenu/sysmenu_work.h | 246 +++ 120 files changed, 28779 insertions(+), 1 deletion(-) create mode 100644 build/buildtools/commondefs.sysmenu create mode 100644 build/buildtools/modulerules.sysmenu create mode 100644 build/libraries_sysmenu/Makefile create mode 100644 build/libraries_sysmenu/acsign/ARM9/Makefile create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/acmemory.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/bn.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/bn_lcl.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/bn_thx.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/md5.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/r_error.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/r_stdiag.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/r_types.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/sha.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/sha1.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/include/sha_locl.h create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/acmemory.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/acsign.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/acsign_util.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_add.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_asm.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_comba.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_div.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_ex_str.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_exp.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_fm_w.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_gcd.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_lib.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_lsh.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_m_exp.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_me.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_mont.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_ms_w.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_mul.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_r_exp.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_rec.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_recp.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_rsh.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_sqr.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_wdiv.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/bn_word.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/main.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/md5.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/sha1.c create mode 100644 build/libraries_sysmenu/acsign/ARM9/src/sha1dgst.c create mode 100644 build/libraries_sysmenu/acsign/Makefile create mode 100644 build/libraries_sysmenu/mb_loader/ARM7/Makefile create mode 100644 build/libraries_sysmenu/mb_loader/ARM9/Makefile create mode 100644 build/libraries_sysmenu/mb_loader/Makefile create mode 100644 build/libraries_sysmenu/mb_loader/common/src/mb_loader.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/MakeCrt0 create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/Makefile create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_card.h create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_define.h create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/cmn.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/crt1.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/gameBoot.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/ninLogoFunc.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/nitroSettingsEx.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_card.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_lib.c create mode 100644 build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_util.c create mode 100644 build/libraries_sysmenu/sysmenu/Makefile create mode 100644 build/systemMenu_RED/ARM9/ARM9-TS.lsf create mode 100644 build/systemMenu_RED/ARM9/Makefile create mode 100644 build/systemMenu_RED/ARM9/data/NTR_IPL_font_l.NFTR create mode 100644 build/systemMenu_RED/ARM9/data/NTR_IPL_font_m.NFTR create mode 100644 build/systemMenu_RED/ARM9/data/NTR_IPL_font_s.NFTR create mode 100644 build/systemMenu_RED/ARM9/data/sound_data.sadl create mode 100644 build/systemMenu_RED/ARM9/data/sound_data.sdat create mode 100644 build/systemMenu_RED/ARM9/font/f12han.dat create mode 100644 build/systemMenu_RED/ARM9/font/f12han_map.bmp create mode 100644 build/systemMenu_RED/ARM9/font/f12zen.dat create mode 100644 build/systemMenu_RED/ARM9/font/f12zen_map.bmp create mode 100644 build/systemMenu_RED/ARM9/main.rsf create mode 100644 build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.h create mode 100644 build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.h create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/AgbLcdSel.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.h create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/autoBoot.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/font.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/font.h create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/langSelect.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/misc.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/misc.h create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/myChar.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/myFontequ.h create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/ownerInfo.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/rtcSet.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/settingMenu.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/tpCalib.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/unicode.c create mode 100644 build/systemMenu_RED/ARM9/src/DS_Setting/unicode.h create mode 100644 build/systemMenu_RED/ARM9/src/Logo/logoData.c create mode 100644 build/systemMenu_RED/ARM9/src/Logo/logoDemo.c create mode 100644 build/systemMenu_RED/ARM9/src/Logo/logoDemo.h create mode 100644 build/systemMenu_RED/ARM9/src/launcher.c create mode 100644 build/systemMenu_RED/ARM9/src/main.c create mode 100644 build/systemMenu_RED/ARM9/src/main.h create mode 100644 build/systemMenu_RED/ARM9/src/mainFunc.c create mode 100644 build/systemMenu_RED/Makefile create mode 100644 include/sysmenu.h create mode 100644 include/sysmenu/acsign.h create mode 100644 include/sysmenu/acsign/ARM9/acsign.h create mode 100644 include/sysmenu/acsign/ARM9/acsign_util.h create mode 100644 include/sysmenu/banner.h create mode 100644 include/sysmenu/machineSettings.h create mode 100644 include/sysmenu/machineSettings/common/nitroSettings.h create mode 100644 include/sysmenu/mb_loader.h create mode 100644 include/sysmenu/mb_loader/common/mb_loader.h create mode 100644 include/sysmenu/memorymap.h create mode 100644 include/sysmenu/mmap.h create mode 100644 include/sysmenu/rom_header.h create mode 100644 include/sysmenu/sysmenu_lib.h create mode 100644 include/sysmenu/sysmenu_lib/ARM9/cmn.h create mode 100644 include/sysmenu/sysmenu_lib/ARM9/sysmenu_api.h create mode 100644 include/sysmenu/sysmenu_work.h diff --git a/build/Makefile b/build/Makefile index 87a15b0b..c45dcc6b 100644 --- a/build/Makefile +++ b/build/Makefile @@ -24,7 +24,6 @@ include $(TWLFIRM_ROOT)/build/buildtools/commondefs SUBDIRS = \ tools \ libraries \ - norfirm \ nandfirm \ nand_formatter \ diff --git a/build/buildtools/commondefs.sysmenu b/build/buildtools/commondefs.sysmenu new file mode 100644 index 00000000..352fd9a4 --- /dev/null +++ b/build/buildtools/commondefs.sysmenu @@ -0,0 +1,95 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL - commondefs - common definitions for build system +# File: commondefs +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-09-06$ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- +ifndef TWL_SYSMENU_COMMONDEFS_ +TWL_SYSMENU_COMMONDEFS_ = TRUE + +NITRO_NO_STD_PCHDR = TRUE # プリコンパイルヘッダ抑止 + +EMPTY ?= +SPACE ?= $(EMPTY) $(EMPTY) + +#---------------------------------------------------------------------------- +# TWL-SYSTEM-MENU path settings +# + +SYSMENU_ROOT := $(subst $(SPACE),\ ,$(subst \,/,$(TWLIPL_ROOT))) +SYSMENU_BUILDTOOLSDIR := $(SYSMENU_ROOT)/build/buildtools +SYSMENU_INCDIR := $(SYSMENU_ROOT)/include +SYSMENU_TOOLSDIR := $(SYSMENU_ROOT)/tools +SYSMENU_COMPONENTSDIR := $(SYSMENU_ROOT)/components + +LDEPENDS_LCF += $(SYSMENU_BUILDTOOLSDIR)/commondefs.sysmenu +LDEPENDS_RES += $(SYSMENU_BUILDTOOLSDIR)/commondefs.sysmenu + + +#---------------------------------------------------------------------------- +### TWL-commondefs +# +#include $(TWLSDK_ROOT)/build/buildtools/commondefs +include $(NITROSYSTEM_ROOT)/build/buildtools/commondefs + + +#---------------------------------------------------------------------------- +### SYSTEM_MENU Library settings + +SYSMENU_LIBDIR := $(SYSMENU_ROOT)/lib/$(TWL_LIBTYPE) + +ifeq ($(CODEGEN_PROC),ARM9) + +SYSMENU_LIBS ?= \ + libsysmenu$(TWL_LIBSUFFIX).a \ + libmbloader$(TWL_LIBSUFFIX).a \ + libacsign$(TWL_LIBSUFFIX).a + +else # ($(CODEGEN_PROC),ARM7) + +SYSMENU_LIBS ?= \ + libmbloader_sp$(TWL_LIBSUFFIX).a + +endif + + +#---------------------------------------------------------------------------- +# MY BUILD TOOLS +# +OPENSSL := $(SYSMENU_TOOLSDIR)/openssl/openssl.exe + +MAKESYSMENU_RSA_PRVKEY ?= $(SYSMENU_TOOLSDIR)/openssl/rsa_private.der +MAKESYSMENU_RSA_PUBKEY ?= $(SYSMENU_TOOLSDIR)/openssl/rsa_public.der + +#---------------------------------------------------------------------------- + +### Global Library resettings + +GINCLUDES := $(SYSMENU_INCDIR) $(GINCLUDES) +GLIBRARY_DIRS := $(SYSMENU_LIBDIR) $(GLIBRARY_DIRS) +GLIBRARIES := $(SYSMENU_LIBS) $(GLIBRARIES) + + +#---------------------------------------------------------------------------- +# TWLSYSMENU_INSTALL_ROOT +# +SYSMENU_INSTALL_ROOT := $(SYSMENU_ROOT) +SYSMENU_INSTALL_INCDIR := $(SYSMENU_INSTALL_ROOT)/include +SYSMENU_INSTALL_TOOLSDIR := $(SYSMENU_INSTALL_ROOT)/tools +SYSMENU_INSTALL_LIBDIR := $(SYSMENU_INSTALL_ROOT)/lib/$(TWL_LIBTYPE) +SYSMENU_INSTALL_COMPONENTSDIR := $(SYSMENU_INSTALL_ROOT)/components + +#---------------------------------------------------------------------------- +endif # TWL_SYSMENU_COMMONDEFS_ +#----- End of commondefs ----- diff --git a/build/buildtools/modulerules.sysmenu b/build/buildtools/modulerules.sysmenu new file mode 100644 index 00000000..ff50b1e2 --- /dev/null +++ b/build/buildtools/modulerules.sysmenu @@ -0,0 +1,30 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL - modulerules - common rules for build system +# File: modulerules +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-09-06$ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- +ifndef TWL_SYSMENU_MODULERULES_ + +#---------------------------------------------------------------------------- +### TWL-modulerules +# +#include $(TWLSDK_ROOT)/build/buildtools/modulerules +include $(NITROSYSTEM_ROOT)/build/buildtools/modulerules + + +#---------------------------------------------------------------------------- +TWL_SYSMENU_MODULERULES_ = TRUE +endif # TWL_SYSMENU_MODULERULES_ +#----- End of modulerules ----- diff --git a/build/libraries_sysmenu/Makefile b/build/libraries_sysmenu/Makefile new file mode 100644 index 00000000..7d9f58a8 --- /dev/null +++ b/build/libraries_sysmenu/Makefile @@ -0,0 +1,30 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-10-03#$ +# $Rev: 1319 $ +# $Author: kitase_hirotake $ +#---------------------------------------------------------------------------- + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +#---------------------------------------------------------------------------- + +SUBDIRS = sysmenu mb_loader acsign + +#---------------------------------------------------------------------------- + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + + +#===== End of Makefile ===== diff --git a/build/libraries_sysmenu/acsign/ARM9/Makefile b/build/libraries_sysmenu/acsign/ARM9/Makefile new file mode 100644 index 00000000..655cd1b8 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/Makefile @@ -0,0 +1,56 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-10-03#$ +# $Rev: 1319 $ +# $Author: kitase_hirotake $ +#---------------------------------------------------------------------------- + +#---------------------------------------------------------------------------- + +SUBDIRS = + + +#---------------------------------------------------------------------------- +TARGET_PLATFORM = TWL +TWL_ARCHGEN = LIMITED +TWL_PROC = ARM9 + +INCDIR = include \ + $(TWLSDK_ROOT)/build/libraries/mb/common/include + +SRCS = acsign.c acmemory.c acsign_util.c + +TARGET_LIB = libacsign$(TWL_LIBSUFFIX).a + + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(SYSMENU_INSTALL_LIBDIR) + +CCFLAGS += -DSMALL_CODE_SIZE \ + -DSTANDALONE \ + -DOPT_32_BIT \ + -DNO_SPLIT \ + -DNO_FP_API \ + -DNO_R_DIAG \ + -DNO_STDIO_H \ + -DNO_STDLIB_H + +do-build: $(TARGETS) + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + + +#===== End of Makefile ===== diff --git a/build/libraries_sysmenu/acsign/ARM9/include/acmemory.h b/build/libraries_sysmenu/acsign/ARM9/include/acmemory.h new file mode 100644 index 00000000..8247764c --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/acmemory.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: acmemory.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef _ACMEMORY_H_ +#define _ACMEMORY_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +// +void ACMemory_Clear( ); +void* ACMemory_Alloc( u32 size ); +void ACMemory_Free( void* adrs ); +void* ACMemory_Memset( void* adrs, u32 val, u32 cnt ); +void* ACMemory_Memcpy( void* dst, void* src, u32 cnt ); + +#ifdef __cplusplus +} +#endif + +#endif //_ACMEMORY_H_ diff --git a/build/libraries_sysmenu/acsign/ARM9/include/bn.h b/build/libraries_sysmenu/acsign/ARM9/include/bn.h new file mode 100644 index 00000000..ed99275e --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/bn.h @@ -0,0 +1,1136 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#ifndef HEADER_COMMON_BN_H +#define HEADER_COMMON_BN_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef FLAT_INC +#include "r_types.h" +#else +#include "../include/r_types.h" +#endif + +#if !defined(CCONV) +#define CCONV +#endif + +#ifndef PRE_CCONV +#define PRE_CCONV +#endif + +/* convert from the new to the old option names */ +#if defined(OPT_BN_LLONG) +#define BN_LLONG /* comment to make sure Configure leaves this alone */ +#endif + +#if defined(OPT_BN_MUL_LATENCY) +#define BN_MUL_LATENCY +#endif + +/* by default we have the following switched on - unless we have an option + * that switched them off for a specific platform + */ +#ifdef OPT_NO_COMBA +#define OPT_NO_BN_MUL_COMBA +#define OPT_NO_BN_SQR_COMBA +#endif + +#ifdef OPT_NO_REC +#define OPT_NO_BN_RECURSION_MUL +#define OPT_NO_BN_RECURSION_SQR +#endif + +#ifndef OPT_NO_BN_MUL_COMBA +#define BN_MUL_COMBA +#endif +#ifndef OPT_NO_BN_SQR_COMBA +#define BN_SQR_COMBA +#endif +#ifndef OPT_NO_BN_RECURSION_MUL +#define BN_RECURSION_MUL +#endif +#ifndef OPT_NO_BN_RECURSION_SQR +#define BN_RECURSION_SQR +#endif +#ifndef OPT_NO_BN_RECURSION_MONT +#undef BN_RECURSION_MONT /* DO NOT TURN THIS ON, IT IS BROKEN */ +#endif + +#if (!defined(OPT_NO_BN_MUL_COMBA) && !defined(OPT_NO_BN_SQR_COMBA)) +#if OPT_MONT_REDUCE_COMBA /* TEMP UNTIL C IS IMPLEMENTED-DEF'd ON PLATFORMS W/ ASM */ +#define BN_REDUCE_COMBA +#endif +#endif + +#define RECP_MUL_MOD +#define MONT_MUL_MOD + +#ifndef OPT_NO_BN_SURRENDER +#define BN_SURRENDER +#else +#undef BN_SURRENDER +#endif + +#ifdef SMALL_CODE_SIZE +#undef BN_MUL_COMBA /* stop modification */ +#undef BN_SQR_COMBA /* stop modification */ +#undef BN_REDUCE_COMBA /* stop modification */ +#undef BN_RECURSION_MUL /* stop modification */ +#undef BN_RECURSION_SQR /* stop modification */ +#undef BN_RECURSION_MONT /* stop modification */ +#endif + + + +/* This next option uses the C libraries (2 word)/(1 word) function. + * If it is not defined, I use my C version (which is slower). + * The reason for this flag is that when the particular C compiler + * library routine is used, and the library is linked with a different + * compiler, the library is missing. This mostly happens when the + * library is built with gcc and then linked using nornal cc. This would + * be a common occurance because gcc normally produces code that is + * 2 times faster than system compilers for the big number stuff. + * For machines with only one compiler (or shared libraries), this should + * be on. Again this in only really a problem on machines + * using "long long's", are 32bit, and are not using my assember code. */ +#if defined(MSDOS) || defined(WINDOWS) || defined(linux) +#define BN_DIV2W +#endif + +/* Only one for the following should be defined */ +/* The prime number generation stuff may not work when + * EIGHT_BIT but I don't care since I've only used this mode + * for debuging the bignum libraries */ +#undef SIXTY_FOUR_BIT_LONG +#undef SIXTY_FOUR_BIT +#undef SIXTY_BIT +#undef THIRTY_TWO_BIT +#undef THIRTY_BIT +#undef SIXTEEN_BIT +#undef EIGHT_BIT +#undef TEST_EIGHT_BIT + +#if defined(OPT_64_BIT_LONG) +#define SIXTY_FOUR_BIT_LONG +#endif +#if defined(OPT_64_BIT) +#define SIXTY_FOUR_BIT +#endif +#if defined(OPT_60_BIT) +#define SIXTY_BIT +#endif +#if defined(OPT_32_BIT) +#define THIRTY_TWO_BIT +#endif +#if defined(OPT_32_BIT_INT) +#define THIRTY_TWO_BIT +#endif +#if defined(OPT_30_BIT) +#define THIRTY_BIT +#endif +#if defined(OPT_16_BIT) +#define SIXTEEN_BIT +#endif +#if defined(OPT_8_BIT) +#define EIGHT_BIT +#endif +#if defined(OPT_8_BIT_TEST) +#define TEST_EIGHT_BIT +#endif + +/* This define is used for those few functions that 'break' when + * things are compiled for 8 bit words. Basically the size of an + * integer. + */ +#define BN_ILONG BN_ULONG + +/* assuming long is 64bit - this is the DEC Alpha + * unsigned long long is only 64 bits, don't define + * BN_LLONG for the DEC Alpha */ +#ifdef SIXTY_FOUR_BIT_LONG +#undef BN_LLONG +#define BN_ULLONG unsigned long long +#define BN_ULONG unsigned long +#define BN_LONG long +#define BN_BITS 128 +#define BN_BYTES 8 +#define BN_BITS2 64 +#define BN_BITS4 32 +#define BN_MASK (0xffffffffffffffffffffffffffffffffLL) +#define BN_MASK2 (0xffffffffffffffffL) +#define BN_MASK2l (0xffffffffL) +#define BN_MASK2lh (0xffffffffL) +#define BN_MASK2h (0xffffffff00000000L) +#define BN_MASK2h1 (0xffffffff80000000L) +#define BN_TBIT (0x8000000000000000L) +#define BN_DEC_CONV (10000000000000000000UL) +#define BN_DEC_FMT1 "%lu" +#define BN_DEC_FMT2 "%019lu" +#define BN_DEC_NUM 19 +#define BN_HEX_FMT "%016lX" +#endif + +/* This is where the long long data type is 64 bits, but long is 32. + * For machines where there are 64bit registers, this is the mode to use. + * IRIX, on R4000 and above should use this mode, along with the relevent + * assember code. Do NOT define BN_LLONG. + */ +#ifdef SIXTY_FOUR_BIT +#undef BN_LLONG /* Protect against config */ +/* #define BN_ULLONG unsigned long long */ +#ifdef WIN64 +#define BN_ULONG unsigned _int64 +#define BN_LONG _int64 +#else +#define BN_ULONG unsigned long long +#define BN_LONG long long +#endif +#define BN_BITS 128 +#define BN_BYTES 8 +#define BN_BITS2 64 +#define BN_BITS4 32 +#define BN_MASK2 (0xffffffffffffffffLL) +#define BN_MASK2l (0xffffffffL) +#define BN_MASK2lh (0xffffffffL) +#define BN_MASK2h (0xffffffff00000000LL) +#define BN_MASK2h1 (0xffffffff80000000LL) +#define BN_TBIT (0x8000000000000000LL) +#define BN_DEC_CONV (10000000000000000000ULL) +#ifdef WIN64 +#define BN_DEC_FMT1 "%I64u" +#define BN_DEC_FMT2 "%019I64u" +#define BN_DEC_NUM 19 +#define BN_HEX_FMT "%016I64X" +#else +#define BN_DEC_FMT1 "%llu" +#define BN_DEC_FMT2 "%019llu" +#define BN_DEC_NUM 19 +#define BN_HEX_FMT "%016llX" +#endif +#endif + +#ifdef SIXTY_BIT +#undef SIXTY_FOUR_BIT +#undef BN_LLONG /* Protect against config */ +/* #define BN_ULLONG unsigned long long */ +#define BN_ULONG unsigned long long +#define BN_LONG long long +#define BN_BITS 120 +#define BN_BITS2 60 +#define BN_BITS4 30 +#define BN_MASK2 (0x0fffffffffffffffLL) +#define BN_MASK2l ( 0x3fffffffL) +#define BN_MASK2lh ( 0x3fffffffL) +#define BN_MASK2h (0x0fffffffc0000000LL) +#define BN_MASK2h1 (0x0fffffffe0000000LL) +#define BN_TBIT (0x0800000000000000LL) +#define BN_DEC_CONV (100000000000000000LL) +#define BN_DEC_FMT1 "%9u" +#define BN_DEC_FMT2 "%017llu" +#define BN_DEC_NUM 17 +#define BN_HEX_FMT "%016llX" +#endif + +#ifdef THIRTY_TWO_BIT +#ifdef WIN32 +#if defined(__BORLANDC__) +#define BN_ULLONG unsigned __int64 +#else /* !__BORLANDC__ */ +#if defined(__MINGW32__) || defined(__DJGPP__) +#define BN_ULLONG unsigned long long +#else +#define BN_ULLONG unsigned _int64 +#endif /* __MINGW32__ || __DJGPP__ */ +#endif /* __BORLANDC__ */ +#else /* !WIN32 */ +#define BN_ULLONG unsigned long long +#endif /* WIN32 */ +#ifdef OPT_32_BIT_INT +#define BN_ULONG unsigned int +#define BN_LONG int +#else +#define BN_ULONG unsigned long +#define BN_LONG long +#endif +#define BN_BITS 64 +#define BN_BYTES 4 +#define BN_BITS2 32 +#define BN_BITS4 16 +/* This is needed because the Watcom compiler pre-processor + * under QNX tries to parses the 'LL' part even though it is + * never used. + */ +#ifdef BN_LLONG +#ifndef WIN32 +#define BN_MASK (0xffffffffffffffffLL) +#else +#define BN_MASK (0xffffffffffffffffL) +#endif +#endif +#define BN_MASK2 (0xffffffffL) +#define BN_MASK2l (0xffff) +#define BN_MASK2lh (0xffff) +#define BN_MASK2h1 (0xffff8000L) +#define BN_MASK2h (0xffff0000L) +#define BN_TBIT (0x80000000L) +#define BN_DEC_CONV (1000000000L) +#define BN_DEC_FMT1 "%lu" +#define BN_DEC_FMT2 "%09lu" +#define BN_DEC_NUM 9 +#define BN_HEX_FMT "%08lX" +#endif + +#ifdef THIRTY_BIT +#ifdef WIN32 +#if defined(__MINGW32__) || defined(__DJGPP__) +#define BN_ULLONG unsigned long long +#else /* ! (__MINGW32__ || __DJGPP__) */ +#define BN_ULLONG unsigned _int64 +#endif /* __MINGW32__ || __DJGPP__ */ +#else /* !WIN32 */ +#define BN_ULLONG unsigned long long +#endif /* WIN32 */ +#define BN_ULONG unsigned long +#define BN_LONG long +#define BN_BITS 60 +#define BN_BITS2 30 +#define BN_BITS4 15 +/* This is needed because the Watcom compiler pre-processor + * under QNX tries to parses the 'LL' part even though it is + * never used. + */ +#ifdef BN_LLONG +#ifndef WIN32 +#define BN_MASK (0x0fffffffffffffffLL) +#else +#define BN_MASK (0x0fffffffffffffffL) +#endif +#endif +#define BN_MASK2 (0x3fffffffL) +#define BN_MASK2l (0x7fff) +#define BN_MASK2lh (0x7fff) +#define BN_MASK2h1 (0x3fffc000L) +#define BN_MASK2h (0x3fff8000L) +#define BN_TBIT (0x20000000L) +#define BN_DEC_CONV (1000000000L) +#define BN_DEC_FMT1 "%lu" +#define BN_DEC_FMT2 "%09lu" +#define BN_DEC_NUM 9 +#define BN_HEX_FMT "%08lX" +#endif + +#ifdef SIXTEEN_BIT +#ifndef BN_DIV2W +#define BN_DIV2W +#endif +#define BN_ULLONG unsigned long +#define BN_ULONG unsigned short +#define BN_LONG short +#define BN_BITS 32 +#define BN_BYTES 2 +#define BN_BITS2 16 +#define BN_BITS4 8 +#define BN_MASK (0xffffffff) +#define BN_MASK2 (0xffff) +#define BN_MASK2l (0xff) +#define BN_MASK2lh (0xff) +#define BN_MASK2h1 (0xff80) +#define BN_MASK2h (0xff00) +#define BN_TBIT (0x8000) +#define BN_DEC_CONV (10000) +#define BN_DEC_FMT1 "%u" +#define BN_DEC_FMT2 "%04u" +#define BN_DEC_NUM 4 +#define BN_HEX_FMT "%04X" +#endif + +#ifdef TEST_EIGHT_BIT +#define EIGHT_BIT /* comment to stop editing */ +#endif + +#ifdef EIGHT_BIT +#undef BN_ILONG +#define BN_ILONG unsigned int +#ifndef BN_DIV2W +#define BN_DIV2W +#endif +#ifdef TEST_EIGHT_BIT +#define BN_ULLONG unsigned int +#define BN_ULONG unsigned int +#define BN_LONG int +#else +#define BN_ULLONG unsigned short +#define BN_ULONG unsigned char +#define BN_LONG char +#endif +#define BN_BITS 16 +#define BN_BYTES 1 +#define BN_BITS2 8 +#define BN_BITS4 4 +#define BN_MASK (0xffff) +#define BN_MASK2 (0xff) +#define BN_MASK2lh (0xf) +#define BN_MASK2l (0xf) +#define BN_MASK2h1 (0xf8) +#define BN_MASK2h (0xf0) +#define BN_TBIT (0x80) +#define BN_DEC_CONV (100) +#define BN_DEC_FMT1 "%u" +#define BN_DEC_FMT2 "%02u" +#define BN_DEC_NUM 2 +#define BN_HEX_FMT "%02X" +#endif + +#ifdef BIGNUM +#undef BIGNUM +#endif + +#define BN_FLG_MALLOCED 0x01 +#define BN_FLG_STATIC_DATA 0x02 +#define BN_FLG_FREE 0x8000 /* used for debuging */ +#define BN_CTX_FLG_ABORT 0x4000 /* used for aborting RSA operations*/ +#define BN_set_flags(b,n) ((b)->flags|=(n)) +#define BN_get_flags(b,n) ((b)->flags&(n)) +#define BN_CTX_set_flags(b,n) ((b)->flags|=(n)) +#define BN_CTX_get_flags(b,n) ((b)->flags&(n)) + +#ifndef HEADER_COMMON_BN_H_TYPEDEF_DEF +#define HEADER_COMMON_BN_H_TYPEDEF_DEF +typedef struct bignum_st BIGNUM; +typedef struct bignum_ctx BN_CTX; +typedef struct bn_mont_ctx_st BN_MONT_CTX; +typedef struct bn_recp_ctx_st BN_RECP_CTX; +typedef struct bn_prime_ctx_st BN_PRIME_CTX; +typedef struct bn_blind_ctx_st BN_BLIND_CTX; +typedef struct bn_blind_meth_st BN_BLIND_METH; +#endif + +typedef struct bn_mod_exp_meth_st BN_ME_METH; +typedef struct bn_mod_exp_ctx_st BN_ME_CTX; + + +/* The data array d must always have an extra 'valid' word in location + * bn->d[bn->max]. It must be ok for reading. This is needed if + * BN_MUL_LATENCY is defined. + */ +struct bignum_st + { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */ + int top; /* Index of last used d +1. */ + /* The next are internal book keeping for bn_expand. */ + int max; /* Size of the d array. */ + int neg; /* one if the number is negative */ + int flags; + }; + +/* Used for temp variables */ +#define BN_CTX_NUM 12 +struct bignum_ctx + { + int tos; + BIGNUM bn[BN_CTX_NUM+1]; + int flags; + R_SURRENDER *surrender; + }; + +#if defined(WIN64) || defined(__ia64__) || defined(CPU_IA64) +#define BN_USHORT unsigned int +#else +#define BN_USHORT unsigned short +#endif + +/* Used for prime number generation */ +struct bn_prime_ctx_st + { + BN_USHORT *primes; + BN_USHORT *mods; + int num_primes; + int prime_checks; + R_SURRENDER *surrender; + R_RANDOM *random; + int flags; + }; + +struct bn_blind_ctx_st + { + int init; + BN_BLIND_METH *meth; + BIGNUM B; + BIGNUM Bi; + BIGNUM mod; + }; + +struct bn_blind_meth_st + { + void (*init) (BN_BLIND_CTX *); + void (*ctx_free)(BN_BLIND_CTX *); + int (*set) (BN_BLIND_CTX *,R_RANDOM *,BIGNUM *,BIGNUM *, BN_ME_CTX *,BN_CTX *); + int (*convert) (BN_BLIND_CTX *,BIGNUM *,BN_CTX *); + int (*invert) (BN_BLIND_CTX *,BIGNUM *,BN_CTX *); + int (*update) (BN_BLIND_CTX *,BN_CTX *); + int (*copy) (BN_BLIND_CTX *,BN_BLIND_CTX *); + }; + +/* Used for montgomery multiplication */ +struct bn_mont_ctx_st + { + int use_word; /* 0 for word form, 1 for long form */ + int ri; /* number of bits in R */ + int riw; /* number of words in R */ + BIGNUM RR; /* used to convert to montgomery form */ + BIGNUM N; /* The modulus */ + BIGNUM Ni; /* The inverse of N */ + BN_ULONG n0; /* word form of inverse, normally only one of + * Ni or n0 is defined */ + int flags; + }; + +/* Used by the recursive exponentiation implementations */ +typedef struct bn_mod_exp_rec_meth_st + { +#ifndef NOPROTO + void (PRE_CCONV CCONV *mul)(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b); + void (PRE_CCONV CCONV *sqr)(BN_ULONG *r, BN_ULONG *a); + void (PRE_CCONV CCONV *low_mul)(); +#else + void (PRE_CCONV CCONV *mul)(); + void (PRE_CCONV CCONV *sqr)(); + void (PRE_CCONV CCONV *low_mul)(); +#endif + } BN_MOD_EXP_REC_METH; + +/* If this flag is set, if there is a custom method for a modulus + * two times larger, use it. This is mostly mean for use on the + * itanium where a 512*512 routine is 10 times faster than the C + * code version, so we need to detect that we can turn of CRT + * for RSA if there is an native IA64 512*512 present. + */ +#define BN_ME_FLG_FAST_ASM 0x0001 + +struct bn_mod_exp_meth_st + { + int num; /* Word size we target */ + char *name; /* Identify the method */ +#ifndef NOPROTO + int (*useit)(const BN_ME_METH *meth); + /* If 'power' is null, reuse the old one */ + int (*mod_exp)(BN_ME_CTX *mctx,BIGNUM *r,BIGNUM *a,BIGNUM *p, + BN_CTX *ctx); + /* Create the BN_ME_CTX */ + int (*init_ctx)(const BN_ME_METH *meth,BN_ME_CTX **mctx); + /* Get rid of it */ + int (*free_ctx)(BN_ME_CTX *mctx); + /* Assign the modulus */ + int (*set)(BN_ME_CTX *mctx,BIGNUM *n,int cmd,int flags,BN_CTX *ctx); +#else + int (*useit)(); + int (*mod_exp)(); + int (*init_ctx)(); + int (*free_ctx)(); + int (*set)(); +#endif + int argi; + char *argp; /* 'Extra stuff' */ + }; + +#define BN_ME_METH_TABLE_MAX 32 +/* Used in BN_library_init */ +#define BN_INIT_LAST 0x00 +#define BN_INIT_BN_ME_METH 0x01 + +#define BN_BNME_F_DEFAULT 0x01 +/* Used only when loading, kept as bits internally, normally loaded as + * words */ +#define BN_BNME_F_BITS 0x02 +typedef struct bn_me_meth_info_st + { +#ifndef NOPROTO + const BN_ME_METH *(*meth)(void); +#else + const BN_ME_METH *(*meth)(); +#endif + int min; + int max; + int flags; + } BN_ME_METH_INFO; + +#define BN_ME_SET_MOD 0x01 +#define BN_ME_SET_BASE 0x02 +#define BN_ME_SET_EXP 0x03 +#define BN_ME_SET_FLG_NO_LOOKUP 0x01 /* Passed to BN_ME_CTX_set() */ + +#define BN_FLG_CACHE 0x10 /* Cache values */ +#define BN_ME_FLG_BASE 0x40 /* base has been cached */ +#define BN_ME_FLG_EXP 0x80 /* power has been cached */ +/* When one of these structures is setup, it is intended that the + * base or power, if not null, will be used for the current calculation. + * If the base and/or power are cached, they will only be used if the input + * value is null. + * For RSA, the power would normally be set. + * For DH, the base and power would be set. The initial value generated + * would be the public key, which is exchanged. The phase2 part would + * change the base but not the power. + * For DSA signing, a fixed base is used, but a random power. + * For DSA verification, there are two bases and two powers, + * a^p%m * b^q%m + * One way to implement this is to use a special function to + * generate a composite power value, and or a special base form. + * The other option is to have a special function to generate + * the 'base' array. The problem is that we are exponentiating with + * a 3 value power value, instead of the normal two. It should be possible + * to use the standard a^b%m function. + */ +struct bn_mod_exp_ctx_st + { + const BN_ME_METH *meth; + char *callback; + char *cb_arg; + int flags; + /* Evil hack for storage of data values, it should really be here + * other than the first value */ + char *modulus; /* eg BN_MONT_CTX */ + char *power; /* eg power representation */ + char *base; /* eg base representation */ + char *arg; + }; + +/* Used for reciprocal division/mod functions + * It cannot be shared between threads + */ +struct bn_recp_ctx_st + { + BIGNUM N; /* the divisor */ + BIGNUM Nr; /* the reciprocal */ + int num_bits; + int shift; + int flags; + }; + +typedef struct bn_rec_st + { + int depth; + int n; +#ifndef NOPROTO + void (PRE_CCONV CCONV *mul)(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b); + void (PRE_CCONV CCONV *sqr)(BN_ULONG *r, BN_ULONG *a); + void (PRE_CCONV CCONV *low_mul)(); +#else + void (PRE_CCONV CCONV *mul)(); + void (PRE_CCONV CCONV *sqr)(); + void (PRE_CCONV CCONV *low_mul)(); +#endif + } BN_REC; + +#define BN_to_montgomery(r,a,mont,ctx) BN_mod_mul_montgomery(\ + r,a,&((mont)->RR),(mont),ctx) + +#define BN_prime_checks (5) + +#define BN_num_bytes(a) ((BN_num_bits(a)+7)/8) +#define BN_length(a) ((a)->top * BN_BYTES) +#define BN_is_word(a,w) (((a)->top == 1) && ((a)->d[0] == (BN_ULONG)(w))) +#define BN_is_zero(a) (((a)->top == 0) || BN_is_word(a,0)) +#define BN_is_one(a) (BN_is_word((a),1)) +#define BN_is_odd(a) (((a)->top > 0) && ((a)->d[0] & 1)) +#define BN_one(a) (BN_set_word((a),(BN_ULONG)1)) +#define BN_zero(a) (BN_set_word((a),(BN_ULONG)0)) + +/*#define BN_ascii2bn(a) BN_hex2bn(a) */ +/*#define BN_bn2ascii(a) BN_bn2hex(a) */ + +#define bn_expand(n,b) ((((((b+BN_BITS2-1))/BN_BITS2)) <= (n)->max)?\ + (n):bn_expand2((n),(b)/BN_BITS2+1)) +#define bn_wexpand(n,b) (((b) <= (n)->max)?(n):bn_expand2((n),(b))) + +#ifdef SMALL_CODE_SIZE +void bn_zexpand(BIGNUM *a,int n); +void bn_fix_top(BIGNUM *a); +#else +#define bn_zexpand(a,n) \ + if ((a)->top < n) \ + { \ + int i; \ + bn_wexpand((a),n); \ + if ((a)->d!=NULL) \ + { \ + for (i=(a)->top; id[i]=0; \ + } \ + } + +#define bn_fix_top(a) \ + { \ + BN_ULONG *ftl; \ + if ((a)->top > 0) \ + { \ + for (ftl= &((a)->d[(a)->top-1]); (a)->top > 0; (a)->top--) \ + if (*(ftl--)) break; \ + } \ + } +#endif + +#define BN_MONT_CTX_set(a,b,c) BN_MONT_CTX_set_word((a),(b),(c)) + +#ifndef NOPROTO + + +const BN_ME_METH *BN_ME_METH_word(void); +const BN_ME_METH *BN_ME_METH_full(void); + +#if (defined(BN_MUL_COMBA) || defined(BN_SQR_COMBA)) + +/* word4 - used for 64bit multiprime*/ +const BN_ME_METH *BN_ME_METH_word4(void); +const BN_ME_METH *BN_ME_METH_rec4_word8(void); +const BN_ME_METH *BN_ME_METH_rec4_word16(void); +const BN_ME_METH *BN_ME_METH_rec4_word32(void); +const BN_ME_METH *BN_ME_METH_rec4_word64(void); +const BN_ME_METH *BN_ME_METH_rec4_word128(void); + +/* word6 - used for 64bit multiprime*/ +const BN_ME_METH *BN_ME_METH_word6(void); +const BN_ME_METH *BN_ME_METH_rec6_word12(void); +const BN_ME_METH *BN_ME_METH_rec6_word24(void); +const BN_ME_METH *BN_ME_METH_rec6_word48(void); +const BN_ME_METH *BN_ME_METH_rec6_word96(void); + +const BN_ME_METH *BN_ME_METH_word8(void); +const BN_ME_METH *BN_ME_METH_rec8_word16(void); +const BN_ME_METH *BN_ME_METH_rec8_word32(void); +const BN_ME_METH *BN_ME_METH_rec8_word64(void); +const BN_ME_METH *BN_ME_METH_rec8_word128(void); +const BN_ME_METH *BN_ME_METH_rec8_word256(void); + +const BN_ME_METH *BN_ME_METH_word11(void); +const BN_ME_METH *BN_ME_METH_rec11_word22(void); +const BN_ME_METH *BN_ME_METH_rec11_word44(void); +const BN_ME_METH *BN_ME_METH_rec11_word88(void); + +const BN_ME_METH *BN_ME_METH_word16(void); +const BN_ME_METH *BN_ME_METH_rec16_word32(void); +const BN_ME_METH *BN_ME_METH_rec16_word64(void); +const BN_ME_METH *BN_ME_METH_rec16_word128(void); +const BN_ME_METH *BN_ME_METH_rec16_word256(void); + +#endif + +#ifdef CPU_IA64 +const BN_ME_METH *BN_ME_METH_ia64_384(void); +const BN_ME_METH *BN_ME_METH_ia64_512(void); +const BN_ME_METH *BN_ME_METH_ia64_1024(void); +#endif + +#if (defined(CPU_SPARC_V8PLUS) || defined (CPU_SPARC_V9)) +const BN_ME_METH *BN_ME_METH_usparc(void); +const BN_ME_METH *BN_ME_METH_usparc_352(void); +const BN_ME_METH *BN_ME_METH_usparc_512(void); +#endif + +#if 1 || defined(CPU_X86) +const BN_ME_METH *BN_ME_METH_pentium4_29(void); +const BN_ME_METH *BN_ME_METH_pentium4_28(void); +#endif + +/* NCipher Nfast hardware accelerator method prototype */ +const BN_ME_METH *BN_ME_METH_nfast(void); + + +BIGNUM *BN_value_one(void); +const char * BN_options(void); +BN_CTX *BN_CTX_new(void); +void BN_CTX_init(BN_CTX *c); +void BN_CTX_free(BN_CTX *c); +#ifndef NO_BN_RAND +int BN_rand(BIGNUM *rnd, R_RANDOM *rand, int bits, int top,int bottom); +#endif +int BN_num_bits(BIGNUM *a); +int BN_num_bits_word(BN_ILONG); +BIGNUM *BN_new(void); +void BN_init(BIGNUM *); +void BN_clear_free(BIGNUM *a); +BIGNUM *BN_copy(BIGNUM *a, BIGNUM *b); +BIGNUM *BN_bin2bn(unsigned char *s,int len,BIGNUM *ret); +int BN_bn2bin(BIGNUM *a, unsigned char *to); +BIGNUM *BN_mpi2bn(unsigned char *s,int len,BIGNUM *ret); +int BN_bn2mpi(BIGNUM *a, unsigned char *to); +int BN_sub(BIGNUM *r, BIGNUM *a, BIGNUM *b); +int BN_usub(BIGNUM *r, BIGNUM *a, BIGNUM *b); +int BN_uadd(BIGNUM *r, BIGNUM *a, BIGNUM *b); +int BN_add(BIGNUM *r, BIGNUM *a, BIGNUM *b); +int BN_mod(BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx); +int BN_div(BIGNUM *dv, BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx); +int BN_mul(BIGNUM *r, BIGNUM *a, BIGNUM *b,BN_CTX *ctx); +int BN_sqr(BIGNUM *r, BIGNUM *a,BN_CTX *ctx); +BN_ULONG BN_mod_word(BIGNUM *a, BN_ULONG w); +BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w); +int BN_mul_word(BIGNUM *a, BN_ULONG w); +int BN_add_word(BIGNUM *a, BN_ULONG w); +int BN_sub_word(BIGNUM *a, BN_ULONG w); +int BN_set_word(BIGNUM *a, BN_ULONG w); +BN_ULONG BN_get_word(BIGNUM *a); +int BN_cmp(BIGNUM *a, BIGNUM *b); +void BN_free(BIGNUM *a); +int BN_is_bit_set(BIGNUM *a, int n); +int BN_lshift(BIGNUM *r, BIGNUM *a, int n); +int BN_lshift1(BIGNUM *r, BIGNUM *a); +int BN_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p,BN_CTX *ctx); +int BN_mod_exp(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m,BN_CTX *ctx); +int BN_mod_exp_mont(BIGNUM *r, BIGNUM *a, BIGNUM *p, BIGNUM *m,BN_CTX *ctx, + BN_MONT_CTX *m_ctx); +int BN_mod_exp2_mont(BIGNUM *r, BIGNUM *a1, BIGNUM *p1,BIGNUM *a2, + BIGNUM *p2,BIGNUM *m,BN_CTX *ctx,BN_MONT_CTX *m_ctx); +int BN_mod_exp_simple(BIGNUM *r, BIGNUM *a, BIGNUM *p, + BIGNUM *m,BN_CTX *ctx); +int BN_mask_bits(BIGNUM *a,int n); +int BN_mod_mul(BIGNUM *ret, BIGNUM *a, BIGNUM *b, BIGNUM *m, + BN_CTX *ctx); +#if !defined(WIN16) && !defined(NO_FP_API) +int BN_print_fp(FILE *fp, BIGNUM *a); +#endif +#ifdef HEADER_COMMON_BIO_H +int BN_print(BIO *fp, BIGNUM *a); +#else +/* int BN_print(char *fp, BIGNUM *a); */ +#endif +int BN_reciprocal(BIGNUM *r, BIGNUM *m, int len, BN_CTX *ctx); +int BN_rshift(BIGNUM *r, BIGNUM *a, int n); +int BN_rshift1(BIGNUM *r, BIGNUM *a); +void BN_clear(BIGNUM *a); +BIGNUM *bn_expand2(BIGNUM *b, int bits); +BIGNUM *BN_dup(BIGNUM *a); +int BN_ucmp(BIGNUM *a, BIGNUM *b); +int BN_set_bit(BIGNUM *a, int n); +int BN_clear_bit(BIGNUM *a, int n); +char * BN_bn2hex(BIGNUM *a); +char * BN_bn2dec(BIGNUM *a); +int BN_hex2bn(BIGNUM **a,char *str); +int BN_dec2bn(BIGNUM **a,char *str); +int BN_gcd(BIGNUM *r,BIGNUM *in_a,BIGNUM *in_b,BN_CTX *ctx); +BIGNUM *BN_mod_inverse(BIGNUM *ret,BIGNUM *a, BIGNUM *n,BN_CTX *ctx); +/* Return R, where it is R*(1< +#include +#include "r_error.h" +#include "err.h" +#include +#else //NITRO +#include "r_error.h" +#ifndef NULL +#define NULL 0 +#endif +#endif + +#ifndef STANDALONE +#include "r_com.h" +#else +#if 0 //RSA +#define NO_STDLIB_MAPPING +#define Malloc(a) malloc(a) +#define Free(a) free(a) +#define Memset(a,b,c) memset(a,b,c) +#define Memcpy(a,b,c) memcpy(a,b,c) +#else // Nitro +#define NO_STDLIB_MAPPING +#include "acmemory.h" +#define Malloc(a) ACMemory_Alloc(a) +#define Free(a) ACMemory_Free(a) +#define Memset(a,b,c) ACMemory_Memset(a,b,c) +#define Memcpy(a,b,c) ACMemory_Memcpy(a,b,c) +#endif +#endif + +/* TEMP FIX */ +#undef BNerr +#define BNerr(a,b) +#include "bn.h" + +#define BN_EXP_TABLE_SIZE 16 + +/* see the bn_limit_ fields which are the start of a runtime + * tunable set of values to match these fixed compile-time constants + */ +/* Pentium pro 16,16,16,32,64 */ +/* Alpha 16,16,16,16.64 */ +/* StrongARM */ +#define BN_MULL_SIZE_NORMAL (16) /* 32 */ +#define BN_MUL_RECURSIVE_SIZE_NORMAL (16) /* 32 */ /* less than */ +#define BN_SQR_RECURSIVE_SIZE_NORMAL (16) /* 32 */ +#define BN_MUL_LOW_RECURSIVE_SIZE_NORMAL (32) /* 32 */ +#define BN_MONT_CTX_SET_SIZE_WORD (64) /* 32 */ + +/************************************************************* + * Using the long long type + */ +#define Lw(t) (((BN_ULONG)(t))&BN_MASK2) +#define Hw(t) (((BN_ULONG)((t)>>BN_BITS2))&BN_MASK2) + +/* These are used for internal error checking and are not normally used */ +#ifdef BN_DEBUG +#define bn_check_top(a) \ + { if ( ((a)->top < 0) || \ + ((a)->top > (a)->max) || \ + (((a)->top == 0) && (a)->neg) || \ + (((a)->top == 1) && (a->d[0] == 0))) \ + { char *nullp=NULL; *nullp='z'; } } +#define bn_check_num(a) if ((a) < 0) { char *nullp=NULL; *nullp='z'; } +#define bn_assert(a) if (!(a)) { char *nullp=NULL; *nullp='z'; } +#define bn_set_used_check(l,size,num) bn_su_check(l,size,num) +#ifdef BN_DEBUG2 +#define bn_do_used_check(fp,str,l,size,num) bn_du_check(fp,str,l,size,num) +#else +#define bn_do_used_check(fp,str,l,size,num) +#endif +#else +#define bn_assert(a) +#define bn_check_top(a) +#define bn_check_num(a) +#define bn_set_used_check(l,size,num) +#define bn_do_used_check(fp,str,l,size,num) +#endif + + +/*********************************************** +* IA64 32 bit build SWIZZLE code +* This essentially casts our points which are +* 32bits under abi32 to 64bit unsigned long +* longs and then grabs the top two bits of the +* pointer and places it in the 2nd and 3rd bits +* of the unsigned long long. +**********************************************/ +#ifdef HPUX_IA64_32 +#define SWIZLLE(VALUE) ((((unsigned long long)(VALUE) & 0xc0000000LL) <<31)\ +|((unsigned long long)(VALUE))) +#else +#define SWIZZLE(VALUE) (VALUE) +#endif + +#define bn_neg_words(a,n) \ + { \ + int iii; \ + \ + for (iii=0; iiimax=(r)->top,BN_set_flags((r),BN_FLG_STATIC_DATA)) +#else +#define bn_set_max(r) +#endif + +/* These macros are used to 'take' a section of a bignum for read only use */ +#define bn_set_low(r,a,n) \ + { \ + (r)->top=((a)->top > (n))?(n):(a)->top; \ + (r)->d=(a)->d; \ + (r)->neg=(a)->neg; \ + (r)->flags|=BN_FLG_STATIC_DATA; \ + bn_set_max(r); \ + } + +#define bn_set_high(r,a,n) \ + { \ + if ((a)->top > (n)) \ + { \ + (r)->top=(a)->top-n; \ + (r)->d= &((a)->d[n]); \ + } \ + else \ + (r)->top=0; \ + (r)->neg=(a)->neg; \ + (r)->flags|=BN_FLG_STATIC_DATA; \ + bn_set_max(r); \ + } + +/* #define bn_expand(n,b) ((((b)/BN_BITS2) <= (n)->max)?(n):bn_expand2((n),(b))) */ + +#ifdef BN_LLONG +#define mul_add(r,a,w,c) { \ + BN_ULLONG t; \ + t=(BN_ULLONG)w * (a) + (r) + (c); \ + (r)= Lw(t); \ + (c)= Hw(t); \ + } + +#define mul(r,a,w,c) { \ + BN_ULLONG t; \ + t=(BN_ULLONG)w * (a) + (c); \ + (r)= Lw(t); \ + (c)= Hw(t); \ + } + +#else +/************************************************************* + * No long long type + */ + +#define LBITS(a) ((a)&BN_MASK2l) +#define HBITS(a) (((a)>>BN_BITS4)&BN_MASK2lh) +#define L2HBITS(a) ((BN_ULONG)((a)&BN_MASK2lh)<>(BN_BITS4-1); \ + m =((m&BN_MASK2l)<<(BN_BITS4+1))&BN_MASK2; \ + l=(l+m)&BN_MASK2; if (l < m) h++; \ + (lo)=l; \ + (ho)=h; \ + } + +#if 0 +#define mul_add(r,a,bl,bh,b_hl,c) { \ + BN_ULONG l,h; \ + BN_ULONG lt,mt; \ + \ + h= (a); \ + l=LBITS(h); \ + h=HBITS(h); \ + mt=bl*l; \ + lt=mt+c+(r); \ + c=bh*h; \ + mt+=c+(l-h)*b_hl; \ + mt+=(lt>>BN_BITS4); \ + (r)=(lt&BN_MASK2l)|((mt&BN_MASK2l)<>BN_BITS4); \ + } +#else /* Normal version */ +#define mul_add(r,a,bl,bh,b_hl,c) { \ + BN_ULONG l,h; \ + \ + h= (a); \ + l=LBITS(h); \ + h=HBITS(h); \ + mul64(l,h,(bl),(bh)); \ + \ + /* non-multiply part */ \ + l=(l+(c))&BN_MASK2; if (l < (c)) h++; \ + (c)=(r); \ + l=(l+(c))&BN_MASK2; if (l < (c)) h++; \ + (c)=h&BN_MASK2; \ + (r)=l; \ + } +#endif + +#define mul(r,a,bl,bh,c) { \ + BN_ULONG l,h; \ + \ + h= (a); \ + l=LBITS(h); \ + h=HBITS(h); \ + mul64(l,h,(bl),(bh)); \ + \ + /* non-multiply part */ \ + l+=(c); if ((l&BN_MASK2) < (c)) h++; \ + (c)=h&BN_MASK2; \ + (r)=l&BN_MASK2; \ + } + +#endif + +#ifndef BN_MUL_COMBA +#define bn_mul_comba4(r,a,b) bn_mul_normal(r,a,4,b,4) +#define bn_mul_comba5(r,a,b) bn_mul_normal(r,a,5,b,5) +#define bn_mul_comba6(r,a,b) bn_mul_normal(r,a,6,b,6) +#define bn_mul_comba8(r,a,b) bn_mul_normal(r,a,8,b,8) +#define bn_mul_comba11(r,a,b) bn_mul_normal(r,a,11,b,11) +#define bn_mul_comba12(r,a,b) bn_mul_normal(r,a,12,b,12) +#define bn_mul_comba16(r,a,b) bn_mul_normal(r,a,16,b,16) +#endif +#if 1 +#ifndef BN_SQR_COMBA +#define bn_sqr_comba4(r,a) bn_mul_normal(r,a,4,a,4) +#define bn_sqr_comba5(r,a) bn_mul_normal(r,a,5,a,5) +#define bn_sqr_comba6(r,a) bn_mul_normal(r,a,6,a,6) +#define bn_sqr_comba8(r,a) bn_mul_normal(r,a,8,a,8) +#define bn_sqr_comba11(r,a) bn_mul_normal(r,a,11,a,11) +#define bn_sqr_comba12(r,a) bn_mul_normal(r,a,12,a,12) +#define bn_sqr_comba16(r,a) bn_mul_normal(r,a,16,a,16) +#endif +#else +#ifndef BN_SQR_COMBA +#define bn_sqr_comba4(r,a) bn_mul_comba4(r,a,a) +#define bn_sqr_comba5(r,a) bn_mul_comba5(r,a,a) +#define bn_sqr_comba6(r,a) bn_mul_comba6(r,a,a) +#define bn_sqr_comba8(r,a) bn_mul_comba8(r,a,a) +#define bn_sqr_comba11(r,a) bn_mul_comba11(r,a,a) +#define bn_sqr_comba12(r,a) bn_mul_comba12(r,a,a) +#define bn_sqr_comba16(r,a) bn_mul_comba16(r,a,a) +#endif +#endif +#ifndef BN_REDUCE_COMBA +#define r0_bn_mont_comba4(r,a,n,num,n0) bn_from_montgomery_words(r,a,n,num,n0) +#define r0_bn_mont_comba5(r,a,n,num,n0) bn_from_montgomery_words(r,a,n,num,n0) +#define r0_bn_mont_comba6(r,a,n,num,n0) bn_from_montgomery_words(r,a,n,num,n0) +#define r0_bn_mont_comba8(r,a,n,num,n0) bn_from_montgomery_words(r,a,n,num,n0) +#define r0_bn_mont_comba11(r,a,n,num,n0) bn_from_montgomery_words(r,a,n,num,n0) +#define r0_bn_mont_comba12(r,a,n,num,n0) bn_from_montgomery_words(r,a,n,num,n0) +#define r0_bn_mont_comba16(r,a,n,num,n0) bn_from_montgomery_words(r,a,n,num,n0) +#endif + +#ifndef NOPROTO + +BIGNUM *bn_expand2(BIGNUM *b, int bits); + +#ifdef X86_ASM +void bn_add_words(BN_ULONG *r,BN_ULONG *a,int num); +#endif + +#else + +BIGNUM *bn_expand2(); +#ifdef X86_ASM +BN_ULONG bn_add_words(); +#endif + +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_COMMON_BN_LCL_H */ + +void bn_mul_low_recursive(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b,int n2,BN_ULONG *t); +void bn_mul_high(BN_ULONG *r,BN_ULONG *a,BN_ULONG *b,BN_ULONG *l,int n2, BN_ULONG *t); +int BN_gen_exp_string(unsigned char *str, BIGNUM *p, int bits); +void bn_from_montgomery_rec_full(BN_ULONG *rp, BN_ULONG *ap, + BN_ULONG *np, BN_ULONG *nip, BN_ULONG *tmp,BN_REC *rec); + +int bn_mont_ctx_new_word(const BN_ME_METH *meth, BN_ME_CTX **retp); + diff --git a/build/libraries_sysmenu/acsign/ARM9/include/bn_thx.h b/build/libraries_sysmenu/acsign/ARM9/include/bn_thx.h new file mode 100644 index 00000000..451b3e4d --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/bn_thx.h @@ -0,0 +1,317 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ +/***************************************************************************** + * Copyright (c). 2001 RSA Security Inc. All rights reserved. + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + ****************************************************************************/ +/** + * @file bn_thx.h + * @brief header file created for used as interface defines for systems + * containing hetergeneous environments where some bn operations + * will be performed in isolation from the rest of the library + */ +#ifndef HEADER_COMMON_BN_THX_H +#define HEADER_COMMON_BN_THX_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* These defines are required on systems so that the mod_exp code + * to be used in isolation from the bn operation with library will work, + * if these are not available, the header files with equivalent functionality + * should be added inside a CPU or Operating system define + */ +#ifndef NO_STDIO_H +#include +#endif + +#ifndef NO_STDLIB_H +#include +#endif + +#ifndef NO_STRING_H +#include +#endif + +/* Interface for ARM/DSP systems, this interface requires only + * the standard defines and includes at the moment + */ +#ifdef CPU_TMS320 +#define THX_RECIPIENT +#define CPU_DSP +#endif + +#ifdef THX_RECIPIENT + +#ifndef restrict +#define restrict +#endif + +#ifndef Malloc +#define Malloc malloc +#endif + +#ifndef Memcpy +#define Memcpy memcpy +#endif + +#ifndef Memmove +#define Memmove memmove +#endif + +#ifndef Memset +#define Memset memset +#endif + +#ifndef Free +#define Free free +#endif + +#endif /* THX_RECIPIENT */ + +#ifndef THX_RECIPIENT /* not the recipient, we must be the caller */ + +#include "bn_lcl.h" + +#endif /* ! THX_RECIPIENT */ + +/* The follow define protected inclusions are excerpts from the + * header file bn.h, this has been done, so that code written for the + * THX systems can be used in isolation from the library + * This code may need to be updated in line with changes to the bn.h + * header file. + */ +#ifndef HEADER_COMMON_BN_H +#define HEADER_COMMON_BN_H + +#if !defined(CCONV) +#define CCONV +#endif + +#ifndef PRE_CCONV +#define PRE_CCONV +#endif + +/* convert from the new to the old option names */ +#if defined(OPT_BN_LLONG) +#define BN_LLONG /* comment to make sure Configure leaves this alone */ +#endif + +#if defined(OPT_32_BIT_INT) || defined(OPT_32_BIT) +#define THIRTY_TWO_BIT +#endif + +#define BN_ILONG BN_ULONG + +#ifdef THIRTY_TWO_BIT +#define BN_ULLONG unsigned long long +#ifdef OPT_32_BIT_INT +#define BN_ULONG unsigned int +#define BN_LONG int +#else +#define BN_ULONG unsigned long +#define BN_LONG long +#endif +#define BN_BITS 64 +#define BN_BYTES 4 +#define BN_BITS2 32 +#define BN_BITS4 16 +/* This is needed because the Watcom compiler pre-processor + * under QNX is perverted and tries to parses the 'LL' + * part even though it is never used. + */ +#ifdef BN_LLONG +#define BN_MASK (0xffffffffffffffffL) +#endif +#define BN_MASK2 (0xffffffffL) +#define BN_MASK2l (0xffff) +#define BN_MASK2lh (0xffff) +#define BN_MASK2h1 (0xffff8000L) +#define BN_MASK2h (0xffff0000L) +#define BN_TBIT (0x80000000L) +#define BN_DEC_CONV (1000000000L) +#define BN_DEC_FMT1 "%lu" +#define BN_DEC_FMT2 "%09lu" +#define BN_DEC_NUM 9 +#define BN_HEX_FMT "%08lX" +#endif + +#define BN_EXP_TABLE_SIZE 16 + +typedef struct bignum_st BIGNUM; + +struct bignum_st + { + BN_ULONG *d; /* Pointer to an array of 'BN_BITS2' bit chunks. */ + int top; /* Index of last used d +1. */ + /* The next are internal book keeping for bn_expand. */ + int max; /* Size of the d array. */ + int neg; /* one if the number is negative */ + int flags; + }; + +PRE_CCONV BN_ULONG CCONV bn_mul_add_words(BN_ULONG *rp,BN_ULONG *ap, + int num, BN_ULONG w); +PRE_CCONV BN_ULONG CCONV bn_mul_words(BN_ULONG *rp, BN_ULONG *ap, + int num, BN_ULONG w); +PRE_CCONV void CCONV bn_sqr_words(BN_ULONG *rp, BN_ULONG *ap, int num); +BN_ULONG CCONV bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d); +PRE_CCONV BN_ULONG CCONV bn_add_words(BN_ULONG *rp, BN_ULONG *ap, + BN_ULONG *bp,int num); +PRE_CCONV BN_ULONG CCONV bn_sub_words(BN_ULONG *rp, BN_ULONG *ap, + BN_ULONG *bp,int num); + +#ifndef BN_ME_METH +#define BN_ME_METH void +#endif + +#endif /* ! HEADER_COMMON_BN_H */ + +/* The follow define protected inclusions are excerpts from the + * header file r_error.h, this has been done, so that code written for the + * THX systems can be used in isolation from the library + * This code may need to be updated in line with changes to the r_error.h + * header file. + */ +#ifndef HEADER_COMMON_R_ERROR_H +#define HEADER_COMMON_R_ERROR_H + +/* The FATAL_INTERNAL_ERROR is a flag that is set with the following + * error codes: + * R_ERROR_INVALID_STATE + * R_ERROR_INIT_NOT_CALLED + * R_ERROR_SHOULD_NOT_HAVE_BEEN_CALLED + */ +#define R_ERROR_FATAL_INTERNAL_ERROR 64 + +/* The BAD_PARAMETER is a flag that is set with the following error + * codes: + * R_ERROR_NULL_ARG + * R_ERROR_BUFFER_TOO_SMALL + * R_ERROR_BAD_VALUE + * R_ERROR_BAD_RANGE + * R_ERROR_BAD_FORMAT + * R_ERROR_BAD_TYPE + * R_ERROR_BAD_DATA + * R_ERROR_BAD_LENGTH + */ +#define R_ERROR_BAD_PARAMETER 32 + +/* Base value for all general errors used through all products */ +#define R_ERROR_BASE 10000 + +#define R_ERROR_NONE 0 + +#define R_ERROR_FAILED (R_ERROR_BASE+1) +#define R_ERROR_IO (R_ERROR_BASE+2) +#define R_ERROR_PROTOCOL (R_ERROR_BASE+3) +#define R_ERROR_EOF (R_ERROR_BASE+4) +#define R_ERROR_ALLOC_FAILURE (R_ERROR_BASE+5) +#define R_ERROR_EVAL_RESTRICTION (R_ERROR_BASE+6) +#define R_ERROR_EVAL_EXPIRED (R_ERROR_BASE+7) +#define R_ERROR_NOT_FOUND (R_ERROR_BASE+8) +#define R_ERROR_NOT_AVAILABLE (R_ERROR_BASE+9) +#define R_ERROR_NOT_IMPLEMENTED (R_ERROR_BASE+10) +#define R_ERROR_NOT_SUPPORTED (R_ERROR_BASE+11) +#define R_ERROR_INVALID_STATE \ + ((R_ERROR_BASE+12) | R_ERROR_FATAL_INTERNAL_ERROR) +#define R_ERROR_INIT_NOT_CALLED \ + ((R_ERROR_BASE+13) | R_ERROR_FATAL_INTERNAL_ERROR) +#define R_ERROR_SHOULD_NOT_HAVE_BEEN_CALLED \ + ((R_ERROR_BASE+14) | R_ERROR_FATAL_INTERNAL_ERROR) +#define R_ERROR_METHOD_UNDEFINED \ + ((R_ERROR_BASE+15) | R_ERROR_FATAL_INTERNAL_ERROR) +#define R_ERROR_BUFFER_TOO_SMALL \ + ((R_ERROR_BASE+16) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_NULL_ARG ((R_ERROR_BASE+17) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_BAD_VALUE ((R_ERROR_BASE+18) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_BAD_RANGE ((R_ERROR_BASE+19) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_BAD_FORMAT ((R_ERROR_BASE+20) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_BAD_TYPE ((R_ERROR_BASE+21) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_BAD_DATA ((R_ERROR_BASE+22) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_BAD_LENGTH ((R_ERROR_BASE+23) | R_ERROR_BAD_PARAMETER) +#define R_ERROR_RCOM_LIBRARY_NOT_SUPPORTED (R_ERROR_BASE+24) + +/* Resource Manager base for errors */ +#define R_COM_ERR_LIB_CTX_BASE 10100 + +#endif /* HEADER_COMMON_R_ERROR_H */ + + +const BN_ME_METH *BN_ME_METH_thxc(void); +/** + * @note THX code only needs to store rr, n0, str + * + */ +typedef struct thxc_mont_ctx_st + { + BIGNUM *rr; + unsigned char *str; + unsigned int str_len; + BN_ULONG n0; + } THXC_MONT_CTX; + + +int Rx_thxr_mod_exp_mont( BN_ULONG *result, BN_ULONG *ap, BN_ULONG *np, + BN_ULONG *rrp, BN_ULONG n0, int top, int tmp_len, unsigned char *str); + +int Ri_thxr_mod_exp_mont( BN_ULONG *result, BN_ULONG *ap, BN_ULONG *np, + BN_ULONG *rrp, BN_ULONG *dp, BN_ULONG *aap, BN_ULONG *rp, BN_ULONG *tmp, + BN_ULONG n0, int top, unsigned char *str); + +void Ri_thxr_mul_normal(BN_ULONG *r,BN_ULONG *a,int na,BN_ULONG *b,int nb); +void Ri_thxr_sqr_normal(BN_ULONG *r, BN_ULONG *a, int n, BN_ULONG *tmp); + +void Ri_thxr_from_montgomery_words(BN_ULONG *ret,BN_ULONG *ap,BN_ULONG *np, + int w, BN_ULONG n0); + +BN_ULONG Ri_thxr_from_mont_words(BN_ULONG *ap,BN_ULONG *wap, + BN_ULONG *np, int w, BN_ULONG n0); + +#ifdef CPU_TMS320 + +/* Method and functions required for the ARM/DSP interface */ + +const BN_ME_METH *BN_ME_METH_dspc(void); + +int Rx_dsp_mod_exp_mont( BN_ULONG *result, BN_ULONG *ap, BN_ULONG *np, + BN_ULONG *rrp, BN_ULONG n0, int top, int tmp_len, unsigned char *str); + +int Ri_dsp_mod_exp_mont( BN_ULONG *result, BN_ULONG *ap, BN_ULONG *np, + BN_ULONG *rrp, BN_ULONG *dp, BN_ULONG *aap, BN_ULONG *rp, BN_ULONG *tmp, + BN_ULONG n0, int top, unsigned char *str); + +#endif + +#ifdef __cplusplus +} +#endif +#endif /* HEADER_COMMON_BN_THX_H */ diff --git a/build/libraries_sysmenu/acsign/ARM9/include/md5.h b/build/libraries_sysmenu/acsign/ARM9/include/md5.h new file mode 100644 index 00000000..7a5ca73a --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/md5.h @@ -0,0 +1,73 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef _MD5_H_ +#define _MD5_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +typedef struct MD5_CTX MD5_CTX; +typedef struct MD5_CTX MD5Context; + +/* MD5 context. */ +struct MD5_CTX{ + unsigned long state[4]; /* state (ABCD) */ + unsigned long count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} ; + +void MD5Init(MD5_CTX *); +void MD5Update(MD5_CTX *, unsigned char *, unsigned int); +void MD5Final(unsigned char digest[16], MD5_CTX *); + + +#if defined( MD5_TEST ) +int MD5Test( ); +#endif // MD5_TEST + +#ifdef __cplusplus +} +#endif + +#endif // _MD5_H_ diff --git a/build/libraries_sysmenu/acsign/ARM9/include/r_error.h b/build/libraries_sysmenu/acsign/ARM9/include/r_error.h new file mode 100644 index 00000000..16ffb55a --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/r_error.h @@ -0,0 +1,226 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ +/** + * @file r_error.h + * This file contains the error definitions for the toolkit. + */ +#ifndef HEADER_COMMON_R_ERROR_H +#define HEADER_COMMON_R_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup R_ERROR_IDS Error Identifiers + * This section outlines the error codes returned, enabling identification of + * specific errors. For more information, see the + * Developer's Guide. + * + * @{ + */ +/** + * Indicates that a fatal error has occurred in the operation performed. + * This flag is set with the following error codes:
+ *
    + *
  • #R_ERROR_INVALID_STATE.
  • + *
  • #R_ERROR_INIT_NOT_CALLED.
  • + *
  • #R_ERROR_SHOULD_NOT_HAVE_BEEN_CALLED.
  • + *
+ */ +#define R_ERROR_FATAL_INTERNAL_ERROR 64 + +/** + * Indicates that the specified parameter is incorrect or contains invalid + * information. This flag is set with the following error codes:
+ *
    + *
  • #R_ERROR_NULL_ARG.
  • + *
  • #R_ERROR_BUFFER_TOO_SMALL.
  • + *
  • #R_ERROR_BAD_VALUE.
  • + *
  • #R_ERROR_BAD_RANGE.
  • + *
  • #R_ERROR_BAD_FORMAT.
  • + *
  • #R_ERROR_BAD_TYPE.
  • + *
  • #R_ERROR_BAD_DATA.
  • + *
  • #R_ERROR_BAD_LENGTH.
  • + *
+ */ +#define R_ERROR_BAD_PARAMETER 32 + +/* Indicates the base value for all general errors used through all products */ +#define R_ERROR_BASE 10000 + +/** + * Indicates that no errors were detected in the requested operation. + */ +#define R_ERROR_NONE 0 + +/** + * Indicates that the requested operation failed. + */ +#define R_ERROR_FAILED (R_ERROR_BASE+1) +/** + * Indicates that the requested operation detected an Input/Output error. + */ +#define R_ERROR_IO (R_ERROR_BASE+2) +/** + * Indicates that the requested operation detected a protocol error. + */ +#define R_ERROR_PROTOCOL (R_ERROR_BASE+3) +/** + * Indicates that the requested operation detected an End-of-File (EOF) error. + */ +#define R_ERROR_EOF (R_ERROR_BASE+4) +/** + * Indicates that the requested operation failed in a memory allocation + * operation. + */ +#define R_ERROR_ALLOC_FAILURE (R_ERROR_BASE+5) +/** + * Indicates that the requested operation is restricted in an evaluation + * version of the library. + */ +#define R_ERROR_EVAL_RESTRICTION (R_ERROR_BASE+6) +/** + * Indicates that the evaluation period of the library has expired. + */ +#define R_ERROR_EVAL_EXPIRED (R_ERROR_BASE+7) +/** + * Indicates that the requested operation detected that a pre-requirement was + * not found. + */ +#define R_ERROR_NOT_FOUND (R_ERROR_BASE+8) +/** + * Indicates that the requested operation detected that a pre-requirement was + * unavailable. + */ +#define R_ERROR_NOT_AVAILABLE (R_ERROR_BASE+9) +/** + * Indicates that the requested operation is not implemented in the current + * instantiation of the library. + */ +#define R_ERROR_NOT_IMPLEMENTED (R_ERROR_BASE+10) +/** + * Indicates that the requested operation is not supported in the current + * instantiation of the library. + */ +#define R_ERROR_NOT_SUPPORTED (R_ERROR_BASE+11) +/** + * Indicates that the requested operation entered an invalid state. + */ +#define R_ERROR_INVALID_STATE \ + ((R_ERROR_BASE+12) | R_ERROR_FATAL_INTERNAL_ERROR) +/** + * Indicates that the requested operation detected that an initialization + * operation has not been performed. + */ +#define R_ERROR_INIT_NOT_CALLED \ + ((R_ERROR_BASE+13) | R_ERROR_FATAL_INTERNAL_ERROR) +/** + * Indicates that the requested operation should not have been called. + */ +#define R_ERROR_SHOULD_NOT_HAVE_BEEN_CALLED \ + ((R_ERROR_BASE+14) | R_ERROR_FATAL_INTERNAL_ERROR) +/** + * Indicates that the requested method is not defined. + */ +#define R_ERROR_METHOD_UNDEFINED \ + ((R_ERROR_BASE+15) | R_ERROR_FATAL_INTERNAL_ERROR) +/** + * Indicates that the requested operation detected an inadequately sized + * buffer. + */ +#define R_ERROR_BUFFER_TOO_SMALL \ + ((R_ERROR_BASE+16) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the requested operation detected that a required argument + * was passed as NULL. + */ +#define R_ERROR_NULL_ARG ((R_ERROR_BASE+17) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the requested operation detected that a required argument + * passed contained a bad or incorrect value. + */ +#define R_ERROR_BAD_VALUE ((R_ERROR_BASE+18) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the requested operation detected that a required argument + * passed was out of the allowed range. + */ +#define R_ERROR_BAD_RANGE ((R_ERROR_BASE+19) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the requested operation detected that a required argument + * passed used a format that is not supported or incorrect. + */ +#define R_ERROR_BAD_FORMAT ((R_ERROR_BASE+20) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the requested operation detected that a required argument + * passed used a type that is not supported or incorrect. + */ +#define R_ERROR_BAD_TYPE ((R_ERROR_BASE+21) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the requested operation detected that a required argument + * passed contained incorrect or invalid data. + */ +#define R_ERROR_BAD_DATA ((R_ERROR_BASE+22) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the requested operation detected that a required argument + * passed contained an incorrect length value. + */ +#define R_ERROR_BAD_LENGTH ((R_ERROR_BASE+23) | R_ERROR_BAD_PARAMETER) +/** + * Indicates that the library instantiation requested is not supported. + */ +#define R_ERROR_RCOM_LIBRARY_NOT_SUPPORTED (R_ERROR_BASE+24) +/** + * Indicates that the request operation was denied. + */ +#define R_ERROR_DENIED (R_ERROR_BASE+25) +/** + * Indicates that authentication is required before the operation + * can succeed. + */ +#define R_ERROR_AUTHENTICATION_REQUIRED (R_ERROR_BASE+26) + +/** + * Indicates that a required module was unable to be loaded. + */ +#define R_ERROR_MODULE_LOAD_FAILED \ + ((R_ERROR_BASE+27)|R_ERROR_FATAL_INTERNAL_ERROR) + +/* Resource Manager base for errors */ +#define R_COM_ERR_LIB_CTX_BASE 10100 + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif +#endif /* HEADER_COMMON_R_ERROR_H */ + + + diff --git a/build/libraries_sysmenu/acsign/ARM9/include/r_stdiag.h b/build/libraries_sysmenu/acsign/ARM9/include/r_stdiag.h new file mode 100644 index 00000000..fbe3d3ca --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/r_stdiag.h @@ -0,0 +1,98 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +/* + * *************************************************************************** + * + * Purpose: + * + * This file defines an API for performing stack diagnostics. + * + * It provides: + * Peek Stack Usage statistics + * To use it: + * 1. Build the library without "NO_R_DIAG" defined + * 2. Make a call to R_DIAG_set_stack_datum() prior to + * calling the first library function. + * 3. Add calls to the macro R_DIAG_CHECK_STACK where potential + * high stack usage points are. + * 4. Call R_DIAG_get_stack_low_water_mark() at then end of the + * library calls to return the maximum stack usage OR + * 5. Call R_DIAG_print_stack_depth() to display the peek stack + * usage + * + * + * + * History: + * 3-Aug-00 mjs development + * + * ************************************************************************** + */ + + +#ifndef HEADER_COMMON_R_STDIAG_H +#define HEADER_COMMON_R_STDIAG_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef NO_R_DIAG + +#ifdef NOPROTO +int R_DIAG_set_stack_datum(char *ptr); +int R_DIAG_check_stack(char *ptr, char *file, int line, int hit); +int R_DIAG_get_stack_low_water_mark(int *depth, char **file, int *line, + int *hit); +int R_DIAG_print_stack_depth(BIO *bio); + +#else + +int R_DIAG_set_stack_datum(); +int R_DIAG_check_stack(); +int R_DIAG_get_stack_low_water_mark(); +int R_DIAG_print_stack_depth(); + +#endif + +#define R_DIAG_CHECK_STACK {\ + char r_diag_stack_check_var = 0;\ + static int r_diag_stack_check_cnt = 0;\ +\ + R_DIAG_check_stack(&r_diag_stack_check_var, __FILE__,\ + __LINE__,++r_diag_stack_check_cnt);\ + } +#else +#define R_DIAG_CHECK_STACK +#endif + + +#ifdef __cplusplus +} +#endif +#endif /* HEADER_COMMON_R_STDIAG_H */ + diff --git a/build/libraries_sysmenu/acsign/ARM9/include/r_types.h b/build/libraries_sysmenu/acsign/ARM9/include/r_types.h new file mode 100644 index 00000000..f6514b13 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/r_types.h @@ -0,0 +1,257 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ +/** + * @file r_types.h + * This file contains the library structure and type definitions. + */ +#ifndef HEADER_COMMON_R_TYPES_H +#define HEADER_COMMON_R_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup DATA_MNG_FLAGS Data Management Flags + * This section lists the data management flags. + * @{ + */ + +/** + * @} + */ + +/* This gets set if the flags field if the we need to 'free' the + * R_RANDOM when we call R_rand_free(). If it is not set, the + * rand_ctrl will only be called to clean things up. + */ +#define R_RANDOM_FLG_MALLOCED 0x01 + +/* portable form of a random callback function */ +/** + * @typedef R_RANDOM + * The random object type. + */ +typedef struct r_random_st R_RANDOM; +/** + * This structure is used by the random object type. + */ +struct r_random_st +{ + /** + * A method function for generation of random data. + * + * @see R_rand_bytes(). + */ + int (*rand_bytes)(R_RANDOM *ctx,unsigned char *bytes,int len); + /** + * A method function for seeding of the random generator. + * @see R_rand_seed(). + */ + int (*rand_seed)(R_RANDOM *ctx,unsigned char *bytes,int len); + /** + * A method function for control of the random generator used by + * other functions as a single interface. + * + * @see R_rand_entropy_count(), R_rand_set_entropy_func(), + * R_rand_get_entropy_func(), R_rand_load_file(), R_rand_write_file() + * and R_rand_file_name(). + */ + int (*rand_ctrl)(R_RANDOM *ctx,int op,char *arg); + /** + * The data used by the random implementation. + */ + char *arg; + /** + * A method flag for used for keeping the state of the #R_RANDOM. + */ + int flags; /* normally set to zero */ +}; +/** + * @typedef R_SURRENDER + * The surrender function and argument. + */ +typedef struct r_surrender_st R_SURRENDER; +/** + * This structure provides a status update of a time intensive operation. It + * also allows you to abort the operation if required. + */ +struct r_surrender_st +{ + /* Return 0 to continue, non-zero to 'cancel' function */ + /** + * The surrender function pointer used as a generic method of + * passing user-defined callback or information collection functions. + */ + int (*callback)(R_SURRENDER *ctx,int function,int num); + /** + * The argument data used by the callback operation. + */ + char *arg; +}; + +typedef struct r_fixed_point_number_st R_FIXED_POINT_NUMBER; +struct r_fixed_point_number_st +{ + unsigned long hi; + unsigned long lo; +}; + +/** + * @typedef R_INDEXED_INFO + * This structure details the index containing information for get and set + * functions. + */ +typedef struct r_indexed_info_st R_INDEXED_INFO; +/** This structure details the index containing information for get and set + * functions. + */ +struct r_indexed_info_st +{ + /** The index into the list of the item to work with. */ + int index; + /** The data of the item in the list. */ + void *data; + /** The length of the data. */ + unsigned int len; + /** The data value as an integer. */ + int value; +}; + +/** + * @typedef R_ID_INFO + * The information to work with requires a second identity value to find it. + */ +typedef struct r_id_info_st R_ID_INFO; +/** The information to get or set requires a second information identifier. + * This type is used when calling set_info and get_info to get a number of + * information items in one call. + */ +struct r_id_info_st +{ + /** The information identifier. */ + int info_id; + /** The information data associated with the identifier. */ + void *value; +}; + +/** @defgroup R_FLAG_COPY_IDS Copy Flag Identifiers + * + * This section provides information on the copy mode. When data is passed + * to/from the library you can specify whether or not the copy should be done + * by value, by reference or by direct assignment. + * @ingroup DATA_MNG_FLAGS + * @{ + */ + +/** + * The copy flag. When data is passed to/from the library you can specify + * whether or not the copy should be done by value, by reference or + * by direct assignment. + */ +typedef int R_FLAG_COPY; + +/* + * action flag app lib + * obj_get BY_VAL F X + * BY_REF X F [app will not free "obj" until it is + * BY_ASSIGN F X finished with the returned reference] + * obj_set BY_VAL F X + * BY_REF F X [app will not free passed reference + * BY_ASSIGN X F until after it has freed "obj"] + * + * BY_REF makes the lifetime of the two objects linked and it is up to + * the application to manage the objects in a manner that preserves this + * relationship. + */ + +/** + * Indicates to copy by value. A complete clone of the object is made. + * The lifecycles of the two objects are independent. + */ +#define R_FLAG_COPY_BY_VALUE 0x0000 + +/** + * Indicates to copy by reference. A reference to the object is made. + * The lifecycles of objects sharing references are linked. + */ +#define R_FLAG_COPY_BY_REFERENCE 0x0001 + +/** + * Indicates to copy by assignment. The object is assigned to the required + * party. The caller does not keep a reference to the passed object. + */ +#define R_FLAG_COPY_BY_ASSIGN 0x0002 + +/** + * Indicates to copy using the default flag settings. + */ +#define R_FLAG_COPY_DEFAULT R_FLAG_COPY_BY_VALUE + +/** + * @} + */ + +/** @defgroup R_FLAG_SHARE_IDS Shared Flag Identifiers + * + * This section provides information on the shared flags available. + * @ingroup DATA_MNG_FLAGS + * @{ + */ + +/** + * The constructor flag. Indicates whether or not it is permissible to share + * the internal state between objects. + */ +typedef int R_FLAG_SHARE; + +/** + * Indicates to share nothing. The states of the two objects are completely + * separate. + */ +#define R_FLAG_SHARE_NONE 0x0000 + +/** + * Indicates to share data. Constructed objects may reference the state of + * the object from which it was constructed. The lifecycles of the two objects + * are linked. + */ +#define R_FLAG_SHARE_DATA 0x0001 + +/** Indicates the share default in which nothing is shared. */ +#define R_FLAG_SHARE_DEFAULT R_FLAG_SHARE_NONE + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/build/libraries_sysmenu/acsign/ARM9/include/sha.h b/build/libraries_sysmenu/acsign/ARM9/include/sha.h new file mode 100644 index 00000000..e1543a75 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/sha.h @@ -0,0 +1,105 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#ifndef HEADER_COMMON_SHA_H +#define HEADER_COMMON_SHA_H + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(CCONV) +#define CCONV +#endif + +#ifndef PRE_CCONV +#define PRE_CCONV +#endif + +#define SHA_CBLOCK 64 +#define SHA_LBLOCK 16 +#define SHA_BLOCK 16 +#define SHA_LAST_BLOCK 56 +#define SHA_LENGTH_BLOCK 8 +#define SHA_DIGEST_LENGTH 20 + +/* the default is to use unsigned long */ +#if !defined(OPT_SHA_INT) && !defined(OPT_SHA_LONG) +#define OPT_SHA_LONG +#endif + +#ifdef OPT_SHA_LONG +#define SHA_LONG unsigned long +#endif + +#ifdef OPT_SHA_INT +#define SHA_LONG unsigned int +#endif + +typedef struct sha_ctx_st SHA_CTX; + +struct sha_ctx_st + { + SHA_LONG h0,h1,h2,h3,h4; + SHA_LONG Nl,Nh; + SHA_LONG data[SHA_LBLOCK]; + int num; + void (PRE_CCONV CCONV *sha_block)(SHA_CTX *c, const unsigned char *W, + int num); + }; + +#ifndef NOPROTO +int SHA1_Setup(SHA_CTX *c, void (PRE_CCONV CCONV *sha_block)(SHA_CTX *c, + const unsigned char *W, int num)); +void SHA_Init(SHA_CTX *c); +void SHA_Update(SHA_CTX *c, const unsigned char *data, unsigned long len); +void SHA_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA(const unsigned char *d, unsigned long n,unsigned char *md); +void SHA_Transform(SHA_CTX *c, const unsigned char *data); +void SHA1_Init(SHA_CTX *c); +void SHA1_Update(SHA_CTX *c, const unsigned char *data, unsigned long len); +void SHA1_Final(unsigned char *md, SHA_CTX *c); +unsigned char *SHA1(const unsigned char *d, unsigned long n,unsigned char *md); +void SHA1_Transform(SHA_CTX *c, const unsigned char *data); +#else +void SHA_Init(); +void SHA_Update(); +void SHA_Final(); +unsigned char *SHA(); +void SHA_Transform(); +void SHA1_Init(); +void SHA1_Update(); +void SHA1_Final(); +unsigned char *SHA1(); +void SHA1_Transform(); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_COMMON_SHA_H */ diff --git a/build/libraries_sysmenu/acsign/ARM9/include/sha1.h b/build/libraries_sysmenu/acsign/ARM9/include/sha1.h new file mode 100644 index 00000000..692f2e9b --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/sha1.h @@ -0,0 +1,90 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * sha1.h + * + * Description: + * This is the header file for code which implements the Secure + * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published + * April 17, 1995. + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the names + * used in the publication. + * + * Please read the file sha1.c for more information. + * + */ + +#ifndef _SHA1_H_ +#define _SHA1_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _SHA_enum_ +#define _SHA_enum_ +enum +{ + shaSuccess = 0, + shaNull, /* Null pointer parameter */ + shaInputTooLong, /* input data too long */ + shaStateError /* called Input after Result */ +}; +#endif + +/* + * This structure will hold context information for the SHA-1 + * hashing operation + */ +typedef struct SHA1Context +{ + unsigned long Intermediate_Hash[20/4]; /* Message Digest */ + + unsigned long Length_Low; /* Message length in bits */ + unsigned long Length_High; /* Message length in bits */ + + int Message_Block_Index; /* Index into message block array */ + unsigned char Message_Block[64]; /* 512-bit message blocks */ + + int Computed; /* Is the digest computed? */ + int Corrupted; /* Is the message digest corrupted? */ +} SHA1Context; + +/* + * Function Prototypes + */ + +int SHA1Reset( SHA1Context *); +int SHA1Input( SHA1Context *, + const unsigned char *, + unsigned int); +int SHA1Result( SHA1Context *, + unsigned char Message_Digest[20]); + +#if defined( SHA1_TEST ) +int SHA1Test( ); +#endif // SHA1_TEST + + +#ifdef __cplusplus +} +#endif + +#endif // _SHA1_H_ diff --git a/build/libraries_sysmenu/acsign/ARM9/include/sha_locl.h b/build/libraries_sysmenu/acsign/ARM9/include/sha_locl.h new file mode 100644 index 00000000..10553ab4 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/include/sha_locl.h @@ -0,0 +1,290 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#ifndef HEADER_COMMON_SHA_LOCL_H +#define HEADER_COMMON_SHA_LOCL_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef STANDALONE +#include "r_com.h" +#else +#if 0 //RSA +#include +#include +#include +#define Memcpy memcpy +#define Memset memset +#define Strcpy strcpy +#else //NITRO +#include "acmemory.h" +#define Malloc(a) ACMemory_Alloc(a) +#define Free(a) ACMemory_Free(a) +#define Memset(a,b,c) ACMemory_Memset(a,b,c) +#define Memcpy(a,b,c) ACMemory_Memcpy(a,b,c) +#endif +#endif + +#ifdef undef +/* one or the other must be defined */ +#ifndef SHA_1 /* FIPE 180-1 */ +#define SHA_0 /* FIPS 180 */ +#endif +#endif + +#define ULONG unsigned long +#define UCHAR unsigned char +#define UINT unsigned int + +#ifdef NOCONST +#define const +#endif + +#undef c2nl +#define c2nl(c,l) (l =(((unsigned long)(*((c)++)))<<24), \ + l|=(((unsigned long)(*((c)++)))<<16), \ + l|=(((unsigned long)(*((c)++)))<< 8), \ + l|=(((unsigned long)(*((c)++))) )) + +#undef p_c2nl +#define p_c2nl(c,l,n) { \ + switch (n) { \ + case 0: l =((unsigned long)(*((c)++)))<<24; \ + case 1: l|=((unsigned long)(*((c)++)))<<16; \ + case 2: l|=((unsigned long)(*((c)++)))<< 8; \ + case 3: l|=((unsigned long)(*((c)++))); \ + } \ + } + +#undef c2nl_p +/* NOTE the pointer is not incremented at the end of this */ +#define c2nl_p(c,l,n) { \ + l=0; \ + (c)+=n; \ + switch (n) { \ + case 3: l =((unsigned long)(*(--(c))))<< 8; \ + case 2: l|=((unsigned long)(*(--(c))))<<16; \ + case 1: l|=((unsigned long)(*(--(c))))<<24; \ + } \ + } + +#undef p_c2nl_p +#define p_c2nl_p(c,l,sc,len) { \ + switch (sc) \ + { \ + case 0: l =((unsigned long)(*((c)++)))<<24; \ + if (--len == 0) break; \ + case 1: l|=((unsigned long)(*((c)++)))<<16; \ + if (--len == 0) break; \ + case 2: l|=((unsigned long)(*((c)++)))<< 8; \ + } \ + } + +#undef nl2c +#define nl2c(l,c) (*((c)++)=(unsigned char)(((l)>>24)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l) )&0xff)) + +#undef c2l +#define c2l(c,l) (l =(((unsigned long)(*((c)++))) ), \ + l|=(((unsigned long)(*((c)++)))<< 8), \ + l|=(((unsigned long)(*((c)++)))<<16), \ + l|=(((unsigned long)(*((c)++)))<<24)) + +#undef p_c2l +#define p_c2l(c,l,n) { \ + switch (n) { \ + case 0: l =((unsigned long)(*((c)++))); \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + case 3: l|=((unsigned long)(*((c)++)))<<24; \ + } \ + } + +#undef c2l_p +/* NOTE the pointer is not incremented at the end of this */ +#define c2l_p(c,l,n) { \ + l=0; \ + (c)+=n; \ + switch (n) { \ + case 3: l =((unsigned long)(*(--(c))))<<16; \ + case 2: l|=((unsigned long)(*(--(c))))<< 8; \ + case 1: l|=((unsigned long)(*(--(c)))); \ + } \ + } + +#undef p_c2l_p +#define p_c2l_p(c,l,sc,len) { \ + switch (sc) \ + { \ + case 0: l =((unsigned long)(*((c)++))); \ + if (--len == 0) break; \ + case 1: l|=((unsigned long)(*((c)++)))<< 8; \ + if (--len == 0) break; \ + case 2: l|=((unsigned long)(*((c)++)))<<16; \ + } \ + } + +#undef l2c +#define l2c(l,c) (*((c)++)=(unsigned char)(((l) )&0xff), \ + *((c)++)=(unsigned char)(((l)>> 8)&0xff), \ + *((c)++)=(unsigned char)(((l)>>16)&0xff), \ + *((c)++)=(unsigned char)(((l)>>24)&0xff)) + +#ifdef OPT_SHA_B_ENDIAN +#define B_ENDIAN +#endif +#ifdef OPT_SHA_L_ENDIAN +#define L_ENDIAN +#endif + +#undef ROTATE +#if defined(WIN32) +#define ROTATE(a,n) _lrotl(a,n) +#else +#define ROTATE(a,n) (((a)<<(n))|(((a)&0xffffffff)>>(32-(n)))) +#endif + +/* byte order reversal */ +#if defined(WIN32) +/* 5 instructions with rotate instruction, else 9 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + (a)=((ROTATE(l,8)&0x00FF00FF)|(ROTATE(l,24)&0xFF00FF00)); \ + } +#else +/* 6 instructions with rotate instruction, else 8 */ +#define Endian_Reverse32(a) \ + { \ + unsigned long l=(a); \ + l=(((l&0xFF00FF00)>>8L)|((l&0x00FF00FF)<<8L)); \ + (a)=ROTATE(l,16L); \ + } +#endif + +/* F() below can be + * simplified to the code in F_00_19. + * #define F(x,y,z) (((x) & (y)) | ((~(x)) & (z))) + * another tweak to be made + * in F_40_59, (x&a)|(y&a) -> (x|y)&a + */ +#define F_00_19(b,c,d) ((((c) ^ (d)) & (b)) ^ (d)) +#define F_20_39(b,c,d) ((b) ^ (c) ^ (d)) +#define F_40_59(b,c,d) (((b) & (c)) | (((b)|(c)) & (d))) +#define F_60_79(b,c,d) F_20_39(b,c,d) + +#ifdef SHA_0 +#undef Xupdate +#define Xupdate(a,i,ia,ib,ic,id) X[(i)&0x0f]=(a)=\ + (ia[(i)&0x0f]^ib[((i)+2)&0x0f]^ic[((i)+8)&0x0f]^id[((i)+13)&0x0f]); +#endif +#ifdef SHA_1 +#undef Xupdate +#define Xupdate(a,i,ia,ib,ic,id) (a)=\ + (ia[(i)&0x0f]^ib[((i)+2)&0x0f]^ic[((i)+8)&0x0f]^id[((i)+13)&0x0f]);\ + X[(i)&0x0f]=(a)=ROTATE((a),1); +#endif + +#define BODY_00_15(i,a,b,c,d,e,f,xa) \ + (f)=xa[i]+(e)+K_00_19+ROTATE((a),5)+F_00_19((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#define BODY_60_79(i,a,b,c,d,e,f,xa) \ + Xupdate(f,i,xa,xa,xa,xa); \ + (f)=X[(i)&0x0f]+(e)+K_60_79+ROTATE((a),5)+F_60_79((b),(c),(d)); \ + (b)=ROTATE((b),30); + +/* + * The CodeWarrior compiler has a problem correctly expanding things like + * + * (f)+=(e)+K_00_19+ROTATE((a),5)+F_00_19((b),(c),(d)); + * + * so we separate this to 3 explicit adds, just for PalmOS. + */ +#ifndef UNDER_PALMOS + +#define BODY_16_19(i,a,b,c,d,e,f,xa,xb,xc,xd) \ + Xupdate(f,i,xa,xb,xc,xd); \ + (f)+=(e)+K_00_19+ROTATE((a),5)+F_00_19((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#define BODY_20_31(i,a,b,c,d,e,f,xa,xb,xc,xd) \ + Xupdate(f,i,xa,xb,xc,xd); \ + (f)+=(e)+K_20_39+ROTATE((a),5)+F_20_39((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#define BODY_32_39(i,a,b,c,d,e,f,xa) \ + Xupdate(f,i,xa,xa,xa,xa); \ + (f)+=(e)+K_20_39+ROTATE((a),5)+F_20_39((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#define BODY_40_59(i,a,b,c,d,e,f,xa) \ + Xupdate(f,i,xa,xa,xa,xa); \ + (f)+=(e)+K_40_59+ROTATE((a),5)+F_40_59((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#else /* UNDER_PALMOS */ + +#define BODY_16_19(i,a,b,c,d,e,f,xa,xb,xc,xd) \ + Xupdate(f,i,xa,xb,xc,xd); \ + (f)+=(e); \ + (f)+=K_00_19; \ + (f)+=ROTATE((a),5)+F_00_19((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#define BODY_20_31(i,a,b,c,d,e,f,xa,xb,xc,xd) \ + Xupdate(f,i,xa,xb,xc,xd); \ + (f)+=(e); \ + (f)+=K_20_39; \ + (f)+=ROTATE((a),5)+F_20_39((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#define BODY_32_39(i,a,b,c,d,e,f,xa) \ + Xupdate(f,i,xa,xa,xa,xa); \ + (f)+=(e); \ + (f)+=K_20_39; \ + (f)+=ROTATE((a),5)+F_20_39((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#define BODY_40_59(i,a,b,c,d,e,f,xa) \ + Xupdate(f,i,xa,xa,xa,xa); \ + (f)+=(e); \ + (f)+=K_40_59; \ + (f)+=ROTATE((a),5)+F_40_59((b),(c),(d)); \ + (b)=ROTATE((b),30); + +#endif /* UNDER_PALMOS */ + +#ifdef __cplusplus +} +#endif + +#endif /* HEADER_COMMON_SHA_LOCL_H */ diff --git a/build/libraries_sysmenu/acsign/ARM9/src/acmemory.c b/build/libraries_sysmenu/acsign/ARM9/src/acmemory.c new file mode 100644 index 00000000..a6785f03 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/acmemory.c @@ -0,0 +1,306 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +// +// BN系関数用のメモリ関連処理を置き換え +// +#include +#include "acmemory.h" + +/* + head tail + | | | | + +--------+---------+----....----+---------+--------+ + |block |check |buffer |check |block | + +--------+---------+----....----+---------+--------+ + |4byte |4byte |Upper4(size)|4byte |4byte | + <------------------ 4 * n -------------------> + + block = n = (4 * 4 + Upper4(size)) / 4 + check = 0x0F5555F0:未使用/0x0FAAAAF0:使用中 +*/ + +unsigned long aACMemoryPoolA[ 16 ]; +unsigned long aACMemoryPool[ 1024 * 32 / sizeof (unsigned long) ]; // 32K +unsigned long aACMemoryPoolB[ 16 ]; + +#define ACMEMORYPOOL_HEAD (aACMemoryPool) +#define ACMEMORYPOOL_TAIL (aACMemoryPool + sizeof aACMemoryPool / sizeof (unsigned long)) +#define ACMEMORYPOOL_SIZE ((unsigned long)ACMEMORYPOOL_TAIL - (unsigned long)ACMEMORYPOOL_HEAD) + +#define ACMEMORY_CHECK_BASE 0xF000000F +#define ACMEMORY_CHECK_FREE (0x00555500 | ACMEMORY_CHECK_BASE) +#define ACMEMORY_CHECK_USED (0x00AAAA00 | ACMEMORY_CHECK_BASE) + +#define ACMemory_Lower4( _size ) (((_size) ) & 0xFFFFFFFC) +#define ACMemory_Upper4( _size ) (((_size) + 3) & 0xFFFFFFFC) + +#define pACMemory_FromHeadToBody( _head ) ((unsigned long*)(((volatile unsigned long*)(_head)) + 2)) +#define pACMemory_FromBodyToHead( _body ) ((unsigned long*)(((volatile unsigned long*)(_body)) - 2)) +#define pACMemory_FromHeadToTail( _head ) ((unsigned long*)(((volatile unsigned long*)(_head)) + nACMemory_HeadBlock( _head ))) +#define pACMemory_FromTailToHead( _tail ) ((unsigned long*)(((volatile unsigned long*)(_tail)) - nACMemory_TailBlock( _tail ))) +#define nACMemory_HeadBlock( _head ) (((volatile unsigned long*)(_head))[+0]) +#define nACMemory_HeadCheck( _head ) (((volatile unsigned long*)(_head))[+1]) +#define nACMemory_TailBlock( _tail ) (((volatile unsigned long*)(_tail))[-1]) +#define nACMemory_TailCheck( _tail ) (((volatile unsigned long*)(_tail))[-2]) + +//#define USE_OSALLOC +//#define USE_ACMEMORY_DEBUGDUMP +//#define USE_ACMEMORY_DEBUGFILL + +// +#if defined( USE_ACMEMORY_DEBUGDUMP ) +static +void acMemory_DebugDump( ) +{ + unsigned long* ptr = ACMEMORYPOOL_HEAD; + + // + OS_Printf( "----ACMemory_Dump [0x%.8x - 0x%.8x : 0x%.8x ]----\n", ACMEMORYPOOL_HEAD, ACMEMORYPOOL_TAIL, ACMEMORYPOOL_SIZE ); + + for ( ; (unsigned long)ptr < (unsigned long)ACMEMORYPOOL_TAIL; ) + { + OS_Printf( " [0x%.8x - 0x%.8x] (0x%.8x) <%c> ", + ptr, + pACMemory_FromHeadToTail( ptr ), + nACMemory_HeadBlock( ptr ), + nACMemory_HeadCheck( ptr ) == ACMEMORY_CHECK_USED ? '*' : '-' ); + + //OS_Printf( "0x%.8x 0x%.8x", nACMemory_HeadBlock( ptr ), nACMemory_HeadCheck( ptr ) ); + + //OS_Printf( " .... " ); + + ptr += nACMemory_HeadBlock( ptr ); + + //OS_Printf( "0x%.8x 0x%.8x", nACMemory_TailCheck( ptr ), nACMemory_TailBlock( ptr ) ); + + OS_Printf( "\n" ); + OS_PrintServer(); + } + ptr = 0; +} + +#define ACMemory_DebugDump( ) acMemory_DebugDump( ) + +#else + +#define ACMemory_DebugDump( ) + +#endif //USE_ACMEMORY_DEBUGDUMP + +// +#if defined( USE_ACMEMORY_DEBUGFILL ) +static +void acMemory_DebugFill( void* ptr, int cnt, int val ) +{ + (void)ACMemory_Memset( ptr, val, cnt ); +} + +#define ACMemory_DebugFill( _ptr, _cnt, _val ) acMemory_DebugFill( _ptr, _cnt, _val ) + +#else + +#define ACMemory_DebugFill( _ptr, _cnt, _val ) + +#endif //USE_ACMEMORY_DEBUGFILL + +// +void ACMemory_Clear( ) +{ + unsigned long* head = ACMEMORYPOOL_HEAD; + unsigned long* tail = ACMEMORYPOOL_TAIL; + unsigned long block; + unsigned long check; + + + block = ACMEMORYPOOL_SIZE / 4; + check = ACMEMORY_CHECK_FREE; + + nACMemory_HeadBlock( head ) = block; + nACMemory_HeadCheck( head ) = check; + nACMemory_TailBlock( tail ) = block; + nACMemory_TailCheck( tail ) = check; + + ACMemory_DebugFill( pACMemory_FromHeadToBody( head ), (block - 4) * 4, 0xFF ); + ACMemory_DebugDump( ); +} + +// +void* ACMemory_Alloc( u32 size ) +{ + #if defined( USE_OSALLOC ) + OSIntrMode nOSIntrMode; + void* alloc = NULL; + + nOSIntrMode = OS_DisableInterrupts( ); + alloc = OS_Alloc( size ); + (void)OS_RestoreInterrupts( nOSIntrMode ); + return alloc; + + #else + + unsigned long* head = ACMEMORYPOOL_HEAD; + unsigned long* tail = ACMEMORYPOOL_TAIL; + unsigned long block, oldblock, newblock; + unsigned long check, oldcheck, newcheck; + + if ( !size ) return 0; + + // + if ( size < 16 ) size = 16; + block = 4 + ACMemory_Upper4( size ) / 4; + check = ACMEMORY_CHECK_USED; + + // + for ( ; ; ) + { + if ( (unsigned long)head >= (unsigned long)tail ) + { + head = 0; + break; + } + + newblock = nACMemory_HeadBlock( head ); + newcheck = nACMemory_HeadCheck( head ); + if ( newcheck == check ) + { + head += newblock; + continue ; + } + if ( newblock < block + 4 + 4 ) + { + head += newblock; + continue ; + } + + break; + } + + if ( !head ) return 0; + + // + oldblock = nACMemory_HeadBlock( head ); + oldcheck = nACMemory_HeadCheck( head ); + + nACMemory_HeadBlock( head ) = block; + nACMemory_HeadCheck( head ) = check; + + tail = pACMemory_FromHeadToTail( head ); + nACMemory_TailBlock( tail ) = block; + nACMemory_TailCheck( tail ) = check; + + if ( (unsigned long)tail < (unsigned long)ACMEMORYPOOL_TAIL ) + { + nACMemory_HeadBlock( tail ) = oldblock - block; + nACMemory_HeadCheck( tail ) = oldcheck; + tail = pACMemory_FromHeadToTail( tail ); + nACMemory_TailBlock( tail ) = oldblock - block; + nACMemory_TailCheck( tail ) = oldcheck; + } + + // + (void)ACMemory_Memset( pACMemory_FromHeadToBody( head ), 0x00, (block - 4) * 4 ); + + ACMemory_DebugFill( pACMemory_FromHeadToBody( head ), (block - 4) * 4, 0x00 ); + ACMemory_DebugDump( ); + + return (void*)pACMemory_FromHeadToBody( head ); + #endif +} + +// +void ACMemory_Free( void* adrs ) +{ + #if defined( USE_OSALLOC ) + OSIntrMode nOSIntrMode; + + nOSIntrMode = OS_DisableInterrupts( ); + OS_Free( adrs ); + (void)OS_RestoreInterrupts( nOSIntrMode ); + #else + + unsigned long* work; + unsigned long* head; + unsigned long* tail; + unsigned long block; + unsigned long check; + + + if ( !adrs ) return ; + + // + head = pACMemory_FromBodyToHead( adrs ); + tail = pACMemory_FromHeadToTail( head ); + block = nACMemory_HeadBlock( head ); + check = ACMEMORY_CHECK_FREE; + + // + if ( nACMemory_HeadBlock( head ) != nACMemory_TailBlock( tail ) ) + return ; + if ( nACMemory_HeadCheck( head ) != nACMemory_TailCheck( tail ) ) + return ; + + + // + if ( (unsigned long)head != (unsigned long)ACMEMORYPOOL_HEAD ) + { + work = pACMemory_FromTailToHead( head ); + if ( nACMemory_HeadCheck( work ) == check ) + { + block += nACMemory_HeadBlock( work ); + head = work; + } + } + // + if ( (unsigned long)tail != (unsigned long)ACMEMORYPOOL_TAIL ) + { + work = pACMemory_FromHeadToTail( tail ); + if ( nACMemory_TailCheck( work ) == check ) + { + block += nACMemory_TailBlock( work ); + tail = work; + } + } + + // + nACMemory_HeadBlock( head ) = nACMemory_TailBlock( tail ) = block; + nACMemory_HeadCheck( head ) = nACMemory_TailCheck( tail ) = check; + + ACMemory_DebugFill( pACMemory_FromHeadToBody( head ), (block - 4) * 4, 0xFF ); + ACMemory_DebugDump( ); + + #endif +} + + +// +void* ACMemory_Memset( void* adrs, u32 val, u32 cnt ) +{ + if ( !adrs ) return 0; + MI_CpuFill8( (void*)adrs, (u8)val, (u32)cnt ); + return adrs; +} + +// +void* ACMemory_Memcpy( void* dst, void* src, u32 cnt ) +{ + if ( !dst || !src ) return 0; + MI_CpuCopy8( (const void*)src, (void*)dst, (u32)cnt ); + return dst; +} + + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/acsign.c b/build/libraries_sysmenu/acsign/ARM9/src/acsign.c new file mode 100644 index 00000000..f5dc67d8 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/acsign.c @@ -0,0 +1,453 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "acmemory.h" + +// SHA1 +#include "sha.h" +#include "sha1dgst.c" + +#define _DLENGTH_ (160/8) +#define _BLENGTH_ (512/8) + +#define HASHContext SHA_CTX + +#define HASHReset( _context ) (void)SHA1_Init( _context ) +#define HASHSetSource( _context, _ptr, _len ) (void)SHA1_Update( _context, _ptr, _len ) +#define HASHGetDigest( _context, _ptr ) (void)SHA1_Final( _ptr, _context ) + +// BN +#include "bn.h" + +#include "bn_lib.c" +#include "bn_asm.c" +#include "bn_comba.c" +#include "bn_lsh.c" +#include "bn_rsh.c" +#include "bn_word.c" +#include "bn_add.c" +#include "bn_mul.c" +#include "bn_div.c" +#include "bn_exp.c" +#include "bn_sqr.c" +#include "bn_fm_w.c" +#include "bn_gcd.c" +#include "bn_ex_str.c" +#include "bn_ms_w.c" +//#include "bn_me.c" +#include "bn_rec.c" +#include "bn_mont.c" +#include "bn_recp.c" +#include "bn_wdiv.c" +#include "bn_r_exp.c" +#include "bn_m_exp.c" + + +#if !defined( RSA_ENC_DEC ) + +#define BER_NULL 5 +#define BER_OBJECT 6 +#define BER_SEQUENCE 16 +#define BER_OCTET_STRING 4 +#define BER_CONSTRUCTED 0x20 + + +// +// rsa_padding_check_pkcs1_type_1関数相当 +// +static +int decode_padding( unsigned char* pdst_adrs, unsigned int* pdst_size, + unsigned char* psrc_adrs, unsigned int nsrc_size, + int length ) +{ + unsigned char* p; + unsigned char* q; + unsigned char* pe; + int i; + + if (nsrc_size >= length ) + return 0; + + /* The leading 0 was removed by the bignum->bin conversion */ + if (nsrc_size < 10) + return 0; + + p = psrc_adrs; + pe = &(psrc_adrs[nsrc_size]); + /* if (p[0] != 0) goto err; */ + if ( p[0] != 1 ) + return 0; + p++; + + for ( i = 0; i < 8; i++ ) + { + if ( *(p++) != 0xFF ) + return 0; + } + for ( ; p != pe; p++ ) + { + if ( *p != 0xFF ) + break; + } + if ( p == pe ) + return 0; + + if ( *(p++) != 0 ) + return 0; + + *pdst_size = (unsigned int)((int)pe - (int)p); + q = pdst_adrs; + while ( p != pe ) + *(q++)= *(p++); + + return 1; +} + +// +// +// +static +int pk_skip( unsigned char **datap, unsigned int *dlenp, + unsigned char type, unsigned int *lenp) +{ + unsigned char *data = *datap; + unsigned int dlen = *dlenp; + unsigned int len = 0; + unsigned char l; + + if (*(data++) != type) + return 0; + + if (dlen < 1) + return 0; + dlen--; + + if ( (*data & 0x80) != 0 ) + { + l = (unsigned char)( *data & 0x7F ); + if (dlen < (unsigned int)l + 1) + return 0; + dlen -= l; + if (lenp != NULL) + { + data++; + do + { + len <<= 7; + len += (*data & 0x7f); + l--; + } + while (l > 0); + } + else + { + data += l; + } + } + else + { + len = *data; + data++; + if (dlen < 1) + return 0; + dlen--; + } + + *datap = data; + *dlenp = dlen; + if (lenp != NULL) + { + *lenp = len; + } + + return 1; +} + +// +// PK_decode_sighash関数相当 +// +static +int decode_sighash( unsigned char* data, unsigned int dlen, + unsigned char** ppdgst_adrs, unsigned int* pdgst_size, + unsigned char** pphash_adrs, unsigned int* phash_size ) +{ + #if 0 + /* 01 */ OB_cmpu(BER_SEQUENCE, 0, 0), + /* 02 */ OB_down(0, 1), + /* 03 */ OB_cmpu(BER_SEQUENCE, 0, 0), + /* 04 */ OB_down(0, 1), + /* 05 */ OB_cmpu(BER_OBJECT, 0, 0), + /* 06 */ OB_call(OB_F_SET, PK_TYPE_SIG, PK_SIG_DIGEST_OID), + + /* go up a level - we got all we need out of the + * sequence that contains the parameters + * - we could OB_next(0,1) and check that we have BER_NULL + * as then next item but there is no real need to do that + */ + + /* 07 */ OB_up(0, 1), + /* 08 */ OB_next(0, 1), + /* 09 */ OB_cmpu(BER_OCTET_STRING, 0, 0), + /* 10 */ OB_call(OB_F_SET, PK_TYPE_SIG, PK_SIG_HASH), + + /* 11 */ OB_exit(0), + /* 12 */ OB_FINISH, + #endif + + unsigned int len; + + if ( !pk_skip(&data, &dlen, (BER_SEQUENCE|BER_CONSTRUCTED), NULL) ) + return 0; + + if ( !pk_skip(&data, &dlen, (BER_SEQUENCE|BER_CONSTRUCTED), NULL) ) + return 0; + + if ( !pk_skip(&data, &dlen, (BER_OBJECT), &len) ) + return 0; + + /* + if (digest != NULL) + { + digest->adrs = data; + digest->size = len; + } + */ + if ( ppdgst_adrs ) *ppdgst_adrs = data; + if ( pdgst_size ) *pdgst_size = len; + + data += len; + if (dlen < len) + return 0; + dlen -= len; + + if ( !pk_skip(&data, &dlen, BER_NULL, &len) ) + return 0; + data += len; + if (dlen < len) + return 0; + dlen -= len; + + if ( !pk_skip(&data, &dlen, (BER_OCTET_STRING), &len) ) + return 0; + + /* + if (hash != NULL) + { + hash->adrs = data; + hash->size = len; + } + */ + if ( pphash_adrs ) *pphash_adrs = data; + if ( phash_size ) *phash_size = len; + + return 1; +} + +#endif + + + + +// +#define SGN_LEN 128 +#define MOD_LEN 128 +#define EXP_LEN 3 + +int ACSign_Decrypto( + void* buffer, // 出力領域 + void* sgn_ptr, // データへのポインタ + void* key_ptr // キーへのポインタ + ) +{ + BN_CTX* ctx; + BIGNUM src, dst, exp, mod; + void* exp_ptr; + void* mod_ptr; + int nTmp, nWrk; + unsigned char* pAdrs = 0; + unsigned int nSize = 0; + unsigned long nDummyExp = 0x00010001; // 65537固定 + unsigned long aBufferA[ 256 / sizeof (unsigned long) ]; + unsigned long aBufferB[ 256 / sizeof (unsigned long) ]; + + + if ( !buffer ) return 0; + if ( !sgn_ptr ) return 0; + if ( !key_ptr ) return 0; + + // + ACMemory_Clear( ); + + // + exp_ptr = &nDummyExp; + mod_ptr = key_ptr; + + (void)ACMemory_Memset( aBufferA, 0, sizeof aBufferA ); + (void)ACMemory_Memset( aBufferB, 0, sizeof aBufferB ); + + ctx=BN_CTX_new(); + + BN_init( &src ); + BN_init( &dst ); + BN_init( &exp ); + BN_init( &mod ); + + (void)BN_bin2bn( sgn_ptr, SGN_LEN, &src ); + (void)BN_bin2bn( exp_ptr, EXP_LEN, &exp ); + (void)BN_bin2bn( mod_ptr, MOD_LEN, &mod ); + + nTmp = BN_mod_exp( &dst, &src, &exp, &mod, ctx ); + + nTmp = BN_bn2bin( &dst, (unsigned char*)aBufferA ); + + BN_free( &src ); + BN_free( &dst ); + BN_free( &exp ); + BN_free( &mod ); + + if (ctx != NULL) + BN_CTX_free(ctx); + + #if defined( RSA_ENC_DEC ) + + pAdrs = (unsigned char*)aBufferA + 4; //ダミー部4バイトは読み飛ばし + nSize = nTmp; + + (void)ACMemory_Memcpy( buffer, pAdrs, _DLENGTH_ * 4 ); + + #else + + if ( !decode_padding( (unsigned char*)aBufferB, (unsigned int*)&nWrk, (unsigned char*)aBufferA, (unsigned int )nTmp, SGN_LEN ) ) + return 0; + if ( !decode_sighash( (unsigned char*)aBufferB, (unsigned int)nWrk, NULL, NULL, (unsigned char**)&pAdrs, (unsigned int*)&nSize ) ) + return 0; + if ( nSize != _DLENGTH_ ) + return 0; + + (void)ACMemory_Memcpy( buffer, pAdrs, _DLENGTH_ * 1 ); + + #endif + + return 1; +} + + +// +#define ROMH_SIZE 0x0160 +int ACSign_Digest( + void* buffer, // 出力領域 + void* romh_ptr, // データへのポインタ + void* mbin_ptr, // データへのポインタ + int mbin_len, // データの長さ + void* sbin_ptr, // データへのポインタ + int sbin_len, // データの長さ + u32 serial_num // シリアルナンバー + ) +{ + #if defined( RSA_ENC_DEC ) + HASHContext context; + + + if ( !buffer ) return 0; + if ( !romh_ptr ) return 0; + if ( !mbin_ptr || !mbin_len ) return 0; + if ( !sbin_ptr || !sbin_len ) return 0; + + + HASHReset( &context ); + HASHSetSource( &context, romh_ptr, ROMH_SIZE ); + HASHGetDigest( &context, (unsigned char*)buffer + _DLENGTH_ * 0 ); + + HASHReset( &context ); + HASHSetSource( &context, mbin_ptr, mbin_len ); + HASHGetDigest( &context, (unsigned char*)buffer + _DLENGTH_ * 1 ); + + HASHReset( &context ); + HASHSetSource( &context, sbin_ptr, sbin_len ); + HASHGetDigest( &context, (unsigned char*)buffer + _DLENGTH_ * 2 ); + + HASHReset( &context ); + HASHSetSource( &context, buffer, _DLENGTH_ * 3 ); + HASHGetDigest( &context, (unsigned char*)buffer + _DLENGTH_ * 3 ); + + #else + + HASHContext context; + unsigned char aBuffer[ (_DLENGTH_ * 3 + sizeof (unsigned long)) ]; + + if ( !buffer ) return 0; + if ( !romh_ptr ) return 0; + if ( !mbin_ptr || !mbin_len ) return 0; + if ( !sbin_ptr || !sbin_len ) return 0; + + HASHReset( &context ); + HASHSetSource( &context, romh_ptr, ROMH_SIZE ); + HASHGetDigest( &context, (unsigned char*)aBuffer + _DLENGTH_ * 0 ); + + HASHReset( &context ); + HASHSetSource( &context, mbin_ptr, mbin_len ); + HASHGetDigest( &context, (unsigned char*)aBuffer + _DLENGTH_ * 1 ); + + HASHReset( &context ); + HASHSetSource( &context, sbin_ptr, sbin_len ); + HASHGetDigest( &context, (unsigned char*)aBuffer + _DLENGTH_ * 2 ); + + // シリアル番号分 今は0固定 + aBuffer[ (_DLENGTH_ * 3) + 0 ] = (unsigned char)((serial_num >> 0) & 0xFF); + aBuffer[ (_DLENGTH_ * 3) + 1 ] = (unsigned char)((serial_num >> 8) & 0xFF); + aBuffer[ (_DLENGTH_ * 3) + 2 ] = (unsigned char)((serial_num >> 16) & 0xFF); + aBuffer[ (_DLENGTH_ * 3) + 3 ] = (unsigned char)((serial_num >> 24) & 0xFF); + + HASHReset( &context ); + HASHSetSource( &context, (unsigned char*)aBuffer, _DLENGTH_ * 3 + sizeof (unsigned long) ); + HASHGetDigest( &context, (unsigned char*)buffer ); + #endif + return 1; +} + + +// +int ACSign_Compare( + void* decrypto, // ACSign_Decryptoの出力 + void* digest // ACSign_Digestの出力 + ) +{ + unsigned char* ptrA = (unsigned char*)decrypto; + unsigned char* ptrB = (unsigned char*)digest; + int loop; + int test = 1; + + if ( !decrypto ) return 0; + if ( !digest ) return 0; + + #if defined( RSA_ENC_DEC ) + for ( loop = 0; loop < _DLENGTH_ * 4; loop++ ) + #else + for ( loop = 0; loop < _DLENGTH_ * 1; loop++ ) + #endif + { + if ( *ptrA++ != *ptrB++ ) + { + test = 0; + break; + } + } + return test; +} + + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/acsign_util.c b/build/libraries_sysmenu/acsign/ARM9/src/acsign_util.c new file mode 100644 index 00000000..ccda052f --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/acsign_util.c @@ -0,0 +1,111 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include + +#define AUTH_KEY_BUFFER_LEN 128 +#define MB_AUTH_SIGN_SIZE (128) /* digital sign size */ + + +typedef struct MbAuthCode +{ + char magic_code[2]; // マジックナンバー + u16 version; // バージョン + u8 sign[MB_AUTH_SIGN_SIZE]; // 署名 + u32 serial_number; // シリアル番号 +} MbAuthCode; // 16byte + + + +static u8 key_buffer[AUTH_KEY_BUFFER_LEN] = { + 0x9E,0xC1,0xCC,0xC0,0x4A,0x6B,0xD0,0xA0,0x6D,0x62,0xED,0x5F,0x15,0x67,0x87,0x12, + 0xE6,0xF4,0x77,0x1F,0xD8,0x5C,0x81,0xCE,0x0C,0xD0,0x22,0x31,0xF5,0x89,0x08,0xF5, + 0xBE,0x04,0xCB,0xC1,0x4F,0x63,0xD9,0x5A,0x98,0xFF,0xEB,0x36,0x0F,0x9C,0x5D,0xAD, + 0x15,0xB9,0x99,0xFB,0xC6,0x86,0x2C,0x0A,0x0C,0xFC,0xE6,0x86,0x03,0x60,0xD4,0x87, + 0x28,0xD5,0x66,0x42,0x9C,0xF7,0x04,0x14,0x4E,0x6F,0x73,0x20,0xC3,0x3E,0x3F,0xF5, + 0x82,0x2E,0x78,0x18,0xD6,0xCD,0xD5,0xC2,0xDC,0xAA,0x1D,0x34,0x91,0xEC,0x99,0xC9, + 0xF7,0xBF,0xBF,0xA0,0x0E,0x1E,0xF0,0x25,0xF8,0x66,0x17,0x54,0x34,0x28,0x2D,0x28, + 0xA3,0xAE,0xF0,0xA9,0xFA,0x3A,0x70,0x56,0xD2,0x34,0xA9,0xC5,0x9E,0x5D,0xF5,0xE1 +}; + + +int ACSignDecrpto(void *output_buffer, MBDownloadFileInfo *download_file_info_buf) +{ + return ACSign_Decrypto(output_buffer, + ((MbAuthCode *)(download_file_info_buf->auth_code))->sign, + key_buffer); +} + + +int ACSignDigest(void *input_buffer, MBDownloadFileInfo *download_file_info_buf) +{ + int ret_code; + u8 digest_output_buffer[AUTH_BUFFER_LEN]; + + ret_code = ACSign_Digest((void *)digest_output_buffer, // 出力領域 20 Bytes + (void *)(download_file_info_buf->seg[0].recv_addr), + (void *)(download_file_info_buf->seg[1].recv_addr), + (int)(download_file_info_buf->seg[1].size), + (void *)(download_file_info_buf->seg[2].recv_addr), + (int)(download_file_info_buf->seg[2].size), + ((MbAuthCode *)(download_file_info_buf)->auth_code)->serial_number // serial_number + ); + if( ret_code == 0 ) + { + return ret_code; // failure + } + + return ACSign_Compare( + input_buffer, // ACSign_Decryptoの出力 + (void*)digest_output_buffer // ACSign_Digestの出力 + ); +} + +#if 0 +void* doAlloc( int size ) +{ + OSIntrMode nOSIntrMode; + void* alloc = NULL; + + nOSIntrMode = OS_DisableInterrupts( ); + alloc = OS_Alloc( size ); + (void)OS_RestoreInterrupts( nOSIntrMode ); + return alloc; +} + +void doFree( void* adrs ) +{ + OSIntrMode nOSIntrMode; + + nOSIntrMode = OS_DisableInterrupts( ); + OS_Free( adrs ); + (void)OS_RestoreInterrupts( nOSIntrMode ); +} + +void* doMemset( void* adrs, int val, int cnt ) +{ + return memset( adrs, val, cnt ); +} + +void* doMemcpy( void* dst, void* src, int cnt ) +{ + return memcpy( dst, src, cnt ); +} + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_add.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_add.c new file mode 100644 index 00000000..7b36c8b6 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_add.c @@ -0,0 +1,320 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +/** + * @file bn_add.c + * @brief BIGNUM addition and subtraction functions + */ + +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_ADD +#define SPLIT_BN_UADD +#define SPLIT_BN_USUB +#define SPLIT_BN_SUB +#endif /* NO_SPLIT */ + +#ifdef SPLIT_BN_ADD +/* r can == a or b */ +int BN_add(r, a, b) +BIGNUM *r; +BIGNUM *a; +BIGNUM *b; + { + BIGNUM *tmp; + + bn_check_top(a); + bn_check_top(b); + + /* a + b a+b + * a + -b a-b + * -a + b b-a + * -a + -b -(a+b) + */ + if (a->neg ^ b->neg) + { + /* only one is negative */ + if (a->neg) + { tmp=a; a=b; b=tmp; } + + /* we are now a - b */ + + if (BN_ucmp(a,b) < 0) + { + if (!BN_usub(r,b,a)) return(0); + r->neg=1; + } + else + { + if (!BN_usub(r,a,b)) return(0); + r->neg=0; + } + return(1); + } + + if (a->neg) /* both are neg */ + r->neg=1; + else + r->neg=0; + + if (!BN_uadd(r,a,b)) return(0); + return(1); + } +#endif + +#ifdef SPLIT_BN_UADD +/* unsigned add of b to a, r must be large enough */ +int BN_uadd(r,a,b) +BIGNUM *r; +BIGNUM *a; +BIGNUM *b; + { + register int i; + int max,min; + BN_ULONG *ap,*bp,*rp,carry,t1; + BIGNUM *tmp; + + bn_check_top(a); + bn_check_top(b); + + if (a->top < b->top) + { tmp=a; a=b; b=tmp; } + max=a->top; + min=b->top; + + if (bn_wexpand(r,max+1) == NULL) + return(0); + + r->top=max; + + + ap=a->d; + bp=b->d; + rp=r->d; + carry=0; + + carry=bn_add_words(rp,ap,bp,min); + rp+=min; + ap+=min; + bp+=min; + i=min; + + if (carry) + { + while (i < max) + { + i++; + t1= *(ap++); + if ((*(rp++)=(t1+1)&BN_MASK2) >= t1) + { + carry=0; + break; + } + } + if ((i >= max) && carry) + { + *(rp++)=1; + r->top++; + } + } + if (rp != ap) + { + for (; ib from a + * @param r result of subtraction + * @param a pointer to a BIGNUM + * @param b pointer to a BIGNUM + * @pre a must be larger than b + * @return 1 on success, 0 on failure + * @todo On next IRIX port check the validity of IRIX_CC_BUG. + */ +#ifdef SPLIT_BN_USUB +int BN_usub(r, a, b) +BIGNUM *r; +BIGNUM *a; +BIGNUM *b; + { + int max,min; + register BN_ULONG t1,t2,*ap,*bp,*rp; + int i,carry; +#if defined(IRIX_CC_BUG) && !defined(LINT) + int dummy; +#endif + + bn_check_top(a); + bn_check_top(b); + + /* + * check for pre-condition violation + */ + if (a->top < b->top) + { +#ifndef NO_ERR + BNerr(BN_F_BN_USUB,BN_R_ARG2_LT_ARG3); +#endif + return(0); + } + + max=a->top; + min=b->top; + if (bn_wexpand(r,max) == NULL) return(0); + + ap=a->d; + bp=b->d; + rp=r->d; + + /* + * perform the subtraction and see if we + * have a (final) carry + */ + carry=0; + for (i=0; i t2) break; + } + } + + if (rp != ap) + { +#ifdef BN_LIBRARY_SMALL + Memcpy(rp,ap,sizeof(*rp)*(max-i)); +#else /* BN_LIBRARY_SMALL */ + for (;;) + { + if (i++ >= max) break; + rp[0]=ap[0]; + if (i++ >= max) break; + rp[1]=ap[1]; + if (i++ >= max) break; + rp[2]=ap[2]; + if (i++ >= max) break; + rp[3]=ap[3]; + rp+=4; + ap+=4; + } +#endif /* BN_LIBRARY_SMALL */ + } + + r->top=max; + bn_fix_top(r); + return(1); + } +#endif + +#ifdef SPLIT_BN_SUB +int BN_sub(r, a, b) +BIGNUM *r; +BIGNUM *a; +BIGNUM *b; + { + int max; + int add=0,neg=0; + BIGNUM *tmp; + + bn_check_top(a); + bn_check_top(b); + + /* a - b a-b + * a - -b a+b + * -a - b -(a+b) + * -a - -b b-a + */ + if (a->neg) + { + if (b->neg) + { tmp=a; a=b; b=tmp; } + else + { add=1; neg=1; } + } + else + { + if (b->neg) { add=1; neg=0; } + } + + if (add) + { + if (!BN_uadd(r,a,b)) return(0); + r->neg=neg; + return(1); + } + + /* We are actually doing a - b */ + + max=(a->top > b->top)?a->top:b->top; + if (bn_wexpand(r,max) == NULL) return(0); + if (BN_ucmp(a,b) < 0) + { + if (!BN_usub(r,b,a)) return(0); + r->neg=1; + } + else + { + if (!BN_usub(r,a,b)) return(0); + r->neg=0; + } + return(1); + } +#endif + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_asm.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_asm.c new file mode 100644 index 00000000..64efa61f --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_asm.c @@ -0,0 +1,525 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#ifndef OPT_BN_ASM + +#define BN_MUL_ADD_WORDS + +#ifndef BN_MUL_WORDS +#define BN_MUL_WORDS +#endif + +#ifndef BN_SQR_WORDS +#define BN_SQR_WORDS +#endif + +#ifndef BN_ADD_WORDS +#define BN_ADD_WORDS +#endif + +#ifndef BN_SUB_WORDS +#define BN_SUB_WORDS +#endif + +#endif + + +#include "bn_lcl.h" + +#ifdef BN_LLONG + +/* + * bn_mul_add_words + * + * for(i=0;i=0; i--) + fprintf(stderr,BN_HEX_FMT,ap[i]); + fprintf(stderr,"*"); + fprintf(stderr,BN_HEX_FMT,w); + fprintf(stderr,"+"); + for (i=num-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,rp[i]); +#endif + + for (;;) + { + mul_add(rp[0],ap[0],w,c1); + if (--num == 0) break; + mul_add(rp[1],ap[1],w,c1); + if (--num == 0) break; + mul_add(rp[2],ap[2],w,c1); + if (--num == 0) break; + mul_add(rp[3],ap[3],w,c1); + if (--num == 0) break; + ap+=4; + rp+=4; + } + +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + fprintf(stderr,"-"); + fprintf(stderr,BN_HEX_FMT,c1); + for (i=nn-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,rp[i]); + fprintf(stderr,"\n"); + } +#endif + return(c1); + } +#endif + +#ifdef BN_MUL_WORDS +BN_ULONG bn_mul_words(rp,ap,num,w) +BN_ULONG *rp,*ap; +int num; +BN_ULONG w; + { + BN_ULONG c1=0; + + bn_check_num(num); + if (num <= 0) return(c1); + +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + { + int i,nn=num; + + for (i=num-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,ap[i]); + fprintf(stderr,"*"); + fprintf(stderr,BN_HEX_FMT,w); +#endif + + for (;;) + { + mul(rp[0],ap[0],w,c1); + if (--num == 0) break; + mul(rp[1],ap[1],w,c1); + if (--num == 0) break; + mul(rp[2],ap[2],w,c1); + if (--num == 0) break; + mul(rp[3],ap[3],w,c1); + if (--num == 0) break; + ap+=4; + rp+=4; + } + +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + fprintf(stderr,"-"); + fprintf(stderr,BN_HEX_FMT,c1); + for (i=nn-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,rp[i]); + fprintf(stderr,"\n"); + } +#endif + return(c1); + } +#endif + +#ifdef BN_SQR_WORDS +void bn_sqr_words(r,a,n) +BN_ULONG *r,*a; +int n; + { + bn_check_num(n); + if (n <= 0) return; + +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + { + int i,nn=n; + + for (i=n-1; i>=0; i--) + { + fprintf(stderr,BN_HEX_FMT,a[i]); + if (i != 0) + fprintf(stderr,"^2*2^%X+",i*2*BN_BITS2); + else + fprintf(stderr,"^2"); + } +#endif + + for (;;) + { + BN_ULLONG t; + + t=(BN_ULLONG)(a[0])*(a[0]); + r[0]=Lw(t); r[1]=Hw(t); + if (--n == 0) break; + + t=(BN_ULLONG)(a[1])*(a[1]); + r[2]=Lw(t); r[3]=Hw(t); + if (--n == 0) break; + + t=(BN_ULLONG)(a[2])*(a[2]); + r[4]=Lw(t); r[5]=Hw(t); + if (--n == 0) break; + + t=(BN_ULLONG)(a[3])*(a[3]); + r[6]=Lw(t); r[7]=Hw(t); + if (--n == 0) break; + + a+=4; + r+=8; + } +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + + fprintf(stderr,"-"); + for (i=nn+nn-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,r[i]); + fprintf(stderr,"\n"); + } +#endif + } +#endif + +#else + +#ifdef BN_MUL_ADD_WORDS + +BN_ULONG bn_mul_add_words(rp,ap,num,w) +BN_ULONG *rp,*ap; +int num; +BN_ULONG w; + { + BN_ULONG c=0; + BN_ULONG bl,bh,b_hl; + + bn_check_num(num); + if (num <= 0) return((BN_ULONG)0); + + bl=LBITS(w); + bh=HBITS(w); + b_hl=bh-bl; +/* +{ int i,nnum=num; +BN_ULONG *rrp=rp; +for (i=num-1; i>=0; i--) printf("%02X",rp[i]); +printf("+"); +for (i=num-1; i>=0; i--) printf("%02X",ap[i]); +printf("*%02X - ",w); +*/ + for (;;) + { + mul_add(rp[0],ap[0],bl,bh,b_hl,c); + if (--num == 0) break; + mul_add(rp[1],ap[1],bl,bh,b_hl,c); + if (--num == 0) break; + mul_add(rp[2],ap[2],bl,bh,b_hl,c); + if (--num == 0) break; + mul_add(rp[3],ap[3],bl,bh,b_hl,c); + if (--num == 0) break; + ap+=4; + rp+=4; + } + +/* +printf("%02X",c); +for (i=nnum-1; i>=0; i--) printf("%02X",rrp[i]); +printf("\n"); +} +*/ + return(c); + } + +#endif + +#ifdef BN_MUL_WORDS +BN_ULONG bn_mul_words(rp,ap,num,w) +BN_ULONG *rp,*ap; +int num; +BN_ULONG w; + { + BN_ULONG carry=0; + BN_ULONG bl,bh; + + bn_check_num(num); + if (num <= 0) return((BN_ULONG)0); + + bl=LBITS(w); + bh=HBITS(w); + + for (;;) + { + mul(rp[0],ap[0],bl,bh,carry); + if (--num == 0) break; + mul(rp[1],ap[1],bl,bh,carry); + if (--num == 0) break; + mul(rp[2],ap[2],bl,bh,carry); + if (--num == 0) break; + mul(rp[3],ap[3],bl,bh,carry); + if (--num == 0) break; + ap+=4; + rp+=4; + } + return(carry); + } +#endif + +#ifdef BN_SQR_WORDS +void bn_sqr_words(r,a,n) +BN_ULONG *r,*a; +int n; + { + bn_check_num(n); + if (n <= 0) return; + for (;;) + { + sqr64(r[0],r[1],a[0]); + if (--n == 0) break; + + sqr64(r[2],r[3],a[1]); + if (--n == 0) break; + + sqr64(r[4],r[5],a[2]); + if (--n == 0) break; + + sqr64(r[6],r[7],a[3]); + if (--n == 0) break; + + a+=4; + r+=8; + } + } +#endif + +#endif + +#ifdef BN_ADD_WORDS +#ifdef BN_LLONG +BN_ULONG bn_add_words(r,a,b,n) +BN_ULONG *r,*a,*b; +int n; + { + BN_ULLONG ll=0; + + bn_check_num(n); + if (n <= 0) return((BN_ULONG)0); + +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + { + int i,nn=n; + + for (i=n-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,a[i]); + fprintf(stderr,"+"); + for (i=n-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,b[i]); +#endif + + for (;;) + { + ll+=(BN_ULLONG)a[0]+b[0]; + r[0]=(BN_ULONG)ll&BN_MASK2; + ll>>=BN_BITS2; + if (--n <= 0) break; + + ll+=(BN_ULLONG)a[1]+b[1]; + r[1]=(BN_ULONG)ll&BN_MASK2; + ll>>=BN_BITS2; + if (--n <= 0) break; + + ll+=(BN_ULLONG)a[2]+b[2]; + r[2]=(BN_ULONG)ll&BN_MASK2; + ll>>=BN_BITS2; + if (--n <= 0) break; + + ll+=(BN_ULLONG)a[3]+b[3]; + r[3]=(BN_ULONG)ll&BN_MASK2; + ll>>=BN_BITS2; + if (--n <= 0) break; + + a+=4; + b+=4; + r+=4; + } +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + fprintf(stderr,"-"); + fprintf(stderr,BN_HEX_FMT,(BN_ULONG)ll); + for (i=nn-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,r[i]); + fprintf(stderr,"\n"); + } +#endif + return((BN_ULONG)ll); + } +#else +BN_ULONG bn_add_words(r,a,b,n) +BN_ULONG *r,*a,*b; +int n; + { + BN_ULONG c,l,t; + + bn_check_num(n); + if (n <= 0) return((BN_ULONG)0); + + c=0; + for (;;) + { + t=a[0]; + t=(t+c)&BN_MASK2; + c=(t < c); + l=(t+b[0])&BN_MASK2; + c+=(l < t); + r[0]=l; + if (--n <= 0) break; + + t=a[1]; + t=(t+c)&BN_MASK2; + c=(t < c); + l=(t+b[1])&BN_MASK2; + c+=(l < t); + r[1]=l; + if (--n <= 0) break; + + t=a[2]; + t=(t+c)&BN_MASK2; + c=(t < c); + l=(t+b[2])&BN_MASK2; + c+=(l < t); + r[2]=l; + if (--n <= 0) break; + + t=a[3]; + t=(t+c)&BN_MASK2; + c=(t < c); + l=(t+b[3])&BN_MASK2; + c+=(l < t); + r[3]=l; + if (--n <= 0) break; + + a+=4; + b+=4; + r+=4; + } + + return((BN_ULONG)c); + } +#endif +#endif + +#ifdef BN_SUB_WORDS +BN_ULONG bn_sub_words(r,a,b,n) +BN_ULONG *r,*a,*b; +int n; + { + BN_ULONG c,t1,t2; + + bn_check_num(n); + if (n <= 0) return((BN_ULONG)0); + +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + { + int i,nn=n; + + for (i=n-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,a[i]); + fprintf(stderr,"-"); + for (i=n-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,b[i]); +#endif + + c=0; + for (;;) + { + t1=a[0]; t2=b[0]; + r[0]=(t1-t2-c)&BN_MASK2; + if (t1 != t2) c=(t1 < t2); + if (--n <= 0) break; + + t1=a[1]; t2=b[1]; + r[1]=(t1-t2-c)&BN_MASK2; + if (t1 != t2) c=(t1 < t2); + if (--n <= 0) break; + + t1=a[2]; t2=b[2]; + r[2]=(t1-t2-c)&BN_MASK2; + if (t1 != t2) c=(t1 < t2); + if (--n <= 0) break; + + t1=a[3]; t2=b[3]; + r[3]=(t1-t2-c)&BN_MASK2; + if (t1 != t2) c=(t1 < t2); + if (--n <= 0) break; + + a+=4; + b+=4; + r+=4; + } + +#if defined(BN_ASM_DEBUG) && !defined(NO_FP_API) + fprintf(stderr,"- "); + if (c) fprintf(stderr,"-"); + for (i=nn-1; i>=0; i--) + fprintf(stderr,BN_HEX_FMT,r[i]); + fprintf(stderr,"\n"); + } +#endif + return(c); + } +#endif + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_comba.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_comba.c new file mode 100644 index 00000000..462c8f4d --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_comba.c @@ -0,0 +1,450 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_MUL_COMBA8 +#define SPLIT_BN_MUL_COMBA4 +#define SPLIT_BN_SQR_COMBA8 +#define SPLIT_BN_SQR_COMBA4 +#endif /* NO_SPLIT */ + +#ifndef OPT_BN_ASM +/* #if 1 */ + +#ifdef BN_LLONG +#define mul_add_c(a,b,c0,c1,c2) \ + t=(BN_ULLONG)a*b; \ + t1=(BN_ULONG)Lw(t); \ + t2=(BN_ULONG)Hw(t); \ + c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \ + c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++; + +#define mul_add_c2(a,b,c0,c1,c2) \ + t=(BN_ULLONG)a*b; \ + tt=(t+t)&BN_MASK; \ + if (tt < t) c2++; \ + t1=(BN_ULONG)Lw(tt); \ + t2=(BN_ULONG)Hw(tt); \ + c0=(c0+t1)&BN_MASK2; \ + if ((c0 < t1) && (((++t2)&BN_MASK2) == 0)) c2++; \ + c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++; + +#define sqr_add_c(a,i,c0,c1,c2) \ + t=(BN_ULLONG)a[i]*a[i]; \ + t1=(BN_ULONG)Lw(t); \ + t2=(BN_ULONG)Hw(t); \ + c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \ + c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++; + +#define sqr_add_c2(a,i,j,c0,c1,c2) \ + mul_add_c2((a)[i],(a)[j],c0,c1,c2) +#else +#define mul_add_c(a,b,c0,c1,c2) \ + t1=LBITS(a); t2=HBITS(a); \ + bl=LBITS(b); bh=HBITS(b); \ + mul64(t1,t2,bl,bh); \ + c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \ + c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++; + +#define mul_add_c2(a,b,c0,c1,c2) \ + t1=LBITS(a); t2=HBITS(a); \ + bl=LBITS(b); bh=HBITS(b); \ + mul64(t1,t2,bl,bh); \ + if (t2 & BN_TBIT) c2++; \ + t2=(t2+t2)&BN_MASK2; \ + if (t1 & BN_TBIT) t2++; \ + t1=(t1+t1)&BN_MASK2; \ + c0=(c0+t1)&BN_MASK2; \ + if ((c0 < t1) && (((++t2)&BN_MASK2) == 0)) c2++; \ + c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++; + +#define sqr_add_c(a,i,c0,c1,c2) \ + sqr64(t1,t2,(a)[i]); \ + c0=(c0+t1)&BN_MASK2; if ((c0) < t1) t2++; \ + c1=(c1+t2)&BN_MASK2; if ((c1) < t2) c2++; + +#define sqr_add_c2(a,i,j,c0,c1,c2) \ + mul_add_c2((a)[i],(a)[j],c0,c1,c2) +#endif + +#if defined(BN_MUL_COMBA) + +#ifdef SPLIT_BN_MUL_COMBA8 +#undef bn_mul_comba8 +void bn_mul_comba8(r,a,b) +BN_ULONG *r,*a,*b; + { +#ifdef BN_LLONG + BN_ULLONG t; +#else + BN_ULONG bl,bh; +#endif + BN_ULONG t1,t2; + BN_ULONG c1,c2,c3; + + c1=0; + c2=0; + c3=0; + mul_add_c(a[0],b[0],c1,c2,c3); + r[0]=c1; + c1=0; + mul_add_c(a[0],b[1],c2,c3,c1); + mul_add_c(a[1],b[0],c2,c3,c1); + r[1]=c2; + c2=0; + mul_add_c(a[2],b[0],c3,c1,c2); + mul_add_c(a[1],b[1],c3,c1,c2); + mul_add_c(a[0],b[2],c3,c1,c2); + r[2]=c3; + c3=0; + mul_add_c(a[0],b[3],c1,c2,c3); + mul_add_c(a[1],b[2],c1,c2,c3); + mul_add_c(a[2],b[1],c1,c2,c3); + mul_add_c(a[3],b[0],c1,c2,c3); + r[3]=c1; + c1=0; + mul_add_c(a[4],b[0],c2,c3,c1); + mul_add_c(a[3],b[1],c2,c3,c1); + mul_add_c(a[2],b[2],c2,c3,c1); + mul_add_c(a[1],b[3],c2,c3,c1); + mul_add_c(a[0],b[4],c2,c3,c1); + r[4]=c2; + c2=0; + mul_add_c(a[0],b[5],c3,c1,c2); + mul_add_c(a[1],b[4],c3,c1,c2); + mul_add_c(a[2],b[3],c3,c1,c2); + mul_add_c(a[3],b[2],c3,c1,c2); + mul_add_c(a[4],b[1],c3,c1,c2); + mul_add_c(a[5],b[0],c3,c1,c2); + r[5]=c3; + c3=0; + mul_add_c(a[6],b[0],c1,c2,c3); + mul_add_c(a[5],b[1],c1,c2,c3); + mul_add_c(a[4],b[2],c1,c2,c3); + mul_add_c(a[3],b[3],c1,c2,c3); + mul_add_c(a[2],b[4],c1,c2,c3); + mul_add_c(a[1],b[5],c1,c2,c3); + mul_add_c(a[0],b[6],c1,c2,c3); + r[6]=c1; + c1=0; + mul_add_c(a[0],b[7],c2,c3,c1); + mul_add_c(a[1],b[6],c2,c3,c1); + mul_add_c(a[2],b[5],c2,c3,c1); + mul_add_c(a[3],b[4],c2,c3,c1); + mul_add_c(a[4],b[3],c2,c3,c1); + mul_add_c(a[5],b[2],c2,c3,c1); + mul_add_c(a[6],b[1],c2,c3,c1); + mul_add_c(a[7],b[0],c2,c3,c1); + r[7]=c2; + c2=0; + mul_add_c(a[7],b[1],c3,c1,c2); + mul_add_c(a[6],b[2],c3,c1,c2); + mul_add_c(a[5],b[3],c3,c1,c2); + mul_add_c(a[4],b[4],c3,c1,c2); + mul_add_c(a[3],b[5],c3,c1,c2); + mul_add_c(a[2],b[6],c3,c1,c2); + mul_add_c(a[1],b[7],c3,c1,c2); + r[8]=c3; + c3=0; + mul_add_c(a[2],b[7],c1,c2,c3); + mul_add_c(a[3],b[6],c1,c2,c3); + mul_add_c(a[4],b[5],c1,c2,c3); + mul_add_c(a[5],b[4],c1,c2,c3); + mul_add_c(a[6],b[3],c1,c2,c3); + mul_add_c(a[7],b[2],c1,c2,c3); + r[9]=c1; + c1=0; + mul_add_c(a[7],b[3],c2,c3,c1); + mul_add_c(a[6],b[4],c2,c3,c1); + mul_add_c(a[5],b[5],c2,c3,c1); + mul_add_c(a[4],b[6],c2,c3,c1); + mul_add_c(a[3],b[7],c2,c3,c1); + r[10]=c2; + c2=0; + mul_add_c(a[4],b[7],c3,c1,c2); + mul_add_c(a[5],b[6],c3,c1,c2); + mul_add_c(a[6],b[5],c3,c1,c2); + mul_add_c(a[7],b[4],c3,c1,c2); + r[11]=c3; + c3=0; + mul_add_c(a[7],b[5],c1,c2,c3); + mul_add_c(a[6],b[6],c1,c2,c3); + mul_add_c(a[5],b[7],c1,c2,c3); + r[12]=c1; + c1=0; + mul_add_c(a[6],b[7],c2,c3,c1); + mul_add_c(a[7],b[6],c2,c3,c1); + r[13]=c2; + c2=0; + mul_add_c(a[7],b[7],c3,c1,c2); + r[14]=c3; + r[15]=c1; + } +#endif + +#ifdef SPLIT_BN_MUL_COMBA4 +#undef bn_mul_comba4 +void bn_mul_comba4(r,a,b) +BN_ULONG *r,*a,*b; + { +#ifdef BN_LLONG + BN_ULLONG t; +#else + BN_ULONG bl,bh; +#endif + BN_ULONG t1,t2; + BN_ULONG c1,c2,c3; + + c1=0; + c2=0; + c3=0; + mul_add_c(a[0],b[0],c1,c2,c3); + r[0]=c1; + c1=0; + mul_add_c(a[0],b[1],c2,c3,c1); + mul_add_c(a[1],b[0],c2,c3,c1); + r[1]=c2; + c2=0; + mul_add_c(a[2],b[0],c3,c1,c2); + mul_add_c(a[1],b[1],c3,c1,c2); + mul_add_c(a[0],b[2],c3,c1,c2); + r[2]=c3; + c3=0; + mul_add_c(a[0],b[3],c1,c2,c3); + mul_add_c(a[1],b[2],c1,c2,c3); + mul_add_c(a[2],b[1],c1,c2,c3); + mul_add_c(a[3],b[0],c1,c2,c3); + r[3]=c1; + c1=0; + mul_add_c(a[3],b[1],c2,c3,c1); + mul_add_c(a[2],b[2],c2,c3,c1); + mul_add_c(a[1],b[3],c2,c3,c1); + r[4]=c2; + c2=0; + mul_add_c(a[2],b[3],c3,c1,c2); + mul_add_c(a[3],b[2],c3,c1,c2); + r[5]=c3; + c3=0; + mul_add_c(a[3],b[3],c1,c2,c3); + r[6]=c1; + r[7]=c2; + } +#endif + +#else + +#ifdef SPLIT_BN_MUL_COMBA4 +#undef bn_mul_comba4 +void bn_mul_comba4(r,a,b) +BN_ULONG *r,*a,*b; + { + r[4]=bn_mul_words( &(r[0]),a,4,b[0]); + r[5]=bn_mul_add_words(&(r[1]),a,4,b[1]); + r[6]=bn_mul_add_words(&(r[2]),a,4,b[2]); + r[7]=bn_mul_add_words(&(r[3]),a,4,b[3]); + } +#endif + +#ifdef SPLIT_BN_MUL_COMBA8 +#undef bn_mul_comba8 +void bn_mul_comba8(r,a,b) +BN_ULONG *r,*a,*b; + { + r[ 8]=bn_mul_words( &(r[0]),a,8,b[0]); + r[ 9]=bn_mul_add_words(&(r[1]),a,8,b[1]); + r[10]=bn_mul_add_words(&(r[2]),a,8,b[2]); + r[11]=bn_mul_add_words(&(r[3]),a,8,b[3]); + r[12]=bn_mul_add_words(&(r[4]),a,8,b[4]); + r[13]=bn_mul_add_words(&(r[5]),a,8,b[5]); + r[14]=bn_mul_add_words(&(r[6]),a,8,b[6]); + r[15]=bn_mul_add_words(&(r[7]),a,8,b[7]); + } +#endif + +#endif /* BN_MUL_COMBA */ + +#ifdef BN_SQR_COMBA + +#ifdef SPLIT_BN_SQR_COMBA8 +#undef bn_sqr_comba8 +void bn_sqr_comba8(r,a) +BN_ULONG *r,*a; + { +#ifdef BN_LLONG + BN_ULLONG t,tt; +#else + BN_ULONG bl,bh; +#endif + BN_ULONG t1,t2; + BN_ULONG c1,c2,c3; + + c1=0; + c2=0; + c3=0; + sqr_add_c(a,0,c1,c2,c3); + r[0]=c1; + c1=0; + sqr_add_c2(a,1,0,c2,c3,c1); + r[1]=c2; + c2=0; + sqr_add_c(a,1,c3,c1,c2); + sqr_add_c2(a,2,0,c3,c1,c2); + r[2]=c3; + c3=0; + sqr_add_c2(a,3,0,c1,c2,c3); + sqr_add_c2(a,2,1,c1,c2,c3); + r[3]=c1; + c1=0; + sqr_add_c(a,2,c2,c3,c1); + sqr_add_c2(a,3,1,c2,c3,c1); + sqr_add_c2(a,4,0,c2,c3,c1); + r[4]=c2; + c2=0; + sqr_add_c2(a,5,0,c3,c1,c2); + sqr_add_c2(a,4,1,c3,c1,c2); + sqr_add_c2(a,3,2,c3,c1,c2); + r[5]=c3; + c3=0; + sqr_add_c(a,3,c1,c2,c3); + sqr_add_c2(a,4,2,c1,c2,c3); + sqr_add_c2(a,5,1,c1,c2,c3); + sqr_add_c2(a,6,0,c1,c2,c3); + r[6]=c1; + c1=0; + sqr_add_c2(a,7,0,c2,c3,c1); + sqr_add_c2(a,6,1,c2,c3,c1); + sqr_add_c2(a,5,2,c2,c3,c1); + sqr_add_c2(a,4,3,c2,c3,c1); + r[7]=c2; + c2=0; + sqr_add_c(a,4,c3,c1,c2); + sqr_add_c2(a,5,3,c3,c1,c2); + sqr_add_c2(a,6,2,c3,c1,c2); + sqr_add_c2(a,7,1,c3,c1,c2); + r[8]=c3; + c3=0; + sqr_add_c2(a,7,2,c1,c2,c3); + sqr_add_c2(a,6,3,c1,c2,c3); + sqr_add_c2(a,5,4,c1,c2,c3); + r[9]=c1; + c1=0; + sqr_add_c(a,5,c2,c3,c1); + sqr_add_c2(a,6,4,c2,c3,c1); + sqr_add_c2(a,7,3,c2,c3,c1); + r[10]=c2; + c2=0; + sqr_add_c2(a,7,4,c3,c1,c2); + sqr_add_c2(a,6,5,c3,c1,c2); + r[11]=c3; + c3=0; + sqr_add_c(a,6,c1,c2,c3); + sqr_add_c2(a,7,5,c1,c2,c3); + r[12]=c1; + c1=0; + sqr_add_c2(a,7,6,c2,c3,c1); + r[13]=c2; + c2=0; + sqr_add_c(a,7,c3,c1,c2); + r[14]=c3; + r[15]=c1; + } +#endif + +#ifdef SPLIT_BN_SQR_COMBA4 +#undef bn_sqr_comba4 +void bn_sqr_comba4(r,a) +BN_ULONG *r,*a; + { +#ifdef BN_LLONG + BN_ULLONG t,tt; +#else + BN_ULONG bl,bh; +#endif + BN_ULONG t1,t2; + BN_ULONG c1,c2,c3; + + c1=0; + c2=0; + c3=0; + sqr_add_c(a,0,c1,c2,c3); + r[0]=c1; + c1=0; + sqr_add_c2(a,1,0,c2,c3,c1); + r[1]=c2; + c2=0; + sqr_add_c(a,1,c3,c1,c2); + sqr_add_c2(a,2,0,c3,c1,c2); + r[2]=c3; + c3=0; + sqr_add_c2(a,3,0,c1,c2,c3); + sqr_add_c2(a,2,1,c1,c2,c3); + r[3]=c1; + c1=0; + sqr_add_c(a,2,c2,c3,c1); + sqr_add_c2(a,3,1,c2,c3,c1); + r[4]=c2; + c2=0; + sqr_add_c2(a,3,2,c3,c1,c2); + r[5]=c3; + c3=0; + sqr_add_c(a,3,c1,c2,c3); + r[6]=c1; + r[7]=c2; + } +#endif +#else + +#ifdef SPLIT_BN_SQR_COMBA4 +/* hmm... is it faster just to do a multiply? */ +#undef bn_sqr_comba4 +void bn_sqr_comba4(r,a) +BN_ULONG *r,*a; + { + BN_ULONG t[8]; + bn_sqr_normal(r,a,4,t); + } +#endif + +#ifdef SPLIT_BN_SQR_COMBA8 +#undef bn_sqr_comba8 +void bn_sqr_comba8(r,a) +BN_ULONG *r,*a; + { + BN_ULONG t[16]; + bn_sqr_normal(r,a,8,t); + } +#endif + +#endif + +#endif /* OPT_BN_ASM */ + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_div.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_div.c new file mode 100644 index 00000000..7036d196 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_div.c @@ -0,0 +1,381 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ +/** + * @file bn_div.c + * @brief Division and modulus functions + */ +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_DIV +#define SPLIT_BN_MOD +#endif /* NO_SPLIT */ + +#ifdef SPLIT_BN_DIV +/* The old slow way */ +#ifdef OLD_BN_DIVISION +int BN_div(dv, rem, m, d,ctx) +BIGNUM *dv; +BIGNUM *rem; +BIGNUM *m; +BIGNUM *d; +BN_CTX *ctx; + { + int i,nm,nd; + BIGNUM *D; + + bn_check_top(m); + bn_check_top(d); + if (BN_is_zero(d)) + { +#ifndef NO_ERR + BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); +#endif + return(0); + } + + if (BN_ucmp(m,d) < 0) + { + if (rem != NULL) + { if (BN_copy(rem,m) == NULL) return(0); } + if (dv != NULL) BN_zero(dv); + return(1); + } + + D= &(ctx->bn[ctx->tos]); + if (dv == NULL) dv= &(ctx->bn[ctx->tos+1]); + if (rem == NULL) rem= &(ctx->bn[ctx->tos+2]); + + nd=BN_num_bits(d); + nm=BN_num_bits(m); + if (BN_copy(D,d) == NULL) return(0); + if (BN_copy(rem,m) == NULL) return(0); + + /* The next 2 are needed so we can do a dv->d[0]|=1 later + * since BN_lshift1 will only work once there is a value + */ + BN_zero(dv); + bn_wexpand(dv,1); + dv->top=1; + + if (!BN_lshift(D,D,nm-nd)) return(0); + for (i=nm-nd; i>=0; i--) + { + if (!BN_lshift1(dv,dv)) return(0); + if (BN_ucmp(rem,D) >= 0) + { + dv->d[0]|=1; + if (!BN_usub(rem,rem,D)) return(0); + } +/* CAN IMPROVE (and have now :=) */ + if (!BN_rshift1(D,D)) return(0); + } + rem->neg=BN_is_zero(rem)?0:m->neg; + dv->neg=m->neg^d->neg; + return(1); + } + +#else +/** + * Performs Big number division + * + * @param dv [In] division + * @param rm [Out] remainder + * @param num [In] number + * @param divisor [In] divisor + * @param ctx [In] Temporary data storage + * + * @todo add more comments to this function + */ +int BN_div(BIGNUM *dv, BIGNUM *rm, BIGNUM *num, BIGNUM *divisor, BN_CTX *ctx) + { + int norm_shift,i,j,loop; + BIGNUM *tmp,wnum,*snum,*sdiv,*res; + BN_ULONG *resp,*wnump; + BN_ULONG d0,d1; + int num_n,div_n; + + bn_check_top(num); + bn_check_top(divisor); + + if (BN_is_zero(divisor)) + { +#ifndef NO_ERR + BNerr(BN_F_BN_DIV,BN_R_DIV_BY_ZERO); +#endif + return(0); + } + + if (BN_ucmp(num,divisor) < 0) + { + if (rm != NULL) + { if (BN_copy(rm,num) == NULL) return(0); } + if (dv != NULL) (void)BN_zero(dv); + return(1); + } + + tmp= &(ctx->bn[ctx->tos]); + tmp->neg=0; + snum= &(ctx->bn[ctx->tos+1]); + sdiv= &(ctx->bn[ctx->tos+2]); + if (dv == NULL) + res= &(ctx->bn[ctx->tos+3]); + else res=dv; + + /* First we normalise the numbers */ + norm_shift=BN_BITS2-((BN_num_bits(divisor))%BN_BITS2); + if (!BN_lshift(sdiv,divisor,norm_shift)) return(0); + sdiv->neg=0; + norm_shift+=BN_BITS2; + if (!BN_lshift(snum,num,norm_shift)) return(0); + snum->neg=0; + div_n=sdiv->top; + num_n=snum->top; + loop=num_n-div_n; + + /* Lets setup a 'window' into snum + * This is the part that corresponds to the current + * 'area' being divided */ + BN_init(&wnum); + wnum.d= &(snum->d[loop]); + wnum.top= div_n; + wnum.max= snum->max+1; /* a bit of a lie */ + + /* Get the top 2 words of sdiv */ + /* i=sdiv->top; */ + d0=sdiv->d[div_n-1]; + d1=(div_n == 1)?0:sdiv->d[div_n-2]; + + /* pointer to the 'top' of snum */ + wnump= &(snum->d[num_n-1]); + + /* Setup to 'res' */ + if (!bn_wexpand(res,(loop+1))) goto err; + res->neg= (num->neg^divisor->neg); + res->top=loop; + resp= &(res->d[loop-1]); + + /* space for temp */ + if (!bn_wexpand(tmp,(div_n+1))) goto err; + + if (BN_ucmp(&wnum,sdiv) >= 0) + { + if (!BN_usub(&wnum,&wnum,sdiv)) goto err; + *resp=1; + res->d[res->top-1]=1; + } + else + res->top--; + resp--; + + for (i=0; i>BN_BITS2) || + (t2 <= ((BN_ULLONG)(rem< t1l) t3h++; + t3h=(t1h-t3h)&BN_MASK2; + + /*if ((t3>>BN_BITS2) || + (t2 <= ((t3<d,sdiv->d,div_n,q); + tmp->d[div_n]=l0; + for (j=div_n+1; j>0; j--) + if (tmp->d[j-1]) break; + tmp->top=j; + + j=wnum.top; +#ifdef BN_DEBUG + /* Sometimes this is 0 now (wnum.top is not). + * We need to look at this some time, I am quite + * sure it has no affect. + */ + bn_fix_top(&wnum); +#endif + (void)BN_sub(&wnum,&wnum,tmp); + + snum->top=snum->top+wnum.top-j; + + if (wnum.neg) + { + q--; + j=wnum.top; + (void)BN_add(&wnum,&wnum,sdiv); + snum->top+=wnum.top-j; + } + *(resp--)=q; + wnump--; + } + bn_fix_top(snum); + if (rm != NULL) + { + i=num->neg; /* just in case num == rm */ + if (BN_rshift(rm,snum,norm_shift) == 0) + return(0); + rm->neg=i; + } + return(1); +err: + return(0); + } +#endif +#endif + +#ifdef SPLIT_BN_MOD +/** + * Calculate the remainder where rem = m mod d + * + * @param rem [Out] Modulus result + * @param m [In] Base value + * @param d [In] Divisor + * @param ctx [In] BN_CTX for data space + * + * @pre variables are initialised and valid + * @post rem contained modulus + * + * @retval 1 success + * @retval 0 failure + * + * @note when BN_LIBRARY_SMALL define uses following algorithm + * otherwise calls through to BN_div + * + * @note m < d rem = m + * (length m = length of d) and (m > d) , rem = m - d + * alg otherwise + * let rem = m + * loop while rem > d + * let dv = shift left d, n bits to = length rem + * if dv > rem + * let dv = shift left d, n - 1 bits ( = length rem - 1) + * end if + * let rem = rem - dv; + * end loop + * + * @relates BN_div + */ +int BN_mod(BIGNUM *rem, BIGNUM *m, BIGNUM *d, BN_CTX *ctx) +{ +#ifdef BN_LIBRARY_SMALL + int nm,nd; + BIGNUM *dv, *dv2; + + /* if m < d , mod = m */ + if (BN_ucmp(m,d) < 0) + return((BN_copy(rem,m) == NULL)?0:1); + + dv= &(ctx->bn[ctx->tos]); + dv2 = &(ctx->bn[ctx->tos+1]); + + nm=BN_num_bits(m); + nd=BN_num_bits(d); + + /* if bits m = bits d and m >= d (from above) + * rem = m - d + */ + if(nm == nd) + { + BN_usub(rem, m, d); + goto end; + } + + if (BN_copy(rem, m) == NULL) + { + return 0; + } + + /* while the rem > d */ + while(BN_ucmp(rem,d) > 0) + { + nm=BN_num_bits(rem); + if(!BN_lshift(dv2,d,nm-nd)) + { + return(0); + } + + if(BN_ucmp(dv2, rem) >0) + { + if(!BN_lshift(dv2,d,nm-nd-1)) + { + return(0); + } + } + + BN_usub(rem,rem,dv2); + } +end: + return(1); +#else + return(BN_div(NULL,rem,m,d,ctx)); +#endif +} +#endif + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_ex_str.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_ex_str.c new file mode 100644 index 00000000..02e31d1c --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_ex_str.c @@ -0,0 +1,453 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ +#include "bn_lcl.h" + +const static unsigned char p2 []={0,8,1,1,1,1,1,0,0,0}; +const static unsigned char p4 []={0,8,1,1,1,4,1,0,0,0}; +const static unsigned char p16[]={0,8,1,1,1,16,1,0,0,0}; + +/* The following defines allow for redefinition of the window size + * of the exponent string at compile time, this affects the size + * of temporary data required in montgomery operations. + * Larger window sizes have more memory and are slightly faster + */ +#ifndef MAX_WIN_SIZE +#define MAX_WIN_SIZE 5 +#endif + +#if (MAX_WIN_SIZE == 6) +#define MAX_NUM_SIZE 16 +#endif + +#if (MAX_WIN_SIZE == 5) +#define MAX_NUM_SIZE 16 +#endif + +#if (MAX_WIN_SIZE == 4) +#define MAX_NUM_SIZE 8 +#endif + +#if (MAX_WIN_SIZE == 3) +#define MAX_NUM_SIZE 4 +#endif + +#ifndef MAX_NUM_SIZE +#define MAX_NUM_SIZE 16 +#endif + +/* This table is used to calculate how far to shift a window to find + * the next 1 bit within the window, for a given window size + * Comment next to each value represents window size, value of the window + * and the number of shifts to find the next 1 bit. + * where the value of the window is 0, the shift is the size of the window + * and thus may not necessary yield a 1 bit, but refreshes the window + */ +const static unsigned char shift[64]= + {6, /* window 6, bits 000000, shift 6 */ + 0, /* 6, bits 000001, shift 0 */ + 1, /* 6, bits 000010, shift 1 */ + 0, /* 6, bits 000011, shift 0 */ + 2, /* 6, bits 000100, shift 2 */ + 0, /* 6, bits 000101, shift 0 */ + 1, /* 6, bits 000110, shift 1 */ + 0, /* 6, bits 000111, shift 0 */ + 3, /* 6, bits 001000, shift 3 */ + 0, /* 6, bits 001001, shift 0 */ + 1, /* 6, bits 001010, shift 1 */ + 0, /* 6, bits 001011, shift 0 */ + 2, /* 6, bits 001100, shift 2 */ + 0, /* 6, bits 001101, shift 0 */ + 1, /* 6, bits 001110, shift 1 */ + 0, /* 6, bits 001111, shift 0 */ + 4, /* 6, bits 010000, shift 4 */ + 0, /* 6, bits 010001, shift 0 */ + 1, /* 6, bits 010010, shift 1 */ + 0, /* 6, bits 010011, shift 0 */ + 2, /* 6, bits 010100, shift 2 */ + 0, /* 6, bits 010101, shift 0 */ + 1, /* 6, bits 010110, shift 1 */ + 0, /* 6, bits 010111, shift 0 */ + 3, /* 6, bits 011000, shift 3 */ + 0, /* 6, bits 011001, shift 0 */ + 1, /* 6, bits 011010, shift 1 */ + 0, /* 6, bits 011011, shift 0 */ + 2, /* 6, bits 011100, shift 2 */ + 0, /* 6, bits 011101, shift 0 */ + 1, /* 6, bits 011110, shift 1 */ + 0, /* 6, bits 011111, shift 0 */ + 5, /* 6, bits 100000, shift 5 */ + /* also window 5, bits 00000, shift 5 */ + 0, /* 5 ,bits 00001, shift 0 */ + 1, /* 5 ,bits 00010, shift 1 */ + 0, /* 5 ,bits 00011, shift 0 */ + 2, /* 5 ,bits 00100, shift 2 */ + 0, /* 5 ,bits 00101, shift 0 */ + 1, /* 5 ,bits 00110, shift 1 */ + 0, /* 5 ,bits 00111, shift 0 */ + 3, /* 5 ,bits 01000, shift 3 */ + 0, /* 5 ,bits 01001, shift 0 */ + 1, /* 5 ,bits 01010, shift 1 */ + 0, /* 5 ,bits 01011, shift 0 */ + 2, /* 5 ,bits 01100, shift 2 */ + 0, /* 5 ,bits 01101, shift 0 */ + 1, /* 5 ,bits 01110, shift 1 */ + 0, /* 5 ,bits 01111, shift 0 */ + 4, /* 5 ,bits 10000, shift 1 */ + /* also window 4, bits 0000, shift 4 */ + 0, /* 4 ,bits 0001, shift 0 */ + 1, /* 4 ,bits 0010, shift 1 */ + 0, /* 4 ,bits 0011, shift 0 */ + 2, /* 4 ,bits 0100, shift 2 */ + 0, /* 4 ,bits 0101, shift 0 */ + 1, /* 4 ,bits 0110, shift 1 */ + 0, /* 4 ,bits 0111, shift 0 */ + 3, /* 4 ,bits 1000, shift 3 */ + /* also window 3, bits 000, shift 3 */ + 0, /* 3 ,bits 001, shift 0 */ + 1, /* 3 ,bits 010, shift 1 */ + 0, /* 3 ,bits 011, shift 0 */ + 2, /* 3 ,bits 100, shift 2 */ + 0, /* 3 ,bits 101, shift 0 */ + 1, /* 3 ,bits 110, shift 1 */ + 0 /* 3 ,bits 111, shift 0 */ + }; + +/* This table defines the starting point in the shift table for + * a particular window size + */ +const static unsigned char *shift_val[7]= + { + &(shift[63]), /* window 0 - unused */ + &(shift[62]), /* window 1 */ + &(shift[60]), /* window 2 - unused */ + &(shift[56]), /* window 3 */ + &(shift[48]), /* window 4 */ + &(shift[32]), /* window 5 */ + &(shift[ 0]), /* window 6 - unused */ + }; + +/** + * Calculates a Montgomery exponent string. + * + * For a supplied exponent p, generate an exponent string strp, which + * defines in pairs the number of multiplies and square operations + * required by a particular bit pattern, commonly used exponents + * 3, 11 and F4 have predefined constant string values, the rest + * are calculated into a cast unsigned char * array via the data + * pointer of a BIGNUM taken from the BN_CTX stack of BIGNUMs + * + * @param p [In] Exponent + * @param strp [Out] Exponent string result + * @param flags [In] Unused + * @param ctx [In] Temporary data storage + * + * @pre p, and ctx are initialised and valid + * @post strp points to required exponent string + * + * @notes String length value in strp[2] is invalid for strings + * greater than length 255 + * string terminates with pattern, 0, 0 this should be + * used in accurately determining the length of a returned + * string strp. + * + * @note strings with value sqr = 255, mul = 0, sqr value should be + * treated as value 256, and added to the next sqr value, this + * is used by exponent strings where more then 256 contiguous + * zero bits are in the exponent bit representation. + * + * @note code contains conditional compilation of code dependent on + * the OS int/long sizes + */ +int BN_gen_exp_bits(p,strp,flags,ctx) +BIGNUM *p; +unsigned char **strp; +int flags; +BN_CTX *ctx; + { + int bits,i,j,window,num; + unsigned char *str=NULL; + BIGNUM *tmp; + + flags=flags; + bits=p->top*BN_BITS2; + tmp=&(ctx->bn[ctx->tos]); + if (p->top == 0) + return(0); + +#if (BN_BITS2 > 17) + if (p->top == 1) +#else + if (bits <= 32) +#endif + { +#if (BN_BITS2 > 17) + if ((p->top == 1) && (p->d[0] == 0x10001)) + str=(unsigned char *)p16; +#endif +#if (16 >= BN_BITS2) && (BN_BITS > 8) + if ( (p->top == 2) && + (p->d[0] == 0x0001) && + (p->d[1] == 0x0001)) + str=(unsigned char *)p16; +#endif +#if (8 >= BN_BITS) + if ( (p->top == 3) && + (p->d[0] == 0x01) && + (p->d[1] == 0x00) && + (p->d[2] == 0x01)) + str=(unsigned char *)p16; +#endif + else if ((p->d[0] == 0x11) && (p->top == 1)) + str=(unsigned char *)p4; + else if ((p->d[0] == 0x3) && (p->top == 1)) + str=(unsigned char *)p2; + window=1; + num=1; + i=BN_BITS2; + } + else if (bits >= 256) + { + window=MAX_WIN_SIZE; /* max size of window */ + num=MAX_NUM_SIZE; + i=(BN_BITS2+(MAX_WIN_SIZE -1))/MAX_WIN_SIZE; + } + else if (bits >= 128) + { + window=4; + num=8; + i=(BN_BITS2+3)/4; + } + else /* 128 to 33 */ + { + window=3; + num=4; + i=(BN_BITS2+2)/3; + } + + /* Number of tmp words */ + j=(p->top*i*2+BN_BYTES-1+4)/BN_BYTES; + + if (str == NULL) + { + if (!bn_wexpand(tmp,j)) + return(0); + str=(unsigned char *)tmp->d; + i=BN_gen_exp_string(&(str[4]),p,window); + i+=2; + str[0]=(unsigned char)((i>>8)&0xff); + str[1]=(unsigned char)((i )&0xff); + str[2]=(unsigned char)window; + str[3]=(unsigned char)num; + } + else + { + i=8; + } + *strp=str; + return(i+2); + } + + +/** + * Generates the Montgomery exponent string. + * + * This function is used to generate an 'exponent string' + * which is an array of bytes that encode how to perform the steps in + * the a^p%m operation. + * + * @param str [Out] Containing the generated string + * @param p [In] Exponent to generate the string for + * @param bits [In] Size of the window for shifting the values of the BIGNUM + * + * @pre p is initialised and value BIGNUM, bits is not 0 + * @post str points to generated exponent string + * + * @note str is cast assigned the data of a BIGNUM allocated and + * expanded from the BN_CTX of the calling function BN_gen_exp_bits + * it does not need to be de-allocated + * + * @note string consisted of unsigned char pairs and 4 byte init + * pairs are sqr count and multiply, where strings are greater + * than 256 bit, length in position str[2] is invalid + * + * @note strings with value sqr = 255, mul = 0, sqr value should be + * treated as value 256, and added to the next sqr value, this + * is used by exponent strings where more then 256 contiguous + * zero bits are in the exponent bit representation. + * + */ +int BN_gen_exp_string(str,p,bits) +unsigned char *str; +BIGNUM *p; +int bits; + { + unsigned char *sp; + unsigned int mask; + const unsigned char *shift; + BN_ULONG w,wh,wl,*d; + unsigned int i,mul,sqr,t,s,ss; + int top; + + if (bits > 6) bits=6; + shift= shift_val[bits]; + + /* This is the mask for the bits we wish to operate on */ + mask=(unsigned int)( (1<top*BN_BITS2+bits-1)/bits)*2+2]); + *sp-- = 0; + *sp-- = 0; + top=p->top; /* Total words we will shift in */ + d=p->d; + w=wl= *d++; + if (top <= 1) + wh=0; + else + wh= *d++; + sqr=0; + i=0; + + for (;;) + { + /* t will contain how far we need to shift to set a 1 + * in the bottom bit. */ + for (;;) + { + t=w&mask; /* retrieve our window */ + s=shift[t]; /* get the shift value for the window */ + if (s == 0) break; /* no shift write out the vals */ + sqr+=s; /* add the shifted zero count to sqr */ + ss+=s; /* ss is total shift for wl */ + if (ss >= BN_BITS2) /* we have shifted > word len */ + { + if (top <= 1) break; /* no more to do */ + top--; /* dec the count */ + + wl=wh; /* copy the next word */ + /* load the word after or 0 if no more */ + wh=(top <= 1)?0:(*d++); + /* adjust our shift by len of word */ + ss-=BN_BITS2; + } + /* reset our window word w */ + if (ss == 0) + w=wl; + else + w=(wl>>ss)|(wh<<(BN_BITS2-ss)); + } + + /* At this point we have the 0th bit set */ + mul=t; + if (t == 0) break; /* we have reached the end of p */ + /* write out sqr/mul pair */ + *sp-- = (unsigned char)(sqr & 0xff); + *sp-- = (unsigned char)(mul & 0xff); + if(sqr >= 256) /* check whether sqr exceeds max uchar */ + { + /* output the expanded list of to allow for this + * and numbers will require to be added together + * at interpret time + */ + while(sqr >= 256) + { + *sp-- = 255; + *sp-- = 0; /* mul is never zero normally */ + sqr-= 256; + } + } + sqr=(unsigned int)bits; /* set sqr to be the window size */ + + ss+=bits; /* ss is total shift for wl */ + if (ss >= BN_BITS2) /* adjust window words w,wl, wh again */ + { + if (top <= 1) break; + top--; + + wl=wh; + wh=(top <= 1)?0:(*(d++)); + ss-=BN_BITS2; + } + + if (ss == 0) + w=wl; + else + w=(wl>>ss)|(wh<<(BN_BITS2-ss)); + } + sp++; + i=2; + /* reverse the string from the top of the exponent string + * and copy to the bottom, allocated exponent string is 2 * max length + * expected for exponent string + */ + while (sp[0] != 0 || sp[1] != 0) + { + str[0]=sp[0]; + str[1]=sp[1]; + str+=2; + sp+=2; + i+=2; + } + str[0]=0; + str[1]=0; + + return( (int)i ); + } + +#ifdef MAIN +main() + { + BIGNUM p; + unsigned char buf[512],*pp; + int i; + + BN_init(&p); + BN_rand(&p,33,1,0); +#ifndef NO_FP_API + BN_print_fp(stdout,&p); fprintf(stdout,"\n"); +#endif + + BN_rand(&p,512,1,1); +#ifndef NO_FP_API + BN_print_fp(stdout,&p); fprintf(stdout,"\n"); +#endif + for (i=0; i<10000; i++) + BN_gen_exp_string(buf,&p,5); + +#if 0 + BN_gen_exp_string(buf,&p,3); + + pp=buf; + for (;;) + { + printf("mul %d sqr %d\n",pp[0],pp[1]); + if (pp[1] == 0) break; + pp+=2; + } +#endif + } +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_exp.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_exp.c new file mode 100644 index 00000000..723b62f5 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_exp.c @@ -0,0 +1,172 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_MOD_EXP_ORIG +#define SPLIT_BN_MOD_EXP +#endif /* NO_SPLIT */ + +#define TABLE_SIZE 16 + +#ifdef SPLIT_BN_MOD_EXP_ORIG +#if 0 +/* this one works - simple but works */ +int BN_mod_exp_orig(r,a,p,m,ctx) +BIGNUM *r,*a,*p,*m; +BN_CTX *ctx; + { + int i,bits,ret=0; + BIGNUM *v,*tmp; + + v= &(ctx->bn[ctx->tos++]); + tmp= &(ctx->bn[ctx->tos++]); + + if (BN_copy(v,a) == NULL) goto err; + bits=BN_num_bits(p); + + if (BN_is_odd(p)) + { if (BN_copy(r,a) == NULL) goto err; } + else { if (!BN_one(r)) goto err; } + + for (i=1; itos-=2; + return(ret); + } + +#endif + +/* this one works - simple but works */ +int BN_exp(r,a,p,ctx) +BIGNUM *r,*a,*p; +BN_CTX *ctx; + { + int i,bits,ret=0,tos; + BIGNUM *v,*rr; + + bn_check_top(a); + bn_check_top(p); + + tos=ctx->tos; + v= &(ctx->bn[ctx->tos++]); + if ((r == a) || (r == p)) + rr= &(ctx->bn[ctx->tos++]); + else + rr=r; + + if (BN_copy(v,a) == NULL) goto err; + bits=BN_num_bits(p); + + if (BN_is_odd(p)) + { if (BN_copy(rr,a) == NULL) goto err; } + else { if (!BN_one(rr)) goto err; } + + for (i=1; itos=tos; + if (r != rr) (void)BN_copy(r,rr); + return(ret); + } +#endif + +#ifdef SPLIT_BN_MOD_EXP +/** + * Perform mod exp on BIGNUM + * @param r Pointer to return value BIGNUM + * @param a Pointer to data value BIGNUM + * @param p Pointer to Public exponent BIGNUM + * @param m Pointer to modulus BIGNUM + * @param ctx Pointer to BN_CTX + * @return 0 success + * @pre BIGNUMs a, p, m and BN_CTX ctx exist and are valid + * @post BIGNUM r points to evaluated mod_exp + * @note BN_mod_exp_mont is only available if library compiled + * with define BN_MONT_MUL, and will only be used to compute + * mod_exp operation where the modulus m is odd. + * BN_mod_exp_recp is only available if library is compiled + * with define RECP_MUL_MOD. + * BN_mod_exp_simple is the default method, not available if + * library is compiled with define RECP_MUL_MOD. + * if BN_mod_exp_mont is available, which ever of BN_mod_exp_simple + * or BN_mod_exp_recp is available will only be used for even + * modulus m values. + * @relates BN_mod_exp_mont + * @relates BN_mod_exp_recp + * @relates BN_mod_exp_simple + */ +int BN_mod_exp(r,a,p,m,ctx) +BIGNUM *r; +BIGNUM *a; +BIGNUM *p; +BIGNUM *m; +BN_CTX *ctx; + { + int ret; + + bn_check_top(a); + bn_check_top(p); + bn_check_top(m); + +#ifdef MONT_MUL_MOD + + if (BN_is_odd(m)) + { ret=BN_mod_exp_mont(r,a,p,m,ctx,NULL); } + else +#endif +#ifdef RECP_MUL_MOD + { ret=BN_mod_exp_recp(r,a,p,m,ctx); } +#else + { ret=BN_mod_exp_simple(r,a,p,m,ctx); } +#endif + + return(ret); + } +#endif + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_fm_w.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_fm_w.c new file mode 100644 index 00000000..54c67abb --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_fm_w.c @@ -0,0 +1,79 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ +#include "bn_lcl.h" + +/* rp has w words, the top w words are 0 */ +void bn_from_montgomery_words(ret,a,np,w,n0) +BN_ULONG *ret; +BN_ULONG *a; +BN_ULONG *np; +int w; +BN_ULONG n0; + { + BN_ULONG v0,v1,*ap,*wap; + int i; + + v1=0; + + ap=a; + wap= &(a[w]); + /* Consider putting this loop in ASM */ + for (i=0; i0; i--) + if (ap[i] != np[i]) break; + } + v1=(ap[i] >= np[i]); + } + if (v1) + (void)bn_sub_words(ret,ap,np,w); + else + { +#if 0 /* Alpha does not like Memcpy */ + Memcpy(ret,ap,sizeof(BN_ULONG)*w); +#else + for (i=0; ibn[ctx->tos]); + b= &(ctx->bn[ctx->tos+1]); + + if (BN_copy(a,in_a) == NULL) goto err; + if (BN_copy(b,in_b) == NULL) goto err; + + if (BN_cmp(a,b) < 0) { t=a; a=b; b=t; } + t=bn_euclid(a,b); + if (t == NULL) goto err; + + if (BN_copy(r,t) == NULL) goto err; + ret=1; +err: + return(ret); + } + +BIGNUM *bn_euclid(a,b) +BIGNUM *a,*b; + { + BIGNUM *t; + int shifts=0; + + bn_check_top(a); + bn_check_top(b); + + for (;;) + { + if (BN_is_zero(b)) + break; + + if (BN_is_odd(a)) + { + if (BN_is_odd(b)) + { + if (!BN_sub(a,a,b)) goto err; + if (!BN_rshift1(a,a)) goto err; + if (BN_cmp(a,b) < 0) + { t=a; a=b; b=t; } + } + else /* a odd - b even */ + { + if (!BN_rshift1(b,b)) goto err; + if (BN_cmp(a,b) < 0) + { t=a; a=b; b=t; } + } + } + else /* a is even */ + { + if (BN_is_odd(b)) + { + if (!BN_rshift1(a,a)) goto err; + if (BN_cmp(a,b) < 0) + { t=a; a=b; b=t; } + } + else /* a even - b even */ + { + if (!BN_rshift1(a,a)) goto err; + if (!BN_rshift1(b,b)) goto err; + shifts++; + } + } + } + if (shifts) + { + if (!BN_lshift(a,a,shifts)) goto err; + } + return(a); +err: + return(NULL); + } +#endif + +#ifdef SPLIT_BN_MOD_INVERSE +/* solves ax == 1 (mod n) */ +BIGNUM *BN_mod_inverse(in, a, n, ctx) +BIGNUM *in; +BIGNUM *a; +BIGNUM *n; +BN_CTX *ctx; + { + BIGNUM *A,*B,*X,*Y,*M,*D,*R; + BIGNUM *T,*ret=NULL; + int sign; + + bn_check_top(a); + bn_check_top(n); + + A= &(ctx->bn[ctx->tos]); + B= &(ctx->bn[ctx->tos+1]); + X= &(ctx->bn[ctx->tos+2]); + D= &(ctx->bn[ctx->tos+3]); + M= &(ctx->bn[ctx->tos+4]); + Y= &(ctx->bn[ctx->tos+5]); + ctx->tos+=6; + if (in == NULL) + R=BN_new(); + else + R=in; + if (R == NULL) goto err; + + (void)BN_zero(X); + (void)BN_one(Y); + if (BN_copy(A,a) == NULL) goto err; + if (BN_copy(B,n) == NULL) goto err; + sign=1; + + while (!BN_is_zero(B)) + { + if (!BN_div(D,M,A,B,ctx)) goto err; + T=A; + A=B; + B=M; + /* T has a struct, M does not */ + + if (!BN_mul(T,D,X,ctx)) goto err; + if (!BN_add(T,T,Y)) goto err; + M=Y; + Y=X; + X=T; + sign= -sign; + } + if (sign < 0) + { + if (!BN_sub(Y,n,Y)) goto err; + } + + if (BN_is_one(A)) + { if (!BN_mod(R,Y,n,ctx)) goto err; } + else + { +#ifndef NO_ERR + BNerr(BN_F_BN_MOD_INVERSE,BN_R_NO_INVERSE); +#endif + goto err; + } + ret=R; +err: + if ((ret == NULL) && (in == NULL)) BN_free(R); + ctx->tos-=6; + return(ret); + } +#endif + +#ifdef SPLIT_BN_MOD_INVERSE_WORD +/* solves 1 == (ret*(1<l + * @param l [In] a word (size of word depends on machine) + * @returns number of bits in parameter l + */ +#ifdef SPLIT_BN_NUM_BITS_WORD +int BN_num_bits_word(l) +BN_ILONG l; + { + int i; + + /* + * This table represents the number of bits required to + * represent a "number", where "number" is indexed from + * 0 into the table. So: + * number 0 = # bits req'd to represent 0 = bits[0] = 0 + * number 1 = # bits req'd to represent 1 = bits[1] = 1 + * number 2 = # bits req'd to represent 2 = bits[2] = 2 + * number 3 = # bits req'd to represent 3 = bits[3] = 2 + * number 4 = # bits req'd to represent 4 = bits[4] = 3 + * etc. + * + * The small code size table exists to save some space, + * but requires (at most) an extra shift, an extra AND, + * and an extra add. + */ +#ifdef SMALL_CODE_SIZE + const static char bits[16]={ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 + }; +#else + const static char bits[256]={ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + }; +#endif + +#if defined(SIXTY_FOUR_BIT_LONG) + if (l & 0xffffffff00000000L) + { + if (l & 0xffff000000000000L) + { + if (l & 0xff00000000000000L) + i=56; + else i=48; + } + else + { + if (l & 0x0000ff0000000000L) + i=40; + else i=32; + } + } + else +#else +#ifdef SIXTY_FOUR_BIT + if (l & 0xffffffff00000000LL) + { + if (l & 0xffff000000000000LL) + { + if (l & 0xff00000000000000LL) + i=56; + else i=48; + } + else + { + if (l & 0x0000ff0000000000LL) + i=40; + else i=32; + } + } + else +#endif +#endif + { +#if defined(THIRTY_BIT) || defined(THIRTY_ONE_BIT) || defined(THIRTY_TWO_BIT) || defined(SIXTY_FOUR_BIT) || defined(SIXTY_FOUR_BIT_LONG) + if (l & 0xffff0000L) + { + if (l & 0xff000000L) + i=24; + else i=16; + } + else +#endif + { + if (l & 0xff00L) + i=8; + else + i=0; + } + } +#ifndef SMALL_CODE_SIZE + return(i+bits[l>>i]); +#else + l>>=i; + if (l & 0xf0) + return(bits[l>>4]+i+4); + else + return(bits[l]+i); +#endif + } +#endif + +#ifdef SPLIT_BN_NUM_BITS +int BN_num_bits(a) +BIGNUM *a; + { + BN_ULONG l; + int i; + + bn_check_top(a); + + if (a->top == 0) return(0); + l=a->d[a->top-1]; + i=(a->top-1)*BN_BITS2; +#ifdef BN_DEBUG + if (l == 0) + { +#if !defined(NO_FP_API) && !defined(WIN16) + fprintf(stderr,"BAD TOP VALUE\n"); +#endif + abort(); /* BN_DEBUG */ + /* TODO: need to understand what sort of error can + * be reported for this error + */ + return(0); + } +#endif + return(i+BN_num_bits_word(l)); + } +#endif + +/** + * Clears and free a BIGNUM + * + * @param a [In] BIGNUM to clear then free + */ +#ifdef SPLIT_BN_CLEAR_FREE +void BN_clear_free(BIGNUM *a) +{ + if (a == NULL) + { + return; + } + + BN_clear(a); + BN_free(a); +} +#endif + +#ifdef SPLIT_BN_FREE +/** + * Frees a BIGNUM + * + * @param a [In] BIGNUM to free + */ +void BN_free(a) +BIGNUM *a; + { + if (a == NULL) return; + if ((a->d != NULL) && !(BN_get_flags(a,BN_FLG_STATIC_DATA))) + Free(a->d); + a->flags|=BN_FLG_FREE; /* REMOVE? */ + if (a->flags & BN_FLG_MALLOCED) + Free(a); + } +#endif + +#ifdef SPLIT_BN_INIT + +#ifdef SMALL_CODE_SIZE +/** + * Zero expands a bignum + * + * @param a [In] BIGNUM to expand + * @param n [In] number of bits to expand to + * + * @pre a is a valid BIGNUM. + */ +void bn_zexpand(a,n) +BIGNUM *a; +int n; + { + if ((a)->top < n) + { + int i; + bn_wexpand((a),n); + if (a->d!=NULL) + { + for (i=(a)->top; id[i]=0; + } + } + } + +/** + * Fixes the top value in the BIGNUM to be the count of BN_ULONGs with data. + * + * @param a [In] BIGNUM to free + * + * @pre a is a valid BIGNUM. + */ +void bn_fix_top(a) +BIGNUM *a; + { + BN_ULONG *ftl; + if ((a)->top > 0) + { + for (ftl= &((a)->d[(a)->top-1]); (a)->top > 0; (a)->top--) + if (*(ftl--)) break; + } + } +#endif + +/** + * Initializes a BIGNUM + * + * @param a [In] BIGNUM reference + * + * @pre a is a valid BIGNUM. + */ +void BN_init(a) +BIGNUM *a; + { + (void)Memset(a,0,sizeof(BIGNUM)); + } +#endif + +#ifdef SPLIT_BN_NEW +/** + * Allocates a BIGNUM + * + * @return pointer to allocated BIGNUM + */ +BIGNUM *BN_new() + { + BIGNUM *ret; + + if ((ret=(BIGNUM *)Malloc(sizeof(BIGNUM))) == NULL) + { +#ifndef NO_ERR + BNerr(BN_F_BN_NEW,ERR_R_MALLOC_FAILURE); +#endif + return(NULL); + } + ret->flags=BN_FLG_MALLOCED; + ret->top=0; + ret->neg=0; + ret->max=0; + ret->d=NULL; + return(ret); + } +#endif + +#ifdef SPLIT_BN_CTX_NEW +/** + * Allocates a BIGNUM context + * + * @return pointer to allocated BIGNUM context + */ +BN_CTX *BN_CTX_new() + { + BN_CTX *ret; + + ret=(BN_CTX *)Malloc(sizeof(BN_CTX)); + if (ret == NULL) + { +#ifndef NO_ERR + BNerr(BN_F_BN_CTX_NEW,ERR_R_MALLOC_FAILURE); +#endif + return(NULL); + } + + BN_CTX_init(ret); + ret->flags=BN_FLG_MALLOCED; + return(ret); + } +#endif + +#ifdef SPLIT_CTX_INIT +/** + * Initializes a BIGNUM context + * + * @param a [In] BIGNUM context reference + * + * @pre a is a valid BIGNUM context. + */ +void BN_CTX_init(ctx) +BN_CTX *ctx; + { + (void)Memset(ctx,0,sizeof(BN_CTX)); + ctx->tos=0; + ctx->flags=0; + } +#endif + +#ifdef SPLIT_BN_CTX_FREE +/** + * Frees a BIGNUM context + * + * @param a [In] BIGNUM context reference + * + * @pre a is a valid BIGNUM context. + */ +void BN_CTX_free(c) +BN_CTX *c; + { + int i; + + for (i=0; ibn[i])); + if (c->flags & BN_FLG_MALLOCED) + Free(c); + } +#endif + +#ifdef SPLIT_BN_EXPAND2 +BIGNUM *bn_expand2(b, words) +BIGNUM *b; +int words; + { + BN_ULONG *A,*B,*a; + + R_DIAG_CHECK_STACK; + + bn_check_top(b); + + if (words > b->max) + { + bn_check_top(b); + if (BN_get_flags(b,BN_FLG_STATIC_DATA)) + { +#ifndef NO_ERR + BNerr(BN_F_BN_EXPAND2,BN_R_EXPAND_ON_STATIC_BIGNUM_DATA); +#endif + return(NULL); + } + a=A=(BN_ULONG *)Malloc(sizeof(BN_ULONG)*(words+1)); + if (A == NULL) + { +#ifndef NO_ERR + BNerr(BN_F_BN_EXPAND2,ERR_R_MALLOC_FAILURE); +#endif + return(NULL); + } + /* during development this is a nice way of making sure + * that we are not relying on the top byte being 0 or + * other such things + */ +#ifdef BN_DEBUG + (void)Memset(A,0x5c,sizeof(BN_ULONG)*(words+1)); +#endif + + B=b->d; + if (B != NULL) + { +#ifndef SMALL_CODE_SIZE + int i; + + /* for (i=b->top&(~7); i>0; i-=8) */ + /* The above line can induce a SunC compiler bug */ + for (i=(b->top>>3); i>0; i--) + { + BN_ULONG T0,T1,T2,T3; + + T0=B[0]; + T1=B[1]; + T2=B[2]; + T3=B[3]; + A[0]=T0; + A[1]=T1; + A[2]=T2; + A[3]=T3; + T0=B[4]; + T1=B[5]; + T2=B[6]; + T3=B[7]; + A[4]=T0; + A[5]=T1; + A[6]=T2; + A[7]=T3; + A+=8; + B+=8; + } + switch (b->top&7) + { + case 7: + A[6]=B[6]; + case 6: + A[5]=B[5]; + case 5: + A[4]=B[4]; + case 4: + A[3]=B[3]; + case 3: + A[2]=B[2]; + case 2: + A[1]=B[1]; + case 1: + A[0]=B[0]; + case 0: + /* I need the 'case 0' entry for utrix cc. + * If the optimiser is turned on, it does the + * switch table by doing + * a=top&7 + * a--; + * goto jump_table[a]; + * If top is 0, this makes us jump to 0xffffffc + * which is rather bad. + * eric 23-Apr-1998 + */ + ; + } +#if 0 /* Not needed */ + B= &(b->d[b->top]); + j=b->max-8; + for (i=b->top; itop); +#endif + Free(b->d); + } + + b->d=a; + b->max=words; + } + return(b); + } +#endif + +#ifdef SPLIT_BN_DUP +/** + * Duplicates a BIGNUM + * + * @param a [In] BIGNUM reference + * + * @returns pointer to duplicate BIGNUM of a + */ +BIGNUM *BN_dup(a) +BIGNUM *a; + { + BIGNUM *r; + BIGNUM *ret; + + bn_check_top(a); + + r=BN_new(); + if (r == NULL) return(NULL); + ret = (BIGNUM *)BN_copy(r,a); + if (ret == NULL) + { + BN_free(r); + } + return(ret); + } +#endif + +#ifdef SPLIT_BN_COPY +/** + * Copies a BIGNUM to an existing BIGNUM + * + * @param a [In] To BIGNUM reference + * @param b [Out] From BIGNUM reference + * + * @pre Both a and b are valid BIGNUMs + * + * @returns pointer to duplicate BIGNUM of a + */ +BIGNUM *BN_copy(a, b) +BIGNUM *a; +BIGNUM *b; + { +#ifndef SMALL_CODE_SIZE + int i; + BN_ULONG *A,*B; +#endif + + bn_check_top(b); + + if (a == b) return(a); + if (bn_wexpand(a,b->top) == NULL) return(NULL); +#ifndef SMALL_CODE_SIZE + A=a->d; + B=b->d; + +/* for (i=b->top&~0x07; i>0; i-=8) */ +/* The above version of this loop has been removed. It appeared + to generate a compiler bug in SunC 4.x and 5.x. I do not believe + that the code was to blame. Compiling with -fast was the problem + since this would loop unroll the loop below another 3 times. + The compiler would generate generate + andcc %o0,-8,%o1 # load ~0x07 + ld [%i2],%o3 # load *B + ble .L77000125 # exit loop unless 8 or more + ld [%i1],%o2 # load *A + sub %o1,-7,%o0 # + sdivcc %o0,8,%o0 # when do we clear %y? + bvs,a .L900001510 + sethi %hi(0x80000000),%o0 +.L900001510: + cmp %o0,3 + bl .L77000114 # one loop + ld [%o2],%o0 + # three loop code + + The loop would then be unrolled 3 times. The problem I believe + I was seeing was that the sdivcc operates is %y:%o0 / 8. + %y is not being cleared, and so occasionally this would + cause problems. The replacement code sequence stops + the compiler generating the sdiv instruction. + */ + for (i=(b->top>>3); i>0; i--) + { + BN_ULONG T0,T1,T2,T3; + T0=B[0]; + T1=B[1]; + T2=B[2]; + T3=B[3]; + A[0]=T0; + A[1]=T1; + A[2]=T2; + A[3]=T3; + T0=B[4]; + T1=B[5]; + T2=B[6]; + T3=B[7]; + A[4]=T0; + A[5]=T1; + A[6]=T2; + A[7]=T3; + A+=8; + B+=8; + } + switch (b->top&0x07) + { + case 7: + A[6]=B[6]; + case 6: + A[5]=B[5]; + case 5: + A[4]=B[4]; + case 4: + A[3]=B[3]; + case 3: + A[2]=B[2]; + case 2: + A[1]=B[1]; + case 1: + A[0]=B[0]; + case 0: + /* I need the 'case 0' entry for utrix cc. + * If the optimiser is turned on, it does the + * switch table by doing + * a=top&7 + * a--; + * goto jump_table[a]; + * If top is 0, this makes us jump to 0xffffffc which is + * rather bad. + * eric 23-Apr-1998 + */ + ; + } +#else + (void)Memcpy(a->d,b->d,sizeof(b->d[0])*b->top); +#endif + +/* (void)Memset(&(a->d[b->top]),0,sizeof(a->d[0])*(a->max-b->top));*/ + a->top=b->top; + if ((a->top == 0) && (a->d != NULL)) + a->d[0]=0; + a->neg=b->neg; + return(a); + } +#endif + +#ifdef SPLIT_BN_CLEAR +/** + * Clears a BIGNUM + * + * @param a [In] BIGNUM to clear + * + * @pre a is valid + */ +void BN_clear(a) +BIGNUM *a; + { + if (a->d != NULL) + (void)Memset(a->d,0,a->max*sizeof(a->d[0])); + a->top=0; + a->neg=0; + } +#endif + +#ifdef SPLIT_BN_GET_WORD +BN_ULONG BN_get_word(a) +BIGNUM *a; + { + int i,n; + BN_ULONG ret=0; + + n=BN_num_bytes(a); + if (n > ((int) sizeof(BN_ULONG))) + return(BN_MASK2); + for (i=a->top-1; i>=0; i--) + { +#ifndef SIXTY_FOUR_BIT /* the data item > unsigned long */ + ret<<=BN_BITS4; /* stops the compiler complaining */ + ret<<=BN_BITS4; +#else + ret=0; +#endif + ret|=a->d[i]; + } + return(ret); + } +#endif + +#ifdef SPLIT_BN_SET_WORD +/** + * Set the BIGNUM to the supplied BN_ULONG value. + * + * @param a [In/Out] BIGNUM to be updated + * @param w [In] Value to be set in a + * + * @notes Function will expand a to be an + * array of 8 BN_ULONGs in size. + * @todo Review behaviour of expansion without checking + * of size first. + */ +int BN_set_word(a,w) +BIGNUM *a; +BN_ULONG w; + { + int i,n; + + if (bn_expand(a,(int)(sizeof(BN_ULONG)*8)) == NULL) return(0); + +#ifdef BN_BYTES + /* This is used when a BN_ULONG is greater in size + * than the BN_BYTES of the array, eg BN_ULONG 64 bits + * and actual a->d array of 32 bits. + */ + n=sizeof(BN_ULONG)/BN_BYTES; +#else + n=1; +#endif + a->neg=0; + a->top=0; + a->d[0]=(BN_ULONG)w&BN_MASK2; + if (a->d[0] != 0) a->top=1; + for (i=1; i>=BN_BITS2 so compilers don't complain + * on builds where sizeof(long) == BN_TYPES */ +#ifndef SIXTY_FOUR_BIT /* the data item > unsigned long */ + w>>=BN_BITS4; + w>>=BN_BITS4; +#else + w=0; +#endif + a->d[i]=(BN_ULONG)w&BN_MASK2; + if (a->d[i] != 0) a->top=i+1; + } + return(1); + } +#endif + +#ifdef BN_BYTES +#ifdef SPLIT_BN_BIN2BN +/* ignore negative */ +BIGNUM *BN_bin2bn(s, len, ret) +unsigned char *s; +int len; +BIGNUM *ret; + { + int i,m; + int n; + BN_ULONG l; + + if (ret == NULL) ret=BN_new(); + if (ret == NULL) return(NULL); + l=0; + n=len; + if (n == 0) + { + ret->top=0; + return(ret); + } + if (bn_expand(ret,(int)(n+2)*8) == NULL) + return(NULL); + i=((n-1)/BN_BYTES)+1; + m=((n-1)%(BN_BYTES)); + ret->top=i; + while (n-- > 0) + { + l=(l<<8L)| *(s++); + if (m-- == 0) + { + ret->d[--i]=l; + l=0; + m=BN_BYTES-1; + } + } + /* need to call this due to clear byte at top if avoiding + * having the top bit set (-ve number) */ + bn_fix_top(ret); + return(ret); + } +#endif + +#ifdef SPLIT_BN_BN2BIN +/* ignore negative */ +int BN_bn2bin(a, to) +BIGNUM *a; +unsigned char *to; + { + int n,i; + BN_ULONG l; + + bn_check_top(a); + + n=i=BN_num_bytes(a); + while (i-- > 0) + { + l=a->d[i/BN_BYTES]; + *(to++)=(unsigned char)((l>>(8*(i%BN_BYTES)))&0xff); + } + return(n); + } +#endif +#else +#ifdef SPLIT_BN_BIN2BN +/* ignore negative */ +BIGNUM *BN_bin2bn(s, len, ret) +unsigned char *s; +int len; +BIGNUM *ret; + { + int i,w,r,b,j,v; + int n; + BN_ULONG l; + + if (ret == NULL) ret=BN_new(); + if (ret == NULL) return(NULL); + while (len > 0) + { + if (*s != 0) break; + s++; + len--; + } + n=len*8; + if (bn_expand(ret,n) == NULL) + return(NULL); + for (i=0; imax; i++) + ret->d[i]=0; + j=0; + for (i=len-1; i>=0; i--) + { + v=((int)s[i])&0xff; + w=j/BN_BITS2; + b=j%BN_BITS2; + r=BN_BITS2-b; + j+=8; + if (r >= 8) + { + ret->d[w]|=(((BN_ULONG)v)<d[w] =(ret->d[w]|(((BN_ULONG)v)<d[w+1]=(ret->d[w+1]|(((BN_ULONG)v)>>r)); + } + } + + ret->top=((n-1)/BN_BITS2)+1; + bn_fix_top(ret); + return(ret); + } +#endif + +#ifdef SPLIT_BN_BN2BIN +int BN_bn2bin(a, to) +BIGNUM *a; +unsigned char *to; + { + int num,i,bi,w,b,r,max; + BN_ULONG l,*lp; + + bn_check_top(a); + + num=bi=BN_num_bytes(a); + lp=a->d; + for (i=0; i= 8) + to[bi]=(lp[w]>>b)&0xff; + else + { + to[bi]=(lp[w]>>b); + if (w+1 < a->top) + to[bi]|=lp[w+1]<top-b->top; + if (i != 0) return(i); + ap=a->d; + bp=b->d; + for (i=a->top-1; i>=0; i--) + { + t1= ap[i]; + t2= bp[i]; + if (t1 != t2) + return(t1 > t2?1:-1); + } + return(0); + } +#endif + +#ifdef SPLIT_BN_CMP +int BN_cmp(a, b) +BIGNUM *a; +BIGNUM *b; + { + int i; + int gt,lt; + BN_ULONG t1,t2; + + if ((a == NULL) || (b == NULL)) + { + if (a != NULL) + return(-1); + else if (b != NULL) + return(1); + else + return(0); + } + + bn_check_top(a); + bn_check_top(b); + + if (a->neg != b->neg) + { + if (a->neg) + return(-1); + else return(1); + } + if (a->neg == 0) + { gt=1; lt= -1; } + else { gt= -1; lt=1; } + + if (a->top > b->top) return(gt); + if (a->top < b->top) return(lt); + for (i=a->top-1; i>=0; i--) + { + t1=a->d[i]; + t2=b->d[i]; + if (t1 > t2) return(gt); + if (t1 < t2) return(lt); + } + return(0); + } +#endif + +#ifdef SPLIT_BN_SET_BIT +int BN_set_bit(a, n) +BIGNUM *a; +int n; + { + int i,j,k; + + bn_check_top(a); + + i=n/BN_BITS2; + j=n%BN_BITS2; + if (a->top <= i) + { + if (bn_wexpand(a,i+1) == NULL) return(0); + for(k=a->top; kd[k]=0; + a->top=i+1; + } + + a->d[i]|=(((BN_ULONG)1)<top <= i) return(0); + + a->d[i]&=(~(((BN_ULONG)1)<top <= i) return(0); + return((a->d[i]&(((BN_ULONG)1)<= a->top) return(0); + if (b == 0) + a->top=w; + else + { + a->top=w+1; + a->d[w]&= ~(((BN_ULONG)BN_MASK2)< bb)?1:-1); + for (i=n-2; i>=0; i--) + { + aa=a[i]; + bb=b[i]; + if (aa != bb) return((aa > bb)?1:-1); + } + return(0); + } +#endif +#endif + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_lsh.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_lsh.c new file mode 100644 index 00000000..21508b16 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_lsh.c @@ -0,0 +1,128 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_LSHIFT1 +#define SPLIT_BN_LSHIFT +#endif /* NO_SPLIT */ + +#ifdef SPLIT_BN_LSHIFT1 +#ifdef SMALL_CODE_SIZE + +int BN_lshift1(r, a) +BIGNUM *r,*a; + { + return(BN_lshift(r, a, 1)); + } + +#else + +int BN_lshift1(r, a) +BIGNUM *r; +BIGNUM *a; + { + register BN_ULONG *ap,*rp,t,c; + int i; + + bn_check_top(a); + + if (r != a) + { + if (bn_wexpand(r,a->top+1) == NULL) return(0); + r->neg=a->neg; + r->top=a->top; + } + else + { + if (bn_wexpand(r,a->top+1) == NULL) return(0); + } + ap=a->d; + rp=r->d; + c=0; + for (i=0; itop; i++) + { + t= *(ap++); + *(rp++)=((t<<1L)|c)&BN_MASK2; + c=(t & BN_TBIT)?1:0; + } + if (c) + { + *rp=1; + r->top++; + } + return(1); + } +#endif +#endif + +#ifdef SPLIT_BN_LSHIFT +int BN_lshift(r, a, n) +BIGNUM *r; +BIGNUM *a; +int n; + { + int i,nw,lb,rb; + BN_ULONG *t,*f; + BN_ULONG l; + + bn_check_top(a); + +#ifndef SMALL_CODE_SIZE + if (n == 1) return(BN_lshift1(r,a)); +#endif + if (bn_wexpand(r,a->top+(n/BN_BITS2)+1) == NULL) return(0); + r->neg=a->neg; + nw=n/BN_BITS2; + lb=n%BN_BITS2; + rb=BN_BITS2-lb; + f=a->d; + t=r->d; + t[a->top+nw]=0; + if (lb == 0) + for (i=a->top-1; i>=0; i--) + t[nw+i]=f[i]; + else + for (i=a->top-1; i>=0; i--) + { + l=f[i]; + t[nw+i+1]|=(l>>rb)&BN_MASK2; + t[nw+i]=(l<top=a->top+nw+1; + bn_fix_top(r); + return(1); + } +#endif + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_m_exp.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_m_exp.c new file mode 100644 index 00000000..480bb599 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_m_exp.c @@ -0,0 +1,299 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#if 0 //RSA +#include +#endif +#include "bn_lcl.h" + +/* #ifdef MONT_MUL_MOD */ +/** + * Generic form of Montgomery Exponentiation, can be called directly + * out side of a BN_ME_METH + * + * @param rr_in BIGNUM pointer for result + * @param a_in BIGNUM pointer for base + * @param p BIGNUM pointer to the exponent + * @param m BIGNUM pointer to the modulus + * @param ctx BN_CTX pointer for temp values are argument storage + * @param in_mont BN_MONT_CTX pointer to structure of montgomery values + * + * @pre arguments are all initialised and not NULL or zero + * @post rr_in contains evaluated result + * + * @note + */ +int BN_mod_exp_mont(rr_in,a_in,p,m,ctx,in_mont) +BIGNUM *rr_in; +BIGNUM *a_in; +BIGNUM *p; +BIGNUM *m; +BN_CTX *ctx; +BN_MONT_CTX *in_mont; + { + int i,j,k,ret=0,tos,top; + int mul,sqr,num; + BIGNUM *d,*aa,*r,*a,*t; + BN_ULONG *vall[BN_EXP_TABLE_SIZE],*dp,*rp,n0,*rr,*tmp,*np; + BN_MONT_CTX *mont=NULL; + unsigned char *str=NULL; +#ifdef BN_SURRENDER + R_SURRENDER *surrender=NULL; + int count=0; +#endif + + bn_check_top(a_in); + bn_check_top(p); + bn_check_top(m); + + if (!(m->d[0] & 1)) + { +#ifndef NO_ERR + BNerr(BN_F_BN_MOD_EXP_MONT,BN_R_CALLED_WITH_EVEN_MODULUS); +#endif + return(0); + } + + tos=ctx->tos; + + if (BN_is_zero(a_in)) + { (void)BN_zero(rr_in); return(1); } + if (BN_is_zero(p)) + { (void)BN_one(rr_in); return(1); } + if (BN_is_one(p)) + { (void)BN_copy(rr_in,a_in); return(1); } + + /* If this is not done, things will break in the montgomery + * part */ + +#if 1 + if (in_mont != NULL) + mont=in_mont; + else +#endif + { + if ((mont=BN_MONT_CTX_new()) == NULL) goto err; + if (!BN_MONT_CTX_set(mont,m,ctx)) goto err; + } + +#ifdef BN_SURRENDER + surrender=ctx->surrender; +#endif + + if (!BN_gen_exp_bits(p,&str,0,ctx)) goto err; + /* Remember this function uses another element from the passed ctx */ + ctx->tos++; + num=str[3]; + i=(BN_BITS+str[2]-1)/str[2]; + str+=4; + + + top=mont->N.top; + if ((a_in->top == top) && (a_in->d[top-1] < m->d[top-1])) + { + a=a_in; + } + else if (a_in->top < top) + { + a= &(ctx->bn[ctx->tos++]); + a->top=a_in->top; + bn_zexpand(a,top); + for (j=0; jtop; j++) + a->d[j]=a_in->d[j]; + } + else /* if (a_in->top > i) */ + { + a= &(ctx->bn[ctx->tos++]); + if (!BN_mod(a,a_in,m,ctx)) goto err; + bn_zexpand(a,top); + } + + /* At this point a is the size of the modulus and is 0 padded + * out to its size if needed. + */ + + /* Number of tmp words */ + k=num*top; + j=k+(p->top*i*2+BN_BYTES-1+4)/BN_BYTES; + + aa=&(ctx->bn[ctx->tos++]); + d= &(ctx->bn[ctx->tos++]); + r= &(ctx->bn[ctx->tos++]); + t= &(ctx->bn[ctx->tos++]); + + if (bn_wexpand(rr_in,top) == NULL) goto err; + if (bn_wexpand(d,top*4) == NULL) goto err; /* *2? */ + if (bn_wexpand(r,top*2) == NULL) goto err; + if (bn_wexpand(aa,j) == NULL) goto err; + if (bn_wexpand(t,top*2) == NULL) goto err; + dp=d->d; + rp=r->d; + tmp=t->d; + rr=mont->RR.d; + + n0=mont->n0; + np=mont->N.d; + + vall[0]=aa->d; + + bn_mul_normal(tmp,a->d,top,rr,top); + bn_from_montgomery_words(vall[0],tmp,np,top,n0); + + if (num > 1) + { + bn_sqr_normal(tmp,vall[0],top,dp); + bn_from_montgomery_words(dp,tmp,np,top,n0); + + for (i=1; i>1],sizeof(BN_ULONG)*top); + while (sqr != 0) + { +#ifdef BN_SURRENDER + /* + * Check this at the start of the loop rather than the + * end so we avoid as many of the bn operations as possible + */ + if (surrender != NULL) + { + if (surrender->callback(surrender,0xff, count++) != 0) + { + goto err; + } + } +#endif /* BN_SURRENDER */ + + /* + * check the abort flag at the start of the loop so we avoid + * as many of the bn operations as possible + */ + if (BN_CTX_get_flags(ctx, BN_CTX_FLG_ABORT)) + { + goto err; + } + + for (i=0; i>1],top); + bn_from_montgomery_words(rp,tmp,np,top,n0); + } + else + { + bn_mul_normal(tmp,rp,top,a->d,top); + bn_from_montgomery_words(rr_in->d,tmp,np,top,n0); + goto end; + } + } + + /* if (mul != 1) */ + { + for (i=top; id,rp,np,top,n0); + } +end: /* Use this to avoid an if */ + + /* + * Even if the operation has completed successfully, if the + * abort flag is set we want to abort so that anything + * calling this function will know not to continue. + */ + if (BN_CTX_get_flags(ctx, BN_CTX_FLG_ABORT)) + { + goto err; + } + + rr_in->top=top; + bn_fix_top(rr_in); + ret=1; +err: +#ifdef BN_SURRENDER + /* + * Even if the operation completed successfully we want to abort + * if the abort flag has been is set, so that subsequent operations + * do not continue. Allow the caller change to return value and + * cause the function to fail. + */ + if (surrender != NULL) + { + if (surrender->callback(surrender, 0xff, -1) != 0) + { + ret = 0; + } + } +#endif + if ((in_mont == NULL) && (mont != NULL)) BN_MONT_CTX_free(mont); + ctx->tos=tos; + return(ret); + } +/* #endif */ + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_me.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_me.c new file mode 100644 index 00000000..fae07491 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_me.c @@ -0,0 +1,267 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ +/** + * @file bn_me.c + * @brief BN method functions and utilities + */ +#include "bn_lcl.h" +#include "bn_thx.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_MOD_EXP_METH_DEFAULT +#define SPLIT_BN_MONT_CTX_USEIT +#define SPLIT_BN_ME_CTX_NAME +#define SPLIT_BN_ME_CTX_NEW +#define SPLIT_BN_ME_CTX_FREE +#define SPLIT_BN_ME_CTX_SET +#define SPLIT_BN_ME_CTX_MOD_EXP +#endif /* NO_SPLIT */ + +#ifndef NOPROTO +BN_ME_METH *bn_mod_exp_meth_default(int fallback); +#else +BN_ME_METH *bn_mod_exp_meth_default(); +#endif + +#ifdef SPLIT_BN_MOD_EXP_METH_DEFAULT + +/** + * Returns the default mod_exp method, choose first available in the + * method table or a hardwired default + * + * @param fallback [In] Flag for choice of method + * - 0 use the first value in the method table + * - 1 use the all encompassing default method + * + * @pre BN_default_init() has been run setting up library + * + * @post + * + * @internal uses global table bnme[] and counter me_num + * + * @internal only read the BN_ME_METH_INFO table no need for locking + * + * @relates BN_library_init + * @relates BN_default_init + * @relates BN_ME_CTX_new + * @relates BN_ME_CTX_free + * + */ +BN_ME_METH *bn_mod_exp_meth_default(int fallback) +{ + const BN_ME_METH *tmp; + +#ifndef BN_LIBRARY_SMALL + BN_ME_METH_INFO *meth_info; + + if(!fallback && ((meth_info = BN_bnme_get_info(0)) != NULL)) + { + tmp = meth_info->meth(); + } + else +#endif + { + /* set in bn.h or override bn_thx.h */ + tmp = BN_ME_METH_DEFAULT(); + } + return((BN_ME_METH *)tmp); +} +#endif + +#ifdef SPLIT_BN_MONT_CTX_USEIT + +#ifndef NOPROTO +int bn_mont_ctx_useit(int argi); +#else +int bn_mont_ctx_useit(); +#endif + +/** + * Montgomery method default useit function + * + * @param argi [In] reserved for future use + * + * @return 0 success + */ +int bn_mont_ctx_useit(int argi) + { + return(0); + } +#endif + +#ifdef SPLIT_BN_ME_CTX_NAME +/** + * Retrieve the BN method name string + * + * @param ctx [In] Method + * + * @pre ctx is valid and not NULL + * + * @return string pointer + */ +char *BN_ME_CTX_name(BN_ME_CTX *ctx) + { + return(ctx->meth->name); + } +#endif + +#ifdef SPLIT_BN_ME_CTX_NEW +/** + * Allocate a new BN_ME_CTX structure and assign method + * + * @param meth [In] Method to assign + * @param in [Out] Result BN_ME_CTX + * + * @note if meth is NULL system method default is used + * + * @retval pointer to BN_ME_CTX success + * @retval NULL failure + */ +BN_ME_CTX *BN_ME_CTX_new(BN_ME_METH *meth, BN_ME_CTX **in) + { + int i; + BN_ME_CTX *ret; + + if (in == NULL) + in= &ret; + + if (meth == NULL) + meth=bn_mod_exp_meth_default(0); + i=meth->init_ctx(meth,in); + if (i) + return(NULL); + else + return(*in); + } +#endif + +#ifdef SPLIT_BN_ME_CTX_FREE +/** + * Free context method + * + * @param mctx [In] Context object to be deallocated + * + * @note it is the callers responsibility to set mctx to NULL after free + * + * @pre mctx is not NULL and is valide BN_ME_CTX + */ +void BN_ME_CTX_free(BN_ME_CTX *mctx) + { + mctx->meth->free_ctx(mctx); + } +#endif + +#ifdef SPLIT_BN_ME_CTX_SET +/** + * Set value to BN_ME_CTX by identifier + * + * @param mctx [In] Method context object + * @param b [In] Big number + * @param cmd [In] Command identifier + * @param flags [In] Mask operation directives + * @param ctx [In] BN data store + * + * @note cmd values: + * @li BN_ME_SET_MOD will cause a method lookup is method not set + * + * @note passes control to set method in mctx + * + * @return result of mctx method set operation + */ +int BN_ME_CTX_set(BN_ME_CTX *mctx, BIGNUM *b, int cmd, int flags, BN_CTX *ctx) + { +#ifndef BN_LIBRARY_SMALL +#ifndef NOPROTO + const BN_ME_METH *(*meth)(void); +#else + const BN_ME_METH *(*meth)(); +#endif +#endif /* BN_LIBRARY_SMALL */ + + /* If we are loading the modulus, and we do not have the + * no_lookup flag (without a null method) + */ + if ((cmd == BN_ME_SET_MOD) && + ((mctx->meth != NULL) && !(flags & BN_ME_SET_FLG_NO_LOOKUP))) + { +#ifndef BN_LIBRARY_SMALL + meth=(const BN_ME_METH*(*)(void)) + BN_bnme_get(BN_num_bits(b),BN_BNME_F_BITS); + if (meth != NULL) + mctx->meth=meth(); + else +#endif + mctx->meth=bn_mod_exp_meth_default(1); + } + return(mctx->meth->set(mctx,b,cmd,flags,ctx)); + } +#endif + +#ifdef SPLIT_BN_ME_CTX_MOD_EXP +/** + * Call method mod_exp operation + * + * @param mctx [In] Method context object + * @param ret [Out] Result + * @param a [In] Base value + * @param p [In] Exponent + * @param m [In] Modulus + * @param ctx [In] Data storage + * + * @pre a must be expandable + * + * @return 0 success + */ +int BN_ME_CTX_mod_exp(BN_ME_CTX *mctx, BIGNUM *ret, BIGNUM *a, BIGNUM *p, + BIGNUM *m, BN_CTX *ctx) + { + int wtop; + + /* Before we call the method, make sure we are not doing 0^p, + * and p is not 0 or 1 */ + if (BN_is_zero(a)) + { BN_zero(ret); return(0); } + if (p != NULL) + { + if (BN_is_zero(p)) + { BN_one(ret); return(0); } + else if (BN_is_one(p)) + { BN_copy(ret,a); return(0); } + } + + /* wtop is the size 'a' needs to be for the method */ + wtop=mctx->meth->num; + bn_zexpand(a,wtop); + + return(mctx->meth->mod_exp(mctx,ret,a,p,ctx)); + } +#endif + +#endif + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_mont.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_mont.c new file mode 100644 index 00000000..d6a45def --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_mont.c @@ -0,0 +1,247 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#undef BN_DEBUG +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_MOD_MUL_MONTGOMERY +#define SPLIT_BN_FROM_MONTGOMERY +#define SPLIT_BN_MONT_CTX_NEW +#define SPLIT_BN_MONT_CTX_INIT +#define SPLIT_BN_MONT_CTX_FREE +#define SPLIT_BN_MONT_CTX_COPY +#endif /* NO_SPLIT */ + +/* #define DEBUG */ + +#ifdef SPLIT_BN_MOD_MUL_MONTGOMERY +/* We multiply a by b, generating a number 2n words long. + * This is then reduced by the montogmery number, which is + * n words. */ +int BN_mod_mul_montgomery(r,a,b,mont,ctx) +BIGNUM *r,*a,*b; +BN_MONT_CTX *mont; +BN_CTX *ctx; + { + BIGNUM *tmp,*tmp2; + int ret=0,w; + int i; + + bn_check_top(a); + bn_check_top(b); + + w=mont->riw; + + tmp= &(ctx->bn[ctx->tos++]); + tmp2= &(ctx->bn[ctx->tos++]); + bn_check_top(tmp); + bn_check_top(tmp2); + if (bn_wexpand(tmp,w+w) == NULL) goto err; + if (bn_wexpand(r,w+w) == NULL) goto err; + + if (a == b) + { + if (bn_wexpand(tmp2,w+w) == NULL) goto err; +#ifdef BN_SQR_COMBA + if ((a->top == 8) && (a->top == b->top)) + bn_sqr_comba8(tmp->d,a->d); + else +#endif + { + bn_sqr_normal(tmp->d,a->d,a->top,tmp2->d); + } + } + else + { +#ifdef BN_MUL_COMBA + if (a->top == 8) + bn_mul_comba8(tmp->d,a->d,b->d); + else +#endif + { + bn_mul_normal(tmp->d,a->d,a->top,b->d,b->top); + } + } + + i=a->top+b->top; + while (i<(w+w)) + { + tmp->d[i]=0; + i++; + } + tmp->top=w+w; + tmp->neg=0; + + /* reduce from aRR to aR */ + /* tmp->d is 2w words */ +#if 0 + bn_fix_top(tmp); + BN_from_montgomery_words(r,tmp,mont,ctx); +#else + bn_from_montgomery_words(r->d,tmp->d,mont->N.d,w,mont->n0); +#endif + r->top=w; + r->neg=0; + bn_fix_top(r); + + ret=1; +err: + ctx->tos-=2; + return(ret); + } +#endif + +#ifdef SPLIT_BN_FROM_MONTGOMERY +int BN_from_montgomery(ret,a,mont,ctx) +BIGNUM *ret; +BIGNUM *a; +BN_MONT_CTX *mont; +BN_CTX *ctx; + { + BIGNUM *n,*r; + BN_ULONG *np,*rp,n0,v0,v1,*nrp; + int al,nl,max,i; + int retn=0; + + bn_check_top(a); + + r= &(ctx->bn[ctx->tos]); + + if (!BN_copy(r,a)) goto err1; + n= &(mont->N); + + /* mont->riw is the size of mont->N in bits/words */ + al=mont->riw; + + nl=n->top; + if ((al == 0) || (nl == 0)) { r->top=0; return(1); } + + max=(nl+al+1); /* allow for overflow (no?) XXX */ + if (bn_wexpand(r,max) == NULL) goto err1; + if (bn_wexpand(ret,max) == NULL) goto err1; + + r->neg=a->neg^n->neg; + np=n->d; + rp=r->d; + nrp= &(r->d[nl]); + + /* clear the top words of T */ + for (i=r->top; id[i]=0; + + r->top=max; + n0=mont->n0; + + v1=0; + for (i=0; iriw will be a multiple of the word size */ + (void)BN_rshift(ret,r,mont->riw*BN_BITS2); + + if (BN_ucmp(ret, &(mont->N)) >= 0) + { + (void)BN_usub(ret,ret,&(mont->N)); /* XXX */ + } + retn=1; + +err1: + return(retn); + } +#endif + +#ifdef SPLIT_BN_MONT_CTX_NEW +BN_MONT_CTX *BN_MONT_CTX_new() + { + BN_MONT_CTX *ret; + + if ((ret=(BN_MONT_CTX *)Malloc(sizeof(BN_MONT_CTX))) == NULL) + return(NULL); + + BN_MONT_CTX_init(ret); + ret->flags=BN_FLG_MALLOCED; + return(ret); + } +#endif + +#ifdef SPLIT_BN_MONT_CTX_INIT +void BN_MONT_CTX_init(ctx) +BN_MONT_CTX *ctx; + { + ctx->use_word=0; + ctx->riw=0; + BN_init(&(ctx->RR)); + BN_init(&(ctx->N)); + BN_init(&(ctx->Ni)); + ctx->flags=0; + } +#endif + +#ifdef SPLIT_BN_MONT_CTX_FREE +void BN_MONT_CTX_free(mont) +BN_MONT_CTX *mont; + { + BN_free(&(mont->RR)); + BN_free(&(mont->N)); + BN_free(&(mont->Ni)); + if (mont->flags & BN_FLG_MALLOCED) + Free(mont); + } +#endif + +#ifdef SPLIT_BN_MONT_CTX_COPY +BN_MONT_CTX *BN_MONT_CTX_copy(to, from) +BN_MONT_CTX *to, *from; + { + if (to == from) return(to); + + (void)BN_copy(&(to->RR),&(from->RR)); + (void)BN_copy(&(to->N),&(from->N)); + (void)BN_copy(&(to->Ni),&(from->Ni)); + bn_zexpand(&(to->RR),from->riw); + bn_zexpand(&(to->Ni),from->riw); + to->use_word=from->use_word; + to->riw=from->riw; + to->n0=from->n0; + return(to); + } +#endif + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_ms_w.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_ms_w.c new file mode 100644 index 00000000..86a6510d --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_ms_w.c @@ -0,0 +1,137 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +int BN_MONT_CTX_set_word(mont,mod,ctx) +BN_MONT_CTX *mont; +BIGNUM *mod; +BN_CTX *ctx; + { + BIGNUM Ri,*R; +#if 1 + BN_ULONG tmod,rr; +#else + BN_ULONG buf[2]; + BIGNUM tmod; +#endif + + + bn_check_top(mod); + if (mod->top == 0) return(0); + + R= &(mont->RR); /* grab RR as a temp */ + if (BN_copy(&(mont->N),mod) == NULL) /* Set N */ + return(0); + + BN_init(&Ri); + + mont->use_word=1; + +/* EAY is this number of words to shift, or the number to shift to end up + * with a '1' in the next word? + * for 8 bit words, is 0x01ab == 1 or 2 + */ + mont->riw=(BN_num_bits(mod)+(BN_BITS2-1))/BN_BITS2; + if (!BN_zero(R)) return(0); + + /* We are now setting a number which is larger than our current + * one after we do the shift + */ + if (!BN_set_bit(R,BN_BITS2)) + goto err; + +#if 0 + tmod.d=buf; + tmod.top=1; + tmod.max=mod->max; + tmod.neg=mod->neg; + buf[0]=mod->d[0]&BN_MASK2; + buf[1]=0; + + if ((BN_mod_inverse(&Ri,R,&tmod,ctx)) == NULL) + goto err; +#else + tmod=mod->d[0]; + rr=BN_mod_inverse_word(tmod); + if (!BN_set_word(&Ri,rr)) + goto err; +#endif + + /* R*Ri */ + if (!BN_lshift(&Ri,&Ri,BN_BITS2)) + goto err; + + if (!BN_is_zero(&Ri)) + (void)BN_sub_word(&Ri,1); + else + { + /* This is not common..., 1 in BN_MASK2, + * It happens when buf[0] was == 1. So for 8 bit, + * this is 1/256, 16bit, 1 in 2^16 etc. + */ + if (!BN_set_word(&Ri,BN_MASK2)) + goto err; + } +#if 0 + BN_div(&Ri,NULL,&Ri,&tmod,ctx); + //BN_div_word(&Ri,tmod); + mont->n0=Ri.d[0]; +#else +#if 0 + { + BN_ULONG h,l; + + h=l=0; + if (Ri.top >= 2) h=Ri.d[1]; + if (Ri.top >= 1) l=Ri.d[0]; + mont->n0=bn_div_words(h,l,tmod); + } +#endif + mont->n0=bn_div_words( + (Ri.top >= 2)?Ri.d[1]:0, + (Ri.top >= 1)?Ri.d[0]:0, + tmod); +#endif + /* mod->top=z; */ + + /* setup RR for conversions */ + (void)BN_zero(&(mont->RR)); + if (!BN_set_bit(&(mont->RR),mont->riw*2*BN_BITS2)) + goto err; + (void)BN_mod(&(mont->RR),&(mont->RR),&(mont->N),ctx); + bn_zexpand(&(mont->RR),mont->riw); +#if 0 + bn_zexpand(&(mont->Ni),mont->riw); /*This is not used? */ +#endif + +err: + BN_free(&Ri); + return(1); + } + + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_mul.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_mul.c new file mode 100644 index 00000000..76e83e74 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_mul.c @@ -0,0 +1,795 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_MUL_RECURSIVE +#define SPLIT_BN_MUL_PART_RECURSIVE +#define SPLIT_BN_MUL_LOW_RECURSIVE +#define SPLIT_BN_MUL_HIGH +#define SPLIT_BN_MUL +#define SPLIT_BN_MUL_NORMAL +#define SPLIT_BN_MUL_LOW_NORMAL +#endif /* NO_SPLIT */ + +#ifdef SMALL_CODE_SIZE +#undef BN_RECURSION_MUL +#endif + +#ifdef BN_RECURSION_MUL +#if 0 /* Replaced by bn_mul_rec_words() */ +/* r is 2*n2 words in size, + * a and b are both n2 words in size. + * n2 must be a power of 2. + * We multiply and return the result. + * t must be 2*n2 words in size + * We calulate + * a[0]*b[0] + * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0]) + * a[1]*b[1] + */ +#ifdef SPLIT_BN_MUL_RECURSIVE +void bn_mul_recursive(r,a,b,n2,t) +BN_ULONG *r,*a,*b; +int n2; +BN_ULONG *t; + { + int n=n2/2,c1,c2; + unsigned int neg,zero; + BN_ULONG ln,lo,*p; + +#ifdef BN_COUNT +printf(" bn_mul_recursive %d * %d\n",n2,n2); +#endif +#ifdef BN_MUL_COMBA +/* if (n2 == 4) + { + bn_mul_comba4(r,a,b); + return; + } + else */ if (n2 == 8) + { + bn_mul_comba8(r,a,b); + return; + } +#endif + if (n2 < BN_MUL_RECURSIVE_SIZE_NORMAL) + { + /* This should not happen */ + bn_mul_normal(r,a,n2,b,n2); + return; + } + /* r=(a[0]-a[1])*(b[1]-b[0]) */ + c1=bn_cmp_words(a,&(a[n]),n); + c2=bn_cmp_words(&(b[n]),b,n); + zero=neg=0; + switch (c1*3+c2) + { + case -4: + bn_sub_words(t, &(a[n]),a, n); /* - */ + bn_sub_words(&(t[n]),b, &(b[n]),n); /* - */ + break; + case -3: + zero=1; + break; + case -2: + bn_sub_words(t, &(a[n]),a, n); /* - */ + bn_sub_words(&(t[n]),&(b[n]),b, n); /* + */ + neg=1; + break; + case -1: + case 0: + case 1: + zero=1; + break; + case 2: + bn_sub_words(t, a, &(a[n]),n); /* + */ + bn_sub_words(&(t[n]),b, &(b[n]),n); /* - */ + neg=1; + break; + case 3: + zero=1; + break; + case 4: + bn_sub_words(t, a, &(a[n]),n); + bn_sub_words(&(t[n]),&(b[n]),b, n); + break; + } + +#ifdef BN_MUL_COMBA + if (n == 4) + { + if (!zero) + bn_mul_comba4(&(t[n2]),t,&(t[n])); + else + Memset(&(t[n2]),0,8*sizeof(BN_ULONG)); + + bn_mul_comba4(r,a,b); + bn_mul_comba4(&(r[n2]),&(a[n]),&(b[n])); + } + else if (n == 8) + { + if (!zero) + bn_mul_comba8(&(t[n2]),t,&(t[n])); + else + Memset(&(t[n2]),0,16*sizeof(BN_ULONG)); + + bn_mul_comba8(r,a,b); + bn_mul_comba8(&(r[n2]),&(a[n]),&(b[n])); + } + else +#endif + { + p= &(t[n2*2]); + if (!zero) + bn_mul_recursive(&(t[n2]),t,&(t[n]),n,p); + else + Memset(&(t[n2]),0,n2*sizeof(BN_ULONG)); + bn_mul_recursive(r,a,b,n,p); + bn_mul_recursive(&(r[n2]),&(a[n]),&(b[n]),n,p); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + */ + + c1=(int)bn_add_words(t,r,&(r[n2]),n2); + + if (neg) /* if t[32] is negative */ + { + c1-=(int)bn_sub_words(&(t[n2]),t,&(t[n2]),n2); + } + else + { + /* Might have a carry */ + c1+=(int)bn_add_words(&(t[n2]),&(t[n2]),t,n2); + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + * c1 holds the carry bits + */ + c1+=(int)bn_add_words(&(r[n]),&(r[n]),&(t[n2]),n2); + if (c1) + { + p= &(r[n+n2]); + lo= *p; + ln=(lo+c1)&BN_MASK2; + *p=ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) + { + do { + p++; + lo= *p; + ln=(lo+1)&BN_MASK2; + *p=ln; + } while (ln == 0); + } + } + } +#endif +#endif + +#if 0 +#ifdef SPLIT_BN_MUL_PART_RECURSIVE +/* n+tn is the word length + * t must be n*4 is size, as does r */ +void bn_mul_part_recursive(r,a,b,tn,n,t) +BN_ULONG *r,*a,*b; +int tn,n; +BN_ULONG *t; + { + int i,j,n2=n*2; + int c1; + BN_ULONG ln,lo,*p; + +#ifdef BN_COUNT +printf(" bn_mul_part_recursive %d * %d\n",tn+n,tn+n); +#endif + if (n < 8) + { + i=tn+n; + bn_mul_normal(r,a,i,b,i); + return; + } + + /* r=(a[0]-a[1])*(b[1]-b[0]) */ + bn_sub_words(t, a, &(a[n]),n); /* + */ + bn_sub_words(&(t[n]),b, &(b[n]),n); /* - */ + +#ifdef BN_MUL_COMBA +/* if (n == 4) + { + bn_mul_comba4(&(t[n2]),t,&(t[n])); + bn_mul_comba4(r,a,b); + bn_mul_normal(&(r[n2]),&(a[n]),tn,&(b[n]),tn); + Memset(&(r[n2+tn*2]),0,sizeof(BN_ULONG)*(n2-tn*2)); + } + else */ if (n == 8) + { + bn_mul_comba8(&(t[n2]),t,&(t[n])); + bn_mul_comba8(r,a,b); + bn_mul_normal(&(r[n2]),&(a[n]),tn,&(b[n]),tn); + Memset(&(r[n2+tn*2]),0,sizeof(BN_ULONG)*(n2-tn*2)); + } + else +#endif + { + p= &(t[n2*2]); + bn_mul_recursive(&(t[n2]),t,&(t[n]),n,p); + bn_mul_recursive(r,a,b,n,p); + i=n/2; + /* If there is only a bottom half to the number, + * just do it */ + j=tn-i; + if (j == 0) + { + bn_mul_recursive(&(r[n2]),&(a[n]),&(b[n]),i,p); + Memset(&(r[n2+i*2]),0,sizeof(BN_ULONG)*(n2-i*2)); + } + else if (j > 0) /* eg, n == 16, i == 8 and tn == 11 */ + { + bn_mul_part_recursive(&(r[n2]),&(a[n]),&(b[n]), + j,i,p); + Memset(&(r[n2+tn*2]),0, + sizeof(BN_ULONG)*(n2-tn*2)); + } + else /* (j < 0) eg, n == 16, i == 8 and tn == 5 */ + { + Memset(&(r[n2]),0,sizeof(BN_ULONG)*n2); + if (tn < BN_MUL_RECURSIVE_SIZE_NORMAL) + { + bn_mul_normal(&(r[n2]),&(a[n]),tn,&(b[n]),tn); + } + else + { + for (;;) + { + i/=2; + if (i < tn) + { + bn_mul_part_recursive(&(r[n2]), + &(a[n]),&(b[n]), + tn-i,i,p); + break; + } + else if (i == tn) + { + bn_mul_recursive(&(r[n2]), + &(a[n]),&(b[n]), + i,p); + break; + } + } + } + } + } + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0]), c1 is the sign + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + */ + + c1=(int)bn_add_words(t,r,&(r[n2]),n2); + c1-=(int)bn_sub_words(&(t[n2]),t,&(t[n2]),n2); + + /* t[32] holds (a[0]-a[1])*(b[1]-b[0])+(a[0]*b[0])+(a[1]*b[1]) + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + * c1 holds the carry bits + */ + c1+=(int)bn_add_words(&(r[n]),&(r[n]),&(t[n2]),n2); + if (c1) + { + p= &(r[n+n2]); + lo= *p; + ln=(lo+c1)&BN_MASK2; + *p=ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) + { + do { + p++; + lo= *p; + ln=(lo+1)&BN_MASK2; + *p=ln; + } while (ln == 0); + } + } + } +#endif +#endif + +#if 0 +#ifdef SPLIT_BN_MUL_LOW_RECURSIVE +/* a and b must be the same size, which is n2. + * r must be n2 words and t must be n2*2 + */ +void bn_mul_low_recursive(r,a,b,n2,t) +BN_ULONG *r,*a,*b; +int n2; +BN_ULONG *t; + { + int n=n2/2; + +#ifdef BN_COUNT +printf(" bn_mul_low_recursive %d * %d\n",n2,n2); +#endif + + bn_mul_recursive(r,a,b,n,&(t[0])); + if (n >= BN_MUL_LOW_RECURSIVE_SIZE_NORMAL) + { + bn_mul_low_recursive(&(t[0]),&(a[0]),&(b[n]),n,&(t[n2])); + bn_add_words(&(r[n]),&(r[n]),&(t[0]),n); + bn_mul_low_recursive(&(t[0]),&(a[n]),&(b[0]),n,&(t[n2])); + bn_add_words(&(r[n]),&(r[n]),&(t[0]),n); + } + else + { + bn_mul_low_normal(&(t[0]),&(a[0]),&(b[n]),n); + bn_mul_low_normal(&(t[n]),&(a[n]),&(b[0]),n); + bn_add_words(&(r[n]),&(r[n]),&(t[0]),n); + bn_add_words(&(r[n]),&(r[n]),&(t[n]),n); + } + } +#endif +#endif + +#ifdef SPLIT_BN_MUL_HIGH +#if 0 +/* a and b must be the same size, which is n2. + * r must be n2 words and t must be n2*2 + * l is the low words of the output. + * t must be n2*3 + */ +void bn_mul_high(r,a,b,l,n2,t) +BN_ULONG *r,*a,*b,*l; +int n2; +BN_ULONG *t; + { + int i,n; + int c1,c2; + int neg,oneg,zero; + BN_ULONG ll,lc,*lp,*mp; + +#ifdef BN_COUNT +printf(" bn_mul_high %d * %d\n",n2,n2); +#endif + n=n2/2; + + /* Calculate (al-ah)*(bh-bl) */ + neg=zero=0; + c1=bn_cmp_words(&(a[0]),&(a[n]),n); + c2=bn_cmp_words(&(b[n]),&(b[0]),n); + switch (c1*3+c2) + { + case -4: + bn_sub_words(&(r[0]),&(a[n]),&(a[0]),n); + bn_sub_words(&(r[n]),&(b[0]),&(b[n]),n); + break; + case -3: + zero=1; + break; + case -2: + bn_sub_words(&(r[0]),&(a[n]),&(a[0]),n); + bn_sub_words(&(r[n]),&(b[n]),&(b[0]),n); + neg=1; + break; + case -1: + case 0: + case 1: + zero=1; + break; + case 2: + bn_sub_words(&(r[0]),&(a[0]),&(a[n]),n); + bn_sub_words(&(r[n]),&(b[0]),&(b[n]),n); + neg=1; + break; + case 3: + zero=1; + break; + case 4: + bn_sub_words(&(r[0]),&(a[0]),&(a[n]),n); + bn_sub_words(&(r[n]),&(b[n]),&(b[0]),n); + break; + } + + oneg=neg; + /* t[10] = (a[0]-a[1])*(b[1]-b[0]) */ + /* r[10] = (a[1]*b[1]) */ +#ifdef BN_MUL_COMBA + if (n == 8) + { + bn_mul_comba8(&(t[0]),&(r[0]),&(r[n])); + bn_mul_comba8(r,&(a[n]),&(b[n])); + } + else +#endif + { +#ifdef BN_MUL_RECURSION + bn_mul_recursive(&(t[0]),&(r[0]),&(r[n]),n,&(t[n2])); + bn_mul_recursive(r,&(a[n]),&(b[n]),n,&(t[n2])); +#else + bn_mul_normal(&(t[0]),&(r[0]),n,&(r[n]),n); + bn_mul_normal(r,&(a[n]),n,&(b[n]),n); +#endif + } + + /* s0 == low(al*bl) + * s1 == low(ah*bh)+low((al-ah)*(bh-bl))+low(al*bl)+high(al*bl) + * We know s0 and s1 so the only unknown is high(al*bl) + * high(al*bl) == s1 - low(ah*bh+s0+(al-ah)*(bh-bl)) + * high(al*bl) == s1 - (r[0]+l[0]+t[0]) + */ + if (l != NULL) + { + lp= &(t[n2+n]); + c1=(int)bn_add_words(lp,&(r[0]),&(l[0]),n); + } + else + { + c1=0; + lp= &(r[0]); + } + + if (neg) + neg=(int)bn_sub_words(&(t[n2]),lp,&(t[0]),n); + else + { + bn_add_words(&(t[n2]),lp,&(t[0]),n); + neg=0; + } + + if (l != NULL) + { + bn_sub_words(&(t[n2+n]),&(l[n]),&(t[n2]),n); + } + else + { + lp= &(t[n2+n]); + mp= &(t[n2]); + for (i=0; i 0) + { + lc=c1; + do { + ll=(r[i]+lc)&BN_MASK2; + r[i++]=ll; + lc=(lc > ll); + } while (lc); + } + else + { + lc= -c1; + do { + ll=r[i]; + r[i++]=(ll-lc)&BN_MASK2; + lc=(lc > ll); + } while (lc); + } + } + if (c2 != 0) /* Add starting at r[1] */ + { + i=n; + if (c2 > 0) + { + lc=c2; + do { + ll=(r[i]+lc)&BN_MASK2; + r[i++]=ll; + lc=(lc > ll); + } while (lc); + } + else + { + lc= -c2; + do { + ll=r[i]; + r[i++]=(ll-lc)&BN_MASK2; + lc=(lc > ll); + } while (lc); + } + } + } +#endif +#endif +#endif + +#ifdef SPLIT_BN_MUL +int BN_mul(r,a,b,ctx) +BIGNUM *r,*a,*b; +BN_CTX *ctx; + { + int top,al,bl,neg; + BIGNUM *rr; +#ifdef BN_RECURSION_MUL + BIGNUM *t; + int i,j,k,l; +#endif + +#ifdef BN_COUNT +printf("BN_mul %d * %d\n",a->top,b->top); +#endif + + bn_check_top(a); + bn_check_top(b); + bn_check_top(r); + + al=a->top; + bl=b->top; + + if ((al == 0) || (bl == 0)) + { + (void)BN_zero(r); + return(1); + } + top=al+bl; + neg=a->neg^b->neg; + + if ((r == a) || (r == b)) + rr= &(ctx->bn[ctx->tos+1]); + else + rr=r; + + if (bn_wexpand(rr,top) == NULL) return(0); + rr->top=top; + +#if defined(BN_MUL_COMBA) || defined(BN_RECURSION_MUL) + if (al == bl) + { +# ifdef BN_MUL_COMBA +/* if (al == 4) + { + bn_mul_comba4(rr->d,a->d,b->d); + goto end; + } + else */ if (al == 8) + { + bn_mul_comba8(rr->d,a->d,b->d); + goto end; + } + else +# endif +#ifdef BN_RECURSION_MUL + if (al < BN_MULL_SIZE_NORMAL) +#endif + { + bn_mul_normal(rr->d,a->d,al,b->d,bl); + goto end; + } +# ifdef BN_RECURSION_MUL + goto symetric; +# endif + } +#endif +#ifdef BN_RECURSION_MUL + else if ((al < BN_MULL_SIZE_NORMAL) || (bl < BN_MULL_SIZE_NORMAL)) + { + bn_mul_normal(rr->d,a->d,al,b->d,bl); + goto end; + } + else + { + i=(al-bl); + if ((i == 1) && !BN_get_flags(b,BN_FLG_STATIC_DATA)) + { + bn_wexpand(b,al); + b->d[bl]=0; + bl++; + goto symetric; + } + else if ((i == -1) && !BN_get_flags(a,BN_FLG_STATIC_DATA)) + { + bn_wexpand(a,bl); + a->d[al]=0; + al++; + goto symetric; + } + } +#endif + +#ifdef BN_RECURSION_MUL +normal_mul: +#endif + bn_mul_normal(rr->d,a->d,al,b->d,bl); + +#ifdef BN_RECURSION_MUL + if (0) + { +symetric: + /* symetric and > 4 */ + /* 16 or larger */ + l=BN_num_bits_word((BN_ULONG)al); + j=1<<(l-1); + k=j+j; + t= &(ctx->bn[ctx->tos]); + if (al == j) /* exact multiple */ + { + BN_REC rec; + rec.depth=l-5; + rec.n=j; + rec.mul=bn_mul_comba8; + rec.sqr=bn_sqr_comba8; + if (bn_wexpand(t,k+k) == NULL) + return(0); + if (bn_wexpand(rr,k) == NULL) + return(0); + bn_mul_rec_words(rr->d,a->d,b->d,t->d,&rec); + } + else + goto normal_mul; +#if 0 + { + bn_zexpand(a,k); + bn_zexpand(b,k); + bn_wexpand(t,k); + bn_wexpand(rr,k); + bn_mul_part_recursive(rr->d,a->d,b->d,al-j,j,t->d); + } +#endif + } +#endif +#if defined(BN_MUL_COMBA) || defined(BN_RECURSION_MUL) +end: +#endif + + r->neg=neg; + bn_fix_top(rr); + if (r != rr) (void)BN_copy(r,rr); + return(1); + } +#endif + + +#ifdef SPLIT_BN_MUL_NORMAL +void bn_mul_normal(r,a,na,b,nb) +BN_ULONG *r,*a; +int na; +BN_ULONG *b; +int nb; + { + BN_ULONG *rr; + +#ifdef BN_COUNT +printf(" bn_mul_normal %d * %d\n",na,nb); +#endif + /* asymetric and >= 4 */ +#if 0 + if ((na == nb) && (na == 8)) + { + bn_mul_normal(r,a,na,b,nb); + return; + } +#endif + + if (na < nb) + { + int itmp; + BN_ULONG *ltmp; + + itmp=na; na=nb; nb=itmp; + ltmp=a; a=b; b=ltmp; + + } + rr= &(r[na]); + rr[0]=bn_mul_words(r,a,na,b[0]); + + for (;;) + { + if (--nb <= 0) return; + rr[1]=bn_mul_add_words(&(r[1]),a,na,b[1]); + if (--nb <= 0) return; + rr[2]=bn_mul_add_words(&(r[2]),a,na,b[2]); + if (--nb <= 0) return; + rr[3]=bn_mul_add_words(&(r[3]),a,na,b[3]); + if (--nb <= 0) return; + rr[4]=bn_mul_add_words(&(r[4]),a,na,b[4]); + rr+=4; + r+=4; + b+=4; + } + } +#endif + +#ifdef SPLIT_BN_MUL_LOW_NORMAL +void bn_mul_low_normal(r,a,b,n) +BN_ULONG *r,*a,*b; +int n; + { +#ifdef BN_COUNT +printf(" bn_mul_low_normal %d * %d\n",n,n); +#endif + (void)bn_mul_words(r,a,n,b[0]); + + for (;;) + { + if (--n <= 0) return; + (void)bn_mul_add_words(&(r[1]),a,n,b[1]); + if (--n <= 0) return; + (void)bn_mul_add_words(&(r[2]),a,n,b[2]); + if (--n <= 0) return; + (void)bn_mul_add_words(&(r[3]),a,n,b[3]); + if (--n <= 0) return; + (void)bn_mul_add_words(&(r[4]),a,n,b[4]); + r+=4; + b+=4; + } + } +#endif +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_r_exp.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_r_exp.c new file mode 100644 index 00000000..ef056efd --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_r_exp.c @@ -0,0 +1,150 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +/* #ifdef RECP_MUL_MOD */ +int BN_mod_exp_recp(r,a,p,m,ctx) +BIGNUM *r; +BIGNUM *a; +BIGNUM *p; +BIGNUM *m; +BN_CTX *ctx; + { + int i,j,bits,ret=0,wstart,wend,window,wvalue; + int start=1,ts=0; + BIGNUM *aa; + BIGNUM val[BN_EXP_TABLE_SIZE]; + BN_RECP_CTX recp; + + bits=BN_num_bits(p); + + if (BN_is_zero(a)) + { (void)BN_zero(r); return(1); } + if (BN_is_zero(p)) + { (void)BN_one(r); return(1); } + if (BN_is_one(p)) + { (void)BN_copy(r,a); return(1); } + + BN_RECP_CTX_init(&recp); + if (BN_RECP_CTX_set(&recp,m,ctx) <= 0) goto err; + + BN_init(&(val[0])); + ts=1; + + aa= &(ctx->bn[ctx->tos++]); + + if (!BN_mod(&(val[0]),a,m,ctx)) goto err; /* 1 */ + if (!BN_mod_mul_reciprocal(aa,&(val[0]),&(val[0]),&recp,ctx)) + goto err; /* 2 */ + + if (bits <= 17) /* This is probably 3 or 0x10001, so just do singles */ + window=1; + else if (bits >= 256) + window=5; /* max size of window */ + else if (bits >= 128) + window=4; + else + window=3; + + j=1<<(window-1); + for (i=1; i>1]),&recp,ctx)) + goto err; + + /* move the 'window' down further */ + wstart-=wend+1; + wvalue=0; + start=0; + if (wstart < 0) break; + } + ret=1; +err: + ctx->tos--; + for (i=0; in; + int n2=n/2; + int neg=0; + BN_ULONG c1; + + + if (rec->depth == 0) + { + /* t needs to have space for 4*n words + * The multiply needs to be a n2*n2 -> n + */ +#ifndef NOPROTO + void (PRE_CCONV CCONV *rmul)(BN_ULONG *r, BN_ULONG *a, BN_ULONG *b); +#else + void (PRE_CCONV CCONV *rmul)(); +#endif + rmul=rec->mul; + +#ifdef _EXTRA_ARG_ + /* THIS IS WRONG - there is no extra int arg on the end */ + rmul(&(r[0]),&(a[0]),&(b[0]),n2); + rmul(&(r[n]),&(a[n2]),&(b[n2]),n2); +#else + rmul(&(r[0]),&(a[0]),&(b[0])); + rmul(&(r[n]),&(a[n2]),&(b[n2])); +#endif + + if (bn_sub_words(&(tt[n+0]), &(a[0]),&(a[n2]),n2)) + { + bn_2s_comp(&(tt[n+ 0]),&(tt[n+ 0]),n2); + neg=1; + } + else + neg=0; + if (bn_sub_words(&(tt[n+n2]),&(b[n2]),&(b[0]),n2)) + { + neg^=1; + bn_2s_comp(&(tt[n+n2]),&(tt[n+n2]),n2); + } + +#ifdef _EXTRA_ARG_ + rmul(&(tt[0]),&(tt[n+0]),&(tt[n+n2]),n2); +#else + rmul(&(tt[0]),&(tt[n+0]),&(tt[n+n2])); +#endif + } + else /* Leaf node */ + { + /* t has 4*n words taken per call. + * Since n is half the size per call, we need + * 6*n words for our current level and all sub levels + * The multiply needs to be a n2*n2 -> n + */ + rec->depth--; + rec->n=n2; + bn_mul_rec_words(&(r[0]), &(a[0]), &(b[0]), &(tt[n+n]),rec); + bn_mul_rec_words(&(r[n]), &(a[n2]),&(b[n2]), &(tt[n+n]),rec); + + neg=0; + if (bn_sub_words(&(tt[n+0]), &(a[0]),&(a[n2]),n2)) + { + bn_2s_comp(&(tt[n+ 0]),&(tt[n+ 0]),n2); + neg=1; + } + else + neg=0; + if (bn_sub_words(&(tt[n+n2]),&(b[n2]),&(b[0]),n2)) + { + neg^=1; + bn_2s_comp(&(tt[n+n2]),&(tt[n+n2]),n2); + } + + bn_mul_rec_words(&(tt[0]),&(tt[n]),&(tt[n+n2]),&(tt[n+n]),rec); + rec->n=n; + rec->depth++; + } + + c1=bn_add_words(&(tt[n]),&(r[0]),&(r[n]),n); + + if (neg) + c1-=bn_sub_words(&(tt[0]),&(tt[n]),&(tt[0]),n); + else + c1+=bn_add_words(&(tt[0]),&(tt[n]),&(tt[0]),n); + tt[n]=c1; + c1=bn_add_words(&(r[n2]),&(r[n2]),&(tt[0]),n+1); + if (c1) + { + tt= &(r[n+n2+1]); + do { + } while (++(*(tt++)) == 0); + } + } +#endif + +#ifdef SPLIT_BN_SQR_REC_WORDS +/* tt needs to be 3*n words */ +void bn_sqr_rec_words(r,a,tt,rec) +BN_ULONG *r,*a,*tt; +BN_REC *rec; + { + int n=rec->n; + int n2=n/2; + BN_ULONG c1; + + if (rec->depth == 0) + { + /* t needs to have space for 4*n words + * The multiply needs to be a n2*n2 -> n + */ +#ifndef NOPROTO + void (PRE_CCONV CCONV *rsqr)(BN_ULONG *r, BN_ULONG *a); +#else + void (PRE_CCONV CCONV *rsqr)(); +#endif + + rsqr=rec->sqr; + +#ifdef _EXTRA_ARG_ + /* THIS IS WRONG - there is no extra int arg on the end */ + rsqr(&(r[0]), &(a[0]), n2); + rsqr(&(r[n]), &(a[n2]),n2); +#else + rsqr(&(r[0]), &(a[0])); + rsqr(&(r[n]), &(a[n2])); +#endif + + if (bn_sub_words(&(tt[n+0]), &(a[0]),&(a[n2]),n2)) + bn_2s_comp(&(tt[n+0]),&tt[n+0], n2); + +#ifdef _EXTRA_ARG_ + rsqr(&(tt[0]),&(tt[n]), n2); +#else + rsqr(&(tt[0]),&(tt[n])); +#endif + + } + else /* Leaf node */ + { + /* t has 4*n words taken per call. + * Since n is half the size per call, we need + * 6*n words for our current level and all sub levels + * The multiply needs to be a n2*n2 -> n + */ + rec->depth--; + rec->n=n2; + bn_sqr_rec_words(&(r[0]), &(a[0]), &(tt[n+n]),rec); + bn_sqr_rec_words(&(r[n]), &(a[n2]),&(tt[n+n]),rec); + + if (bn_sub_words(&(tt[n+0]), &(a[0]),&(a[n2]),n2)) + bn_2s_comp(&(tt[n+0]),&tt[n+0], n2); + bn_sqr_rec_words(&(tt[0]),&(tt[n]),&(tt[n+n]),rec); + + rec->n=n; + rec->depth++; + } + + c1=bn_add_words(&(tt[n]),&(r[0]),&(r[n]),n); + c1-=bn_sub_words(&(tt[0]),&(tt[n]),&(tt[0]),n); + + tt[n]=c1; + c1=bn_add_words(&(r[n2]),&(r[n2]),&(tt[0]),n+1); + if (c1) + { + tt= &(r[n+n2+1]); + do { + } while (++(*(tt++)) == 0); + } + } +#endif + +#endif /* !NO_SPLIT || !SPLIT_FILE */ diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_recp.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_recp.c new file mode 100644 index 00000000..6830f59d --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_recp.c @@ -0,0 +1,218 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +void BN_RECP_CTX_init(recp) +BN_RECP_CTX *recp; + { + BN_init(&(recp->N)); + BN_init(&(recp->Nr)); + recp->num_bits=0; + recp->flags=0; + } + +BN_RECP_CTX *BN_RECP_CTX_new() + { + BN_RECP_CTX *ret; + + if ((ret=(BN_RECP_CTX *)Malloc(sizeof(BN_RECP_CTX))) == NULL) + return(NULL); + + BN_RECP_CTX_init(ret); + ret->flags=BN_FLG_MALLOCED; + return(ret); + } + +void BN_RECP_CTX_free(recp) +BN_RECP_CTX *recp; + { + BN_free(&(recp->N)); + BN_free(&(recp->Nr)); + if (recp->flags & BN_FLG_MALLOCED) + Free(recp); + } + +int BN_RECP_CTX_set(recp,d,ctx) +BN_RECP_CTX *recp; +BIGNUM *d; +BN_CTX *ctx; + { + (void)BN_copy(&(recp->N),d); + (void)BN_zero(&(recp->Nr)); + recp->num_bits=BN_num_bits(d); + recp->shift=0; + ctx=ctx; /* Stop warning */ + return(1); + } + +int BN_mod_mul_reciprocal(r, x, y, recp, ctx) +BIGNUM *r; +BIGNUM *x; +BIGNUM *y; +BN_RECP_CTX *recp; +BN_CTX *ctx; + { + int ret=0; + BIGNUM *a; + + bn_check_top(x); + bn_check_top(y); + + a= &(ctx->bn[ctx->tos++]); + if (y != NULL) + { + if (x == y) + { if (!BN_sqr(a,x,ctx)) goto err; } + else + { if (!BN_mul(a,x,y,ctx)) goto err; } + } + else + a=x; /* Just do the mod */ + + (void)BN_div_recp(NULL,r,a,recp,ctx); + ret=1; +err: + ctx->tos--; + return(ret); + } + +int BN_div_recp(dv,rem,m,recp,ctx) +BIGNUM *dv; +BIGNUM *rem; +BIGNUM *m; +BN_RECP_CTX *recp; +BN_CTX *ctx; + { + int i,j,tos,ret=0,ex; + BIGNUM *a,*b,*d,*r; + + bn_check_top(m); + + tos=ctx->tos; + a= &(ctx->bn[ctx->tos++]); + b= &(ctx->bn[ctx->tos++]); + if (dv != NULL) + d=dv; + else + d= &(ctx->bn[ctx->tos++]); + if (rem != NULL) + r=rem; + else + r= &(ctx->bn[ctx->tos++]); + + if (BN_ucmp(m,&(recp->N)) < 0) + { + (void)BN_zero(d); + (void)BN_copy(r,m); + ctx->tos=tos; + return(1); + } + + /* We want the remainder + * Given input of ABCDEF / ab + * we need multiply ABCDEF by 3 digests of the reciprocal of ab + * + */ + i=BN_num_bits(m); + + j=recp->num_bits*2; + if (j > i) + { + i=j; + ex=0; + } + else + { + ex=(i-j)/2; + } + + j=i/2; + + if (i != recp->shift) + recp->shift=BN_reciprocal(&(recp->Nr),&(recp->N), + i,ctx); + + if (!BN_rshift(a,m,j-ex)) goto err; + if (!BN_mul(b,a,&(recp->Nr),ctx)) goto err; + if (!BN_rshift(d,b,j+ex)) goto err; + d->neg=0; + if (!BN_mul(b,&(recp->N),d,ctx)) goto err; + if (!BN_usub(r,m,b)) goto err; + r->neg=0; + + j=0; +#if 1 + while (BN_ucmp(r,&(recp->N)) >= 0) + { + if (j++ > 2) + { +#ifndef NO_ERR + BNerr(BN_F_BN_DIV_RECP,BN_R_BAD_RECIPROCAL); +#endif + goto err; + } + if (!BN_usub(r,r,&(recp->N))) goto err; + if (!BN_add_word(d,1)) goto err; + } +#endif + + r->neg=BN_is_zero(r)?0:m->neg; + d->neg=m->neg^recp->N.neg; + ret=1; +err: + ctx->tos=tos; + return(ret); + } + +/* len is the expected size of the result + * We actually calculate with an extra word of precision, so + * we can do faster division if the remainder is not required. + */ +int BN_reciprocal(r,m,len,ctx) +BIGNUM *r; +BIGNUM *m; +int len; +BN_CTX *ctx; + { + int ret= -1; + BIGNUM t; + + bn_check_top(m); + + BN_init(&t); + + (void)BN_zero(&t); + if (!BN_set_bit(&t,len)) goto err; + + if (!BN_div(r,NULL,&t,m,ctx)) goto err; + ret=len; +err: + BN_free(&t); + return(ret); + } + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_rsh.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_rsh.c new file mode 100644 index 00000000..0f0d5c60 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_rsh.c @@ -0,0 +1,139 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_RSHIFT1 +#define SPLIT_BN_RSHIFT +#endif /* NO_SPLIT */ + +#ifdef SPLIT_BN_RSHIFT1 +#ifdef SMALL_CODE_SIZE +int BN_rshift1(r, a) +BIGNUM *r; +BIGNUM *a; + { + return(BN_rshift(r,a,1)); + } + +#else + +int BN_rshift1(r, a) +BIGNUM *r; +BIGNUM *a; + { + BN_ULONG *ap,*rp,t,c; + int i; + + bn_check_top(a); + + if (BN_is_zero(a)) + { + BN_zero(r); + return(1); + } + if (a != r) + { + if (bn_wexpand(r,a->top) == NULL) return(0); + r->top=a->top; + r->neg=a->neg; + } + ap=a->d; + rp=r->d; + c=0; + for (i=a->top-1; i>=0; i--) + { + t=ap[i]; + rp[i]=((t>>1)&BN_MASK2)|c; + c=(t&1)?BN_TBIT:0; + } + bn_fix_top(r); + return(1); + } +#endif +#endif + +#ifdef SPLIT_BN_RSHIFT +int BN_rshift(r, a, n) +BIGNUM *r; +BIGNUM *a; +int n; + { + int i,j,nw,lb,rb; + BN_ULONG *t,*f; + BN_ULONG l,tmp; + + bn_check_top(a); + +#ifndef SMALL_CODE_SIZE + if (n == 1) return(BN_rshift1(r,a)); +#endif + nw=n/BN_BITS2; + rb=n%BN_BITS2; + lb=BN_BITS2-rb; + if (nw > a->top) + { + (void)BN_zero(r); + return(1); + } + if (r != a) + { + if (bn_wexpand(r,a->top-nw+1+1/*???*/) == NULL) return(0); + r->neg=a->neg; + } + + f= &(a->d[nw]); + t=r->d; + j=a->top-nw; + r->top=j; + + if (rb == 0) + { + for (i=j+1; i > 0; i--) + *(t++)= *(f++); + } + else + { + l= *(f++); + for (i=1; i>rb)&BN_MASK2; + l= *(f++); + *(t++) =(tmp|(l<>rb)&BN_MASK2; + *t=0; + } + bn_fix_top(r); + return(1); + } +#endif + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_sqr.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_sqr.c new file mode 100644 index 00000000..24b5c4cb --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_sqr.c @@ -0,0 +1,289 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +#ifdef SMALL_CODE_SIZE +#undef BN_RECURSION_SQR +#endif + +#if !(defined(NO_SPLIT) && defined(SPLIT_FILE)) + +#ifdef NO_SPLIT +#define SPLIT_BN_SQR +#define SPLIT_BN_SQR_NORMAL +#define SPLIT_BN_RECURSION_SQR +#endif /* NO_SPLIT */ + +#ifdef SPLIT_BN_SQR +/* r must not be a */ +int BN_sqr(r, a, ctx) +BIGNUM *r; +BIGNUM *a; +BN_CTX *ctx; + { + int max,al; + BIGNUM *tmp,*rr; + +#ifdef BN_COUNT +printf("BN_sqr %d * %d\n",a->top,a->top); +#endif + bn_check_top(a); + tmp= &(ctx->bn[ctx->tos]); + rr=(a != r)?r: (&ctx->bn[ctx->tos+1]); + + al=a->top; + if (al <= 0) + { + r->top=0; + return(1); + } + + max=(al+al); + if (bn_wexpand(rr,max) == NULL) return(0); + + rr->top=max; + rr->neg=0; + + if (al == 4) + { +#ifndef BN_SQR_COMBA + BN_ULONG t[8]; + bn_sqr_normal(rr->d,a->d,4,t); +#else + bn_sqr_comba4(rr->d,a->d); +#endif + } + else if (al == 8) + { +#ifndef BN_SQR_COMBA + BN_ULONG t[16]; + bn_sqr_normal(rr->d,a->d,8,t); +#else + bn_sqr_comba8(rr->d,a->d); +#endif + } + else + { +#if 1 && defined(BN_RECURSION_SQR) + if (al < BN_SQR_RECURSIVE_SIZE_NORMAL) + { + BN_ULONG t[BN_SQR_RECURSIVE_SIZE_NORMAL*2]; + bn_sqr_normal(rr->d,a->d,al,t); + } + else + { + int j,l,k; + + l=BN_num_bits_word((BN_ULONG)al); + j=1<<(l-1); + k=j+j; + if ((al == j) && !BN_get_flags(a,BN_FLG_STATIC_DATA)) + { + BN_REC rec; + if (bn_wexpand(tmp,k*2) == NULL) return(0); + rec.depth=l-5; + rec.n=j; + rec.mul=bn_mul_comba8; + rec.sqr=bn_sqr_comba8; + + bn_sqr_rec_words(rr->d,a->d,tmp->d,&rec); + } + else + { + if (bn_wexpand(tmp,max) == NULL) return(0); + bn_assert(al*2 <= max); + bn_sqr_normal(rr->d,a->d,al,tmp->d); + } + } +#else + if (bn_wexpand(tmp,max) == NULL) return(0); + bn_assert(al*2 <= max); + bn_sqr_normal(rr->d,a->d,al,tmp->d); +#endif +#ifdef BN_DEBUG + tmp->top=0; +#endif + } + + if ((max > 0) && (rr->d[max-1] == 0)) rr->top--; + if (rr != r) (void)BN_copy(r,rr); + return(1); + } +#endif + +#ifdef SPLIT_BN_SQR_NORMAL +/* tmp must have 2*n words */ +void bn_sqr_normal(r, a, n, tmp) +BN_ULONG *r; +BN_ULONG *a; +int n; +BN_ULONG *tmp; + { + int i,j,max; + BN_ULONG *ap,*rp,m; + + max=n*2; + ap=a; + rp=r; + rp[0]=rp[max-1]=0; + rp++; + j=n; + + if (--j > 0) + { + m= (*ap++); + rp[j]=bn_mul_words(rp,ap,j,m); + rp+=2; + } + + for (i=n-2; i>0; i--) + { + j--; + m= *(ap++); + rp[j]=bn_mul_add_words(rp,ap,j,m); + rp+=2; + } + + (void)bn_add_words(r,r,r,max); + + /* There will not be a carry */ + + bn_sqr_words(tmp,a,n); + + (void)bn_add_words(r,r,tmp,max); + } +#endif + +#if 0 /* replaced by bn_sqr_rec_words() AND this has bugs */ +#ifdef SPLIT_BN_RECURSION_SQR +#ifdef BN_RECURSION_SQR +/* r is 2*n words in size, + * a and b are both n words in size. + * n must be a power of 2. + * We multiply and return the result. + * t must be 2*n words in size + * We calulate + * a[0]*b[0] + * a[0]*b[0]+a[1]*b[1]+(a[0]-a[1])*(b[1]-b[0]) + * a[1]*b[1] + */ +void bn_sqr_recursive(r,a,n2,t) +BN_ULONG *r,*a; +int n2; +BN_ULONG *t; + { + int n=n2/2; + int zero,c1; + BN_ULONG ln,lo,*p; + +#ifdef BN_COUNT +printf(" bn_sqr_recursive %d * %d\n",n2,n2); +#endif + if (n2 == 4) + { +#ifndef BN_SQR_COMBA + bn_sqr_normal(r,a,4,t); +#else + bn_sqr_comba4(r,a); +#endif + return; + } + else if (n2 == 8) + { +#ifndef BN_SQR_COMBA + bn_sqr_normal(r,a,8,t); +#else + bn_sqr_comba8(r,a); +#endif + return; + } + if (n2 < BN_SQR_RECURSIVE_SIZE_NORMAL) + { + bn_sqr_normal(r,a,n2,t); + return; + } + /* r=(a[0]-a[1])*(a[1]-a[0]) */ + c1=bn_cmp_words(a,&(a[n]),n); + zero=0; + if (c1 > 0) + bn_sub_words(t,a,&(a[n]),n); + else if (c1 < 0) + bn_sub_words(t,&(a[n]),a,n); + else + zero=1; + + /* The result will always be negative unless it is zero */ + p= &(t[n2*2]); + + if (!zero) + bn_sqr_recursive(&(t[n2]),t,n,p); + else + Memset(&(t[n2]),0,n*sizeof(BN_ULONG)); + bn_sqr_recursive(r,a,n,p); + bn_sqr_recursive(&(r[n2]),&(a[n]),n,p); + + /* t[32] holds (a[0]-a[1])*(a[1]-a[0]), it is negative or zero + * r[10] holds (a[0]*b[0]) + * r[32] holds (b[1]*b[1]) + */ + + c1=(int)(bn_add_words(t,r,&(r[n2]),n2)); + + /* t[32] is negative */ + c1-=(int)(bn_sub_words(&(t[n2]),t,&(t[n2]),n2)); + + /* t[32] holds (a[0]-a[1])*(a[1]-a[0])+(a[0]*a[0])+(a[1]*a[1]) + * r[10] holds (a[0]*a[0]) + * r[32] holds (a[1]*a[1]) + * c1 holds the carry bits + */ + c1+=(int)(bn_add_words(&(r[n]),&(r[n]),&(t[n2]),n2)); + if (c1) + { + p= &(r[n+n2]); + lo= *p; + ln=(lo+c1)&BN_MASK2; + *p=ln; + + /* The overflow will stop before we over write + * words we should not overwrite */ + if (ln < (BN_ULONG)c1) + { + do { + p++; + lo= *p; + ln=(lo+1)&BN_MASK2; + *p=ln; + } while (ln == 0); + } + } + } +#endif +#endif +#endif +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/bn_wdiv.c b/build/libraries_sysmenu/acsign/ARM9/src/bn_wdiv.c new file mode 100644 index 00000000..97c21860 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/bn_wdiv.c @@ -0,0 +1,116 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +#include "bn_lcl.h" + +#ifndef OPT_BN_ASM + +#ifndef BN_DIV_WORDS +#define BN_DIV_WORDS +#endif + +#endif + +#ifdef BN_DIV_WORDS +#if defined(BN_LLONG) +BN_ULONG bn_div_words(h,l,d) +BN_ULONG h,l,d; + { + return((BN_ULONG)(((((BN_ULLONG)h)< ((BN_ULONG)1)<= d) h-=d; + + if (i) + { + d=(d<>(BN_BITS2-i)))&BN_MASK2; + l=(l<>BN_BITS4)&BN_MASK2lh; + dl=(d&BN_MASK2l); + for (;;) + { + if ((h>>BN_BITS4) == dh) + q=BN_MASK2l; + else + q=h/dh; + + for (;;) + { + t=(h-q*dh)&BN_MASK2; + if ((t&BN_MASK2h) || + (((dl*q)&BN_MASK2) <= (( + (t<>BN_BITS4)&BN_MASK2lh))&BN_MASK2))) + break; + q--; + } + th=(q*dh)&BN_MASK2; + tl=(q*dl)&BN_MASK2; + t=(tl>>BN_BITS4); + tl=(tl&BN_MASK2lh)<>BN_BITS4))&BN_MASK2; + l=(l&BN_MASK2l)<top-1; i>=0; i--) + { +#ifndef BN_LLONG + ret=((ret<d[i]>>BN_BITS4)&BN_MASK2l))%w; + ret=((ret<d[i]&BN_MASK2l))%w; +#else + ret=(BN_ULLONG)(((ret<<(BN_ULLONG)BN_BITS2)|a->d[i])% + (BN_ULLONG)w); +#endif + } + return((BN_ULONG)ret); + } +#endif + +#ifdef SPLIT_BN_DIV_WORD +BN_ULONG BN_div_word(a, w) +BIGNUM *a; +BN_ULONG w; + { + BN_ULONG ret; + int i; + + if (a->top == 0) return(0); + ret=0; + w=w&BN_MASK2;//w&=BN_MASK2; + for (i=a->top-1; i>=0; i--) + { + BN_ULONG l,d; + + l=a->d[i]; + d=bn_div_words(ret,l,w); + ret=(l-((d*w)&BN_MASK2))&BN_MASK2; + a->d[i]=d; + } + if ((a->top > 0) && (a->d[a->top-1] == 0)) + a->top--; + return(ret); + } +#endif + +#ifdef SPLIT_BN_ADD_WORD +int BN_add_word(a, w) +BIGNUM *a; +BN_ULONG w; + { + BN_ULONG l; + int i; + + if (w == 0) return(1); + bn_check_top(a); + + w=w&BN_MASK2;//w&=BN_MASK2; + if (a->neg) + { + if(a->top > 1) + { + a->neg=0; + i=BN_sub_word(a,w); + a->neg=1; + return(i); + } + else + { /* a->top == 1, it cannot be 0 */ + l=a->d[0]; + if (l > w) + a->d[0]=l-w; + else if (l < w) + { + a->neg=0; + a->d[0]=w-l; + } + else + { + a->neg=0; + a->top=0; + } + return(1); + } + } + w=w&BN_MASK2;//w&=BN_MASK2; + if (bn_wexpand(a,a->top+1) == NULL) return(0); + a->d[a->top]=0; + i=0; + for (;;) + { + l=(a->d[i]+(BN_ULONG)w)&BN_MASK2; + a->d[i]=l; + if (w > l) + w=1; + else + break; + i++; + } + if (i >= a->top) + a->top++; + return(1); + } +#endif + +#ifdef SPLIT_BN_SUB_WORD +int BN_sub_word(a, w) +BIGNUM *a; +BN_ULONG w; + { + int i; + + bn_check_top(a); + if (w == 0) return(1); + + w=w&BN_MASK2;//w&=BN_MASK2; + if (a->neg) + { + a->neg=0; + i=BN_add_word(a,w); + a->neg=1; + return(i); + } + + w=w&BN_MASK2;//w&=BN_MASK2; + if (a->top <= 1) + { + BN_ULONG l; + + if (a->top == 0) + { + if (bn_wexpand(a,1) == NULL) return(0); + a->d[0]=w; + a->neg = 1; + a->top = 1; + return(1); + } + l=a->d[0]; + if (l == w) + a->top=0; + else if (l > w) + a->d[0]=l-w; + else + { + a->neg=1; + a->d[0]=w-l; + } + return(1); + } + i=0; + for (;;) + { + if (a->d[i] >= w) + { + a->d[i]-=w; + break; + } + else + { + a->d[i]=(a->d[i]-w)&BN_MASK2; + i++; + w=1; + } + } + if ((a->d[i] == 0) && (i == (a->top-1))) + a->top--; + return(1); + } +#endif + +#ifdef SPLIT_BN_MUL_WORD +int BN_mul_word(a,w) +BIGNUM *a; +BN_ULONG w; + { + BN_ULONG ll; + + w=w&BN_MASK2;//w&=BN_MASK2; + if (a->top) + { + ll=bn_mul_words(a->d,a->d,a->top,w); + if (ll) + { + if (bn_wexpand(a,a->top+1) == NULL) return(0); + a->d[a->top++]=ll; + } + } + return(1); + } +#endif + +#endif diff --git a/build/libraries_sysmenu/acsign/ARM9/src/main.c b/build/libraries_sysmenu/acsign/ARM9/src/main.c new file mode 100644 index 00000000..d0d591b8 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/main.c @@ -0,0 +1,320 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------*/ +#include +#include + +#include "acsign.h" +#include "acmemory.h" + +/*---------------------------------------------------------------------------*/ +unsigned long binarray[ 1024 * 1024 * 2 / sizeof (unsigned long) ]; +unsigned long keyarray[ 1024 / sizeof (unsigned long) ]; +unsigned long sgnarray[ 1024 / sizeof (unsigned long) ]; +unsigned long bufferA[ ACSIGN_BUFFER / sizeof (unsigned long) ]; +unsigned long bufferB[ ACSIGN_BUFFER / sizeof (unsigned long) ]; + + + +/*--------------------------------------------------------------------------*/ +// ROMヘッダ +//---------------------------------------------------------------------- +typedef struct { + // + // 0x000 System Reserved + // + char title_name[12]; // Soft title name + u32 game_code; // Game code + + u16 maker_code; // Maker code + u8 machine_code; // Machine code + u8 rom_type; // Rom type + u8 rom_size; // Rom size + + u8 reserved_A[9]; // System Reserved A ( Set ALL 0 ) + u8 soft_version; // Soft version + + u8 comp_arm9_boot_area:1; // Compress arm9 boot area + u8 comp_arm7_boot_area:1; // Compress arm7 boot area + u8 inspectCard:1; // 検査カードフラグ + u8 disableClearMemoryPad:1; // IPL2メモリパッドクリア・ディセーブルフラグ + u8 :0; + + + // + // 0x020 for Static modules (Section:B) + // + // ARM9 + u32 main_rom_offset; // ROM offset + void* main_entry_address; // Entry point + void* main_ram_address; // RAM address + u32 main_size; // Module size + + // ARM7 + u32 sub_rom_offset; // ROM offset + void* sub_entry_address; // Entry point + void* sub_ram_address; // RAM address + u32 sub_size; // Module size + + // + // 0x040 for File Name Table[FNT] (Section:C) + // + u32 fnt_offset; // ROM offset + u32 fnt_size; // Table size + + // + // 0x048 for File Allocation Table[FAT] (Section:E) + // + u32 fat_offset; // ROM offset + u32 fat_size; // Table size + + // + // 0x050 for Overlay Tables[OVT] (Section:D) + // + // ARM9 + u32 main_ovt_offset; // ROM offset + u32 main_ovt_size; // Table size + + // ARM7 + u32 sub_ovt_offset; // ROM offset + u32 sub_ovt_size; // Table size + + // 0x060 for ROM control parameter + u8 reserved_A2[32]; + + // 0x080 - 0x0C0 System Reserved + u8 reserved_B[64]; // System Reserved B (Set 0) + + // 0x0C0 for NINTENDO logo data + u8 nintendo_logo[0x9c]; // NINTENDO logo data + u16 nintendo_logo_crc16; // CRC-16 + + // 0x15E ROM header CRC-16 + u16 header_crc16; // ROM header CRC-16 +} RomHeader; + + +/* V-blank callback */ +static void VBlankIntr(void) +{ + OS_SetIrqCheckFlag(OS_IE_V_BLANK); +} + + + + + +/*---------------------------------------------------------------------------* + Name: InitializeAllocateSystem + + Description: メインメモリ上のアリーナにてメモリ割当てシステムを初期化する。 + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +static void InitializeAllocateSystem(void) +{ + void* tempLo; + OSHeapHandle hh; + + // OS_Initは呼ばれているという前提 + tempLo = OS_InitAlloc( + OS_ARENA_MAIN , + OS_GetMainArenaLo() , + OS_GetMainArenaHi() , + 1 + ); + OS_SetArenaLo( + OS_ARENA_MAIN , + tempLo + ); + hh = OS_CreateHeap( + OS_ARENA_MAIN , + OS_GetMainArenaLo() , + OS_GetMainArenaHi() + ); + if( hh < 0 ) + { + OS_Panic("ARM9: Fail to create heap...\n"); + } + hh = OS_SetCurrentHeap( + OS_ARENA_MAIN , + hh + ); +} + + +// +static +void TestAC(char* iplfile, char* srlfile, char* sgnfile, FSFile* pfile ) +{ + RomHeader* pHeader; + const char* path; + BOOL fresult; + void* srl_ptr = 0; + long srl_len = 0; + void* key_ptr = 0; + long key_len = 0; + void* sgn_ptr = 0; + long sgn_len = 0; + + + if ( !pfile ) return ; + if ( !iplfile ) return ; + if ( !srlfile ) return ; + if ( !sgnfile ) return ; + + path = iplfile; + if ( (fresult = FS_OpenFile(pfile, path)) ) + { + key_len = FS_ReadFile( pfile, keyarray, sizeof keyarray ); + key_ptr = keyarray; + fresult = FS_CloseFile( pfile ); + } + if ( !fresult ) + OS_Printf("file read error! %s\n", path ); + + path = srlfile; + if ( (fresult = FS_OpenFile(pfile, path)) ) + { + srl_len = FS_ReadFile( pfile, binarray, sizeof binarray ); + srl_ptr = binarray; + fresult = FS_CloseFile( pfile ); + } + if ( !fresult ) + OS_Printf("file read error! %s\n", path ); + + path = sgnfile; //"/data/sgn0.bin"; // sgn + if ( (fresult = FS_OpenFile(pfile, path)) ) + { + sgn_len = FS_ReadFile( pfile, sgnarray, sizeof sgnarray ); + sgn_ptr = sgnarray; + fresult = FS_CloseFile( pfile ); + } + if ( !fresult ) + OS_Printf("file read error! %s\n", path ); + + // 認証 + if ( srl_ptr && srl_len && key_ptr && key_len && sgn_ptr && sgn_len ) + { + long nSerial = 0; + pHeader = (RomHeader*)binarray; + + MI_CpuFill8( bufferA, 0, sizeof bufferA ); + MI_CpuFill8( bufferB, 0, sizeof bufferB ); + #if 0 + HMAC/Digtal Signature + >char seg_id[2]; //->"ac"に固定 + >u16 version; //-> 1に固定 + >u8 auth_code[20]/digital_sign[128] + >long serial_number + >char title_name[12]; // RomHeader.title_name + >u32 game_code; // RomHeader.game_code + >u16 maker_code; // RomHeader.make_code + >u8 machine_code; // RomHeader.machine_code + #endif + ((unsigned char*)&nSerial)[0] = ((unsigned char*)sgn_ptr + 4 + 128)[0]; + ((unsigned char*)&nSerial)[1] = ((unsigned char*)sgn_ptr + 4 + 128)[1]; + ((unsigned char*)&nSerial)[2] = ((unsigned char*)sgn_ptr + 4 + 128)[2]; + ((unsigned char*)&nSerial)[3] = ((unsigned char*)sgn_ptr + 4 + 128)[3]; + + (void)ACSign_Decrypto( bufferA, + (char*)sgn_ptr + 4, // ファイル内の暗号化部分はへのオフセットをプラス + (char*)key_ptr + 16 ); // PC側でMODのみのファイルに対応すれば+16が不要 + + (void)ACSign_Digest( bufferB, + srl_ptr, + (char*)srl_ptr + pHeader->main_rom_offset, + pHeader->main_size, + (char*)srl_ptr + pHeader->sub_rom_offset, + pHeader->sub_size, + nSerial ); + + if ( ACSign_Compare( bufferA, bufferB ) ) + { + OS_Printf( "Authentication_Code test : success! [%12s %12s] \n", srlfile, sgnfile ); + } + else + { + OS_Printf( "Authentication_Code test : failure! [%12s %12s]\n", srlfile, sgnfile ); + } + + } + else + { + OS_Printf( "no test\n" ); + } + + OS_PrintServer(); +} + + +void NitroMain(void) +{ + FSFile file; + + + OS_InitPrintServer(); + OS_Init(); + OS_InitThread(); + InitializeAllocateSystem(); + + OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr); + (void)OS_EnableIrqMask(OS_IE_V_BLANK); + (void)OS_EnableIrqMask(OS_IE_FIFO_RECV); + (void)OS_EnableIrq(); + + if ( sizeof (int ) < sizeof ( long ) ) + OS_Printf( "sizeof (int ) != sizeof ( long )\n" ); + if ( sizeof ( RomHeader ) != 0x0160 ) + OS_Printf( "sizeof ( RomHeader ) != 0x0160\n" ); + + /* initialize file-system */ + FS_Init( (u32)MI_DMA_MAX_NUM ); /* use DMA-3 for FS */ + + /* always preload FS table for faster directory access. */ + { + u32 need_size = FS_GetTableSize(); + void *p_table = OS_Alloc(need_size); + SDK_ASSERT(p_table != NULL); + (void)FS_LoadTable(p_table, need_size); + } + + // ファイル読み込み + FS_InitFile(&file); + //TestAC( "/data/iplpub.bin", "/data/main.srl", "/data/sgn.bin", &file ); + + TestAC( "/data/iplpub.bin", "/data/main0.srl", "/data/sgn0.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main1.srl", "/data/sgn1.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main2.srl", "/data/sgn2.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main3.srl", "/data/sgn3.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main4.srl", "/data/sgn4.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main5.srl", "/data/sgn5.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main6.srl", "/data/sgn6.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main7.srl", "/data/sgn7.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main0.srl", "/data/sgn7.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main3.srl", "/data/sgn1.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main5.srl", "/data/sgn5.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main1.srl", "/data/sgn0.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main0.srl", "/data/sgn1.bin", &file ); + TestAC( "/data/iplpub.bin", "/data/main0.srl", "/data/sgn0.bin", &file ); + + OS_Terminate(); +} + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/md5.c b/build/libraries_sysmenu/acsign/ARM9/src/md5.c new file mode 100644 index 00000000..9b89e568 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/md5.c @@ -0,0 +1,412 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +#include "md5.h" + +/* Constants for MD5Transform routine. */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +static void MD5Transform(unsigned long [4], unsigned char [64]); +static void Encode(unsigned char *, unsigned long *, unsigned int); +static void Decode(unsigned long *, unsigned char *, unsigned int); +static void MD5_memcpy(unsigned char*, unsigned char*, unsigned int); +static void MD5_memset(unsigned char*, int, unsigned int); + +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (unsigned long)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (unsigned long)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (unsigned long)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (unsigned long)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init(context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update(context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +unsigned int inputLen; /* length of input block */ +{ + unsigned int i, index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((unsigned long)inputLen << 3)) < ((unsigned long)inputLen << 3)) + context->count[1]++; + context->count[1] += ((unsigned long)inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + MD5_memcpy((unsigned char*)&context->buffer[index], (unsigned char*)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy((unsigned char*)&context->buffer[index], (unsigned char*)&input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final(digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + /* Store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. */ + MD5_memset ((unsigned char*)context, 0, sizeof (*context)); +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +unsigned long state[4]; +unsigned char block[64]; +{ + unsigned long a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + MD5_memset ((unsigned char*)x, 0, sizeof (x)); +} + +/* Encodes input (unsigned long) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode(output, input, len) +unsigned char *output; +unsigned long *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j ] = (unsigned char)( input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (unsigned long). Assumes len is + a multiple of 4. + */ +static void Decode(output, input, len) +unsigned long *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((unsigned long)input[j]) | (((unsigned long)input[j+1]) << 8) | + (((unsigned long)input[j+2]) << 16) | (((unsigned long)input[j+3]) << 24); +} + +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy(output, input, len) +unsigned char* output; +unsigned char* input; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset(output, value, len) +unsigned char* output; +int value; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} + + + + +////////////////////////////////////////////////////////////////////////////// +#if defined( MD5_TEST ) + +#include + +char* samplearray[ 7 ] = +{ + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "1234567890" // x8 +}; + +char* resultarray[ 7 ] = +{ + "\xD4\x1D\x8C\xD9\x8F\x00\xB2\x04\xE9\x80\x09\x98\xEC\xF8\x42\x7E", + "\x0C\xC1\x75\xB9\xC0\xF1\xB6\xA8\x31\xC3\x99\xE2\x69\x77\x26\x61", + "\x90\x01\x50\x98\x3C\xD2\x4F\xB0\xD6\x96\x3F\x7D\x28\xE1\x7F\x72", + "\xF9\x6B\x69\x7D\x7C\xB7\x93\x8D\x52\x5A\x2F\x31\xAA\xF1\x61\xD0", + "\xC3\xFC\xD3\xD7\x61\x92\xE4\x00\x7D\xFB\x49\x6C\xCA\x67\xE1\x3B", + "\xD1\x74\xAB\x98\xD2\x77\xD9\xF5\xA5\x61\x1C\x2C\x9F\x41\x9D\x9F", + "\x57\xED\xF4\xA2\x2B\xE3\xC9\x55\xAC\x49\xDA\x2E\x21\x07\xB6\x7A" +}; + +int repeatarray[ 7 ] = +{ + 1, + 1, + 1, + 1, + 1, + 1, + 8 +}; + +int MD5Test( ) +{ + MD5_CTX context; + unsigned char digest[16]; + int i, j, error; + + error = 0; + for ( j = 0; j < 7; j++ ) + { + MD5Init(&context); + + for ( i = 0; i < repeatarray[j]; i++ ) + { + MD5Update (&context, + (unsigned char*)samplearray[j], + (unsigned int)strlen( samplearray[j]) ); + } + + MD5Final(digest, &context); + + error = memcmp( digest, resultarray[j], 16 ); + + if ( error ) + break; + } + + return error ? 0 : 1; +} + +#endif // MD5_TEST +////////////////////////////////////////////////////////////////////////////// diff --git a/build/libraries_sysmenu/acsign/ARM9/src/sha1.c b/build/libraries_sysmenu/acsign/ARM9/src/sha1.c new file mode 100644 index 00000000..e7f2a653 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/sha1.c @@ -0,0 +1,470 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * sha1.c + * + * Description: + * This file implements the Secure Hashing Algorithm 1 as + * defined in FIPS PUB 180-1 published April 17, 1995. + * + * The SHA-1, produces a 160-bit message digest for a given + * data stream. It should take about 2**n steps to find a + * message with the same digest as a given message and + * 2**(n/2) to find any two messages with the same digest, + * when n is the digest size in bits. Therefore, this + * algorithm can serve as a means of providing a + * "fingerprint" for a message. + * + * Portability Issues: + * SHA-1 is defined in terms of 32-bit "words". This code + * uses (included via "sha1.h" to define 32 and 8 + * bit unsigned integer types. If your C compiler does not + * support 32 bit unsigned integers, this code is not + * appropriate. + * + * Caveats: + * SHA-1 is designed to work with messages less than 2^64 bits + * long. Although SHA-1 allows a message digest to be generated + * for messages of any number of bits less than 2^64, this + * implementation only works with messages with a length that is + * a multiple of the size of an 8-bit character. + * + */ + +#include "sha1.h" + +/* + * Define the SHA1 circular left shift macro + */ +#define SHA1CircularShift(bits,word) \ + (((word) << (bits)) | ((word) >> (32-(bits)))) + +/* Local Function Prototyptes */ +void SHA1PadMessage(SHA1Context *); +void SHA1ProcessMessageBlock(SHA1Context *); + +/* + * SHA1Reset + * + * Description: + * This function will initialize the SHA1Context in preparation + * for computing a new SHA1 message digest. + * + * Parameters: + * context: [in/out] + * The context to reset. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Reset(SHA1Context *context) +{ + if (!context) + { + return shaNull; + } + + context->Length_Low = 0; + context->Length_High = 0; + context->Message_Block_Index = 0; + + context->Intermediate_Hash[0] = 0x67452301; + context->Intermediate_Hash[1] = 0xEFCDAB89; + context->Intermediate_Hash[2] = 0x98BADCFE; + context->Intermediate_Hash[3] = 0x10325476; + context->Intermediate_Hash[4] = 0xC3D2E1F0; + + context->Computed = 0; + context->Corrupted = 0; + + return shaSuccess; +} + +/* + * SHA1Result + * + * Description: + * This function will return the 160-bit message digest into the + * Message_Digest array provided by the caller. + * NOTE: The first octet of hash is stored in the 0th element, + * the last octet of hash in the 19th element. + * + * Parameters: + * context: [in/out] + * The context to use to calculate the SHA-1 hash. + * Message_Digest: [out] + * Where the digest is returned. + * + * Returns: + * sha Error Code. + * + */ +int SHA1Result( SHA1Context *context, + unsigned char Message_Digest[20]) +{ + int i; + + if (!context || !Message_Digest) + { + return shaNull; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + + if (!context->Computed) + { + SHA1PadMessage(context); + for(i=0; i<64; ++i) + { + /* message may be sensitive, clear it out */ + context->Message_Block[i] = 0; + } + context->Length_Low = 0; /* and clear length */ + context->Length_High = 0; + context->Computed = 1; + + } + + for(i = 0; i < 20; ++i) + { + Message_Digest[i] = (unsigned char) + (context->Intermediate_Hash[i>>2] + >> 8 * ( 3 - ( i & 0x03 ) )); + } + + return shaSuccess; +} + +/* + * SHA1Input + * + * Description: + * This function accepts an array of octets as the next portion + * of the message. + * + * Parameters: + * context: [in/out] + * The SHA context to update + * message_array: [in] + * An array of characters representing the next portion of + * the message. + * length: [in] + * The length of the message in message_array + * + * Returns: + * sha Error Code. + * + */ +int SHA1Input( SHA1Context *context, + const unsigned char *message_array, + unsigned int length) +{ + if (!length) + { + return shaSuccess; + } + + if (!context || !message_array) + { + return shaNull; + } + + if (context->Computed) + { + context->Corrupted = shaStateError; + + return shaStateError; + } + + if (context->Corrupted) + { + return context->Corrupted; + } + while(length-- && !context->Corrupted) + { + context->Message_Block[context->Message_Block_Index++] = + (unsigned char)(*message_array & 0xFF); + + context->Length_Low += 8; + if (context->Length_Low == 0) + { + context->Length_High++; + if (context->Length_High == 0) + { + /* Message is too long */ + context->Corrupted = 1; + } + } + + if (context->Message_Block_Index == 64) + { + SHA1ProcessMessageBlock(context); + } + + message_array++; + } + + return shaSuccess; +} + +/* + * SHA1ProcessMessageBlock + * + * Description: + * This function will process the next 512 bits of the message + * stored in the Message_Block array. + * + * Parameters: + * None. + * + * Returns: + * Nothing. + * + * Comments: + * + * Many of the variable names in this code, especially the + * single character names, were used because those were the + * names used in the publication. + * + * + */ +void SHA1ProcessMessageBlock(SHA1Context *context) +{ + const unsigned long K[] = { /* Constants defined in SHA-1 */ + 0x5A827999, + 0x6ED9EBA1, + 0x8F1BBCDC, + 0xCA62C1D6 + }; + int t; /* Loop counter */ + unsigned long temp; /* Temporary word value */ + unsigned long W[80]; /* Word sequence */ + unsigned long A, B, C, D, E; /* Word buffers */ + + /* + * Initialize the first 16 words in the array W + */ + for(t = 0; t < 16; t++) + { + W[t] = context->Message_Block[t * 4 ] << 24; + W[t] |= context->Message_Block[t * 4 + 1] << 16; + W[t] |= context->Message_Block[t * 4 + 2] << 8; + W[t] |= context->Message_Block[t * 4 + 3]; + } + + for(t = 16; t < 80; t++) + { + W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); + } + + A = context->Intermediate_Hash[0]; + B = context->Intermediate_Hash[1]; + C = context->Intermediate_Hash[2]; + D = context->Intermediate_Hash[3]; + E = context->Intermediate_Hash[4]; + + for(t = 0; t < 20; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | ((~B) & D)) + E + W[t] + K[0]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + + B = A; + A = temp; + } + + for(t = 20; t < 40; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 40; t < 60; t++) + { + temp = SHA1CircularShift(5,A) + + ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + for(t = 60; t < 80; t++) + { + temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; + E = D; + D = C; + C = SHA1CircularShift(30,B); + B = A; + A = temp; + } + + context->Intermediate_Hash[0] += A; + context->Intermediate_Hash[1] += B; + context->Intermediate_Hash[2] += C; + context->Intermediate_Hash[3] += D; + context->Intermediate_Hash[4] += E; + + context->Message_Block_Index = 0; +} + +/* + * SHA1PadMessage + * + + * Description: + * According to the standard, the message must be padded to an even + * 512 bits. The first padding bit must be a '1'. The last 64 + * bits represent the length of the original message. All bits in + * between should be 0. This function will pad the message + * according to those rules by filling the Message_Block array + * accordingly. It will also call the ProcessMessageBlock function + * provided appropriately. When it returns, it can be assumed that + * the message digest has been computed. + * + * Parameters: + * context: [in/out] + * The context to pad + * ProcessMessageBlock: [in] + * The appropriate SHA*ProcessMessageBlock function + * Returns: + * Nothing. + * + */ + +void SHA1PadMessage(SHA1Context *context) +{ + /* + * Check to see if the current message block is too small to hold + * the initial padding bits and length. If so, we will pad the + * block, process it, and then continue padding into a second + * block. + */ + if (context->Message_Block_Index > 55) + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 64) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + + SHA1ProcessMessageBlock(context); + + while(context->Message_Block_Index < 56) + { + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + else + { + context->Message_Block[context->Message_Block_Index++] = 0x80; + while(context->Message_Block_Index < 56) + { + + context->Message_Block[context->Message_Block_Index++] = 0; + } + } + + /* + * Store the message length as the last 8 octets + */ + context->Message_Block[56] = (unsigned char)(context->Length_High >> 24); + context->Message_Block[57] = (unsigned char)(context->Length_High >> 16); + context->Message_Block[58] = (unsigned char)(context->Length_High >> 8); + context->Message_Block[59] = (unsigned char)(context->Length_High ); + context->Message_Block[60] = (unsigned char)(context->Length_Low >> 24); + context->Message_Block[61] = (unsigned char)(context->Length_Low >> 16); + context->Message_Block[62] = (unsigned char)(context->Length_Low >> 8); + context->Message_Block[63] = (unsigned char)(context->Length_Low ); + + SHA1ProcessMessageBlock(context); +} + + + + +////////////////////////////////////////////////////////////////////////////// +#if defined( SHA1_TEST ) + +#include "string.h" + +char* samplearray[4] = +{ + "abc", + "abcdbcdecdefdefgefghfghighijhi" "jkijkljklmklmnlmnomnopnopq", + "a", + "01234567012345670123456701234567" "01234567012345670123456701234567" +}; + +char* resultarray[ 4 ] = +{ + "\xA9\x99\x3E\x36\x47\x06\x81\x6A\xBA\x3E\x25\x71\x78\x50\xC2\x6C\x9C\xD0\xD8\x9D", + "\x84\x98\x3E\x44\x1C\x3B\xD2\x6E\xBA\xAE\x4A\xA1\xF9\x51\x29\xE5\xE5\x46\x70\xF1", + "\x34\xAA\x97\x3C\xD4\xC4\xDA\xA4\xF6\x1E\xEB\x2B\xDB\xAD\x27\x31\x65\x34\x01\x6F", + "\xDE\xA3\x56\xA2\xCD\xDD\x90\xC7\xA7\xEC\xED\xC5\xEB\xB5\x63\x93\x4F\x46\x04\x52" +}; + +long int repeatcount[4] = { 1, 1, 1000000, 10 }; + +int SHA1Test( ) +{ + SHA1Context sha; + unsigned char digest[20]; + int i, j, error; + + error = 0; + for ( j = 0; j < 4; ++j ) + { + if ( !error ) + error = SHA1Reset(&sha); + + for(i = 0; i < repeatcount[j]; ++i) + { + if ( !error ) + error = SHA1Input(&sha, + (const unsigned char *)samplearray[j], + (unsigned int)strlen(samplearray[j])); + } + + if ( !error ) + error = SHA1Result(&sha, digest); + + if ( !error ) + error = memcmp( digest, resultarray[j], 20 ); + + if (error) + break; + } + + return error ? 0 : 1; +} + +#endif // SHA1_TEST +////////////////////////////////////////////////////////////////////////////// + diff --git a/build/libraries_sysmenu/acsign/ARM9/src/sha1dgst.c b/build/libraries_sysmenu/acsign/ARM9/src/sha1dgst.c new file mode 100644 index 00000000..4742b605 --- /dev/null +++ b/build/libraries_sysmenu/acsign/ARM9/src/sha1dgst.c @@ -0,0 +1,786 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +/* + * Copyright (C) 1998-2002 RSA Security Inc. All rights reserved. + * + * This work contains proprietary information of RSA Security. + * Distribution is limited to authorized licensees of RSA + * Security. Any unauthorized reproduction, distribution or + * modification of this work is strictly prohibited. + * + */ + +////!!!!#include "r_com.h" + +#ifndef NO_SHA1 +#undef SHA_0 +#define SHA_1 +#include "sha.h" +#include "sha_locl.h" +#ifdef CPU_X86 +#include "r_cpuid.h" +#endif /* NO_SHA1 */ + +const char *SHA1_version="SHA1 part of RCOM 2.3.0 11-Jun-2002"; + +/* Implemented from SHA-1 document - The Secure Hash Algorithm + */ + +#define INIT_DATA_h0 (SHA_LONG)0x67452301L +#define INIT_DATA_h1 (SHA_LONG)0xefcdab89L +#define INIT_DATA_h2 (SHA_LONG)0x98badcfeL +#define INIT_DATA_h3 (SHA_LONG)0x10325476L +#define INIT_DATA_h4 (SHA_LONG)0xc3d2e1f0L + +#define K_00_19 (SHA_LONG)0x5a827999L +#define K_20_39 (SHA_LONG)0x6ed9eba1L +#define K_40_59 (SHA_LONG)0x8f1bbcdcL +#define K_60_79 (SHA_LONG)0xca62c1d6L + +#ifndef CCONV +#define CCONV +#endif + +#ifndef PRE_CCONV +#define PRE_CCONV +#endif + +/* Endian flags are only used for the assembler code */ +#ifndef OPT_SHA1_ASM +#undef L_ENDIAN +#undef B_ENDIAN +#endif + + +#ifdef OPT_SHA1_ASM + +#ifdef CPU_X86 +void CCONV sha1_block_586(SHA_CTX *c,const unsigned char *p, int num); +void CCONV sha1_block_686(SHA_CTX *c,const unsigned char *p, int num); +void CCONV sha1_block_786(SHA_CTX *c,const unsigned char *p, int num); +unsigned long r_cpuid(unsigned long *,char **name); + +#elif OPT_SHA1_ARM +PRE_CCONV void CCONV sha1_arm4_fast(SHA_CTX *c, const unsigned char *p, + int num); +PRE_CCONV void CCONV sha1_arm4_small(SHA_CTX *c, const unsigned char *p, + int num); +#else +void CCONV sha1_block_asm(SHA_CTX *c, const unsigned char *p, int num); +#endif /* CPU_X86 */ + +#else /* OPT_SHA1_ASM */ + +void sha1_block(SHA_CTX *c, SHA_LONG *p, int num); + +#endif /* OPT_SHA1_ASM */ + +#undef M_c2nl +#undef M_p_c2nl +#undef M_c2nl_p +#undef M_p_c2nl_p +#undef M_nl2c + +#if defined(L_ENDIAN) && !defined(OPT_SHA1_ASM) +# define M_c2nl c2l +# define M_p_c2nl p_c2l +# define M_c2nl_p c2l_p +# define M_p_c2nl_p p_c2l_p +# define M_nl2c l2c +#else +# define M_c2nl c2nl +# define M_p_c2nl p_c2nl +# define M_c2nl_p c2nl_p +# define M_p_c2nl_p p_c2nl_p +# define M_nl2c nl2c +#endif /* defined(L_ENDIAN) && !defined(OPT_SHA1_ASM) */ + +int SHA1_Setup(c,sha_block) +SHA_CTX *c; +void (PRE_CCONV CCONV *sha_block)(SHA_CTX *c, const unsigned char *W, int num); + { + c->sha_block=sha_block; + return(0); + } + +void SHA1_Init(c) +SHA_CTX *c; + { + c->h0=INIT_DATA_h0; + c->h1=INIT_DATA_h1; + c->h2=INIT_DATA_h2; + c->h3=INIT_DATA_h3; + c->h4=INIT_DATA_h4; + c->Nl=0; + c->Nh=0; + c->num=0; + +#ifdef OPT_SHA1_ASM +#ifdef CPU_X86 + if (c->sha_block == NULL) + { + unsigned long cpu,attrib; + + /* We should make the methods loadable */ + cpu=r_cpuid(&attrib,NULL); + if (attrib & R_CPU_X86_HAS_PENTIUM_IV) + c->sha_block=sha1_block_786; + else if (attrib & R_CPU_X86_HAS_PENTIUM_PRO) + c->sha_block=sha1_block_686; + else + c->sha_block=sha1_block_586; + } +#else /* CPU_X86 */ + +#ifndef OPT_SHA1_ARM + c->sha_block=sha1_block_asm; +#else /* OPT_SHA1_ARM */ + if (c->sha_block == NULL) + { +#ifdef SMALL_CODE_SIZE + c->sha_block = sha1_arm4_small; +#else /* SMALL_CODE_SIZE */ + c->sha_block = sha1_arm4_fast; +#endif /* SMALL_CODE_SIZE */ + } +#endif /* OPT_SHA1_ARM */ +#endif /* CPU_X86 */ + +#else /* OPT_SHA1_ASM */ + c->sha_block=(void (PRE_CCONV CCONV *)(SHA_CTX *, const unsigned char *, int))sha1_block; +#endif /* OPT_SHA1_ASM */ + } + +#ifdef OPT_SHA1_ASM + +void SHA1_Update(c, data, len) +SHA_CTX *c; +const register unsigned char *data; +unsigned long len; + { + int i; + unsigned int alignment; + unsigned long l; + unsigned char *cp=(unsigned char *)c->data; + + if (len == 0) return; + + l=(c->Nl+(len<<3))&0xffffffffL; + if (l < c->Nl) /* overflow */ + c->Nh++; + c->Nh+=(len>>29); + c->Nl=l; + + if (c->num != 0) + { + if (c->num+len >= SHA_CBLOCK) + { + i=SHA_CBLOCK-c->num; + Memcpy(&(cp[c->num]),data,i); + len-=i; + data+=i; + + c->sha_block(c,cp,64); + c->num=0; + /* drop through and do the rest */ + } + else + { + Memcpy(&(cp[c->num]),data,len); + c->num+=(int)len; + return; + } + } + /* we now can process the input data in blocks of SHA_CBLOCK + * chars and save the leftovers to c->data. */ + if (len >= SHA_CBLOCK) + { + i=(int)(len& ~63); + len-=i; + + /* + * Check to see if the input data lies on a word boundary. + * Do this as the ASM relies on input data being word aligned. + */ + alignment = (((unsigned int)data) & (sizeof(unsigned int)-1)) + & 0x03; + if (alignment == 0) + { + c->sha_block(c,data,i); + data+=i; + } + else + { + do { + Memcpy(cp, data, SHA_CBLOCK); + data += SHA_CBLOCK; + c->sha_block(c, cp, SHA_CBLOCK); + i -= SHA_CBLOCK; + } while (i > 0); + } + } + c->num=len; + if (len) + { + Memcpy(cp,data,(int)len); + } + } + +void SHA1_Transform(c,b) +SHA_CTX *c; +const unsigned char *b; + { + c->sha_block(c,b,64); + } + +void SHA1_Final(md, c) +unsigned char *md; +SHA_CTX *c; + { + register int i,j; + register SHA_LONG l; + register SHA_LONG *p; + const static unsigned char end[4]={0x80,0x00,0x00,0x00}; + unsigned char *cp= (unsigned char *)end; + unsigned char *pc; + + /* c->num should definitly have room for at least one more byte. */ + p=c->data; + j=c->num; + i=j>>2; + +#ifdef PURIFY + /* PURIFY */ + /* we reference uninitialised data but don't keep the result + * which purify complains about ... and we don't want to have + * to come back here to find a non-existant problem later + */ + + /* purify often complains about the following line as an + * Uninitialized Memory Read. While this can be true, the + * following p_c2l macro will reset l when that case is true. + * This is because j&0x03 contains the number of 'valid' bytes + * already in p[i]. If and only if j&0x03 == 0, the UMR will + * occur but this is also the only time p_c2l will do + * l= *(cp++) instead of l|= *(cp++) + */ + if ((j&0x03) == 0) p[i]=0; +#endif + + pc=(unsigned char *)c->data; + pc[j]=0x80; + for (j++; j & 0x03; j++) + pc[j]=0; + i++; + /* i is the next 'undefined word' */ + if (c->num >= SHA_LAST_BLOCK) + { + for (; isha_block(c,(unsigned char *)p,64); + i=0; + } + for (; i<(SHA_LBLOCK-2); i++) + p[i]=0; + + l=c->Nl; + pc[63]=(unsigned char)((l )&0xff); + pc[62]=(unsigned char)((l>> 8)&0xff); + pc[61]=(unsigned char)((l>>16)&0xff); + pc[60]=(unsigned char)((l>>24)&0xff); + l=c->Nh; + pc[59]=(unsigned char)((l )&0xff); + pc[58]=(unsigned char)((l>> 8)&0xff); + pc[57]=(unsigned char)((l>>16)&0xff); + pc[56]=(unsigned char)((l>>24)&0xff); + + c->sha_block(c,(unsigned char *)p,64); + cp=md; + l=c->h0; nl2c(l,cp); + l=c->h1; nl2c(l,cp); + l=c->h2; nl2c(l,cp); + l=c->h3; nl2c(l,cp); + l=c->h4; nl2c(l,cp); + + /* clear stuff, sha1_block_asm may be leaving some stuff on the stack + * but I'm not worried :-) */ + c->num=0; +/* Memset((char *)&c,0,sizeof(c));*/ + } + +#else /* !OPT_SHA1_ASM */ + +void SHA1_Update(c, data, len) +SHA_CTX *c; +const register unsigned char *data; +unsigned long len; + { + register SHA_LONG *p; + int ew,ec,sw,sc; + SHA_LONG l; + + if (len == 0) return; + + l=(c->Nl+(len<<3))&0xffffffffL; + if (l < c->Nl) /* overflow */ + c->Nh++; + c->Nh+=(len>>29); + c->Nl=l; + + if (c->num != 0) + { + p=c->data; + sw=c->num>>2; + sc=c->num&0x03; + + if ((c->num+len) >= SHA_CBLOCK) + { + l= p[sw]; + M_p_c2nl(data,l,sc); + p[sw++]=l; + for (; swnum); + + c->sha_block(c,(unsigned char *)p,64); + c->num=0; + /* drop through and do the rest */ + } + else + { + c->num+=(int)len; + if ((sc+len) < 4) /* ugly, add char's to a word */ + { + l= p[sw]; + M_p_c2nl_p(data,l,sc,len); + p[sw]=l; + } + else + { + ew=(c->num>>2); + ec=(c->num&0x03); + l= p[sw]; + M_p_c2nl(data,l,sc); + p[sw++]=l; + for (; sw < ew; sw++) + { M_c2nl(data,l); p[sw]=l; } + if (ec) + { + M_c2nl_p(data,l,ec); + p[sw]=l; + } + } + return; + } + } + /* We can only do the following code for assember, the reason + * being that the sha1_block 'C' version changes the values + * in the 'data' array. The assember code avoids this and + * copies it to a local array. I should be able to do this for + * the C version as well.... + */ +#if defined(B_ENDIAN) || defined(OPT_SHA1_ASM) + if ((((unsigned long)data)%sizeof(SHA_LONG)) == 0) + { + sw=len/SHA_CBLOCK; + if (sw) + { + sw*=SHA_CBLOCK; + c->sha_block(c,(SHA_LONG *)data,sw); + data+=sw; + len-=sw; + } + } +#endif + /* we now can process the input data in blocks of SHA_CBLOCK + * chars and save the leftovers to c->data. */ + p=c->data; + while (len >= SHA_CBLOCK) + { +#if defined(B_ENDIAN) || defined(L_ENDIAN) + if (p != (SHA_LONG *)data) + Memcpy(p,data,SHA_CBLOCK); + data+=SHA_CBLOCK; +# ifdef L_ENDIAN +# ifndef OPT_SHA1_ASM /* Will not happen */ + for (sw=(SHA_LBLOCK/4); sw; sw--) + { + Endian_Reverse32(p[0]); + Endian_Reverse32(p[1]); + Endian_Reverse32(p[2]); + Endian_Reverse32(p[3]); + p+=4; + } + p=c->data; +# endif +# endif +#else + for (sw=(SHA_BLOCK/4); sw; sw--) + { + M_c2nl(data,l); *(p++)=l; + M_c2nl(data,l); *(p++)=l; + M_c2nl(data,l); *(p++)=l; + M_c2nl(data,l); *(p++)=l; + } + p=c->data; +#endif + c->sha_block(c,(unsigned char *)p,64); + len-=SHA_CBLOCK; + } + ec=(int)len; + c->num=ec; + ew=(ec>>2); + ec&=0x03; + + for (sw=0; sw < ew; sw++) + { M_c2nl(data,l); p[sw]=l; } + M_c2nl_p(data,l,ec); + p[sw]=l; + } + +void SHA1_Transform(c,b) +SHA_CTX *c; +const unsigned char *b; + { + SHA_LONG p[16]; +#ifndef B_ENDIAN + SHA_LONG *q; + int i; +#endif + +#if defined(B_ENDIAN) || defined(L_ENDIAN) + Memcpy(p,b,64); +#ifdef L_ENDIAN + q=p; + for (i=(SHA_LBLOCK/4); i; i--) + { + Endian_Reverse32(q[0]); + Endian_Reverse32(q[1]); + Endian_Reverse32(q[2]); + Endian_Reverse32(q[3]); + q+=4; + } +#endif +#else + q=p; + for (i=(SHA_LBLOCK/4); i; i--) + { + SHA_LONG l; + c2nl(b,l); *(q++)=l; + c2nl(b,l); *(q++)=l; + c2nl(b,l); *(q++)=l; + c2nl(b,l); *(q++)=l; + } +#endif + c->sha_block(c,(unsigned char *)p,64); + } + + +void sha1_block(c, W, num) +SHA_CTX *c; +SHA_LONG *W; +int num; + { +#ifndef SMALL_CODE_SIZE + register SHA_LONG A,B,C,D,E,T; + SHA_LONG X[16]; + + A=c->h0; + B=c->h1; + C=c->h2; + D=c->h3; + E=c->h4; + + for (;;) + { + BODY_00_15( 0,A,B,C,D,E,T,W); + BODY_00_15( 1,T,A,B,C,D,E,W); + BODY_00_15( 2,E,T,A,B,C,D,W); + BODY_00_15( 3,D,E,T,A,B,C,W); + BODY_00_15( 4,C,D,E,T,A,B,W); + BODY_00_15( 5,B,C,D,E,T,A,W); + BODY_00_15( 6,A,B,C,D,E,T,W); + BODY_00_15( 7,T,A,B,C,D,E,W); + BODY_00_15( 8,E,T,A,B,C,D,W); + BODY_00_15( 9,D,E,T,A,B,C,W); + BODY_00_15(10,C,D,E,T,A,B,W); + BODY_00_15(11,B,C,D,E,T,A,W); + BODY_00_15(12,A,B,C,D,E,T,W); + BODY_00_15(13,T,A,B,C,D,E,W); + BODY_00_15(14,E,T,A,B,C,D,W); + BODY_00_15(15,D,E,T,A,B,C,W); + BODY_16_19(16,C,D,E,T,A,B,W,W,W,W); + BODY_16_19(17,B,C,D,E,T,A,W,W,W,W); + BODY_16_19(18,A,B,C,D,E,T,W,W,W,W); + BODY_16_19(19,T,A,B,C,D,E,W,W,W,X); + + BODY_20_31(20,E,T,A,B,C,D,W,W,W,X); + BODY_20_31(21,D,E,T,A,B,C,W,W,W,X); + BODY_20_31(22,C,D,E,T,A,B,W,W,W,X); + BODY_20_31(23,B,C,D,E,T,A,W,W,W,X); + BODY_20_31(24,A,B,C,D,E,T,W,W,X,X); + BODY_20_31(25,T,A,B,C,D,E,W,W,X,X); + BODY_20_31(26,E,T,A,B,C,D,W,W,X,X); + BODY_20_31(27,D,E,T,A,B,C,W,W,X,X); + BODY_20_31(28,C,D,E,T,A,B,W,W,X,X); + BODY_20_31(29,B,C,D,E,T,A,W,W,X,X); + BODY_20_31(30,A,B,C,D,E,T,W,X,X,X); + BODY_20_31(31,T,A,B,C,D,E,W,X,X,X); + BODY_32_39(32,E,T,A,B,C,D,X); + BODY_32_39(33,D,E,T,A,B,C,X); + BODY_32_39(34,C,D,E,T,A,B,X); + BODY_32_39(35,B,C,D,E,T,A,X); + BODY_32_39(36,A,B,C,D,E,T,X); + BODY_32_39(37,T,A,B,C,D,E,X); + BODY_32_39(38,E,T,A,B,C,D,X); + BODY_32_39(39,D,E,T,A,B,C,X); + + BODY_40_59(40,C,D,E,T,A,B,X); + BODY_40_59(41,B,C,D,E,T,A,X); + BODY_40_59(42,A,B,C,D,E,T,X); + BODY_40_59(43,T,A,B,C,D,E,X); + BODY_40_59(44,E,T,A,B,C,D,X); + BODY_40_59(45,D,E,T,A,B,C,X); + BODY_40_59(46,C,D,E,T,A,B,X); + BODY_40_59(47,B,C,D,E,T,A,X); + BODY_40_59(48,A,B,C,D,E,T,X); + BODY_40_59(49,T,A,B,C,D,E,X); + BODY_40_59(50,E,T,A,B,C,D,X); + BODY_40_59(51,D,E,T,A,B,C,X); + BODY_40_59(52,C,D,E,T,A,B,X); + BODY_40_59(53,B,C,D,E,T,A,X); + BODY_40_59(54,A,B,C,D,E,T,X); + BODY_40_59(55,T,A,B,C,D,E,X); + BODY_40_59(56,E,T,A,B,C,D,X); + BODY_40_59(57,D,E,T,A,B,C,X); + BODY_40_59(58,C,D,E,T,A,B,X); + BODY_40_59(59,B,C,D,E,T,A,X); + + BODY_60_79(60,A,B,C,D,E,T,X); + BODY_60_79(61,T,A,B,C,D,E,X); + BODY_60_79(62,E,T,A,B,C,D,X); + BODY_60_79(63,D,E,T,A,B,C,X); + BODY_60_79(64,C,D,E,T,A,B,X); + BODY_60_79(65,B,C,D,E,T,A,X); + BODY_60_79(66,A,B,C,D,E,T,X); + BODY_60_79(67,T,A,B,C,D,E,X); + BODY_60_79(68,E,T,A,B,C,D,X); + BODY_60_79(69,D,E,T,A,B,C,X); + BODY_60_79(70,C,D,E,T,A,B,X); + BODY_60_79(71,B,C,D,E,T,A,X); + BODY_60_79(72,A,B,C,D,E,T,X); + BODY_60_79(73,T,A,B,C,D,E,X); + BODY_60_79(74,E,T,A,B,C,D,X); + BODY_60_79(75,D,E,T,A,B,C,X); + BODY_60_79(76,C,D,E,T,A,B,X); + BODY_60_79(77,B,C,D,E,T,A,X); + BODY_60_79(78,A,B,C,D,E,T,X); + BODY_60_79(79,T,A,B,C,D,E,X); + + c->h0=(c->h0+E)&0xffffffffL; + c->h1=(c->h1+T)&0xffffffffL; + c->h2=(c->h2+A)&0xffffffffL; + c->h3=(c->h3+B)&0xffffffffL; + c->h4=(c->h4+C)&0xffffffffL; + + num-=64; + if (num <= 0) break; + + A=c->h0; + B=c->h1; + C=c->h2; + D=c->h3; + E=c->h4; + + W+=16; + } +#else /* SMALL_CODE_SIZE */ + SHA_LONG A,B,C,D,E,T; + SHA_LONG X[16]; + SHA_LONG *a1,*a2,*a3; + + A=c->h0; + B=c->h1; + C=c->h2; + D=c->h3; + E=c->h4; + + for (;;) + { + int i; + + for (i=0; i<16; i++) + { + BODY_00_15(i,A,B,C,D,E,T,W); + E=D; D=C; C=B; B=A; A=T; + } + + a1=W; + for (i=16; i<20; i++) + { + if (i == 19) a1=X; + BODY_16_19(i,A,B,C,D,E,T,W,W,W,a1); + E=D; D=C; C=B; B=A; A=T; + } + + a1=a2=a3=W; + for (i=20; i<40; i++) + { + if (i == 24) a3=X; + if (i == 30) a2=X; + if (i == 32) a1=X; + BODY_20_31(i,A,B,C,D,E,T,a1,a2,a3,X); + E=D; D=C; C=B; B=A; A=T; + } + + for (i=40; i<60; i++) + { + BODY_40_59(i,A,B,C,D,E,T,X); + E=D; D=C; C=B; B=A; A=T; + } + + for (i=60; i<80; i++) + { + BODY_60_79(i,A,B,C,D,E,T,X); + E=D; D=C; C=B; B=A; A=T; + } + + c->h0=(c->h0+A)&0xffffffffL; + c->h1=(c->h1+B)&0xffffffffL; + c->h2=(c->h2+C)&0xffffffffL; + c->h3=(c->h3+D)&0xffffffffL; + c->h4=(c->h4+E)&0xffffffffL; + + num-=64; + if (num <= 0) break; + + A=c->h0; + B=c->h1; + C=c->h2; + D=c->h3; + E=c->h4; + + W+=16; + } +#endif /* SMALL_CODE_SIZE */ + } + +void SHA1_Final(md, c) +unsigned char *md; +SHA_CTX *c; + { + register int i,j; + register SHA_LONG l; + register SHA_LONG *p; + const static unsigned char end[4]={0x80,0x00,0x00,0x00}; + unsigned char *cp= (unsigned char *)end; + + /* c->num should definitly have room for at least one more byte. */ + p=c->data; + j=c->num; + i=j>>2; + +#ifdef PURIFY + /* PURIFY */ + /* we reference uninitialised data but don't keep the result + * which purify complains about ... and we don't want to have + * to come back here to find a non-existant problem later + */ + + /* purify often complains about the following line as an + * Uninitialized Memory Read. While this can be true, the + * following p_c2l macro will reset l when that case is true. + * This is because j&0x03 contains the number of 'valid' bytes + * already in p[i]. If and only if j&0x03 == 0, the UMR will + * occur but this is also the only time p_c2l will do + * l= *(cp++) instead of l|= *(cp++) + */ + if ((j&0x03) == 0) p[i]=0; +#endif + + l=p[i]; + M_p_c2nl(cp,l,j&0x03); + p[i]=l; + i++; + /* i is the next 'undefined word' */ + if (c->num >= SHA_LAST_BLOCK) + { + for (; isha_block(c,(unsigned char *)p,64); + i=0; + } + for (; i<(SHA_LBLOCK-2); i++) + p[i]=0; + p[SHA_LBLOCK-2]=c->Nh; + p[SHA_LBLOCK-1]=c->Nl; +#if defined(L_ENDIAN) + Endian_Reverse32(p[SHA_LBLOCK-2]); + Endian_Reverse32(p[SHA_LBLOCK-1]); +#endif + c->sha_block(c,(unsigned char *)p,64); + cp=md; + l=c->h0; nl2c(l,cp); + l=c->h1; nl2c(l,cp); + l=c->h2; nl2c(l,cp); + l=c->h3; nl2c(l,cp); + l=c->h4; nl2c(l,cp); + + /* clear stuff, sha1_block may be leaving some stuff on the stack + * but I'm not worried :-) */ + c->num=0; +/* Memset((char *)&c,0,sizeof(c));*/ + } +#endif + +#if 0 +int pr(ctx) +SHA_CTX *ctx; + { + int i,j; + unsigned char *p=(unsigned char *)(ctx->data); + + fprintf(stderr,"num = %08X%08X\n",ctx->Nh,ctx->Nl); + fprintf(stderr," %08X %08X %08X %08X %08X\n", + ctx->h0,ctx->h1,ctx->h2,ctx->h3,ctx->h4); + fprintf(stderr,"bufnum = %d\n",ctx->num); + fprintf(stderr," "); + for (j=0; j<64; j+=16) + { + for (i=0; i<16; i++) + { +/* + if ((i+j) >= ctx->num) + fprintf(stderr,"--"); + else +*/ + fprintf(stderr,"%02X",p[i+j]); + } + if ((j+16) >=64) + fprintf(stderr,"\n"); + else + fprintf(stderr,"\n "); + } + } + +#endif + +#endif /* NO_SHA1 */ diff --git a/build/libraries_sysmenu/acsign/Makefile b/build/libraries_sysmenu/acsign/Makefile new file mode 100644 index 00000000..f337ebc1 --- /dev/null +++ b/build/libraries_sysmenu/acsign/Makefile @@ -0,0 +1,29 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-09-27#$ +# $Rev: 1203 $ +# $Author: yada $ +#---------------------------------------------------------------------------- + +SUBDIRS = ARM9 + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + +#===== End of Makefile ===== diff --git a/build/libraries_sysmenu/mb_loader/ARM7/Makefile b/build/libraries_sysmenu/mb_loader/ARM7/Makefile new file mode 100644 index 00000000..29851ff4 --- /dev/null +++ b/build/libraries_sysmenu/mb_loader/ARM7/Makefile @@ -0,0 +1,52 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-09-27#$ +# $Rev: 1203 $ +# $Author: yada $ +#---------------------------------------------------------------------------- + +SUBDIRS = + +#---------------------------------------------------------------------------- +TARGET_PLATFORM = TWL +TWL_ARCHGEN = LIMITED +TWL_PROC = ARM7 + +#---------------------------------------------------------------------------- + +SRCDIR = ../common/src + +INCDIR = ../common/include \ + $(TWLSDK_ROOT)/build/libraries/mb/common/include + + +SRCS = mb_loader.c + +TARGET_LIB = libmbloader_sp$(TWL_LIBSUFFIX).a + + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(SYSMENU_INSTALL_LIBDIR) + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + + +#===== End of Makefile ===== + diff --git a/build/libraries_sysmenu/mb_loader/ARM9/Makefile b/build/libraries_sysmenu/mb_loader/ARM9/Makefile new file mode 100644 index 00000000..1a1a806f --- /dev/null +++ b/build/libraries_sysmenu/mb_loader/ARM9/Makefile @@ -0,0 +1,51 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-09-27#$ +# $Rev: 1203 $ +# $Author: yada $ +#---------------------------------------------------------------------------- + +SUBDIRS = + +#---------------------------------------------------------------------------- +TARGET_PLATFORM = TWL +TWL_ARCHGEN = LIMITED +TWL_PROC = ARM9 + +#---------------------------------------------------------------------------- + +SRCDIR = ../common/src + +INCDIR = ../common/include \ + $(TWLSDK_ROOT)/build/libraries/mb/common/include + +SRCS = mb_loader.c + +TARGET_LIB = libmbloader$(TWL_LIBSUFFIX).a + + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(SYSMENU_INSTALL_LIBDIR) + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + + +#===== End of Makefile ===== + diff --git a/build/libraries_sysmenu/mb_loader/Makefile b/build/libraries_sysmenu/mb_loader/Makefile new file mode 100644 index 00000000..c1ae0af0 --- /dev/null +++ b/build/libraries_sysmenu/mb_loader/Makefile @@ -0,0 +1,29 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-09-27#$ +# $Rev: 1203 $ +# $Author: yada $ +#---------------------------------------------------------------------------- + +SUBDIRS = ARM7 ARM9 + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + +#===== End of Makefile ===== diff --git a/build/libraries_sysmenu/mb_loader/common/src/mb_loader.c b/build/libraries_sysmenu/mb_loader/common/src/mb_loader.c new file mode 100644 index 00000000..5289b5c7 --- /dev/null +++ b/build/libraries_sysmenu/mb_loader/common/src/mb_loader.c @@ -0,0 +1,312 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: mb_loader.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include + +#if defined(SDK_ARM7) +#include +#else +#ifdef SDK_SMALL_BUILD +#include "SYSM_work.h" +#endif +#endif + + +#include // twl/mb.hがない。 +#include +#include + +// -------------------------------------------------------------------------- + +// Download情報のサイズ + +#define MB_OVT_MAX_SIZE MB_COMM_BLOCK_SIZE // OVTの最大サイズ(Blockサイズを最大サイズとする) + +/*----------------------------------------------------------------------------*/ +#define MB_TRIGGER_SIGNAL_TO_ARM7 (0x00000001) + +/*----------------------------------------------------------------------------*/ +static void MIm_CpuClear32( register u32 data, register void *destp, register u32 size ); +static void MIm_CpuClear32( register u32 data, register void *destp, register u32 size ); +static void LOADERi_LocateAllSegments( MBDownloadFileInfo *mdfi ); +static void MBi_SearchAndLocateSegmentInfo( MBDownloadFileInfo *mdfi, u16 processor ); +static void LOADERi_Jump(void); +static void MBi_fifo_callback_arm7(PXIFifoTag tag, u32 msg_adr, BOOL err); + +/*----------------------------------------------------------------------------*/ +static MB_LoaderCallback loader_precallback = NULL; + +/*----------------------------------------------------------------------------*/ + + +#if defined(SDK_ARM7) + +/*---------------------------------------------------------------------------* + Name: MIm_CpuCopy32 + + Description: ローダー用CpuCopy + + Arguments: srcp, destp, size + + Returns: void + *---------------------------------------------------------------------------*/ + +#include + +asm void MIm_CpuCopy32( register const void *srcp, register void *destp, register u32 size ) +{ + add r12, r1, r2 // r12: destEndp = destp + size + +@30: + cmp r1, r12 // while (destp < destEndp) + ldmltia r0!, {r2} // *((vu32 *)(destp)++) = *((vu32 *)(srcp)++) + stmltia r1!, {r2} + blt @30 + + bx lr +} + +#ifndef SDK_SMALL_BUILD +static asm void MIm_CpuClear32( register u32 data, register void *destp, register u32 size ) +{ + add r12, r1, r2 // r12: destEndp = destp + size + +@20: + cmp r1, r12 // while (destp < destEndp) + stmltia r1!, {r0} // *((vu32 *)(destp++)) = data + blt @20 + + bx lr +} +#endif + +#include + + +/*---------------------------------------------------------------------------* + Name: LOADERi_LocateAllSegments + + Description: ARM9,ARM7の各セグメントを必要に応じて再配置する。 + + Arguments: mdfi + + Returns: void + *---------------------------------------------------------------------------*/ + +static void LOADERi_LocateAllSegments( MBDownloadFileInfo *mdfi ) +{ + MBi_SearchAndLocateSegmentInfo(mdfi, MI_PROCESSOR_ARM9); // ARM9セグメントについての配置処理 + MBi_SearchAndLocateSegmentInfo(mdfi, MI_PROCESSOR_ARM7); // ARM7セグメントについての配置処理 +} + + +/* 指定のセグメントを検索し, 再配置する */ +static void MBi_SearchAndLocateSegmentInfo( MBDownloadFileInfo *mdfi, u16 processor ) +{ + int i; + MbSegmentInfo *seg_info; + + if( mdfi ) { + for( i = 0 ; i < MB_DL_SEGMENT_NUM ; ++i ) { + seg_info = &mdfi->seg[i]; + if ( seg_info->target == processor ) { + if ( seg_info->recv_addr != seg_info->load_addr ) { + MIm_CpuCopy32( (void*)seg_info->recv_addr, (void*)seg_info->load_addr, seg_info->size ); +#ifndef SDK_SMALL_BUILD // ※IPL2の場合は、このメモリクリアはIPL2で行う。 + MIm_CpuClear32( 0, (void*)seg_info->recv_addr, seg_info->size ); +#endif + } + } + } + } +} + + +/*---------------------------------------------------------------------------* + Name: LOADERi_Jump + + Description: ローダーを起動 (ARM7/9 共通) + + Arguments: 無し + + Returns: void + *---------------------------------------------------------------------------*/ + +static void LOADERi_Jump(void) +{ +#if defined(SDK_ARM7) + + MBDownloadFileInfo *mdfi = (MBDownloadFileInfo*)MB_DOWNLOAD_FILEINFO_ADDRESS; + MBParam *p_param = (MBParam*)HW_WM_BOOT_BUF; + + if( p_param->boot_type != MB_TYPE_MULTIBOOT ) { // ブートタイプがマルチブートでない場合は、何もせずにTRUEリターン。 + return; + } + + LOADERi_LocateAllSegments( mdfi ); // ブートプログラムの再配置を行う。 + +#endif +} + + +/*---------------------------------------------------------------------------* + Name: MBi_fifo_callback_arm7 + + Description: 専用 PXI タグ経由でローダー起動 + + Arguments: + + Returns: None. + *---------------------------------------------------------------------------*/ + +static void MBi_fifo_callback_arm7(PXIFifoTag tag, u32 msg_adr, BOOL err) +{ +#pragma unused( err ) + + if (tag == PXI_FIFO_TAG_MB && msg_adr == (u32)MB_TRIGGER_SIGNAL_TO_ARM7) + { + if ( loader_precallback ) { + (*loader_precallback)(); + } + } +} + +#endif /* defined(SDK_ARM7) */ + + +/*---------------------------------------------------------------------------* + Name: LOADER_Start + + Description: ローダーのスタート + + Arguments: None. + + Returns: TRUE - success FALSE - failed + *---------------------------------------------------------------------------*/ + + +void LOADER_Start(void) +{ + +#if defined(SDK_ARM9) + int result; + MBDownloadFileInfo *mdfi = (MBDownloadFileInfo*)MB_DOWNLOAD_FILEINFO_ADDRESS; + MBParam *p_param = (MBParam*)HW_WM_BOOT_BUF; + + // マルチブートの時はデバッガエントリに飛ばないようクリアする。 +#ifdef SDK_SMALL_BUILD + GetMovedInfoFromIPL1Addr()->isOnDebugger = 0; // USG-WW-3rd & USG-China-2ndでは、GetSharedWorkAddr()->isOnDebuggerはパッチ領域とモロバッティングしているが、このルーチンがARM9のマルチブートルーチンで呼ばれた後で、ARM7でパッチ挿入ルーチンが呼ばれるので、大丈夫。 + // しかし、デバッガ版ビルド時には、参照する側のisOnDebuggerフラグがクリアされていなかったので、修正する。 +#endif // SDK_SMALL_BUILD + + // システム領域へマルチブートフラグを書き込み + p_param->boot_type = MB_TYPE_MULTIBOOT; + // 親機情報をシステム領域へ書き込み + MI_CpuCopy8((void*)MB_BSSDESC_ADDRESS, &p_param->parent_bss_desc, MB_BSSDESC_SIZE); + + // ARM7側へローダー起動を通知 + result = PXI_SendWordByFifo( PXI_FIFO_TAG_MB, (u32)MB_TRIGGER_SIGNAL_TO_ARM7, FALSE ); + SDK_ASSERTMSG((result >= 0), "ARM9:FIFO SEND ERROR!\n"); + + return; + +#else /* defined(SDK_ARM9) */ + + // ローダーをコール + LOADERi_Jump(); + +#endif +} + + +/*---------------------------------------------------------------------------* + Name: LOADER_Init + + Description: ローダーの初期化 + + Arguments: callback - ブートの準備が出来たときに返すコールバック + + Returns: None. + *---------------------------------------------------------------------------*/ + +void LOADER_Init(MB_LoaderCallback callback) +{ + MBParam *p_param = (MBParam*)HW_WM_BOOT_BUF; + + PXI_Init(); // 初期化されていなかったら、初期化処理を行う + +#if defined(SDK_ARM7) + + loader_precallback = callback; + + /* ブートフラグの補正(マルチブートフラグが指定されていない場合はROMとみなす。) */ + if (p_param->boot_type != MB_TYPE_MULTIBOOT) { + p_param->boot_type = MB_TYPE_NORMAL; + } + /* 上の処理で, 必ず MB_TYPE_MULTIBOOT か MB_TYPE_NORMAL になる */ + + // マルチブート監視FIFOコールバックをセット + PXI_SetFifoRecvCallback( PXI_FIFO_TAG_MB, MBi_fifo_callback_arm7 ); + +#else /* defined(SDK_ARM7) */ + + #pragma unused(callback) + +#endif +} + + + +/*----------------------------------------------------------------------------* +/* 現状 不使用 + *----------------------------------------------------------------------------*/ + +#if defined(LOADER_USE_OVT_BUF) + +//---------------------------------------------------------------------- +// オーバーレイテーブル +//---------------------------------------------------------------------- +typedef struct { + u32 id; // オーバーレイ ID + void *ram_address; // ロード先頭位置 + u32 ram_size; // ロードサイズ + u32 bss_size; // bss 領域サイズ + void *sinit_init; // static initializer 先頭アドレス + void *sinit_init_end; // static initializer 最終アドレス + u32 file_id; // オーバーレイファイルID + u32 rsv; // 予約。 +} ROM_OVT; + + +// OVTの最大サイズ(これについては再考の余地あり) +#define MB_OVT_MAX_SIZE MB_COMM_BLOCKSIZE + +// Overlay Table Buffer +// マルチブートするプログラム上で、スタティックイニシャライザを起動するのに必要 +// オーバーレイテーブル数で容量が変わってくる。 +// IPL2における仕様が固まるまで、ここに置いておく +static u32 mb_ovt_buf[MB_OVT_MAX_SIZE/sizeof(u32)]; + +static void MB_SetOverlayTable(ROM_OVT *srcp, u16 sec_num) +{ + if (srcp && sec_num) + { + MI_CpuCopy8((void*)srcp, (void*)mb_ovt_buf, sec_num*sizeof(ROM_OVT)); + } +} + +#endif diff --git a/build/libraries_sysmenu/sysmenu/ARM9/MakeCrt0 b/build/libraries_sysmenu/sysmenu/ARM9/MakeCrt0 new file mode 100644 index 00000000..95df6767 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/MakeCrt0 @@ -0,0 +1,46 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-10-03#$ +# $Rev: 1319 $ +# $Author: kitase_hirotake $ +#---------------------------------------------------------------------------- + + +SUBDIRS = + + +#---------------------------------------------------------------------------- +TARGET_PLATFORM = TWL +TWL_ARCHGEN = LIMITED +TWL_PROC = ARM9 + +SRCS = crt1.c + +TARGET_OBJ = crt1.o + +LINCLUDES = $(COMMON_DIR) + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(SYSMENU_INSTALL_LIBDIR) + +#---------------------------------------------------------------------------- + +do-build: $(TARGETS) + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + + +#===== End of Makefile ===== diff --git a/build/libraries_sysmenu/sysmenu/ARM9/Makefile b/build/libraries_sysmenu/sysmenu/ARM9/Makefile new file mode 100644 index 00000000..ef7b3789 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/Makefile @@ -0,0 +1,52 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-10-03#$ +# $Rev: 1319 $ +# $Author: kitase_hirotake $ +#---------------------------------------------------------------------------- + +SUBDIRS = + +MYSUBDIRS = ./ + +#---------------------------------------------------------------------------- +TARGET_PLATFORM = TWL +TWL_ARCHGEN = LIMITED +TWL_PROC = ARM9 + +SRCS = sysmenu_lib.c sysmenu_card.c sysmenu_util.c gameBoot.c ninLogoFunc.c cmn.c \ + nitroSettingsEx.c + +TARGET_LIB = libsysmenu$(TWL_LIBSUFFIX).a + + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +INSTALL_TARGETS = $(TARGETS) +INSTALL_DIR = $(SYSMENU_INSTALL_LIBDIR) + +LINCLUDES = $(TWLSDK_ROOT)/build/libraries/mb/common/include \ + $(TWLSDK_ROOT)/build/libraries/spi/ARM9/include \ + +#---------------------------------------------------------------------------- + +do-build: $(MYSUBDIRS) $(TARGETS) + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + + +$(MYSUBDIRS):: +# $(MAKE) -C $@ -f MakeCrt0 + +#===== End of Makefile ===== diff --git a/build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_card.h b/build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_card.h new file mode 100644 index 00000000..eeee6e8d --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_card.h @@ -0,0 +1,248 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: SYSM_card.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef SYSM_CARD_H_ +#define SYSM_CARD_H_ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +//---------------------------------------------------------------------- +// カード抜け検出 +// +//・ARM7 がカードからのダウンロードを完了するまでは検出を開始しません。 +//・検出処理中はカードバスへのアクセスをロックします。 +//・アプリケーションを起動する前に SYSM_FinalizeCardPulledOut() +// を呼び出して確実に検出処理を完了させるようにして下さい。 +//---------------------------------------------------------------------- + +BOOL SYSM_IsCardPulledOut(void); + + +//---------------------------------------------------------------------- +// カード抜け検出終了処理 +//---------------------------------------------------------------------- + +void SYSM_FinalizeCardPulledOut(void); + + +//---------------------------------------------------------------------- +// カード抜け検出処理中か +//---------------------------------------------------------------------- + +BOOL SYSM_IsDetectingCardPulledOut(void); + + +//---------------------------------------------------------------------- +// カード抜け検出初期化 +//---------------------------------------------------------------------- + +void SYSMi_InitCardPulledOut(void); + + +//---------------------------------------------------------------------- +// カードID読み込み +//---------------------------------------------------------------------- + +u32 SYSMi_ReadCardID(void); + + +//---------------------------------------------------------------------- +// カードデータ読み込み +//---------------------------------------------------------------------- + +void SYSM_ReadCard(void *romp, void *ramp, s32 size); + + +//---------------------------------------------------------------------- +// カードのデータ転送はレディか? +//---------------------------------------------------------------------- + +#define SYSMi_IsCardDataReady() \ + \ + (*(vu32 *)REG_CARDCNT & CARD_DATA_READY) + +//・カードのデータ転送はレディかどうかを返します。 + +//---------------------------------------------------------------------- +// カードデータ待ち +//---------------------------------------------------------------------- + +#define SYSMi_WaitCardData() \ +{ \ + while (!SYSMi_IsCardDataReady()) ; \ +} + +//・カードデータ転送の終了を待ちます。 + + +//---------------------------------------------------------------------- +// カードはビジーか? +//---------------------------------------------------------------------- + +#define SYSMi_IsCardBusy() \ + \ + (*(vu32 *)REG_CARDCNT & CARD_START) + +//・カードがビジーかどうかを返します。 + +//---------------------------------------------------------------------- +// カード待ち +//---------------------------------------------------------------------- + +#define SYSMi_WaitCard() \ +{ \ + while (SYSMi_IsCardBusy()) ; \ +} + +//・カードの終了を待ちます。 + + +//---------------------------------------------------------------------- +// コントロールパラメータ獲得(GAMEモード) +//---------------------------------------------------------------------- + +#define SYSMi_GetCardCnt4Game() \ + \ + (*(vu32 *)MROMCNT_GAME_BUF) + +//・GAMEモードのコントロールパラメータを獲得します。 + + + +//---------------------------------------------------------------------- +// ROMエリア・マップ +//---------------------------------------------------------------------- + +#define MROM_SECURE_AREA 0x4000 // SECUREエリア +#define MROM_GAME_AREA 0x8000 // GAMEエリア + +//---------------------------------------------------------------------- +// ROMエリア・サイズ +//---------------------------------------------------------------------- + +#define MROM_SEGMENT_SIZE 0x1000 // セグメントサイズ +#define MROM_SECURE_SIZE 0x4000 // SECUREエリアサイズ + +#ifndef MROM_PAGE_SIZE +#define MROM_PAGE_SIZE 512 // マスクROM・ページ +#endif + +//---------------------------------------------------------------------- +// メモリ・マップ +//---------------------------------------------------------------------- + +#define MROMCNT_GAME_BUF (HW_ROM_HEADER_BUF + 0x60) // GAMEモード・コントロールデータ +#define MROMCNT_SECURE_BUF (HW_ROM_HEADER_BUF + 0x64) // SECUREモード・コントロールデータ + + +//---------------------------------------------------------------------- +// レジスタ・アドレス +//---------------------------------------------------------------------- + +#ifndef REG_BASE +#define REG_BASE 0x04000000 // レジスタ群 +#endif +#ifndef REG_IME +#define REG_IME (REG_BASE + 0x208) // 割り込みマスタイネーブル +#endif + +#define REG_CARDMST_SPI_CNT (REG_BASE + 0x1a0) // カードマスター&SPIコントロール + +#define REG_CARD_MASTER_CNT (REG_BASE + 0x1a1) // カードマスターコントロール + +#define REG_CARD_SPI_CNT (REG_BASE + 0x1a0) // カードSPIコントロール +#define REG_CARD_SPI_DATA (REG_BASE + 0x1a2) // データ + +#define REG_CARDCNT (REG_BASE + 0x1a4) // カードコントロール +#define REG_CARD_CMD (REG_BASE + 0x1a8) // コマンド設定 +#define REG_CARD_DATA (REG_BASE + 0x100010) // データ + + +//---------------------------------------------------------------------- +// カード マスターコントロール +//---------------------------------------------------------------------- + +#define CARDMST_SEL_DEVICE 0x20 // デバイス選択 +#define CARDMST_SEL_ROM 0x00 // マスクROM/3Dメモリ選択 +#define CARDMST_SEL_SPI 0x20 // SPI選択 + +#define CARDMST_IF_ENABLE 0x40 // 割り込み要求 許可 +#define CARDMST_ENABLE 0x80 // カードイネーブル + + +//---------------------------------------------------------------------- +// カードアクセス コントロール +//---------------------------------------------------------------------- + +#define CARD_LATENCY1_CYCLES_MASK 0x00001fff // レイテンシ1のサイクル数 +#define CARD_LATENCY2_CYCLES_MASK 0x003f0000 // レイテンシ2のサイクル数 +#define CARD_LATENCY_MASK 0x003f1fff // 上記を合わせたマスク + +#define CARD_LATENCY1_CYCLES_SHIFT 0 +#define CARD_LATENCY2_CYCLES_SHIFT 16 + +#define CARD_DATA_SCRAMBLE_ON 0x00002000 // データスクランブル ON +#define CARD_SCRAMBLE_UNIT_ON 0x00004000 // スクランブル回路 ON +#define CARD_CMD_SCRAMBLE_ON 0x00400000 // コマンドスクランブル ON + // スクランブルフラグ群のセット +#define CARD_SCRAMBLE_SET_MASK ( CARD_SCRAMBLE_UNIT_ON | CARD_DATA_SCRAMBLE_ON \ + | CARD_CMD_SCRAMBLE_ON) + +#define CARD_DATA_READY 0x00800000 // データ レディ + +#define CARD_1_PAGE 0x01000000 // 1ページ +#define CARD_STATUS 0x07000000 // ステータスリード + +#define CARD_RESET_LO 0x00000000 // リセット信号レベル Lo +#define CARD_RESET_HI 0x20000000 // Hi +#define CARD_ACCESS_MODE 0x40000000 // アクセス モード +#define CARD_READ_MODE 0x00000000 // リードモード +#define CARD_WRITE_MODE 0x40000000 // ライトモード +#define CARD_START 0x80000000 // スタート + +// 構造体メンバ用定数 + +#define ST_CARD_1_PAGE 1 // 1ページ +#define ST_CARD_STATUS 7 // ステータスリード + +#define ST_CARD_READ_MODE 0 // リードモード +#define ST_CARD_WRITE_MODE 1 // ライトモード + + +//---------------------------------------------------------------------- +// マスクROMコマンド +//---------------------------------------------------------------------- + +// GAMEモード + +#define MROMOP_G_OP_MASK 0xff000000 // コマンドマスク + +#define MROMOP_G_READ_ID 0xb8000000 // ID読み込み +#define MROMOP_G_READ_PAGE 0xb7000000 // ページ読み込み + + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // SYSM_CARD_H_ diff --git a/build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_define.h b/build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_define.h new file mode 100644 index 00000000..05e8886f --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/include/sysmenu_define.h @@ -0,0 +1,50 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: SYSM_define.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __SYSM_DEFINE_H__ +#define __SYSM_DEFINE_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// define data------------------------------------------- + + // 定数 +#define POW_LCDC_SW_TOP 0x0000 // LCD上に画面表示 +#define POW_LCDC_SW_BOTTOM 0x8000 // LCD下に画面表示 +#define POW_E2D2 0x0200 // 2D回路2 の電源ON +#define POW_E2D1 0x0002 // 2D回路1 の電源ON +#define POW_ELC 0x0001 // LCDC回路の電源ON + +#define SUBP_RECV_IF_ENABLE 0x4000 // 割り込み要求受信 許可 + + // 排他制御用ロックID +#define BOOTFLAG_LOCK_ID (OS_MAINP_LOCK_ID_END-1) +#define CARTRIDGE_LOCK_ID (OS_MAINP_LOCK_ID_END-2) + + // SetBootFlag関数の引数int set_clear_flagで指定する定数 +#define SBF_CLEAR 0 +#define SBF_SET 1 + +#ifdef __cplusplus +} +#endif + +#endif // __SYSM_DEFINE_H__ diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/cmn.c b/build/libraries_sysmenu/sysmenu/ARM9/src/cmn.c new file mode 100644 index 00000000..055928d3 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/cmn.c @@ -0,0 +1,250 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: mainFunc.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include + +#include + + +/*---------------------------------------------------------------------------* + Name: CMN_InitFileSystem + + Description: ファイルシステムを有効にします。 + また、ファイルテーブルをメモリに読み込みます。 + + Arguments: pAllocator: 有効なアロケータへのポインタ。 + + Returns: なし。 + *---------------------------------------------------------------------------*/ +// ファイルシステム準備 +void CMN_InitFileSystem( NNSFndAllocator* pAllocator ) +{ + SDK_NULL_ASSERT( pAllocator ); + + // ARM7との通信FIFO割り込み許可 + (void)OS_EnableIrqMask(OS_IE_SPFIFO_RECV); + + // ファイルシステム初期化 + FS_Init( FS_DMA_NOT_USE ); + + // ファイルテーブルキャッシュ + if( pAllocator != NULL ) + { + const u32 need_size = FS_GetTableSize(); + void *p_table = NNS_FndAllocFromAllocator( pAllocator, need_size ); + SDK_ASSERT(p_table != NULL); + (void)FS_LoadTable(p_table, need_size); + } +} + + + +/*---------------------------------------------------------------------------* + Name: CMN_ClearVram + + Description: VRAM をクリアします。 + VRAM が全て未割り当てでなければなりません。 + + Arguments: なし。 + + Returns: なし。 + *---------------------------------------------------------------------------*/ +// VRAMクリア +void CMN_ClearVram( void ) +{ + //--------------------------------------------------------------------------- + // All VRAM banks to LCDC + //--------------------------------------------------------------------------- + GX_SetBankForLCDC(GX_VRAM_LCDC_ALL); + + //--------------------------------------------------------------------------- + // Clear all LCDC space + //--------------------------------------------------------------------------- + MI_CpuClearFast((void *)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE); + + //--------------------------------------------------------------------------- + // Disable the banks on LCDC + //--------------------------------------------------------------------------- + (void)GX_DisableBankForLCDC(); + + MI_CpuFillFast((void *)HW_OAM, 192, HW_OAM_SIZE); // clear OAM + MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE); // clear the standard palette + + MI_CpuFillFast((void*)HW_DB_OAM, 192, HW_DB_OAM_SIZE); // clear OAM + MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE); // clear the standard palette +} + + + +/*---------------------------------------------------------------------------* + Name: CMN_LoadFile + + Description: ファイルをメモリにロードします。 + ファイルデータが不要になった場合は + CMN_UnloadFile( *ppFile, pAlloc ) でファイルデータを + 解放します。 + + Arguments: ppFile: ファイルをロードしたメモリアドレスを受け取る + バッファへのポインタ。 + fpath: ロードするファイルのパス + pAlloc: アロケータへのポインタ + + Returns: ロードしたファイルのファイルサイズを返します。 + 0 の場合はファイルロードに失敗した事を表します。 + この場合 *ppFile の値は無効です。 + *---------------------------------------------------------------------------*/ +u32 CMN_LoadFile(void** ppFile, const char* fpath, NNSFndAllocator* pAlloc) +{ + BOOL bSuccess; + FSFile f; + u32 length; + u32 read; + + SDK_NULL_ASSERT( ppFile ); + SDK_NULL_ASSERT( fpath ); + SDK_NULL_ASSERT( pAlloc ); + + FS_InitFile(&f); + + bSuccess = FS_OpenFile(&f, fpath); + if( ! bSuccess ) + { + OS_Warning("file (%s) not found", fpath); + return 0; + } + + length = FS_GetLength(&f); + *ppFile = NNS_FndAllocFromAllocator(pAlloc, length); + if( *ppFile == NULL ) + { + OS_Warning("cant allocate memory for file: %s", fpath); + return 0; + } + + read = (u32)FS_ReadFile(&f, *ppFile, (s32)length); + if( read != length ) + { + OS_Warning("fail to load file: %s", fpath); + NNS_FndFreeToAllocator(pAlloc, *ppFile); + return 0; + } + + bSuccess = FS_CloseFile(&f); + if( ! bSuccess ) + { + OS_Warning("fail to close file: %s", fpath); + } + + return length; +} + + + +/*---------------------------------------------------------------------------* + Name: CMN_UnloadFile + + Description: ファイルデータを解放します。 + + Arguments: pFile: ファイルデータへのポインタ + pAlloc: ファイルロードに用いたアロケータへのポインタ + + Returns: なし。 + *---------------------------------------------------------------------------*/ +void CMN_UnloadFile(void* pFile, NNSFndAllocator* pAlloc) +{ + NNS_FndFreeToAllocator(pAlloc, pFile); +} + + + +/*---------------------------------------------------------------------------* + Name: CMN_LoadArchive + + Description: パス名で指定されたアーカイブをメモリに読み込み、ファイルシス + テムにマウントします。 + アーカイブが不要になった場合は + CMN_RemoveArchive( 返り値, pAllocator ) でアーカイブを + 解放します。 + + Arguments: name: アーカイブをファイルシステム上で識別する為の名前。 + path: アーカイブのパス名。 + pAllocator: アロケータへのポインタ + + Returns: アーカイブのロードに成功すれば、NNSFndArchive 構造体へのポイ + ンタを返します。失敗した場合には、NULLを返します。 + *---------------------------------------------------------------------------*/ +NNSFndArchive* +CMN_LoadArchive(const char* name, const char* path, NNSFndAllocator* pAllocator) +{ + FSFile file; + NNSFndArchive* archive = NULL; + + SDK_NULL_ASSERT(name); + SDK_NULL_ASSERT(path); + SDK_NULL_ASSERT(pAllocator); + + FS_InitFile(&file); + if (FS_OpenFile(&file, path)) + { + u32 binarySize = FS_GetLength(&file); + u32 memorySize = MATH_ROUNDUP(sizeof(NNSFndArchive), 16) + MATH_ROUNDUP(binarySize, 16); + + u8* memory = (u8*)NNS_FndAllocFromAllocator(pAllocator, memorySize); + + if (memory != NULL) + { + u8* binary = memory + MATH_ROUNDUP(sizeof(NNSFndArchive), 16); + + if ((u32)FS_ReadFile(&file, binary, (s32)binarySize) == binarySize) + { + if (NNS_FndMountArchive((NNSFndArchive*)memory, name, binary)) + { + archive = (NNSFndArchive*)memory; + } + } + } + (void)FS_CloseFile(&file); + } + return archive; +} + + + +/*---------------------------------------------------------------------------* + Name: CMN_RemoveArchive + + Description: 指定されたアーカイブをメモリから削除します。 + + 指定されたアーカイブをファイルシステムからアンマウントし、ア + ーカイブが読み込まれていたメモリを解放します。 + + Arguments: archive: NNSアーカイブ構造体へのポインタ。 + pAllocator: アーカイブロードに用いたアロケータへのポインタ。 + + Returns: なし。 + *---------------------------------------------------------------------------*/ +void +CMN_RemoveArchive(NNSFndArchive* archive, NNSFndAllocator* pAllocator) +{ + SDK_NULL_ASSERT(archive); + SDK_NULL_ASSERT(pAllocator); + + (void)NNS_FndUnmountArchive(archive); + NNS_FndFreeToAllocator(pAllocator, archive); +} + diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/crt1.c b/build/libraries_sysmenu/sysmenu/ARM9/src/crt1.c new file mode 100644 index 00000000..c5d8408a --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/crt1.c @@ -0,0 +1,559 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: crt1.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include // SYSM changed. + +#define SDK_NOCOMPRESS // SYSM changed. + + +extern void NitroMain( void ); +extern void OS_IrqHandler( void ); +static void do_autoload( void ); +static void init_cp15( void ); +void _start( void ); +extern void* const _start_ModuleParams[]; +void _start_AutoloadDoneCallback( void* argv[] ); + +extern void __call_static_initializers( void ); +extern void _fp_init( void ); + +// from LCF +extern u32 SDK_IRQ_STACKSIZE[]; +extern void SDK_AUTOLOAD_START( void ); // autoload data will start from here +extern void SDK_AUTOLOAD_LIST( void ); // start pointer to autoload information +extern void SDK_AUTOLOAD_LIST_END( void ); // end pointer to autoload information +extern void SDK_STATIC_BSS_START( void ); // static bss start address +extern void SDK_STATIC_BSS_END( void ); // static bss end address + + +/*---------------------------------------------------------------------------* + Name: _start + + Description: Start up + + Arguments: None + + Returns: None. + *---------------------------------------------------------------------------*/ +#define INITi_HW_DTCM SDK_AUTOLOAD_DTCM_START + +__declspec ( weak ) asm void _start( void ) +{ + //---- set IME = 0 + // ( use that LSB of HW_REG_BASE equal to 0 ) + mov r12, #HW_REG_BASE + str r12, [r12, #REG_IME_OFFSET] + + //---- initialize cp15 + bl init_cp15 + + //---- initialize stack pointer + // SVC mode + mov r0, #HW_PSR_SVC_MODE + msr cpsr_c, r0 + ldr r0, =INITi_HW_DTCM + add r0, r0, #0x3fc0 + mov sp, r0 + + // IRQ mode + mov r0, #HW_PSR_IRQ_MODE + msr cpsr_c, r0 + ldr r0, =INITi_HW_DTCM + add r0, r0, #0x3fc0 + sub r0, r0, #HW_SVC_STACK_SIZE + mov sp, r0 + + // System mode + ldr r1, =SDK_IRQ_STACKSIZE + sub r1, r0, r1 + mov r0, #HW_PSR_SYS_MODE + msr cpsr_csfx, r0 + sub sp, r1, #4 // 4byte for stack check code + + //---- load autoload block and initialize bss +#ifndef SDK_NOCOMPRESS + ldr r1, =_start_ModuleParams + ldr r0, [r1, #20] // r0 = bottom of compressed data + bl MIi_UncompressBackward +#endif + bl do_autoload + + //---- clear memory + // DTCM (16KB) + mov r0, #0 + ldr r1, =INITi_HW_DTCM + mov r2, #HW_DTCM_SIZE + bl MIi_CpuClear32 + +/* // BG/OBJ palette (1KB) // SYSM changed. + mov r0, #0 + ldr r1, =HW_PLTT + mov r2, #HW_PLTT_SIZE + bl MIi_CpuClear32 + + // OAM (1KB) + mov r0, #0x0200 + ldr r1, =HW_OAM + mov r2, #HW_OAM_SIZE + bl MIi_CpuClear32 +*/ + //---- set interrupt vector + ldr r1, =INITi_HW_DTCM + add r1, r1, #0x3fc0 + add r1, r1, #HW_DTCM_SYSRV_OFS_INTR_VECTOR + ldr r0, =OS_IrqHandler + str r0, [r1, #0] + +#ifndef SDK_NOINIT + //---- for C++ + bl _fp_init + bl NitroStartUp + bl __call_static_initializers +#endif + //---- start (to 16bit code) + ldr r1, =NitroMain +// ldr lr, =HW_RESET_VECTOR + ldr lr, =RETURN_FROM_MAIN_ARM9_FUNCP // SYSM changed. + + bx r1 +} + +/*---------------------------------------------------------------------------* + Name: _start_ModuleParams + + Description: autoload/compress/arguments data block + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +void* const _start_ModuleParams[] = +{ + (void*)SDK_AUTOLOAD_LIST, + (void*)SDK_AUTOLOAD_LIST_END, + (void*)SDK_AUTOLOAD_START, + (void*)SDK_STATIC_BSS_START, + (void*)SDK_STATIC_BSS_END, +#ifndef SDK_NOCOMPRESS + (void*)0, // CompressedStaticEnd +#endif +}; + +/*---------------------------------------------------------------------------* + Name: MIi_UncompressBackward + + Description: Uncompress special archive for module compression + + Arguments: bottom = Bottom adrs of packed archive + 1 + bottom[-12] = offset for top of compressed data + inp_top = bottom + bottom[-12] + bottom[ -8] = offset for bottom of compressed data + inp = bottom + bottom[ -8] + bottom[ -4] = offset for bottom of original data + outp = bottom + bottom[ -4] + + typedef struct + { + int bufferTop; + int compressBottom; + int originalBottom; + } CompFooter; + + Returns: None. + *---------------------------------------------------------------------------*/ +asm void MIi_UncompressBackward( register void* bottom ) +{ +#define data r0 +#define inp_top r1 +#define outp r2 +#define inp r3 +#define outp_save r4 +#define flag r5 +#define count8 r6 +#define index r7 +#define len r12 + cmp bottom, #0 + beq @exit + stmfd sp!, {r4-r7} + ldmdb bottom, {r1-r2} + add outp, bottom, outp + sub inp, bottom, inp_top, LSR #24 + bic inp_top, inp_top, #0xff000000 + sub inp_top, bottom, inp_top + mov outp_save, outp +@loop: + cmp inp, inp_top // exit if inp==inp_top + ble @end_loop + ldrb flag, [inp, #-1]! // r4 = compress_flag = *--inp + mov count8, #8 +@loop8: + subs count8, count8, #1 + blt @loop + tst flag, #0x80 + bne @blockcopy +@bytecopy: + ldrb data, [inp, #-1]! +#ifdef SDK_TEG + sub outp, outp, #1 + swpb data, data, [outp] +#else + strb data, [outp, #-1]! // Copy 1 byte +#endif + b @joinhere +@blockcopy: + ldrb len, [inp, #-1]! + ldrb index, [inp, #-1]! + orr index, index, len, LSL #8 + bic index, index, #0xf000 + add index, index, #0x0002 + add len, len, #0x0020 +@patterncopy: + ldrb data, [outp, index] +#ifdef SDK_TEG + sub outp, outp, #1 + swpb data, data, [outp] +#else + strb data, [outp, #-1]! +#endif + subs len, len, #0x0010 + bge @patterncopy + +@joinhere: + cmp inp, inp_top + mov flag, flag, LSL #1 + bgt @loop8 +@end_loop: + + // DC_FlushRange & IC_InvalidateRange + bic inp, inp_top, #HW_CACHE_LINE_SIZE - 1 +@cacheflush: + mcr p15, 0, inp, c7, c5, 1 // ICache + mcr p15, 0, inp, c7, c14, 1 // DCache + add inp, inp, #HW_CACHE_LINE_SIZE + cmp inp, outp_save + blt @cacheflush + + ldmfd sp!, {r4-r7} +@exit bx lr +} + + +/*---------------------------------------------------------------------------* + Name: do_autoload + + Description: put autoload data block according to autoload information, + and clear static bss by filling with 0. + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +static asm void do_autoload( void ) +{ +#define ptable r0 +#define infop r1 +#define infop_end r2 +#define src r3 +#define dest r4 +#define dest_size r5 +#define dest_end r6 +#define tmp r7 + + ldr ptable, =_start_ModuleParams + ldr infop, [ptable, #0] // r1 = start pointer to autoload_info + ldr infop_end, [ptable, #4] // r2 = end pointer to autoload_info + ldr src, [ptable, #8] // r3 = autoload block + +@2: + cmp infop, infop_end // reach to end? + beq @fill_bss + + ldr dest, [infop], #4 // dest + ldr dest_size, [infop], #4 // size + add dest_end, dest, dest_size // dest_end +@1: + cmp dest, dest_end + ldrmi tmp, [src], #4 // [dest++] <- [src++] + strmi tmp, [dest], #4 + bmi @1 + + //---- fill bss with 0 + ldr dest_size, [infop], #4 // size + add dest_end, dest, dest_size // bss end + mov tmp, #0 +@4: + cmp dest, dest_end + strcc tmp, [dest], #4 + bcc @4 + + beq @2 + + //---- fill static static bss with 0 +@fill_bss: + ldr dest, [ptable, #12] // BSS segment start + ldr dest_end, [ptable, #16] // BSS segment end + mov tmp, #0 +@3: + cmp dest, dest_end + strcc tmp, [dest], #4 + bcc @3 + + // r0 = _start_ModuleParams + b _start_AutoloadDoneCallback // Jump into the callback +} + +/*---------------------------------------------------------------------------* + Name: _start_AutoloadDoneCallback + + Description: hook for end of autoload (This is dummy target for DEBUGGER) + + Arguments: argv: pointer for autoload parameters + argv[0] = SDK_AUTOLOAD_LIST + argv[1] = SDK_AUTOLOAD_LIST_END + argv[2] = SDK_AUTOLOAD_START + argv[3] = SDK_STATIC_BSS_START + argv[4] = SDK_STATIC_BSS_END + + Returns: None. + *---------------------------------------------------------------------------*/ +__declspec ( weak ) asm void _start_AutoloadDoneCallback( void* argv[] ) +{ + bx lr +} + +//----------------------------------------------------------------------- +// システム制御コプロセッサ 初期化 +//----------------------------------------------------------------------- +static asm void init_cp15(void) +{ + // プロテクションユニット/キャッシュ/TCM ディセーブル + + mrc p15, 0, r0, c1, c0, 0 + ldr r1, =HW_C1_ICACHE_ENABLE | HW_C1_DCACHE_ENABLE \ + | HW_C1_ITCM_ENABLE | HW_C1_DTCM_ENABLE \ + | HW_C1_ITCM_LOAD_MODE | HW_C1_DTCM_LOAD_MODE \ + | HW_C1_LD_INTERWORK_DISABLE \ + | HW_C1_PROTECT_UNIT_ENABLE + bic r0, r0, r1 + mcr p15, 0, r0, c1, c0, 0 + + // キャッシュ無効化 + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 // 命令キャッシュ + mcr p15, 0, r0, c7, c6, 0 // データキャッシュ + + // ライトバッファ エンプティ待ち + mcr p15, 0, r0, c7, c10, 4 + +/* +; Region G: BACK_GROUND: Base = 0x0, Size = 4GB, I:NC NB / D:NC NB, I:NA / D:NA +; Region 0: IO_VRAM: Base = 0x04000000, Size = 64MB, I:NC NB / D:NC NB, I:RW / D:RW +; Region 1Rel: MAIN_MEM: Base = 0x02000000, Size = 4MB, I:Cach Buf / D:Cach Buf, I:RW / D:RW +; Region 1Dbg: MAIN_MEM: Base = 0x02000000, Size = 8MB, I:Cach Buf / D:Cach Buf, I:RW / D:RW +; Region 2Rel: SOUND_DATA: Base = 0x02380000, Size = 512KB, I:NC NB / D:NC NB, I:NA / D:NA +; Region 2D4M: SOUND_DATA: Base = 0x02300000, Size = 1MB, I:NC NB / D:NC NB, I:NA / D:NA +; Region 2D8M: SOUND_DATA: Base = 0x02600000, Size = 2MB, I:NC NB / D:NC NB, I:NA / D:NA +; Region 3: CARTRIDGE: Base = 0x08000000, Size = 128MB, I:NC NB / D:NC NB, I:NA / D:RW +; Region 4: DTCM: Base = SOUND_DATA, Size = 16KB, I:NC NB / D:NC NB, I:NA / D:RW +; Region 5: ITCM: Base = 0x01000000, Size = 16MB, I:NC NB / D:NC NB, I:RW / D:RW + +; Region 6: BIOS: Base = 0xffff0000, Size = 32KB, I:Cach NB / D:Cach NB, I:RO / D:RO +; Region 7: SHARE_WORK: Base = 0x027ff000, Size = 4KB, I:NC NB / D:NC NB, I:NA / D:RW +;(Region 7: DBG_RESERVE: Base = 0x02700000, Size = 1MB, I:NC NB / D:NC NB, I:RW / D:RW) +*/ +#define SET_PROTECTION_A( id, adr, siz ) ldr r0, =(adr|HW_C6_PR_##siz|HW_C6_PR_ENABLE) +#define SET_PROTECTION_B( id, adr, siz ) mcr p15, 0, r0, c6, id, 0 +#define REGION_BIT(a,b,c,d,e,f,g,h) (((a)<<0)|((b)<<1)|((c)<<2)|((d)<<3)|((e)<<4)|((f)<<5)|((g)<<6)|((h)<<7)) +#define REGION_ACC(a,b,c,d,e,f,g,h) (((a)<<0)|((b)<<4)|((c)<<8)|((d)<<12)|((e)<<16)|((f)<<20)|((g)<<24)|((h)<<28)) +#define NA 0 +#define RW 1 +#define RO 5 + + + // + // メモリリージョン初期化 + // + //---- I/O レジスタ & VRAM 等 + SET_PROTECTION_A( c0, HW_IOREG, 64MB ) + SET_PROTECTION_B( c0, HW_IOREG, 64MB ) + + //---- メインメモリ + SET_PROTECTION_A( c1, HW_MAIN_MEM_MAIN, 4MB ) + SET_PROTECTION_B( c1, HW_MAIN_MEM_MAIN, 4MB ) + +/* //---- サウンドデータ領域 // SYSM changed. +#if HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x1000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 4KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 4KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x2000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 8KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 8KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x4000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 16KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 16KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x8000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 32KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 32KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x10000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 64KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 64KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x20000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 128KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 128KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x40000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 256KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 256KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x80000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 512KB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 512KB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x100000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 1MB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 1MB ) +#elif HW_MAIN_MEM_SUB_SIZE+HW_MAIN_MEM_SHARED_SIZE == 0x200000 + SET_PROTECTION_A( c2, HW_MAIN_MEM_SUB, 2MB ) + SET_PROTECTION_B( c2, HW_MAIN_MEM_SUB, 2MB ) +#else +#pragma message(ERROR: Size unmatch HW_MAIN_MEM_SUB_SIZE) +#endif +*/ + //---- カートリッジ又は他の用途 + // CPU 内部ワーク RAM 等 + SET_PROTECTION_A( c3, HW_CTRDG_ROM, 128MB ) + SET_PROTECTION_B( c3, HW_CTRDG_ROM, 128MB ) + + //---- データ TCM + // + CPU 内部ワーク RAM の場合あり +//#if (HW_DTCM & 0x3FFF) != 0 +//#pragma message(ERROR: HW_DTCM need to be aligned 16KB!) +//#endif + +// SET_PROTECTION_A( c4, HW_DTCM, 16KB ) + ldr r0, =SDK_AUTOLOAD_DTCM_START + orr r0, r0, #HW_C6_PR_16KB + orr r0, r0, #HW_C6_PR_ENABLE + SET_PROTECTION_B( c4, HW_DTCM, 16KB ) + + //---- 命令 TCM + // データ TCM より優先が高い、メインメモリ領域までのイメージ + SET_PROTECTION_A( c5, HW_ITCM_IMAGE, 16MB ) + SET_PROTECTION_B( c5, HW_ITCM_IMAGE, 16MB ) + + //---- BIOS + SET_PROTECTION_A( c6, HW_BIOS, 32KB ) + SET_PROTECTION_B( c6, HW_BIOS, 32KB ) + + //---- SHARED CPU 間通信ワーク領域 + SET_PROTECTION_A( c7, HW_MAIN_MEM_SHARED, 4KB ) + SET_PROTECTION_B( c7, HW_MAIN_MEM_SHARED, 4KB ) + +#if HW_MAIN_MEM_SHARED_SIZE != 0x1000 +#pragma message(ERROR: Size unmatch HW_MAIN_MEM_SHARED_SIZE) +#endif + + // + // 命令TCM 設定 + // + mov r0, #HW_C9_TCMR_32MB + mcr p15, 0, r0, c9, c1, 1 + + // + // データTCM 設定 + // + ldr r0, =INITi_HW_DTCM + orr r0, r0, #HW_C9_TCMR_16KB + mcr p15, 0, r0, c9, c1, 0 + + // + // 命令キャッシュ イネーブル (リージョン設定) + // 1: MAIN_MEM + // 6: BIOS + // + mov r0, #REGION_BIT(0,1,0,0,0,0,1,0) + mcr p15, 0, r0, c2, c0, 1 + + // + // データキャッシュ イネーブル (リージョン設定) + // 1: MAIN_MEM + // 6: BIOS + // + mov r0, #REGION_BIT(0,1,0,0,0,0,1,0) + mcr p15, 0, r0, c2, c0, 0 + + // + // ライトバッファ イネーブル(リージョン設定) + // 1: MAIN_MEM + // + mov r0, #REGION_BIT(0,1,0,0,0,0,0,0) + mcr p15, 0, r0, c3, c0, 0 + + // + // 命令アクセス許可 (リージョン設定) + // IO_VRAM : RW + // MAIN_MEM_MAIN : RW + // MAIN_MEM_SUB : NA + // CTRDG : NA + // DTCM : NA + // ITCM : RW + // BIOS : RO + // SHARED : NA + // + ldr r0, =REGION_ACC(RW,RW,NA,NA,NA,RW,RO,NA) + mcr p15, 0, r0, c5, c0, 3 + + // + // データアクセス許可(リージョン設定) + // IO_VRAM : RW + // MAIN_MEM_MAIN : RW + // MAIN_MEM_SUB : NA + // CTRDG : RW + // DTCM : RW + // ITCM : RW + // BIOS : RO + // SHARED : RW + // + ldr r0, =REGION_ACC(RW,RW,NA,RW,RW,RW,RO,RW) + mcr p15, 0, r0, c5, c0, 2 + + // + // システム制御コプロセッサ マスター設定 + // + mrc p15, 0, r0, c1, c0, 0 + ldr r1,=HW_C1_ICACHE_ENABLE | HW_C1_DCACHE_ENABLE | HW_C1_CACHE_ROUND_ROBIN \ + | HW_C1_ITCM_ENABLE | HW_C1_DTCM_ENABLE \ + | HW_C1_SB1_BITSET | HW_C1_EXCEPT_VEC_UPPER \ + | HW_C1_PROTECT_UNIT_ENABLE + orr r0, r0, r1 + mcr p15, 0, r0, c1, c0, 0 + + bx lr +} + + +/*---------------------------------------------------------------------------* + Name: NitroStartUp + + Description: hook for user start up + + Arguments: None + + Returns: None. + *---------------------------------------------------------------------------*/ +__declspec ( weak ) void NitroStartUp( void ) +{ +} diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/gameBoot.c b/build/libraries_sysmenu/sysmenu/ARM9/src/gameBoot.c new file mode 100644 index 00000000..558b3284 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/gameBoot.c @@ -0,0 +1,247 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: gameBoot.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include + +// define data------------------------------------------------------- +#define C1_DTCM_ENABLE 0x00010000 // データTCM イネーブル +#define C1_EXCEPT_VEC_UPPER 0x00002000 // 例外ベクタ 上位アドレス(こちらに設定して下さい) +#define C1_SB1_BITSET 0x00000078 // レジスタ1用1固定ビット列(後期アボートモデル、DATA32構成シグナル制御、PROG32構成シグナル制御、ライトバッファイネーブル) + +#define INITi_HW_DTCM SDK_AUTOLOAD_DTCM_START + +// extern data------------------------------------------------------- + +// from LCF +extern u32 SDK_IRQ_STACKSIZE[]; + +// function's prototype---------------------------------------------- +void ReturnFromMain(void); +void ResetCP15(void); +void ClearBankregAndStack(void); +void CpuClear32Byte(void); +void BootFuncEnd(void); + +// global variables-------------------------------------------------- + +// static variables-------------------------------------------------- + +// const data-------------------------------------------------------- + + +#include // このソースはデフォルトではARMでコンパイルされる。 + +//----------------------------------------------------------------------- +// メインルーチンからのリターン +//----------------------------------------------------------------------- + +/* + ※ReturnFromMainをRamの後方にコピーする方法が、今はReturnFromMainアドレスから、 +   (BootFuncEnd - ReturnFromMain)サイズ分だけコピーとしているが、 +   この方法だと、コンパイラの最適化仕様で関数並びが変わってしまった時におかしくなる。 +   何か他にいい方法はないか? +*/ + + +asm void ReturnFromMain(void) +{ + //--------------------------------------- + // データキャッシュを全て無効に。(DC_InvalidateAllを抜き出して実装) + //--------------------------------------- + mov r0, #0 + mcr p15, 0, r0, c7, c6, 0 + + //--------------------------------------- + // ARM7との同期をとる(subp_stateが2になるのを待って、mainp_stateを2にする。) + //--------------------------------------- + ldr r1, =REG_SUBPINTF_ADDR +@0 ldrh r0, [r1] + and r0, r0, #0x000f + cmp r0, #0x0002 + bne @0 + mov r0, #0x0200 + strh r0, [r1] + + //--------------------------------------- + // ISデバッガ動作フラグの格納 + //--------------------------------------- +#ifdef __IS_DEBUGGER_BUILD + ldr r3, =HW_MAIN_MEM_EX_END + sub r0, r3, #0x400 + ldrh r11, [r0, #0x14] // r11 = GetMovedInfoFromIPL1Addr()->isOnDebugger +#endif + //--------------------------------------- + // ARM7との同期をとる(subp_stateが1になるのを待って、mainp_stateを1にする。) + //--------------------------------------- + ldr r1, =REG_SUBPINTF_ADDR +@1 ldrh r0, [r1] + and r0, r0, #0x000f + cmp r0, #0x0001 + bne @1 + mov r0, #0x0100 + strh r0, [r1] + + //--------------------------------------- + // バンクレジスタ&スタッククリア + //--------------------------------------- + bl ClearBankregAndStack + + //--------------------------------------- + // プロテクションユニットの解除 + //--------------------------------------- + bl ResetCP15 + + //--------------------------------------- + // ARM7との最終同期をとる(subp_stateが0になるのを待って、mainp_stateを0にする) + //--------------------------------------- + ldr r1, =REG_SUBPINTF_ADDR +@2 ldrh r0, [r1] + and r0, r0, #0x000f + cmp r0, #0x0001 + beq @2 + ldr r3, =REG_VCOUNT_ADDR // Vカウンタを全IPL2バージョンで同一値(=0)でアプリに引き渡すようにする。 +@3 ldrh r0, [r3] + cmp r0, #0 + bne @3 +// mov r0, #0 // R0に読んだVカウント値が"0"なので、これはいらない + strh r0, [r1] + + //--------------------------------------- + // R11の値をもとにブートアドレス取得 + //--------------------------------------- + ldr r3, =HW_MAIN_MEM_EX_END // ゲーム・エントリポイント 獲得 + ldr r12, [r3, #-(0x200 - 0x24)] // rmhp->arm9->entryAddr + mov lr, r12 + +#ifdef __IS_DEBUGGER_BUILD + cmp r11, #1 // if (!GetMovedInfoFromIPL1Addr()->isOnDebugger) + ldreq r12, [r3, #-(0x200 - 0x168)] // デバッガ・エントリポイント 獲得 +#endif + + //--------------------------------------- + // 汎用レジスタクリア + //--------------------------------------- + ldr r11, =INITi_HW_DTCM // クリアしたDTCMからデータを読み出して、汎用レジスタをクリアする。 + ldmia r11, {r0-r10} + mov r11, #0 + + //--------------------------------------- + // ゲームブート + //--------------------------------------- + bx r12 +} + + +//----------------------------------------------------------------------- +// システム制御コプロセッサ リセット +//----------------------------------------------------------------------- +asm void ResetCP15(void) +{ + // プロテクションユニット&キャッシュ&ITCM無効。DTCMは有効(スタックをクリアするため) + ldr r0, = C1_DTCM_ENABLE | C1_EXCEPT_VEC_UPPER | C1_SB1_BITSET + mcr p15, 0, r0, c1, c0, 0 + + // ITCMの割り当てを解除 + mov r0, #0 + mcr p15, 0, r0, c6, c5, 0 + + // DTCMの割り当てを解除 +// mov r0,#0 +// mcr p15, 0, r0, c9, c1, 0 + + // キャッシュ無効化 + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 // 命令キャッシュ + mcr p15, 0, r0, c7, c6, 0 // データキャッシュ + + // ライトバッファ エンプティ待ち + mcr p15, 0, r0, c7, c10, 4 + + bx lr +} + + +//----------------------------------------------------------------------- +// バンクレジスタ リセット & スタック領域 クリア +//----------------------------------------------------------------------- +asm void ClearBankregAndStack(void) +{ + mov r12, lr + +#ifndef IPL2_ONLYMULTIBOOT + mov r0, #0xc0 | HW_PSR_SVC_MODE // SVCモードへ切り換え & IRQ/FIQ不許可 + msr cpsr_cxsf, r0 + ldr r0, =INITi_HW_DTCM + add r0, r0, #0x3fc0 + mov sp, r0 // SP のセット + mov lr, #0 + msr spsr_csxf, lr + + mov r0, #0xc0 | HW_PSR_IRQ_MODE // IRQモードへ切り換え & IRQ/FIQ不許可 + msr cpsr_cxsf, r0 + ldr r0, =INITi_HW_DTCM + add r0, r0, #0x3fc0 + sub r0, r0, #HW_SVC_STACK_SIZE + mov sp, r0 // SP のセット + mov lr, #0 + msr spsr_cxsf, lr + + ldr r1, =SDK_IRQ_STACKSIZE + sub r1, r0, r1 + mov r0, #0xc0 | HW_PSR_SYS_MODE // システムモードへ切り換え & IRQ/FIQ不許可 + msr cpsr_cxsf, r0 + sub sp, r1, #4 // SP のセット & 4byte for stack check code +#endif // IPL2_ONLYMULTIBOOT + + ldr r0, =HW_ITCM // ITCMのクリア + mov r1, #HW_ITCM_SIZE + bl CpuClear32Byte + + ldr r0, =INITi_HW_DTCM // スタックを含めたDTCMのクリア + mov r1, #HW_DTCM_SIZE + bl CpuClear32Byte + + bx r12 +} + + +// 32byte単位のメモリクリア r0 dstp,r1 byteSize +asm void CpuClear32Byte(void) +{ + add r2, r0, r1 // 終了アドレスの算出 + mov r1, r1, lsr #5 // サイズは32byte単位 + mov r3, #0 + mov r4, r3 + mov r5, r3 + mov r6, r3 + mov r7, r3 + mov r8, r3 + mov r9, r3 + mov r10, r3 +@0 cmp r0, r2 // クリア終了? + stmltia r0!, {r3-r10} + blt @0 + bx lr +} + + +void BootFuncEnd(void) +{ +} +#include // ここまで。 + diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/ninLogoFunc.c b/build/libraries_sysmenu/sysmenu/ARM9/src/ninLogoFunc.c new file mode 100644 index 00000000..cb4387aa --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/ninLogoFunc.c @@ -0,0 +1,168 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: ninLogoFunc.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include + +// define data----------------------------------------------------------- + +// extern data----------------------------------------------------------- + +// function's prototype-------------------------------------------------- +static void UnCompNintendoLogo2(u16 *NintendoLogoDatap, u16 *dstp, u32 *temp); +static void SVC_DiffUnFilter16_16_2(u16 *srcp,u16 *dstp); +static s32 MEMBm_InitFunc(const u8 *devicep, void *ramp, const void *paramp); +static s32 MEMBm_TerminateFunc(const u8 *devicep); +static u8 MEMBm_ByteStreamFunc(const u8 *devicep); +static u32 MEMBm_WordStreamFunc(const u8 *devicep); + + +// global variable------------------------------------------------------- + +// static variable------------------------------------------------------- +static MIUnpackBitsParam Nin_UnPackBitsParam2 = { (8 * 8 / 2) * ( 7 * 2 ), 1, 4, 0, 0 }; + +// const data------------------------------------------------------------ +static const u8 Nin_Char_Diff_Huff_Table2[]={ + 0x24,0xd4,0x00,0x00, + 0x0f,0x40,0x00,0x00,0x00,0x01,0x81,0x82,0x82,0x83,0x0f,0x83,0x0c,0xc3,0x03,0x83, + 0x01,0x83,0x04,0xc3,0x08,0x0e,0x02,0xc2,0x0d,0xc2,0x07,0x0b,0x06,0x0a,0x05,0x09, +}; + + +const MIReadStreamCallbacks memb_ifp2={ + MEMBm_InitFunc, + MEMBm_TerminateFunc, + MEMBm_ByteStreamFunc, + NULL, + MEMBm_WordStreamFunc, +}; + + +// function's description-------------------------------------------- + +// Nintendoロゴデータの展開ルーチン(OBJ2Dマップモードで展開) +// ※tempBuffpには、0x700byte必要です。 +void SYSM_LoadNintendoLogo2D( u16 *ninLogoDatap, u16 *dstp, u16 color, u32 *tempBuffp ) +{ + u32 work[ 0x100 / sizeof(u32) ]; + + Nin_UnPackBitsParam2.destOffset = color - 1; + UnCompNintendoLogo2( ninLogoDatap, (u16 *)tempBuffp, work ); + MI_CpuCopyFast( (u16 *)( (u32)tempBuffp + 0 ), dstp + 0x0000 / sizeof(u16), 0x1a0 ); + MI_CpuCopyFast( (u16 *)( (u32)tempBuffp + 0x1a0), dstp + 0x0400 / sizeof(u16), 0x1a0 ); +} + + +void SYSM_LoadNintendoLogo1D( u16 *ninLogoDatap, u16 *dstp, u16 color, u32 *tempBuffp ) +{ + u32 work[ 0x100 / sizeof(u32) ]; + + Nin_UnPackBitsParam2.destOffset = color - 1; + UnCompNintendoLogo2( ninLogoDatap, (u16 *)tempBuffp, work ); + MI_CpuCopyFast( (u16 *)tempBuffp, dstp, 0x340 ); +} + +/* UnCompNintendoLogo2ワーク内訳 + + <配置先> dstp(0x700) temp(0x100) + + Nintendoロゴ+ヘッダ 0x0c0 + ハフマン展開バッファ 0x200 + ハフマン展開後のバッファ 0x0d0 + diff後のデータ 0x0d0 + UnpackBits後のデータ 0x700 + +*/ + +// Nintendoロゴ展開ルーチン (r0=ロゴ圧縮データ r1=展開先アドレス) +#include +static asm void UnCompNintendoLogo2(u16 *NintendoLogoDatap, u16 *dstp, u32 *temp) +{ + push {r0-r2,r4, lr} + + ldr r0, =Nin_Char_Diff_Huff_Table2 + mov r1, r2 // r1 <- temp + mov r4, r1 // r4 <- temp + mov r2, #36 + bl MIi_CpuCopy16 // Nintendoロゴの圧縮テーブル部分のみをコピーしてくる + + ldr r0, [sp, #0] // r0 <- NintendoLogoDatap + mov r2, #36 + add r1, r4, r2 // r1 <- temp + 36 + mov r2, #NINTENDO_LOGO_LENGTH + bl MIi_CpuCopy16 // NintendoLogoDatapからNintendoロゴデータ本体をコピーしてくる + + mov r0, r4 // r0 <- temp + ldr r1, [sp, #4] // r1 <- dstp + mov r2, #1 + lsl r2, r2, #8 + add r2, r2, r1 // r2 <- dstp + 0x100 + ldr r3, =memb_ifp2 // r3 <- memb_ifp2 + bl SVC_UncompressHuffmanFromDevice // ハフマン展開 + + ldr r0, [sp, #4] + ldr r2, =0x0000d082 + str r2, [r0,#0] + + mov r1, r4 // temp + bl SVC_DiffUnFilter16_16_2 // Diff展開 + + mov r0, r4 // temp + ldr r1, [sp, #4] // dstp + ldr r2, =Nin_UnPackBitsParam2 + bl SVC_UnpackBits // ビット展開 + + pop {r0-r2,r4, pc} +} + + +// 差分フィルタ展開システムコール(16Bit→16Bit) (r0=Srcp, r1=Destp) +static asm void SVC_DiffUnFilter16_16_2(u16 *srcp,u16 *dstp) +{ + swi 24 + bx lr +} +#include + + +// ============================================================================ +// バイトアクセス可能メモリ用アクセスルーチン群 +// ============================================================================ +static s32 MEMBm_InitFunc(const u8 *devicep, void *ramp, const void *paramp) +{ + #pragma unused(ramp) + if(paramp) return (s32)MEMBm_WordStreamFunc(devicep); + else return 0; +} + +static s32 MEMBm_TerminateFunc(const u8 *devicep) +{ + #pragma unused(devicep) + return 0; +} + +static u8 MEMBm_ByteStreamFunc(const u8 *devicep) +{ + return *devicep; +} + +static u32 MEMBm_WordStreamFunc(const u8 *devicep) +{ + return *(u32 *)devicep; +} diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/nitroSettingsEx.c b/build/libraries_sysmenu/sysmenu/ARM9/src/nitroSettingsEx.c new file mode 100644 index 00000000..8b24d576 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/nitroSettingsEx.c @@ -0,0 +1,582 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: nitroSettingsEx.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "spi.h" + +#ifndef USED_COMPONENT +#include +#endif + +// define data---------------------------------------------------------- + +#define NCD_EX_FORCE_ENABLE // このスイッチを定義すると、SYSMバージョンに関わらず強制的にNitroConfigDataExが有効になる。 + // ※実機上では、このフラグのON,OFFに関係なく正常動作するが、アプリビルドをデバッガや他実機で動作させる際に、ここがONでないとダメ。 + // 読み込まれていないNCDEXをリードして死亡してしまうので注意。 + +#define SAVE_COUNT_MAX 0x0080 // NitroConfigData.saveCountの最大値 +#define SAVE_COUNT_MASK 0x007f // NitroConfigData.saveCountの値の範囲をマスクする。(0x00-0x7f) +#define NCD_NOT_CORRECT 0x00ff // NITRO設定データが読み出されていない or 有効なものがないことを示す。 +#define NVRAM_RETRY_NUM 8 // NVRAMリトライ回数 + +// NVRAMステータスレジスタ値 +#define SR_WIP 0x01 // 0:READY 1:ライト、イレース中 +#define SR_WEN 0x02 // 0:ライト禁止 1:ライト許可 +#define SR_EER 0x20 // 1:イレースエラー発生(SANYO製FLASHのみ) + + +// NVRAM関連送信コマンドステート +static enum NvramCommState{ + COMM_READY = 0, + COMM_RD, + COMM_WE, + COMM_WR, + COMM_RDSR_WE, + COMM_RDSR_WR, + COMM_SRST +}NvramCommState; + + +// SYSMヘッダ情報 +typedef struct SYSMHeader { + u16 bm_arm9_rom_addr; + u16 bm_arm7_rom_addr; + u16 bm_crc16; + u16 ipl2_crc16; + u8 ipl2_key[4]; + u16 ipl2_arm9_rom_addr; + u16 ipl2_arm9_ram_addr; + u16 ipl2_arm7_rom_addr; + u16 ipl2_arm7_ram_addr; + u16 ipl2_arm9_romOffsetUnit:3; + u16 ipl2_arm9_ramOffsetUnit:3; + u16 ipl2_arm7_romOffsetUnit:3; + u16 ipl2_arm7_ramOffsetUnit:3; + u16 ipl2_arm7_ramSelect:1; + u16 ipl2_header_ver:3; + u16 ipl2_data_rom_addr; + union { + struct { + u8 timestamp[5]; // SYSMタイムスタンプ [0]:分,[1]:時,[2]:日,[3]:月,[4]:年 + u8 ipl2_type; // SYSMタイプ(nitroConfigData.hで定義のSYSM_TYPE...) + u8 rsv[2]; + } version; + u8 card_key[8]; + } info; + u16 ncd_rom_addr; + union { // SYSMHeader.info.version.type == SYSM_TYPE_I_DISPLAY_JAPANもしくは + u16 sys_rsv_rom_addr; // SYSMHeader.info.version.timestamp >= 0x0502280851(SYSM_TYPE_NORMAL 3rd.以降) + u16 font_bncmp_offset; // ならば、font_bncmp_offset, font_bnfr_offsetが有効。 + } rom_addr1; // ※なお、sys_rsv_rom_addr, app_rsv_rom_addrは、アドレスが変わったので + union { //  ここに入っている値は無効。ncd_rom_addrからの相対値で算出。 + u16 app_rsv_rom_addr; + u16 font_bnfr_offset; + } rom_addr2; + u16 ipl2_data_crc16; + + u8 pad[ 0x18 ]; // ※キャッシュラインに合わせるためのパディング。本来は必要なし。 + +} SYSMHeader; // 0x40bytes + + +// function's prototype------------------------------------------------- +static int NVRAMm_checkCorrectNCD(NCDStoreEx *ncdsp); +static BOOL NCD_CheckDataValue( NCDStoreEx *ncdsp ); +static BOOL NVRAMm_ExecuteCommand( int nv_state, u32 addr, u16 size, u8 *srcp ); +static void Callback_NVRAM(PXIFifoTag tag, u32 data, BOOL err); + +// const data----------------------------------------------------------- + +// global variables----------------------------------------------------- +NitroConfigDataEx ncdEx; + +// static variables----------------------------------------------------- +static volatile BOOL nv_cb_occurred; +static volatile u16 nv_result; +static u16 ena_ncd_num = NCD_NOT_CORRECT; +static u16 next_saveCount; +static NCDStoreEx ncds[2] ATTRIBUTE_ALIGN(32); + +#ifdef USED_COMPONENT +static SYSMHeader ipl2Header ATTRIBUTE_ALIGN(32); +static BOOL read_ipl2h = FALSE; +#endif + + +// function's description----------------------------------------------- + +//---------------------------------------------------------------------- +// SYSMヘッダ情報の読み出し +//---------------------------------------------------------------------- +#ifndef USED_COMPONENT +// SYSM上での使用時 + +// SYSMタイプの取得 +#define NCD_GetSYSMType() ( (u32)GetSYSMWork()->ipl2_type ) + +// NCD格納ROMアドレスの取得 +#define NCD_GetNCDRomAddr() ( (u32)GetSYSMWork()->ncd_rom_adr ) + +#else +// コンポーネント上での使用時 + +// SYSMヘッダの読み出し +void NCD_ReadSYSMHeader( void ) +{ + if( !read_ipl2h ) { + OS_TPrintf( "SYSMHeader:%x\n", sizeof(SYSMHeader) ); + DC_InvalidateRange( &ipl2Header, sizeof(SYSMHeader) ); + while( !NVRAMm_ExecuteCommand( COMM_RD, 0, sizeof(SYSMHeader), (u8 *)&ipl2Header ) ) {} + read_ipl2h = TRUE; + } +} + +// SYSMタイプの取得 +u8 NCD_GetSYSMType( void ) +{ + NCD_ReadSYSMHeader(); + return ipl2Header.info.version.ipl2_type; +} + +// SYSMバージョンの取得 +u8 *NCD_GetSYSMVersion( void ) +{ + NCD_ReadSYSMHeader(); + return ipl2Header.info.version.timestamp; +} + +// NCD格納ROMアドレスの取得 +u32 NCD_GetNCDRomAddr( void ) +{ + NCD_ReadSYSMHeader(); + return (u32)( ipl2Header.ncd_rom_addr << NCD_ROM_ADDR_SHIFT ); +} + +// システム予約領域ROMアドレスの取得 +u32 NCD_GetSysRsvRomAddr( void ) +{ + NCD_ReadSYSMHeader(); + return (u32)( ipl2Header.ncd_rom_addr << NCD_ROM_ADDR_SHIFT ) - NCD_SYS_RSV_SIZE; +} + +// アプリ予約領域ROMアドレスの取得 +u32 NCD_GetAppRsvRomAddr( void ) +{ + NCD_ReadSYSMHeader(); + return (u32)( ipl2Header.ncd_rom_addr << NCD_ROM_ADDR_SHIFT ) - NCD_SYS_RSV_SIZE - NCD_APP_RSV_SIZE; +} + +// SYSMデータ格納ROMアドレスの取得 +u32 NCD_GetSYSMDataRomAddr( void ) +{ + NCD_ReadSYSMHeader(); + return (u32)( ipl2Header.ipl2_data_rom_addr << NCD_ROM_ADDR_SHIFT ); +} + +// bncmpフォントデータ格納ROMアドレスの取得 +u32 NCD_GetFontBncmpRomAddr( void ) +{ + NCD_ReadSYSMHeader(); + return (u32)( ipl2Header.rom_addr1.font_bncmp_offset << FONT_ROM_ADDR_SHIFT ); +} + +// bnfrフォントデータ格納ROMアドレスの取得 +u32 NCD_GetFontBnfrRomAddr( void ) +{ + NCD_ReadSYSMHeader(); + return (u32)( ipl2Header.rom_addr2.font_bnfr_offset << FONT_ROM_ADDR_SHIFT ); +} +#endif + + +//---------------------------------------------------------------------- +// NITRO設定データのリード +//---------------------------------------------------------------------- +int NVRAMm_ReadNitroConfigData(NitroConfigData *dstp) +{ + int result = 0; + NCDStoreEx *ncdsp = &ncds[ 0 ]; + + DC_InvalidateRange( ncdsp, sizeof(NCDStoreEx) * 2 ); + + // フラッシュからニ重化されているNITRO設定データを読み出す。 + while( !NVRAMm_ExecuteCommand( COMM_RD, NCD_GetNCDRomAddr(), sizeof(NCDStoreEx), (u8 *)&ncdsp[0]) ) {} + while( !NVRAMm_ExecuteCommand( COMM_RD, NCD_GetNCDRomAddr() + SPI_NVRAM_PAGE_SIZE, sizeof(NCDStoreEx), (u8 *)&ncdsp[1]) ) {} + OS_TPrintf("NCD read addr=%08x\n", NCD_GetNCDRomAddr() ); + + // 読み出したデータのどちらが有効かを判定する。 + if(NVRAMm_checkCorrectNCD(ncdsp)) { + next_saveCount = 1; + result = 1; + goto END; // 有効なデータがなければエラー終了。 + } + next_saveCount = (u8)((ncdsp[ena_ncd_num].saveCount + 1) & SAVE_COUNT_MASK); + + // 有効なNITRO設定データをバッファに転送 + if(dstp!=NULL) { + SVC_CpuCopy( (void *)&ncdsp[ ena_ncd_num ].ncd, (void *)dstp, sizeof(NitroConfigData), 16); + SVC_CpuCopy( (void *)&ncdsp[ ena_ncd_num ].ncd_ex, (void *)&ncdEx, sizeof(NitroConfigDataEx), 16); + } + +END: + return result; +} + + +//---------------------------------------------------------------------- +// NITRO設定データのライト +//---------------------------------------------------------------------- +void NVRAMm_WriteNitroConfigData( NitroConfigData *srcp ) +{ + NCDStoreEx *ncdsp = &ncds[ 0 ]; + u16 size = sizeof(NCDStore); + u32 flash_addr; + int retry; + + // まだNITRO設定データがリードされていなければ、リードを行って必要な情報を取得する。 + if( ena_ncd_num == NCD_NOT_CORRECT ) { + if( NVRAMm_ReadNitroConfigData( NULL ) ) { + ena_ncd_num = 0; // 有効なデータがなければ"0"側にライトする。 + } + } + + // NCD のCRC、セーブカウント値、ライトアドレスの算出。 + ncdsp->ncd = *srcp; // *GetNCDWork(); でも一緒やん。 + ncdsp->ncd.version = NITRO_CONFIG_DATA_VERSION; // バージョンを現在のものに設定。 + ncdsp->crc16 = SVC_GetCRC16( 0xffff, (const void *)&ncdsp->ncd, sizeof(NitroConfigData) ); + ncdsp->saveCount = next_saveCount; + next_saveCount = (u8)( ( next_saveCount + 1 ) & SAVE_COUNT_MASK ); + + // NCD_EXのCRC算出。 +#ifndef NCD_EX_FORCE_ENABLE + if( ( NCD_GetSYSMType() != SYSM_TYPE_NTR_WW ) && ( NCD_GetSYSMType() & SYSM_TYPE_NCD_EX_FLAG ) ) +#endif + { + ncdsp->ncd_ex = *GetNCDExWork(); + ncdsp->ncd_ex.version = NITRO_CONFIG_DATA_EX_VERSION; // バージョンを現在のものに設定。 + ncdsp->crc16_ex = SVC_GetCRC16( 0xffff, (const void *)&ncdsp->ncd_ex, sizeof(NitroConfigDataEx) ); + size = sizeof(NCDStoreEx); // ※書き込みサイズをNCDStoreExに拡張。 + } + + // NITRO設定データのライト + DC_FlushRange(ncdsp, sizeof(NCDStoreEx)); + retry = NVRAM_RETRY_NUM; + while( retry-- ) { + ena_ncd_num ^= 0x01; // リトライの度に書き込みアドレスを切り替える。 + flash_addr = NCD_GetNCDRomAddr() + ena_ncd_num * SPI_NVRAM_PAGE_SIZE; + OS_TPrintf("NCD write addr=%08x\n", flash_addr ); + + if( NVRAMm_ExecuteCommand( COMM_WE, flash_addr, size, (u8 *)ncdsp) ) { + OS_TPrintf("NVRAM Write succeeded.\n"); + break; + } + SVC_WaitByLoop( 0x4000 ); + OS_TPrintf("NVRAM Write retry = %d.\n", NVRAM_RETRY_NUM - retry ); + } +} + + +//---------------------------------------------------------------------- +// ミラーリングされているNITRO設定データのどちらが有効かを判定 +//---------------------------------------------------------------------- + +static int NVRAMm_checkCorrectNCD(NCDStoreEx *ncdsp) +{ + u16 i; + u16 ncd_valid = 0; + + // 各ミラーデータのCRC & saveCount正当性チェック + for(i = 0; i < 2; i++) { + u16 crc; + BOOL invalid = FALSE; + + crc = SVC_GetCRC16( 0xffff, (const void *)&ncdsp[i].ncd, sizeof(NitroConfigData) ); + + if( ( ncdsp[ i ].crc16 != crc ) // CRCが正しく、saveCount値が0x80以下で、かつバージョンが一致するデータを正当と判断。 + || ( ncdsp[ i ].ncd.version != NITRO_CONFIG_DATA_VERSION ) + || ( ncdsp[ i ].saveCount >= SAVE_COUNT_MAX ) ) { + OS_TPrintf("NCD crc error.\n"); + invalid = TRUE; + } + + // NCDExが有効なSYSMTypeならば、NCDExのCRCチェックを行う。 +#ifndef NCD_EX_FORCE_ENABLE + if( ( NCD_GetSYSMType() != SYSM_TYPE_NTR_WW ) && ( NCD_GetSYSMType() & SYSM_TYPE_NCD_EX_FLAG ) ) +#endif + { + crc = SVC_GetCRC16( 0xffff, (const void *)&ncdsp[i].ncd_ex, sizeof(NitroConfigDataEx) ); + + if( ( ncdsp[ i ].crc16_ex != crc ) + || ( ncdsp[ i ].ncd_ex.version != NITRO_CONFIG_DATA_EX_VERSION ) ) { + OS_TPrintf("NCDEx crc error.\n"); + invalid = TRUE; + } + } + // NCD, NCDExのCRCが正しいなら、データの中身をチェック。 + if( !invalid ) { + if( NCD_CheckDataValue( &ncdsp[ i ] ) ) { + ncd_valid |= 0x01 << i; // データがおかしい値でないかもチェック。 + ena_ncd_num = i; // 有効なNCDのインデックスを切り替える。 + }else { + invalid = TRUE; + } + } + + if( ncd_valid & ( 0x01 << i ) ) { + OS_TPrintf("NCD mirror%d is valid.:saveCount = %d\n", i, ncdsp[i].saveCount); + }else { + OS_TPrintf("NCD mirror%d is invalid.\n", i); + } + } + + + if( ncd_valid == 0 ) { + return 1; + }else if( ncd_valid == 0x03 ) { + // ミラーリングされたNCDが両方ともに正当な場合、セーブカウント値が大きい方を有効とする。 + u16 saveCount = (u8)( ( ncdsp[ 0 ].saveCount + 1 ) & SAVE_COUNT_MASK ); + if( saveCount != ncdsp[ 1 ].saveCount ) { + ena_ncd_num = 0; + } + } + + OS_TPrintf("use NCD mirror%d.:saveCount = %d\n", ena_ncd_num, ncdsp[ena_ncd_num].saveCount); + + return 0; +} + + +// NITRO設定データの値が正しい値かチェック。 // FALSE:正しくない。TRUE:正しい。 +static BOOL NCD_CheckDataValue( NCDStoreEx *ncdsp ) +{ + NitroConfigData *ncdp = &ncdsp->ncd; + NitroConfigDataEx *ncdexp = &ncdsp->ncd_ex; + + //ncdp->option; + // NCDのlanguageチェック + if( ~( LANG_BITMAP_WW & VALID_LANG_BITMAP ) & ( 0x0001 << ncdp->option.language ) ) { + OS_TPrintf("NCD: invalid language : org:%02d ex:%02d bitmap:%04x\n", + ncdp->option.language, ncdexp->language, ncdexp->valid_language_bitmap ); + return FALSE; + } + // NCDExのlanguageチェック(NCDExが有効なのは、下記のSYSMタイプのもの) +#ifndef NCD_EX_FORCE_ENABLE + if( ( NCD_GetSYSMType() != SYSM_TYPE_NTR_WW ) && ( NCD_GetSYSMType() & SYSM_TYPE_NCD_EX_FLAG ) ) +#endif + { + if( ( ~VALID_LANG_BITMAP & ( 0x0001 << ncdexp->language ) ) + || ( ncdexp->valid_language_bitmap != VALID_LANG_BITMAP ) ) { + + OS_TPrintf("NCDEx: invalid language : org:%02d ex:%02d bitmap:%04x\n", + ncdp->option.language, ncdexp->language, ncdexp->valid_language_bitmap ); + return FALSE; + } + } + + //ncdp->owner; + // favoriteColorは4bitなので範囲外はない。 + // birthday + if( ncdp->option.input_birthday ) { + if( ( ncdp->owner.birthday.month > 12 ) || ( ncdp->owner.birthday.day > 31 ) ) { + OS_TPrintf("NCD: invalid birthday : %02d/%02d\n", ncdp->owner.birthday.month, ncdp->owner.birthday.day ); + return FALSE; + } + } + + // nickname + if( ncdp->option.input_nickname ) { + if( ncdp->owner.nickname.length > NCD_NICKNAME_LENGTH ) { + OS_TPrintf("NCD: invalid nickname length : %02d\n", ncdp->owner.nickname.length ); + return FALSE; + } + } + + // comment + if( ncdp->owner.comment.length > NCD_COMMENT_LENGTH ) { + OS_TPrintf("NCD: invalid comment length : %02d\n", ncdp->owner.comment.length ); + return FALSE; + } + + //ncdp->alarm; + if( ( ncdp->alarm.hour > 23 ) || ( ncdp->alarm.minute > 59 ) ) { + OS_TPrintf("NCD: invalid alarm time : %02d:%02d\n", ncdp->alarm.hour, ncdp->alarm.minute ); + return FALSE; + } + + //ncdp->tp; + // TPキャリブレーション値は、TP_CalcCalibrateParamで値のチェックをしているので、チェックしない。 + + OS_TPrintf( "NCD: correct data.\n" ); + return TRUE; +} + + +//---------------------------------------------------------------------- +// NVRAMへのアクセスルーチン本体 ( nv_state <- COMM_RD or COMM_WE ) +//---------------------------------------------------------------------- +static BOOL NVRAMm_ExecuteCommand( int nv_state, u32 addr, u16 size, u8 *srcp ) +{ + OSTick start; + BOOL nv_sending = FALSE; + u8 *nvram_srp = (u8 *)&ncds[1]; + + PXI_SetFifoRecvCallback( PXI_FIFO_TAG_NVRAM , Callback_NVRAM ); + + while( 1 ) { + //--------------------------------------- + // NVRAMコマンドを発行する + //--------------------------------------- + if( !nv_sending ) { + + nv_cb_occurred = FALSE; + + switch( nv_state ) { + case COMM_RD: + nv_sending = SPI_NvramReadDataBytes( addr, size, srcp ); + break; + + case COMM_WE: + nv_sending = SPI_NvramWriteEnable(); + break; + + case COMM_WR: + nv_sending = SPI_NvramPageWrite( addr, size , srcp ); + start = OS_GetTick(); + break; + + case COMM_RDSR_WE: + case COMM_RDSR_WR: + nv_sending = SPI_NvramReadStatusRegister( nvram_srp ); + break; + + case COMM_SRST: + nv_sending = SPI_NvramSoftwareReset(); + break; + } + //--------------------------------------- + // コマンド実行結果(コールバック発生)を待って結果を処理する + //--------------------------------------- + }else { // nv_sending == TRUE + if( nv_cb_occurred == TRUE ) { // コールバック発生を待つ。 + + nv_sending = FALSE; + + if( nv_result == SPI_PXI_RESULT_SUCCESS ) { + switch( nv_state ) { + case COMM_RD: + return TRUE; + + case COMM_WE: + nv_state = COMM_RDSR_WE; + break; + + case COMM_WR: + nv_state = COMM_RDSR_WR; + break; + + case COMM_RDSR_WE: + case COMM_RDSR_WR: + + DC_InvalidateRange( nvram_srp, 1 ); + + if( nv_state == COMM_RDSR_WE ) { // ライトイネーブル確認ステートなら + if( ( *nvram_srp & SR_WEN ) ) { + nv_state = COMM_WR; + }else { + OS_TPrintf("NVRAM ERR: Write Enable Invalid.\n"); + return FALSE; + } + }else { + if( ( *nvram_srp & SR_WIP ) == 0 ) { // ライト/イレース終了 + return TRUE; + }else { + if( ( *nvram_srp & SR_EER ) // SR_EERが立っていたらエラー + || ( OS_TicksToMilliSeconds( OS_GetTick() - start ) > 4000 ) ) { + // コマンド発行から4秒経過したらエラー(※保険) + OS_TPrintf( "NVRAM SR : %02x\n", *nvram_srp ); + nv_state = COMM_SRST; + }else { + SVC_WaitByLoop( 0x4000 ); + } + } + } + break; + + case COMM_SRST: + OS_TPrintf("NVRAM ERR: PageErase Timeout and SoftReset.\n"); + return FALSE; + } + }else { // nv_result != SPI_PXI_RESULT_SUCCESS + OS_TPrintf("NVRAM ERR: NVRAM PXI command failed.\n"); + return FALSE; + } + } + } + } +} + + +//---------------------------------------------------------------------- +// コールバック +//---------------------------------------------------------------------- +static void Callback_NVRAM( PXIFifoTag tag, u32 data, BOOL err ) +{ + #pragma unused(tag) + + u16 command = (u16)( ( ( data & SPI_PXI_DATA_MASK ) & 0x7f00 ) >> 8 ); + + nv_result = (u16)( data & 0x00ff ); + nv_cb_occurred = TRUE; // コールバック発生フラグTRUE + + if( err ) { + OS_TPrintf("NVRAM-ARM9: Received PXI data is error.\n"); + nv_result = 0x00ff; + } + + switch(command){ // コマンド名表示 + case SPI_PXI_COMMAND_NVRAM_READ: + OS_TPrintf("NVRAM-ARM9:ReadDataBytes"); + break; + case SPI_PXI_COMMAND_NVRAM_WREN: + OS_TPrintf("NVRAM-ARM9:WriteEnable"); + break; + case SPI_PXI_COMMAND_NVRAM_PW: + OS_TPrintf("NVRAM-ARM9:PageWrite"); + break; + case SPI_PXI_COMMAND_NVRAM_RDSR: + OS_TPrintf("NVRAM-ARM9:ReadStatusRegister"); + break; + case SPI_PXI_COMMAND_NVRAM_WRDI: + OS_TPrintf("NVRAM-ARM9:WriteDisable"); + break; + case SPI_PXI_COMMAND_NVRAM_PE: + OS_TPrintf("NVRAM-ARM9:PageErase"); + break; + case SPI_PXI_COMMAND_NVRAM_SR: + OS_TPrintf("NVRAM-ARM9:SoftwareReset"); + break; + default: + OS_TPrintf("NVRAM-ARM9:?????"); + break; + } + if( nv_result != SPI_PXI_RESULT_SUCCESS ) { + OS_TPrintf(" Error! ->%x", nv_result ); + } + OS_TPrintf("\n"); +} + diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_card.c b/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_card.c new file mode 100644 index 00000000..1bc09cdb --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_card.c @@ -0,0 +1,253 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: SYSM_card.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "sysmenu_card.h" + + +typedef enum { + CARD_NOT_DETECTING = 0, + CARD_DETECTING +} CARDPullStatus; + + +typedef struct SYSMCardPullWork +{ + CARDPullStatus pullStatus; + u32 cardCnt; + u16 lockID; + u16 detectPullOut; + +} SYSMCardPullWork; + + +static SYSMCardPullWork cpw; + + +// 内部関数 +void SYSMi_InitCardPulledOut(void); +BOOL SYSMi_IsDetectableCardPulledOut(void); +void SYSMi_StartReadCardID(void); +void SYSMi_ReadCardPage(void *romp, void *ramp, s32 size); +static void SYSMi_SetCardOp(const u32 *op); + + +//---------------------------------------------------------------------- +// カード抜け検出初期化 +//---------------------------------------------------------------------- + +void SYSMi_InitCardPulledOut(void) +{ + cpw.lockID = (u16 )OS_GetLockID(); + cpw.cardCnt = *(vu32 *)MROMCNT_GAME_BUF; +} + + +//---------------------------------------------------------------------- +// カード抜け検出 +//---------------------------------------------------------------------- + +BOOL SYSM_IsCardPulledOut(void) +{ + if (SYSMi_IsDetectableCardPulledOut() == FALSE) return FALSE; + + switch (cpw.pullStatus) { + case CARD_NOT_DETECTING: + if (OS_TryLockCard( cpw.lockID ) == OS_LOCK_SUCCESS ) + { + SYSMi_StartReadCardID(); + cpw.pullStatus = CARD_DETECTING; + } + break; + + case CARD_DETECTING: + if (SYSMi_IsCardDataReady()) { + u32 cardID = *(vu32 *)REG_CARD_DATA; + if (cardID != GetSYSMWork()->nCardID + && SYSM_IsNITROCard()) + { + cpw.detectPullOut = TRUE; + } + + (void)OS_UnlockCard( cpw.lockID ); + cpw.pullStatus = CARD_NOT_DETECTING; + } + break; + } + + return cpw.detectPullOut; +} + + +//---------------------------------------------------------------------- +// カード抜け検出終了処理 +//---------------------------------------------------------------------- + +void SYSM_FinalizeCardPulledOut(void) +{ + while (SYSM_IsDetectingCardPulledOut()) { + (void)SYSM_IsCardPulledOut(); + } +} + + +//---------------------------------------------------------------------- +// カード抜け検出処理中か +//---------------------------------------------------------------------- + +BOOL SYSM_IsDetectingCardPulledOut(void) +{ + return (cpw.pullStatus == CARD_DETECTING); +} + + +//---------------------------------------------------------------------- +// カード抜け検出の準備ができているか +//---------------------------------------------------------------------- + +BOOL SYSMi_IsDetectableCardPulledOut(void) +{ + return (SYSM_GetBootFlag() & BFLG_LOAD_CARD_COMPLETED ) ? TRUE : FALSE; +} + + +//---------------------------------------------------------------------- +// カードID読み込み開始 +//---------------------------------------------------------------------- + +void SYSMi_StartReadCardID(void) +{ + u32 op[2]; + + op[0] = 0; // コマンド設定 + op[1] = MROMOP_G_READ_ID; + + SYSMi_SetCardOp( op ); + // コントロール設定 + *(vu32 *)REG_CARDCNT = cpw.cardCnt + | CARD_READ_MODE | CARD_STATUS + | CARD_START | CARD_RESET_HI; +} + + +//---------------------------------------------------------------------- +// カードID読み込み +//---------------------------------------------------------------------- + +u32 SYSMi_ReadCardID(void) +{ + u32 op[2]; + + op[0] = 0; // コマンド設定 + op[1] = MROMOP_G_READ_ID; + + SYSMi_SetCardOp( op ); + // コントロール設定 + *(vu32 *)REG_CARDCNT = *(vu32 *)MROMCNT_GAME_BUF + | CARD_READ_MODE | CARD_STATUS + | CARD_START | CARD_RESET_HI; + + SYSMi_WaitCardData(); + + return *(vu32 *)REG_CARD_DATA; +} + + +//---------------------------------------------------------------------- +// カードデータ同期読み込み +//---------------------------------------------------------------------- + +void SYSM_ReadCard(void *romp, void *ramp, s32 size) +{ + s32 restSize = size; + s32 blockSize = MROM_PAGE_SIZE; + + while (restSize > 0) { // ブロック分割読み込み + if (restSize >= MROM_PAGE_SIZE) { size = MROM_PAGE_SIZE; + } else { size = restSize; + } + + SYSMi_ReadCardPage(romp, ramp, size); + + (u8 *)romp += size; + (u8 *)ramp += size; + restSize -= size; + } +} + + +//---------------------------------------------------------------------- +// ページ読み込み +//---------------------------------------------------------------------- + +void SYSMi_ReadCardPage(void *romp, void *ramp, s32 size) +{ + { u32 op[2]; + + op[0] = (u32 )romp <<24; // コマンド設定 + op[1] = MROMOP_G_READ_PAGE | (u32 )romp >>8; + + SYSMi_SetCardOp( op ); + } + + // ページリード + { void *ramEndp; + u32 cardCntTmp; + + *(vu32 *)REG_CARDCNT = *(vu32 *)MROMCNT_GAME_BUF // コントロール設定 + | CARD_READ_MODE | CARD_1_PAGE + | CARD_START | CARD_RESET_HI; + + ramEndp = (u8 *)ramp + size; // 格納終了アドレス算出 + + do { // CPU読み込み + cardCntTmp = *(vu32 *)REG_CARDCNT; + + if (cardCntTmp & CARD_DATA_READY) { + u32 dataTmp = *(vu32 *)REG_CARD_DATA; + + if (ramp < ramEndp) + *((vu32 *)ramp) = dataTmp; // 指定サイズまで格納(後続データは読み捨て) + ((vu32 *)ramp)++; + } + } while (cardCntTmp & CARD_START); + } +} + + +//---------------------------------------------------------------------- +// コマンド設定 +//---------------------------------------------------------------------- + +static void SYSMi_SetCardOp(const u32 *op) +{ + int i; + + *(vu8 *)REG_CARD_MASTER_CNT = CARDMST_SEL_ROM // マスターイネーブル + | CARDMST_ENABLE; + + for (i=0; i<2; i++) { // コマンド設定 + u32 opTmp = op[1 - i]; + vu8 *opDestBasep = (vu8 *)(REG_CARD_CMD + i*4); + + opDestBasep[0] = (u8 )(opTmp >>24); + opDestBasep[1] = (u8 )(opTmp >>16); + opDestBasep[2] = (u8 )(opTmp >>8); + opDestBasep[3] = (u8 )(opTmp >>0); + } +} + diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_lib.c b/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_lib.c new file mode 100644 index 00000000..4d138dc2 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_lib.c @@ -0,0 +1,721 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: SYSM_lib.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "sysmenu_define.h" +#include "sysmenu_card.h" +#include "spi.h" +#include "mb_child.h" + +// define data----------------------------------------------------------------- + +#define SCREEN_RED 0 +#define SCREEN_YELLOW 1 + +typedef struct BannerCheckParam { + u8 *srcp; + u32 size; +}BannerCheckParam; + + +typedef struct TitleProperty { // この情報は、ランチャー時には認証通ってないけど、起動時には認証通すので大丈夫だろう。 + u64 titleID; // アプリケーション識別ID + u32 platform; // NTR, TWL (HYBLIDはTWLを返す) + void *pBanner; // 固定長フォーマットなら偽造されても大丈夫だろう。 +}TitleProperty; + +typedef enum AuthState { + AUTH_PROCESSING = 0, + AUTH_RESULT_SUCCEEDED = 1, + AUTH_RESULT_TITLE_POINTER_ERROR = 2, + AUTH_RESULT_AUTHENTICATE_FAILED = 3, + AUTH_RESULT_ENTRY_ADDRESS_ERROR = 4 +}AuthState; + +// extern data----------------------------------------------------------------- +extern void ReturnFromMain( void ); +extern void BootFuncEnd( void ); + +FS_EXTERN_OVERLAY( ipl2_data ); +FS_EXTERN_OVERLAY( bm_mainp ); + +// function's prototype------------------------------------------------------- +static BOOL SYSMi_CheckTitlePointer( TitleProperty *pBootTitle ); +AuthState SYSM_AuthAndLoadTitle( TitleProperty *pBootTitle ); +void SYSM_Finalize( void ); + + +static void INTR_SubpIRQ( void ); + +static void SYSMi_CheckCardLoadAddressAndSize( void ); +static void LoadRomRegSizeAdjust( CARDRomRegion *romRegp, u32 load_limit_lo, u32 load_limit_hi ); +static void SYSMi_ReadyBootNitroGame( void ); +static BOOL SYSMi_CheckARM7LoadNITROCard( void ); +static void SYSMi_MainpRegisterAndRamClear( BOOL isPlatformTWL ); +static void ClearMemory( int addr1, int addr2 ); + +static void SYSMi_CopyInfoFromIPL1( void ); + +static void SYSMi_ReadNTRSetting( void ); +static void SYSMi_ReadTWLSetting( void ); +static void SYSMi_VerifyNTRSetting( void ); +static void SYSMi_CheckEntryAddress( void ); +static void SYSMi_CaribrateTP( void ); +static void SYSMi_WriteAdjustRTC( void ); +static BOOL SYSMi_SendMessageToARM7( u32 msg ); +static BOOL SYSMi_CheckNitroCardRightly( void ); +static int SYSMi_ExistCard( void ); +static u32 SYSMi_SelectBootType( void ); +static void SYSMi_DispInitialDebugData( void ); +static void SYSMi_DispDebugData( void ); + +static void DispSingleColorScreen( int mode ); + +static void SYSMi_ReadCardBannerFile( void ); +static void SYSMi_CheckCardCloneBoot( void ); + + +// global variable------------------------------------------------------------- +#ifdef __SYSM_DEBUG +SharedWork *swp; // デバッガでのIPL1SharedWorkのウォッチ用 +SYSM_work *pSysm; // デバッガでのSYSMワークのウォッチ用 +NitroConfigData *ncdp; // デバッガでのNCデータ のウォッチ用 +#endif + +// static variable------------------------------------------------------------- +static BOOL s_isBanner = FALSE; +static BannerFile s_bannerBuf; + +// const data------------------------------------------------------------------ + +static BannerCheckParam s_bannerCheckList[ BNR_VER_MAX ] = { + { (u8 *)&s_bannerBuf.v1, sizeof( BannerFileV1 ) }, + { (u8 *)&s_bannerBuf.v2, sizeof( BannerFileV2 ) }, + { (u8 *)&s_bannerBuf.v3, sizeof( BannerFileV3 ) }, +}; + +#ifdef __DEBUG_SECURITY_CODE +static GXRgb security_detection_color[] = { GX_RGB( 31, 0, 0 ), + GX_RGB( 31, 31, 0 ), }; +#endif + +// inline functions------------------------------------------------------------ + +static inline void DBG_SetRed(u32 y_pos) +{ + *(u16 *)(HW_DB_BG_VRAM + 0xf000 + 0x20*2*y_pos) = (1<<12) | 0x100; + MI_CpuFill16(((u8 *)HW_DB_BG_VRAM + 0x20*0x100), 0x1111, 0x20); +} + +// ============================================================================ +// function's description +// ============================================================================ + +// SystemMenuの初期化 +void SYSM_Init( void ) +{ +#ifdef __SYSM_DEBUG + pSysm = GetSYSMWork(); + ncdp = GetNCDWork(); +// SYSMi_DispInitialDebugData(); // 初期デバッグ情報表示 +#endif /* __SYSM_DEBUG */ + + // WRAM設定はいる? +// MI_SetMainMemoryPriority(MI_PROCESSOR_ARM7); +// MI_SetWramBank(MI_WRAM_ARM7_ALL); + + SVC_CpuClearFast(0x0000, (u16 *)GetSYSMWork(), sizeof(SYSM_work)); // SYSMワークのクリア + + // ※ISデバッガかどうかの判定。 BootROMからのパラメータ引渡し? +} + + +// ARM7側の初期化待ち +BOOL SYSM_WaitARM7Init( void ) +{ +/* while( !( SYSM_GetBootFlag() & BFLG_ARM7_INIT_COMPLETED ) ) { + SVC_WaitByLoop(0x1000); // ARM7の初期化が終了するのを待つ。 + } +*/ + reg_OS_PAUSE |= REG_OS_PAUSE_CHK_MASK; // PAUSEレジスタのチェックフラグのセット + + SYSMi_ReadNTRSetting(); // NOR からNTR本体設定データをリード + SYSMi_ReadTWLSetting(); // NANDからTWL本体設定データをリード + PMm_SetBackLightBrightness(); + SYSMi_CaribrateTP(); // 読み出したTWL本体設定データをもとにTPキャリブレーション。 + SYSMi_WriteAdjustRTC(); // 読み出したTWL本体設定データをもとにRTCクロック補正値をセット。 + + SYSMi_VerifyNTRSetting(); // NVRAMのNTR本体設定データをリードし、不一致箇所があればNTR側をリカバリ。 + + SYSMi_CheckCardCloneBoot(); // カードがクローンブートかチェック + SYSMi_ReadCardBannerFile(); // カードバナーファイルの読み出し。 + + // ============================================================== + // デバッガ対応コード +#ifdef __IS_DEBUGGER_BUILD + if( GetSYSMWork()->isOnDebugger ) { + if( !SYSM_IsDebuggerBannerViewMode() ){ // デバッガ上動作の場合は、この中でカードブートまでやってしまう。 + + ( void )OS_EnableIrqMask( OS_IE_V_BLANK ); + ( void )OS_EnableIrq(); + ( void )OS_EnableInterrupts(); + ( void )GX_VBlankIntr( TRUE ); + + if( SYSMi_ExistCard() ) { + ( void )SYSM_Main(); + SYSM_SetBootFlag( BFLG_BOOT_CARD ); + ( void )SYSM_BootCARD(); + SYSM_PermitToBootSelectedTarget(); + while(1) { + OS_WaitIrq( 1, OS_IE_V_BLANK ); // Vブランク割込終了待ち + if( SYSM_Main() ) { // システムのメイン + return TRUE; // TRUEが帰ってきたらメインループからリターン(カード起動) + } + } + } + } + }else { + while( 1 ) {} // ISデバッガビルドでISデバッガが検出できなかったら停止。 + } +#endif // __IS_DEBUGGER_BUILD + // ============================================================== + + return FALSE; +} + + +// 指定タイトルがブート可能なポインタかチェック +static BOOL SYSMi_CheckTitlePointer( TitleProperty *pBootTitle ) +{ +#pragma unused( pBootTitle ) + + return TRUE; +} + + +// 指定タイトルの認証&ロード ※1フレームじゃ終わらん。 +AuthState SYSM_AuthAndLoadTitle( TitleProperty *pBootTitle ) +{ +#pragma unused( pBootTitle ) + // メインメモリのクリア + // DSダウンロードプレイの時は、ROMヘッダを退避する + // アプリロード + // アプリ認証 + + // エントリアドレスの正当性をチェックし、無効な場合は無限ループに入る。 + SYSMi_CheckEntryAddress(); + + return AUTH_RESULT_SUCCEEDED; +} + + +// ブートのための終了処理 +void SYSM_Finalize( void ) +{ + // ARM7へのブート通知 + // レジスタ・RAMクリア + + // ※ブート時にプロテクションユニットをOFFにしなければ、不正なアドレスでの起動を防げるのでは? + + u32 i; + + // ブートの前準備 + MI_CpuCopyFast( (void *)ReturnFromMain, (void *)RETURN_FROM_MAIN_ARM9_FUNCP, (u32)( (u32)BootFuncEnd - (u32)ReturnFromMain ) ); + DC_StoreRange ( (void *)ReturnFromMain, 0x200 ); // ゲームブート時の最終処理をメインメモリの後ろの方にコピー(※SYSM実行時のスタック上昇で破壊されないように、このタイミングでコピーする。) + + for( i = 0; i <= MI_DMA_MAX_NUM; i++ ) { // DMAの停止 + MI_StopDma( i ); + } + SYSM_FinalizeCardPulledOut(); // カード抜け検出終了処理 + SYSMi_MainpRegisterAndRamClear( TRUE ); // レジスタ&RAMクリア + ( void )GX_VBlankIntr(FALSE); + ( void )OS_SetIrqFunction(OS_IE_SUBP, INTR_SubpIRQ); + ( void )OS_SetIrqMask(OS_IE_SUBP); // サブプロセッサ割り込みのみを許可。 + reg_PXI_SUBPINTF = SUBP_RECV_IF_ENABLE | 0x0f00; // ARM9ステートを "0x0f" に + GetSYSMWork()->mainp_state = MAINP_STATE_WAIT_BOOT_REQ; + // ※もうFIFOはクリア済みなので、使わない。 + // ARM7からの通知待ち + OS_WaitIrq(1, OS_IE_SUBP); // SVC_WaitIntr(0,OS_IE_SUBP);から変更。 + + // 割り込みをクリアして最終ブートシーケンスへ。 + reg_PXI_SUBPINTF &= 0x0f00; // サブプロセッサ割り込み許可フラグをクリア + ( void )OS_DisableIrq(); + ( void )OS_SetIrqMask(0); + ( void )OS_ResetRequestIrqMask( (u32)~0 ); +} + + +#if 0 +// NITRO起動をARM7に通知 +BOOL SYSM_BootCard( void ) +{ // Nintendoロゴチェックは、このタイミングで行う。 + + ( void )SYSMi_SendMessageToARM7(MSG_BOOT_TYPE_CARD); // ARM7にカード起動を通知。 + + if( SYSM_CheckNinLogo( (u16 *)GetRomHeaderAddr()->nintendo_logo ) == FALSE + || GetSYSMWork()->enableCardNormalOnly == TRUE ) { // NORMALカード非対応化 + SYSM_SetBootFlag( BFLG_ILLEGAL_NITRO_CARD ); + return FALSE; + }else { + SYSM_SetBootFlag( BFLG_BOOT_DECIDED | BFLG_BOOT_NITRO ); + return TRUE; + } +} +#endif + + +// TPリード可能かどうかを調べる。 +BOOL SYSM_IsTPReadable( void ) +{ + if( SYSM_GetBootFlag() & BFLG_BOOT_DECIDED ) return FALSE; + else return TRUE; +} + + +// ARM7-ARM9共有リソースのbootFlagへの値のセット +void SYSM_SetBootFlag( u32 value ) +{ + BOOL preIrq = OS_DisableIrq(); + LockVariable *lockp = &GetSYSMWork()->boot_flag; + ( void )OS_LockByWord( BOOTFLAG_LOCK_ID, &(lockp->lock), (void (*)( void ))0x00000000); + lockp->value |= value; + ( void )OS_UnLockByWord(BOOTFLAG_LOCK_ID, &(lockp->lock), (void (*)( void ))0x00000000); + ( void )OS_RestoreIrq( preIrq ); +} + + +void SYSM_ClearBootFlag( u32 value ) +{ + BOOL preIrq = OS_DisableIrq(); + LockVariable *lockp = &GetSYSMWork()->boot_flag; + ( void )OS_LockByWord( BOOTFLAG_LOCK_ID, &(lockp->lock), (void (*)( void ))0x00000000); + lockp->value &= ~value; + ( void )OS_UnLockByWord(BOOTFLAG_LOCK_ID, &(lockp->lock), (void (*)( void ))0x00000000); + ( void )OS_RestoreIrq( preIrq ); +} + + +// ============================================================================ +// 割り込み処理 +// ============================================================================ + +// サブプロセッサ割り込み +static void INTR_SubpIRQ( void ) +{ + OS_SetIrqCheckFlag( OS_IE_SUBP ); +} + + +// ============================================================================ +// アプリ起動処理 +// ============================================================================ + +// エントリアドレスの正当性チェック +static void SYSMi_CheckEntryAddress( void ) +{ + // エントリアドレスがROM内登録エリアかAGBカートリッジエリアなら、無限ループに入る。 + if( !( ( (u32)GetRomHeaderAddr()->main_entry_address >= HW_MAIN_MEM ) + && ( (u32)GetRomHeaderAddr()->main_entry_address < SYSM_ARM9_MMEM_ENTRY_ADDR_LIMIT ) ) + || !( ( ( (u32)GetRomHeaderAddr()->sub_entry_address >= HW_MAIN_MEM ) + && ( (u32)GetRomHeaderAddr()->sub_entry_address < SYSM_ARM7_LOAD_MMEM_LAST_ADDR ) ) + || ( ( (u32)GetRomHeaderAddr()->sub_entry_address >= HW_WRAM ) + && ( (u32)GetRomHeaderAddr()->sub_entry_address < SYSM_ARM7_LOAD_WRAM_LAST_ADDR ) ) ) ) + { + OS_TPrintf("entry address invalid.\n"); +#ifdef __DEBUG_SECURITY_CODE + DispSingleColorScreen( SCREEN_YELLOW ); +#endif + while( 1 ) {} + } + OS_TPrintf("entry address valid.\n"); +} + + +// ARM7によるNITROゲームのロード完了を確認する。 +static BOOL SYSMi_CheckARM7LoadNITROCard( void ) +{ + if( SYSMi_ExistCard() +// && !( SYSM_GetBootFlag() & BFLG_LOAD_CARD_COMPLETED ) + ) { + return FALSE; + } + return TRUE; +} + + + +// SystemMenuで使用したレジスタ&メモリのクリア +static void SYSMi_MainpRegisterAndRamClear( BOOL isPlatformTWL ) +{ + // 最後がサブプロセッサ割り込み待ちなので、IMEはクリアしない。 + ( void )OS_SetIrqMask(0); + ( void )OS_ResetRequestIrqMask( (u32)~0 ); + + // メモリクリア + GX_SetBankForLCDC(GX_VRAM_LCDC_ALL); // VRAM クリア + MI_CpuClearFast((void*)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE); + ( void )GX_DisableBankForLCDC(); +// MI_CpuClearFast((void *)HW_ITCM, HW_ITCM_SIZE); // ITCM クリア ※ITCMにはSDKのコードが入っているので、gameBoot.cでクリアする。 +// MI_CpuClearFast((void *)HW_DTCM, HW_DTCM_SIZE-0x800); // DTCM クリア ※DTCMはスタック&SDK変数入りなので、最後にgameBoot.cでクリアしている。 + MI_CpuClearFast((void *)HW_OAM, HW_OAM_SIZE); // OAM クリア + MI_CpuClearFast((void *)HW_PLTT, HW_PLTT_SIZE); // パレット クリア + MI_CpuClearFast((void *)HW_DB_OAM, HW_DB_OAM_SIZE); // OAM クリア + MI_CpuClearFast((void *)HW_DB_PLTT, HW_DB_PLTT_SIZE); // パレット クリア + + // レジスタクリア + MI_CpuClearFast((void*)(HW_REG_BASE + 0x8), 0x12c); // BG0CNT 〜 KEYCNT + MI_CpuClearFast((void*)(HW_REG_BASE + 0x280), 0x40); // DIVCNT 〜 SQRTD3 + MI_CpuClearFast((void*)(HW_REG_BASE + 0x1000), 0x6e); // DISP1CNT1 〜 DISPBRTCNT1 + CP_SetDiv32_32( 0, 1 ); + reg_PXI_SUBP_FIFO_CNT = 0x4008; + reg_GX_DISPCNT = 0; + reg_GX_DISPSTAT = 0; // ※ reg_GX_VCOUNTはベタクリアできないので、この先頭部分のクリアを分離する。 + + + // NTRの時には、バナーがある時は、MCCNTのカードイネーブルビットが"1"で、無いときには"0"になっていたが、 + // NTR起動の時には、ここでもそれを踏襲しないとダメかも。。。 + + // クリアしていないレジスタは、VCOUNT, PIFCNT, MC-, EXMEMCNT, IME, RBKCNT1, PAUSE, POWLCDCNT, 全3D系です。 + if( isPlatformTWL ) { + // TWL専用レジスタのクリア + } +} + + +// ============================================================================ +// サブルーチン +// ============================================================================ + +// ISデバッガのバナービューモード起動かどうか? +BOOL SYSM_IsDebuggerBannerViewMode( void ) +{ +#ifdef __IS_DEBUGGER_BUILD + return ( GetSYSMWork()->isOnDebugger && + SYSMi_ExistCard() && + GetRomHeaderAddr()->dbgRomSize == 0 ) ? TRUE : FALSE; +#else + return FALSE; +#endif // __IS_DEBUGGER_BUILD +} + + +// NITRO設定データの読み出し。 +static void SYSMi_ReadNTRSetting( void ) +{ + RTCDate date; + RTCTime time; + + GetSYSMWork()->ncd_invalid = NVRAMm_ReadNitroConfigData( GetNCDWork() ); + // NVRAMからNITRO設定データをロード。 + if( GetSYSMWork()->ncd_invalid ) { // リードしたNITRO設定データが無効だったら、0クリアしたものを使用。 + OS_TPrintf(" NCD destroyed.\n" ); + SVC_CpuClearFast( 0x0000, GetNCDExWork(), sizeof(NitroConfigDataEx) ); + GetNCDExWork()->version = NITRO_CONFIG_DATA_EX_VERSION; + GetNCDWork()->option.backLightBrightness= 2; // 出荷時と同じ値に。 + GetNCDWork()->option.language = LANG_ENGLISH; // プリセットが必要なデータはプリセットしておく + GetNCDWork()->option.destroyFlashFlag = 1; + GetNCDWork()->owner.birthday.month = 1; + GetNCDWork()->owner.birthday.day = 1; + GetNCDExWork()->valid_language_bitmap = VALID_LANG_BITMAP; + } + + // RTCのリセット or おかしい値を検出した場合は初回起動シーケンスへ。 + ( void )RTC_GetDateTime( &date, &time ); + if( !SYSM_CheckRTCDate( &date ) || + !SYSM_CheckRTCTime( &time ) +#ifndef __IS_DEBUGGER_BUILD // 青デバッガではRTCの電池がないので、毎回ここにひっかかって設定データが片方クリアされてしまう。これを防ぐスイッチ。 + || ( GetSYSMWork()->rtcStatus & 0x01 ) +#endif + ) { // RTCの異常を検出したら、rtc入力フラグ&rtcOffsetを0にしてNVRAMに書き込み。 + OS_TPrintf("\"RTC reset\" or \"Illegal RTC data\" detect!\n"); + GetNCDWork()->option.input_rtc = 0; + GetNCDWork()->option.rtcOffset = 0; + GetNCDWork()->option.rtcLastSetYear = 0; + ( void )NVRAMm_WriteNitroConfigData( GetNCDWork() ); + } +} + + +// TWL設定データの読み出し +static void SYSMi_ReadTWLSetting( void ) +{ + +} + + +// NTR設定とTWL設定をベリファイして、不一致があれば、NTR設定を更新 +static void SYSMi_VerifyNTRSetting( void ) +{ +} + + +// RTCの日付が正しいかチェック +BOOL SYSM_CheckRTCDate( RTCDate *datep ) +{ + if( ( datep->year >= 100 ) + || ( datep->month < 1 ) || ( datep->month > 12 ) + || ( datep->day < 1 ) || ( datep->day > 31 ) + || ( datep->week >= RTC_WEEK_MAX ) ) { + return FALSE; + } + return TRUE; +} + + +// RTCの時刻が正しいかチェック +BOOL SYSM_CheckRTCTime( RTCTime *timep ) +{ + if( ( timep->hour > 23 ) + || ( timep->minute > 59 ) + || ( timep->second > 59 ) ) { + return FALSE; + } + return TRUE; +} + + +// バナーファイルの読み込みの実体 +static void SYSMi_ReadCardBannerFile( void ) +{ + s32 lockCardID; + BannerFile *pBanner = &s_bannerBuf; + + if( ( !SYSMi_ExistCard() ) || ( *(void** )BANNER_ROM_OFFSET == NULL ) ) { + s_isBanner = FALSE; + return; + } + + // ROMカードからのバナーデータのリード + if ( ( lockCardID = OS_GetLockID() ) > 0 ) { + ( void )OS_LockCard( (u16 )lockCardID ); + DC_FlushRange( pBanner, sizeof(BannerFile) ); + SYSM_ReadCard(*(void** )BANNER_ROM_OFFSET, pBanner, sizeof(BannerFile) ); + ( void )OS_UnLockCard( (u16 )lockCardID ); + OS_ReleaseLockID( (u16 )lockCardID ); + } + + // バナーデータの正誤チェック + { + int i; + u16 calc_crc = 0xffff; + u16 *hd_crcp = (u16 *)&pBanner->h.crc16_v1; + BannerCheckParam *chkp = &s_bannerCheckList[ 0 ]; + + s_isBanner = TRUE; + + for( i = 0; i < BNR_VER_MAX; i++ ) { + if( i < pBanner->h.version ) { + calc_crc = SVC_GetCRC16( calc_crc, chkp->srcp, chkp->size ); + if( calc_crc != *hd_crcp++ ) { + s_isBanner = FALSE; + break; + } + }else { + MI_CpuClear16( chkp->srcp, chkp->size ); + } + chkp++; + } + if( !s_isBanner ) { + MI_CpuClear16( &s_bannerBuf, sizeof(BannerFile) ); + } + } +} + + +// クローンブート判定 +static void SYSMi_CheckCardCloneBoot( void ) +{ + s32 lockCardID; + u8 *buffp = (u8 *)&s_bannerBuf; // バナー用バッファをテンポラリとして使用 + u32 total_rom_size = GetRomHeaderAddr()->total_rom_size ? GetRomHeaderAddr()->total_rom_size : 0x01000000; + u32 file_offset = total_rom_size & 0xFFFFFE00; + + if( !SYSMi_ExistCard() ) { + return; + } + + if ( ( lockCardID = OS_GetLockID() ) > 0 ) { + ( void )OS_LockCard( (u16 )lockCardID ); + DC_FlushRange( buffp, BNR_IMAGE_SIZE ); + SYSM_ReadCard( (void *)file_offset, buffp, BNR_IMAGE_SIZE ); + ( void )OS_UnLockCard( (u16 )lockCardID ); + OS_ReleaseLockID( (u16 )lockCardID ); + } + + buffp += total_rom_size & 0x000001FF; + if( *buffp++ == 'a' && *buffp == 'c' ) { + GetSYSMWork()->clone_boot_mode = CLONE_BOOT_MODE; + }else { + GetSYSMWork()->clone_boot_mode = OTHER_BOOT_MODE; + } +} + + +// タッチパネルキャリブレーション +static void SYSMi_CaribrateTP( void ) +{ +#ifndef __TP_OFF + TPCalibrateParam calibrate; + + ( void )TP_CalcCalibrateParam(&calibrate, // タッチパネル初期化 + GetNCDWork()->tp.raw_x1, GetNCDWork()->tp.raw_y1, (u16)GetNCDWork()->tp.dx1, (u16)GetNCDWork()->tp.dy1, + GetNCDWork()->tp.raw_x2, GetNCDWork()->tp.raw_y2, (u16)GetNCDWork()->tp.dx2, (u16)GetNCDWork()->tp.dy2 ); + TP_SetCalibrateParam(&calibrate); + OS_Printf("TP_calib: %4d %4d %4d %4d %4d %4d\n", + GetNCDWork()->tp.raw_x1, GetNCDWork()->tp.raw_y1, (u16)GetNCDWork()->tp.dx1, (u16)GetNCDWork()->tp.dy1, + GetNCDWork()->tp.raw_x2, GetNCDWork()->tp.raw_y2, (u16)GetNCDWork()->tp.dx2, (u16)GetNCDWork()->tp.dy2 ); +#endif +} + + +// RTCクロック補正値をセット +static void SYSMi_WriteAdjustRTC( void ) +{ +#ifndef __IS_DEBUGGER_BUILD // デバッガ用ビルド時は補正しない。 + RTCRawAdjust raw; + + raw.adjust = GetNCDWork()->option.rtcClockAdjust; // ncd_invalid時にはrtcClockAdjustは + // 0クリアされているため補正機能は使用されない + ( void )RTCi_SetRegAdjust( &raw ); +#endif /* __IS_DEBUGGER_BUILD */ +} + + +// FIFO経由でARM7にメッセージ通知。※PXI_FIFO_TAG_USER_1を使用。 +static BOOL SYSMi_SendMessageToARM7(u32 msg) +{ +#pragma unused(msg) + return TRUE; +} + + +// NTR,TWLカード存在チェック 「リターン 1:カード認識 0:カードなし」 +static int SYSMi_ExistCard( void ) +{ + if( ( GetRomHeaderAddr()->nintendo_logo_crc16 == 0xcf56 ) && + ( GetRomHeaderAddr()->header_crc16 == GetSYSMWork()->cardHeaderCrc16) ) { + return TRUE; // NTR,TWLカードあり(NintendoロゴCRC、カードヘッダCRCが正しい場合) + // ※Nintendoロゴデータのチェックは、特許の都合上、ロゴ表示ルーチン起動後に行います。 + }else { + return FALSE; // NTR,TWLカードなし + } +} + + +// Nintendoロゴチェック 「リターン 1:Nintendoロゴ認識成功 0:失敗」 +BOOL SYSM_CheckNinLogo(u16 *logo_cardp) +{ + u16 *logo_orgp = (u16 *)SYSROM9_NINLOGO_ADR; // ARM9のシステムROMのロゴデータとカートリッジ内のものを比較 + u16 length = NINTENDO_LOGO_LENGTH >> 1; + + while(length--) { + if(*logo_orgp++ != *logo_cardp++) return FALSE; + } + return TRUE; +} + + +// スリープモードへの遷移 +void SYSM_GoSleepMode( void ) +{ +#ifndef __IS_DEBUGGER_BUILD // デバッガ用ビルド時はスリープしない。 + PM_GoSleepMode( (PMWakeUpTrigger)( (PAD_DetectFold() ? PM_TRIGGER_COVER_OPEN : 0) | PM_TRIGGER_RTC_ALARM ), + 0, + 0 ); +#endif /* __IS_DEBUGGER_BUILD */ +} + + +// バックライト輝度調整 +void PMm_SetBackLightBrightness( void ) +{ + ( void )PMi_WriteRegister( 4, (u16)NCD_GetBackLightBrightness() ); + ( void )PM_SetBackLight( PM_LCD_ALL, PM_BACKLIGHT_ON ); +} + + +//====================================================================== +// デバッグ関数 +//====================================================================== + +// 初期データのデバッグ表示 +#ifdef __SYSM_DEBUG +static void SYSMi_DispInitialDebugData( void ) +{ + OS_Printf("SYSM version :20%x\n", SYSMENU_VER); + if( GetMovedInfoFromIPL1Addr()->isOnDebugger ) OS_Printf("Run On IS-DEBUGGER\n"); + else OS_Printf("Run On IS-EMULATOR\n"); + if(GetMovedInfoFromIPL1Addr()->rtcStatus & 0x01) OS_Printf("RTC reset is detected!\n"); + if(GetMovedInfoFromIPL1Addr()->rtcError) OS_Printf("RTC error is detected!\n"); +#if 0 + OS_Printf("NvDate :%4d\n",sizeof(NvDate)); + OS_Printf("NvNickname :%4d\n",sizeof(NvNickname)); + OS_Printf("NvComment :%4d\n",sizeof(NvComment)); + OS_Printf("NvOwnerInfo :%4d\n",sizeof(NvOwnerInfo)); + OS_Printf("NvAlarm :%4d\n",sizeof(NvAlarm)); + OS_Printf("NvTpCalibData:%4d\n",sizeof(NvTpCalibData)); + OS_Printf("NvOption :%4d\n",sizeof(NvOption)); + OS_Printf("NCD :%4d\n",sizeof(NitroConfigData)); + OS_Printf("NCDStore :%4d\n",sizeof(NCDStore)); +#endif +#if 0 + { // ROM_HEADER_BUFFの内容を書き出し + int i,j; + u32 *romhp = (u32 *)GetRomHeaderAddr(); + OS_Printf("ROM Header Buff\n "); + for(i = 0; i < 6; i++) { + for(j = 0; j < 4; j++) OS_Printf(" 0x%8x", *romhp++); + OS_Printf("\n "); + } + OS_Printf("\n"); + } + { // ROM_HEADER_BUFFの内容を書き出し + int i,j; + u32 *romhp = (u32 *)MB_CARD_ROM_HEADER_ADDRESS; + OS_Printf("MB Card ROM Header Buff\n "); + for(i = 0; i < 6; i++) { + for(j = 0; j < 4; j++) OS_Printf(" 0x%8x", *romhp++); + OS_Printf("\n "); + } + OS_Printf("\n"); + } +#endif /* 0 */ +} +#endif /* __SYSM_DEBUG */ + + + +#ifdef __DEBUG_SECURITY_CODE +// セキュリティがきちんと働いているかを確認するデバッグコード +static void DispSingleColorScreen( int mode ) +{ + ( void )OS_DisableIrq(); + GX_LoadBGPltt ( &security_detection_color[ mode ], 0, sizeof(GXRgb) ); + GXS_LoadBGPltt ( &security_detection_color[ mode ], 0, sizeof(GXRgb) ); + GX_DispOn(); + GXS_DispOn(); + GX_SetGraphicsMode ( GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D ); + GXS_SetGraphicsMode( GX_BGMODE_0 ); + GX_SetMasterBrightness( 0 ); + GXS_SetMasterBrightness( 0 ); + GX_SetVisiblePlane ( GX_PLANEMASK_NONE ); + GXS_SetVisiblePlane( GX_PLANEMASK_NONE ); +} +#endif + + diff --git a/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_util.c b/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_util.c new file mode 100644 index 00000000..76c45b10 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/ARM9/src/sysmenu_util.c @@ -0,0 +1,172 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: SYSM_util.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include + +// define data------------------------------------------ + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +static s64 SYSMi_CalcRtcSecOffset( RTCDate *datep, RTCTime *timep ); + +// global variable ------------------------------------- + +// static variable ------------------------------------- + +// const data ----------------------------------------- + +// function's description------------------------------- + +//====================================================================== +// NITRO設定データ ワーク制御 +//====================================================================== + +// NITRO設定データのニックネーム・色・誕生日の初期化。 +void NCD_ClearOwnerInfo( void ) +{ + NitroConfigData *ncdp = GetNCDWork(); + + MI_CpuClear16( &ncdp->owner, sizeof(NvOwnerInfo) ); + ncdp->owner.birthday.month = 1; + ncdp->owner.birthday.day = 1; + ncdp->option.input_birthday = 0; + ncdp->option.input_favoriteColor = 0; + ncdp->option.input_nickname = 0; +} + + +//====================================================================== +// RTCオフセット制御 +//====================================================================== + +// RTCに新しい設定値をセットして、その値をもとにrtcOffset値を算出する。 +s64 SYSM_CalcRtcOffsetAndSetDateTime( RTCDate *newDatep, RTCTime *newTimep ) +{ + RTCDate oldDate; + RTCTime oldTime; + s64 offset0; + s64 offset1; + s64 offset; + + // RTCへの新しい値の設定 + (void)RTC_GetDateTime( &oldDate, &oldTime ); // ライト直前に現在のRTC値を取得する。 + (void)RTC_SetDateTime( newDatep, newTimep ); // 新RTC設定値のセット。 + oldTime.second = 0; + + // RTC設定時は、今回の設定でどれだけRTC値が変化したか(秒オフセット単位)を算出。 + if( ( oldDate.year < NCD_GetRtcLastSetYear() ) && ( NCD_GetInputRTC() ) ) { + oldDate.year += 100; // 前回の設定〜今回の設定の間にRTCが一周してしまったら、yearは100を加算してoffsetを計算する。 + } + NCD_SetRtcLastSetYear( (u8)newDatep->year ); + + offset0 = SYSMi_CalcRtcSecOffset( &oldDate, &oldTime ); // 設定直前のRTC値のオフセットを算出 + offset1 = SYSMi_CalcRtcSecOffset( newDatep, newTimep ); // 新しくセットされたRTC値のオフセットを算出 + offset = NCD_GetRtcOffset() + offset1 - offset0; // 新RTC_ofs と 現在のRTC_ofs の差分の値を加算してリターン。 + + OS_Printf ("Now Date = year:%3d month:%3d date:%3d hour:%3d minute:%3d second:%3d\n", + oldDate.year, oldDate.month, oldDate.day, + oldTime.hour, oldTime.minute, oldTime.second); + OS_Printf ("Set Date = year:%3d month:%3d date:%3d hour:%3d minute:%3d second:%3d\n", + newDatep->year, newDatep->month, newDatep->day, + newTimep->hour, newTimep->minute, newTimep->second); + OS_Printf ("offset[0] = %x\n", offset0 ); + OS_Printf ("offset[1] = %x\n", offset1 ); + OS_Printf ("rtcOffset = %x\n", offset ); + + return offset; +} + + +// RTCオフセット値の算出 +#define SECOND_OFFSET +static s64 SYSMi_CalcRtcSecOffset( RTCDate *datep, RTCTime *timep ) +{ + u32 i; + int uruu = 0; + int dayNum = 0; + s64 offset; + + // 時、分、秒を 秒 or 分オフセットに +#ifdef SECOND_OFFSET + offset = ( timep->hour * 60 + timep->minute ) * 60 + timep->second; +#else + offset = timep->hour * 60 + timep->minute; +#endif + + // 月、日を 日数に換算してから、 秒 or 分オフセットに + dayNum = (int)datep->day - 1; + for( i = 1; i < datep->month; i++ ) { + dayNum += SYSM_GetDayNum( datep->year, i ); + } + + // 年を 日数に換算 + if( datep->year > 0 ) { + uruu = ( ( (int)datep->year - 1 ) >> 2 ) + 1; // 指定年-1までのうるう年の個数を算出して、その日数を加算。 + } + dayNum += uruu + (u32)( datep->year * 365 ); + + // 年・月・日を日数に換算した値を 秒 or 分オフセットに +#ifdef SECOND_OFFSET + offset += (s64)( dayNum * 24 * 3600 ); +#else + offset += (s64)( dayNum * 24 * 60 ); +#endif + + return offset; +} + + +// 指定された年・月の日数を返す。 +u32 SYSM_GetDayNum( u32 year, u32 month ) +{ + u32 dayNum = 31; + if( month == 2 ) { + if( SYSM_IsLeapYear100( year ) ) { + dayNum -= 2; + }else { + dayNum -= 3; + } + }else if( ( month == 4 ) || ( month == 6 ) || ( month == 9 ) || ( month == 11 ) ) { + dayNum--; + } + return dayNum; +} + +/* +u32 SYSM_GetDayNum( u32 year, u32 month ) +{ + u8 date_tbl[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + + if( ( month == 2 ) && SYSM_IsLeapYear100( year ) ) { + return 29; + } + return date_tbl[ month - 1 ]; // 1月から12月だから1引く +} +*/ + +// 簡易うるう年の判定 (うるう年:1、通常の年:0)※RTCのとりうる範2000〜2100年に限定する。 +BOOL SYSM_IsLeapYear100( u32 year ) +{ + if( ( year & 0x03 ) || ( year == 100 ) ) { // うるう年は、「4で割り切れ かつ 100で割り切れない年」または「400で割り切れる年」 + return FALSE; + }else { + return TRUE; + } +} + diff --git a/build/libraries_sysmenu/sysmenu/Makefile b/build/libraries_sysmenu/sysmenu/Makefile new file mode 100644 index 00000000..f5ba9913 --- /dev/null +++ b/build/libraries_sysmenu/sysmenu/Makefile @@ -0,0 +1,31 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-10-03#$ +# $Rev: 1319 $ +# $Author: kitase_hirotake $ +#---------------------------------------------------------------------------- + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + + +#---------------------------------------------------------------------------- + +SUBDIRS = ARM9 + +#---------------------------------------------------------------------------- + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + + +#===== End of Makefile ===== diff --git a/build/systemMenu_RED/ARM9/ARM9-TS.lsf b/build/systemMenu_RED/ARM9/ARM9-TS.lsf new file mode 100644 index 00000000..1b0a503a --- /dev/null +++ b/build/systemMenu_RED/ARM9/ARM9-TS.lsf @@ -0,0 +1,70 @@ +#---------------------------------------------------------------------------- +# Project: TwlSDK - include +# File: ARM9-BB.lsf +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- +# +# TWL LCF SPEC FILE +# + +Static $(TARGET_NAME) +{ + Address 0x02800000 + Object $(OBJS_STATIC) + Library $(LLIBS) $(GLIBS) $(CW_LIBS) +} + +Overlay bm_mainp +{ + After $(TARGET_NAME) + Object $(OBJDIR)/DS_Setting.o $(OBJDIR)/settingMenu.o $(OBJDIR)/rtcSet.o $(OBJDIR)/langSelect.o \ + $(OBJDIR)/tpCalib.o $(OBJDIR)/ownerInfo.o $(OBJDIR)/AgbLcdSel.o $(OBJDIR)/autoBoot.o \ + $(OBJDIR)/unicode.o $(OBJDIR)/misc.o \ + $(OBJDIR)/DS_DownloadPlay.o \ + $(OBJDIR)/DS_Chat.o +} + +Overlay ipl2_data +{ + After bm_mainp + Object ./font/f12han.o +} + + +Autoload ITCM +{ + Address 0x01ff8000 + Object * (.itcm) + Object $(OBJS_AUTOLOAD) (.text) + Object $(OBJS_AUTOLOAD) (.rodata) +} + +Autoload DTCM +{ + Address $(ADDRESS_DTCM) + Object * (.dtcm) + Object $(OBJS_AUTOLOAD) (.data) + Object $(OBJS_AUTOLOAD) (.sdata) + Object $(OBJS_AUTOLOAD) (.bss) + Object $(OBJS_AUTOLOAD) (.sbss) +} + +Ltdautoload LTDMAIN +{ + # NITRO/TWL 共有のオーバーレイが在る場合は、さらにその後ろに配置する必要があります。 + After ipl2_data + Object * (.ltdmain) + Object $(OBJS_LTDAUTOLOAD) + Library $(LLIBS_EX) $(GLIBS_EX) +} diff --git a/build/systemMenu_RED/ARM9/Makefile b/build/systemMenu_RED/ARM9/Makefile new file mode 100644 index 00000000..5ee14a6f --- /dev/null +++ b/build/systemMenu_RED/ARM9/Makefile @@ -0,0 +1,81 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlSDK - demos - simpleShoot-1 +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev: $ +# $Author: $ +#---------------------------------------------------------------------------- + +SUBDIRS = + +#---------------------------------------------------------------------------- + +TARGET_PLATFORM = TWL +TWL_ARCHGEN = LIMITED + +TARGET_BIN = main.srl + +LCFILE_SPEC = ARM9-TS.lsf +ROM_SPEC = main.rsf + +LOGO_DIR = Logo +SETTING_DIR = DS_Setting +MBOOT_DIR = DS_DownloadPlay +CHAT_DIR = DS_Chat + +FONT_DIR = font +FONTS = f12han.dat +FONT_DATAS = $(addprefix $(FONT_DIR)/, $(FONTS)) +FONT_OBJS = $(FONT_DATAS:.dat=.o) + +SRCS_IPL2 = main.c mainFunc.c launcher.c $(SETTING_DIR)/font.c $(SETTING_DIR)/myChar.c +SRCS_LOGO = logoDemo.c logoData.c +SRCS_SETTING = DS_Setting.c settingMenu.c unicode.c misc.c \ + rtcSet.c langSelect.c tpCalib.c ownerInfo.c AgbLcdSel.c autoBoot.c +SRCS_MBOOT = DS_DownloadPlay.c +SRCS_DSCHAT = DS_Chat.c +SRCS = $(SRCS_IPL2) $(addprefix $(LOGO_DIR)/, $(SRCS_LOGO)) +SRCS_OVERLAY = $(addprefix $(SETTING_DIR)/,$(SRCS_SETTING)) \ + $(addprefix $(MBOOT_DIR)/,$(SRCS_MBOOT)) \ + $(addprefix $(CHAT_DIR)/,$(SRCS_DSCHAT)) \ + +OBJS_OVERLAY += $(FONT_OBJS) + +LINCLUDES = $(TWLSDK_ROOT)/build/libraries/spi/arm9/include \ + $(TWLSDK_ROOT)/build/libraries/mb/common/include \ + $(SRCDIR)/$(LOGO_DIR) \ + $(SRCDIR)/$(SETTING_DIR) \ + $(SRCDIR)/$(CHAT_DIR) \ + $(SRCDIR)/$(MBOOT_DIR) \ + +LLIBRARY_DIRS = +LLIBRARIES = +LDEPENDS_NEF = + +include $(TWLIPL_ROOT)/build/buildtools/commondefs.sysmenu + +#---------------------------------------------------------------------------- + +do-build : $(FONT_OBJS) $(TARGETS) + + +include $(TWLIPL_ROOT)/build/buildtools/modulerules.sysmenu + +#---------------------------------------------------------------------------- +CW_ROOT := $(subst $(SPACE),\ ,$(subst \,/,$(CWFOLDER_NITRO))) + +$(FONT_DIR)/%.o : $(FONT_DIR)/%.dat + $(CW_ROOT)/ARM_Tools/Command_Line_Tools/BinToElf.exe $< -aligndata 4 -endian little -output $@ + + +#===== End of Makefile ===== diff --git a/build/systemMenu_RED/ARM9/data/NTR_IPL_font_l.NFTR b/build/systemMenu_RED/ARM9/data/NTR_IPL_font_l.NFTR new file mode 100644 index 0000000000000000000000000000000000000000..b6fe11e03f0ed48c6d3f22b2cee630b6cab3ef14 GIT binary patch literal 181128 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

+`3}KD#uex1orifycHwv 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 literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/ARM9/data/NTR_IPL_font_m.NFTR b/build/systemMenu_RED/ARM9/data/NTR_IPL_font_m.NFTR new file mode 100644 index 0000000000000000000000000000000000000000..03ba3a4885cba7b2cd38400a749425587ae911cd GIT binary patch literal 107180 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%0DL@U>Kf~S+EhCEWuce3@ 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%0DTZOf#X>Myiij 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 z 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 I_5TO;7YHZZ9smFU literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/ARM9/data/NTR_IPL_font_s.NFTR b/build/systemMenu_RED/ARM9/data/NTR_IPL_font_s.NFTR new file mode 100644 index 0000000000000000000000000000000000000000..59591f8be6def8fe4de486ab80d222c2a61cac62 GIT binary patch literal 79924 zcma&P4P2Aw)jytuAPHDW0uy*?I|O7C4Jm8c{)Nmj47u3jL)GZ+6WmC}3hOEoBw zyeE@N%Ga)0^|wp-c9dK6vOQPK-tsX2R534kw=_`R zvrIue>hz{Mv$@2WttO;MPLz2(Jq?!I2?;9t8GjTCIkjLGSUEuJFQ9S^1t5SGg!F1feUUH)enJKKIAMmifYAG@23}_YHAYpkZZAN&!WkMvL9nyd z(Ko8hLqF(|(+{(me&UhIWD<|S{-hsC0qN)rP=Ms|aJWn+m7+;euJaU)-FBbjbs?3g z3VEWews5q;q9?QheOX0)VIx|IZjfNi3*)pRU7WUpjR-WxIfDe^WaX~JM@w>9MToV4 zLGwBpr}(Ezv5d;;HOj;Uskyo2Mov+>H@$eKqg<>-f6Lt6MIB3D;dPSCSkIWu_!!VL z)E}FPP~J>&p#wVhnY)P-Q-2dUY~dFE8hMtyh!oddqp8 z9L48$1r$q)spe8z79Trn5ABk0@r&A97H^%=R5z?6qO*r--HbZNKTYxoqYV}|N2n~R zZf1_akZ@*Z{?OR2Gel#YM61({igP;#?sk)|ooltiWK*nm;Hc)en~W zoKs#`>+zNt0H_@2jMtfT)oN(98azaVwz7WmI$2-PGd6#5+OzS_B=EjSSusiCF4iIk z7=t7r&L32nkAbWhJ@TU2qm>s4@%dx4j`E%vYb7r1`N{%rRQ>=3$ObEt5Pi%t8v zcQ!%`vp78hZDgnfO2{?|u}-r9R6d&~xe=j~`l766m{u%zj6ps3MOe32)?z)NFY~V3 zR)~8R5^`rFl$%8>m&`^OphQsz8`(gA5$SBv!{z5JTjsGAW?5RaFbkoDSqP(@g;c5= zEv-O<(5Xggw2-G-v77A60}Np=oMj`SbF+{lc{WPE0ZC>fQu0~l&`6T2B-~u0_25rD z33cN9VLixa+g7wU%hIB~SqLr6LeR9C`D1R&EIWZ6VHQnt14@@CN@}mf?I(?a#?JR6 z-j_Iy_a%;aU*ZVm(3d#kJ)1!inFO{#U?Zg;(hryRY}GGeSRtEjX=Sq!T9{3{5fLY| z$=uSiolBfQv_6Y=TdPuD_ngpNa+`-WC`s62UBOT}Y2>Uu9CI|YBb373W&nnkTXrmPsWe~~z(s3i)>D21BA=_aP}NZ9HoF9H6+l2)SD<-pe;}Wa zPZCuiau%B1K_C-o30JTkDT+zvDixNjF-5&W^b5o};z}n`)H9C-whkkL5}3UWmO>#w z5VRtl>fAZH1`Q>n5&O&Uh1>%Sx39pcA&{3T-se(wxc}&*8`s4(4L)S}0 zOV>8c(lf3h(Zaa4k`7+i*8gwaO{yz|s#%KMUNh>vQFrxuG?@;op;G{Dp$a1iD&%}b zLi4#UyVcV9u;2l0o~mT49efw^RooFE-4@5oN$_G zq{G)G519#6C6`%NtMR6!U4`CrhdtobLIZT85IvI%bV+V@U1(T)3rG@al05O(v$Q7_ zwlyf8)v&JWF?LJ_abi2FHG7*&YT~s(2d6x7ty46W^ei*-`C}~zE=An;R#>)FuUgZdfZQcZSJEY(cT;Zl9yo%H|y_2Nq=ttB3dH#?_H}maP?$mh$2atD|0zF~s|s z8pLoQIbMrGuT$Xw#@4M&I_I7L$x^?5vMx@e)xoU|Z#_PL9L@g$WWyfitocJ!gCjP7 z&{wHs6df1WpTdxKKE0`Ug@={H{JoEDbQVeq&j5Huvz{B#41s-|e#5!(Ml{38KUU0xNFZPSF_1*! z35p0^Nq9f#;w1c(>u=}*``pNWDs07tW{1;O=K)l}d%gZ7!=bqTP!NaCPVv)=9Kd7d z&Fk~@!r?`^dajXk9l(x6$xY^!=OgLX6(fWx_?kZB}o(e>ftPyy%L>@CkFUSkG3&G$Iih;rL(hR%vy7$%}Y zH|xNN;taKvbheaq;X@D6e)@pF-PWydDe;PEaN9{^yNyt88;qbXx2+=AL$n(r1mqbc zL_Goscn}qdIiw1yQx(Tx#@Co4Dff%>(=H;386|Z(l|}DlkwjIxf=-IelS97}Sm|Fs>|wv>e|IVU zo-6L!bM9S~r4xHSUy?c{k;WuA8`C3|>=`W#(?NHDd<>Fbzc@!SIwvME1wdMw zByr6j^N2`RgvZ=$P|D1p(XVC$JpeEoLo}bWWDT7ZWu1DC!kRS_w}%)_ICm+OQzGJe zt5S%qn_cB4mZCz=sl70JVdA8}4?b7}KclBM>G(wfP)QffQ^B>>P>-4`Zwy^lSFPCPw z##=D1+pyPqLPX%a`9Sdur}56O_ipO!5X%`qTm7rzIA??Z`0AfI{hc$kn-5sK;&r0E z1J`LlKPirLHu;Zj_>S{E&Pg)8!L~{gVlnyez=gvuxdIBz{C-h0e6Qc<&E~2Z8a4LoE2APSD>u^~M~Kh~MCP@` zdnVQ?_J!9O?+Zg$M#Y}77J|f2wTSJBh(1Y(#>+7ji_IQUG+s`miRD-eGkX<7GxB6D z%+MH`q49F@_QZ0t`#IB|SWaxu6pKGWbi_1@k7<(Jgk%Y|?~hJJ-R>Aevf4tN&f;gT z*q8sFn%c2|`^h(2K3T%9e|{B>7I2zOR)_E!{f{aoSRJf|xSkOWprD>r8)q z9nIo|J^Rn_)UvOuRc6!zwC0rDAtDNn2tgsry&1ClQt~GjP>E;&~@l? zyJoRnjmfN zd4Q2pB?(v2lR0e00RD&ioxslMl2l1jP>7$-QYEPXOAUGtfk+QzVcZ}rVW~P({j)}_*B+^VHRRjAVr-EL6QjS zk}lZ{l4?f_uh3NilZ3Q?Hc~Z|h17~y%mQmy)l)qSX=|mJThyFD?P)tIW+8?4jPyB) zr=%n+0GguTJ`2gUSEbUaI;n)MKY9PfSqRpQW<|!j2{rqjid3?8KPr((j{a>n(vHF{ zfmbOF5KSBOv^C*^k@ZET*z$fYv@qUl`z)kbcr{tAc>REN6%`ZG=v=63F3Ac4DU*KV zT>Xgdj>^=olY&U z<)%Q=X`hXX?5)>nIis`tng7;LCa(7^|Au}_Nn2IVuGasUT3;xYv|PJ0tK}{!A%#4@ zQCf@JIyPe@rA3GDYJRKMLo{ujG-0$zr`khEqD=hXlKP^XxsB8)A1O1`t;g~wl0>ci zxHMaHT0WP6G;L)4q65}LGN$Dc%+|BQ=)U3wX3#L@h$6<(9L3qhe=1>%*{N<(`abd_ zWn5def!f-!MCtri*195bzfRR~wzGxVOz5W+G>M1x8aFoo+kjhPwUSy_B>s`+*4y0Z z0a_?cxZ1QzcZAQowic*sg|N6&08Iw_^4Tr->QzZWAhe4B(}yKzJ3K%N4Idc(#PfgL zp+GYw=22$bP>Zag4*K}4$gd4jAWFs0fu;aDJ%bRvH2>Ngx0qP!wZCSImo*_v#V&&D z7$!lvb~rs59TFudNeXzd9z>r#HAo=tagr}gPA8YOr)-Kjpb1o`T$YMsexcxfI6$bg znnf-IHa^fs&AKQpK~95#i6ceQRZTKZgxs1cj$WLNS&O%tJe4pv3_9Xom z*yyAt4}hY+Y#KYNIJb(f>RAY;a*m=N?Xf*)erNd{c^!t%Y&l}Ff=V@Cqk2m~EhcQl z!VH2niPhIz1XWUiTIjORLPBmjU0{jwl)UB8Fvz54rV4=XS( zbXtM~>MSIarcTk^imfxtED=u{+JK;L&Q&DOe~Ze=QiF(={os5(^8_SJN+`CJXcW9t z<8Wqn352@rv(Z`mUDs)7>PKg=jQF0TEAM&qIue?D{9~GYi-_;H z|JN3bMq6lTZ8%#*y_R)U&qjr_5zcrBU!0qdb%$qxG?3<5CL2v+MiMG4l{6Hss^J3l z6d{mE`a+!8s*=Ja(1ZX%h3w0QdINSE0xJ2x_scDDgiRnw6DBhShzRKtkiyAf5VFT^ zVxqrEBiYu%^cov-(iAwk76{E0S%zSkBpW;ox?G<7ufm8}Vzm+vV+^WbP!w|3Gei$E(XaTd%$HH8#g!xPALg}i%Yb`d zEPuT&izkWQ!9SG~jZV8i%u=6@`|P>52DcnKjyKUHQ?vt~M_?O&K-Ezvzt^+dl%3D2MV}6ffJd zjfaCk1?{DMH61@1X}1%SNN&o&+1__)8zF-x`D=?aY==v_13;iT>D)iK&C8H{aKqw^ zra?O)L6tmMwHUN-Gn&V{=-rNTG1A7OMu=wH9teOl`|j7Ai*K=Y+a48w=(&DkH(g=Y zMX*Zo^hJ4q=r{#<#h&JE~0sU?0cZ6^%c)7n$v%o(G-Wq%$;`s*OM6yV?eq1Ib5cl z+8@@%8e(Tq3H+rq+3E(1J$p-#>O5y?EsfR{^0CXAWyb-Nw*Z+e0LkkjPDK)JVyblY zQWp?f7=`<=G&hTAs?>>k$R(9aLb_j4SK>qKOxD`>Q>V!08+6186e^9j#@g?85%SPe z>j_i`fUw&K$uzY*83aO|iBqbjg13xl8s)eCY&E=W7OIIRd$TC#LgQr92Q`EWB(|d$ ztP}c{2MDPbPV6~dJY?BXL1>{mb?CsfA*x6U0GV*Aa?$*WJu|Nf>oI=}r8evzEsbho z@;P9X$g~p&rm|y7Qyn2~fPUg(aseWHt>^P+8cM+7#Zthnu;~n(QB0qjaVidt>r{;~ zy;|jAg_FjW;W{_3#WW1GwdodFe-Jd~%_GG*|B%FKSNDgHROZE+SS^rs2#P0ah)g@K zPj12%%k&dSR?=lyWT+QVi%dIa?r`|pTGIe%3~5u+sGN_FA!U44WZKaL=%B)IgqIu7 zi6-n+#K%6a8p77}{Jw zvN^xIWmJL`(Ilc_yInMwK&aX>2bg8jHV#;%ifx`%(xS5|U6{pe4!I{Z~R* zkE~1pNxBV9%j>^o*eU>Jj@%ULwjZ$@TM21KHleldjUDA4AVp)C>M!eHy;d}?4Yerx zanvAM%J5pT*Fhi}-&$dFZaSN>%yY*>c{?y%4M>vI^KGO(Ph)t=ky{O1bt;zq0^{%|pty1x-8kEoI(JqNx$^r)w0$K|+}W>q5BU*u-gU zv?K|}NvN;@SA!hU_=Nt)x>%h`Hd_DIqpa7N!*^cvIsBXWOef8KOgXBHiQ1a1j1=h> zHmvDnoY14yhG}6B9_m(a$`IPXgh&)zdV0xBpy%QF?-)v|Tz=_dzI=|ayUBnR8>2t);f*G{T zv6Aj6?PE^_360zyYW%^GO?eLpKYY zqK(|1jQJC1Gjn)dsJ*7Ux|7jThWE8rr1uwP+r8jSqj^vqwB@8zxtklSq80bQZOwjJ z08%RN3{`AyeUR&!rs=b}#rX!NLl+q7AzwRS=7tZZo&{TWF`crmaRS(m%j8bSw?myQX(gL9I z_28@aJ6%AT=k|wut*6D+m~#G(aVsRz#phO8cI&j`w5UCrluuhDmeXQiv?F(p*Vdqx z2dNhHvo%umCJrrvlrL7>c$H$vSt^-kl1gchEB==g?DobR67<^ocl zduhCJM`v{|Tm7j6$H#p&z6~cX37};tf7dx(A2aiQk|sxr8ql)^8^~P6; zGikvO+MU@>g`4f~OfL3*hu`4>P0{$xkhSJgS$A3xNIS82a!I75|Kd{u5G20}BdW+} zt!tE#1JFQ%zN~}QlG#`mY6rEuifCy~W#hgbuU2Je zxPUS*><$05*X{rFV?@*J4V-(Bsi3IfUHmdr3RDl|_K($XFdXG8xmL+9X|;T?lkMx#A7Eu1HECTiNt zJDhQpclWC=ysLqVd+>PYth$ z=4S9(@-Ho(OpYi-TJoW(6e`DQvfF;S_J6AWBVF?()qe+;8Ldy9raFWL|+89gcH0`+@@>pUm zONo}4`f=s7!!IIuoNK14qF*<53!uTr+_$>27?(@LX&RfqZ%qvME8K4#=(hJpVQHHK zM7xqSZVk7_yc~^c!%5LPw{VEjM&~QZd*U9TL_4kUJS&gYCV8mbXr{_E~fTPU0`oqnEe zXS#sAfs=Nh+v@@?`ybvazY`nqX+pv~53c?8J=tDz*n<`3Gs?LAwGv!JKSzrp`C zO*6CJY0(yIcIA0Tr=4hulN)^~7iunHoIib_Z!me%*7a>d3%aU(83TizBF+Cm-=)2i z`nDZJ%k8)41NkqB<*JWoe&X!8^cc}J#cM`aMJ=%wW_J+xtG+JDK|qv%3X9tv*)uNk*t=3(<^S3{9P7eNkD;LcUA>XL6aPRrEWJ2S*Y^ zXKRSF;AA!3Pm7!if3**Nnc}s8GcR*n_mf-_D`3)Jgggw*L%9vVJ=rt#J>Hj%Cmc=PQ_YOVqp0z@ zl`hyF!u)MLYave6!b!}K&oS`5Adsd)bu?HQQ#C&o09u(ATYL0Rd9RPNnN~*I?^#qB zRjYnVG{u|aG}A@rcM3oS&9UP*e*)j;X%|p>aanjb=?mvPRJ_A!>o)kAJk<;9BiWT! z%f;2i35$~dk?~`F#5#j|C-uMljsTh|upf3%6>E5wX!F}*$E!xV9l4JNfmYN5L1ry( z7f|}4N#ns!zV+AlSzlHrkN>&(=V$v`HxljsUqp*z-H-R#{Q)4;(3Q91Xo(GIVQNGn0fWbxLWtT8Q(!i*ZieG;}k9rPailD1UKX?kgqm zlmmohho1D7=iWO~OtgZQ>bKH{i+?pLT86!mMF&djiVkKQOD2yXme}L1* zO5d}8p8l&3I2v!X967Kb8NyVjX*4;#^{)A?<^2qeD<^TVYAO*?=|s`atA{uz9pWgS z%+K$VKYC`Nxv%3W7DY@>@Ssjr>afQQPn>gVip_fvSrCz&AGP)F0C8d$)v2B8SiKAY zJ5Z2zL(xZ3r~J!qEs5EE4+@NPbWgN$XTxQtJ<0p|ft`CZ>cuhpv?K0`lo3L2yW$!H@4%zjpz2!SJ(gi&v}Eq7S+5^+0cQXYsaOd4P9%C=Mq|Z^_I1` zG}PbC+S5{e!qR5RVVo%wx4yLcu~=+X$^3$+UG}^gaFfZbI4* z%EF1^y06Pu27zuF*IIKff|JekV(9Uu-pRc5eO}N^V^w!leWD3{P(vuAdUQ|39CbdI zltNsBt<1+wBkM%9_Xb+H*<&R@O(&L7@9HzDj(4w`EAaijX38L7I5mT)&Q&q&=x0z&vdkIEu(jJdp7aEO;P-qw=d0pQ9s`so{ZD%H zQul?1H9^oMPn<ndpsb zQiFTK*JXy7qqi|8&ZcSXwog}oB|ZJ&6JFF}nz;3*sLwHyxHbqRT>wWTR`RdpMgeH~ zgzfmo7-m!I0b)_3%Xw{ly<`50^@mF6wh7P5p+o1hFaD*g)fxo4|6r&XwTNxb@sAFOc?JemE&6 z6~`w#wK1}~zoKuV$OYQ+$&HZ>{g%&blY&5L2vu0KJL8g{yp=dVuVby>=e#Xq?6+S_ znBxMcb~rQC@_eT_x2Cbwi82Z_^aVgmij+n+;NY?##h~RynTjg2-a9+b*!*| zl-){XENyJ7WnqLnddq<~srTX!729GCn`N$k>rLABV= zL@n04!4dN^3%2~vINSF-KHr_-Lb>~Y5jwuP!yTWM!Nrjczb%RFW>yL@al{fV@p6Mk z%wNU7>Q{MDZdrTiB^jhN%6e_OGVfGXw7FEjB1m<9`PbuL?3torZMe*Bz^Au>eBbAmgN(El6>DdlP=COV`)*(m;P@N4JVYV z(x@cHy>02=u!oq$i-X6PTwm_X3^}7Xr2mMosxSSgHuUZ6{leo#3-^CHuoAad z{>dUj@~Y=DDK6DsDFD%}LU%Yf_V%$Lq0#xs_{1H9n;|+)z=IIc=xv`NZ|!s(;kpW7Xl+ zUpY??@^X{a;Uiz|IsKv70{ZgR*N%O_5ImM$QxwTJ@i8bY`WOy3`Gl~m6=l`LV~*G< z_k?Fo$(qLX6iQ3ZQ8Yk6dQdam=pvpbNI(LpQ?ZB7G^c#w;%Pa z*9HD+fBP!6XwOuS|DkTDaOkn2VqR_@B2leRxRMB^UE56YmnW_;q$-VRt~q+28EEi= z2LC$iU4Oi1s@|x6%y#OL@6`&RWe((z*Y4T*V5y|Cq^-M0Np;cGXqOGTSKN(H-#*RghFWZ~i%J%C*A&xQiMPIT;?TW6 zxu}ZqavED%sHLXMeLg9O7VgUow|~{G5l5SLehDHq_22nlIngw@60+8e{G}m@Q07SA zc3;iN#pFGNl(E+8E7jB4ZZ=1}T<^AlA{S`tlz-S^z_wm3B+kr%K18B^zU>3KhY9N1|UwX4e>{;fuC0nc;Jx^@i6#z}QciF0l zQyHg?Ao5ky^`jAH^`QmmweLs6OhYn97LFG?UVmoGDip&CuYzTWOHc#O=Oq2xJ}3)< zhL|Ho{oEhR&BQt0H>vqtafthhYVEbEo+IWM*K3mePW|N%WG}jilbvj4>MV_IJ6Ut_ zk8;+}`<&t8s+Z#Z#AtCY_KWj}e%d33Hy?krUO+7?hhBd!$5A1UXvKk;BX&MroH2Du zEcukZ|M9JRg5b;?E<@yU-}6Iz1Rxr1#L&O(_sm9SUds>dUeWOUuV3_nM)4&|V32DA zKr`nDh7@h9DT`)H1+#-v?dYnACT11{V#IE^CtA05nQDK4qg_+DcWPpO7PnGW zo>=QG_wY{WFy82mOKAvX<`!DeMY&+~iuh~kkp+#Zv)xqkPF(dO!NI|b^sGzqev zp`{MtJ~fUsI4#YhX-5xC<0#t1#sDjIWL>z`&HX{#+!dxpWjpnU%v7g#e9@=U_C@I>2_rwD7Gr)pV4XT>4HBG~7NWOx4Epe8$qkc(atsEhd`k zjZk*YVOx>iF90bDKGwr(=y?mOH#Q#M(73L!Vlhb2tljGJ!gwtxS6pxaafWR!kf=_5 z4CwJ7kXnlnRjg$FMxOu#Jv$ICj+c|AUd;*5t|c4(nQd^`L**7Uwc{d2>~-4TjTGp% zI(mbksa_|qIZo5OVT-gj91_O>%RXI^jTYtysFqD5+0mAb8|TEmX&G;I#u0iQvHdE}nf5nhWOZY;D8bC|MjBDcpGO30Z&S#5KYCW__X1`9 zy)>eam6tuZ*agJ;`I8N6oR13}wMV<%R_Ad-nnO^~Ubk%%D+f*|d?MQ*s}mB0hieo2 z$!P8F;tf78%H@aYcA&(~ZwKHnJ@0=6y=E3g8!($$lw%$kB`alhg~EsD4XqCbfpEsV zX+j;p9arE6;03zrWpTxovM=n`jFBS!+X8Wx1&@ZCn`8BJ04Re2-i69-><3mSIH@SM;LZKzA1bGp7Ldppt4I=kPD+X4}>7C=*^Mdf;>)WbNZ z6}zGq(GC)ARW$w{CL058h{c-&MvI?>L2K9*Eh#D4FSeI5<%xF0?e0_x?5=pbY8p+u zqM9%a8}g~c6Y!txW3_)#L24H~l@LQEtpMECbg_)#m9;+*I6^ zdyHtA!#CM{iT&cu`HH(^`;tB>7Nhm#zxZCqZ4%pMv_b83&OhWLx_eJVGhOVKxzBm1 z1*x23GYx!=$&`jxoBnQbe+OzitBcLoEDeH_t*WnZnsB+OT%mT#>{^=J^$5|}_;8oS zZ{QSfmd9GHLyHE#OEfxpPvc9o_-&c#LjFY2bb6EZF-F5FS!#K&JonM-oL#mOw&O8Q zxSST&0-dLIU%c+T`w>*hPS?_C?PlMjUJ>bP8mfC94FW;S!}%WL(}8knk2NqHS*9A{P+qgdN6BD6=orf-R=#Kg)VXw91$& z_5quB)A(YshWC^ZfC>0POugevZp+$IiUV*15e- zpmGxrmPNDT8D}YjY;W}K*b@XzV`Y&q_k}V-izhcy%tJiwDs$f$*CiiNa2tY{*mzb{ zg>0Arl`9J(N`+hXD*%$b^pWCdt^3IKT0+!1A`+e3Ulf4mv_BNF_ip^7pSOMWvB1hrv20MjZb93F)geYX@|=)TOZD44nzk6R63kcM z=qeY=(fA6ipF4U#6bMyM<@}@ai%d5-a;Ywc0l!a(JgaTT?LM9>mbhQGCZdai7ywOi z=y`Y$6+M?qgFx_UbE5jFSPORhz72~9{e#bXK!Ya`V`z#H_Lc0Y)!lXR3IO8e<42=e zJN+5V?k>J$oJ@{c^YtA>V?I&L;qN*iFiz|i$dBY1-f0mQKkMUJNonC^_!`bWp7%sF zO>cF#o}HQF=dt!=53BQ`$o+_)aZcl*P~U)G72|bc#>h($?@3Hompydb4Z)yVh9Ib1G^9@AEd{t47Mt)&zi5d#CTbxoNj!fZhM;@4EHGzj|L4 zeRhr0(OwlT$5?vPm%v%XvVU^>EH(1bS0Fw@2zBN} zk+$R9=4G^$iS-fto6fsk4DlGJ!yh0t?myNPOYi^Sjvzz(kyK;s-^Ny>X*}iBhR>Yu ze)umBqoqbRe3pStm7$5$Q<Jf1G~I>92^>hPuL4Co1}QIaLWVq~vvC#9GmiPdOQS^->S& z#7TIH-EuR;HH%gp(WH_?Q^@*9CZY>yg|}=fZCIZC9J6PpK>kER6gLxV0-%|$Xv3?Z z2D{GyND2ytg9C}Zp~E%$kVmhFievbxq9IOjJ;jyrnk{^bQPXv|Jr&a)4!bpb8^ zc;3XSsKeOyD*@=f;;6w*sbZ|XZ#;hc-~7&BIs88&&ilKg$B33WL=?q3y%hf_Ocvn~OwfyciAE!^9Jwh~1UjEhMXWn_NtCe$R=lmvnLI^hyD!41ZBWW`I$xD7h zX)VqI>5kUbJbIu`n_NF_@jLTwbAhI44C&Jf;yJ9Dqec44CAcWc41$(<&A6oumz6xf zRq^V$J|>U*OX{?t&C@FEhAm)}sMY!{r8TV^#1_=6Zhab#hq2vEw6vjBG1Upjl3Rj6 z>DJOv7Lbw2CG%qT7mdiN>1hoR?aRUZNhFr^m3x3PCk?$vi=HLef*BtLwEom2sR&_Gp zX}kEm&q+uoZz?wKD(vL@gS@t=TYval`k&@|KqHMziVD7pCm4D^U-ij8l{5EIFKE~; zaL1=|=7|XL0wKBF_b729!#{%L5F}{@8Rt~JUT5za%pw}B4c*RVS3KbbQY-(pA+M&v z#xp+Y21goJ>TD{7F*!la~b%>VxNoLSreP?mzo ziMv*;)Tn{inX1@7ni5tya*tB$s>bzEmLbe$`u6dI4;+4z#^(Vob7094-FK0v%JykQ z_7=s$R#qx`a3pheo+J8_&)}L~z{4r0W5Vvb@rwov-=3&4f~i=zWA- zQG$(krXp4;W}h-&ANPj#J})@6wK(4{ic11fTS_LhbvuZL{K2H1#(t#Y3qXi_f00+? zDdW3n#;ubVTQ*QR4`_IakW%u~xy;h7>%MHXoW_g=LCeV7Jm>ctk3YzBQBBB$KN`)A zaGgk8IJV}!iqA#KBk!r~bV7!2@DVS{sn6~If?}#XCm50LMTmHc{siXs<>%z})gA0K zZ@RXoCnXfuI>h`>IPD%M*K&;Lm$ci0D5pJJ#&Tx)Ol!~QhgUD&smNn`MtAJpCHMb;-?3|l*L=2dIOPE@Pt#Cw zg}U-{amF&&uc!WF^H``3Juzpj^WHNugro{Th0`Km~WX_ho)kp?321 zKE5A!jCq&sUk`$okujP7p<_(JwazqDloRcI@9uBUBbuf(_WhG2&jSJCEWwuJ=zk{X zZ)PCO<_4PEoHhX{^L$yCEqr!SlPM;ED7c%SxsZK&^m-O)=E$8f-;NGg zw*YEcIsDr5M;z;v;z}JZiyp1nC+0P$ADB3C&3HviHFE)@nMR8aj~uZt{Ap(8Q$KKq$K+I4RZi>g3w8Gp4YxafXMb}^*V92D%}BMe{kO*- z@-6ic?fjD0q$|%@v%c;Ef-cFP>&6l69YSf>=GE!f4!>zzS36VZFl22yTh_7E1J2BWx`*(w6;$AUJWV z+cFTs4I^uhw7_Y+d`ADW0Gj&t?2xX%tE}^FhLZd2zF##|cYY%X8g@$L>yHfj+r2CJA<* zS~GOH=SM-%H1AmugShxnrI!lc;eDS-S>JJC%?_T^PwP+ru0PXwLPty z48Je~LAtV?hYyMEsXqC!U+4at^X{iWLJONaUux-JZ~Ub|oO^LMh!OD_qt%gza=Lqh zpz&Maq07EZLaH|=?1N0Yj8=+rGxHAJ#RW_35B?7YaMDe0ZOw;&=&JMrK}sXtFMP6@ zO9^+h+Xqd9WgXuLf~Lvs3ptk$uIKZhF2$Yc^;Jdp%&5V0oRBq(Wzh=9yRC6h0%8D;cGI&rj}!dvVfBoVMu2yxwlJ@uWcLJaV2R*hRTK_y7L>YlH7P^BFBYC1#H} zVgd1uBUp|5dg1du9Yi^J2_cN{vXR$0dQw_P|9Rp6L>e6n_k;?mB;FR4y(b{O(w`I$V0+4dy!~wipX3slL zXr+9--8N|Je7=s52F@E&(L3$$5>ls5Ri1ZF*zf1%wBydlFWI(N>?PVtP0aDzLF0Iq zpOA9lc-1wBWnA+bq1)xLR^O$rjnA`k84D*t`_#VtWuhSqs;&1@oHIi^SvBGq5nC{} z|LA*;z2g;XCi#`}=$~F|jVky%g^EMZlzr4Y>Hk}&7qt}ByN^Hmi8Eq2LI`oUX=HpZ z5N{)f3jcEf-NdLoprvirPbXhG@yz0*0&!}`g@69I&Ta4qfVf8;zbCo>ldjCX&8?4b zYY2iSsWW$|O7QlD!~?EXce}MET+fF;<#29A1udR5qYj5oXo#myu#EG|mcOmP;Y5ZOg2s3@Sd&e;#0Ey=I z>7<&yj^01tA=2tr4)@uOCj`*aqFrD4zKMh!hRB#y#^gtwY|o)w)RdV#V|H^OkH5v6 zGk(k57v1zT(!F{-x zk4brsyACPa#@`2tN3$b}FVCzbPO38n*>61h!_Z87$kK};^KZD`;sU4X!_;ur%$qeV z)6nB~3@|^Epa0@--LQV*H7%ZVf*iWO4KYhMkNIogPs09QcbcE(@5>xngIjemFAo`! zYv@j4T#Du}hS$p0*H$BEHVDLe7FCtqn?neA>YXWv+{r2A z3%mK<8KfJdtU#VSiS|YlF6W6kbh>D3*~iuKtX1k+O?x%QPIV&75?Ogp-;avCK-z|? z(Mr6lz@y-Z0mk$(`^l#gT%e&`l`)1E*x2bFy);%H>vjsD!CvESr^0^zwqwC$*)KE4 z&7y{gXD)X|nFpNc8EzOYu`a)tq5Q}OzeLR5puQMmCH=gGW z;(lBI=Z(GS&7kFv)APUCu05yA;g0D z{q5}|2cPf$2P`i;TP&Yk_{OS!r~eWgZFSSM5-(^OvGy0btEc7sJrtJ1gKwF(6oEvyfyl+V zepgP>rWu6%CHxaWr};`%%J&!QF8o&)&+X+oJaJBZLr}*p1D8703J>ap2hmzeCx$i` zP|8r5PWR@O9{y&O!jS)P;@Q86-|z&R)oI%v_gfL~c^}y#@o29l|2gIF24GtQs6|2O z(m)4C*pHg_9O%Y(`vpOx6GNI0Uy^>ai#Y4co>QMgUs8z1Z(E{bu5{AALi4ZRREgiS zz}hoNM42I`(^5Gj2|5G4kbQAx4EehIMm`Y7Cq{q7dnfp3`n3Koyg}wcdvunm!YRv8 zNv&(FOIr7|P&~`aXsI~aoJ5_3kaIcmknbJa(G5XHn^)&%GBX1ycE^0qhM^5^*t2;94|TV% z?MkCMnampdOS)J;SB|u=TcL}IQi7-2l+}LBqOTxMoTNfky+0}GvbzYK&$p}Fe_FJt z*#ku9u{CraW3`a|#Ep?yi^iHCD(%L}=0E_PcO`sUUb;FidF}gU)7BYIIwfb(S&g+v zJ*y&5mDQ_hxG0l0S)ey1ZzQX;vtncY&NeePv%f z)=cLkcQ4L==zT8a@{7{N*&;dCi2Rq#AZSc3 zzrZ{Fte@OY#K(sg>}%Sa#CbqOY5ck*5Dg6-Fr8hK&02>h*Ts61!|Lt!vNhe=cQXd<=-NhSv1QBdn}W>1A=W8eg?N3nvD?;?hfF z_TH0CYr5LZXaOgUB9c?I8<~=%x)X302{o)6H}#zjmX~UJ`E)>qzE? z56vT`B*DcvwTik+I@sT~n&*IMe4AO%c&|yii`@Y+rdrTd-TUH^c%A5r(d|35n#W>Q z_#%_uog+^Ft6uahbL5aMR(Z9zZRpfsAXGK@2S$RRx>zh-I8AW(x{v!C1(8c_owW=A9;Z2 zdk-pip0CcyFcS@DwV3m?({zbYy0yl5*>_O<<`4DW0?bisSyxpMG_^IRcQ^Li4!3%N z#1_QwipW6zb#KI9Wqi#ATIRK~P*p6ROO-L4|NPO*K4;HuK`Mv6BcZ=x4gcN|I>WB% z_mp*Lyr9u~h{4k0OYMl0(Xi>VF{qWXPWR*SZ!=I^!3pVhvOOSkTlK|*FPtsw$PA(! z)|;1#i1!7WDU=uSwG=~>Fh)zi-Yr}Fvt!Dl$DAYFaz;(KPQ z6Yr;%%w!}RQpS`9mBNy3aDjH8Du$d{OSipA09vVOa=AvoB7xeV3FI*<$uv@|PtChr68oBy38Ky;L=95zFZo zjvmiEZ<(~S7U+9j=^xrLFkc_H_jQH%hjutp%3pg1-(%Z#ac2;%FZ5PVwLIHp@7v)5 zk|kb6jzsHgFRlQ9WT4k=D~^bFy6?)Uwk0r3GoD z`i{c_5WeFqW3&Iy#`dR!M7!X7v#$T)!9tS@=(Z1Y57n)__~O%gLV4$oIDS|A`PRQQ z3P9?AbXA|JK7Y94IH8pn`!=omyKS-}$3+O%M)o&&GfZ2x1BQbUORL*c8vqS&4JS-z z$E>D+83>--9#~-!A#vlOpCWd_b1_Na_oe*=;vr>W5J;R6QE z`Nx7ldga*M-G<~M{w>8h=R6i&4bl*GjB~g)Tv#AA^Y05z1XOo}fu z15NlXYu#4TL!A25@qHD!={DX^UCOA%=O~c#Zv~O9>^!n|=3PWx>iD{Br0eru>ykU1 z*{WOPBWkKxDczyB@$Z8mnMFzrcHV+6b=0EUp;*t~_st*HUGh1MoA~#w>GzKwkMy{c zyN5jJi%zvGvIwcRJo`qc)Xj~|d{afvaP!*V&metcVMgK(eMRok0LtYI=+YZ^q}%eC ztnn5$-k|(%BR~7<6t&^qMW*s|j|Rc1S9sei-l@p_U2g!0MvHl{mK^m0!G_#4nY==k z`)CkI*gJMdOHE#-Rg~wbywRe!WwUv}_`5)=Q)D9lq-&DM?o>q8Pb=Iwpk4(GoNYwN&E2{e}=7ltC!0C)>9l& z6~v`9A`SZ-i=DQ|1y<*1TSQ`X+In0-Sxto#c{Rz^`YZs6uB0UlxfHKjM6{d%=|oG3 z+gxlg6D@z#g4UhJZbJITF~jvaLeJ8tEd@@iSgvEjw?iRjb>@$FyCQN^5nnm_Cc#o+ zajW_K8B)gO(+;;YKS*`voYPGxqlH@iq9C<^%;nuRx@!Kd5;^Az!`(G`)dSyh5huR$ zWOt3B`ut)-`jpZ7h{0{Oc>_Q+w~?ZBTlUr~+ufiQ-)yS}~9 zn$u|}lzavAZgh0y0B|IM?iz@eGt&G{L}e0pN?pnYXGCz9bTNwpoi~ix3ha44fj9?r z<8?K0Zw)j@#IeL_WwOp0xh2%|JZ=Y=JaY!}w)aE}Pw+fklygi=pdo!h)UxDc^1awn5(R%A9(K67w1!uL8?E)?T8eY|l zN=%(>j-chv?A-4-_1R|7umZyEHO4BxFUSxqSWRyAz~e3;SoXEk4r4XfU0#d6x`d4( z|5_n5Qeo<5+Czxebhm-Z<+hI+YH(>%krM>U8OTEGdfOVd0${U>BbI`SvK|36{pV-8 zBmSMX%Uis}`DtyqqGqesmlFia{=DMOkMF>m_6a~s#%`dFSPD@x#jH|L*YL z3!~1J_xe~Z`?r5KXxmwFCtH8{pH+ryqt1dZwyN~|$B#!mZsR-5GUQyNIZ|vqe1yv3 zyOJe~9ob8-$691_AH)`<{^Os!C{ErSq19Efc~CIYrf+FM(Pwsz2J6-aQXfOSHs9kfIQ zfuPXa*4jEiwA!kjl!6_VNU=g}MJXsCNxrrBK8fDm@80iw-v9I7?|q)XK0NXK&RToz zwTH9MK6|gVwpMx|!idlZJ${a}2M=9cXay9~eY~loep%#&2!zDlrlWoJd2_xpn*dEV z|Jic1H!6?p{BYsu@7ba-)*p}OF}S^OU8*vy!UCLuoeV_e+nGjMQ^35D{Oe}#bmA@N z#oV5gRx%@_<|!+1`l!;jQXv{Pl4by`0w4!}&HX?^`#{BIU@}WqAbrwty5WJxf(AUCoL2laLOi5;jXCH^5>p0N!F$16(P@0u0-W%z z4beHl;|Qk{cD`2vzPXy87FdA>E3DwtTf%DX4SPg(trOxDnSkac7@7`txEvC9%X@S7 z;MTHjE(G6kU{A|>ccE|5yohqv_lj5Er-rZxYNBUAX9HOGt;;zVh4MpRpRa+bi5k~6 ztmK!&dU-d|8hz~|`?F@V2si^%6$3PkFRT>su`S5oul;@zqWNDm8rIC~+(FU_NAwBO z=a%HO;JF6&YdvZUXKCPj+@-1SGCpjDbOAD_Y7x9piT!TC;)^{eQGRuZ=2J7nDFm~Z z?`$GKutnLx_2bHtijtBXoblz`+6$aCGTD;YQ zq=2xMBYIw`9bHw8aoI`oS=CSS*NDyOy!#;X%>XCk}C7R_kL2y0PW zfhI%|O@)Or64NlUQx+sdp-5v8EfTi(uuX8C2~dRBZLj5Z+R0mA)FayI2=I%TAMSV1 z3Mj0wcwok!oUl^-1r}B`Smf2Dl6Yf10o7{jVBE#|0SeOA8N@yxi;$GAx$w;lK^g*laJbh`O8d5)sm)3x zB|LplNi{*7Gn^l?$Z8JnHRt2!0nzg6v=0zH{mNAa2wVEoO#CG*+SDttSIwVvaU04n zYT*NeBbKdUy@Mp(vfcK&7C8i5wk1P=AJy~QM5#GIQ|d9^v=z7Okx25a{eg!A$7 zZZcssAd{(FelPHK4Z9eAUQCk}Xb55dM*Jll@71xRhzs3mprXNOSD0{`Q`;ruR|!|bjU4;(8ESqiLLDo)sEjRyFnQdtxMy?(F|zB z88@PLM;-_AE7T)e=lX`Y=QgcMp#X5Emdv?XlK#R^rx_!l#7@P^^1MEWmnVmK$F_EPAY%5;qp2YLS0dIMTBcd1!C=>5oJz} zUIes68$@wx8Q$lEdkDmNZWqojO$}dZ1sd#Yzg*W_uZ^fioS}}Q6*UuVWis5h#0S9P z+7-e!x-~0Ifhb)(jL>r+q^ahx1rXQEb1>B%(*oJL@6JD!Q-R0wV7ta_*xHoVGgA+o z5Q%Y%BUtD>@f1SvjSe0;j&x~BGND0~Mpvvr;=AMaT4d9a(FW0glO21=8U#db%R(}f z{0DcO0Y}$dqXo&lG~$m;h~UBQfWvCV?EcRyws{+YMs{!tXN1S<0r_@m8&E{yRy;z- zAD9~oUeOgVaS&(1_3|vr?R6^cD6njFxO`A~0t!4G zvc13789_#{gx1JsBYvG_SnE4l4=Av6(_mHJ2btlK2tie+D!*9wgsIvH2z+9O4G1BE zY6zkQc8(ehGSog!z6L2l?=ZU%tp0JkgSXBkyBBy8m@FjS=mA)<4xhxP>!I>0a>#rT zq_hX2v92l^I02cptIOtpgnJ0+g2q9EBowE!jk>LkJSwYOXvLgc29>a)OU6j9z#eRm zypu~8Bn6^_#?gGT|)dY6J_d~qhN2I_zClP zg5Ke1!??);oYHnrWVOmZ0m6v`kACr;Wb3J1J12$&S4Kkqf~N_<+#E$#TLs zx=fYkO2=vF4Q`c4*mO9`(M6#P`8z$N7MB#^HwQfJv+GX>%h|e zuY8^iG%9eg!Q9l`@X|07poHEAh^pjD7kE7Ri=n4f>}f$L;^3Va8W4joJ+vo1q^=#3 zae|L%Y_lqMrJlpRPI#?2MG8ys5fUq+4KahW8jZ8bJTe%N{Ial>o1q1)!}Rwe*|w?&P{0KToV#$-hE>eNJ5r!}05H6mJ9TBV^%weKu0AG2|} zc!wjI^?8jgTo&Tn1YV1)t-u-YH866;#wTht7{wO#?o&5q*J+Q6uoPxU-2jm^u{}d< zQU5xan49O~_1*Z|tf5&=%7&Izdf<#3(O+sP0M1+!O4m6X=8>Acs(33xr^9;TjnJT- zhEQDkn2^Xl@+#G*7CA@au<|NM2|AYzGkQex-kCZe zECMS9UxauQZ=_3Ffp!`Ic%7#1&I@mmh3pUk5`s-v9=3c)1_bGX<^hd(X$dFvqy$O3 z*qwUc3*v3BNiJrS{TyG20y0B-hCS!Ndlw9tk!`G1gwKROgM^V_1uQgzOrL2L1K7qI zzyHY2Im{XGyl#SR*Mqm+p2#S_Jbx#<4~zB`wL=_d4vxiGo-BwVqXw=W9}cB{T$XJ#CIrlK%4Nr zysFs*QXqo(c8JfgwRx!?5cMs1tGexGa7>Fyt{B$@tqdS>Uq|jt4K;1GRrzg1QpQ85 zZSAR+D)QaI%MQ_{`+xSWXlpXikl)L;jr&uGzf1yevg*U{Y9BRkvj8mttY}tOHL|;9 z37vAY4%r@%I=h7I&q^A}c_HzzkBlr($o_4-m!o2PU73p1b!_K*<`L!FW}0>wLFR+A z<;{lEh1!?VDw^wf3ZbUTL^LAFb{9b~G zW;juLY|4<2@I{mkBaSP&II^aohSoVZ#Ti{R@L*=Ygb^+0WNPg^Jxlu}*^nVP z0RWzG9g64Swmce`Grn+;NBp@U_C}~f=!${>IV^+VNDzL~iqpLr+Bm&?YUJ-Cf?nJM zZ+o&{0O?+ybEKp@7_Sq7mk;cSx#K8-B^Sk{iYfdS1v`(yyJ!&i$9^XU?SvqR3m}Vo zWtbl2(4iolI32_>duSX)RoaG;&(Z51;NKsAIn@N5y!m}m;A8YR)qa#NC~#0admVJv zA`2iPe{i=q#{uH31euE5_Mbr8e#86oY_e~G5IWI<)F2>JihI86y?Iqe$`B(ak*^Ya zO>lM>EWzOUbz*M?98pt|F2YaFgg!<8EQsD@lP*=p=#NKKY zrHY+v0BtQi?`#AQ;l#lmC16xDut0>N1Gf~8al;oZNCtd%78?lJuh9wqke z1U1;G2KzxfFhadlNYB^Z66ejfV$=XpHnr?&0-)#1k-xdt{3rCK4c5(W(mkLtvYgXl z{l)kyn+~ENxO(0A-iF+2=L|N&DC7`eSJm66>^0$Z)q}f-Uc}75R@UQLS<+SIz0nF%A~vTQI!d~qBXx#s z8CQ3_*G1lOys{PGA)3x=7I^HD>nZ!-3(RbRbkg<>;7h7;ZpQPF_{-oU_S*MhrE~Q_ z1FM}4=~2zuA!SxTzF?_LNzZ*t-cCMUIfJ?ebS{SpXaNonXBo2dABQ>ZX)tEBC@QrG z!PhlBjVO+p9#Ftgm9xqKZ?)|fgdo^Aq?=p!rU_7FpO4en*xImdgcT6O%uKedx3gAk zfycSYmKk;)YcYt<_|aaC%EGH~{=I%9o6gP-A<@Eo{0EC)-+oebb|I4D+cQ(_lind_ zV{(-Zsv^qHh{;N@ciEshv+n0GGLQ5H|GtQ(GZIxDO6OhH8!Iwg*m;q4~oUwju6cf zD@xZIQ3A%j;hF}F`usFL2Tw$ui$n<3OTJsC_x78rnNXj^uEfXRR`NmFjVO|XkMQ>J zS7H7C`-OUxuC%f^-knYuFqkTHwnS*3Lo$VBl98*8hDzd93!0(QhOxTz`3-TK&P9Igj`AN62KzN8Jx zZUy9fBXe+OT`MaS(wXz?S|izB&^K3=SB_!<{E0$V#`+ z|0k8BsBJ3gyF%!@`9&8(=V6(UyXsC30eulYsnE8q&zV4`Z*SF*uR~U=93Gyx zvjq^!9a=1c#A)+6FmIKt+9pw(^+5CMGe_7Onj>5GTM1`ze%JRAt&3SCc0ljZ?Gphl z$(GYxS^|?6+^>Cfm9SxC(_Skz0S$bbmiwLu+7vw?-`=@{KF}(yixJI7cUg=4NiNnP zB-9Ry9YxS$ORRw4{chJ8v~46mVM`@weL_m=6TMePILzjz3K4Mn_C*|$H9*^%Q97Py z2m1PCqZLVe%KP_R47*i)ACO>fQ$FC^IdgDZk`YkgnTGyU_G> zlP^<3EB6uOGGMgbDS6FH4^kkmyR0;|sw*T>1j~XE<_-uu4fBa_iYJ?KoA)XbC z{ABbVvFyzs)eg?aVKR_55RE0XnT-p~V*+IGmQFN)Z?DO$xDc00VZ?MXyS)Xvw=f{5OJb4)DK zIW>c2Ul{>`6bXDYTm5BLK=Hb3T4&j+%kLGM044Tpf%86{DF#b2Ml}sXa1J9`k3^9w z_SOkY&*}9*i}TxT58a+#Nyd4ImktJ(sxHkwL_<-{Q0#9K)ht%)@Sg)Q-$~3I)>o)q z8D<2|gx1Ns*1{Q{WXy_1n(dKQkatx=-~9bL2;@LUMX6N)GF_3xfOCe_ox5)l%$m_E z4&GmhgI8>D8JH_RZ-pFS{~;KnL!?NzCIf;QHEE+l3m}{y#FZxF8N6k1!~!A(){r0y z<++BlxZM+vZ&`U)4*rujISX=X$g>&m?;M5KN|snbCdB)FEfhsvPZa?Q(U?n%`{0z) zT0J1VE(IrtkzNq*@7T1X4%R2|+d|m9Ww!L#2Zp3ut(D8BFU?#$b*=ARd0 zG!@pf_T*HNH%a_Q^&YbhYWI`;KuX_qh%ePrCxUe7Ya-NLyAX>lw^(baY{gnb4epQJ zlT)F@wFEW4$#7M-muQyIBDecO>?!gVmG;311|C4o^;VDx?T&nm8d{%6IV9WybX0YK zyk+8`UJONf)$&li_Ye{Jzd9Uos_Ej}4OA#mX&oLBf+1drP->^H!+|q#4!D#J-!@)A~I~B=9 zt5hv@CP*i}0o$Yyh#(DrA3NZ8zMl* zL_7u**rym!JIt*C*AYT`!fC4MWDOo-m3btz!c&dke?o|Aq_~h;#m)pEMr&{@93!*H z3hBJxE6T0@GpdxF&;#itp{?Nkv;@(FPnfl^BFH`~0YheOPM_>x%L9n!I}bie4_X>p zmm-Ah3r5(*#dD((f+#B}s*6k-E>Z2B($Iu z$xiU8un;7g?tloR@3SZv>>zx+%Ux)|?IDVDfanVMJ!mB9LTWX#he+)rt&gg%mXc_v z(vFnR#&R9(37>2hh4ke&GhCmLJX_X_eGMCY=R-8slz&^o7& zJ%bCgA{wlrnEyQ&NQE3?UQlYxenHj z8r2|r9~I-i1W&*qcxB0#hI^}FK5N;@_TRZe%tnx95FpmZ~DyH5oGtzk8Wox8cp zK+2BFSLl`rS_j__arl!RBUFQX?rP0hH_%+lRdzWT1K6|?WPE}8gh*)@N|H$Kvj$<` z#9_|SgDxO56xMA@Zyy%{f-;bJ&7?#f$+V{K+Ec1xOl#i)C2~ik?U>zjX3U3zkUbVQ zod`xEGXLb2_ofX5xXy$`da50%Y+oYfL+7YqnNSlOZc7}*o)6|{p7sz}J;1#Hd{@!B zR2Z2hpqi-p?pv|ptP$ncF>7$IO3g+H0-CI*c6$=L?gsStgHV;wUT1p`)lr1bdMLAw4h5alj|15z){(gQIXcSusQPIl>w4T$f1FDIkpB@V*SQ z1#xyL@Y{l{%}6`s3+5QooF~X01C-WhK-<{TV8Wa*<@>O&)>T^6mo$c_+lZ7|H&ceT zx=UO9KrbaLZT=L~Ad1s&`wZu~r9_Hi+0|2zA54pkFHEPZhsIcMx-PrK-t9aYn03pH0+Ik-eab#{3B;kPK1$Q~)x zTs`5Uy>s}w!tP^EW;r1`nJb6O>1WI@hq<3I*{ma##eG2!=rQN4{yDIG#(sr#Mxm1% z+?EkQG_v)0h3UP5w6?-4u9QZrkh^3KRco|EizN!!D3OaeQ=Gqoa;!!mTB zfX8AZMhaLJ(>8vCdzR;M!O-giqEcct?s?o3VrUq1YC^5RiK0fW?=NHRRB;TcA#+Z} zGkTywItUHy4KW)LVxzr*#fu3LFL1DIPDg5xU!xTeyffmz zsVOz`5JHFsU-OFESSz5U)fAY8ELG$SgJ_w`H-O!RQR9qCQ#8VH0pB zndgOj1UV(kN9qBEZRrWk-R;Uj+7$|KLvLrvcq`C^^L&EBgB`37vG>uQAefE9)X@aA zhf=Ga@K(B{_}WziS`@d*7p23oeL(9)cozfH3@6%%cOH0%?$_*bE>Pm!Vb^j%>0V*= zb&AnWAsYu0_BU??Ej=eEv38`F@9z;Ng|Kx7JCm@#c_N4Pz?;{j43}D1U%fe0(gV9Y3i1tvG)tFUWTOKnoSb|Ez9zbT-qAxkT=v3THeFJW0DpZFDPCxec)N3X zW-;QN&|97t+9m@JHH7e77{&sT$%1G-swi_#&yIfl4K$_Thew#k42C5e0q%QdU}l7Gs^rGnl+PS*wAR$y+yUwB{m#z0nUNLQmPl(M-$Vx8FOdC33T*_C?WjNyzrm9TPbpK3J#PJGHYg$8%J z*gX!>pP*;XCnBIh4rnQ+OZAC`puz;C8Lp*RV|^jr2y0zfPsDjg3gnK;!0HkUlX@*XI{(xodpVag z@%ZU=am{Oy?)m4#mnLuBQt8v(l887HEb{&Y^Tf+7xfoeDUyp3$bd%PMhDE-O%OWpl zeqsX7huX_mt{vh!n{f|8n$2oN{Y4KnT%rmGylfQ6q3pneN!?+sNxCJu4p2 zYUoQO2Pj{EaN~p5T2`BYGX`qnP8sm2uWy3|Q=J89Q+NL!4<@JI(M&| zGRv-XGVy(9@Usb8o74`UZp~qody=i;{c3j)iA#b0SsHlx{HG?ML66LEmP&0G4vPRK zfXwfpZJV)X@zb3PS65E#(j7rG*v+-8-BNf(;pt$1#;#AmNQ5op$U3b@;J~BE7LM!? zC-iQvdgPBs4=WcLK?+2qh4)JK&;AeV0iijj$B@{@A8Q2!=jLuU{yG$o@j*yZ6pH<+KHFH9ICMZk$r8xJ2+0qvp5M{aE3thJd`YE9vDVTKLSwatPnGR$;k_R$u!78lo}8cVlqk{m?%jH} zMlFc^b$(X}?pfphp$xDpHpB3pqGL~&2&6pHQCfMYw6O;r67_BE)gU~Ri#>qW$a30E z_{$Wp2sUYKm6#^&)113i2o5^9uHmbv`i|DHvRAfx_fp&X=k<^SyyGH~cL^y2)Qi?o zkkeU-SB79+acZ@@t`k1WvHR9OVXJ-trAxfNB`@4fi}Syzb#60sR4lRr4c6F= zi%mojtP&@86PeOJc~w3(C)5KCw@QXtb7l?z9OLY?_9ImUwo2k{25SoKVQs|TWEZFC zJ=PKyjKbk8-enapMp;ohhmXO!ZBg}g7O51LazLSo=6$rcT05zEZabz0Oziviz;at7 zLB5XCoRp-llO33bBUrg}NbD(^b!5BZBNZNn;lxc{*ulkBb3d?v%xT*PbSIi-A3Tf4 z@%4*;>vA=Z@+TttUJbHtNmaJ4}E;<_b;I zOARdsDQ8%dT3Td9V0FRLw|EUh%485g?#>I%<0*tL9h%dGAbvh*>bzQ6mJw>>l~)!`{#VFHGCjtAm}_)Kw)S zpiQe(4EVzN+FOfEfS?^h;cEh>NC-uC!z|X^R-wCQ1cai**}-a@tWS8qSLs{>UkrB4 z>3c!qgzt`Y!`Wou6khOK!9Cn6?^9U;4KG47+!A*6)z_|B;nQSM^kU6?$|3F@M9s=C z69Fg8g>R_gyvW<9jDRBQYO3cgD`8_~L3|sqL~zx_$X&4W(*(w``282y=?T$lYqaT; z^+?KffnEF!1P$^)Qas=*1cDS-Ht(|n3hmq~m-uW`z8{JZc&<;fgLjt*_pD%^ab{3h zsglI(2ajoFFPuYY;PH+)XA%T{?9^)SZ8?N9^pxmLDBo;?#5Uz*_%dW=g4ggcJ46x+ zA~|$%Zl+Hy)v}yd&w>L$6^lYfT%TF1IsGV`!*I&69;|r@r(}e6=74vplF))8t-xu1 znx)B1Gwra>R)KQ>-{a8($&Jde22?)q3596bW)(pp>C+uSj?(n7rHCfpnDKFIO_`cV z5pP7fH>OPuMYPaU1&-Rm()4gFGqkgyK5pUWxg>{BTY+PDeyx_xZ)5b$pnO;EQJoaz zS85(q)UThPsdTyqYQ8GKswu^sGP*mQHQ&wLFmwz zGi-jRgB(RrT7sgwl%rec_h#0T+<~(wcb8U-a}T+Cwo#j3rZN%QnLR)=x$629XRqDc z)px-w`c1oPem4YIAE7;s^yP@o+=UucQsHHVICaf8Fz&eT!!MY{RA*yqmV_QB% zM8Ua(pDE;5krRzk(1@P;fzKOV?I62xZP&7fdC^45A8O!yCsT|O%r36euy$dQqWXmI zMleI@(wP4MfJP}r&GxR4ic1JVgf3NG^CHceuMwKoJ2&d5jgl`5l8k_aj<*zMbyw-_ zDnx@=_>V5o)P|UGI*1a7XsngjwDz2ucfa)LIX#5Z@toSIA4Xg*aiNyFA7pUy!4HU* z)RFVY%+WGt8L|bHP zZKa8&ncJq^I(5_vC}Cm!ruecP_IoAK%dtPRNqd#pf(P_h!5U|nlUVnGE?|XWfcdT- z(ghx4?us?X$vIU#n{w?OBzC-;E^U#)F1`pjiH#DB^SFn=tP)}+xmL)N`U1-g?Wu4y zh6Txlh=VZhva9E?k2enXtJ3{(Ixkz;j#KM|LW>&r?wmEe3HLOu^cY&&zAtqRw!cNxTAGMBdpVNM@^=kU;yvTM6n z>Vb1iNy8xRDC(`S0|5IMhuF7qTW95JDbfV_7&Qs+2| zA!3i-MXN8nT8Y2$Q106sT{K~9kWLslkXC_Z`jkPWw0#F`5O9!t!>a*~GHx&djT=<_oW(9J~*JQKh-uRy~L~$4-H`O%>(t-1&oZDx0jNw5WWB zlJbr!`~)DaA++?>Dx9BhA4D}Xmvs|8eS77DbmKM_3AG9+ZD}`|J^8jk3@JyMb9aIj zq8_9mt?9n3IJ+2N>gnwxA7;QV|(x(2Pet-Ioo z2snkU5TmYfYj-8?gMMXJ-KRdmOGD~M)LBHzYhSI^QWwNL-p*j;6?f)u~f8w$JDrZcZbDDaeL5A7(C zMZ_Y6EM?$ScO$V*AxKzwW}ykw;8YIZyf;W>1w;dzn#Q}4u<^uF!dafXH#l!+>r*0} z4rJc3poMgM!Cu%U6VRUUM%xt^=S;QR))sL(Pgi}n*vd-T3xV3sEHbfZCge``Y>+Mi zPRY%4d5DJR_Id*(SBy;u4PvqdlCRAsdrAJ7~%;KJwdaX4k*J3i4|xN;n$IQP}zNwE#F+w6H2?l zglMn+lzG0uRd!Tb$DW+dZ>>f|gLK21Qo7GnSpmg=gaRJs41V^T2oTsHN9B68&RU*f z1jO4igv_>s1hINRLc!2lbOtkPk>$1U)G_C5X^FrJG&mj1uo#8zt3^mSyJ6L$`Ng_3 zM-fVtRXJ-enssM3Ar$zdXV0BTe(02p?Z`4G3em!~w|C@M<AjYanv0l|9{a~4Uhh}Ji^=F%q0z^nlPZ`iRlXbwhvWl=hR^cJNt zCm=OYAw%QqUH zX)?QjwUS`8A4l5HA7*6d58o2o)Ahg^zH3Iq+*&lDumVc->)rC|#VbZuLd49p*-af`MpPY3mQYShS+(ZJf?I!|+>qZ9`WrLJ4q+-<@}3 zVlU+0mVWCTrg=GMtcKD$iDr={&)}IH>Sw2vPH`Yl4>XVov1lCZnlXCfthL+OK9~qDnLanYo#d2YI6-mfjtz4B zHpB0_I)9tr5-UiFe{lXjgvy>10ZRNR>Y-a<&R0> zWK9{K!6)`^dFmf|@b8br7-WAaKoE~Us z^)G3enT$67Ie6@WcArPLrQ9lBj?ziNlJZ$-+afGwT4@99fIEE_<6fSq zb?!G@&FK;J8iA9nacUaQF3|%@>S++wxh<{(Pc;z#elNrsTjmU@tCQJOW)VV}4wLk% z&PMF(&=Y>0Lg&2dftD1#w0LZabILO#t$-$W3J%fNVARKB0g51yJ{0Ef`x2sg&#w(I z&*)zCa5X~IgzF6uhllm8_J&}*%}u?!2cAVVDT)pce%LbHngZSiv|`5k3c;#7*zlOy zZ^|*HWc|A0d6aHSc;Hd+N8k}l*fC|!G$+{et^Gp;v}pJOgLOVGDG|^lhSNDcR3uIp zRu49%5CtL32%Puz!t5!h-SdY7h!)c+w}WqlfXE!zH{U+1L3?!_ZX=Mw9B!T5{J-po-EpO)h`$$U%u7_9QMc29k9?kTdE zeI9fE8TDEyt`|L|8(-M4&+%o`2QoZ*2ij&0mN_aP4-d5h4R+&)s-0o~;|; z3%)}60-_~-q_F#5%^Cdenh0@TLMM@?o+szdf&ZR&@Ox90Oz>l7g z&YQJ#3XoMb*A9iJ}XS%!U4F%W3=GO+%>r7NL1w zx#=`CwOw*Lt&mO{_|?PRf`b{(dr^6WwcU@APhj(s9wZ!qHi@xc0OOf`+-@i9FyuwPf{x|61pY_8&({n6( zkip>~^z(E0k|53x&v9tVi0(W*jx+2tJ-UJaK?=D1`FSIO9F&el(PJdTL2AX)+Ad>i`S&SCj!Ldk(v` zvIffuknX=jAXoZm{J+Tc523)bV@3{xer3tA0E%`siZ`N3E$}45DeK8ns|yW5lNl_4 zP>^gNFUC;7F(TS^9z(lnfoB2PT{5LsZ}bl&10&AQ!%aiEd!SREaqgTkBVoc}v>-nC z$0D{w$;Z}mIhHXrCm9nt*tm&Yibhh#XfX4S79l(lj(LI-dUJ4H3kt)bw?6icX)~g6 zxdkcSg=-ASdJ!NgU9MH3OW-vr2drE{7as(%kE<`5idECc?TM#6`Bn~dax?Je6=pT)=P7Q>N5aL~4 zi)v7Wu92QxPCu8DqH7)_xP&M?{00Jyo>H67 zKtbLaVLS$&JoqOdEhsg@^++fYv{|wUlidAN1SC#0YT0C{K{BF%+MlB;x%*#o1};!6 z+Y4MINCzUlV_g{jH?l>Cp^$dph92UH7}*>qQt$$>B#T6tfy<@2h)CLxCt%hfPPXRx zT$II&L=v>L(P%MwkHL_~cw#9oPNEC$gHUz|M`&exB%FCW3^IU!DBUzJG?zPfsFk~N z_nzp*AXV7h$CEBka)&meU?gC3_vQ&eiYa6E{YWN46lG=0;LZ2o-YJ7O&(i~!kLWp( zs7aocFh9Xvv}g{6^ki!ZKUK!$jIa=t13Vqj<&xRwFJ!m}u6Uv+)CY7crHa- zkQkJXGjbd?>toe@Js0(FOR3q*hsLgfQi;6;ct5&v>l;{QMw$RSx2CPL5~a-b+n z25D(hM<@$KgINK3G`7xWwf6GlBB`W5v1Mm_0dF`o1Y2cn4Vum_bk`CZ=ybtlp4JVp=o3w*vi%tAjrT~^WJP5MI+8IKlJPR z=k0o!@eRgveaM;=k!m6?ktdT%Ta2ksvXf|z;5y{UCX`y)3;ds`aE%e>4B!%g;OsQr z^nDMYt0{Oa;=+`IqB%6p@$}?)c%a{5!#L1zG{b>Ea+6B~32sre2jamHT>vNi-t~t> zaalIR%(x`DdEgHG5lB(&wfl~n4KDu0O;8L;M(QE0;PrmD0_fVE5aa_7K;R(-am$CB zbpgh?>hC&yl65KZtgNx^G5{HMFK?wPU3v`W{ zX&MU$29nS%;V%&K;;}lgnh>pU!oTPSqR<_ps#_q2|8Sqk1hKB%-I77V-AclJx5DfN zNF$QnzyCr$QG=v{jK~F-!95LkA=GgA4>~RGHt<~FZU)^33gR&gJ}o#jTzKK92DJ$4 zLSA0Cyg2ZOboTUu<{&jmY8ZYI8zw=HaB=r9O9J7zO3^RRYXH81NtgCwuR$QoiHn9b z_w=&En;!GKN$7&y`R89RuYP#dyHq6#|JQz<6vx5k-1guM4nx1>@9t|t`pcdFo4iOt z{%?NSx^;Cts2%vQ<1nZvxRcXROSqzdnE?{R{(8{Rd@LKeCPhG1hntE0#ZQV`+T9oK zHbpmaDtFp{Ah{axZXWjfFC;ho|9C;#9fY{G!gu~bD?++EBX|VxvyW z|F#Bb7+3!?M*TOzd(ZNJQ^npBd#?uW)xfftATqp@IS8x?lveQ7IFXQy>fVg;y&z9>8)B7~F~x+c1FW4wwBU5|EA1zYql^VnKvb5ksSY!3h#bj{i#3zq${`Y(N5g zHe|c#g|Z_`x_^m%AV6dqicR2%!mLWTL~dqsfdsnlgM5?_3kM@Z@&_h=V0JsiaNK`z z-+ld;i+@A<3+I0aBnp$lq8>upl*7qLd2BjzVi0lik-;{n1x(Y?Ki7Q|$BFUpa6jj+ z`zg`eu{AkEQ=BeH;^N;OeG}gw5BHP7Slo4==bVoPO@;e!gRdjHUkLKH(Wl`KhjRpe zPjk+2zT|wx`I_?$=UdKM&N)sq=Q~adrI2So>94p|v z|6Ss=bAIJ?a4vIx<6Pl%a=JJ+&Q;FuoIg0%INhA2k!1*DlX26IYd>kl-@}P!Mo)izd$Z%=|HIf=d@hJi2 zO$jL<%9rw^{Hf7Y05yiXj~YvjqsCJcsEJe{C8B~TF%?XOP!ehq6-tFs;Zy__N!?F9 zKuxBisA%dzY6=xYO{E^99;P0lVyQUF>5OOVyA<^0Sfy5^H*#&&@U{F*zK);8&*snN zKhA%GKaW43pTpPlpX5Kq{~P~l{sR6p{Ac+K`HT3A`AhiE@t^0vz+cLLk^d6^W&SJt zW&Gv*SNSXWEBUYSSMgW#bNPAve7=Ei&{|3K@|0lnf-^ahnzs2w85AX;1xA{YS zJKw>FYUXnUlz=Os1&qK$FihYn;0e40!v!M*BL$-be1SmVEf5NP1ik`4fxlq1AV4ri zaGzkTV4PsQV1i(xAW$F@1PR1~U_ppLBA6ry6@&@G1rdTs!To{<1plTP|0ATyf+#_> z;6cy>c|xH2@tcAg&FOUcQ5Z(5s3wk@vT*d&G0v0Jan4HWGfp0Lf|F03ol&YC+KB)H6X(P|pU?2qnd-Brdom)P#p0y6j%H#MT-|wp5jFmPrR5KAznfW#m`Y=#m`d{#4k`2#Y?F` z@r#s5{1PP*zf6USU!lUp%cyYiawBafflVSt)jMzv$D=wfGi`P&~#A~TF;&s$o@p|fY@$1wE@dm0&Tu3#EizuJqVoD#f zk$N)Z4eF_oP1N5)Hd9ZBY@rr}Y^9zF*+xAZQbH{Z*-kAADWw*Nlu=7U-lU!j*+D%Y z@)q?%$lKJ?kawsTL*Auc3fW1$9I}ggCFDJdBPpjSiHYJ$c2l&Zf*L8=LkT36l((dc z@|EnR{3O*>fTV^RBdMjvNzBxENgXvovX2r;_EW)xd`^8S`GWdJa*Fy^a+>OvoS{4>eMt?Q^c9sn>1!%= z(l^xNN#9b>PdZC2opg@kL^o4Z^mi0Dx`m>nTPcs|^VG2D?xh1v`{0y!xKpOQ%Z;0|lUq4u7q@E4 zd)&QK%DL53Ox&6&ySa2s1$R`;9Mkee6t5jQ{P0C#iD$J{M32e~_A zKH=_)`IP%!%pvaXn8Vx?F-N#x#~kHyK-6rqimdI_~Qu$SGnf!O| zTk=1+Z_BT7-<5ZBcgnAGcgt^ZE9E`hD*2z>z4Bgejl7RrC%?(vC%?trFYo8p%LllJ zfuk8%(Cf_xbLtK5_B zkn`xvaxeOtd^mkwK7#I%kECzPN71+Ce40`S=-~=)dXz#)^A$d{K;cV!EBt7o!k-?i z7)?)51kh26G4xc$ee}bMv2?6r938J1Pft@!pc54n>FJ6c!WNnh^0SP#L-QPc>1^^f&NS}jXt4Bq|Ydl=>DrV7M8MEmT8R_(>3>oc{F^3+V@hE*? z#$$9~hMW%0P|zV68T6zKB^{Zeq94dm(+_88=(r3mot}|ND>8KS6B$|bf{bkX<&3%X zvW&;+w=2n!N=+=zq=$|s4r>|tZK;O<-N^_Ji(v0#Y+DG{^9jJVTj!-V6 zrzn@xDau#r>B<#!nsOyQL-`s#Q@M(srCd$VR_4;_$~=0GGM|1-X`tmwBb}ivpyw*r z&`&7W(hHR9=!MGl^b+Ok^mED$^z+I>`Xyx%yu z>&mTkv2q)|Nm)XdD7Vu)l%@3B$}-xde3PzH?x1UwZ_)ddZ_^(s-=RNNzDple?xasB zchR3K-=n`&meXG;P4w5w-Sh=z1${}mhyG1jNncS`(Kh8?`i8QazNxIC`<1oyfYMA4 zD(h&wav#l6?Wbu~Jv~g-Kzpj*r+KQs)5BFC&_dORbb#t3dV=Zz9isY}mZ%QW;i^yQ zXw|3m!>U8{BdWu6tm+6IuR2O6s2b_%swR4t%0kOj$LPmY$LUPfXY}K$6ZGFyC+VkE zpVJFeU(iccr|1_|r|FkfXXxdsFX^?aujmb`ujwMyH}t!zZ|QQ?S=yvJNAFQJ)3vJa zXtSz?u2Z$re^;HSKT>^9f2#U{ZdCn9f2R70KB@Yd{zCN&eOh&aZdF~Re^9m2KdP+s z1=S_GP1R1ftA3?BR2}pc)n&Rz^&35?xFMeLdX{>So~^!3%hW@( zQf;SIY6q=WJ86xY!|2o$lcnY|bJaBSgqmUWY7gca^)P0s+LL)v&0}6tdoi!5hcnC6 zBbeptk<3c<}I~1^Nw1`l&gK18nrJ|tM+5|tNob|)uWli>Hy}rdJJ<) zeIIjLJ(fA69>;vC9?yKGp1^#qp2&Qo4rE%?BIdk0i1}VEW`0x$Ge4_Cm`iF2)2^Px z{HhLRI@DpzWpy~yrH){1>PY6Q`hMnj^#e?|dNOle9mU*GM>9R@2bn+BQ<$6T80MCG zD$}oih@mwPGmPdDhNp>Tyfksla7{cjLX*IZ)J$VWX%ZQ}CW#Sfq>Q&FnGtGIm~om^ zCQvh-5oywxNtzifBV$rEbC{W$N1550$Cz}DoRMi1j8c=q zEYv8O#Tpg!ibl=kYBWrqM$2r}WHN7Pbj$~uEapQ^Hgi-nm$7IbXO3x}U`}i1F_$#+ znNCd()1}cfJ(?#OM*9>qO#3&+Q~NaItzE#3);_~TX`f{t)GlO_w2PQD?P6x8b_oNA z12Jmt^UON!3rvxADYH@gBJ+;+C1$7gWoDQ56{cFdj4^AMGj-ZmnSI(7%=_Av%*Wc- zm|wN4m|>Z#8L!M-CLlA98IzgMgl8I<2Q!UKYGwiRXyzK`@yxZ%!pwEdvds0&%FNf9 zRhb)@4Vi^ZMP?E6Q)V&qbLK|oV&)r+HFFd5YvyL=dgd0UCvz+FXXZ9$FtdcQXKrU` zT`42bl`%fLH<>`)4klFh789m>n|VO@4il|=mr2#_WM=7hF*4nIOopzUQR+<0)4JWv zGr9_9v2G8uMpwyf)KxJRy1mRET{ZKiu7>$WSIhjOGc#?vI>xHo$Mov&pi%d#-atYeHO>o}v!`i#lSI>BUTon+=_ea_6!`hr=Mb&6S%b(&e8 zb%x2$`jT0j^%b){>uY95);G+~tZ$i`th3CAS?8F>tY+p|)_2SoSuM<&tXAf$tn*B3 z*7wZStRI-)vwmc*W&Oll&-$6Uk@XAHlXZc)m35Kv%5Gx>*;d9s`w}xcyPdf&`&VXc zb_X*)`!XZW{*4LEzQTlOcQO&#T}))QjhUQ%m3c7xcjl4oKbW-aYs{?dZf17&btXOg z2BXOCVU*c_GMemOMwi{kEXcmeEX=;eEY9v{UdSF`UdbM0mSx{&^0J4RHQ9D%ZMK71 zm+fSVvpF8yvnh`^v$-B`XVV^4*^Ea`wui^Q>|q|CW_x-Z&gOYEW_x*@&K~aZW%dY< zv)Lm(&Sj7C_%568(UL9jxSZ|n@msdg!$L(x?4`=ph4{C0J2R(O; z$C$bId5GqY^$4Fk&Le8>c#mmwCwQdHo%p{RHVdz|uLca)uHXBsd%N1|?dtCCu4_UP z5+V=*0s#^Tgy11SfD)X#yR56O?k?Nf)!p6w`~HXbJm)#*IWHJJuNjy(uQ|}oYXK7G zwFG(dT7lAezk>bqT7%>B+JIB@+Jf8j+5sYK4_eAPfKIZGpsTDCm@4ZGX3Bm8b7Wn> zTv=BjmvsXHvhF}B>j5;fo*+op3+QCMfl<~6q{#Y$G+958F6$36WCK8^Y#{K;27xTu zV2~pl0t#e9L7{9ID3T2a#j+8gL^cwX%0_`Q*=SHM8v_=|#)8GNabSsTJXk850G7!n zg7vaVV54j@*dm((w#uf0KV;LuHraHrLpB5KmCXbPWV65_*=%rFHU}J$%>}1qzk>_1 zdElZ<2CmBF;JPdT+>|N6ZJ820l&QdDSs-{JQ-k+14frGr0$*fW@I$5pKV^DQS#AJT zD^CF9YqCd(8p*RjA6(>N9;v}#uPJvj( zX%MG41DuMpAYO3}Br48>B*g`gthfl$6qkTU@i)j(`~wOU{{p|_GALAB0VRt6K$+qy zSgyDRRw%B6HHsTxo#H0=LvagiQ``oBD(-;oio4*T;vP7zxDQS!9)OFAhv25-5xAvz z3_d8HfRBo&;EUoJ_^NmgzA0XSpNf~Dvho$ErhE;k@(rl2d<$wQ-+|i7_n?mQ1E{O~ z2q4Kh9?VnLhxy6|uu$0$E>bpvtCWr5YGo6+UfC3GQT_tADx1L_%I0v7vIRV-YzYr5 zTftMxU*TzGYxu9S4ZN&u3$G~K!E4I)@RqUze5&jS-zz)8@5;`wmg+ZHPt^rBQFVn) zRo!57Rd?80)dRLw^@QzIyAEs#OD_Ry7D3RD)r# zY6vu|hQd(QFc_v94sEItFheyGdR3#~eAQ^UKs5#~RE>p8RO8@s)p)o{H36;Ca<__@8P9yr!B7Z>na&yQ8>og80yS`AU=W-fsD-lvbx<9shnheG)CUGb zLtqHB1R7yjpb16=nqhpP1-b)6VRm2`^aX~)rGZwsA}|833XFuC18s0yU=;i-Fd7~W zjDhC@?eI;Y1AYpOg;X5}CAAaQP{+fX>I7Iz?Sl2xiLjB{4V$TxU>kKZ?4nMAJ=LkO zuR0A5P^ZHo>I^tk?SW&|nQ)xi3n!?v;3Rc6oT1Kvv(!E~SDgzj>O2^(&WBOz`OvN| zfC*|pbg2trvbqR*)WtAYT>=Z#rLa(428-0?uuNS6E7S|%8udcBNxcaEpZNdxdKo;dUJg&ISHN@XmGFXk6}+fk4KJ(Lz$@yt@Tz(pyslmkZ>cxH+v<(*nR*j^ zuHFpas<*%o>aFmj`VaU+y$x2@{0Wg}J0zMNu%>1wY^d1g)0a}Z9{9Qwb89for>N1$AD6zVm{ph0sSS~Mr1RdW(XYfeFj<}{4e zoPkN2voKwA4th1`VV>p!EYe(rrJ74{q2_P6Nb?U|toau%(_DrtG*{qC&3|x}<|7N()L7;wY|_YZEy5k+XsEo_C-~6{SegkM@TmSaos>9=?00?l5 zy&ZMaJ5W!3Eb6b1Lxc2AG)^CnChHT>6uk>g)hD89dN-P(PeQZx$w;nGK}vlp3e=|| zwLTqb^%=;l_n=UHCJNVkkxie4qV?G*UY~;!^gfiP&qY3c9xBl1qeA_BRH83HWqLm< z*B7FN`XaPgUyL^BOVBobDcY|uLx=R`=!Cukoz*Wu=kyEFdHo`EQNI{n(l0@m^-Ixz z`eo>~emQ!pUxD7~SEBd&Rp_gJHTt1ngMRAQqAG@UsH$N-s%F@LY8y79dWKD?zF{+J zVc3FN8n&VihCfhG!#32{@F(hL*p3DocA!CqooJY07aDHZjYb&ups|L(&{V@-G|jLN z%`ogoGYtoj+;9*D7!Dz&;V{x0j-V*RQIu#nhEfd2QNG~>Dm0u#iw&pH3d3o%(r^ZC zFq}mj4d>7%!+EsLZ~^T$TttTqm(X#;-{_>_A9TU+FZ$1L8QnBoK`#vdp*M!B=!@YR zsuX-3f#4g61>Zy>_!g3aZ=;66cTnTtyQoRZ;>bX9m)=VkLCw|K&8PS(aGRX z=v44$bUOG8x*Yr!T?zh%z6O6s--CZ37V;C-52=J3hE&GQLaN{vAyskvkZQO?2*4df zAnx`5$@L4txPJ)2gF+~t5W?`>5RR200tbdjI3c7uc7@cy*&#LY#gJO~YDjJTD5MUq zW~_^w8tdWa#`?I0u>o#nY>3+$8{zK8#<;(+2_9r@iU%8i!4r+m@ML3iJj2)mtBozO z#@Gr68Gpq(V{062Y=c9LZE>iv9gZ-z$C1VkIM&z^ry4uq3}a{PG5&@#ja{(c*cERz zcEf)dyW^e49(b3rC*Eu9g%2Bh8eHzF_Q!FB$ve%fC)W;|I2>YjVv{)@Tg(YK((J;~=0qH0cH?w&684&taj`iCmzq;?nK=z_ zFsI|q<_x^s?7{oYnfRpHi_e?0@MUv0zHQFIPt893+MJ8un)C2`b3XoPo{ztp3ox+w zF|rh5Y$?LTQjD3U1lP8d;zpJ-+}Ki%n_DVy3(ErB+OiP0u`I&vEsJp{%M#qhvJ{WE zEW@)c%kf;x3M{j%#Cppr9BNsO<1K4&f@LjsS=M2%Wj*#;HekPHBQCRS!sV9Dc(G** z-e%c~cUu0yhb`OiNz0%3yk$GSZrOovSa#xfmR-1V=x$skbPtB1e_;~37grD6hwFsy z$8|#w;O3zRam&y{xK-$3+%fbB?i6|y_YFOUM};28Geb{cdFV;33_XQ|LQi8$=ouUq zdKM>#p2LNq=kcb{3wU4XMZ7=s5J;Lk49^)Nh zPw>vLr}$XdGkiAeIsP2>0@n$Di5rE#!Y#sI<2K=MaPRQ9cwqQDJTCk_o*e!G{~rDk z2Zeva`tZ*?lHOKE`dc{}WEEtvRU%`o)yY_E4KmSMlT5ePBEMT}6PdLR z39!~BN^3n5Xsu7w)&@jxZAgNxjfmCSnAojNh|}7XxU9dBh1Oh=4^;hz*wKch7Z9}eF+mgrDcI270J$Y{JKt5SJl5f^dy(4;%J`p|1kceJnWJGT=Dxwe3MD!)rh<+qFqCZKC7(g;229nH(LBt<1 zn5>EzLN-SXB?lsgkrNTa$?1p@Gssz#0_FmfCrk>g3r$O)uJ zVBP9?I)X+#k@ov0#bkch~cBq?$h*%&#S?1`L1u0_rzcOri$ z4*(_wHEtLFj3nOw{I0>*>iOLp1)V4^Xwb_Wy7DYmA z(Im_kLn3T;5^Zyk1Y0c0w8fEZo0H_&;z_P8fvmB)$Yxt2*{jRYCrZT0pKwEhIOi7LmJA zi^;vHCFDiaQt~Eh8F?4AoP3H}L4HK7B$cCA5fZ(cu;?{}N3SK#qSuk;(d$Y7=nZ6G z^hPo?dJ_qZ-b^&nTZk@tD_Iu(2U#1vjjW6QlWd9JPOe7pAa|m7lKauS$iwK}cku%bz=^a)-i`jo0!9-ZOjqUJ?1Fs8FP&Ek2y|;#GD`j zF(-*J<`gl-oF<_$XNWcCEJ=(xN77=>ldPBvBsb4$ST((!DH|>?_J$n`U zz+RO;wpXLC?0|l?Lt4p!D05&cIS8%eptQb&(MAqVn>Ymh%^}h5j_P!vqXr%1s7Z%7 zYSE#N+H|<14jt{NOD8$%(aDbbbc&+^o$6>vHI7Eq=x9tM9ZhJIqbYSbexV7DW;D^! zoF+M1&}2tTn&)Um^Bup^1&-EqwWAGP?`TUmINH&jj`sARqXRwZ=t!?QI?-E>&h)P1 zH+tXEg+6g~r7s=b=m$r4`q|NgesT1qKOMa&j_plr#`d9&WBbzPvHfW4*#5Ll>;T#+ zb|CE+JBW^s9Zbi@4x!^>htdhL!|0UQ;dEN;2s%A>B%K*Miq4K5O;cmX(6rdGbbjnO zS`a&)7RFAXi()6z)v=T4y4cBdQ|uJFJ$5SH7dwp}ik(i6#?GL}V`tJ^v9svC*xB@X z>>S!6ZZ7Q`_d6XNH;)d9lhH|WavBjAK;z>SG%-#|-Ek_K5f?}^7tFCiL|lP zO`AKDXbWdDZRt#*9i6GPlQWHWai-I*&J5ba>7o6cnY6#tONTqN=m=*v9qG)W6P-Rf z)tO5b&O93E%%^JSe5!L6&~T@p+MIUEPe+aAHS1M zh~Gsg#qXvwo)D-xr(IVGtTJCy7 z7rEZj#jbaBnd?1W<@!KZyFStlu1|E6>oeW#`a-w5zS5npZ}gz+J3Zq1K~K4U(lf3~ z?1rl{yX~sN?zyV6cdlyelMAr#F374RA_fvMgNcNpM9Od?V>FSoMu~!TOO#lT#OkbH zVhuJqu_l|ESc}a}tj%U6)?voPx-2ZQ9*aq=&+Lf}m?N5Y*p@v{Y{%XvwrB4WJFstw z9T|3aV%*)CN$%fReRmhuz}=NKc6Vb<+}+tP?jEd}yC>`5?!`K}d$V5dKCHL9FYDv( z$NIVZvoY=gOy?fREbc)p)IFG4-9uQEdnn6v4`apd;jG*}f-Q58WXs*7*gE%Uw!uAy zZE}xgTioN=cK3L;!##oRaZhB2-ILgP_hfd_J%wFzPi6nQr?IQ<>FmCH27BP1$sW3A zv8V3Y?6rFitCBRA{Xe!akTj1;Nix5LSIx9}jU}ec3wmCVIZBO>H-N{+(P;xdq zo}9x@Ci~d=KBa<9PFcX_q%35HltnB!Wibm$S;CT2ma@W>Wvn=5Ia{8xf~`tf$yTSVVrx=X zv$ZK}*!q;UY(vUAwm)S(JDswD-AmcX9;a+#A5%87uPIv?O5Msjr~bhvr*30YQ~zZ1 zQnxdC>JFwz-N}rpyO=$7H;YZ(!#t^fv4YgSY-#E~b~JTAJDGZbolZT-&ZHh33N|`aPDOexGHgKVbg!hipyyBepgDG5a(93EQ9klpRQa#tx@HXJ^x2 zu)ot^vTNzD*v<6U>~{Ja_BQ=3`;`8UeNTVSex!e3DB~lmk@1Pu%J|G?XMADGjIYd^ z@r@;9d}oOnKUiwUPnMQZiDzb1<~bQvxId#RFU+XMOELgokpcPY48*r&V16Nk@Vgn5 zKgeLbl85su9>K9k;?z@}OP(6Mwx=eq@2SNbcxv-zo;tjhr!Mc{smD8e>ho@%2E2!- zA@AvF#QS?1^8ubFe4wW(pX&LAPxCb6Gd<1uEKdur@U-MAPb;qR{K|En);!qLh8sO? zxy93thk4rba8Czr^>pMBo=!Z?)0t;@e&b$G7oO$m%JV(lc!8%oFY@%@6`r1ap{EyL z>gmnbdiwBnp1yperyt+!>Cbm~2JqdUfqbuL5I^b}%ujlT@Kc_l{H$jfzu+0p|M86A z*E}Qn1J5Y_+%uZL@QmS~JY)G6&p7_WGoDwZ}5ikjoxs+)obN{dL#IDZzSL4wej8FD8APl&G&g@_yMn-AM`r-A#W@{>W$+k zyiR_`8_&;s6Zl21i(mC7@@rlFqIFgE! zLiS32GkX=klf9aM%3j02XRqZ|bJlT^v!2(<*}$9TY~<~8Ht`NQn|YU z4?Z$y8=sW(Cs*cd=Ycspcxlc~UXinlZ_L@vH|6Z%n{)o+J9GB(T{-*s?wtL6Z_WXJ zAm<=Ilyit5&N?>cYk zyTM!eZt~xJw|F<-ZQk8?hxhf}j-sjT@jL7PndG+ z3tMgj5uMvm#N;*-X}OI>R&EpF%WW$1a(@wpxy?jbZga6Tw}sfA+fp3KZ6%K8{wj{; zwic&y+lbS-ZN-_~cH(SqdvQLugSedAQC!RIB(CRn7I$-h6AyB`h=;jdg~;nBq`dB; zXI>A{C$Fa%nb%9m@_Gw(ULT>$>np+*()3wguEy}S|PN#02DJa3eElQ&wt%^M>=<&72J^2Q06KVHs_8fmJLkh!C3#BE``Ho48yMC7Sr7MF)S3 z=%>?8dQquxgFuBF1ufhpniOsp zzZ7l}Z40-G?uCDd>4n?G?7~0A?}giiqHu>$7w#0ng}a2gaJPso+#`|;{}Ne+dqq*< zKC!THzgSmzKwK<5C|(pE5^oC+i?4-8#LvQ`qH@tOQKjg(s9JPFfTEKE7M&8f=(MO& zbVk%HIxA`wofEZ-&Wrj*7es@ii=t7{CDEzqZ_&BvAJMbuUooKQvKUx&MNBOEPfRMh zDkc|Q6Elmhi&;fC#N48rLRNH3D2i?iebF7Uvgoe3T69m`EV?i56g?0xiyn$MMUTY0 zqQ~M}(G&5#=&ATo^h|)_=Ykf$5WM)Ms8Re%)GmH4+7-VMbBf;zfAKp}T>M_FEdC(Y z7Jn35ia&|1#h=Cg;xFP*@mF!U_?tLV{9PO?{vpm4{}dOBD@lJBSC)PjSCOQWs#2|z zYEtbIAhj!jQr8kB%`3su$`T@NFQL+*5++?P;nI^5Aw4gVq=BW?rD3Htq~WDCrBS7| zq?x6)rFo@wq|nm3Qg&%QDX+A?w7Rr`w5GJ7w63&~w7#^lbiA~Q^iOG1>1ydO(xcL5 z()-fpk|=8-)hKHzbuMcqbt(H*>Q~lU8c^0o8e7&@nqJmUnp4(Zx?k2odR*2~dRx{> zdRNw2`cU?pgvz@}Qh8UYad|hXU3qt@V|fp$Q+ZEmKzT1oUfx?$mG_YX%lk^E@_tfI zd4FkZ`2gun`9SG&`5@^_`CuugVu+MbF;vR07$y}~43`#EjF6UBjFfg%jFNU%jFxs) zjFI+MjFk>mjFV1RjF&D{OpvZrOq8xxOp>Gplcm}Vrbx{fOqB*Km?o(gOqa42%#bSo YoG(@VSs+#W>6gIILJ9sX`u`8=e>mHKZvX%Q literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/ARM9/data/sound_data.sadl b/build/systemMenu_RED/ARM9/data/sound_data.sadl new file mode 100644 index 00000000..d72c8162 --- /dev/null +++ b/build/systemMenu_RED/ARM9/data/sound_data.sadl @@ -0,0 +1,8 @@ +#define WAVE_VGROUP000 0 +#define BANK_VGROUP000 0 +#define SEQ_SONG0 0 +#define SEQ_DUMMY 0 +#define DUMMY 0 + +extern const u8 _binary_sound_data_sdat[]; // サウンドデータ + diff --git a/build/systemMenu_RED/ARM9/data/sound_data.sdat b/build/systemMenu_RED/ARM9/data/sound_data.sdat new file mode 100644 index 0000000000000000000000000000000000000000..58b6dd67fc47f34bbc2bb7b92c30d2b5a32531a5 GIT binary patch literal 16160 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 z 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 literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/ARM9/font/f12han.dat b/build/systemMenu_RED/ARM9/font/f12han.dat new file mode 100644 index 0000000000000000000000000000000000000000..08bd466fee917f69d9337fb4484f116a288b4021 GIT binary patch literal 10528 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%0DenHV#BcY2 zq6ZZ{r08Kqk0^Rn(PN;cl@(++co%h#b1nn?@;%2fkHm|k{MEs@Cvjd7rb;XEJQ5e$ z@~-Bdih6jMz)GDOo?K5uH$aSLm^SViHWHh%9nT|i2SZw*XE{RocIKWN78{7y2jh4i ziD^OByT4NS#MIbsp)|d8GSF zwNvMj?i;03=aKGPrTb2i$|If1Bb~}4oysGf$|If1Bi)Z`1eHg+pOjAJk?!Yto$tb5 z;Er@dWBewJdK3EK1hgqj6>T;jF})nJ(~*1A)cDQkBc}gFQX(Re-vZtTPi6WI!r!%P zJOh+72)|{DpvSa)#L>4(5Cc&y(AM+u)2}Rx`{RQ(x0#Qhep^mBL`LY;d8F^pM@+xH ztO#pl)b}`#l%m85zvFzw^b*vuJpMV=_?_k>rr&u!V)|V|Ai(FeX8eG2NpbkXw8Zbq zrHjxKyOof!=I%oTnhsahfo>z4;UR$4gZALOD$DOln=PV8yaE}&m)!d6sEM5150}vn zw!tT8Z?(7kDB4#MMwyAQPB7+g~kQ(@7ny=2@!v_&|*Q?1d>nVua&D|ca0Bu3>OR2>t*7 literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/ARM9/font/f12han_map.bmp b/build/systemMenu_RED/ARM9/font/f12han_map.bmp new file mode 100644 index 0000000000000000000000000000000000000000..fd7c1e0f13f2b68789388dfac43cc38ceed2294c GIT binary patch literal 43454 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 T_Wz+h+l~CezjMTIi@-ksbFGKF literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/ARM9/font/f12zen.dat b/build/systemMenu_RED/ARM9/font/f12zen.dat new file mode 100644 index 0000000000000000000000000000000000000000..ee38836d5d164023e51586fa41ba45e9de7a61f9 GIT binary patch literal 190632 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ÒkQgu55){<+?JS z^O=UsC;M8kvTe7r63qOA;w7jAlJXaD?!Y%6(;R#@$YTGmEIm`xbAy#)PQESceLmNS zTMV_0FIt7q4^;45+PjOc__@VpG3P+I)ow?XHviaC;ndd3aEvvY`#?NgITp>2fsjY3 zu>~uV-w9}HUW)#L_MYfa9C17SMvP5Dn}251SQ9o_)d6lnBE$NdU1fmCE(TU@=lvzu zpwE~PK{WHP$HBwBQ6(MB_EalXKC?L89nt3B*uh>Ce;nyGc!Wc4(##i?laJNQ$X^iR zTH3Sc={f)2z_(DTZH_+Ae5rw#s=OGiRyvD~HvbXqz3VgNQE1C>5~tS$9R0E+A+4~u zT(BjDllEr5G7jE!rQ<14Wco~Xj=-G>y?MNlJ|f+DTO2b%TooW+MdmBIqAsjT%1M;< zN*9o?ZKzs@l)|;L$|uwc%4vaoJ>Wryy{*`7y*^y@*)0W-|5T-qifbw=?(%#rpBIn0 z5KA!gjUCwmqWTYH_-0rIr~)TjdHcaP1GSWvdt;9Dgr*VB`kVQd^5Zt;>$9cBxLE>? z8>xje)n~pPY(gEbr#KcrT#?mCHzWA3GX}46+_;Gi=eo-P`3`@R?)A6N3r(>yrB-de zdyd_^r#52u)W${M`1uUJNFd(}_(pw~tlNfD>cPD-knd~MvbJJfhEjUFGV=}O2l9a7 z4dS`VER(k!{Zu3PVQ-2)S}5LF8ZfE z59CMM!P3$#tJhWOsd8e2*$Qmtf1>PG=rezpM9Hm5yGqDK{X zT<7TjD?G3!Hm&KkhJWd@G%}HT`-!|sM3g|U@F!)bW}CAe>CPIEpK5kIR#A(k@$Gs2 z&rGD<5adL~+_Yn1I;P%!F2oB_)8Qw5DvM<17hzvm{$2bNkY8Sk-rCQo&n7KU>a+0k z1?iRQ?N`@EK~rkP9vf$^Gf{K_MD4%=Ks7RO9rJ!p6CI>xiz4yUWsLcB{>% zfY-8m&E1;q3!6=OX(BFOPS${*;S#=G7_jB#UaJljp(O(--T}y#b9sxs)y}sIY>EB1 zFhYWe6>Wdv4kV%UbQ;x8n&uLEb3!GVSxI&mw(3OQWyMJB_-ukYDH=rl=fXB@Y*~A{ zwCGBoUwdeFMXj4#_;z7?XEX{YX=hY7P=UL#u0VEZeFlg^+La26WEEo6=#P*UqPZ)4LS6*qVdE*>HACxvexF1slqRyTv2? zS=c!ibDpWlye2(oSIBSl@_03JElH#1?}b>}QaF|1=Dcjd_ozR9T(dLC`GVleO4sdf z$ne4$8-)`jFATNEOWjCuAJX^`ba9F41+pck4R$ebtrF}GWb+tB<;do6VVDXZ$b<0B z!uWsMGft2ZGz`~)j)K=TzM?X0de}(^1li*ytUR(2YtzJxT^WV^g$sLw-7VA(3(|n* zm^Qw?nB;ZtpC; z-S;d{%B&(}$P_C9x!Y8$woX>@&lyYo)68B$9ysdo zUE?Dr0<#!{!U41Qr9cj}Bv>Ng^t!c*a1OUi&nchIFSFrR4x!EhUKn3p0df$&YkRAz zC#)HeRNCz0axNTd*u0Phm^#1FrSC--9u(~zOS`zR5l7G~6TEO24%<>sRi}D%W{vE% z5N&edp^$ABMeT(ocrwyc_?|}n@LX@`!S&uejvkSPX+cWv5~IJ&_BpIwZjavQ5m_e} zn4Nha@3F8<2Dc5FP8S}PB{kgQrn12WN%g{Gs$AX{d&`emX|y`)vw4Qzu!~V|J?+Wo zF%z3hjLXeWqyt{?=TXW>?d8Y13@Pd9g6i&z_WEapr-Ycf3op{{nY$%(g4Y`Llk&c< zu5`LX{1r16V_n`B+KHXXvopo=!di)n9MT|HE4 zjskrVg#q$3vtHnlD>~wiVjc5Lt!Z>uAjcP$PGWB&H;wse$bwdo6P09d5l8wQ22+N0 z&Bl7pNlCoA6|og`Aki@(r_L6}oHav+s#3{|*az$f_5~2mqeQB)oeupXlD-k*OMwtC zCVR#xJ1;;Qwxq}-@wkoB~S+ChdST(Zs+0E#CZ5gvt29hXuOnGa{ z0WLB2)~a%LfV^0cP_<)sE@`xn-UbAD$?l@l>@HM!`v%5NPtl<5G(dhMMBvTMi|nA~ z5|EcREx#n`n4!R@Et1JYgHdu8pykcu^ zkv5{}2;V*a4m#k4R}#MyH|k*cv*gGVKUJZ(S6zin2P|%l4RyyFc3mK^UY_2X#_8g; zjkQ>u%BtLzZb^asX2AFp^>$c;;T)2LE)Xx)8nKIsiwv@x=z-tC6K73xd^T?OmX+y-Pcp)D6bB^# z|1V00fG3sP}7MMp2R#2nU z6zZJm_0l8RA>4`{9I|_6E6Js^w0VPgNwbr6X+ClXet{%Z)VuITczC_d5IEUpSI_n) zcc{&qG^0UxmBx9zDAUf*s6UTVvFrgCrNdoW^_ckEXG{!zh>2#8BcHW|el7X>f{zz# zXvi(mqUyQ^O?<2NYfGfs@|z5CsPP>vn5Puk|3}w%$47Ns`;UY$!uB&GA&isfn9;IA z(t^?2fuF$zjf4aewqYdgN;U?xU@!)^3kVB@kZ$@*ze!MclAE5qv`z2HruSsidveoz za?|S{zwdWuSCajL?&t2V_PaB8%9%4~&N*|&>Fk8yjw@*3Bt{qBk=x5g6jlU5z22&i zs|}K)@hD0WSTC`6(hfK@+IZ! z3$LObYdnT`T;Z&|4>K^HgfR}})!f~2-k`N3&YOtNgRx;{ir1Vf@XV@{xbbRwab--# zLmK#tA>yXH_-p7?n+xFTCk|9&rODbln(* zjQNYRr^EAUJm<}=Qsr<0QtrI0&QZU0ukTI^xRA$5Wr`g0pg=ShRj*Y5ZG=Law>VxU z#5O4~R&m~rfsddE| zq?qwyZ_s1k0W)GM10e5mJbpNW zUKzh%U%U~LWi`{h8|{mF;|#ti11X>TPM#o7$3WgAea^t+xZO!6+C&VZxf zK5jPUJCOHbU17+foEF%=S}%|b?=S1TNpUVGz9Y>CIBP@FviiiN=6TsW3U{zOmP>4W+7-*~Jokg7X~CO~!S-hp6Q`i-R(c|K=(7TlDXQ6?7TIq2wRfI=_+Gd<5xbvmH@EI8~ z!rrE^A43 z13=!~7Nqhie>|vW*}gz64)w(B&&AOpF2G+5aqGajoW-aXn(b!QE|I2)7?zq|OcgQK zqA_@X?9Oz$@TJGa4WbY2#;Dl1(F)DzNu>GmTJUhhss=}R&vi$99)zP+aZ9auECxTRNN8r|hNb`00Kn96;+&ckme5AO2!mwEOU#DBT@?mv8yow=V~^ zJGqT3Bgt=lT;jra9xFjA{MqMxmln@a%&rY_r|1TK&9C0Shv#AhaW65}i8;RRG`F!0 zzR$7Q5!6A};v9PzRM2Ft{}+BxmLT1Gt!OT<#3Pmv`AO#Kr0d;YyGCw5C%zr3`mEL~{^Ix;>@&{OgpA(_3l3e6bJmeQx zp<~{`=@jM|WNu2{TgYz2gJIDbdzf~F%n5ot4A>H05VWHIU zkCi}vcS0}26X0{>Q4`M3pkF@c_n^0^Iz)TnX`}$&R@#VnBcDsdE5c*(MveF{dZR8$ zLVs{=z4+Cg3wPm<Q3J(WK54*y{WC3^3;o&)dYR1SK(wOnh1Mv}q@o18mQGoo} z%}fpPxM|Sb<2@cU*>8K>oRSeQFW(yhZ-i8Ye8} za+Y(q^ToOFZ|k*(ap&fq1^I14s*w;lm!nZzJ3+jh2YA zBNdSL>%>uTBg%-4SOpx?kVmy*n(fdp`R<}U&435Ewev&=4||M)c?Rt^(M@|PB9h@1K6R=a?_KJS2*|EskF(OS*Qq-}jXYmq75)Qq zE8^7aN@$D7Ia2aAgOii=Lj@qWm0Qc5hfCh*X7q{M9qph53g3ZpU7I7#ZrZEpaqBGH z&dM^#vh9%t`aB`VK(s|{5`DB)sFg(^25}wr2&g`V=cgbG!-E?C0qJp?610Qhy*6r4 zrZA8O(z`ZlR)`*j`IMs-J`JizQHq}EV=0{%gd0~1f8?+enPG3KIhDqp$F8@$(5HN( zPO+w0uAL!4MF+uU;A`hTF)ngjnO z&SI=TUfvtjVXw&LvW^knJs^V>sC!Z{LRPDH9quH?atBM0qn6;LVhuM1hcO9V%ni9^^s2A#o3SQl*ZH-|<+3iVeClvp`o```Qk?H0_CnB4Wg1Dc_h$mP(`oulu+-|WgQ;ju3D!em5nxpi_ zVq9fdi1Ciy9VLDI#JxA0PK-HNKnmx*eyo)%sB7eNj=5EmqZi8OyvTPZj$=Ko#tYyV z@}}^KI*WJi8US)1P69D!G~^-h_MQTL0JFsb1>}C6ZY)%Zov`&X@;q0xZhboOK!-P= z>R{#T@K!;Zxz^Ns32~c2ng_XxsnS~uY#)|`H|K>3#NDSJWKH2vum;-WMTl1u@6$bT z4@z2tdeq3xadmh?BFzb=n@jkdlk1_$Ixlek6I!%6qzu~}-OA^j zqJ%=7`K1M(7t0Y}8udd`alNioPC?Iv%l@I=Cr;CU$NDnc_eSg`d598^m_U3nN1={Z z7wohX!)sBuQ;|`W?fN46_4G#6eodTlH61L{X2KOC?JSg9CeE@228*t3%9uq)s?a*s z7jJc%nU9NWqSXr_w%v+@8dl=|7#& zG4W)bZh>yFBLqLl2_J2XCvNwV<|!C2TH%j+FP>Rc)<#S`)$v{_Bq<6rY6A08eF15n z#+oJ-<)7vpBDSH=yMtZq?WaStLQHZs;G$6>N&(Y6!;PPXKAL~d|KKF}_yi<0@DITV z+o#a7ry`_zri(j9$}HbbXE*UIPY)Q}m@zpPP9t?`EIixVpf%RoSUbWOUN`AG;BAH6 zo-^;UhQ4Edj#7X;_oRYvRh&@|D6Zc#YDl5ySc2zKI|(@ko+gRV`GmpKGY91PO`;_p z0S~}=Mz9Q#JEg*t0g&M4P(aoa=%;FbqYn>xv(docNKCwdeU$~R@eCCOS*R1UkEemW zkgY?X66^;l!d?KrhdU3X6kiM}qjE}T8Jf6IjrBzWS6w(B2&|_PdF&$ek!C`wQOr?% ztx#N(ONCuf5s=BoLb5Qd8+0Su>}Y{JqyZXkAXDRoHhloAP)3v(#CxaN3Ey!bb|0nF zSE1DGi}ZLTh|IV?Js<5<9R<#~`=cIpp3j-ZUgm(Ze9k9LL*`YqK?9i^w>phB%sm2k zH*Y!a0eK{eF@2kI`v(%@?r5WOQPn423=Rv80(oafzyn}jTQu_ZlFtw5=1sKPsk& zF}Oy6Hpv5d6}9}MxNF1{#0ktZkeIw10wAxpnnu%ZV7tQnoiGWL^tv>V*UKuicu4aG&hU1ZrJ}|go>Xc{bP02NBYT?BQeC6~ z>Za~?$eXO^NH`Gl_q}LYMs2y0Y2Hll%pvgiCV4{yeHG{fy9-G>`Nej?c9~G~oZ>Cy zy;l{ErPo9}k+8h(MVhzbY*k$FNy41IC2(ig*77-TQBkhhaA8R;}5 zPes(_9K`1&OYja#JMw}Ba@ENR|VhKLfh-X_L z3{U{pbLn*wT70%>!TFDqyLAOvKZpEe=f)3H)~VJt7^5|6%$5XFkwlu0EN-1Pv`?qJ zQ*LK&AB7i-8OUYyQM1o8J~+Csp_c{nv4s*ljgUR$7lSa#P0^dum^NDNpe?!ll z3Lk`ow^66ySI%`U(tMIpf^QBHMFg6!eP{>A|ABm}g6%9G1TWqg-W$SFtnb3w7|5sH zjt5vCP#(_uWi8IcXT~H?sTm948rWu`=eF zZAs5*2`0X}GfoP6H64+pMd;%4CFE;+ARWL`0>0aT5;La~@^xzS$cc~QCWTQ)yAG{8 z@r|4P4u5&Xb8$eyA*94yleF{pH=WLo(iVAPsklVQ7k3wnPoVIOxC$XBPQnD{p0 zD?>MUlc9tUTbqWKU)Qjv-ysjOI}$C=qBNKc6kF%J6559j$nV@=36FK$orXI6iSIcC zs{#Yb7x~%s0+H`SHVg)fjMe7!}mSk=}mM9ZBCiuI(tsRkN`-zL; z<1`CHXmRCZwl4ztshyd8Qm0bmSg*8%9l=(%!OtFzfIEfl(1Zc``2xapYS;GH8M$ZvT{MT?h2^a1GT4fWs6X1xIdf3Yu0vWr`gh7zXJjKdRXR8tBt6<5jC z!iFOM&-p<9Nk2RECe|L%@P*W@xt;eD|8jE~PXeh1-$9H+T=fys{F^0m zw+Zf<;_DjHJait(;vNa4tpjDNmOD{45iBc}jisJ!XS=!ng|t~%A}$e5?w#B|BG!Ua ztu1ab_Zr08@KWMNxrAvtnxcjbHy&xWzH3ML0)u` z2q$-xsR}JF;HMWU{Atu@a;HNC^cakv$^B3CDFb5lV#}i)s=jbV{_cpa=5~xucFU;7 z&cEzarwe#OJcK@-wEkkX3Ok|wb$R74l~FUGlo znx`_gJIbHDow7eY^{_Uigozjnj`L0KmeG1h<2R*gwWsC8`2USQMs9oTd7<)_V$$3U zK5$FAUf>KawvHJuQ10(>cfn}*q876uke*>hKjC5AS#Mb5v&1L1L9fV-BUkhi*8&B^ z7Z*vZgPiPh6r%9;!o_hqY0smij_0ssn{js+=Mx}VoF8r|?Q-Y0wRak4@to|Zy^&sc z?$-&)cu%yoO%5=Rv#?)qG|~sLhFU!$cR){%`IGAfcf-0YYhoaGTB<_1SRT8hOS;HB zlY6CJ$=yo!>JgN-aWM__Vrc!Cc8vPc80%7o_1Wh*5UJGB3hY{8zX5`Ml;%f%_IicVqfyf0d=AE%FDU;g#X?Vej=g;CFWa-lUSsZJiHg}qbVRK(g1 zv+7=Gj@${7llQu^bqmC8<+y?@2-%pq9TOpT9irr1F(C?|rq4~41af@A1Dt&en^o+* zs3z~@yk8w4qE~^RuEJT|7!xtl+|NBX@P>vJn^EMs&#v9y$LBoYJh7LFszMd=cmGwf z7alCnysme41@0ZlLk)&{SkiCWccZ@E>PIKN@_J4dwuGAk{u>vNK;DayMiOuxt7D8_etQYKG5P7Gt+3V!6*6>sv>s;?mBO7`}U1f?T( zxS4h#CKTPa`MTG5vQ|i z5B9O9Pa#5EsLPKjp~=!fp6X;d%2iH=y#aIPGNySNVq0L`IB(_V0{zuC1Wi7Wr@P*E z>zkfJPoXy)3Iq`wUu-mn9HDLuH-(0x0@krW7P|c`m6K zzF$EtbnEFtkEZ6*a+l}btfAS4S7R2|CG=q|P@YU4X`TaD;Q` z$>fWu+aZ`!@Ta?;T#Um1se zLFSu;zgRiW_KIk!ZqUu@I@u<1jPZFDVOaqXcHw@%@SvU zXdtuYd7{_c7x$TSajzNidW%5j9!-f&=xZZwZjU(0#7QSoNmNa#wg_on%zoy6LwZmR zK;KuR(f=NhmyqXG;iktsIE4XTG;E!hBHD#o5p^N|+F%W4qNHBycw)%1Da%7(>>-CD_Njr+b z$*nK-)#_VoJe1&}vMnT?<+$Rj_0 zOMY{~KsPAaI&W@`(ZyEQsK@xnYARS~wa1frr|ZP4X2e)V9vd;s6wYgmG}fxARmO-=MFyi%Gd$=7c$M-)%s7wwjJ zvwxB19jyhS|I25)R?17%lBc7Z&nFoUNC>dvoG|bZ|jb9sL-$4N6Js8o!NVMMH5Yso2zu-HN_j2r({fJW< zz7Pr;cnRcvq$*l+Xnl7prV{PEAL|r+XXEQbzW3O?YE6VRA6VEy!SnHW-IA+deLh&> zWF|-_ke#fIG9oKIARl`4YGBd)Q|Jg1p}$;#W zZ)KNH)r-aFs13yXf{a5xjsEcmV%Q(e=^}Qs7NH+BjV#+|938m*zuW`NPvb;B>sFeK zUF+_FGPnF3b)P47W8@-jIPco~*#@6qK!&ly(jgm&e8JImCAb(P)R6q%LjpYm)p!k9su)%#hyJ!WNS;(gVVM zl$cLR!>!R3>WLU-C-fCe^Nnk?jBrX_{2*qujd6W|y_~p#z+a4IC`(mNJ8H-2w?>Wg z@`L3Ex-@FVOJn=n<#M{x^0idz@3_32-ydaOmph*GUC>Tk7r6PC@hoa((pm&2zxOzq z411teO@=pP&b~QRVN-aTz3_d^*_s-WD%ca@B?~`U7g=QT2c(9Q6e7ssp#Lk-M{_b- z8Iy0y;5_av#m%M%X=*(nKTIMo7t>>*z3sg4qs4mV`F-b1^Wz1iUADpRGJ~Gm$>;n8 z{x66)1wanAU|D5qcJ;`F6Q<#a!a(Z>c!5NOVrY^+LKDLx8W~_bz*LH zcveA%%hd>pzcn$CU$hI@6I69^4f1A$j&h8SNgH1bmPO>443BH-%u2G$udXWGn|D4o zV==TSkWa?)RX%e2HUGyq0VN^42J7;pzD0h6c~(Mi%9++kGn$j|Kky1j^V^dGJ}&+c zw7=~ky(H=a>7QV3zq9ob?UsTTM<<&6Jz5x}hocc!L|u{7BTdF@3kltB>O2WlsY9A8 z2|F7908N587LzW{ONl|B*DkD`=LA#TNaGli!wLu5cEm$E&+Brvv$Gy|>QTh}C#K0xjUR zUcF9eAb)csD+5_|D`w`=uzWiC|$HR?bD%Yt8ib70jMr(gKT~YAFGVpz#i9BFV<2h4p(%MtcM;S2=Uc%T_xQVn^ zs*@UXh2Cdhp|982)r#j#ZKuWpJknYS8{y+bZT(sz9gLdG9)%SlNT~JEI#cg&^ni4> z7OMP5uXw8@J-nuN&`a0p_^wijPU)A&>C{egiVpB8+C$QaWX;)Bq8FyRc=B7XITRev z^Zj^!BzF4Bsc!00*29mgsjxmRFsqd#B2Vpd+7ZfI?GkNSEbnZXx|Jm!0@ru*0{%<4 zK-R`{ZgXX$wr=71G6HftA|moU^-lFVzDZjj z>t23Gnm*dousT9ZUWd4R4X~%+Vs4p)I;rY{8l6&`Wceh-wX9F}R7BaklB-2=DymQ? z(!FxX1Jd82TRd=C@2G^_;=vmgO*6>c1{`;##mbdIL&hE_a>pg!8LJye!8?L}I@R7~ zkkEnL2|E^6X7y^Vf-VjBbqZ1Am}c*&Zqi%h3PTGr&lSPk;$@3K?xOxzDha-}Lsw|- z=ByN#3n0*o34OW01SPP3ikfXgIdN)#S>kf7gt&`XFIeONds7PVrGn5xqr7-s<|EA@ z{Q)V<(Q?3gld>r24K>#@)xgDa^nGB(W z3_($TW3(=WY#9Q%TS2Z`kCl(Xm8NAgxLuz1fE+IGLvD#Fi*ZGpQX81t5srnfAe|#$ zaPhU=d^&~mC^5Gwdq?zzDaT-)I!d}`#JHAtleLgBHqenYa=W(?ymu&||C_Vjka~~C zK#q}KJwuCcDm;vPBkb*mi5!QouN?3Y55^;3*yn>IfDZw=k8<-l+&E27JTXSJPy^2Z zKIeXZcgD(;H{eN`fHMPE)l(02$b?!JJ6R&tQ}1TKu$XAGU>xfA;c-w zOr5I9XM!y5nmp`-@p|;{wVE->riRGln{YGs7jrJ_RHsf8;d-tsxIRaZDYrU6nuiy> z9Um`wGtWw;EoKU>V| zh1_TyDa-c{S@}L|&YJe1GmSLoShjNAon=gh+dLqnNxwaYY^CA#72YDLsdlr>)cN{& z9XK25f*z8T0yg;6U`&ls3*ITIp+PKj&HYDiKArNpJGVkOJw}B{_z6F$DRE6bsa+@4 z@}ONObd{=>q)Wz70`g>@F?uAZgD?B#X||~A6(CPROf-D|K)yU{%#XRJYSg_-YSD-` ztHN%vq@VI_|2)m<6H@xV_)5J#9?{s1gB!U$ogVen2*LUlp4T#11s(Be1LPUdKL*gF z1dZs~VNiV8PCNBKuFV#9ikX?dU``K zncskZugX{ZX&=Z7Sw^K?)C{bE(K_4n2Ld23YV>gGC+1X5BOoSI=vv-jL8G$HCRE1X~nW+8P#=aB-RTBp`WTh)5i zRiKyX)Ev{elPWN)6zrVh=8{LYN$w6y8ORcrM(0QUi=6~O3R=+6uHbWC;;fyBNoqJw z>1TYzEG+_gX$AP35=SK>`k6zJAlI2)vYjOe9X&aE=jU?tfvK1A35*-z&MtJ^64WoI zUOrz(#r1Z1lmmGMS_a%Jt9B~TA#TJgQJqZlN)No7lI=mr8hkH%!c4si+&^klkm4|p z@VwP}l(imxIQ44Rq79(-rGmD4wy))uRxc)m)EK$iT1dbHEM32rz1=K!M#wEbs2Y(Q zrAFlTI@SO&v13G6ltCC5D=rSmA;RZCF_YEEHGFx=NR^~T+C6XcLx!L{kD#Il%u3#eU{xrKk6@)EtB4VT<>$PrZ*j4pIgli)r$r#t5@h z*c>3Y_d8l4zoWEH{}m7mpYwq>K{{I#R|Z!@zk+D+db`yTPvJaD{+>Hu8HWEsJu2o6s6Blvi54WLhgrG*cTCKnn*+zX5 zX+Dybi4gjh!YX}3A*=bGHOt5CrW}wW`5x)a-Imul+2u>*9`r84uBB*G)MNMw6TF!E za)+kwoUd0zm%}!e#HS7-U#WvMIRHP=OpsB~mxYK69e1#QzUt1dXG~5=-BHS1uMg=; zruiDrS@Gzb;5Z@V|4%^{9 z4CI@)z*4t79*uY^TR(cXGQ_M; zPqT4_wBAG|EB4e6$}1y*KSnpg6;$ltIR5i-V|1@876P^;p{hlq2ffc)L~w?@_e_NYDl z?+9nbTVITU7zp%Y?o3PCo+b= z=nD&;ARAeN9V=rg>@Ea}s8P_XHH#GVs6cjNUqN(IWi`*Y;|x@ZRY4zf>w*_fv`b-q z1LQ!u53+}g4?ErMXtdXG55;I|=v z%K(2D^p@uz6!6zlZa2iVnU9Q+8^+!~@J+8#U(4KjI0IH=T-ei4VDoIk47g7M=^cy_ zFExfn6&f(;3xfV)Hs4TKlH6 zJeAH_Ov;?r#j2d{M?H(!8w(UCRj0=boF6IsPY=Ln&c~j7nTWUfiGcDF__zXc2cn3D z<57Ru9}Yx_4H4pG*}SElJ4>w-BtoC=9uVOD;BlB2mC`KRUF21a zVurp5S}`kZEOD3VeK=nSwc+fHli-mjCG3U(Y4-E1HSDJiXfNX{y`uJ}fgD(gw%i_V z!CYFN(V?Ygnn9;MUJ^lj97B7IJ8OoRCdczwIPMOi?jf5sO+>V$VnH@g(18!>%1_vu|xIGJXjuyYA$O1gYOpUqG+vFQi z30K8Pb1!16pdGgqvhX>xV>A}>ICDD&SzXY!DfN}QMsLt-wZQX$9Oo;4%MtBfS$ZJ% z-4b`go5`MWKpyXlI3qJ2kozgwjY^R_hjwsh`=U3P#>N+8A5)XD2W2j=Nv9ulyb60f z{V~-3xW+0PGYHZ=#2&y_M$zceCb8awMZ(bAaT+u6Aa>qo;e9Van_XfL=)aB6LEL?E znuI_+{NjdUDsI+WO(oNuq@0++GMduSS(Eh;AII2IpF+3%$G_>J|M)e&oIZU~Ca?z9{mPiy}|G zDDt$6B2T|4@{Efj|8r5~nHNQ#by4Km7e$_PQRKN7MV@z20VlU(Gv9r5ysltg?_~d2|ATQ@ChqGl4v&q5*kmF;r;9%WecH~lKdkr@HE*79b`G+HAK^kR>`xMHqG+UeIY4KL2xi}yQE zzgFa2OVd>j@b@rUROpg4Mz&V;$=26Bar_c*C{=&;p+fj<*Ye}S*{zr z8OZA&{e1Tybv4s(I2T>61|SKY6BhS6QYi<@OdzPK@rthG0}3UUqJL zD-d+zHIQAQ)zBmQlCU&uz70jUx$$?4|EAy0XSi=mQPi>K$&n7;;l6iLHRoa4`|e2t z!9L0beN|gLw%ZF2zhs|#*AjLY@bm{Et62H)Fl0pddImNfOYou95xlBZ12kZ3Ree~WOQhlT z5dkU4+-jfp>YVTPYmtLi&LWV$ZB0K4Z*j;D zO~|d0+E5K?LnT?$k5P)^cRA!v>4H~d4CLdr(BV*P@KBsWz4$5N+2?%1?t91Y?kn1F z&Dx@piuL&)1aC`e-R0Mte4)^z89eQU?L{^HF-t&- zIcU~-q*BtWtXGxpS()xhKz>CUb-h4; z(S$}DX{CYuTKX6zg0YKI@kV87UR}@JezV$JWoRXYpOok59k1-4-_lQrc^{K4#r0;r zxi*g$CGtCHa#ceFE*2%xDh(=GXi&CwevjN_gG7spq}M2+ja0BAv!<9OuPPjcP6c(J z=j8O^nEnG|jpyLc2i+QLMcU>K=kTsrP! zndvFDXq=Oc1&*+k+8Eki=;d?jHJ^iTqyiLH?WZ7Te=LW(bY{?6RxcY zW)ZTF8d|4`C8vPDuyNkPGy9$WiT($Sk433(L!KI@nFBtVi7rqd!=-YzX-@t z>YTa)Z&99jst4p=N*lD=l)XV%14~uM7_Wyiy~~w(GDoC=UX1%B;AdXY+UdSs4C9&m zg#9bm%KgXJ8N}VkUZkSZ>5eff1_yNxZ=r()U1`oRDFpB+Fb!A~| z;mYt#u!OliMDNi%i&8(KKe#khy|lH1cjo{18aQZOB&Y(r9| z2j0xHxF4N)?8j<)+(@&=RLB)Xo?RiYHQ#^^h22m84EEHx0@ST zdt5h~%HRr??PX&cl46`NyHWo!)6NU~JAk~L*7B7xz2>+hf*ydF(^$4w&~pG>61-e$ zoFq{!$D*2f<(L*a6_=@M3{-k$aE7_Pio3x@Z0XsK37&Lh+xpdI?h4MYVery&{5-jR%JjYVV|1#D@ySUlMuAqSX zRS*e5CRm@>59=CDZ{%uA!_}CFFAvhp?G5g1Nj`<=mV^3(@xao-8^`r7Js9soyX``( zP*{r1{-7_7G;d0vrU~RW3<}tWcp%$A2iut2n_(4-!D^&-dP)0Q5d+B+NupHyg3ILc zpcZ4k%IYm=-cnAJ#rR&uQC}1ed21QLo@so`yM(-rNFr!0woCUt_9PamADwx-OVe8H z3d#sl5qSrFzf!WZxRvxYxy9)T`HD0jk{k>6 z;!N-KcUl91RIvDa_nGU)nGY}IfNs?s5!Cns`3O!nDP5pm;jZm0+ebTm_~-a*a6|gV zE)S=n0rD}I8zqTLAQ!?{1)r(}kdM=zxcFLGAo&3Kgz!pn*+e5|NoXC4Zgx0{ZD$Z(o7m;P=Q+1$^>Yxr-8*J?G1f7tm)^7v`B0Fr~MzdmUcAaJW9wrkYC)5wU6)o z`DVVrG@B5iqFI7dfp6g~dTYI$`63XRidy{?*4EHRg$iD7Jqph$GR%zW9!>B8>7A|scc^te0ZYS!l~^c?9$D{!?yi+r6v zo?nfs&V02g+!h}TZ-$h=4fTUOTX233Ghe$@Tn|a~M%>gXFG9Y~l?3ncs9SZb@kshB z1idC^zEP_O%pJwms9~c*l+CETyM5-H@aBW{eenhRw~sX6S`s^pJmqg^lSc#~56HJG z^jT>9%NL`NkJvaRGvA>V-R0%bdE~nb&v8CAUHD}MpYuJN8^-4@-Gy=5h1WB-yJxpZ2;2A2k6AzhcmimV) zG~>eayFSGFq|fI`a|w|jF%9Af6pcVURbD`3KNb~awAGU4Zg#G#6kXI%^ zrs$1C4$Bx{!7x7cwVY>eQ^VZ8xJr=(UOzbmgy z5oO!*xp^u2_l$+@@+!Z2zF=;#YlB;(QY)YZ8FvTBA8%(WUy8Yd4-nRhdJYKUX4}X-3{vWIy*6d(*w*q+G)1{Ka|7!tV=I zVqZ~Ko7-RATAFPs*oV*%mDa(36RVf~NfZqpb zX$7D24|^ujD98S+(lF(pNkpEw7i1hZ|7EZn09V%MVm9;uf#oo#0u z!0*HK!PCUVpgi9T1d;8+KUKsYu#gncm)>9Kktg8U0;Ge_q@D`%9oECfls%?rJFDU$ zafj#?y>UkELz!7>j)mDByq3F zzdzT5QQV6@!oK@pC{Nm%?M8jjDx?gy8r#RU&g`ybv7kf%cb_25ZucBwECpXrVhjV> zQ>BN(0~n1NJ)jULUu5-Jbr}(Zk);{mj(e2dJp>P3AU##yaFMZQK|3akPub$Q$BAyX zm;Hli+2BOj4I$iUv_02nW4{XMBCzINJnCmN+zUsa!mL3GuLqw`DvqDoEchGhkNQY= z+gM9%gZ?VSu6Ge{jL5*J*!U+bjm{2m{PfC5tJ-LUC z?Vo+N4P;-`uNa}2euIp;i!|6r$u!)-K@q*@WVZ>iFC2LC~n~MLsAwa_rZ=*hjvE^*K}p{!ISCo^j*r zwBfukdv~SBl^l0Y4;YpqV}?D>OtXg_y)Ed{%Cgw(5!Tev6JxZKlbwt##ot53QX+cO zmA*uYN0-fW3j3@u8xC7;IeTxF9LG}~C&dZZ=72eE=d9Ud?m2xC%bh`vJ=)E4v&V(c z_$ru9Iiuq4l4s3Q52d~j;|IUx?@`x~^(|4z{gsMkLvCn+UeSkEKcmTEXCEL>?%|hpk+bFbhuny(j`IJrBjn(2b;?~Qi)i#*g*u(j zs=<68+IujjpD}htq>wo#zIp;@2NA*SJsi8y=1OhKqy9;t0}mtELpp`tLl3&0C$mqsH4VV4gMqj|&#^ZY zT$)F2PpQ(w_`MrHd{VaP`J6RppSlF&vM+MIY5OP~3hY>Tnxi+A3^-FV{)!!QHoh44 z->PiUeLsj2SRV2W%x1QYSu*$h6|tRV{^!4oC(xz`ioIrk(Y3&(!5WtBnU2S!-wHjL z)s3Ht9`-H2e%1nFOCHQ4&t}Mr!Eoj21!p1Ta5 zk*=P11a`JlCkj^(dEPZ~Eu@X4Xw@liV=-km!ehFfxjmm6bf?!QkIJQ;B@9Tg45v7= zP0$1Ai>w;RVPxfiykJEy?!>rT$dj-MhqhN6-6KuSBIx%7PRheM4O1}!bAjQ65~|5 zvSn<)4HuW2%kn^`s^T$|2@XUVpU>&fXR!yxj)iGT8IQdO2UV{n&QlqQ7E0d3hP(LT`d=wM$S`bO60 zWiB`OjKKiWKZKAnvPQstXK1%ABhH$%!d$nz!{x9P`uZ%||wA&$be4H-j_IjCH>6gw9)YN%A z9^BH-ns0FWkP%($IbF!(!KH0(Z$t^S#7d_otc89-`t}4%A7y(JElE5}hwt=T;VFPt za(FXW%^rtx}VdwJ}A#b7AgRPH`om;9wZ}N}nOVdd6)_PU1 z5_rx!MGbZ$e;e78B{~;W1?A#Eh7NzF&on;I{5ti=elw^2qH2D&10OP($NU6!5%IE_MY!GcIT) zYx)V;s%0bmENG8T28&AlN$25#H26L5v_uKgNb{-kjLwyjmW$GSx&y!46*k6|;o4Y3 zI-RG{&(stiz{w;Jm>nK>h>gk`bu~1V$nCR;junk)p69hu;e;=BBhCQes%!Rh)^=}( z(L!h?#3k6|AGWLA+0S!F2+!C_g=67zEB897WA+P(sibV|LW6i+R@x{bUt}xNqaXen zvZ06;ExH}#vqi-F6=+Y{h(3pB2kh?0oV@d;gr=|7Ngo#ZkUF?lcu9x?%JyZnPTWv@ zIL|%$Ny%O)(c4$(p@p6NDDk>Hd>HlrGl$eNi8NnTej{4>bdi0|x@|5VmbT}<<|yQZ zXbkH$dP3cRC;`->u@V=;y z_4zK>9K6Yc-LAY+TYrzgOoiv5dEqGnP5w>Mz3|sSn(sS*JdApbMeL)&bI>|PAU`Oz z8|*Y_CEVAUd(@HuNM!eKN297a+A5plMfLe1qq^|)9a>fyzm?am9H&2GNqBe4@|fhP z1oGoD0!unZEA@%a#y0yCa1@F0Bi4ggaV*_{*magy{nX{fnR)RTM{YkW=O&OFKPRD8 zwbc7_DWHWZD4m8DYq7ub>@TWCm)KK4JS&v8Q!HA&|FSj04mXsUd$d`$tMoGejECnS z?!LhP0w_<7@YLmci9afU{Mvb1aNm+U=VBiD%_t=QaS3Tg*C2}4O1UM>=#@Uw{MNRi z!fq>ElY!vcQtj9f?Xdti@>aHXX~GlCr4P&JK>M%^81v)P+7+^qjxX=jKylyb3!RopyirAJvFN z!{^ge#`Sk8w|~NpA2lk*Gve!_=lrWFUT?PMF7wZTyLDrZoi73OV(v2}8r@P*m^~W6 zVT72|3$k&JK>?5tUMm z?3q$L7pMuj0@-Pi5Rosz#Zw^=`kzHWy2$xFAM$;GwG2M1fIBULbaU*LM>K3spotY| zV<5ZMf)|}t^yJ{l!SM9P(^9O@t&oihIDH0@)TouBHHW$>Ah*#k^t9>AQ4`*mqgQCJ z$uPIu>-9#1HFDgGZ~Dx}TmtX?c_6#74?>=cn=tBAa(!GYSK>XD2C@gyzg3T1qLsf# zR4p!>X~A4_ntF;Hq)&sH*vsm>G}83gIHw^aQ_*vdG9&tjW$Pu!8;-e>GwrRi8UJn+>sVaQBFW#?D`DSf4u=xQo<}O0&0A zAK_y4^AzW-ypuJ(i^x!5*K=Y3^Bm)i4iec%f4Q@oG|d)*mowVP_UZmcuU;}97Bv`s zY50Ptv!;)2Z~#(MekgEjaI^ua&z<@;H;Cu>Xi>B#Zzb^@X*{IKL1y!Z@GZ0oC;=(l zm@IQUh&1AK~kr6E`GF8Umkn$mER=#px2s-e9 z+-uX=-eDS!Cg{FdwqwpWVl&3UetTl&{P;OO67xhG&dd$)xVzS*Oe)x)Mwq1={DdbLb7t3}(a~_h=r532Wy@BK8gRFHiE4~Z3d7Blkr9~lph2g3bQm6!D8U)& zkNFMJ%^{;>YI!8W7!{x&34L8WppvR1hcxF_ z}xppRGTK)63zP>2F+#yNZM`PuW>Hovqw*CV7lK~CQXscEreO+5MgeWS zP0%Op<8vMfFgHnex9i*3KQDDi5>X2i z*sHQZ;&fQunFkV<5am{Hd~Meq8pz8^x%u=Eg>6%9LnNKsazI}0kOpm6l<|#0OVDlx zncFKWg^M}rUP<#+;wqNymC}c1zkCH5T%*?FIS0KMe?5*`LuQtYDTKj{|K?s@!+BZs z!^Qxcre^B%QV@9!HA@`J;F|v9u=?k&jooP=uXTBqC3*Ztlivb)os)9W{;FDe(ZW;b z{&&&yQHF)6-E*&(Rw|S;Bf^8w~YY2B`v)f!cU+xFZCnZ|KQw+3^&VUgxTcn; z^^>kITx+B2&wbeS!XkSyXCkKgh)ib-paIkpwlUm@17S5Xb02m6gYUy^8a*3lgV9_? zfHWT~myPkCxq9Q>z@Ga!HM#xBkuspA#Q40mh0cA#wLucGA#g^bxmhC;kB#U#_et0O z3l^^O2$=g6YC7MaC|i&%j#}&G+^0*3>l@pzXQgd}&+s|yQ?@McOLc8Y8-@tnt46-UJ~ruhQ%hPP~#^0!&dS#>zB zmMb7%l)jVDXanMHeDD(=NRj7Q8Bi%?K96!=k3MTI@qm13WzJgbi||#lX?oRJZJ+by zTKtY_Y&wm!W?WSor1^^Udo=8+NW(P?a~x4iiG0Y?~H+bok&t_jS<0K_ry3$G1shj5cx)}pUGz^Qy2U39Lna-!)xxFD+?KI zCD@3xlU3tUWpFvue2ckl6)U5$@TRCg94|KKYRqvD$hV1rHo^N_(Qo^4L`%-o!FQPk5;nY;#^P+aF9ffG_5*3Y$Jvnlm%G6E&i`wO;5(HHNH1`wiU6;x5DoDf}`z&`NXL-m^7jYv?rEG(C zw%gC#`6Ng2dHyN*1(2Vk#_D`LfL;ct!o6Q%Z65>q1$EJotOWaJpvZF6>BkZICB|ty z8sK|rIWN+{=NfH3_bbT#D0P`rvWH5g{xzcA$nz1NU~jGkYgDa7n&03#2G21Aqz;d3 zpt}5OKIgYJ5z2<&<4K^9jNGqeVPzV~?`rkxA|h!+gJ85xr&cL?pUwTAqvSj&y+0fP z?F>Zwd`jX#;*^HAwFsM;YBQxiKwkj)1EMXW{5*wn6fJ3c$Fs;DvGK){@UlwkO$Kq`q4(JVPjn!Et*~@s z>4`LjOXC9K&ZE=`pR$X)-5#5{zq>SxJyrKelSi6=I3yXvyEWc`72xIop73mge}ZB_ zh190HyBv{n?q5uk6!cN0rUWNR!Ao*a8fk3YeIU>ftWR$gO~`RqZg(KWBbsSa=KtkW ztW9BSdL3gfqSTMH+1xa8#LcnLtmqjHq}`P*<-sDYH+m`T640iXxox*;pm#*M6?PYf z3jS_`IUpTGTrSLUt4H2D7z61fk_vD3Hb#j&%eFCScV*jQa}zvOp4xAYO2l$ANVC(X z5u4&|CS_o=z|-2}9STU7Yn|43J!E*cHO`UOccy`KGYxlyLjR_yD`~M52?Xa+vJEyN zpKUlpdRv%|d&2`P8{&&${iC_g*pE>JONbr~`XeAVzL?TTr;($f&gDSRPUQAcD^Dvi z3Td-LGzlp-*wY{%+3kV88siRVaxh+kOwfoL**4gNxU}}7yvK{wsx)%5RE~3`!!gP4 ziIyT7zOLA3$SEG_Cm$7-hmr?6??`Y$@yNhfoCvPY z9l~0#ghR5Tto+Cwu(v{+dM-lrbG+iSw<6ra-0mFqxQ}Vr>olEs<>yt<2m;v)Pv~%U z=;h#9AA4$b=>7w8S1AqJbZ5*~C7dpD1)K6f_H%|A z_7wb7Fr%P+D6uQs0robv~kKVwY*){$(2P~%Mam3 zvwKMMAm_evGwWxgqt)BJyHS4s9Sj~tWTlEF?)(Y&P(6;cM3?aMarryF)bEA#)wec z-J{^Y=v`@%T9yEGM&u5>Qro^L&68?HAEbh^Z+5L&S(H*T&68Kgy>hSYi{VM^_Xf35 ztzQ?^#Xz0{dsy5g_Cy?$)u8qHvOSfuo88S6EH}033V~hHuGCLk88Ol%WmR4)BPpb? z?e=s?(byr{EB`-R-yI*-aqU0I!W0)q&2k*SFk0=R255~TGy?+&BZLhjAt4(V7A&fb zxd_Pu(QbNAZhA8?>E-1mo8FU6@5xQ?$wj2so1VPnkKgw@vnvVz9{ahgWxqQ!XU?2C zGjrz58NPO4hQn7K%XvnPMpRJKi+RfcJ~0|!4I~N3GaFMA(lf3u&nG2}cj)DLTACMlUf(7AB6wHDh&)l@byOozQ%Ub)`gwWX zds7h( zhCH$Nf&82#z5=T@d0*TwxkE4jjnNR-%lbUZd8ME8O>umZwpUR??n$tgLfS#}{YE^l z|Gb*HVc!Ga66F|EZtX{Xn#ww_7Mv-!_IakcH$q-mv+gX`M|eqBp9`!hInW<*ZR_R0 z$*G%RncO-`2f;J~rudNq@$z7^a z&b0P2^6&UB?Q~{$}wlIxv?{+#wvCmObkiyjo6d=Bsw{4Kq`2tSB zigvr5w7nNr7hP^SJqV9E%2k~N^1k|ra>mlx8lE=S7v9hM4EhJijgF_TO>rM3zek?~ z4b<150o+4wAFM|{h+i7@#RGXGYBac@Y7!tHYLuv{@egkblLlBG$cJl8pWS79jX`Vl z$+~=PT$gtm_9LgmuJjDf*`3urb|0vPZQbkZkFp%EuVG6OHA$nArAFrVvD*@5*A%nZ z8_McCi_^6K$C;*IxIUcpsyf@4)Z`ls(v)hFGpaU!CfS5p(rS!=?G-)x32Hv_hfkla zjcZf%)D&qxDWe^QyESy1;lrphbp@B(r>4#jZqoOFrgpW(%%i^kbZx$_#4*dSksFeF zaLtYApJ{{5(b-k;w>GcDq>le=O^NM1sY66v3cito&q+I&ny^A2^=_?lGl$Q&pf_#C zNH+`AW{Vr9`W)_{PAifyNfNj9r{~FR8 zOufD-2J+=vH_BsQGw3S~s2ig?v_hQ#@)fMZHBLzeJmEe&nkKzpt&xKXXebQ?gE8bF zu5l02e2wSD8;qZybxhY3abw`EZtU5Esn@-Zwy(2Iy&Ql?hqlnN5N0f!hRsbh6riCOa9$!!8<$y2KN%+d7J_AJ@!+s6xdJsce0;;A7{FCdwL(% zayQ#{J56?euu|2fuwOt@H^E{uje;LSyI^E;+66Upz0p(fqguTq-Kn9i@V8dOf+N_! zLBWrycPIm1wn;M|AU~&GH=um)YkyD)Q-GB+EDng>b|7uA^Me{yr;z5C8O;;% z{!Bhj&=)K5l^^|;=P2?6mj(k;zzplf|2Qv}1Gww%e^`aqZP>)N1{H9Tlr;U15 zvb@k|ZqRJG@>~pY_j#XVtp>M4j9bX99uLy|juEHO4l(s?Z)sXNzi&h>*gD*mA54jq zTka2CsuO!#o#{1(F~>GcX^KDArWlutyTe`Su6TD^YZ`-_!dioJ*p}vS>0G)`ABl5j zk%cwBxR}VF5W~Xk)&B?b=URBM@fL{N?FOI`uufD z4*K*J$ln@~f-;KMQM(aA|0X*hl8W5^K4@TtHbKyWC=o4+@>ZUc|Dzg~HI8T1s!CU3 z#e1C$BJTe@`cM2{(OQGsMs$MmMo_U3{7YdX@Vv!T1~mI%&KPNi9dG?U1`X&b2y z5yK-zgz{;hAN>z|`Z}!OU0`D4vFUs zkPVF2!2Gc%uCWG$UrRQ>j>yI_tOW=3<00EUI&ZEuOVqXbfJoPvfqWp%7RaiL^q|h= zXA{}<1S9p?v=16fL%w^}Zq<|DP2_f;+pXz<&Z3kd+S`0Nn`x7Poy_gx!X_2*=_w*j zH=|{q!Gqm2aZJ)iUgILRo!`QKc>+C?GDxp^e#(bP(?fgjxa4~1COPc>*2-H^!uhRJ zX(}ls{B?oc0Yr{RwNb5loI0lc`e&&GawolEkExt$R=21 z%hW#XBjrS!JjC3#PnGj{>{F1kayf<;&|`{Tj<+aA?txE}KA1})!{d+^zMO;o1GGI2gDbEFW8{M63AU#p<~GykBoELVC6Hr24S!qldn&ijF#1?=B!YK-v>fLfS`zv>>}P$BPfv42 zeMU$d&uL`RrO^?yz=Ae6(?35-3UKlToe8-qMiFeWg#vPW1o2zp9fgu1yaZjB=_I(Wii%pkHTz95WXF@2C~!%5mppt6Yl{Q){F4{9`yeo&{e< zBq9yQ%jAI=p6aG0F0ekQ(5rE3m9<))4uKQ2O}d_SnpBTSauoMg!0Nal%!LP2q&cI& z#bE_oqF5g61BLX2ENCESy?-MA&yzAzcaW+97y~w(18TVQ%D+5qMCDl3OXnT4ydy- zXY!neYoEe0>^CE?v{UaP51!Q$X7q^a0C(2m%u0t{WIKGDK3k(esv?NOvI4W9_cHA6>G#Eeq87$mVf>FlrtL3oPnZ!8xkT=o@|fk4RQWOlp5cr=sy8VX-4k{@?vEx?SnLt0?iq(t6t(;0kuk( zLWdw8EFQ-L*u@Y{(4Mif*m$MBei?h#C@9FO<;fliN_9pTN+{>$Ehu%A^^2F-BNBe5 z;OzkcmXPQ^HIH_7F7vQ$IqxsfkvCZiH7RaMaGiulte$0X_h5MM>dBh1aBf1?o5Hq$e z=L8w`Py*zFGU!>l#bnKLbtKSpW<-kRR8tMnD4<{OxrWAK8a8y6z9oR{7=PV4pYK7-LY;NA#wd(-j)q^8iM zXan<7?R@~xzqx`eD@@0b<}FUgM~l#}78QmR<*o%WX@R`ew-0NG6Gjqe9OJU)`)`h{ z#{_B^KW5B&8*@8`M@h&I{xSw@p@7`}hq;YNXrJ)bWWVEEbK-RT+dFkT*8Er<2CK>u zXUnql4#;aTZovsb*`aoBk^Az)Me#LgbyfpfzTEyUt`q%*fEt z9Qq*J^j*GvGCCJ5*M*=3e_Qmv0LZ%=umW3F*cHMoTm!NQ7=1X z9((}(!j7cwmTinO=)X2+o%a9W^j*a(B;-RCImndD;i&mAdGO(C!TT+%#koW%+NFJr zARr%+f_oeaGtF*T3b1w&*OmgN`REypOq}&*>}|H%Vg;qE?SDxiADbh1?=d}e7ipeV zS;3R3l#q{e)=%Vc8R0pW43QGfGllT$Qaj=E%KLcnvS*mvCwQ7yq_}Sl{;Tx0uEbY9 z|4Dbw7nX`zq*3q{!fl84PNw-(1=)$bP9x0<0&fSd#(yQhzAZ zGf{t`KN1*u8q{dX$9g^gmT=8OC-i!V98L}haJtcu(1r`*$2O3AYadj zQ)yN-_~cGjRW#MrB0PNH(O;FMqV3~k?*t5_!svn5%(DDQ#Wq^;2e+*?)4Z1_fc{k z!w0Kg{EBP#DuHrvjnTvO7+`20_&5XU#y zQ(YQYrq7)eOyzw3(pBlW^f6S%L->0pJ>j@Jp?rSgM#$O%~zYyU_)E9AoZVWbI zMi27wUC#d!xr8}&DkcX!&3s30zpCWM|Lw~+=zaOJ#Q%CK4%0AfLia|MI85hpj*=$_ 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 z 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

}xaeiiHi-&)$jLhVMl}{<600)LMJ~MAG1m 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

5%{^RIf(f>JXf9}{mUc&Uq-Ou-#$4`CF z>%O-AeUPUKNZ1GyMBTHr{VXhSI_WYIOER?ftmkv^1b-{_aZQ(fBo;h z?c#1z1Qz(umlVDn{QsH#EobyUv&Q^S=C|Chp)tR)=eI|{vFFQueL46~A~4sJ$e4-w zH5B}RWzVnYzq04ceSJyzgZ&i$N%X&cX@^O~_T_?4&A%M{4OpWjvGjiv|NqH+$qn!Y z;hzP2ZL$g7|KGtC{V({>zl8w*X#{^hE&nID#Ek!k|CZZ-rki{@^bem0f8q8M^IJ~v zpUOYE&jiiCrPwbB|H$HR`Tq@QzG&|AC5^v~zC!;C{BIE7zw_rm?fA2z)vG|BpV|mvR0K|9NS@7x(@DKFlDl literal 0 HcmV?d00001 diff --git a/build/systemMenu_RED/ARM9/main.rsf b/build/systemMenu_RED/ARM9/main.rsf new file mode 100644 index 00000000..dd40e6cd --- /dev/null +++ b/build/systemMenu_RED/ARM9/main.rsf @@ -0,0 +1,147 @@ +#---------------------------------------------------------------------------- +# Project: TwlSDK - include +# File: ROM-BB.rsf +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded insructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: $ +# $Rev$ +# $Author$ +#---------------------------------------------------------------------------- +# +# TWL ROM SPEC FILE +# + +Arm9 +{ + Static "$(MAKEROM_ARM9:r).FLX.TWL.sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.FLX.TWL.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.FLX.TWL.sbin$(COMPSUFFIX9)" + Elf "$(MAKEROM_ARM9:r).tef" +} + +Arm7 +{ + Static "$(MAKEROM_ARM7_BASE:r).FLX.TWL.sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7_BASE:r)_defs.FLX.TWL.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7_BASE:r)_table.FLX.TWL.sbin$(COMPSUFFIX7)" + Elf "$(MAKEROM_ARM7_BASE:r).tef" +} + +Arm9.Ltd +{ + Static "$(MAKEROM_ARM9:r).LTD.TWL.sbin$(COMPSUFFIX9)" + OverlayDefs "$(MAKEROM_ARM9:r)_defs.LTD.TWL.sbin$(COMPSUFFIX9)" + OverlayTable "$(MAKEROM_ARM9:r)_table.LTD.TWL.sbin$(COMPSUFFIX9)" +} + +Arm7.Ltd +{ + Static "$(MAKEROM_ARM7_BASE:r).LTD.TWL.sbin$(COMPSUFFIX7)" + OverlayDefs "$(MAKEROM_ARM7_BASE:r)_defs.LTD.TWL.sbin$(COMPSUFFIX7)" + OverlayTable "$(MAKEROM_ARM7_BASE:r)_table.LTD.TWL.sbin$(COMPSUFFIX7)" +} + +Property +{ + ### + ### Settings for FinalROM + ### + #### BEGIN + # + # TITLE NAME: Your product name within 12bytes + # + #TitleName "YourAppName" + + # + # MAKER CODE: Your company ID# in 2 ascii words + # issued by NINTENDO + # + #MakerCode "00" + + # + # REMASTER VERSION: Mastering version + # + #RomVersion 0 + + # + # ROM SPEED TYPE: [MROM/1TROM/UNDEFINED] + # + RomSpeedType $(MAKEROM_ROMSPEED) + + # + # ROM SIZE: in bit [64M/128M/256M/512M/1G/2G] + # + #RomSize 128M + #RomSize 256M + + # + # ROM PADDING: TRUE if finalrom + # + #RomFootPadding TRUE + + # + # ROM HEADER TEMPLATE: Provided to every product by NINTENDO + # + #RomHeaderTemplate ./etc/rom_header.template.sbin + + # + # BANNER FILE: generated from Banner Spec File + # + #BannerFile ./etc/myGameBanner.bnr + BannerFile $(TWLSDK_ROOT)/include/twl/specfiles/default.bnr + + ### + ### Setting for TWL + ### + # + # BANNER FILE: + # + BannerTWLFile $(TWLSDK_ROOT)/include/twl/specfiles/default.bnr + + # + # Boot allowed Media: [GameCard/NAND/SDCard/DownloadPlay] + # possible to choose one or more. + # + BootMedia GameCard NAND SDCard DownloadPlay + + # + # Certification FILE: + # + Certificate $(TWLSDK_ROOT)/include/twl/specfiles/default_sgn.sbin + + # + # Digest parameters: + # + DigestParam 1024 32 + + # + # WRAM mapping: [MAP_BB_HYB/MAP_BB_LTD/MAP_TS_HYB/MAP_TS_LTD] + # don't have to edit + # + WramMapping $(MAKEROM_WRAM_MAPPING) + + # + # Codec mode: + # don't have to edit + # + CodecMode $(MAKEROM_CODEC_MODE) + + ### + #### END +} + +RomSpec +{ + Offset 0x00000000 + Segment ALL + HostRoot data + Root /data + File NTR_IPL_font_m.NFTR +} diff --git a/build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.c b/build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.c new file mode 100644 index 00000000..d6425b6c --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.c @@ -0,0 +1,102 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: DS_Chat.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "misc.h" +#include "DS_Chat.h" +#include "DS_Setting.h" + +// define data------------------------------------------ +#define RETURN_BUTTON_TOP_X 2 +#define RETURN_BUTTON_TOP_Y 21 +#define RETURN_BUTTON_BOTTOM_X ( RETURN_BUTTON_TOP_X + 8 ) +#define RETURN_BUTTON_BOTTOM_Y ( RETURN_BUTTON_TOP_Y + 2 ) + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- + +static void DS_ChatInit(void); +static int DS_Chat(void); + +// global variable ------------------------------------- + +// static variable ------------------------------------- + +// const data ----------------------------------------- + +// ピクトチャットのメインループ +int DS_ChatMain(void) +{ + DS_ChatInit(); + + while(1) { + OS_WaitIrq( 1, OS_IE_V_BLANK ); + ReadKeyPad(); + + if( DS_Chat() ) { + return 0; + } + + if ( PAD_DetectFold() == TRUE ) { // スリープモードへの遷移 + SYSM_GoSleepMode(); + } + } + return 0; +} + + +//====================================================== +// ピクトチャット +//====================================================== +// ピクトチャットの初期化 +static void DS_ChatInit( void ) +{ + NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_WHITE ); + + switch(csrMenu) { + case 0: + PutStringUTF16( 1 * 8, 0 * 8, TXT_COLOR_BLUE, (const u16 *)L"PictoChat"); + break; + } + + PutStringUTF16( 4 * 8, 8 * 8, TXT_COLOR_BLACK, (const u16 *)L"Under Construction..."); + + GXS_SetVisiblePlane( GX_PLANEMASK_BG0 ); +} + + +// ピクトチャット(空処理) +static int DS_Chat(void) +{ + BOOL tp_cancel = FALSE; + + ReadTpData(); // タッチパネル入力の取得 + + // [RETURN]ボタン押下チェック + if(tpd.disp.touch) { + tp_cancel = InRangeTp( RETURN_BUTTON_TOP_X * 8, RETURN_BUTTON_TOP_Y * 8 - 4, + RETURN_BUTTON_BOTTOM_X * 8, RETURN_BUTTON_BOTTOM_Y * 8 - 4, &tpd.disp ); + } + + if( ( pad.trg & PAD_BUTTON_B ) || tp_cancel ) { + return 1; + } + return 0; +} + diff --git a/build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.h b/build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.h new file mode 100644 index 00000000..3b34b21f --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Chat/DS_Chat.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: DS_Chat.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __DS_CHAT_H__ +#define __DS_CHAT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include + +// define data---------------------------------------------------------- + +int DS_ChatMain( void ); + +#ifdef __cplusplus +} +#endif + +#endif // __DS_CHAT_H__ diff --git a/build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.c b/build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.c new file mode 100644 index 00000000..13d9abb4 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.c @@ -0,0 +1,1618 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: DS_DownloadPlay.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +// ※※※ mb_private.hのPRINT_DEBUGを"1"にしていると、ダウンロード後に正常にブートできなくなっているので、注意。 + +#include +#include // ここはとするのはOK? +#include +#include "mb_child.h" +#include "mb_private.h" + + +#include "misc.h" +#include "DS_Setting.h" +#include "DS_DownloadPlay.h" + +// define data------------------------------------------ +#define PARENT_VIEW_NUM 4 // 親機情報リストの一画面表示数 +#define PLIST_X 1 // 親機情報リストの表示X位置 +#define PLIST_Y 4 // 親機情報リストの表示Y位置 +#define MB_DMA_NO 2 // マルチブート用DMA番号 +#define PRG_NEXT_SEQ_QUE_NUM 4 // 次のプログラムシーケンスを格納するキューの数 +#define MY_GGID 0x00000000 // マルチブート用GGID +#define G_INTRO_X 1 // ゲーム内容説明表示X位置 +#define G_INTRO_Y 4 // ゲーム内容説明表示Y位置 +#define G_MEMBER_X 1 // 通信メンバー表示X位置 +#define G_MEMBER_Y 10 // 通信メンバー表示Y位置 +#define MSG_VIEW_COUNT 75 // メッセージ表示Vカウント数 +#define MSG_BLINK_COUNT 12 // メッセージ点滅カウント数 + +#define NINLOGO_LOAD_1D_CHAR // Nintendoロゴデータを1Dマッピングキャラクタでロードする。 + + // プログラムシーケンス +typedef enum PrgSeq { + PSEQ_READY = 0, + PSEQ_INIT, + PSEQ_INITIALIZING, + PSEQ_ENDING, + PSEQ_END, + PSEQ_CANCELLED, + PSEQ_DISCONNECTED_BY_PARENT, + PSEQ_SCANNING, + PSEQ_CONNECTING, + PSEQ_CONNECT_SUCCEEDED, + PSEQ_CONNECT_FAILED, + PSEQ_REQ_REFUSED, + PSEQ_MEMBER_FULL, + PSEQ_DOWNLOAD_READY, + PSEQ_DOWNLOADING, + PSEQ_DOWNLOAD_COMPLETED, + PSEQ_DOWNLOAD_FAILED, + PSEQ_BOOT_REQ_WAIT, + PSEQ_BOOT_READY, + PSEQ_BOOT_START, + PSEQ_BOOT_FAILED +}PrgSeq; + +static char *str_prgSeq[] = { + "PSEQ_READY", + "PSEQ_INIT", + "PSEQ_INITIALIZING", + "PSEQ_ENDING", + "PSEQ_END", + "PSEQ_CANCELLED", + "PSEQ_DISCONNECTED_BY_PARENT", + "PSEQ_SCANNING", + "PSEQ_CONNECTING", + "PSEQ_CONNECT_SUCCEEDED", + "PSEQ_CONNECT_FAILED", + "PSEQ_REQ_REFUSED", + "PSEQ_MEMBER_FULL", + "PSEQ_DOWNLOAD_READY", + "PSEQ_DOWNLOADING", + "PSEQ_DOWNLOAD_COMPLETED", + "PSEQ_DOWNLOAD_FAILED", + "PSEQ_BOOT_REQ_WAIT", + "PSEQ_BOOT_READY", + "PSEQ_BOOT_START", + "PSEQ_BOOT_FAILED", +}; + + + // 親機情報発見時間データ +typedef struct FindTime { + BOOL find; // 発見したかどうか + int vcount; // 発見時間 +}FindTime; + + // メッセージ表示ステータス +typedef struct MsgViewStatus { + u16 handle; + u16 vcount; + u16 flag; + u16 color; + const u8 *str; + int (*nextProcessp)(void); +}MsgViewStatus; + + // 次プログラムシーケンスを格納用キュー +typedef struct PrgNextSeqQue { + BOOL lock; + u8 pad; + u8 num; + u8 top; + u8 bottom; + PrgSeq seq[ PRG_NEXT_SEQ_QUE_NUM ]; +}PrgNextSeqQue; + + +// extern data------------------------------------------ +extern void MBw_SetMaxScanTime( u16 time ); +extern int MBw_GetScanChannel( void ); +extern void UnCompNintendoLogo( u16 *NintendoLogoDatap, u16 *dstp, u32 *temp ); + +// function's prototype declaration--------------------- + // メインシーケンス +static void SEQ_DSDL_init( void ); +static int SEQ_DSDL_Connect( void ); +static int SEQ_DSDL_Download( void ); +static BOOL CheckNextSeq_Connect( void ); +static BOOL CheckNextSeq_Download( void ); + // 無線コールバック +static void CallbackChild_MB( u32 status, void *arg ); // マルチブート用コールバック関数 + // 表示系 +static void DispTopScreen( void ); +static void DispScanStatus( void ); +static void DispParentNum( void ); +static void DispParentList( void ); +static void DispGameIntroduction( void ); +static void DispPlayMember( void ); +static void DispParentGameInfo( u32 view_no, u32 listNo, BOOL drawFixedDataFlag ); +static void ClearDispParentGameInfo( u32 view_no, u32 listNo ); +static void DispGameIntroduction_Core( u32 listNo ); +static void DispPlayMember_Core( u32 listNo ); +static void ClearDispGameIntroduction( void ); +static void ClearDispPlayMember( void ); +static void DecimalToString( u8 *dstp, const void *valuep, u8 drawLength, u8 size ); +static void InitParentFindTime( void ); +static void CountParentFindTime( void ); +static BOOL CheckParentFindTime( u32 index ); +static void CountAndDispTotalTime( void ); +static void SetIconOBJ( u32 index ); +static void ClearIconOBJ( u32 index ); +static void SetDispMessage( u16 color, const u8 *str ); +static BOOL DispMessage( void ); +static void SetBlinkMessage( u16 color, const u8 *str ); +static void DispBlinkMessage( void ); + // Nintendoロゴ表示 +static void InitDispNintendoLogo( void ); +static BOOL DispNintendoLogo( void ); + // その他 +static void SetMyUserInfo( MBUserInfo *my ); +static BOOL IsScanLock( void ); + // 割り込み +static void VBlankIntr_WDL( void ); + // シーケンスキュー処理 +static void InitPrgNextSeqQue( void ); +static BOOL SetPrgNextSeqQue( PrgSeq seq ); +static BOOL GetPrgNextSeqQue( PrgSeq *seqp ); +static void LockPrgNextSeqQue( void ); +static void UnlockPrgNextSeqQue( void ); +static BOOL IsEmptyPrgNextSeqQue( void ); + +void SearchPatchAddress( void ); + +// global variable ------------------------------------- + +// static variable ------------------------------------- +static int (*wdProcess)( void ); // 現在実行中のプロセスへのポインタ +static int csrC; // メニューのカーソル位置 +static int csrC_old; // メニューの前カーソル位置 +static PrgSeq prgSeq; // プログラムシーケンス +static PrgNextSeqQue nextSeq; // 次のプログラムシーケンスを格納するキュー +static BOOL end_flag; // 終了フラグ +static MsgViewStatus msgStat; // メッセージ表示ステータス +static MBUserInfo myUser; // 自分のユーザー情報 +static u16 tgid = 0; +static u16 tp_touch_count = 0; +static u32 gameInfoLostCount = 0; +// 親機リストの表示に使用 +static int unrenewalFlag; +static int total_vcount; +static int time_ms; // 親機発見時間ms +static int time_sec; // 親機発見時間sec +static u16 msgHandle; // メッセージ表示ハンドル +static u16 dispGameInfoFlag; // 既に表示したゲーム情報をビットで示す。 +static u16 dispIntroFlag; // ゲームの詳細データ描画フラグ +static u16 dispMemberFlag; // ゲームの詳細データ描画フラグ +static u16 gameName[ MB_GAME_NAME_LENGTH + 1 ]; // 親機ゲームネーム +static u16 userName[ MB_USER_NAME_LENGTH + 1 ]; // 親機ユーザーネーム +static u16 gameIntroduction[2][ MB_GAME_INTRO_LENGTH / 2 + 1 ]; + // 親機ゲーム内容説明 +static u16 playMember[ MB_MEMBER_MAX_NUM ][ MB_USER_NAME_LENGTH + 1]; + // 通信メンバー名リスト +static u8 parentListNo[ PARENT_VIEW_NUM ][ 4 ] ATTRIBUTE_ALIGN(2); + // 親機リスト番号 +static u32 objVramBuff[ (MB_ICON_DATA_SIZE * PARENT_VIEW_NUM + 0x20) / sizeof(u32) ] ATTRIBUTE_ALIGN(32); +static FindTime findTime[ MB_GAME_INFO_RECV_LIST_NUM ]; // 親機発見時間データ +static GXOamAttr oamBakM[ 128 ] ATTRIBUTE_ALIGN(32); // OAM バックアップ + +static const MbBeaconRecvStatus *mbrsp; + +// MBライブラリ用ワーク +static u32 mbwork[ MB_CHILD_SYSTEM_BUF_SIZE / sizeof(u32) ]; + +// Nintendoロゴ表示 +static int loop_count; +static u32 ninLogoBuff[ 0x700 / sizeof(u32) ]; + +static MBDownloadFileInfo dlfileinfo; +static u8 output_buffer[ AUTH_BUFFER_LEN ]; + +// const data ----------------------------------------- + // 表示用文字列 +static const u8 str_sura[] ATTRIBUTE_ALIGN(2) = "/"; +static const u8 str_period[] ATTRIBUTE_ALIGN(2) = "."; +static const u8 str_sec[] ATTRIBUTE_ALIGN(2) = "sec"; +static const u8 str_disconnected[] ATTRIBUTE_ALIGN(2) = "disconnected by parent."; +static const u8 str_connect_succeeded[] ATTRIBUTE_ALIGN(2) = "connect succeeded."; +static const u8 str_connect_failed[] ATTRIBUTE_ALIGN(2) = "connect failed."; +static const u8 str_req_refused[] ATTRIBUTE_ALIGN(2) = "req refused."; +static const u8 str_member_full[] ATTRIBUTE_ALIGN(2) = "member full."; +static const u8 str_downloading[] ATTRIBUTE_ALIGN(2) = "DOWNLOADING...."; +static const u8 str_download_completed[] ATTRIBUTE_ALIGN(2) = "download completed."; +static const u8 str_download_cancelled[] ATTRIBUTE_ALIGN(2) = "download cancelled."; + + // メニュー関数用 親機リストuカ字列リスト +static u8 *str_parentListNo[] ATTRIBUTE_ALIGN(2) = { + parentListNo[0], + parentListNo[1], + parentListNo[2], + parentListNo[3], +}; + + // メニュー関数用 メニュー構成データ +static const MenuComponent childModeSel = { + PARENT_VIEW_NUM, // 項目数 + PLIST_X, // X位置(キャラ数) + PLIST_Y, // Y位置( 〃  ) + 0, // 次の項目へのX位置キャラ数 + 4, // 次の項目へのY位置キャラ数 + 3, + WHITE, // 非選択色 + HIGHLIGHT_Y, // 選択色 + (const u8 **)&str_parentListNo, // メニュー項目文字列リスト +}; + + +//====================================================== +// メインループ +//====================================================== + +// 無線マルチブートのメインループ +int DS_DownloadPlayMain(void) +{ + SEQ_DSDL_init(); + + wdProcess = SEQ_DSDL_Connect; + + OS_TPrintf("MbBeaconRecvStatus:%d\n", sizeof(MbBeaconRecvStatus) ); + + while(1) { + OS_WaitIrq(1, OS_IE_V_BLANK); + ReadKeyPad(); + mf_KEYPAD_rapid(); + + mbrsp = MB_GetBeaconRecvStatus(); + + if( wdProcess != NULL ) { + if(wdProcess()) { + return 0; + } + } + + //// ここから //// + { + static int touch = 0; + TPData tmp1 ATTRIBUTE_ALIGN(32); + TPData tmp2 ATTRIBUTE_ALIGN(32); + + while (TP_RequestRawSampling(&tmp1) != 0) {} + TP_GetCalibratedPoint(&tmp2, &tmp1); + + if (tmp2.touch != touch) + { + tp_touch_count++; + (void)DrawDecimalSJIS( 16, 0, RED, &tp_touch_count, 4, 2 ); + OS_Printf("touch change %d validity = %d\n", tmp2.touch, tmp2.validity); + touch = tmp2.touch; + } + } + //// ここまで //// + +// if (SYSM_IsCardPulledOut()) { // カード抜け検出 + if ( 0 ) { + OS_Printf("Card is pulled out.\n"); +#ifdef __DEBUG + OS_Terminate(); +#endif + } + + if (PAD_DetectFold() == TRUE) { // スリープモードへの遷移 + SYSM_GoSleepMode(); + } + + OS_PrintServer(); // ARM7からのプリントデバッグを処理する + } + return 0; +} + + +//====================================================== +// 無線マルチブート(初期化) +//====================================================== + +// 無線マルチブートの初期化 +static void SEQ_DSDL_init(void) +{ + GXS_SetVisiblePlane( GX_PLANEMASK_NONE ); + GX_SetVisiblePlane ( GX_PLANEMASK_NONE ); + + (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr_WDL); + GXS_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_1D_32K); + + // NITROカードのROM内登録データのクリア + MI_CpuClearFast( (void *)HW_ROM_HEADER_BUF, 0x160 ); + + // サブスクリーンのクリア + MI_CpuClearFast( bgBakS, sizeof(bgBakS) ); + MI_CpuFillFast ( (void *)HW_OAM, 192 , HW_OAM_SIZE ); + MI_CpuFillFast ( (void *)oamBakS, 192 , sizeof(oamBakS) ); // 192でフィルしないと、未使用OBJが(0, 0)にキャラNo.0で全部表示されてしまう。 + + // メインスクリーンのクリア + MI_CpuClearFast( (void *)HW_BG_VRAM, 0x10000 ); + MI_CpuClearFast( (void *)HW_OBJ_VRAM, 0x8000 ); + MI_CpuClearFast( bgBakM, sizeof(bgBakM) ); + MI_CpuFillFast ( (void *)oamBakM, 192 , sizeof(oamBakM) ); // 192でフィルしないと、未使用OBJが(0, 0)にキャラNo.0で全部表示されてしまう。 + MI_CpuFillFast ( (void *)HW_OAM, 192 , HW_OAM_SIZE ); + MI_CpuCopyFast ( myPlttData, (void *)HW_BG_PLTT, sizeof(myPlttData) ); // BGパレット セット + + ClearAllStringSJIS(); + + (void)DrawStringSJIS ( 1, 0, WHITE, (const u8 *)"NICKNAME="); + (void)DrawStringSJIS ( 1, 2, LIGHTGREEN, (const u8 *)"PARENT NUM ="); +// (void)DrawStringSJIS ( 1, 22, LIGHTGREEN, (const u8 *)"GINFO LOST COUNT ="); + (void)DrawStringSJISEx( 26, 2, CYAN, str_period, PARENT_VIEW_NUM); + (void)DrawStringSJISEx( 29, 2, CYAN, str_sec, PARENT_VIEW_NUM); + + InitPrgNextSeqQue(); + unrenewalFlag = 0; + end_flag = FALSE; + prgSeq = PSEQ_INIT; + msgHandle = 0x8000; + dispGameInfoFlag = 0; + dispIntroFlag = 0; + dispMemberFlag = 0; + csrC_old = 2; // 最初はわざと違う値にしておく + csrC = 0; + { + int i; + for( i = 0; i < PARENT_VIEW_NUM; i++ ) { + parentListNo[i][2] = '.'; + parentListNo[i][3] = 0x00; + } + } + SetMyUserInfo( &myUser ); // MBUserInfoをNITRO設定データから読み出してセット + { + // ニックネーム表示 + u16 nickname[ MB_USER_NAME_LENGTH + 1 ]; + ExUTF16_LEtoSJIS_BE( (u8 *)nickname, (u16 *)myUser.name, myUser.nameLength ); + nickname[ myUser.nameLength ] = 0; + (void)DrawStringSJIS( 8, 0, WHITE, (const u8 *)nickname ); + } + + InitParentFindTime(); // 親機発見時間変数のクリア + + while( (SYSM_GetBootFlag() & BFLG_WM_INITIALIZED) == 0 ) {} + + LOADER_Init( NULL ); + + GXS_SetVisiblePlane( GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1 ); + GX_SetVisiblePlane ( GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1 ); +} + + +// TOPスクリーンへの表示 +static void DispTopScreen( void ) +{ + SetTargetScreenSJIS( TOP_SCREEN ); + ClearAllStringSJIS(); + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"WIRELESS DOWNLOAD"); + (void)DrawStringSJIS( G_INTRO_X, G_INTRO_Y, LIGHTGREEN, (const u8 *)"GAME INTRODUCTION"); + (void)DrawStringSJIS( G_MEMBER_X, G_MEMBER_Y, LIGHTGREEN, (const u8 *)"MEMBER LIST"); + SetTargetScreenSJIS( BOTTOM_SCREEN ); +} + + +//====================================================== +// 無線マルチブート(親機サーチ 〜 接続) +//====================================================== + +// 無線マルチブートの接続シーケンス +static int SEQ_DSDL_Connect(void) +{ + // 現在のprgSeqに応じた処理 + BOOL getSeqFlag = CheckNextSeq_Connect(); + + switch ( prgSeq ) { + case PSEQ_INIT: // 子機モードの開始(ライブラリの初期化〜StartScanまでの流れを実行) + if ( MB_Init( mbwork, &myUser, MY_GGID, tgid, MB_DMA_NO ) != WM_ERRCODE_SUCCESS ) { + OS_Printf("MB init failed.\n"); + break; + } + MB_CommSetChildStateCallback( CallbackChild_MB ); + if ( MB_StartChild() != WM_ERRCODE_SUCCESS ) { + OS_Printf("MB start failed.\n"); + break; + } + tgid++; + DispTopScreen(); + prgSeq = PSEQ_INITIALIZING; + break; + + case PSEQ_INITIALIZING: + break; + + case PSEQ_SCANNING: // スキャン中は随時、次シーケンスチェックを行う。 + case PSEQ_ENDING: + if( !getSeqFlag ) { + return 0; + } + break; + + case PSEQ_CONNECTING: // 接続中はキー入力を受け付けずにリターンする。(次シーケンスチェックは行う) + return 0; + + case PSEQ_CONNECT_SUCCEEDED: // メッセージ表示後、ダウンロードシーケンスに移行。 + if( DispMessage() ) { + UnlockPrgNextSeqQue(); // シーケンスロック解除 + wdProcess = SEQ_DSDL_Download; + } + return 0; + + case PSEQ_CONNECT_FAILED: // メッセージ表示後、スキャン再開。(スキャン再開そのものは、ライブラリが自動で行う。) + if( DispMessage() ) { + UnlockPrgNextSeqQue(); // シーケンスロック解除 + prgSeq = PSEQ_SCANNING; + } + break; + + case PSEQ_DISCONNECTED_BY_PARENT: // 切断検出メッセージ表示設定。 + if( DispMessage() ) { + UnlockPrgNextSeqQue(); // シーケンスロック解除 + prgSeq = PSEQ_INIT; + } + break; + + case PSEQ_CANCELLED: // 終了 + return 0; + + default: + break; + } + + + // カーソル移動 + if(pad.trg & PAD_KEY_DOWN){ // カーソルの移動 + if( ++csrC == MB_GAME_INFO_RECV_LIST_NUM ){ + csrC = 0; + } + } + if(pad.trg & PAD_KEY_UP){ + if( --csrC & 0x80 ){ + csrC = MB_GAME_INFO_RECV_LIST_NUM - 1; + } + } + DrawMenu((u16)(csrC & (PARENT_VIEW_NUM - 1)), &childModeSel); // リスト番号(カーソル)の表示 + DispParentNum(); // 発見親機数の表示 + DispParentList(); // 親機リストの表示 + DispScanStatus(); // WMスキャン状態の表示 + CountAndDispTotalTime(); // トータル時間のカウント&表示 + CountParentFindTime(); // 親機発見時間のカウント + + + // 親機への接続 + if(pad.trg & PAD_BUTTON_A) { + if( mbrsp->usefulGameInfoFlag & (0x0001 << csrC) ) { + if( MB_CommDownloadRequest( csrC ) == WM_ERRCODE_SUCCESS ) { // 接続開始 + OS_Printf("start conntct to parent.\n"); + prgSeq = PSEQ_CONNECTING; + }else { + OS_Printf("this parent info is invalid.\n"); + } + } + }else if(pad.trg & PAD_BUTTON_B) { // 終了開始 + if( prgSeq == PSEQ_SCANNING ) { + OS_Printf("MB End start\n"); + prgSeq = PSEQ_ENDING; +// end_flag = TRUE; + MB_End(); + } + }else if( pad.trg & PAD_BUTTON_R ) { + unrenewalFlag ^= 0x01; +// MB_SetUnrenewalGameInfoFlag( (BOOL)unrenewalFlag ); + } + + csrC_old = csrC; // 旧カーソル位置の退避 + return 0; +} + + +// 次シーケンスのチェック(コールバックでメインループとは非同期に返される次シーケンスへの移行をメインループのプログラム進行に合わせる。) +static BOOL CheckNextSeq_Connect(void) +{ + PrgSeq seq; + // MBコールバックによって、シーケンスが移行していた場合の処理 + if( GetPrgNextSeqQue( &seq) ) { // MBコールバックによって、シーケンスが移行していた場合の処理 + prgSeq = seq; + OS_Printf("prgSeq = %s\n", str_prgSeq[ prgSeq ]); + + switch( seq ) { + case PSEQ_SCANNING: + { +/* + u8 *ver = MBw_GetWLVersion(); + (void)DrawStringSJIS( 21, 0, WHITE, (const u8 *)"WL ver=" ); + (void)DrawStringSJIS( 26, 0, WHITE, (const u8 *)ver ); +*/ + } + break; + + case PSEQ_CONNECT_SUCCEEDED: // 接続成功メッセージ表示設定。 + SetDispMessage( YELLOW, str_connect_succeeded ); + LockPrgNextSeqQue(); // prgSeqをロックする。 + return FALSE; + + case PSEQ_CONNECT_FAILED: // 接続失敗メッセージ表示設定。 + SetDispMessage( RED, str_connect_failed); + LockPrgNextSeqQue(); // prgSeqをロックする。 + return FALSE; + + case PSEQ_DISCONNECTED_BY_PARENT: // 切断検出メッセージ表示設定。 + SetDispMessage( RED, str_disconnected); + LockPrgNextSeqQue(); // prgSeqをロックする。 + return FALSE; + + case PSEQ_CANCELLED: // 終了 + { + u32 i; + for( i = 0; i < PARENT_VIEW_NUM; i++ ) { + ClearIconOBJ( i ); // 全アイコンの消去 + } +// if( end_flag ) { +// ClearAllStringSJIS(); +// SetTargetScreenSJIS( TOP_SCREEN ); +// ClearAllStringSJIS(); +// SetTargetScreenSJIS( BOTTOM_SCREEN ); +// (void)DrawStringSJIS( 11, 11, WHITE, (const u8 *)"しゅうりょうしました。"); +// }else { + prgSeq = PSEQ_INIT; +// } + } + return FALSE; + } + } + return TRUE; // シーケンス移行がなかった場合もしくはFALSEリターンのシーケンスでなかった場合はTRUEリターン。 +} + + +//====================================================== +// 無線マルチブート(ダウンロード) +//====================================================== + +// 無線マルチブートのファイルダウンロードシーケンス +static int SEQ_DSDL_Download(void) +{ + static int count_old = 0; + // 現在のprgSeqに応じた処理 + BOOL getSeqFlag = CheckNextSeq_Download(); + + switch(prgSeq) { + + case PSEQ_REQ_REFUSED: + case PSEQ_MEMBER_FULL: // メッセージ表示後、一旦終了して初期化からやり直し。 + if( DispMessage() ) { + UnlockPrgNextSeqQue(); // シーケンスロック解除 + prgSeq = PSEQ_ENDING; + wdProcess = SEQ_DSDL_Connect; + MB_End(); + } + break; + + // ダウンロードファイル情報を受信し、ダウンロード準備ができた状態 + case PSEQ_DOWNLOAD_READY: +// if (pad.trg & PAD_BUTTON_A) { // ダウンロード開始 + OS_Printf("Start download.\n"); + ClearStringSJIS_handle(msgHandle); + (void)MB_CommStartDownload(); + SetBlinkMessage( YELLOW, str_downloading ); +// } + break; + + // ダウンロード中 + case PSEQ_DOWNLOADING: + if( getSeqFlag ) { + DispBlinkMessage(); + msgHandle = msgStat.handle; + + if( 1 ) { + u16 percent = MB_GetChildProgressPercentage(); + msgHandle = DrawDecimalSJIS( 16, 21, WHITE, &percent ,3, 2 ); + } + } + break; + + // ダウンロード完了 + case PSEQ_DOWNLOAD_COMPLETED: + if( DispMessage() ) { + { + msgHandle = DrawStringSJIS( 4, 21, LIGHTGREEN, "Sign Digest...."); + if ( ACSignDigest ( output_buffer, &dlfileinfo ) ) { + ClearStringSJIS_handle( msgHandle ); + msgHandle = DrawStringSJIS( 4, 21, LIGHTGREEN, "Digest SUCCEEDED."); + }else { + ClearStringSJIS_handle( msgHandle ); + msgHandle = DrawStringSJIS( 4, 21, RED, "Digest FAILED."); + } + { + int i; + for ( i = 0; i < 120; i++ ) { + SVC_WaitVBlankIntr(); + } + } + ClearStringSJIS_handle( msgHandle ); + } + UnlockPrgNextSeqQue(); // シーケンスロック解除 + prgSeq = PSEQ_BOOT_REQ_WAIT; + msgHandle = DrawStringSJIS( 4, 21, WHITE, "Waiting BOOT-REQ from parent."); + } + break; + + // 親機からのブート許可待ち + case PSEQ_BOOT_REQ_WAIT: + break; + + // ダウンロードが完了し、ブート準備ができた状態 +// case PSEQ_BOOT_READY: +// (void)LOADER_Start(); // ここでARM7によって、ダウンロードプログラムの再配置を行う。 +// return 1; // "1"でリターンすることで、無線マルチブートのメインループから抜けてIPL2に処理を戻す。 + + // 親機からのブート要求受信により、起動可否チェックを行う。(Nintendoロゴ表示&チェック) + case PSEQ_BOOT_READY: + if( DispNintendoLogo() ) { + if( SYSM_CheckNinLogo( (u16 *)GetRomHeaderAddr()->nintendo_logo ) ) { + prgSeq = PSEQ_BOOT_START; + }else { + SetDispMessage( RED, (const u8 *)"Illegal game data."); + prgSeq = PSEQ_BOOT_FAILED; + } + } + break; + + // ブート開始 + case PSEQ_BOOT_START: + ClearStringSJIS_handle(msgHandle); + + SearchPatchAddress(); + + (void)LOADER_Start(); // ここでARM7によって、ダウンロードプログラムの再配置を行う。 + return 1; // "1"でリターンすることで、無線マルチブートのメインループから抜けてIPL2に処理を戻す。 + + // ブート失敗 + // 親機によって、接続が切断された状態 + // キャンセルをした場合 + case PSEQ_BOOT_FAILED: + case PSEQ_DISCONNECTED_BY_PARENT: + case PSEQ_CANCELLED: + if( DispMessage() ) { // 指定メッセージを一定期間表示 + UnlockPrgNextSeqQue(); // シーケンスロック解除 + ClearStringSJIS_handle( msgHandle ); + prgSeq = PSEQ_INIT; + wdProcess = SEQ_DSDL_Connect; + } + break; + + default: + break; + } + + // Bボタンで終了処理を行う + if( pad.trg & PAD_BUTTON_B ) { + MB_End(); // キャンセル時は、親機サーチ状態からやり直す。 + } + + DrawMenu((u16)(csrC & (PARENT_VIEW_NUM - 1)), &childModeSel); // リスト番号(カーソル)の表示 + DispParentNum(); // 発見親機数の表示 + DispParentList(); // 親機リストの表示 + DispScanStatus(); // WMスキャン状態の表示 + CountAndDispTotalTime(); // トータル時間のカウント&表示 + CountParentFindTime(); // 親機発見時間のカウント + return 0; +} + + +// 次シーケンスのチェック(コールバックでメインループとは非同期に返される次シーケンスへの移行をメインループのプログラム進行に合わせる。) +static BOOL CheckNextSeq_Download(void) +{ + PrgSeq seq; + + // MBコールバックによって、シーケンスが移行していた場合の処理 + if( GetPrgNextSeqQue( &seq) ) { + prgSeq = seq; + OS_Printf("prgSeq = %s\n", str_prgSeq[ prgSeq ]); + + switch( seq ) { + + case PSEQ_REQ_REFUSED: // 接続拒否メッセージ表示設定 + SetDispMessage( RED, str_req_refused); + LockPrgNextSeqQue(); // prgSeqをロックする。 + return FALSE; + + case PSEQ_MEMBER_FULL: // メンバーFULLメッセージ表示設定。 + SetDispMessage( RED, str_member_full); + LockPrgNextSeqQue(); // prgSeqをロックする。 + return FALSE; + + case PSEQ_DOWNLOAD_READY: // ダウンロード準備完了 + ClearStringSJIS_handle( msgHandle ); + { + msgHandle = DrawStringSJIS( 4, 21, WHITE, "Sign Decript...."); + if ( ACSignDecrpto( output_buffer, &dlfileinfo ) ) { + ClearStringSJIS_handle( msgHandle ); + msgHandle = DrawStringSJIS( 4, 21, LIGHTGREEN, "Decript SUCCEEDED."); + }else { + ClearStringSJIS_handle( msgHandle ); + msgHandle = DrawStringSJIS( 4, 21, RED, "Decript FAILED."); + } + { + int i; + for ( i = 0; i < 120; i++ ) { + SVC_WaitVBlankIntr(); + } + } + ClearStringSJIS_handle( msgHandle ); + } + + msgHandle = DrawStringSJIS( 4, 21, WHITE, "PUSH [A] TO DOWNLOAD."); + break; + + case PSEQ_DOWNLOAD_COMPLETED: // ダウンロード完了 + ClearStringSJIS_handle( msgHandle ); + SetDispMessage( YELLOW, str_download_completed ); + LockPrgNextSeqQue(); // シーケンスロック + return FALSE; + +// case PSEQ_BOOT_READY: // ブート準備完了 +// ClearStringSJIS_handle( msgHandle ); +// break; + + case PSEQ_BOOT_READY: // ブート準備完了 + ClearStringSJIS_handle( msgHandle ); + InitDispNintendoLogo(); + break; + + case PSEQ_CANCELLED: + ClearStringSJIS_handle( msgHandle ); + SetDispMessage( RED, str_download_cancelled ); + LockPrgNextSeqQue(); // シーケンスロック + return FALSE; + + case PSEQ_DISCONNECTED_BY_PARENT: // 切断検出メッセージ表示設定。 + ClearStringSJIS_handle( msgHandle ); + SetDispMessage( RED, str_disconnected ); + LockPrgNextSeqQue(); // prgSeqをロックする。 + return FALSE; + + default: + break; + } + } + return TRUE; +} + + +//====================================================== +// コールバック +//====================================================== + +// 子機モードでのコールバック +static void CallbackChild_MB( u32 status, void *arg ) +{ + switch (status) + { + case MB_COMM_CSTATE_INIT_COMPLETE: // 初期化完了 + OS_Printf("CB: init completed.\n"); + (void)SetPrgNextSeqQue( PSEQ_SCANNING ); + break; + +// case MB_COMM_CSTATE_END_COMPLETE: // マルチブート終了 +// OS_Printf("CB: end completed.\n"); +// (void)SetPrgNextSeqQue( PSEQ_END ); +// break; + + case MB_COMM_CSTATE_REQ_REFUSED: // 親機からのエントリー拒否 + OS_Printf("CB: request refused.\n"); + (void)SetPrgNextSeqQue( PSEQ_REQ_REFUSED ); + break; + + case MB_COMM_CSTATE_MEMBER_FULL: // ゲームが定員に達した + OS_Printf("CB: member full.\n"); + (void)SetPrgNextSeqQue( PSEQ_MEMBER_FULL ); + break; + + case MB_COMM_CSTATE_CONNECT: // 親機への接続成功 + OS_Printf("CB: connected.\n"); + (void)SetPrgNextSeqQue( PSEQ_CONNECT_SUCCEEDED ); + break; + + case MB_COMM_CSTATE_CONNECT_FAILED: // 親機への接続失敗 + OS_Printf("CB: connect failed!\n"); + (void)SetPrgNextSeqQue( PSEQ_CONNECT_FAILED ); + break; + + case MB_COMM_CSTATE_DLINFO_ACCEPTED: // 親機からダウンロード情報を受信 + OS_Printf("CB: dlinfo accepted.\n"); + (void)SetPrgNextSeqQue( PSEQ_DOWNLOAD_READY ); + MI_CpuCopy16( (void *)arg, (void *)&dlfileinfo, sizeof( MBDownloadFileInfo ) ) ; + break; + + case MB_COMM_CSTATE_RECV_PROCEED: // 受信開始 + OS_Printf("CB: recv proceed.\n"); + (void)SetPrgNextSeqQue( PSEQ_DOWNLOADING ); + break; + + case MB_COMM_CSTATE_RECV_COMPLETE: // 受信成功 + OS_Printf("CB: recv completed.\n"); + (void)SetPrgNextSeqQue( PSEQ_DOWNLOAD_COMPLETED ); + break; + + case MB_COMM_CSTATE_BOOT_READY: // ブート準備完了 + OS_Printf("CB: boot ready.\n"); +// GetSYSMWork()->mb_flag = 1; +// GetSYSMWork()->mb_ggid = *(u32 *)( MB_GetBeaconRecvStatus()->list[ pCwork->connectTargetNo ].bssDesc.gameInfo.ggid ); +// GetSYSMWork()->mb_ggid = MB_GetBeaconRecvStatus()->list[ pCwork->connectTargetNo ].gameInfo.ggid; + (void)SetPrgNextSeqQue( PSEQ_BOOT_READY ); + break; + + case MB_COMM_CSTATE_CANCELLED: // ダウンロードキャンセル + OS_Printf("CB: download cancel.\n"); + (void)SetPrgNextSeqQue( PSEQ_CANCELLED ); + break; + + case MB_COMM_CSTATE_DISCONNECTED_BY_PARENT: // 親機からの切断通知 + OS_Printf("CB: disconnected by parent!\n"); + (void)SetPrgNextSeqQue( PSEQ_DISCONNECTED_BY_PARENT ); + break; + + case MB_COMM_CSTATE_GAMEINFO_LOST: + gameInfoLostCount++; + break; + } +} + + +//====================================================== +// 表示系サブルーチン +//====================================================== + +// スキャン状態の表示 +static void DispScanStatus(void) +{ +#if 0 + int channel = MBw_GetScanChannel(); + + (void)DrawHexSJIS( 13, 2, WHITE, &channel, 2); + if( IsScanLock() ) { // スキャンロック中なら、その時間を表示 + (void)DrawStringSJIS( 15, 2, RED, (const u8 *)"LOCK"); + (void)DrawHexSJIS ( 19, 2, WHITE, &mbrsp->nowLockTimeCount, 4); + }else { + (void)DrawStringSJIS( 15, 2, RED, (const u8 *)" "); + } +#endif +} + + +// 発見した親機数の表示 +static void DispParentNum(void) +{ + int i; + int num = 0; + + for (i = 0; i < MB_GAME_INFO_RECV_LIST_NUM; i++) { // 親機数のカウント + if( mbrsp->usefulGameInfoFlag & (0x0001 << i) ) num++; + } + (void)DrawDecimalSJIS( 10, 2, LIGHTGREEN, &num, 2, 4); +} + + +// 親機情報リストの表示 +static void DispParentList(void) +{ + u32 i; + u32 listNo = (u32)( csrC & ~(PARENT_VIEW_NUM - 1) ); // 現在表示中のリストの先頭を算出(~表示数でマスク) + u32 listNo_old = (u32)( csrC_old & ~(PARENT_VIEW_NUM - 1) ); // 前回表示したリストの先頭を算出 + +// (void)DrawDecimalSJISEx( 15, 22, WHITE, &gameInfoLostCount, 8, 4, 0); + + // ゲーム内容説明の表示 + DispGameIntroduction(); + + // 通信メンバーの表示 + DispPlayMember(); + + // 親機リストの表示 + for( i = 0; i < PARENT_VIEW_NUM; i++ ) { + if( (listNo != listNo_old) || !(mbrsp->usefulGameInfoFlag & (0x0001 << listNo)) ){ + if( dispGameInfoFlag & (0x0001 << listNo_old) ) { // 表示リスト位置が変更 or 該当親機が有効でなくなった場合、前回表示データが既に表示済みならクリアする。 + ClearDispParentGameInfo( i, listNo_old); + dispGameInfoFlag ^= 0x0001 << listNo_old; + } + } + + if( mbrsp->usefulGameInfoFlag & (0x0001 << listNo) ) { // 該当リストbフデータが有効で、かつ未表示なら表示する。 + DispParentGameInfo( i, listNo , !(dispGameInfoFlag & (0x0001 << listNo)) ); + dispGameInfoFlag |= 0x0001 << listNo; + } + if( csrC != csrC_old ) { + DecimalToString( parentListNo[i], &listNo, 2, 2); // ビュー画面の先頭リストナンバーからを文字列バッファに入れる。 + } + listNo++; + listNo_old++; + } +} + + +// ゲーム内容説明の表示 +static void DispGameIntroduction( void ) +{ + BOOL clear = FALSE; + + if( ( ( csrC != csrC_old ) && ( dispIntroFlag & (0x0001 << csrC_old) ) ) + || ( !(mbrsp->usefulGameInfoFlag & (0x0001 << csrC)) && ( dispIntroFlag & (0x0001 << csrC) ) ) ) { + ClearDispGameIntroduction(); // カーソルが動いて、前カーソル位置の詳細表示を行っていたか、 + dispIntroFlag = 0; + clear = TRUE; + } + + if( (mbrsp->usefulGameInfoFlag & (0x0001 << csrC)) && !( dispIntroFlag & (0x0001 << csrC) ) ) { + if ( !clear ){ // 現在カーソル位置のゲーム情報が有効で、まだ詳細表示を行っていなかったら表示。 + ClearDispGameIntroduction(); + } + DispGameIntroduction_Core( (u32)csrC ); + dispIntroFlag = (u16)( 0x0001 << csrC ); // カーソルが移動された時か、現在位置のゲーム情報が未表示の時にのみ表示 or クリアを行う。 + } +} + + +// 通信メンバーのクリア&表示 +static void DispPlayMember( void ) +{ + BOOL clear = FALSE; + + if( ( ( csrC != csrC_old ) && ( dispMemberFlag & (0x0001 << csrC_old) ) ) + || ( !(mbrsp->validGameInfoFlag & (0x0001 << csrC)) && ( dispMemberFlag & (0x0001 << csrC) ) ) ) { + ClearDispPlayMember(); // カーソル位置のゲーム詳細情報を表示していて、そのゲーム情報が無効になったらクリア。 + dispMemberFlag = 0; + clear = TRUE; + } + + if( (mbrsp->validGameInfoFlag & (0x0001 << csrC)) && !( dispMemberFlag & (0x0001 << csrC) ) ) { + if ( !clear ){ // 現在カーソル位置のゲーム情報が有効で、まだ詳細表示を行っていなかったら表示。 + ClearDispPlayMember(); + } + DispPlayMember_Core( (u32)csrC ); + dispMemberFlag = (u16)( 0x0001 << csrC ); // カーソルが移動された時か、現在位置のゲーム情報が未表示の時にのみ表示 or クリアを行う。 + } +} + + +// 指定された親機情報の表示 +static void DispParentGameInfo( u32 view_no, u32 listNo, BOOL drawFixedDataFlag) +{ + if(drawFixedDataFlag) { // 変化しない情報の表示 + + MI_CpuClear16( gameName, MB_GAME_NAME_LENGTH * 2 ); + MI_CpuClear16( userName, MB_USER_NAME_LENGTH * 2 ); + ExUTF16_LEtoSJIS_BE( (u8 *)gameName, (u16 *)mbrsp->list[ listNo ].gameInfo.fixed.gameName, MB_GAME_NAME_LENGTH * 2 ); + ExUTF16_LEtoSJIS_BE( (u8 *)userName, (u16 *)mbrsp->list[ listNo ].gameInfo.fixed.parent.name, (u16)( mbrsp->list[ listNo ].gameInfo.fixed.parent.nameLength * 2)); +// MI_CpuCopy16( mbrsp->list[ listNo ].gameInfo.fixed.gameName, gameName, MB_GAME_NAME_LENGTH * 2); +// MI_CpuCopy16( mbrsp->list[ listNo ].gameInfo.fixed.parent.name, userName, mbrsp->list[ listNo ].gameInfo.fixed.parent.nameLength * 2); + gameName[ MB_GAME_NAME_LENGTH ] = 0; + userName[ mbrsp->list[ listNo ].gameInfo.fixed.parent.nameLength ] = 0; + + (void)ClearStringSJISEx( gameName, view_no); + (void)ClearStringSJISEx( userName, view_no); + (void)DrawStringSJISEx( 9, (PLIST_Y + (int)view_no*4), WHITE, gameName, view_no); + (void)DrawStringSJISEx( 9, (PLIST_Y + (int)view_no*4 + 2), WHITE, userName, view_no); + + (void)DrawStringSJISEx( 26, (PLIST_Y + (int)view_no*4), YELLOW, str_sura, view_no); + (void)DrawDecimalSJIS ( 27, (PLIST_Y + (int)view_no*4), YELLOW, &mbrsp->list[ listNo ].gameInfo.fixed.maxPlayerNum, 2, 1); + + // 親機発見時間の表示 + (void)CheckParentFindTime( listNo ); // ここで親機を発見しているかを再確認しておく。 + time_ms = (int)findTime[listNo].vcount * 17; + time_sec = time_ms / 1000; + time_ms = (time_ms % 1000) / 10; + (void)DrawDecimalSJISEx( 23, (PLIST_Y + (int)view_no*4 + 2), CYAN, &time_sec, 4, 4, view_no); + (void)DrawDecimalSJISEx( 27, (PLIST_Y + (int)view_no*4 + 2), CYAN, &time_ms, 2, 4, view_no); + (void)DrawStringSJISEx ( 26, (PLIST_Y + (int)view_no*4 + 2), CYAN, str_period, view_no); + (void)DrawStringSJISEx ( 29, (PLIST_Y + (int)view_no*4 + 2), CYAN, str_sec, view_no); + + SetIconOBJ( listNo ); // アイコンの表示 + } + { // 変化する情報(現メンバー数・親機寿命カウントの表示) + (void)DrawDecimalSJIS( 24, (PLIST_Y + (int)view_no*4), YELLOW, &mbrsp->list[ listNo ].gameInfo.volat.nowPlayerNum, 2, 1); + (void)DrawHexSJIS ( 19, (PLIST_Y + (int)view_no*4 + 2), CYAN, &mbrsp->list[ listNo ].lifetimeCount, 4); + { + u16 color = RED; + if ( mbrsp->validGameInfoFlag & ( 0x0001 << listNo ) ) { + color = CYAN; + } + (void)DrawHexSJIS ( 19, (PLIST_Y + (int)view_no*4), color, &mbrsp->list[ listNo ].gameInfo.seqNoVolat, 2); + } + } +} + + +// 指定された親機情報の表示クリア +static void ClearDispParentGameInfo( u32 view_no, u32 listNo) +{ + // ※これらの変数のアドレスは、DispParentGameInfo側のものと一致してないと、表示をクリアすることができないので注意。(自動変数で表示するときはアドレスが変わってしまう) + // (これはDrawStringSJIS関数の仕様) + ClearStringSJISEx( gameName, view_no ); // ゲーム名 + ClearStringSJISEx( userName, view_no ); // ユーザー名 + ClearStringSJISEx( &time_sec, view_no ); // 親機発見時間sec + ClearStringSJISEx( &time_ms, view_no ); // 親機発見時間ms + ClearStringSJISEx( (void *)str_sura, view_no ); // "/" + ClearStringSJISEx( (void *)str_period, view_no ); // "." + ClearStringSJISEx( (void *)str_sec, view_no ); // "sec" + ClearStringSJIS ( (void *)&mbrsp->list[ listNo ].lifetimeCount ); // 親機寿命カウント + ClearStringSJIS ( (void *)&mbrsp->list[ listNo ].gameInfo.volat.nowPlayerNum ); // プレイ人数 + ClearStringSJIS ( (void *)&mbrsp->list[ listNo ].gameInfo.fixed.maxPlayerNum ); // 最大プレイ人数 + ClearStringSJIS ( (void *)&mbrsp->list[ listNo ].gameInfo.seqNoVolat ); // 最大プレイ人数 + + ClearIconOBJ( listNo ); // アイコンの消去 +} + + +// ゲーム内容説明の表示(実処理) +static void DispGameIntroduction_Core( u32 listNo ) +{ + int i; + const u16 *strp = mbrsp->list[ listNo ].gameInfo.fixed.gameIntroduction; + u16 *dstp; + u16 gameIntroTmp[ MB_GAME_INTRO_LENGTH / 2 + 1 ]; + + MI_CpuClear16( gameIntroduction[0], (MB_GAME_INTRO_LENGTH / 2 + 1) * sizeof(u16) ); + MI_CpuClear16( gameIntroduction[1], (MB_GAME_INTRO_LENGTH / 2 + 1) * sizeof(u16) ); + + dstp = gameIntroTmp; + for ( i = 0; i < MB_GAME_INTRO_LENGTH / 2; i++ ) { // バイト単位でのコピーなので、1行分は、MB_GAME_INTRO_LENGTH/2*2。 + if( ( *strp == NULL) || ( *strp == 0x000a ) ) { + *dstp++ = 0x0000; + }else { + *dstp++ = *strp++; + } + } + ExUTF16_LEtoSJIS_BE( (u8 *)gameIntroduction[ 0 ], gameIntroTmp, MB_GAME_INTRO_LENGTH / 2 ); + + if( *strp == 0x000a ) { + strp++; + } + + dstp = gameIntroTmp; + for ( i = 0; i < MB_GAME_INTRO_LENGTH / 2; i++ ) { + if( ( *strp == NULL) || ( *strp == 0x000a ) ) { + *dstp++ = 0x00; + }else { + *dstp++ = *strp++; + } + } + ExUTF16_LEtoSJIS_BE( (u8 *)gameIntroduction[ 1 ], gameIntroTmp, MB_GAME_INTRO_LENGTH / 2 + 1 ); + + ClearDispGameIntroduction(); + + SetTargetScreenSJIS( TOP_SCREEN ); + (void)DrawStringSJIS( ( G_INTRO_X + 1 ), ( G_INTRO_Y + 2 ), WHITE, (const u8 *)gameIntroduction[0] ); + (void)DrawStringSJIS( ( G_INTRO_X + 1 ), ( G_INTRO_Y + 4 ), WHITE, (const u8 *)gameIntroduction[1] ); + SetTargetScreenSJIS( BOTTOM_SCREEN ); +} + + +// ゲーム内容説明表示のクリア +static void ClearDispGameIntroduction( void ) +{ + SetTargetScreenSJIS( TOP_SCREEN ); + ClearStringSJIS( (void *)gameIntroduction[0] ); + ClearStringSJIS( (void *)gameIntroduction[1] ); + SetTargetScreenSJIS( BOTTOM_SCREEN ); +} + + +// 通信メンバーの表示(実処理) +static void DispPlayMember_Core( u32 listNo ) +{ + int n, count_x; + u16 nameLength; + int pos_x, pos_y; + const MBUserInfo *memberp = &mbrsp->list[ listNo ].gameInfo.volat.member[ 0 ]; + u16 *dstp; + + SetTargetScreenSJIS( TOP_SCREEN ); + + MI_CpuClear16( playMember, sizeof(playMember) ); + count_x = 0; + pos_x = G_MEMBER_X + 1; + pos_y = G_MEMBER_Y + 2; + for ( n = 0; n < MB_MEMBER_MAX_NUM; n++ ) { + + if( memberp->nameLength > MB_USER_NAME_LENGTH ) { // 名前長のチェック + nameLength = MB_USER_NAME_LENGTH; + }else { + nameLength = memberp->nameLength; + } + dstp = playMember[ n ]; + if( mbrsp->list[ listNo ].gameInfo.volat.nowPlayerFlag & (0x0002 << n ) ) { + + ExUTF16_LEtoSJIS_BE( (u8 *)dstp, (u16 *)memberp->name, nameLength ); + playMember[ n ][ nameLength ] = 0; + (void)DrawStringSJIS( pos_x, pos_y, WHITE, (const u8 *)playMember[ n ] ); + }else { + MI_CpuCopy16( (void *)"----------", (void *)playMember[ n ], MB_USER_NAME_LENGTH + 1); + (void)DrawStringSJIS( pos_x, pos_y, WHITE, playMember[ n ] ); + } + memberp++; + + if( ++count_x == 3 ) { // 表示位置の算出 + pos_x -= 20; + pos_y += 2; + count_x = 0; + }else { + pos_x += 10; + } + } + + SetTargetScreenSJIS( BOTTOM_SCREEN ); +} + + +// 通信メンバー表示のクリア +static void ClearDispPlayMember( void ) +{ + int i; + + SetTargetScreenSJIS( TOP_SCREEN ); + for( i = 0; i < MB_MEMBER_MAX_NUM + 1; i++ ) { + ClearStringSJIS( (void *)playMember[ i ] ); + } + SetTargetScreenSJIS( BOTTOM_SCREEN ); +} + + +// 10進データを文字列に変換 +static void DecimalToString(u8 *dstp, const void *valuep, u8 drawLength, u8 size) +{ + u16 count; + u32 mask, divisor, target; + + mask = 0xff; + while(--size > 0) { + mask = (mask << 8) | 0xff; + } + target=(*(u32 *)valuep) & mask; + count=10; + divisor=1000000000; + while(count) { + CP_SetDiv32_32(target, divisor); + if (count <= drawLength) { + *dstp++ = (u8)(CP_GetDivResult32()+0x0030); + } + target=(u32)CP_GetDivRemainder32(); + CP_SetDiv32_32(divisor, 10); + divisor=(u32)CP_GetDivResult32(); + count--; + } +} + + +// 親機発見時間変数のクリア +static void InitParentFindTime( void ) +{ + int i; + for( i = 0; i < MB_GAME_INFO_RECV_LIST_NUM; i++) { + findTime[i].find = FALSE; + findTime[i].vcount = 0; + } + total_vcount = 0; +} + + +// 親機発見時間のカウント +static void CountParentFindTime( void ) +{ + u32 i; + + for( i = 0; i < MB_GAME_INFO_RECV_LIST_NUM; i++ ) { + if( !CheckParentFindTime( i ) ) { + findTime[i].vcount = total_vcount; // 親機情報が見つかるまでカウント + } + } +} + + +// 親機情報が揃ったかどうかチェックして、発見時間カウントを停止する。 +static BOOL CheckParentFindTime( u32 index ) +{ + if( mbrsp->validGameInfoFlag & (0x01 << index) ) { // 親機情報が発見されたなら、カウントを停止する。 + findTime[ index ].find = TRUE; + } + return findTime[ index ].find; +} + + +// トータル時間のカウント&表示 +static void CountAndDispTotalTime( void ) +{ + total_vcount++; + time_ms = total_vcount * 17; + time_sec = time_ms / 1000; + time_ms = (time_ms % 1000) / 10; + (void)DrawDecimalSJISEx( 23, 2, CYAN, &time_sec, 4, 4, PARENT_VIEW_NUM); + (void)DrawDecimalSJISEx( 27, 2, CYAN, &time_ms, 2, 4, PARENT_VIEW_NUM); +} + + +// アイコンOBJのロード +static void SetIconOBJ( u32 index ) +{ + u16 view_no = (u16)( index & 0x03 ); + const MBIconInfo *iconp = &mbrsp->list[ index ].gameInfo.fixed.icon; + + GXS_LoadOBJPltt( iconp->palette, (u32)( MB_ICON_PALETTE_SIZE * view_no ), MB_ICON_PALETTE_SIZE ); + MI_CpuCopyFast( iconp->data, (void *)((u32)objVramBuff + 0x20 + MB_ICON_DATA_SIZE * view_no), MB_ICON_DATA_SIZE ); + G2_SetOBJAttr( (GXOamAttr*)&oamBakS[ view_no ], // OAM pointer + 8 * (PLIST_X + 3), // X position + 8 * PLIST_Y + (view_no * 32), // Y position + 0, // Priority + GX_OAM_MODE_NORMAL, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_32x32, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 1 + view_no * 16, // charactor + view_no, // palette + 0); // affine +} + +// アイコンOBJのクリア +static void ClearIconOBJ( u32 index ) +{ + u16 view_no = (u16)( index & 0x03 ); + u16 *oamp = (u16 *)&oamBakS[ view_no ]; + + *oamp++ = 192; // Y座標を画面外に。(オール0クリアではダメ) + *oamp++ = 0; + *oamp++ = 0; + *oamp = 0; +} + + +// メッセージ表示のセット +static void SetDispMessage( u16 color, const u8 *str ) +{ + msgStat.vcount = MSG_VIEW_COUNT; + msgStat.color = color; + msgStat.str = str; +} + + +// メッセージ表示 +static BOOL DispMessage(void) +{ + if( msgStat.vcount == MSG_VIEW_COUNT ) { + msgStat.handle = DrawStringSJIS( 4, 21, msgStat.color, msgStat.str ); + } + + if ( --msgStat.vcount == 0 ) { + ClearStringSJIS_handle( msgStat.handle ); + return TRUE; + } + return FALSE; +} + + +// メッセージ表示のセット(点滅表示) +static void SetBlinkMessage( u16 color, const u8 *str ) +{ + msgStat.vcount = MSG_BLINK_COUNT; + msgStat.flag = 1; + msgStat.color = color; + msgStat.str = str; +} + + +// メッセージ表示 +static void DispBlinkMessage( void ) +{ + if( ( msgStat.vcount == MSG_BLINK_COUNT ) && msgStat.flag ) { + msgStat.handle = DrawStringSJIS( 4, 21, msgStat.color, msgStat.str ); + } + + if ( --msgStat.vcount == 0 ) { + ClearStringSJIS_handle( msgStat.handle ); + msgStat.flag ^= 0x01; + msgStat.vcount = MSG_BLINK_COUNT; + } +} + + +//============================================================================= +// Nintendoロゴ表示 +//============================================================================= + +// Nintendoロゴ表示の初期化 +static void InitDispNintendoLogo( void ) +{ + int i; + u16 *palettep = (u16 *)(HW_OBJ_PLTT + 0x20 * 15 ) + 1; // パレット15のカラー1に。 + *palettep++ = 0x7fff; + *palettep = 0x1111; + + // TOP画面の全表示クリア + SetTargetScreenSJIS( TOP_SCREEN ); + ClearAllStringSJIS(); + SetTargetScreenSJIS( BOTTOM_SCREEN ); + + // 画面上に受信したゲームのNintendoロゴを表示する。 +#ifdef NINLOGO_LOAD_1D_CHAR + // 1Dマッピングでのロード&表示 + GX_SetOBJVRamModeChar( GX_OBJVRAMMODE_CHAR_1D_32K ); + SYSM_LoadNintendoLogo1D( (u16 *)GetRomHeaderAddr()->nintendo_logo, (u16 *)( HW_OBJ_VRAM + 0x40 ), 1, ninLogoBuff ); +// SYSM_LoadNintendoLogo1D( (u16 *)SYSROM9_NINLOGO_ADR, (u16 *)( HW_OBJ_VRAM + 0x40 ), 1, ninLogoBuff ); + + for ( i = 0; i < 3; i++ ) { + G2_SetOBJAttr( &oamBakM[ 10 + i ], // OAM pointer + 72 + 32 * i, // X position + 88, // Y position + 0, // Priority + GX_OAM_MODE_NORMAL, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_32x8, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 0x2 + i * 4, // charactor + 15, // palette + 0); // affine + } + { + G2_SetOBJAttr( &oamBakM[ 13 ], // OAM pointer + 72 + 32 * 3, // X position + 88, // Y position + 0, // Priority + GX_OAM_MODE_NORMAL, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_8x8, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 0x2 + 3 * 4, // charactor + 15, // palette + 0); // affine + } + for ( i = 0; i < 3; i++ ) { + G2_SetOBJAttr( &oamBakM[ 14 + i ], // OAM pointer + 72 + 32 * i, // X position + 96, // Y position + 0, // Priority + GX_OAM_MODE_NORMAL, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_32x8, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 0x0f + i * 4, // charactor + 15, // palette + 0); // affine + } + { + G2_SetOBJAttr( &oamBakM[ 17 ], // OAM pointer + 72 + 32 * 3, // X position + 96, // Y position + 0, // Priority + GX_OAM_MODE_NORMAL, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_8x8, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 0xf + 3 * 4, // charactor + 15, // palette + 0); // affine + } +#else + // 2Dマッピングでのロード&表示 + GX_SetOBJVRamModeChar( GX_OBJVRAMMODE_CHAR_2D ); + SYSM_LoadNintendoLogo2D( (u16 *)GetRomHeaderAddr()->nintendo_logo, (u16 *)( HW_OBJ_VRAM + 0x40 ), 1, ninLogoBuff ); +// SYSM_LoadNintendoLogo2D( (u16 *)SYSROM9_NINLOGO_ADR, (u16 *)( HW_OBJ_VRAM + 0x40 ), 1, ninLogoBuff ); + + for ( i = 0; i < 4; i++ ) { + G2_SetOBJAttr( &oamBakM[11 + i], // OAM pointer + 72 + 32 * i, // X position + 88, // Y position + 0, // Priority + GX_OAM_MODE_NORMAL, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_32x16, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 0x2 + i * 4, // charactor + 15, // palette + 0); // affine + } +#endif + + loop_count = 120; +} + + +// Nintendoロゴ表示 +static BOOL DispNintendoLogo( void ) +{ + if( --loop_count == 0 ) { + { + int i; + for ( i = 0; i < 4; i++ ) { + G2_SetOBJPosition( &oamBakM[ 11 + i ], 0, 192 ); + } + } + return TRUE; + } + return FALSE; +} + + +//============================================================================= +// その他サブルーチン +//============================================================================= + +// 自分のユーザー情報をNITRO設定データから読み出してセット +static void SetMyUserInfo( MBUserInfo *my ) +{ + NvNickname *nickname = NCD_GetNickname(); + + MI_CpuCopy16( nickname->str, my->name, (u32)( nickname->length * 2 ) ); + my->nameLength = nickname->length; + my->playerNo = 0; // とりあえず0にする。 + my->favoriteColor = NCD_GetFavoriteColor(); +} + + +// 現在スキャンロック中かどうかを取得する。 +static BOOL IsScanLock(void) +{ + return mbrsp->nowScanTargetFlag ? TRUE : FALSE; +} + + +//============================================================================= +// 割り込みルーチン +//============================================================================= + +// Vブランク割り込み +static void VBlankIntr_WDL(void) +{ + // OAM, BG-VRAMの更新 + DC_FlushRange (oamBakM, sizeof(oamBakM)); + DC_FlushRange (oamBakS, sizeof(oamBakS)); + DC_FlushRange (bgBakM, sizeof(bgBakM)); + DC_FlushRange (bgBakS, sizeof(bgBakS)); + DC_FlushRange (objVramBuff, sizeof(objVramBuff)); + MI_CpuCopyFast(oamBakM, (void*)HW_OAM, sizeof(oamBakM)); + MI_CpuCopyFast(oamBakS, (void*)HW_DB_OAM, sizeof(oamBakS)); + MI_CpuCopyFast(bgBakM, (void*)(HW_BG_VRAM + 0xf000), sizeof(bgBakM)); + MI_CpuCopyFast(bgBakS, (void*)(HW_DB_BG_VRAM + 0xf000), sizeof(bgBakS)); + MI_CpuCopyFast(objVramBuff, (void*)HW_DB_OBJ_VRAM, sizeof(objVramBuff)); + //---- 割り込みチェックフラグ + OS_SetIrqCheckFlag(OS_IE_V_BLANK); +} + + +//============================================================================= +// プログラムシーケンスキュー処理 +//============================================================================= + +// キュー初期化 +static void InitPrgNextSeqQue( void ) +{ + MI_CpuClear16( &nextSeq, sizeof(nextSeq) ); +} + + +// 次のPrgSeqをキューにセットする。 +static BOOL SetPrgNextSeqQue( PrgSeq seq ) +{ + BOOL preIRQ = OS_DisableIrq(); + BOOL retval = FALSE; + + if( nextSeq.num != PRG_NEXT_SEQ_QUE_NUM ) { + nextSeq.seq[ nextSeq.bottom ] =seq; + nextSeq.num++; + nextSeq.bottom++; + if( nextSeq.bottom == PRG_NEXT_SEQ_QUE_NUM ) { + nextSeq.bottom = 0; + } + retval = TRUE; + } + (void)OS_RestoreIrq( preIRQ ); + return retval; +} + + +// 次のPrgSeqをキューから取り出す +static BOOL GetPrgNextSeqQue( PrgSeq *seqp ) +{ + BOOL preIRQ = OS_DisableIrq(); + BOOL retval = FALSE; + + if( ( !nextSeq.lock ) && ( nextSeq.num != 0 ) ) { // キューがロックされておらず、かつ次Seqが存在するなら、キューから取り出し。 + *seqp = nextSeq.seq[ nextSeq.top ]; + nextSeq.num--; + nextSeq.top++; + if( nextSeq.top == PRG_NEXT_SEQ_QUE_NUM ) { + nextSeq.top = 0; + } + retval = TRUE; + } + (void)OS_RestoreIrq( preIRQ ); + return retval; +} + + +// キューをロックする。(ロック中はGetPrgNextSeqQueで次Seqを取り出せなくなります。) +static void LockPrgNextSeqQue(void) +{ + nextSeq.lock = TRUE; +} + + +// キューのロック解除。 +static void UnlockPrgNextSeqQue(void) +{ + nextSeq.lock = FALSE; +} + +// キューが空か? +static BOOL IsEmptyPrgNextSeqQue(void) +{ + return nextSeq.num ? FALSE : TRUE; +} + + + +static const u32 searchCode[] = { + 0xe59f1028, + 0xe59f2028, + 0xe1d200b0, + 0xe2100001, + 0x1afffffc, + 0xe1d100b0, + 0xe3500006, + 0x0afffff9, + 0xe1d100b0, + 0xe3500005, + 0x0afffff6, + 0xe12fff1e, + 0x04808214, + 0x0480819c, +}; + + +void SearchPatchAddress( void ) +{ + MBDownloadFileInfo *dlfinfo = (MBDownloadFileInfo *)MB_DOWNLOAD_FILEINFO_ADDRESS; + BOOL find = FALSE; + u32 *tgtp = (u32 *)MB_ARM7_STATIC_RECV_BUFFER; + u32 size = dlfinfo->seg[ 2 ].size >> 2; + + while( size-- ) { + if( *tgtp++ == searchCode[0] ) { + u32 *srcp = (u32 *)&searchCode[ 1 ]; + u32 *checkp = tgtp ; + int i = sizeof( searchCode ) / sizeof(u32) - 1; + while( i-- ) { + if( *srcp++ != *checkp++ ) break; + } + if( i < 0 ) { + u32 addr = (u32)tgtp - 0x04 + 0x18; + OS_TPrintf("Found! -> 0x%08x\n", addr ); + find = TRUE; + } + } + } + if( !find ) { + OS_TPrintf("Not found.\n"); + } +} + diff --git a/build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.h b/build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.h new file mode 100644 index 00000000..1c9a8f83 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_DownloadPlay/DS_DownloadPlay.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: DS_DownloadPlay.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __DS_DOWNLOAD_PLAY_H__ +#define __DS_DOWNLOAD_PLAY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include + +// define data---------------------------------------------------------- + +int DS_DownloadPlayMain( void ); + + +#ifdef __cplusplus +} +#endif + +#endif // __DS_DOWNLOAD_PLAY_H__ diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/AgbLcdSel.c b/build/systemMenu_RED/ARM9/src/DS_Setting/AgbLcdSel.c new file mode 100644 index 00000000..c0c16974 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/AgbLcdSel.c @@ -0,0 +1,131 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: AgbLcdSel.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "misc.h" +#include "DS_Setting.h" + +// define data------------------------------------------ +#define CANCEL_BUTTON_LT_X 2 +#define CANCEL_BUTTON_LT_Y 21 +#define CANCEL_BUTTON_RB_X (CANCEL_BUTTON_LT_X+8) +#define CANCEL_BUTTON_RB_Y (CANCEL_BUTTON_LT_Y+2) + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +void SEQ_AgbLcdSelect_init(void); +int SEQ_AgbLcdSelect(void); + +// global variable ------------------------------------- + +// static variable ------------------------------------- +static u16 agbLcd = 0; + +// const data ----------------------------------------- +static const u8 *const str_lcd[] ATTRIBUTE_ALIGN(2) = { + (const u8 *)"TOP LCD", + (const u8 *)"BOTTOM LCD", +}; + +static const MenuComponent agbLcdSel = { + 2, + 10, + 8, + 0, + 4, + 8, + WHITE, + HIGHLIGHT_Y, + (const u8 **)&str_lcd, +}; + + +//====================================================== +// function's description +//====================================================== + +// AGBモード設定の初期化 +void SEQ_AgbLcdSelect_init(void) +{ + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + MI_CpuClearFast(bgBakS,sizeof(bgBakS)); + + ClearAllStringSJIS(); + + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"AGB-MODE LCD SELECT"); + (void)DrawStringSJIS( CANCEL_BUTTON_LT_X, CANCEL_BUTTON_LT_Y,HIGHLIGHT_C, (const u8 *)" CANCEL "); + + if(GetSYSMWork()->ncd_invalid) { + agbLcd = 0; + }else { + agbLcd = GetNCDWork()->option.agbLcd; + if(agbLcd > 1) agbLcd = 1; + } + + DrawMenu((u16)agbLcd, &agbLcdSel); + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + + GXS_SetVisiblePlane(GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1); +} + + +// AGBモード設定 +int SEQ_AgbLcdSelect(void) +{ + BOOL tp_select; + BOOL tp_cancel = FALSE; + + ReadTpData(); // タッチパネル入力の取得 + + //-------------------------------------- + // キー入力処理 + //-------------------------------------- + if(pad.trg & (PAD_KEY_DOWN | PAD_KEY_UP)){ // カーソルの移動 + agbLcd ^= 0x01; + } + tp_select = SelectMenuByTp((u16 *)&agbLcd, &agbLcdSel); + DrawMenu((u16)agbLcd, &agbLcdSel); + + // [CANCEL]ボタン押下チェック + if(tpd.disp.touch) { + tp_cancel = InRangeTp(CANCEL_BUTTON_LT_X*8, CANCEL_BUTTON_LT_Y*8-4, + CANCEL_BUTTON_RB_X*8, CANCEL_BUTTON_RB_Y*8-4, &tpd.disp); + } + + if((pad.trg & PAD_BUTTON_A) || (tp_select)) { // メニュー項目への分岐 + GetSYSMWork()->ncd_invalid = 0; + GetNCDWork()->option.agbLcd = agbLcd; + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData(GetNCDWork()); + SEQ_MainMenu_init(); + return 0; + }else if((pad.trg & PAD_BUTTON_B) || (tp_cancel)) { + SEQ_MainMenu_init(); + return 0; + } + + ReadTpData(); + + return 0; +} + + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.c b/build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.c new file mode 100644 index 00000000..ef950e1a --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.c @@ -0,0 +1,128 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: DS_Setting.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "main.h" +#include "DS_Setting.h" + +// define data----------------------------------------------------------------- + +// function's prototype-------------------------------------------------------- +int DS_SettingMain(); +void VBlankIntr_bm(void); + +// extern data----------------------------------------------------------------- + +// global variable------------------------------------------------------------- + +// static variable------------------------------------------------------------- + +// const data------------------------------------------------------------------ + + +// ============================================================================ +// function's description +// ============================================================================ + +int DS_SettingMain() +{ + (void)OS_DisableIrq(); + +// GXS_DispOff(); // LCDC OFF + +// reg_GX_POWCNT = 0x7fff; // 表示画面を下LCDに切り替え + + OS_Printf("ARM9 bootMenu start.\n"); + + //---- VRAM クリア +// GX_SetBankForLCDC(GX_VRAM_LCDC_ALL); // VRAMクリアのために一時的にLCDCにVRAMを全て割り当てる。 +// MI_CpuClearFast((void*)HW_LCDC_VRAM, HW_LCDC_VRAM_SIZE); +// (void)GX_DisableBankForLCDC(); + + //---- OAMとパレットクリア +// MI_CpuFillFast( (void*)HW_DB_OAM, 192, HW_DB_OAM_SIZE ); +// MI_CpuClearFast((void*)HW_DB_PLTT, HW_PLTT_SIZE); + + //---- VRAMの割り当て +// GX_SetBankForBG(GX_VRAM_BG_64_E); // VRAM割り当て +// GX_SetBankForOBJ(GX_VRAM_OBJ_32_FG); + + //---- グラフィックス表示モードにする +// GX_SetGraphicsMode(GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D); + + //---- BG1の設定 +// G2_SetBG1Control(GX_BG_SCRSIZE_TEXT_256x256, GX_BG_COLORMODE_16, GX_BG_SCRBASE_0xf000, +// GX_BG_CHARBASE_0x00000, GX_BG_EXTPLTT_01 ); +// G2_SetBG1Priority(3); // BGコントロール セット + + //---- OBJ,BG1の表示のみON + GXS_SetVisiblePlane(GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1); + + //---- OBJは2Dマップモードで使用 + GXS_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_2D); + + //---- データロード +// MI_CpuCopyFast(myChar, (void *)HW_BG_VRAM, sizeof(myChar)); // BGキャラクタ セット +// MI_CpuCopyFast(myChar, (void *)HW_OBJ_VRAM, sizeof(myChar)); // OBJキャラクタ セット +// MI_CpuCopyFast(myPlttData, (void *)HW_BG_PLTT, sizeof(myPlttData));// BGパレット セット +// MI_CpuCopyFast(myPlttData, (void *)HW_OBJ_PLTT, sizeof(myPlttData));// OBJパレット セット + + //---- Vブランク割込切り替え + (void)OS_SetIrqFunction(OS_IE_V_BLANK, VBlankIntr_bm); + (void)OS_EnableIrq(); + + //---- 表示開始 + OS_WaitIrq(1, OS_IE_V_BLANK); +// SVC_WaitVBlankIntr(); +// GXS_DispOn(); + + //---- メインループ前処理 + SEQ_MainMenu_init(); + + //================ メインループ + while(1) + { + OS_WaitIrq(1, OS_IE_V_BLANK); +// SVC_WaitVBlankIntr(); // Vブランク割込終了待ち + ReadKeyPad(); + mf_KEYPAD_rapid(); + + (void)nowProcess(); // メインプロセス実行 + + if (PAD_DetectFold() == TRUE) { // スリープモードへの遷移 + SYSM_GoSleepMode(); + } + + OS_PrintServer(); // ARM7からのプリントデバッグを処理する + } +} + +//============================================================================= +// 割り込みルーチン +//============================================================================= + +// Vブランク割り込み +void VBlankIntr_bm(void) +{ + //---- OAM、BG-VRAMの更新 + DC_FlushRange(oamBakS, sizeof(oamBakS)); + MI_CpuCopyFast(oamBakS,(void*)HW_DB_OAM, sizeof(oamBakS)); + DC_FlushRange(bgBakS, sizeof(bgBakS)); + MI_CpuCopyFast(bgBakS, (void*)(HW_DB_BG_VRAM+0xf000), sizeof(bgBakS)); + //---- 割り込みチェックフラグ + OS_SetIrqCheckFlag(OS_IE_V_BLANK); +} diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.h b/build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.h new file mode 100644 index 00000000..7c249495 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/DS_Setting.h @@ -0,0 +1,90 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: DS_Setting/DS_Setting.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __DS_SETTING_H__ +#define __DS_SETTING_H__ + +#ifdef __cplusplus +extern "C" { +#endif + + +#include +#include "font.h" +#include "unicode.h" + +// define data---------------------------------------------------------- +#define TP_CSR_TOUCH_COUNT 2 // TPカーソルのチャタリング吸収のためのカウント値 +#define TP_CSR_DETACH_COUNT 2 // TPカーソルを「選択」と判定するTPデタッチからのカウント値 + +#define HANDLE_MENU 48 +#define HANDLE_RTC_VIEW 240 +#define HANDLE_OK_BUTTON 255 +#define HANDLE_CANCEL_BUTTON 256 + +// 数値入力インターフェース用ワーク(void InputDecimal()で使用) +typedef struct InputNumParam { + u16 pos_x; // 入力値の表示X位置 + u16 pos_y; // 〃     Y位置 + int up_count; + int down_count; + int keta_max; // 最大桁 + int value_min; // 入力値の最小 + int value_max; // 入力値の最大 + int y_offset; // タッチパネル入力の基準位置からのYオフセット +}InputNumParam; + +// global variable------------------------------------------------------ +extern u16 csrMenu; +extern BOOL initialSet; + +// function------------------------------------------------------------- +extern int DS_SettingMain( void ); + +extern void SEQ_MainMenu_init(void); +extern int SEQ_MainMenu(void); +extern void SEQ_Setting_init(void); +extern int SEQ_Setting(void); +extern void SEQ_OwnerInfo_init(void); +extern int SEQ_OwnerInfo(void); +extern void SEQ_RtcSet_init(void); +extern int SEQ_RtcSet(void); +extern void SEQ_LangSelect_init(void); +extern int SEQ_LangSelect(void); +extern void SEQ_TP_Calibration_init(void); +extern int SEQ_TP_Calibration(void); +extern void SEQ_AgbLcdSelect_init(void); +extern int SEQ_AgbLcdSelect(void); +extern void SEQ_AutoBootSelect_init(void); +extern int SEQ_AutoBootSelect(void); + +extern void DrawMenu(u16 nowCsr, const MenuComponent *menu); +extern BOOL SelectMenuByTp(u16 *nowCsr, const MenuComponent *menu); +//extern BOOL InRangeTp(u16 lt_x, u16 lt_y, u16 rb_x, u16 rb_y, TPData *tgt); +extern BOOL InRangeTp(int lt_x, int lt_y, int rb_x, int rb_y, TPData *tgt); + +extern void DrawOKCancelButton(void); +extern void CheckOKCancelButton(BOOL *tp_ok, BOOL *tp_cancel); +extern void InputDecimal(int *tgtp, InputNumParam *inpp); + +extern void ClearRTC( void ); + +#ifdef __cplusplus +} +#endif + +#endif // __DS_SETTING_H__ diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/autoBoot.c b/build/systemMenu_RED/ARM9/src/DS_Setting/autoBoot.c new file mode 100644 index 00000000..671bdd3b --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/autoBoot.c @@ -0,0 +1,131 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: autoBoot.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "misc.h" +#include "DS_Setting.h" + +// define data------------------------------------------ +#define CANCEL_BUTTON_LT_X 2 +#define CANCEL_BUTTON_LT_Y 21 +#define CANCEL_BUTTON_RB_X (CANCEL_BUTTON_LT_X+8) +#define CANCEL_BUTTON_RB_Y (CANCEL_BUTTON_LT_Y+2) + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +void SEQ_AutoBootSelect_init(void); +int SEQ_AutoBootSelect(void); + +// global variable ------------------------------------- + +// static variable ------------------------------------- +static u16 autoBootFlag = 0; + +// const data ----------------------------------------- +static const u8 *const str_lcd[] ATTRIBUTE_ALIGN(2) = { + (const u8 *)" OFF ", + (const u8 *)" ON ", +}; + +static const MenuComponent autoBootSel = { + 2, + 12, + 8, + 0, + 4, + 8, + WHITE, + HIGHLIGHT_Y, + (const u8 **)&str_lcd, +}; + + +//====================================================== +// function's description +//====================================================== + +// AGBモード設定の初期化 +void SEQ_AutoBootSelect_init(void) +{ + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + MI_CpuClearFast(bgBakS,sizeof(bgBakS)); + + ClearAllStringSJIS(); + + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"AUTO BOOT SELECT"); + (void)DrawStringSJIS( CANCEL_BUTTON_LT_X, CANCEL_BUTTON_LT_Y,HIGHLIGHT_C, (const u8 *)" CANCEL "); + + if(GetSYSMWork()->ncd_invalid) { + autoBootFlag = 0; + }else { + autoBootFlag = GetNCDWork()->option.autoBootFlag; + if(autoBootFlag > 1) autoBootFlag = 1; + } + + DrawMenu((u16)autoBootFlag, &autoBootSel); + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + + GXS_SetVisiblePlane(GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1); +} + + +// AGBモード設定 +int SEQ_AutoBootSelect(void) +{ + BOOL tp_select; + BOOL tp_cancel = FALSE; + + ReadTpData(); // タッチパネル入力の取得 + + //-------------------------------------- + // キー入力処理 + //-------------------------------------- + if(pad.trg & (PAD_KEY_DOWN | PAD_KEY_UP)){ // カーソルの移動 + autoBootFlag ^= 0x01; + } + tp_select = SelectMenuByTp((u16 *)&autoBootFlag, &autoBootSel); + DrawMenu((u16)autoBootFlag, &autoBootSel); + + // [CANCEL]ボタン押下チェック + if(tpd.disp.touch) { + tp_cancel = InRangeTp(CANCEL_BUTTON_LT_X*8, CANCEL_BUTTON_LT_Y*8-4, + CANCEL_BUTTON_RB_X*8, CANCEL_BUTTON_RB_Y*8-4, &tpd.disp); + } + + if((pad.trg & PAD_BUTTON_A) || (tp_select)) { // メニュー項目への分岐 + GetSYSMWork()->ncd_invalid = 0; + GetNCDWork()->option.autoBootFlag = autoBootFlag; + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData(GetNCDWork()); + SEQ_MainMenu_init(); + return 0; + }else if((pad.trg & PAD_BUTTON_B) || (tp_cancel)) { + SEQ_MainMenu_init(); + return 0; + } + + ReadTpData(); + + return 0; +} + + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/font.c b/build/systemMenu_RED/ARM9/src/DS_Setting/font.c new file mode 100644 index 00000000..748cf7a7 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/font.c @@ -0,0 +1,1030 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: font.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "font.h" +#include "main.h" + +// define data---------------------------------- +#define SEARCH_ENTRY_MAX_NUM 128 // 処理が重くなるのを防ぐための、エントリのサーチ回数上限 +#define NITRO_CHAR_SIZE 0x20 // NITRO標準キャラクタサイズ(4bitカラー) +#define CHAR_CODE_OFFSET (SJIS_CHAR_VRAM_OFFSET / NITRO_CHAR_SIZE) // キャラナンバーをスクリーンに転送する際のオフセット(BG_CHAR_VRAM+0x4000から始めているので、オフセットは0x200) +#define DRAW_CHAR_NUM_LIMIT (SJIS_CHAR_VRAM_SIZE / NITRO_CHAR_SIZE) // 1つの文字列で表示できるキャラクタ数の限界 + +#define HANDLE_INDEX 0x40000000 + +// フォント構成データ +typedef struct FontComponent { + u16 need_tate_dot; // 文字を表示するのに必要なキャラ単位のドット数 + u16 tate_dot; // 文字キャラの縦ドット数 + u16 yoko_dot; // 文字キャラの横ドット数 + u16 org_char_size; // 文字キャラのbyteサイズ + u32 org_row_size; // 文字キャラ + u32 start_adr; // キャラクタバイナリのスタートアドレス + u32 end_adr; // キャラクタバイナリのエンドアドレス +}FontComponent; + + +// VRAMキャラデータのメモリブロック動的確保リスト +typedef struct CharAllocListTag CharAllocList; +struct CharAllocListTag { + CharAllocList *next; // 次のメモリブロック確保構造体へのポインタ + u16 memTop; // キャラ割り当てテーブルcharAllocTblの占有ブロックの先頭ポイント + u16 memNum; // 確保したメモリブロックの数 +}CharAllocListTag; + + +// SJIS文字列表示のためのVRAMエントリデータ +typedef struct StrEntry { + const FontComponent *font; // 表示するフォントの構成要素 + u32 dataAddr; // データ元のアドレス(IDとして使用) + u32 *charMemp; // 動的に確保したVRAMメモリブロックへのポインタ + u16 charNum; // トータルのキャラ数 + u16 drawPos; // 表示位置(BGスクリーンバッファの先頭からの2byteオフセット) +}StrEntry; + + +// フォントの文字間隔詰め展開用データ +typedef struct FontPropotion { + u16 *leftp; // 現在の左側フォントデータへのポインタ + u16 *rightp; // 現在の右側フォントデータへのポインタ + u16 h_offset; // 16x16ドット単位のキャラクタデータ内の現在の横オフセット + u8 pad[2]; + u32 buff16x16[2][16/2]; +}FontPropotion; + +// インクリメント/インクリメントなしフラグ(SetScrDataで使用) +typedef enum IncFlag { + NO_INC, // インクリメントなし + INC_1 // 1インクリメント +}IncFlag; + +// extern data---------------------------- +extern void _binary_f12han_dat(void); +extern void _binary_f12han_dat_end(void); + + +// function's prototype declaration------------- +static void SetScrData(u16 code_top, StrEntry *sEntryp, IncFlag inc_flag); +static u16 MeasureStringCharWidth(const u8 *str); +static void SpreadStringCloser(u8 *str, StrEntry *sEntryp, u16 v_offset); +static void SetFirstFont(u8 **strpp, u16 v_offset, FontPropotion *fontProp); +static u8 * CloseFontChar(u8 **strpp, u16 v_offset, FontPropotion *fontProp); +static u32 CalcCharCodeAddress(u8 **strpp, const FontComponent **font); +static void SpreadFontZen(u16 bit0_color, u16 bit1_color, u8 *fromAdr, u32 *toAdr); +static void InitStrEntryTable( StrEntry **sEntrypp ); +static StrEntry *GetStrEntry( u16 handle ); +static StrEntry **GetStrEntryAddress( u16 handle ); +static int InsertStrEntry(u16 *handle, u16 charNum); +static int InsertStrEntry2(u16 handle, u16 charNum); +static u16 DeleteStrEntry( u16 handle); +static BOOL GetEmptyStrEntry(u32 dataAddr, u16 *handlep); +static u16 SearchStrEntry(u32 dataAddr); +static u8 * HexToDecimalString(const void *hexp, u8 *strp, u16 figure, u16 size); +static u8 * HexToString(const void *hexp, u8 *strp, u16 figure); +static void InitAllocSystemSJIS( TargetScreen target ); +static void *AllocMemoryFromVram( u32 size ); +static void FreeMemoryToVram( void *p ); + +static u16 DrawStringSJIS_Core( int x, int y, u16 color, const void *strp, u32 handleIndex); +static u32 CalcHandleIndex(u32 dataAddr, u32 index); + +// global variables----------------------------- + + +// static variables----------------------------- +static int font_init = 0; +static TargetScreen targetScreen = BOTTOM_SCREEN; +static const FontComponent *nowFontHan; +static StrEntry *entryTblS[ STR_ENTRY_MAX_NUM ]; +static StrEntry *entryTblM[ STR_ENTRY_MAX_NUM ]; +static StrEntry **entryTblp; +static u16 *bgBakp; + +// const data----------------------------------- +const u16 tbl_ASCII_to_SJIS[0x100]; +const FontComponent fontTypeTableHan[] = { + { 16, 12, 6, 12, 14*0xbc, (u32)&_binary_f12han_dat, (u32)&_binary_f12han_dat_end}, +}; + + +// functions description------------------------ + +//---------------------------------------------- +// API関数 +//---------------------------------------------- + +// フォントAPIの初期化 +void InitFont( TargetScreen target) +{ + if( font_init & (0x01 << target ) ) { // ターゲットが初期すみならリターン + return; + } + + InitAllocSystemSJIS( target ); // ターゲットのVRAMアリーナ初期化 + + if( target == TOP_SCREEN ) { // ターゲットのエントリを初期化 + InitStrEntryTable( &entryTblM[0] ); + }else { + InitStrEntryTable( &entryTblS[0] ); + } + + if( font_init == 0 ) { // まだ何も初期化されていないなら、スクリーンを初期設定に。 + SetTargetScreenSJIS( target ); + } + + SetFont( (FontType)0 ); + font_init |= 0x01 << target; +} + + +// 表示フォントの切り替え +void SetFont(FontType font) +{ + if(font >= FONT_TYPE_MAX) { + font = (FontType)0; + } + nowFontHan = &fontTypeTableHan[font]; +} + + +// 表示ターゲットスクリーンの切り替え +void SetTargetScreenSJIS( TargetScreen target ) +{ + targetScreen = target; + if( target == TOP_SCREEN ) { + entryTblp = &entryTblM[0]; + bgBakp = bgBakM; + }else { + entryTblp = &entryTblS[0]; + bgBakp = bgBakS; + } +} + + +// 指定されたSJIS文字列を表示する。(ハンドル指定なしでハンドル算出加算値付き) +static u16 DrawStringSJIS_Core( int x, int y, u16 color, const void *strp, u32 handleIndex) +{ + StrEntry *sEntryp; + int newEntry; + u16 handle; + u16 charNum; + u16 code; + u16 v_offset = 1; // ※v_offsetは引数にすることもできる。 + + InitFont( targetScreen ); + + // 空文字列チェック + if(*(u8 *)strp == 0x00) { + return 0; + } + + // 文字列表示に必要なキャラクタ数の測定 + charNum = MeasureStringCharWidth((const u8 *)strp); + if(charNum > DRAW_CHAR_NUM_LIMIT) { // 必要キャラクタ数が512以内ならメモリ確保。 + OS_Printf("SJIS-draw: str length max over.\n"); + return DSJIS_ERR_STR_LENGTH_TOO_LONG; + } + + // ハンドル取得 + if( !GetEmptyStrEntry( handleIndex, &handle ) ) { + OS_Printf("SJIS-draw: error StrEntry get failed.\n"); + return DSJIS_ERR_ENTRY_GET_FAILED; + } + + // 文字列エントリの登録 + newEntry = InsertStrEntry2( handle, charNum ); + if(newEntry < 0) { + OS_Printf("SJIS-draw: error StrEntry alloc failed.\n"); + return DSJIS_ERR_ENTRY_ALLOC_FAILED; + } + sEntryp = GetStrEntry(handle); // エントリへのポインタを格納 + sEntryp->dataAddr = handleIndex; + + // VRAMキャラメモリの動的確保 + if(newEntry > 0) { + sEntryp->charMemp = AllocMemoryFromVram( (u32)( charNum * NITRO_CHAR_SIZE * 2 ) ); + // ※縦も2キャラ分必要なので、NITRO_CHAR_SIZE*2 +// OS_Printf("alloc charMemp = %x\n",sEntryp->charMemp); + if( sEntryp->charMemp == NULL ) { // メモリ確保に失敗したら、エントリのメモリを解放してリターン + OS_Printf("VRAM char memory alloc failed.\n"); + OS_Free(sEntryp); + return DSJIS_ERR_CHAR_ALLOC_FAILED; + } + } + + // 文字列エントリの登録 + sEntryp->font = nowFontHan; // 現在のフォントタイプを格納 + sEntryp->drawPos = (u16)(x + y * 0x20); // 表示場所を格納。 + sEntryp->charNum = charNum; + + // 縦配置位置指定v_offsetの矯正 + if(v_offset) { + if(((nowFontHan->tate_dot & 0x07)== 0)) { // 縦8dot or 16dotの場合はv_offsetは0 + v_offset = 0; + }else { + if( (16 - nowFontHan->tate_dot) < v_offset ) { // それ以外の時は、縦16dotに収まる範囲に矯正 + v_offset = (u16)(16 - nowFontHan->tate_dot); + } + } + } + // 対象文字列のフォントデータをビット展開&キャラデータ詰めをおこなって、確保したVRAMキャラメモリに転送 + SpreadStringCloser((u8 *)strp, sEntryp, v_offset); + + // スクリーンデータに今回の文字列のキャラナンバーを書き込み + code = (u16)( (((u32)sEntryp->charMemp - (u32)G2_GetBG1CharPtr()) / NITRO_CHAR_SIZE) | color ); + SetScrData(code, sEntryp, INC_1); + + return handle; +} + +// ハンドルインデックスの算出 +static u32 CalcHandleIndex(u32 dataAddr, u32 index) +{ + if(index) { + index += (u32)( HANDLE_INDEX + dataAddr ); // インデックスを加算した場合は、他のデータのアドレスと被らないよう、NITROメモリマップ外になるようオフセットを加算。 + }else { + index = dataAddr; + } + return index; +} + + +// 指定されたSJIS文字列を表示する。(ハンドル指定なし) +u16 DrawStringSJIS( int x, int y, u16 color, const void *strp) +{ + return DrawStringSJIS_Core( x, y, color, strp, (u32)strp ); // index = strp でCoreをコール +} + + +// 指定された値を16進数で表示する。(ハンドル指定なし版) +u16 DrawHexSJIS( int x, int y, u16 color, const void *hexp, u16 figure) +{ + u8 buff[16]; + u8 *strp = HexToString(hexp, buff, figure); + return DrawStringSJIS_Core(x, y, color, strp, (u32)hexp ); +} + + +// 指定された値を10進数で表示する。(ハンドル指定なし版) +u16 DrawDecimalSJIS( int x, int y, u16 color, const void *hexp, u16 figure, u16 size) +{ + u8 buff[16]; + u8 *strp = HexToDecimalString(hexp, buff, figure, size); + return DrawStringSJIS_Core(x, y, color, strp, (u32)hexp ); +} + + +// 指定されたSJIS文字列を表示する。(ハンドル指定なしでハンドル算出加算値付き) +u16 DrawStringSJISEx( int x, int y, u16 color, const void *strp, u32 index) +{ + index = CalcHandleIndex( (u32)strp, index); + return DrawStringSJIS_Core( x, y, color, strp, index ); // index を加算してCoreをコール +} + + +// 指定された値を16進数で表示する。(ハンドル指定なし版) +u16 DrawHexSJISEx( int x, int y, u16 color, const void *hexp, u16 figure, u32 index) +{ + u8 buff[16]; + u8 *strp = HexToString(hexp, buff, figure); + index = CalcHandleIndex( (u32)hexp, index); + return DrawStringSJIS_Core( x, y, color, strp, index ); +} + + +// 指定された値を10進数で表示する。(ハンドル指定なし版) +u16 DrawDecimalSJISEx( int x, int y, u16 color, const void *hexp, u16 figure, u16 size, u32 index) +{ + u8 buff[16]; + u8 *strp = HexToDecimalString(hexp, buff, figure, size); + index = CalcHandleIndex( (u32)hexp, index); + return DrawStringSJIS_Core(x, y, color, strp, index); +} + + +// 指定コードから始まるスクリーンデータのセット +static void SetScrData(u16 code_top, StrEntry *sEntryp, IncFlag inc_flag) +{ + u16 i; + u16 lastPos; + u16 pos_l; + u16 *buffp_l; + u16 *buffp_h; + + lastPos = 0x800 >> 1; // バッファ最終位置 == BGスクリーンサイズ(0x800) + pos_l = (u16)(sEntryp->drawPos + 0x0020); // 下8dotキャラクタ表示位置 + buffp_h = bgBakp + sEntryp->drawPos; + buffp_l = buffp_h + 0x0020; + + for(i = 0; i < sEntryp->charNum; i++) { + *buffp_h++ = code_top; + code_top += inc_flag; + if(nowFontHan->need_tate_dot == 16) { // 必要縦ドットが16の場合(8ドット文字以外全部)、もう1キャラセット + *buffp_l++ = code_top; + } + code_top += inc_flag; + pos_l++; + if(pos_l == lastPos) { + break; + } + } +} + + +// 指定されたハンドルのSJIS文字列をクリアする。 +void ClearStringSJIS_handle(u16 handle) +{ + StrEntry *sEntryp; + + InitFont( targetScreen ); + + sEntryp = GetStrEntry(handle); + if(sEntryp == NULL) { + return; + } + + // スクリーンデータのクリア + SetScrData(0x0000, sEntryp, NO_INC); + + // キャラクタデータのクリア +// MI_CpuClearFast(sEntryp->charMemp, sEntryp->charNum * NITRO_CHAR_SIZE * 2); + // 動的に確保したVRAMキャラデータのクリア + FreeMemoryToVram( sEntryp->charMemp ); // このエントリが確保していたキャラクタメモリの解放。 + (void)DeleteStrEntry(handle); +} + + +// 指定されたデータアドレスで表示しているSJIS文字列をクリアする。 +void ClearStringSJIS(void *datap) +{ + u16 handle = SearchStrEntry( (u32)datap ); + + if( handle > STR_ENTRY_MAX_NUM ) { + return; + } + ClearStringSJIS_handle(handle); +} + + +// 指定されたデータアドレスで表示しているSJIS文字列をクリアする。Ex系で描画したものを消す場合。 +void ClearStringSJISEx(void *datap, u32 handleIndex) +{ + u16 handle; + + handleIndex = CalcHandleIndex( (u32)datap, handleIndex); + + handle = SearchStrEntry( (u32)handleIndex ); + + if( handle > STR_ENTRY_MAX_NUM ) { + return; + } + ClearStringSJIS_handle(handle); +} + + + +// 現在登録されている全てのSJIS文字列をクリアする(動的メモリも全て解放) +void ClearAllStringSJIS(void) +{ + u16 handle; + + InitFont( targetScreen ); + + for(handle = 0; handle < STR_ENTRY_MAX_NUM; handle++) { + if( GetStrEntry( handle ) != NULL) { + ClearStringSJIS_handle(handle); + } + } +} + + +// 指定されたハンドルで表示されている文字列のカラーを変更。 +u16 ChangeColorSJIS(u16 handle, u16 new_color) +{ + int i; + u16 *buffp_l; + u16 *buffp_h; + StrEntry *sEntryp = GetStrEntry( handle ); // エントリへのポインタを格納 + + if((handle > STR_ENTRY_MAX_NUM) || (sEntryp == NULL)) { + return 0; + } + + buffp_h = bgBakp + sEntryp->drawPos; + buffp_l = buffp_h + 0x20; + for(i = 0; i < sEntryp->charNum; i++) { + *buffp_h = (u16)((*buffp_h & 0x0fff) | new_color); + *buffp_l = (u16)((*buffp_l & 0x0fff) | new_color); + buffp_h++; + buffp_l++; + } + return 1; +} + +//---------------------------------------------- +// 文字列エントリテーブルの処理 +//---------------------------------------------- + +// エントリテーブルの初期化 +static void InitStrEntryTable( StrEntry **sEntrypp ) +{ + u16 i; + for(i = 0; i < STR_ENTRY_MAX_NUM; i++) { + *sEntrypp++ = NULL; + } +} + + +// 指定されたハンドルのStrEntryポインタを返す +static StrEntry * GetStrEntry( u16 handle ) +{ + if ( handle >= STR_ENTRY_MAX_NUM ) { + return NULL; + }else { +// return entryTblS[ handle ]; + return entryTblp[ handle ]; + } +} + + +// 指定されたハンドルのStrEntryポインタへのポインタを返す +static StrEntry ** GetStrEntryAddress( u16 handle ) +{ + if ( handle >= STR_ENTRY_MAX_NUM ) { + return NULL; + }else { +// return &entryTblS[ handle ]; + return &entryTblp[ handle ]; + } +} + + +// StrEntryの登録 +static int InsertStrEntry(u16 *handle, u16 charNum) +{ + StrEntry **sEntrypp = GetStrEntryAddress( *handle ); + + if(*handle >= STR_ENTRY_MAX_NUM) { + return -1; + }else if(*handle > 0) { + if( *sEntrypp != NULL) { // 指定ハンドルに既にエントリがある場合は、確保メモリ量を新規メモリ量と比べて、 + if( charNum > (*sEntrypp)->charNum ) { // 再確保が必要な場合は、メモリ解放→再確保を行う。 +// OS_Printf("SJIS: same entry free to charMemory.\n"); +// OS_Printf("free charMemp = %x\n",(*sEntrypp)->charMemp); + SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア + FreeMemoryToVram( (*sEntrypp)->charMemp ); // このエントリが確保していたキャラクタメモリの解放。 + return 1; + }else { + if( charNum < (*sEntrypp)->charNum ) { + SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア + } + return 0; // このエントリでは、キャラクタメモリを継続して使用 + } + } + } + + // *handle == 0 // 指定ハンドルが0の時は新しいハンドルを確保 + *handle = 0; + sEntrypp = GetStrEntryAddress( *handle ); + + for( ; *handle < STR_ENTRY_MAX_NUM; (*handle)++ ) { + if( *sEntrypp++ == NULL) { // NULLエントリを探す + break; + } + } + if(*handle == STR_ENTRY_MAX_NUM) { + return -1; // NULLエントリが見つからなかったら、エラー終了。 + } + + // StrEntryのメモリ確保 + *sEntrypp = (StrEntry *)OS_Alloc( sizeof(StrEntry) ); + if( *sEntrypp == NULL) { + OS_Printf("StrEntry allocate failed.\n"); + return -1; + }else { + return 1; + } +} + + +// エントリ挿入処理2 +static int InsertStrEntry2(u16 handle, u16 charNum) +{ + StrEntry **sEntrypp = GetStrEntryAddress( handle ); + + if( *sEntrypp != NULL) { // 指定ハンドルに既にエントリがある場合は、確保メモリ量を新規メモリ量と比べて、 + if( charNum > (*sEntrypp)->charNum ) { // 再確保が必要な場合は、メモリ解放→再確保を行う。 +// OS_Printf("SJIS: same entry free to charMemory.\n"); +// OS_Printf("free charMemp = %x\n",(*sEntrypp)->charMemp); + SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア + FreeMemoryToVram( (*sEntrypp)->charMemp ); // このエントリが確保していたキャラクタメモリの解放。 + return 1; + }else { + if( charNum < (*sEntrypp)->charNum ) { + SetScrData( 0x0000, *sEntrypp, NO_INC ); // スクリーンデータのクリア + } + return 0; // このエントリでは、キャラクタメモリを継続して使用 + } + } + + // StrEntryのメモリを新規確保 + *sEntrypp = (StrEntry *)OS_Alloc( sizeof(StrEntry) ); + if( *sEntrypp == NULL) { + OS_Printf("StrEntry allocate failed.\n"); + return -1; + }else { + return 1; + } +} + + +// 指定されたハンドルのStrEntry要素をエントリテーブルから削除 +static u16 DeleteStrEntry(u16 handle) +{ + StrEntry **sEntrypp = GetStrEntryAddress( handle ); + + if( *sEntrypp == NULL) { + return NULL; + } + + OS_Free( *sEntrypp ); + *sEntrypp = NULL; + + return handle; +} + + +// 空きエントリを探す(あんま効率よくない) +static BOOL GetEmptyStrEntry(u32 dataAddr, u16 *handlep) +{ + int i = SEARCH_ENTRY_MAX_NUM; // 処理が重くなるのを防ぐため、サーチ回数に制限を加える。 + u16 handle = (u16)( (dataAddr >> 2) & (STR_ENTRY_MAX_NUM - 1) ); + + while(i--) { + StrEntry *sEntryp = GetStrEntry( handle ); + if( sEntryp == NULL ) { + *handlep = handle; + return TRUE; // 新規ハンドル位置確保 + }else { + if( sEntryp->dataAddr == dataAddr ) { + *handlep = handle; + return TRUE; // 既存ハンドル位置発見 + } + handle = (u16)( (handle + 1) & (STR_ENTRY_MAX_NUM - 1) ); + } + } + return FALSE; +} + + +// 指定データのハンドルを探す(あんま効率よくない) +static u16 SearchStrEntry(u32 dataAddr) +{ + int i = SEARCH_ENTRY_MAX_NUM; // 処理が重くなるのを防ぐため、サーチ回数に制限を加える。 + u16 handle = (u16)( (dataAddr >> 2) & (STR_ENTRY_MAX_NUM - 1) ); + + while(i--) { + StrEntry *sEntryp = GetStrEntry( handle ); + if(sEntryp != NULL) { + if( sEntryp->dataAddr == dataAddr ) { + return handle; // 既存ハンドル位置発見 + } + } + handle = (u16)( (handle + 1) & (STR_ENTRY_MAX_NUM - 1) ); + } + return 0xffff; +} + + +//---------------------------------------------- +// キャラクタVRAMの動的確保処理 +//---------------------------------------------- + +// 文字列表示に必要なキャラクタ数の測定 +static u16 MeasureStringCharWidth(const u8 *str) +{ + u16 totalWidth = 0; // 文字列のトータルの横ドットサイズ + u16 charNum = 0; // 文字列表示に必要なキャラクタ数 + + // 文字列のトータルの横ドットサイズを算出 + while(*str) { // 各文字は SJIS か ASCII か? + if( ((*str >= SJIS_HIGHER_CODE1_MIN) && (*str <= SJIS_HIGHER_CODE1_MAX)) + || ((*str >= SJIS_HIGHER_CODE2_MIN) && (*str <= SJIS_HIGHER_CODE2_MAX)) ) { + str += 2; // SJIS文字 + totalWidth += nowFontHan->yoko_dot; + }else { + str++; // ASCII文字 + totalWidth += nowFontHan->yoko_dot; + } + } + // トータル横ドット数から、文字列の表示に必要なキャラクタ数を算出 + charNum = (u16)(totalWidth >> 3); + if(totalWidth & 0x0007) { + charNum = (u16)(charNum + 1); + } + + return charNum; +} + + +//---------------------------------------------- +// フォントデータ→NITROキャラデータへの変換関数群 +//---------------------------------------------- + +// 指定された文字列を指定メモリブロックに展開しながら転送(使用フォントによって文字詰めも行う) +static void SpreadStringCloser(u8 *strp, StrEntry *sEntryp, u16 v_offset) +{ + u32 charBuff[(NITRO_CHAR_SIZE * 4) / 4]; // 16x16キャラ2文字で4キャラ分のバッファ。(2文字展開して、文字詰めを行うため) + u8 *charMemp; + u8 *fromAdr; + u16 i; + u16 charNum; + FontPropotion fontPro; + + // Spread target string char data to WRAM pool + charNum = sEntryp->charNum; + charMemp = (u8 *)sEntryp->charMemp; + fontPro.h_offset = 0; + fontPro.leftp = (u16 *)0x0; + fontPro.rightp = (u16 *)0x0; + + while(1) { + // 隣接する2つの1bitフォントデータを16x16ドットキャラクタ配列にロード + if(fontPro.h_offset == 0) { + SetFirstFont(&strp, v_offset, &fontPro); // 表示文字列を16x16ドット単位に区切った時に先頭にくるキャラクタをロード + } + fromAdr = CloseFontChar(&strp, v_offset, &fontPro); // 上記キャラクタに隣接するキャラクタをロード + + // ロードした1bitフォントデータを4bitNITROキャラデータに展開 + SpreadFontZen(3, 1, fromAdr, (u32 *)charBuff); // キャラクタデータを4bitに展開。 + + // 展開したキャラデータをVRAMにコピー + fromAdr = (u8 *)charBuff; + for(i = 0; i < 2; i++) { // 生成した16x16ドット(4キャラ)分のデータを転送 + MI_CpuCopyFast(fromAdr, charMemp, (NITRO_CHAR_SIZE * 2)); + fromAdr += NITRO_CHAR_SIZE * 2; + charMemp+= NITRO_CHAR_SIZE * 2; + if(--charNum == 0) { + return; + } + } + } +} + + +// 最初のフォントデータをバッファにセット +static void SetFirstFont(u8 **strpp, u16 v_offset, FontPropotion *fontProp) +{ + u8 tate; + u8 *fontAdr; + u16 *firstp; + const FontComponent *fontComp; + + if(**strpp == 0x00) { + return; + } + + fontAdr = (u8 *)CalcCharCodeAddress(strpp, &fontComp); // 今回の文字のコードから、フォントデータ格納アドレスを算出。 + + MI_CpuClearFast(fontProp->buff16x16[0], 64); // 16x16ドット単位の一時展開バッファのクリア + + firstp = (u16 *)fontProp->buff16x16[0] + v_offset; + for(tate = 0; tate < fontComp->tate_dot - 1; tate++) { + *firstp = (u16)(*fontAdr++ << 8); + if(fontComp->yoko_dot > 8) { + *firstp |= *fontAdr++; + } + firstp++; + } + fontProp->h_offset = fontComp->yoko_dot; + fontProp->leftp = (u16 *)fontProp->buff16x16[0]; + fontProp->rightp = (u16 *)fontProp->buff16x16[1]; +} + + +// 隣接するフォントデータをバッファにセット +static u8 * CloseFontChar(u8 **strpp, u16 v_offset, FontPropotion *fontProp) +{ + u8 tate; + u8 *fontAdr; + u16 *temp; + u16 *leftp_tmp; + u16 *rightp_tmp; + const FontComponent *fontComp; + + while(fontProp->h_offset < 16) { + if(**strpp == 0x00) { + break; + } + + fontAdr = (u8 *)CalcCharCodeAddress(strpp, &fontComp); // 今回の文字のコードから、フォントデータ格納アドレスを算出。 + + leftp_tmp = fontProp->leftp + v_offset; // フォントデータを横ドット詰めしながらロード + rightp_tmp = fontProp->rightp + v_offset; + for(tate=0; tate < fontComp->tate_dot - 1; tate++) { + *rightp_tmp = (u16)(*fontAdr++ << 8); + if(fontComp->yoko_dot > 8) { + *rightp_tmp |= *fontAdr++; + } + + *leftp_tmp |= *rightp_tmp >> fontProp->h_offset; + *rightp_tmp <<= 16 - fontProp->h_offset; + leftp_tmp++; + rightp_tmp++; + } + fontProp->h_offset += fontComp->yoko_dot; + } + fontProp->h_offset -= 16; + temp = fontProp->leftp; + fontProp->leftp = fontProp->rightp; + fontProp->rightp = temp; + return (u8 *)temp; +} + + +// 文字コードに対応したフォントデータ格納アドレスを算出する。 +static u32 CalcCharCodeAddress(u8 **strpp, const FontComponent **font) +{ + u8 higher_code; + u8 lower_code; + u16 sjis_code; + u32 adr; + + // 対象文字が SJIS or ASCII かを判定 + higher_code = *(*strpp)++; + if( ((higher_code >= SJIS_HIGHER_CODE1_MIN) && (higher_code <= SJIS_HIGHER_CODE1_MAX)) + ||((higher_code >= SJIS_HIGHER_CODE2_MIN) && (higher_code <= SJIS_HIGHER_CODE2_MAX)) ) { // SJISか? + lower_code = *(*strpp)++; + *font = nowFontHan; + }else { // ASCII + sjis_code = tbl_ASCII_to_SJIS[higher_code]; + higher_code = (u8)(sjis_code >> 8); + lower_code = (u8)(sjis_code & 0x00ff); + *font = nowFontHan; + } + + // 文字コードからフォントデータアドレスを算出 + if(higher_code <= SJIS_HIGHER_CODE1_MIN + 3) { + higher_code -= 0x81; + }else if(higher_code <= SJIS_HIGHER_CODE1_MIN + 6) { + higher_code -= 0x83; + }else if(higher_code <= SJIS_HIGHER_CODE1_MAX) { + higher_code -= 0x84; + }else if(higher_code >= SJIS_HIGHER_CODE2_MIN) { + higher_code -= 0xc4; + } + + if(lower_code < 0x80) { + lower_code -= 0x40; + }else { + lower_code -= 0x41; + } + + adr = (*font)->start_adr + +((*font)->org_row_size) * higher_code + +((*font)->org_char_size+2) * lower_code + 2; + + return adr; +} + + +// 指定バッファの1bitフォントデータを4bitNITROキャラデータに展開。 +static void SpreadFontZen(u16 bit0_color, u16 bit1_color, u8 *fromAdr, u32 *toAdr) +{ + int i; + u8 tate; + u8 yoko; + u8 rd_data; + u32 wr_data; + u32 b0c; + u32 b1c; + u32 *toAdr_left; + u32 *toAdr_right; + + toAdr_left = toAdr; + toAdr_right = toAdr + 16; // toAdr + (16 * 4byte) + + for(tate = 0; tate < nowFontHan->need_tate_dot; tate++) { // キャラクタの縦ドット数だけ展開 + // 左右それぞれの8dotキャラを展開 + for(yoko = 0; yoko < 2; yoko++) { + wr_data = 0x00000000; // ライトデータ初期化 + + if(tate < nowFontHan->tate_dot) { + rd_data = *fromAdr++; // 左右8dotキャラの読み出し + b0c = (u32)bit0_color; // bit0 のカラー + b1c = (u32)bit1_color; // bit1 のカラー + + for(i = 0; i < 8; i++) { // 8dot分の各1bitの判定 + if(rd_data & 0x80) { + wr_data |= b1c; // "1"をカラー1へ + }else { + wr_data |= b0c; // "0"をカラー0へ + } + rd_data <<= 1; + b0c <<= 4; + b1c <<= 4; + } + } + + if(yoko==0) { + *toAdr_right++ = wr_data; // 32bit書きこみ + }else { + *toAdr_left++ = wr_data; + } + } + } +} + + +//---------------------------------------------- +// MALLOCシステムの初期化 +//---------------------------------------------- + +// VRAM上にヒープを作成。(アリーナにVRAMはないので、WRAM_MAIN, WRAM_SUBのアリーナで代用) +static void InitAllocSystemSJIS( TargetScreen target ) +{ + void* tempLo; + OSHeapHandle hh; + + // VRAM上にヒープを作成 + + if( target == TOP_SCREEN ) { + // メインLCD + OS_SetArenaLo( OS_ARENA_WRAM_MAIN, (void *)VRAM_M_ARENA_LO ); + OS_SetArenaHi( OS_ARENA_WRAM_MAIN, (void *)VRAM_M_ARENA_HI ); + tempLo = OS_InitAlloc( OS_ARENA_WRAM_MAIN, OS_GetWramMainArenaLo(), OS_GetWramMainArenaHi(), 1 ); + OS_SetArenaLo( OS_ARENA_WRAM_MAIN, tempLo ); + + hh = OS_CreateHeap( OS_ARENA_WRAM_MAIN, OS_GetWramMainArenaLo(), OS_GetWramMainArenaHi() ); + if(hh < 0) OS_Panic( "ARM9-MAIN LCD: Fail to create heap...\n" ); + OS_Printf( " arena lo = %x\n", OS_GetWramMainArenaLo() ); + OS_Printf( "WRAM arena hi = %x\n", OS_GetWramMainArenaHi() ); + hh = OS_SetCurrentHeap( OS_ARENA_WRAM_MAIN, hh ); + }else { // BOTTOM_SCREEN + // サブLCD + OS_SetArenaLo( OS_ARENA_WRAM_SUB, (void *)VRAM_S_ARENA_LO ); + OS_SetArenaHi( OS_ARENA_WRAM_SUB, (void *)VRAM_S_ARENA_HI ); + tempLo = OS_InitAlloc( OS_ARENA_WRAM_SUB, OS_GetWramSubArenaLo(), OS_GetWramSubArenaHi(), 1 ); + OS_SetArenaLo( OS_ARENA_WRAM_SUB, tempLo ); + + hh = OS_CreateHeap( OS_ARENA_WRAM_SUB, OS_GetWramSubArenaLo(), OS_GetWramSubArenaHi() ); + if(hh < 0) OS_Panic( "ARM9-SUB LCD: Fail to create heap...\n" ); + OS_Printf( "WRAM arena lo = %x\n", OS_GetWramSubArenaLo() ); + OS_Printf( "WRAM arena hi = %x\n", OS_GetWramSubArenaHi() ); + hh = OS_SetCurrentHeap( OS_ARENA_WRAM_SUB, hh ); + } +} + + +// VRAMへのキャラメモリ確保 +static void *AllocMemoryFromVram( u32 size ) +{ + if ( targetScreen == TOP_SCREEN ) { + return OS_AllocFromWramMain( size ); // ※縦も2キャラ分必要なので、NITRO_CHAR_SIZE*2 + }else { + return OS_AllocFromWramSub ( size ); // ※縦も2キャラ分必要なので、NITRO_CHAR_SIZE*2 + } +} + + +// VRAMへのキャラメモリ解放 +static void FreeMemoryToVram( void *p ) +{ + if ( targetScreen == TOP_SCREEN ) { + OS_FreeToWramMain( p ); + }else { + OS_FreeToWramSub( p ); + } +} + + +//---------------------------------------------- +// 16進データを文字列に変換 +//---------------------------------------------- + +// メインメモリからでも大丈夫な形式での1byteのデータ読み出し。 +__inline static u16 ReadByteHWBus(const void *srcp) +{ + if( (u32)srcp & 0x00000001 ) return (u16)(*(u16 *)( (u32)srcp ^ 0x00000001 ) >> 8 ); + else return (u16)(*(u16 *)( srcp ) & 0x00ff ); +} + +// 16進データを10進文字列に変換 +static u8 *HexToDecimalString(const void *hexp, u8 *strp, u16 figure, u16 size) +{ + u16 i; + u32 target = 0; + + for(i = 0; i < size; i++) { + target |= ReadByteHWBus( ((u8 *)hexp)++ ) << (8 * i); + } + + strp += figure; + *strp-- = 0x00; + for(i = 0; i < figure; i++) { + CP_SetDiv32_32(target, 10); + *strp-- = (u8 )(CP_GetDivRemainder32() + 0x30); + target = (u32) CP_GetDivResult32(); + } + return (strp + 1); +} + + +// 16進データを16進文字列に変換 +static u8 *HexToString(const void *hexp, u8 *strp, u16 figure) +{ + u16 i; + u8 hex; + + strp += figure; + *strp-- = 0x00; + + for(i = 0; i < figure; i++){ + hex = (u8)ReadByteHWBus(hexp); + if(i & 0x01){ + hex = (u8)( (hex >> 4) & 0x0f); + ((u8 *)hexp)++; + }else{ + hex = (u8)( hex & 0x0f); + } + if(hex < 0x000a) hex += 0x30; + else hex += 0x41 - 0x0a; + *strp-- = hex; + } + return (strp + 1); +} + + +//---------------------------------------------- +// ASCII -> SJIS 変換テーブル +//---------------------------------------------- + +const u16 tbl_ASCII_to_SJIS[0x100] = { + // 00 + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + // 10 + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + // 20 + 0x8140,0x8149,0x8168,0x81f2,0x8190,0x8193,0x8195,0x8166, + 0x8169,0x816a,0x8196,0x817b,0x8143,0x817c,0x8144,0x815e, + // 30 + 0x824f,0x8250,0x8251,0x8252,0x8253,0x8254,0x8255,0x8256, + 0x8257,0x8258,0x8146,0x8147,0x8183,0x8181,0x8184,0x8148, + // 40 + 0x8197,0x8260,0x8261,0x8262,0x8263,0x8264,0x8265,0x8266, + 0x8267,0x8268,0x8269,0x826a,0x826b,0x826c,0x826d,0x826e, + // 50 + 0x826f,0x8270,0x8271,0x8272,0x8273,0x8274,0x8275,0x8276, + 0x8277,0x8278,0x8279,0x816d,0x818f,0x816e,0x814f,0x8151, + // 60 + 0x8165,0x8281,0x8282,0x8283,0x8284,0x8285,0x8286,0x8287, + 0x8288,0x8289,0x828a,0x828b,0x828c,0x828d,0x828e,0x828f, + // 70 + 0x8290,0x8291,0x8292,0x8293,0x8294,0x8295,0x8296,0x8297, + 0x8298,0x8299,0x829a,0x816f,0x8162,0x8170,0x8160,0x81fc, + + // 80 + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + // 90 + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + // a0 + 0x81fc,0x8142,0x8175,0x8176,0x8141,0x8145,0x8192,0x8340, + 0x8342,0x8344,0x8346,0x8348,0x8383,0x8385,0x8387,0x8362, + // b0 + 0x815b,0x8341,0x8343,0x8345,0x8347,0x8349,0x834a,0x834c, + 0x834e,0x8350,0x8352,0x8354,0x8356,0x8358,0x835a,0x835c, + // c0 + 0x835e,0x8360,0x8363,0x8365,0x8367,0x8369,0x836a,0x836b, + 0x836c,0x836d,0x836e,0x8371,0x8374,0x8377,0x837a,0x837d, + // d0 + 0x837e,0x837f,0x838a,0x8382,0x8384,0x8386,0x8388,0x8389, + 0x838a,0x838b,0x838c,0x838d,0x838f,0x8393,0x814a,0x814b, + + // e0 + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + // f0 + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, + 0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc,0x81fc, +}; + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/font.h b/build/systemMenu_RED/ARM9/src/DS_Setting/font.h new file mode 100644 index 00000000..90e96b13 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/font.h @@ -0,0 +1,93 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: font.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __FONT_H_ +#define __FONT_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// define data---------------------------------- +#define STR_ENTRY_MAX_NUM 256 // 登録可能な文字列データの最大個数 + +#define SJIS_CHAR_VRAM_OFFSET 0x4000 // SJIS文字列キャラクタ用VRAMのオフセット値 +#define SJIS_CHAR_VRAM_SIZE (0x8000 + 0x20) //   〃          のサイズ(0x20はヒープのヘッダ) + +#define VRAM_M_ARENA_LO (HW_BG_VRAM + SJIS_CHAR_VRAM_OFFSET - 0x20) +#define VRAM_M_ARENA_HI (VRAM_M_ARENA_LO + SJIS_CHAR_VRAM_SIZE) +#define VRAM_S_ARENA_LO (HW_DB_BG_VRAM + SJIS_CHAR_VRAM_OFFSET - 0x20) +#define VRAM_S_ARENA_HI (VRAM_S_ARENA_LO + SJIS_CHAR_VRAM_SIZE) + // VRAMアリーナのLo & Hi + // SJISコード判定用の値 +#define SJIS_HIGHER_CODE1_MIN 0x81 +#define SJIS_HIGHER_CODE1_MAX 0x9f +#define SJIS_HIGHER_CODE2_MIN 0xe0 +#define SJIS_HIGHER_CODE2_MAX 0xea + +// 関数のエラーリターン値 +#define DSJIS_ERR_ENTRY_GET_FAILED 0x8000 +#define DSJIS_ERR_ENTRY_ALLOC_FAILED 0x8001 +#define DSJIS_ERR_CHAR_ALLOC_FAILED 0x8002 +#define DSJIS_ERR_STR_MEMORY_OVER 0x8003 +#define DSJIS_ERR_STR_LENGTH_TOO_LONG 0x8004 + +// SetTargetScreenSJISの引数target +typedef enum TargetScreen { + TOP_SCREEN =0, + BOTTOM_SCREEN +}TargetScreen; + +// フォント種類データ(SelectFontで指定) +typedef enum FontType{ // 全角  半角 + FONT12, // 12x12 & 12x 7dot + FONT_TYPE_MAX +}FontType; + + +// function's prototype declaration------------- + +void InitFont( TargetScreen target ); +void SetFont( FontType font ); +void SetTargetScreenSJIS( TargetScreen target ); +u16 ChangeColorSJIS( u16 handle, u16 new_color ); + +// 以下の表示関数は、データアドレスからデータハンドルを算出するので、ハンドルを引数で与えなくて良いが、同一アドレスのデータを複数場所に配置することができない。 +u16 DrawStringSJIS ( int x, int y, u16 color, const void *str ); +u16 DrawHexSJIS ( int x, int y, u16 color, const void *hexp, u16 figure ); +u16 DrawDecimalSJIS( int x, int y, u16 color, const void *hexp, u16 figure, u16 size ); + +// Ex系は、引数にindexを設けることで、上記関数で制限されている同一アドレスデータの複数場所配置に対応している。 +u16 DrawStringSJISEx ( int x, int y, u16 color, const void *strp, u32 index ); +u16 DrawHexSJISEx ( int x, int y, u16 color, const void *hexp, u16 figure, u32 index ); +u16 DrawDecimalSJISEx( int x, int y, u16 color, const void *hexp, u16 figure, u16 size, u32 index ); + +// 表示文字列クリア関数 +void ClearStringSJIS( void *datap ); +void ClearStringSJISEx( void *datap, u32 handleIndex ); +void ClearStringSJIS_handle( u16 handle ); +void ClearAllStringSJIS( void ); + + +#ifdef __cplusplus +} +#endif + +#endif // __FONT_H_ + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/langSelect.c b/build/systemMenu_RED/ARM9/src/DS_Setting/langSelect.c new file mode 100644 index 00000000..ef990447 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/langSelect.c @@ -0,0 +1,141 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: langSelect.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "misc.h" +#include "DS_Setting.h" + +// define data------------------------------------------ +#define CANCEL_BUTTON_LT_X 2 +#define CANCEL_BUTTON_LT_Y 21 +#define CANCEL_BUTTON_RB_X (CANCEL_BUTTON_LT_X+8) +#define CANCEL_BUTTON_RB_Y (CANCEL_BUTTON_LT_Y+2) + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +void SEQ_LangSelect_init(void); +int SEQ_LangSelect(void); + +// global variable ------------------------------------- + +// static variable ------------------------------------- +static NvLangCode langCode; // 言語コード + +// const data ----------------------------------------- +static const u8 *const str_language[] ATTRIBUTE_ALIGN(2) = { + (const u8 *)"にほんご ", + (const u8 *)"English ", + (const u8 *)"Francais", + (const u8 *)"Deutsch ", + (const u8 *)"Italiano", + (const u8 *)"Espanol ", +}; + +static const MenuComponent langSel = { + (u16)LANG_CODE_MAX, + 10, + 5, + 0, + 2, + 8, + WHITE, + HIGHLIGHT_Y, + (const u8 **)&str_language, +}; + + +//====================================================== +// function's description +//====================================================== + +// 言語設定の初期化 +void SEQ_LangSelect_init(void) +{ + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + MI_CpuClearFast(bgBakS, sizeof(bgBakS)); + SVC_CpuClearFast(0xc0, oamBakS, sizeof(oamBakS)); + + ClearAllStringSJIS(); + + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"LANGUAGE SELECT"); + (void)DrawStringSJIS( CANCEL_BUTTON_LT_X, CANCEL_BUTTON_LT_Y,HIGHLIGHT_C, (const u8 *)" CANCEL "); + if( initialSet ) { + (void)DrawStringSJIS( 8, 18, RED, (const u8 *)"Select language."); + } + + if((GetSYSMWork()->ncd_invalid) || (GetNCDWork()->option.language >= LANG_CODE_MAX)) { + langCode = LANG_ENGLISH; + }else { + langCode = (NvLangCode)GetNCDWork()->option.language; + } + + DrawMenu((u16)langCode, &langSel); + SVC_CpuClear(0x0000,&tpd, sizeof(TpWork),16); + + GXS_SetVisiblePlane(GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1); +} + + +// 言語選択 +int SEQ_LangSelect(void) +{ + BOOL tp_select,tp_cancel = FALSE; + + ReadTpData(); // タッチパネル入力の取得 + + //-------------------------------------- + // キー入力処理 + //-------------------------------------- + if(pad.trg & PAD_KEY_DOWN){ // カーソルの移動 + if(++langCode == LANG_CODE_MAX) langCode = (NvLangCode)0; + } + if(pad.trg & PAD_KEY_UP){ + if(--langCode < 0) langCode = (NvLangCode)(LANG_CODE_MAX-1); + } + tp_select = SelectMenuByTp((u16 *)&langCode, &langSel); + DrawMenu((u16)langCode, &langSel); + + // [CANCEL]ボタン押下チェック + if(tpd.disp.touch) { + tp_cancel = InRangeTp(CANCEL_BUTTON_LT_X*8, CANCEL_BUTTON_LT_Y*8-4, + CANCEL_BUTTON_RB_X*8, CANCEL_BUTTON_RB_Y*8-4, &tpd.disp); + } + + if((pad.trg & PAD_BUTTON_A) || (tp_select)) { // メニュー項目への分岐 + GetSYSMWork()->ncd_invalid = 0; + GetNCDWork()->option.input_language = 1; // 言語入力フラグを立てる + GetNCDWork()->option.language = langCode; + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData (GetNCDWork()); + SEQ_MainMenu_init(); + return 0; + }else if((pad.trg & PAD_BUTTON_B) || (tp_cancel)) { + SEQ_MainMenu_init(); + return 0; + } + + ReadTpData(); + + return 0; +} + + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/misc.c b/build/systemMenu_RED/ARM9/src/DS_Setting/misc.c new file mode 100644 index 00000000..501ee223 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/misc.c @@ -0,0 +1,384 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: myFunc.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "misc.h" + +// define data---------------------------------- + +// function's prototype------------------------- + +// extern data---------------------------------- +//extern u16 bgBakS[32*24]; // BG バックアップ +//extern GXOamAttr oamBakS[128]; // OAM バックアップ + + +// const data----------------------------------- +//const u16 csr_charList1[] ={0x008c, 0x008c, 0x008c, 0x008c}; +//const u8 str_time_period[]={" . ."}; + + +// global variable------------------------------ +int (*nowProcess)(void); +//MyTime myTime; +//KeyWork pad; + +// static variable------------------------------ +static u16 key_rapid[4]; +//static u16 csr_animeCount, csr_animeCharNum; +//static u16 csr_pos_x, csr_pos_y, csr_add_y; +//static u16 blinkCount; + + +// ============================================================================ +// function's description +// ============================================================================ + +// BgBakオフセット値算出 +__inline static u16 *calcBgOffset(u16 pos_x,u16 pos_y) +{ + return bgBakS+pos_x+(pos_y<<5); +} + + +// メインメモリからでも大丈夫な形式での1byteのデータ読み出し。 +__inline static u16 ReadByteHWBus(const void *srcp) +{ + if( (u32)srcp & 0x00000001 ) return (u16)(*(u16 *)( (u32)srcp ^ 0x00000001 ) >> 8 ); + else return (u16)(*(u16 *)( srcp ) & 0x00ff ); +} + + +// 初期化 +void mf_init(void) +{ + mf_KEYPAD_initRapid(); +// mf_BLINK_initCounter(); +} + + +/* +// キー入力読み出し +void mf_KEYPAD_read(void) +{ + u16 ReadData= PAD_Read(); + pad.trg = (u16)(ReadData & (ReadData ^ pad.cont)); // トリガ 入力 + pad.cont= ReadData; // ベタ 入力 +} +*/ + + +// キー連射入力処理 初期化(十字キーのみ) +void mf_KEYPAD_initRapid(void) +{ + u16 *krp=key_rapid; + + *krp++=0; + *krp++=0; + *krp++=0; + *krp++=0; +} + + +// キー連射入力(十字キーのみ) +void mf_KEYPAD_rapid(void) +{ + u16 mask,i; + + for(i=0;i<4;i++){ + mask=(u16)(0x0001<<(i+4)); + if(pad.cont & mask){ + key_rapid[i]++; + if(key_rapid[i]==30) { + pad.trg|=mask; + key_rapid[i]=20; + } + }else{ + key_rapid[i]=0; + } + } +} + + +// Xframeウェイト +void mf_waitXframe(u16 frame) +{ + BOOL prelIRQ=OS_EnableIrq(); + while(frame--) OS_WaitIrq(1, OS_IE_V_BLANK); + (void)OS_RestoreIrq(prelIRQ); +} + + + +// 矩形BGクリア +void mf_clearRect(u16 pos_x,u16 pos_y,u8 height,u8 width) +{ + u16 i,j; + u16 *dstp=calcBgOffset(pos_x,pos_y); + + for(i=0;i0) mask=(mask<<8)|0xff; + target=(*(u32 *)valuep)&mask; + count=10; + divisor=1000000000; + dstp=calcBgOffset(pos_x,pos_y); + while(count) { + CP_SetDiv32_32(target, divisor); + if (count<=drawLength) { + charCode=(u16)(CP_GetDivResult32()+0x0030); + *dstp++ =(u16)(charCode | color); + } + target=(u32)CP_GetDivRemainder32(); + CP_SetDiv32_32(divisor, 10); + divisor=(u32)CP_GetDivResult32(); + count--; + } +} + + +// 16進データ表示 +void mf_drawHex(u16 pos_x,u16 pos_y,u16 color,const void *valuep,u8 drawLength) +{ + u16 count,charCode; + u16 *dstp=calcBgOffset(pos_x,pos_y)+drawLength-1; + + for(count=0;count>4) & 0x000f); + ((u8 *)valuep)++; + }else{ + charCode=(u16)( charCode & 0x000f); + } + if (charCode<0x000a) charCode+=0x0030; + else charCode+=0x0041-0x000a; + *dstp--=(u16)(charCode | color); + } +} + + +// 1byte文字列データ表示(0x00〜0xffまでの1文字が1byteで良い文字列を描画する +void mf_drawString(u16 pos_x,u16 pos_y, u16 color, const u8 *strp) +{ + u16 data16; + u16 *dstp=calcBgOffset(pos_x,pos_y); + + while(1) { + data16=ReadByteHWBus(strp++); + if(data16==0) break; + *dstp++=(u16)(color | data16); + } +} + + +// 2byte文字列データ表示(0x0100以降の1文字に2byte必要な文字列を描画する +void mf_drawString2(u16 pos_x,u16 pos_y, u16 color, const u16 *strp) +{ + u16 *dstp=calcBgOffset(pos_x,pos_y); + + while(*strp) *dstp++ = (u16)(*strp++ | color); +} + +// 矩形フレーム描画 +void mf_drawRectFrame(u16 pos_x,u16 pos_y,u16 color,u8 height,u8 width) +{ + u16 i,j,code; + u16 *dstp; + + for(i=0;i +#include "main.h" + +// define data --------------------------------- + +// パレットカラー +#define WHITE (0<<12) +#define RED (1<<12) +#define GREEN (2<<12) +#define BLUE (3<<12) +#define YELLOW (4<<12) +#define CYAN (5<<12) +#define PURPLE (6<<12) +#define LIGHTGREEN (7<<12) +#define HIGHLIGHT_Y (8<<12) +#define HIGHLIGHT_C (9<<12) +#define HIGHLIGHT_W (10<<12) +#define HIGHLIGHT_B (11<<12) + +// 時間計測構造体 +typedef struct { + int enable; + int frame; + int second; + int minute; + int hour; +}MyTime; + +// キーデータ・ワークエリア構造体 +//typedef struct { +// u16 trg; // トリガ入力 +// u16 cont; // ベタ 入力 +//}KeyWork; + + +// global variable------------------------------ +extern MyTime myTime; +//extern KeyWork pad; +extern int (*nowProcess)(void); + + +// const data----------------------------------- +extern const u16 myPlttData[12][16]; // パレットデータ +extern const u16 myChar[0x2800*8/16]; // キャラクターデータ + + +// function------------------------------------- +extern void mf_init(void); +extern void mf_KEYPAD_read(void); +extern void mf_KEYPAD_initRapid(void); +extern void mf_KEYPAD_rapid(void); +extern void mf_waitXframe(u16 frame); +extern void mf_clearRect(u16 pos_x,u16 pos_y,u8 height,u8 width); +/* +extern void mf_drawUInt(u16 pos_x,u16 pos_y,u16 color,const void *valuep,u8 drawLength,u8 size); +extern void mf_drawHex(u16 pos_x,u16 pos_y,u16 color,const void *valuep,u8 drawLength); +extern void mf_drawString(u16 pos_x,u16 pos_y,u16 color,const u8 *strp); +extern void mf_drawString2(u16 pos_x,u16 pos_y,u16 color,const u16 *strp); +extern void mf_drawRectFrame(u16 pos_x,u16 pos_y,u16 color,u8 height,u8 width); +extern void mf_CSR_init(u16 pos_x,u16 pos_y,u16 add_y); +extern void mf_CSR_moveAndAnime(int nowNum); +extern void mf_CSR_anime(const u16 *csr_charListp); +extern void mf_BLINK_initCounter(void); +extern void mf_BLINK_drawString(u16 pos_x,u16 pos_y,u16 color,const u8 *strp); +extern void mf_TIME_init(void); +extern void mf_TIME_start(int init_flag); +extern void mf_TIME_stop(void); +extern void mf_TIME_count(void); +extern void mf_TIME_draw(u16 pos_x,u16 pos_y,u16 color); +extern void mf_strcpy(const u8 *str1p,u8 *str2p); +extern u8 mf_strcmp(const u8 *str1p,const u8 *str2p); +*/ + +#ifdef __cplusplus +} +#endif + +#endif // __MISC_H__ + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/myChar.c b/build/systemMenu_RED/ARM9/src/DS_Setting/myChar.c new file mode 100644 index 00000000..de62a8a4 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/myChar.c @@ -0,0 +1,684 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: myChar.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "misc.h" +#include "myFontequ.h" + +// パレットデータ-------------------------------------------------------------- +#define RGB555(r,g,b) (b<<10|g<<5|r) + +// 背景黒ベース +const u16 myPlttData[12][16] = { + {RGB555(31,31,31), RGB555( 0, 0, 0), RGB555(15,15,15), RGB555(31,31,31),}, // White + {RGB555(31,31,31), RGB555(31, 0, 0), RGB555(31,31,31), RGB555(31,31,31),}, // Red + {RGB555(31,31,31), RGB555( 0, 19, 0), RGB555(31,31,31), RGB555(31,31,31),}, // Green + {RGB555(31,31,31), RGB555( 0, 11, 31), RGB555(31,31,31), RGB555(31,31,31),}, // Blue + {RGB555(31,31,31), RGB555(31, 31, 0), RGB555(31,31,31), RGB555(31,31,31),}, // Yellow + {RGB555(31,31,31), RGB555( 0, 31, 31), RGB555(31,31,31), RGB555(31,31,31),}, // Cyan + {RGB555(31,31,31), RGB555(31, 0, 31), RGB555(31,31,31), RGB555(31,31,31),}, // Purple + {RGB555(31,31,31), RGB555( 0, 31, 0), RGB555(31,31,31), RGB555(31,31,31),}, // Light Green + {RGB555(31,31,31), RGB555(31,31,31), RGB555(31, 31, 0), RGB555(31, 31, 0),}, // HighLight Yellow + {RGB555(31,31,31), RGB555(31,31,31), RGB555( 0, 31, 31), RGB555( 0, 31, 31),}, // HighLight CYAN + {RGB555(31,31,31), RGB555(31,31,31), RGB555(31, 31, 31), RGB555(31, 31, 31),}, // HighLight WHITE + {RGB555(31,31,31), RGB555(31,31,31), RGB555( 0, 11, 31), RGB555( 0, 11, 31),}, // HighLight BLUE +}; + +// キャラクタデータ------------------------------------------------------------ +/* +const u16 myChar[0x2800*8/16]={ + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //0 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //1 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //2 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //3 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //4 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //5 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //6 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //7 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //8 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //9 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //a + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //b + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //c + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //d + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //e + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //f + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //10 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //11 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //12 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //13 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //14 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //15 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //16 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //17 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //18 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //19 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //1a + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //1b + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //1c + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //1d + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //1e + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //1f + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //20 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x1333,0x3321,0x1333,0x3321,0x1333,0x3321, //21 + 0x1333,0x3321,0x2333,0x3332,0x1333,0x3321,0x2333,0x3332, + 0x2113,0x3211,0x2113,0x3211,0x2123,0x3212,0x3213,0x3321, //22 + 0x3323,0x3332,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x2133,0x3321,0x1113,0x3211,0x2123,0x3321, //23 + 0x2133,0x3321,0x1113,0x3211,0x2123,0x3321,0x3233,0x3332, + 0x3333,0x3333,0x1333,0x3332,0x1133,0x3211,0x1213,0x3322, //24 + 0x1123,0x3311,0x1233,0x2112,0x1113,0x3211,0x1223,0x3322, + 0x3333,0x3333,0x2133,0x2133,0x1213,0x3212,0x2123,0x3321, //25 + 0x1233,0x3212,0x2133,0x2121,0x3213,0x3212,0x3323,0x3323, + 0x3333,0x3333,0x1133,0x3331,0x2113,0x3212,0x1123,0x3321, //26 + 0x2113,0x2111,0x3213,0x3213,0x1123,0x2121,0x2233,0x3232, + 0x1133,0x3332,0x1133,0x3332,0x1233,0x3332,0x2133,0x3333, //27 + 0x3233,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3213,0x3333,0x3321,0x1333,0x3332, //28 + 0x1333,0x3332,0x1333,0x3332,0x2333,0x3331,0x3333,0x3312, + 0x3333,0x3333,0x3133,0x3333,0x1233,0x3333,0x2333,0x3321, //29 + 0x3333,0x3321,0x3333,0x3321,0x1333,0x3332,0x2133,0x3333, + 0x3333,0x3333,0x1333,0x3332,0x1213,0x3212,0x1133,0x3321, //2a + 0x1233,0x3332,0x1133,0x3321,0x1213,0x3212,0x1323,0x3222, + 0x3333,0x3333,0x3333,0x3333,0x1333,0x3332,0x1333,0x3332, //2b + 0x1113,0x3211,0x1223,0x3222,0x1333,0x3332,0x2333,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //2c + 0x1133,0x3332,0x1133,0x3332,0x1233,0x3332,0x2133,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //2d + 0x1113,0x3211,0x2223,0x3222,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //2e + 0x3333,0x3333,0x3333,0x3333,0x2133,0x3333,0x2233,0x3333, + 0x3333,0x3333,0x3333,0x2133,0x3333,0x3213,0x3333,0x3321, //2f + 0x1333,0x3332,0x2133,0x3333,0x3213,0x3333,0x3323,0x3333, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x2113,0x2113, //30 + 0x2113,0x2113,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x1333,0x3321,0x1133,0x3321,0x1233,0x3321, //31 + 0x1333,0x3321,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x1113,0x3211,0x2223,0x2112,0x1133,0x3211, //32 + 0x2113,0x3322,0x2113,0x3333,0x1113,0x2111,0x2223,0x3222, + 0x3333,0x3333,0x1113,0x3211,0x2223,0x2112,0x1133,0x3211, //33 + 0x2233,0x2112,0x3333,0x2113,0x1113,0x3211,0x2223,0x3322, + 0x3333,0x3333,0x3333,0x3211,0x1333,0x3211,0x2133,0x3211, //34 + 0x3213,0x3211,0x1113,0x2111,0x2223,0x3211,0x3333,0x3322, + 0x3333,0x3333,0x1113,0x3211,0x2213,0x3322,0x1113,0x3211, //35 + 0x2223,0x2112,0x3333,0x2113,0x1113,0x3211,0x2223,0x3322, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x3322,0x1113,0x3211, //36 + 0x2113,0x2112,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x1113,0x2111,0x2223,0x2122,0x3333,0x3213, //37 + 0x3333,0x3321,0x1333,0x3321,0x1333,0x3321,0x2333,0x3332, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x1123,0x3211, //38 + 0x2113,0x2112,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x2113,0x2113, //39 + 0x1123,0x2111,0x2233,0x2112,0x1133,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, //3a + 0x3333,0x3333,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, //3b + 0x3333,0x3333,0x1333,0x3321,0x1333,0x3321,0x2333,0x3321, + 0x3333,0x3333,0x3333,0x3321,0x1333,0x3332,0x2133,0x3333, //3c + 0x2133,0x3333,0x1233,0x3333,0x2333,0x3321,0x3333,0x3322, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1133,0x3211, //3d + 0x2233,0x3222,0x1133,0x3211,0x2233,0x3222,0x3333,0x3333, + 0x3333,0x3333,0x1333,0x3333,0x2333,0x3331,0x3333,0x3212, //3e + 0x3333,0x3213,0x3333,0x3321,0x1333,0x3332,0x2333,0x3333, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x2113,0x2113, //3f + 0x3223,0x3211,0x1333,0x3321,0x2333,0x3332,0x1333,0x3321, + 0x3333,0x3333,0x1133,0x3321,0x2213,0x3212,0x1213,0x2121, //40 + 0x2113,0x2121,0x2113,0x2121,0x1213,0x3211,0x1123,0x2121, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x2113,0x2113, //41 + 0x1113,0x2111,0x2113,0x2112,0x2113,0x2113,0x2223,0x2223, + 0x3333,0x3333,0x1113,0x3211,0x2113,0x2112,0x1113,0x3211, //42 + 0x2113,0x2112,0x2113,0x2113,0x1113,0x3211,0x2223,0x3322, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x2113,0x2223, //43 + 0x2113,0x3333,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x1113,0x3211,0x2113,0x2112,0x2113,0x2113, //44 + 0x2113,0x2113,0x2113,0x2113,0x1113,0x3211,0x2223,0x3322, + 0x3333,0x3333,0x1113,0x2111,0x2113,0x2222,0x1113,0x3211, //45 + 0x2113,0x3222,0x2113,0x3333,0x1113,0x2111,0x2223,0x2222, + 0x3333,0x3333,0x1113,0x2111,0x2113,0x2222,0x1113,0x3211, //46 + 0x2113,0x3222,0x2113,0x3333,0x2113,0x3333,0x2223,0x3333, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x3322,0x2113,0x2111, //47 + 0x2113,0x2112,0x2113,0x2113,0x1123,0x2111,0x2233,0x3222, + 0x3333,0x3333,0x2113,0x2113,0x2113,0x2113,0x1113,0x2111, //48 + 0x2113,0x2112,0x2113,0x2113,0x2113,0x2113,0x2223,0x2223, + 0x3333,0x3333,0x1333,0x3321,0x1333,0x3321,0x1333,0x3321, //49 + 0x1333,0x3321,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x3333,0x2113,0x3333,0x2113,0x3333,0x2113, //4a + 0x2113,0x2113,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x2113,0x2113,0x2113,0x3211,0x1113,0x3322, //4b + 0x1113,0x3331,0x2113,0x3311,0x2113,0x2112,0x2223,0x2223, + 0x3333,0x3333,0x2113,0x3333,0x2113,0x3333,0x2113,0x3333, //4c + 0x2113,0x3333,0x2113,0x3333,0x1113,0x2111,0x2223,0x2222, + 0x3333,0x3333,0x2133,0x2133,0x1113,0x1112,0x1113,0x1112, //4d + 0x1113,0x1111,0x2113,0x1121,0x2113,0x1121,0x3223,0x2232, + 0x3333,0x3333,0x2113,0x2113,0x1113,0x2112,0x1113,0x2112, //4e + 0x2113,0x2111,0x2113,0x2111,0x2113,0x2112,0x2223,0x2223, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x2113,0x2113, //4f + 0x2113,0x2113,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x1113,0x3211,0x2113,0x2112,0x1113,0x3211, //50 + 0x2113,0x3322,0x2113,0x3333,0x2113,0x3333,0x2223,0x3333, + 0x3333,0x3333,0x1133,0x3211,0x2113,0x2112,0x2113,0x2113, //51 + 0x2113,0x2113,0x2113,0x2113,0x1123,0x3211,0x2233,0x2111, + 0x3333,0x3333,0x1113,0x3211,0x2113,0x2112,0x1113,0x3211, //52 + 0x2113,0x2112,0x2113,0x2113,0x2113,0x2113,0x2223,0x2223, + 0x3333,0x3333,0x1133,0x2111,0x2113,0x3222,0x1123,0x3331, //53 + 0x1233,0x3311,0x2333,0x2112,0x1113,0x3211,0x2223,0x3322, + 0x3333,0x3333,0x1113,0x2111,0x1223,0x3221,0x1333,0x3321, //54 + 0x1333,0x3321,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x2113,0x2113,0x2113,0x2113,0x2113,0x2113, //55 + 0x2113,0x2113,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x2113,0x2113,0x2113,0x2113,0x2113,0x2113, //56 + 0x2113,0x2113,0x2123,0x3213,0x1233,0x3321,0x2333,0x3332, + 0x3333,0x3333,0x2113,0x1121,0x2113,0x1121,0x2113,0x1121, //57 + 0x1113,0x1111,0x1123,0x2112,0x2133,0x2133,0x3233,0x3233, + 0x3333,0x3333,0x2113,0x2113,0x2113,0x2113,0x1123,0x3211, //58 + 0x1233,0x3211,0x2113,0x2112,0x2113,0x2113,0x3223,0x3223, + 0x3333,0x3333,0x2113,0x2113,0x2113,0x2113,0x2133,0x3213, //59 + 0x1133,0x3211,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x1113,0x2111,0x2223,0x2112,0x1333,0x3221, //5a + 0x1133,0x3332,0x2113,0x3333,0x1113,0x2111,0x2223,0x2222, + 0x3333,0x3333,0x1333,0x3321,0x1333,0x3322,0x1333,0x3332, //5b + 0x1333,0x3332,0x1333,0x3332,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x3313,0x3333,0x3123,0x3333,0x1233,0x3333, //5c + 0x2333,0x3331,0x3333,0x3312,0x3333,0x3123,0x3333,0x3233, + 0x3333,0x3333,0x1333,0x3321,0x2333,0x3321,0x3333,0x3321, //5d + 0x3333,0x3321,0x3333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x1333,0x3332,0x2133,0x3321,0x3233,0x3322, //5e + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //5f + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2223,0x2222, + 0x1333,0x3321,0x1333,0x3321,0x1333,0x3332,0x2333,0x3321, //60 + 0x3333,0x3332,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2213,0x2112, //61 + 0x1123,0x2111,0x2113,0x2112,0x1123,0x2111,0x2233,0x2222, + 0x2113,0x3333,0x2113,0x3333,0x1113,0x3211,0x2113,0x2112, //62 + 0x2113,0x2113,0x2113,0x2113,0x1113,0x3211,0x2223,0x3322, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2113,0x2122, //63 + 0x2113,0x3233,0x2113,0x2133,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x2113,0x3333,0x2113,0x1133,0x2111,0x2113,0x2112, //64 + 0x2113,0x2113,0x2113,0x2113,0x1123,0x2111,0x2233,0x2222, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2113,0x2112, //65 + 0x1113,0x2111,0x2113,0x3222,0x1123,0x2111,0x2233,0x3222, + 0x1333,0x3211,0x1133,0x3322,0x1113,0x3321,0x1123,0x3332, //66 + 0x1133,0x3332,0x1133,0x3332,0x1133,0x3332,0x2233,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x2111,0x2113,0x2112, //67 + 0x2113,0x2113,0x1123,0x2111,0x2213,0x2112,0x1133,0x3211, + 0x2113,0x3333,0x2113,0x3333,0x1113,0x3311,0x2113,0x2112, //68 + 0x2113,0x2113,0x2113,0x2113,0x2113,0x2113,0x2223,0x2223, + 0x1333,0x3321,0x2333,0x3332,0x1333,0x3321,0x1333,0x3321, //69 + 0x1333,0x3321,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3211,0x3333,0x3322,0x3333,0x3211,0x3333,0x3211, //6a + 0x3333,0x3211,0x3333,0x3211,0x3213,0x3211,0x1123,0x3321, + 0x2113,0x3333,0x2113,0x3213,0x2113,0x3211,0x1113,0x3321, //6b + 0x1113,0x3321,0x2113,0x3311,0x2113,0x2112,0x2223,0x3223, + 0x1333,0x3321,0x1333,0x3321,0x1333,0x3321,0x1333,0x3321, //6c + 0x1333,0x3321,0x1333,0x3321,0x1333,0x3321,0x2333,0x3322, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x2111,0x1211,0x1121, //6d + 0x1211,0x1121,0x1211,0x1121,0x1211,0x1121,0x2322,0x2232, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x3211,0x2113,0x2112, //6e + 0x2113,0x2113,0x2113,0x2113,0x2113,0x2113,0x2223,0x2223, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2113,0x2112, //6f + 0x2113,0x2113,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x3211,0x2113,0x2112, //70 + 0x2113,0x2113,0x1113,0x3211,0x2113,0x3322,0x2113,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x2111,0x2113,0x2112, //71 + 0x2113,0x2113,0x1123,0x2111,0x2233,0x2112,0x3333,0x2113, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x2112,0x1133,0x2111, //72 + 0x1133,0x3222,0x1133,0x3332,0x1133,0x3332,0x2233,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x1113,0x3322, //73 + 0x1133,0x3211,0x2233,0x2111,0x1133,0x3211,0x2233,0x3322, + 0x1133,0x3332,0x1113,0x3321,0x1123,0x3332,0x1133,0x3332, //74 + 0x1133,0x3332,0x1133,0x3332,0x1233,0x3321,0x2333,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x2113,0x2113,0x2113,0x2113, //75 + 0x2113,0x2113,0x2113,0x2113,0x1123,0x3211,0x2233,0x3322, + 0x3333,0x3333,0x3333,0x3333,0x2113,0x2113,0x2113,0x2113, //76 + 0x2113,0x2113,0x2113,0x3213,0x1113,0x3321,0x2223,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x1211,0x1121,0x1211,0x1121, //77 + 0x1211,0x1121,0x1211,0x1121,0x1111,0x2111,0x2222,0x3222, + 0x3333,0x3333,0x3333,0x3333,0x2113,0x2113,0x2113,0x2113, //78 + 0x1123,0x3211,0x2113,0x2112,0x2113,0x2113,0x3223,0x3223, + 0x3333,0x3333,0x3333,0x3333,0x2113,0x2113,0x2113,0x2113, //79 + 0x2113,0x2113,0x1123,0x2111,0x2233,0x2112,0x1133,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2223,0x3211, //7a + 0x1333,0x3321,0x1133,0x3332,0x1113,0x2111,0x2223,0x2222, + 0x3333,0x3333,0x3333,0x3321,0x1333,0x3332,0x1333,0x3332, //7b + 0x2133,0x3333,0x1333,0x3332,0x1333,0x3332,0x3333,0x3321, + 0x3333,0x3333,0x1333,0x3332,0x1333,0x3332,0x1333,0x3332, //7c + 0x1333,0x3332,0x1333,0x3332,0x1333,0x3332,0x2333,0x3332, + 0x3333,0x3333,0x1333,0x3332,0x3333,0x3321,0x3333,0x3321, //7d + 0x3333,0x3213,0x3333,0x3321,0x3333,0x3321,0x1333,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3113,0x3333, //7e + 0x1221,0x2133,0x2332,0x3211,0x3333,0x3322,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //7f + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x2211,0x2222,0x2211,0x2222,0x2211,0x2222,0x2211,0x2222, //80 + 0x2211,0x2222,0x2211,0x2222,0x2211,0x2222,0x2211,0x2222, + 0x1111,0x2222,0x1111,0x2222,0x1111,0x2222,0x1111,0x2222, //81 + 0x1111,0x2222,0x1111,0x2222,0x1111,0x2222,0x1111,0x2222, + 0x1111,0x2211,0x1111,0x2211,0x1111,0x2211,0x1111,0x2211, //82 + 0x1111,0x2211,0x1111,0x2211,0x1111,0x2211,0x1111,0x2211, + 0x1111,0x1111,0x1111,0x1111,0x1111,0x1111,0x1111,0x1111, //83 + 0x1111,0x1111,0x1111,0x1111,0x1111,0x1111,0x1111,0x1111, + 0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222, //84 + 0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222,0x2222, + 0x1333,0x3331,0x1333,0x3331,0x1333,0x3331,0x1333,0x3331, //85 + 0x1333,0x3331,0x1333,0x3331,0x1333,0x3331,0x1333,0x3331, + 0x1333,0x3331,0x1333,0x3331,0x1333,0x3331,0x1333,0x3331, //86 + 0x1111,0x1111,0x1333,0x3331,0x1333,0x3331,0x1333,0x3331, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //87 + 0x1111,0x1111,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x1113,0x3333,0x2213, //88 + 0x3333,0x1213,0x3333,0x1213,0x3333,0x1213,0x3333,0x1213, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x1111,0x2222,0x2222, //89 + 0x1111,0x1111,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x1111,0x2222,0x2222, //8a + 0x1111,0x1111,0x1333,0x3331,0x1333,0x3331,0x1333,0x3331, + 0x3333,0x1213,0x3333,0x1213,0x3333,0x1213,0x3333,0x1213, //8b + 0x3333,0x1213,0x3333,0x1213,0x3333,0x1213,0x3333,0x1213, + 0x3133,0x3333,0x1133,0x3333,0x1133,0x3331,0x1133,0x3311, //8c + 0x1133,0x3321,0x1133,0x3332,0x2133,0x3333,0x3233,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1113,0x3332, //8d + 0x2123,0x3213,0x1133,0x3321,0x1213,0x3212,0x2113,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //8e + 0x3333,0x3321,0x3213,0x3213,0x3213,0x3213,0x2133,0x3323, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1333,0x3332, //8f + 0x1133,0x3332,0x2213,0x3321,0x3323,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x2133,0x3333, //90 + 0x1113,0x3321,0x1223,0x3332,0x2133,0x3333,0x1213,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1113,0x3312, //91 + 0x2123,0x3323,0x1113,0x3321,0x2113,0x3213,0x2113,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3213,0x3321, //92 + 0x1123,0x3211,0x2113,0x3212,0x1223,0x3322,0x1333,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1333,0x3332, //93 + 0x1213,0x3321,0x1113,0x3212,0x1213,0x3211,0x1323,0x3322, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1333,0x3332, //94 + 0x1333,0x3321,0x1133,0x3332,0x1213,0x3321,0x1123,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //95 + 0x1333,0x3321,0x2113,0x3212,0x3223,0x3213,0x1333,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //96 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //97 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //98 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //99 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //9a + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //9b + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //9c + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //9d + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //9e + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //9f + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //a0 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //a1 + 0x3333,0x3333,0x1133,0x3321,0x2133,0x3321,0x1133,0x3321, + 0x3333,0x3333,0x1333,0x3211,0x1333,0x3322,0x1333,0x3332, //a2 + 0x1333,0x3332,0x2333,0x3332,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3321, //a3 + 0x3333,0x3321,0x3333,0x3321,0x1133,0x3321,0x2233,0x3322, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //a4 + 0x3333,0x3333,0x3333,0x3333,0x2133,0x3333,0x1333,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //a5 + 0x1333,0x3332,0x2333,0x3332,0x3333,0x3333,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2223,0x2122, //a6 + 0x1113,0x2111,0x2223,0x2122,0x3333,0x3213,0x1113,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1113,0x3321, //a7 + 0x2223,0x3321,0x2133,0x3321,0x2133,0x3332,0x3213,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3321, //a8 + 0x1133,0x3332,0x2111,0x3333,0x2122,0x3333,0x2133,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1333,0x3332, //a9 + 0x1113,0x3211,0x2213,0x3212,0x3323,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //aa + 0x1133,0x3321,0x1233,0x3332,0x1333,0x3332,0x1113,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3321, //ab + 0x1113,0x3211,0x2223,0x3321,0x1333,0x3321,0x2113,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1213,0x3211, //ac + 0x2111,0x3212,0x2122,0x3323,0x1333,0x3332,0x1333,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //ad + 0x1113,0x3321,0x2223,0x3321,0x3333,0x3321,0x1113,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1133,0x3211, //ae + 0x2233,0x3212,0x1133,0x3211,0x2233,0x3212,0x1133,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //af + 0x1213,0x3212,0x2323,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //b0 + 0x3333,0x3333,0x1113,0x3211,0x2223,0x3322,0x3333,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x2111,0x2222,0x3212, //b1 + 0x2133,0x3213,0x2133,0x3321,0x2133,0x3332,0x3211,0x3333, + 0x3333,0x3333,0x3333,0x2133,0x3333,0x3213,0x1333,0x3321, //b2 + 0x2113,0x3321,0x3223,0x3321,0x3333,0x3321,0x3333,0x3321, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x2111,0x2213,0x2122, //b3 + 0x3323,0x2133,0x3333,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x3211,0x1223,0x3322, //b4 + 0x1333,0x3332,0x1333,0x3332,0x1333,0x3332,0x1111,0x2111, + 0x3333,0x3333,0x3333,0x3213,0x1113,0x2111,0x2223,0x3212, //b5 + 0x3333,0x3211,0x1333,0x3212,0x1333,0x3212,0x2113,0x3213, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x2111,0x1223,0x2122, //b6 + 0x1333,0x2132,0x2133,0x2133,0x2133,0x2133,0x3213,0x3213, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x2111,0x2223,0x3221, //b7 + 0x3333,0x3321,0x1113,0x1111,0x2223,0x2212,0x3333,0x3213, + 0x3333,0x3333,0x1133,0x2111,0x2133,0x2122,0x3213,0x2133, //b8 + 0x3323,0x3213,0x3333,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3213,0x3333,0x1113,0x2111,0x2213,0x3212, //b9 + 0x3321,0x3213,0x3332,0x3321,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2223,0x2122, //ba + 0x3333,0x2133,0x3333,0x2133,0x3333,0x2133,0x1113,0x2111, + 0x3333,0x3333,0x3213,0x3213,0x1111,0x2111,0x2212,0x3212, //bb + 0x3213,0x3213,0x3323,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x2113,0x2133,0x3223,0x2133, //bc + 0x2113,0x2133,0x3223,0x2133,0x3333,0x3213,0x1113,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2223,0x3212, //bd + 0x3333,0x3321,0x3333,0x3321,0x1333,0x3212,0x2113,0x2133, + 0x3333,0x3333,0x2133,0x3333,0x1133,0x2111,0x2111,0x2122, //be + 0x2122,0x3213,0x2133,0x3323,0x2133,0x3333,0x1133,0x2111, + 0x3333,0x3333,0x3333,0x3333,0x3213,0x2133,0x3213,0x2133, //bf + 0x2123,0x3213,0x3233,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x1133,0x2111,0x2133,0x2122,0x2133,0x2133, //c0 + 0x1213,0x2111,0x2323,0x2122,0x3333,0x3213,0x1133,0x3321, + 0x3333,0x3333,0x3333,0x3213,0x1113,0x3321,0x2223,0x3321, //c1 + 0x1111,0x2111,0x2222,0x3221,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x1213,0x2132,0x1213,0x2132, //c2 + 0x2323,0x2133,0x3333,0x2133,0x3333,0x3213,0x1113,0x3321, + 0x3333,0x3333,0x1113,0x3211,0x2223,0x3322,0x1111,0x2111, //c3 + 0x2222,0x3221,0x3333,0x3321,0x1333,0x3332,0x2113,0x3333, + 0x3333,0x3333,0x2133,0x3333,0x2133,0x3333,0x2133,0x3333, //c4 + 0x1133,0x3332,0x2133,0x3211,0x2133,0x3322,0x2133,0x3333, + 0x3333,0x3333,0x3333,0x3321,0x1111,0x2111,0x2222,0x3221, //c5 + 0x3333,0x3321,0x3333,0x3321,0x1333,0x3332,0x2113,0x3333, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2233,0x3322, //c6 + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1113,0x2111, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x2111,0x2222,0x3212, //c7 + 0x3133,0x3321,0x1233,0x3332,0x2133,0x3321,0x3211,0x3213, + 0x3333,0x3333,0x1333,0x3332,0x1111,0x2111,0x2222,0x3212, //c8 + 0x3333,0x3321,0x1133,0x3212,0x1211,0x2132,0x1322,0x3232, + 0x3333,0x3333,0x3333,0x3213,0x3333,0x3213,0x3333,0x3213, //c9 + 0x3333,0x3321,0x3333,0x3321,0x1333,0x3332,0x2113,0x3333, + 0x3333,0x3333,0x1333,0x3332,0x3333,0x3321,0x3213,0x3213, //ca + 0x3213,0x3213,0x3321,0x2133,0x3321,0x2133,0x3321,0x2133, + 0x3333,0x3333,0x3213,0x2133,0x3213,0x3211,0x1113,0x3322, //cb + 0x2213,0x3333,0x3213,0x3333,0x3213,0x3333,0x1133,0x2111, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x2111,0x2222,0x2122, //cc + 0x3333,0x3213,0x3333,0x3213,0x3333,0x3321,0x1113,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x2133,0x3333,0x1213,0x3332, //cd + 0x3321,0x3321,0x3332,0x3213,0x3333,0x2133,0x3333,0x3233, + 0x3333,0x3333,0x1333,0x3332,0x1111,0x2111,0x1222,0x3222, //ce + 0x1213,0x3212,0x1213,0x2132,0x1321,0x2132,0x1321,0x2132, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x2111,0x2222,0x2122, //cf + 0x3213,0x3213,0x2133,0x3321,0x1333,0x3332,0x3333,0x3321, + 0x3333,0x3333,0x3113,0x3333,0x1223,0x3311,0x2333,0x2122, //d0 + 0x1133,0x3231,0x2233,0x3212,0x1113,0x3322,0x2223,0x2111, + 0x3333,0x3333,0x1333,0x3332,0x2133,0x3333,0x3213,0x3333, //d1 + 0x3213,0x3213,0x3321,0x2133,0x3321,0x2133,0x1111,0x2111, + 0x3333,0x3333,0x3333,0x3213,0x3213,0x3213,0x2133,0x3321, //d2 + 0x1333,0x3332,0x1333,0x3332,0x2133,0x3321,0x3211,0x3213, + 0x3333,0x3333,0x3333,0x3333,0x1111,0x2111,0x2122,0x3222, //d3 + 0x1111,0x2111,0x2122,0x3222,0x2133,0x3333,0x1133,0x2111, + 0x3333,0x3333,0x2133,0x3333,0x1133,0x2111,0x2111,0x2122, //d4 + 0x2122,0x3213,0x2133,0x3323,0x1333,0x3332,0x1333,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x3321,0x2223,0x3321, //d5 + 0x3333,0x3321,0x3333,0x3321,0x3333,0x3321,0x1111,0x2111, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2223,0x2122, //d6 + 0x1113,0x2111,0x2223,0x2122,0x3333,0x2133,0x1113,0x2111, + 0x3333,0x3333,0x1113,0x3211,0x2223,0x3322,0x1111,0x2111, //d7 + 0x2222,0x2122,0x3333,0x2133,0x3333,0x3213,0x1113,0x3321, + 0x3333,0x3333,0x3213,0x3213,0x3213,0x3213,0x3213,0x3213, //d8 + 0x3213,0x3213,0x3323,0x3213,0x3333,0x3321,0x1113,0x3332, + 0x3333,0x3333,0x1333,0x3332,0x1213,0x3332,0x1213,0x3332, //d9 + 0x1213,0x2132,0x1213,0x2132,0x1213,0x3212,0x1321,0x3321, + 0x3333,0x3333,0x3213,0x3333,0x3213,0x3333,0x3213,0x3333, //da + 0x3213,0x3213,0x3213,0x3213,0x3213,0x3321,0x1113,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2213,0x2122, //db + 0x3213,0x2133,0x3213,0x2133,0x3213,0x2133,0x1113,0x2111, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2111,0x2213,0x2122, //dc + 0x3323,0x2133,0x3333,0x2133,0x3333,0x3213,0x1133,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x1113,0x2132,0x2223,0x2133, //dd + 0x3333,0x2133,0x3333,0x2133,0x3333,0x3213,0x1113,0x3321, + 0x3333,0x1313,0x1333,0x2322,0x1113,0x2111,0x1223,0x2122, //de + 0x1333,0x2132,0x2133,0x2133,0x2133,0x2133,0x3213,0x3213, + 0x3333,0x1313,0x1333,0x2322,0x1113,0x2111,0x2223,0x3221, //df + 0x3333,0x3321,0x1113,0x1111,0x2223,0x2212,0x3333,0x3213, + 0x3333,0x1213,0x3333,0x2323,0x1133,0x2111,0x2133,0x2122, //e0 + 0x3213,0x3213,0x3323,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x1313,0x3213,0x2323,0x1113,0x2111,0x2213,0x3212, //e1 + 0x3321,0x3213,0x3332,0x3321,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x1313,0x3333,0x2323,0x1113,0x2111,0x2223,0x2122, //e2 + 0x3333,0x2133,0x3333,0x2133,0x3333,0x2133,0x1113,0x2111, + 0x3333,0x1313,0x3333,0x2323,0x3213,0x3213,0x1111,0x2111, //e3 + 0x2212,0x3212,0x3213,0x3213,0x3323,0x3321,0x1133,0x3332, + 0x3333,0x1313,0x3333,0x2323,0x2113,0x2133,0x3223,0x2133, //e4 + 0x2113,0x2133,0x3223,0x2133,0x3333,0x3213,0x1113,0x3321, + 0x3333,0x1313,0x3333,0x2323,0x1113,0x2111,0x2223,0x3212, //e5 + 0x3333,0x3321,0x3333,0x3321,0x1333,0x3212,0x2113,0x2133, + 0x3333,0x1313,0x2133,0x2323,0x1133,0x2111,0x2111,0x2122, //e6 + 0x2122,0x3213,0x2133,0x3323,0x2133,0x3333,0x1133,0x2111, + 0x3333,0x1313,0x3333,0x2323,0x3213,0x2133,0x3213,0x2133, //e7 + 0x2123,0x3213,0x3233,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x1313,0x3333,0x2323,0x1133,0x2111,0x2133,0x2122, //e8 + 0x1213,0x2111,0x2323,0x2122,0x3333,0x3213,0x1133,0x3321, + 0x3333,0x1313,0x3333,0x2323,0x1113,0x3211,0x2223,0x3321, //e9 + 0x1111,0x2111,0x2222,0x3221,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x1313,0x3333,0x2323,0x1213,0x2132,0x1213,0x2132, //ea + 0x2323,0x2133,0x3333,0x2133,0x3333,0x3213,0x1113,0x3321, + 0x3333,0x1313,0x3333,0x2323,0x1113,0x3211,0x2223,0x3322, //eb + 0x1111,0x2111,0x2222,0x3221,0x3333,0x3321,0x1113,0x3332, + 0x3333,0x3333,0x2133,0x1313,0x2133,0x2323,0x2133,0x3333, //ec + 0x1133,0x3333,0x2133,0x3211,0x2133,0x3322,0x2133,0x3333, + 0x3333,0x1313,0x1333,0x2323,0x3333,0x3331,0x3213,0x3213, //ed + 0x3213,0x3213,0x3321,0x2133,0x3321,0x2133,0x3321,0x2133, + 0x3333,0x1313,0x3213,0x2323,0x3213,0x2111,0x1113,0x3222, //ee + 0x2213,0x3333,0x3213,0x3333,0x3213,0x3333,0x1123,0x2111, + 0x3333,0x1313,0x3333,0x2323,0x1111,0x2111,0x2222,0x2122, //ef + 0x3333,0x3213,0x3333,0x3213,0x3333,0x3321,0x1113,0x3332, + 0x3333,0x3333,0x3333,0x1313,0x2133,0x2323,0x1213,0x3332, //f0 + 0x3321,0x3321,0x3332,0x3213,0x3333,0x2133,0x3333,0x3233, + 0x3333,0x1313,0x1333,0x2323,0x1111,0x2111,0x1222,0x3222, //f1 + 0x1213,0x3212,0x1213,0x2132,0x1321,0x2132,0x1321,0x2132, + 0x3333,0x1313,0x1333,0x2322,0x1113,0x2111,0x2213,0x2122, //f2 + 0x3323,0x2133,0x3333,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3133,0x1333,0x1212,0x3333,0x2121,0x3213,0x3213, //f3 + 0x3213,0x3213,0x3321,0x2133,0x3321,0x2133,0x3321,0x2133, + 0x3333,0x3133,0x3213,0x1213,0x3213,0x2111,0x1113,0x3222, //f4 + 0x2213,0x3333,0x3213,0x3333,0x3213,0x3333,0x1133,0x2111, + 0x3333,0x3133,0x3333,0x1213,0x1111,0x2111,0x2222,0x2122, //f5 + 0x3333,0x3213,0x3333,0x3213,0x3333,0x3321,0x1113,0x3332, + 0x3333,0x3133,0x3333,0x1213,0x2133,0x2123,0x1213,0x3232, //f6 + 0x3321,0x3321,0x3332,0x3213,0x3333,0x2133,0x3333,0x3233, + 0x3333,0x3133,0x1333,0x1212,0x1111,0x2111,0x1222,0x3222, //f7 + 0x1213,0x3212,0x1213,0x2132,0x1321,0x2132,0x1321,0x2132, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x3211,0x2123,0x3322, //f8 + 0x1113,0x2113,0x1223,0x3221,0x2133,0x3332,0x1133,0x2111, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x3321,0x2123,0x2132, //f9 + 0x1113,0x3211,0x2121,0x2121,0x1321,0x2132,0x2113,0x3213, + 0x3333,0x3333,0x3213,0x3333,0x3213,0x3213,0x3213,0x2133, //fa + 0x3213,0x2133,0x3213,0x2133,0x1213,0x3232,0x2133,0x3333, + 0x3333,0x3333,0x1133,0x3321,0x2233,0x3332,0x1333,0x3211, //fb + 0x2113,0x2122,0x3223,0x2133,0x3333,0x3213,0x1133,0x3321, + 0x3333,0x3333,0x1133,0x3321,0x2233,0x3332,0x1113,0x3211, //fc + 0x2223,0x3321,0x1333,0x3332,0x2133,0x3321,0x3213,0x2113, + 0x3333,0x3333,0x2133,0x2133,0x1133,0x2121,0x2113,0x3232, //fd + 0x1123,0x3211,0x2113,0x2122,0x2121,0x2133,0x2113,0x3213, + 0x3333,0x3333,0x3333,0x3321,0x2133,0x3213,0x1111,0x2132, //fe + 0x2122,0x2121,0x3213,0x3321,0x3321,0x3321,0x1132,0x3332, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x3211,0x2223,0x3321, //ff + 0x1133,0x2111,0x2233,0x3212,0x3313,0x3323,0x1133,0x3211, + 0x3333,0x3333,0x3333,0x3213,0x3333,0x3321,0x1333,0x3332, //100 + 0x2133,0x3333,0x1333,0x3332,0x3333,0x3321,0x3333,0x3213, + 0x3333,0x3333,0x3333,0x3213,0x1213,0x2111,0x2213,0x3212, //101 + 0x3213,0x3213,0x3213,0x3213,0x2133,0x3213,0x3233,0x3321, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2233,0x2122, //102 + 0x3333,0x3213,0x3333,0x3323,0x3213,0x3333,0x1133,0x2111, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x3211,0x2223,0x3321, //103 + 0x3333,0x3212,0x3333,0x3213,0x3213,0x3333,0x1123,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x3213,0x3333,0x3213,0x3333, //104 + 0x3213,0x3333,0x3213,0x3333,0x3213,0x3213,0x1123,0x3321, + 0x3333,0x3333,0x3333,0x3321,0x1113,0x2111,0x2223,0x3221, //105 + 0x1133,0x3321,0x2133,0x3321,0x1333,0x3321,0x1113,0x3332, + 0x3333,0x3333,0x3333,0x3333,0x3213,0x3321,0x1113,0x2111, //106 + 0x3211,0x3321,0x3212,0x3321,0x3213,0x2133,0x1133,0x3211, + 0x3333,0x3333,0x2133,0x2133,0x2133,0x2133,0x3233,0x3213, //107 + 0x1113,0x2111,0x1223,0x3222,0x2133,0x3333,0x1333,0x2111, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x3211,0x2123,0x3322, //108 + 0x3213,0x2111,0x3213,0x3222,0x1213,0x3332,0x3321,0x2111, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x3211,0x2123,0x3322, //109 + 0x1213,0x3311,0x2113,0x2122,0x3223,0x2133,0x1333,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2211,0x2122, //10a + 0x3322,0x2133,0x3333,0x2133,0x3333,0x3213,0x1133,0x3321, + 0x3333,0x3333,0x3333,0x2113,0x1133,0x3211,0x2211,0x3321, //10b + 0x1322,0x3332,0x1333,0x3332,0x3333,0x3321,0x3333,0x2113, + 0x3333,0x3333,0x3213,0x3333,0x3213,0x2133,0x2133,0x3211, //10c + 0x1133,0x3322,0x2213,0x3333,0x3213,0x3333,0x1133,0x2111, + 0x3333,0x3333,0x2133,0x3333,0x1111,0x2112,0x2212,0x3223, //10d + 0x3213,0x3213,0x1321,0x3211,0x2132,0x2112,0x1333,0x3221, + 0x3333,0x3333,0x3333,0x3333,0x1213,0x2111,0x2213,0x3222, //10e + 0x3213,0x3333,0x3213,0x3333,0x3213,0x3321,0x2133,0x2113, + 0x3333,0x3333,0x3333,0x3321,0x3213,0x3321,0x1213,0x3211, //10f + 0x2113,0x2121,0x1121,0x2112,0x2121,0x2121,0x3213,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x3213,0x3211,0x1211,0x2122, //110 + 0x2112,0x2133,0x3213,0x2111,0x3211,0x2121,0x3212,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x1133,0x3211,0x2113,0x2122, //111 + 0x2121,0x2133,0x2121,0x2133,0x2121,0x2133,0x3213,0x3213, + 0x3333,0x3333,0x3333,0x3213,0x1121,0x2111,0x2221,0x3212, //112 + 0x3321,0x3213,0x1321,0x3211,0x2121,0x2112,0x1332,0x3221, + 0x3333,0x3333,0x2133,0x3333,0x2111,0x3213,0x3212,0x2113, //113 + 0x3321,0x3213,0x3321,0x3213,0x3321,0x3321,0x1113,0x3332, + 0x3333,0x3333,0x1133,0x3333,0x2233,0x3321,0x3333,0x3332, //114 + 0x1213,0x3332,0x3321,0x2121,0x3321,0x2121,0x1132,0x3232, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x1133,0x3332, //115 + 0x2213,0x3321,0x3321,0x3213,0x3332,0x2133,0x3333,0x2233, + 0x3333,0x3333,0x1321,0x2111,0x2321,0x3212,0x1321,0x2111, //116 + 0x2321,0x3212,0x1321,0x3211,0x2121,0x2112,0x1213,0x3221, + 0x3333,0x3333,0x1113,0x3211,0x2223,0x3321,0x1113,0x3211, //117 + 0x2223,0x3321,0x1113,0x3321,0x2221,0x3211,0x1113,0x3322, + 0x3333,0x3333,0x1113,0x3321,0x1223,0x3332,0x2133,0x3213, //118 + 0x1113,0x3211,0x2121,0x2112,0x3211,0x3213,0x3322,0x3321, + 0x3333,0x3333,0x2133,0x3333,0x1111,0x3212,0x2122,0x2133, //119 + 0x2113,0x3333,0x2121,0x2133,0x3213,0x2133,0x1133,0x3211, + 0x3333,0x3333,0x3333,0x3321,0x1213,0x3211,0x2113,0x2121, //11a + 0x1211,0x2132,0x1121,0x2132,0x2121,0x2133,0x3213,0x3213, + 0x3333,0x3333,0x1333,0x3332,0x1113,0x3321,0x2123,0x3332, //11b + 0x1113,0x3321,0x2123,0x2132,0x2133,0x2133,0x1333,0x3211, + 0x3333,0x3333,0x3333,0x3321,0x1213,0x3211,0x2113,0x2121, //11c + 0x3211,0x2132,0x2122,0x3213,0x2133,0x3323,0x1333,0x3332, + 0x3333,0x3333,0x1333,0x3332,0x1321,0x3211,0x1121,0x2122, //11d + 0x1211,0x2132,0x1321,0x2132,0x1332,0x3212,0x2133,0x3323, + 0x3333,0x3333,0x1333,0x3332,0x1333,0x3211,0x1333,0x3322, //11e + 0x1333,0x3332,0x1113,0x3321,0x1221,0x3212,0x2113,0x3323, + 0x3333,0x3333,0x1133,0x3321,0x2233,0x3332,0x2133,0x3211, //11f + 0x1213,0x2122,0x2113,0x2133,0x3223,0x2133,0x1333,0x3211, + 0x3333,0x3333,0x2133,0x3333,0x3213,0x3213,0x3213,0x3213, //120 + 0x2113,0x3213,0x3223,0x3213,0x3333,0x3321,0x1133,0x3332, + 0x3333,0x3333,0x1113,0x3211,0x2223,0x3321,0x1333,0x3211, //121 + 0x2113,0x2122,0x1221,0x2121,0x2132,0x2121,0x1333,0x3211, + 0x3333,0x3333,0x3333,0x3211,0x1213,0x3212,0x1211,0x3212, //122 + 0x2112,0x3213,0x3213,0x3213,0x3211,0x3213,0x3212,0x2133, + 0x3333,0x3333,0x1333,0x3211,0x2113,0x3321,0x1223,0x3332, //123 + 0x1133,0x3211,0x2211,0x2122,0x3322,0x2133,0x1333,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x3213,0x3311,0x1211,0x2122, //124 + 0x2112,0x2133,0x3213,0x2133,0x3211,0x2133,0x3212,0x3211, + 0x3333,0x3333,0x3333,0x3333,0x1333,0x3332,0x1333,0x3332, //125 + 0x2133,0x3333,0x1133,0x3332,0x1213,0x2132,0x3321,0x3211, + 0x3333,0x1313,0x3333,0x2323,0x2133,0x3213,0x1111,0x2132, //126 + 0x2122,0x2121,0x3213,0x3221,0x3321,0x3321,0x1132,0x3332, + 0x3333,0x1313,0x1333,0x2322,0x1113,0x3211,0x2223,0x3321, //127 + 0x1133,0x2111,0x2233,0x3212,0x3313,0x3323,0x1123,0x3211, + 0x3333,0x1313,0x3333,0x2323,0x3333,0x3321,0x1333,0x3332, //128 + 0x2133,0x3333,0x1233,0x3333,0x2333,0x3331,0x3333,0x3312, + 0x3333,0x1313,0x3333,0x2323,0x1213,0x2111,0x3213,0x3213, //129 + 0x3213,0x3213,0x3213,0x3213,0x2123,0x3213,0x3233,0x3321, + 0x3333,0x1313,0x3333,0x2323,0x1133,0x3211,0x2233,0x2122, //12a + 0x3333,0x3213,0x3333,0x3323,0x3213,0x3333,0x1123,0x3111, + 0x3333,0x1313,0x1333,0x2322,0x1113,0x3211,0x2223,0x3321, //12b + 0x3333,0x3212,0x3333,0x3213,0x3213,0x3323,0x1123,0x3211, + 0x3333,0x3333,0x3333,0x3131,0x3213,0x3232,0x3213,0x3333, //12c + 0x3213,0x3333,0x3213,0x3333,0x3213,0x3213,0x1133,0x3321, + 0x3333,0x1313,0x3333,0x2321,0x1113,0x2111,0x2223,0x3321, //12d + 0x1133,0x3321,0x2133,0x3321,0x1333,0x3321,0x1113,0x3332, + 0x3333,0x1313,0x3333,0x2323,0x3213,0x3321,0x1113,0x2111, //12e + 0x2211,0x3221,0x3212,0x3321,0x3213,0x2132,0x1133,0x3211, + 0x3333,0x1313,0x2133,0x2323,0x2133,0x2133,0x3233,0x3213, //12f + 0x1113,0x3111,0x1223,0x3222,0x2133,0x3333,0x1233,0x2111, + 0x3333,0x1313,0x1333,0x2322,0x1113,0x3211,0x2123,0x3322, //130 + 0x3213,0x2111,0x3213,0x3222,0x1213,0x3332,0x2321,0x2111, + 0x3333,0x1313,0x1333,0x2322,0x1113,0x3211,0x2123,0x3322, //131 + 0x1213,0x3211,0x2113,0x2122,0x3223,0x2133,0x1333,0x3211, + 0x3333,0x1313,0x3333,0x2323,0x1133,0x3211,0x2211,0x2122, //132 + 0x3322,0x2133,0x3333,0x2133,0x3333,0x3213,0x1133,0x3321, + 0x3333,0x1313,0x3333,0x2323,0x1133,0x2111,0x2211,0x3221, //133 + 0x1322,0x3332,0x1333,0x3332,0x3333,0x3321,0x3333,0x2113, + 0x3333,0x1313,0x3213,0x2323,0x3213,0x2133,0x2133,0x3211, //134 + 0x1133,0x3322,0x2213,0x3333,0x3213,0x3333,0x1133,0x2111, + 0x3333,0x1313,0x3333,0x2323,0x1121,0x2111,0x2221,0x3212, //135 + 0x3321,0x3213,0x1321,0x3211,0x2121,0x2112,0x1332,0x3221, + 0x3333,0x1313,0x2133,0x2323,0x2111,0x3213,0x3212,0x2113, //136 + 0x3321,0x3213,0x3321,0x3213,0x3321,0x3321,0x1113,0x3332, + 0x3333,0x1313,0x1133,0x2323,0x2233,0x3321,0x3333,0x3332, //137 + 0x1213,0x3332,0x2321,0x2121,0x3321,0x2121,0x1132,0x3232, + 0x3333,0x3333,0x3333,0x3131,0x3333,0x3232,0x1133,0x3332, //138 + 0x2213,0x3321,0x3321,0x3213,0x3332,0x2133,0x3333,0x3233, + 0x3333,0x1313,0x1321,0x2321,0x2321,0x3212,0x1321,0x2111, //139 + 0x2321,0x3212,0x1321,0x3211,0x2121,0x2112,0x1213,0x3221, + 0x3333,0x3133,0x3333,0x1213,0x1121,0x2111,0x2221,0x3212, //13a + 0x3321,0x3213,0x1321,0x3211,0x2121,0x2112,0x1332,0x3221, + 0x3333,0x3133,0x2133,0x1213,0x2111,0x2123,0x3213,0x1113, //13b + 0x3321,0x2213,0x3321,0x3213,0x3321,0x3321,0x1113,0x3332, + 0x3333,0x3133,0x1133,0x1213,0x2233,0x2121,0x3333,0x3232, //13c + 0x1213,0x3332,0x3321,0x2121,0x3321,0x2121,0x1132,0x3232, + 0x3333,0x3313,0x3333,0x2121,0x3333,0x3212,0x1133,0x3322, //13d + 0x2213,0x3321,0x3321,0x3213,0x3332,0x2133,0x3333,0x3233, + 0x3333,0x3133,0x1321,0x1211,0x2321,0x2112,0x1321,0x2111, //13e + 0x2321,0x3212,0x1321,0x3211,0x2121,0x2112,0x1213,0x3221, + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, //13f + 0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333,0x3333, +}; +*/ diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/myFontequ.h b/build/systemMenu_RED/ARM9/src/DS_Setting/myFontequ.h new file mode 100644 index 00000000..5b118478 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/myFontequ.h @@ -0,0 +1,335 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: myFontequ.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __MY_FONT_H__ +#define __MY_FONT_H__ + +// 文字コードの定義 + +#define EOM_ 0x00 // 終了コード + +// オーナー情報編集用ボタン---------------------- +#define CODE_BUTTON_TOP_ 0x200 +#define VAR_BUTTON1_ CODE_BUTTON_TOP_ +#define VAR_BUTTON2_ (CODE_BUTTON_TOP_ + 1) +#define DEL_BUTTON_ (CODE_BUTTON_TOP_ + 2) +#define CANCEL_BUTTON_ (CODE_BUTTON_TOP_ + 3) +#define OK_BUTTON_ (CODE_BUTTON_TOP_ + 4) +#define CODE_BUTTON_BOTTOM_ (CODE_BUTTON_TOP_ + 5) + +/* +// ひらがな---------------------------------------- + +#define a_ 0x0f9 // "あ" +#define i_ 0x0fa // "い" +#define u_ 0x0fb // "う" +#define e_ 0x0fc // "え" +#define o_ 0x0fd // "お" + +#define ka_ 0x0fe // "か" +#define ki_ 0x0ff // "き" +#define ku_ 0x100 // "く" +#define ke_ 0x101 // "け" +#define ko_ 0x102 // "こ" + +#define sa_ 0x103 // "さ" +#define si_ 0x104 // "し" +#define su_ 0x105 // "す" +#define se_ 0x106 // "せ" +#define so_ 0x107 // "そ" + +#define ta_ 0x108 // "た" +#define ti_ 0x109 // "ち" +#define tu_ 0x10a // "つ" +#define te_ 0x10b // "て" +#define to_ 0x10c // "と" + +#define na_ 0x10d // "な" +#define ni_ 0x10e // "に" +#define nu_ 0x10f // "ぬ" +#define ne_ 0x110 // "ね" +#define no_ 0x111 // "の" + +#define ha_ 0x112 // "は" +#define hi_ 0x113 // "ひ" +#define hu_ 0x114 // "ふ" +#define he_ 0x115 // "へ" +#define ho_ 0x116 // "ほ" + +#define ma_ 0x117 // "ま" +#define mi_ 0x118 // "み" +#define mu_ 0x119 // "む" +#define me_ 0x11a // "め" +#define mo_ 0x11b // "も" + +#define ya_ 0x11c // "や" +#define yu_ 0x11d // "ゆ" +#define yo_ 0x11e // "よ" + +#define ra_ 0x11f // "ら" +#define ri_ 0x120 // "り" +#define ru_ 0x121 // "る" +#define re_ 0x122 // "れ" +#define ro_ 0x123 // "ろ" + +#define wa_ 0x124 // "わ" +#define wo_ 0x0f8 // "を" +#define n_ 0x125 // "ん" + + +#define ga_ 0x126 // "が" +#define gi_ 0x127 // "ぎ" +#define gu_ 0x128 // "ぐ" +#define ge_ 0x129 // "げ" +#define go_ 0x12a // "ご" +#define za_ 0x12b // "ざ" +#define zi_ 0x12c // "じ" +#define zu_ 0x12d // "ず" +#define ze_ 0x12e // "ぜ" +#define zo_ 0x12f // "ぞ" +#define da_ 0x130 // "だ" +#define di_ 0x131 // "ぢ" +#define du_ 0x132 // "づ" +#define de_ 0x133 // "で" +#define do_ 0x134 // "ど" +#define ba_ 0x135 // "ば" +#define bi_ 0x136 // "び" +#define bu_ 0x137 // "ぶ" +#define be_ 0x138 // "べ" +#define bo_ 0x139 // "ぼ" +#define pa_ 0x13a // "ぱ" +#define pi_ 0x13b // "ぴ" +#define pu_ 0x13c // "ぷ" +#define pe_ 0x13d // "ぺ" +#define po_ 0x13e // "ぽ" + +#define aa_ 0x08d // "ぁ" +#define ii_ 0x08e // "ぃ" +#define uu_ 0x08f // "ぅ" +#define ee_ 0x090 // "ぇ" +#define oo_ 0x091 // "ぉ" +#define yya_ 0x092 // "ゃ" +#define yyu_ 0x093 // "ゅ" +#define yyo_ 0x094 // "ょ" +#define ttu_ 0x095 // "っ" + + +// カタカナ---------------------------------------- +#define A_ 0x0b1 // "ア" +#define I_ 0x0b2 // "イ" +#define U_ 0x0b3 // "ウ" +#define E_ 0x0b4 // "エ" +#define O_ 0x0b5 // "オ" +#define KA_ 0x0b6 // "カ" +#define KI_ 0x0b7 // "キ" +#define KU_ 0x0b8 // "ク" +#define KE_ 0x0b9 // "ケ" +#define KO_ 0x0ba // "コ" +#define SA_ 0x0bb // "サ" +#define SI_ 0x0bc // "シ" +#define SU_ 0x0bd // "ス" +#define SE_ 0x0be // "セ" +#define SO_ 0x0bf // "ソ" +#define TA_ 0x0c0 // "タ" +#define TI_ 0x0c1 // "チ" +#define TU_ 0x0c2 // "ツ" +#define TE_ 0x0c3 // "テ" +#define TO_ 0x0c4 // "ト" +#define NA_ 0x0c5 // "ナ" +#define NI_ 0x0c6 // "ニ" +#define NU_ 0x0c7 // "ヌ" +#define NE_ 0x0c8 // "ネ" +#define NO_ 0x0c9 // "ノ" +#define HA_ 0x0ca // "ハ" +#define HI_ 0x0cb // "ヒ" +#define HU_ 0x0cc // "フ" +#define HE_ 0x0cd // "ヘ" +#define HO_ 0x0ce // "ホ" +#define MA_ 0x0cf // "マ" +#define MI_ 0x0d0 // "ミ" +#define MU_ 0x0d1 // "ム" +#define ME_ 0x0d2 // "メ" +#define MO_ 0x0d3 // "モ" +#define YA_ 0x0d4 // "ヤ" +#define YU_ 0x0d5 // "ユ" +#define YO_ 0x0d6 // "ヨ" +#define RA_ 0x0d7 // "ラ" +#define RI_ 0x0d8 // "リ" +#define RU_ 0x0d9 // "ル" +#define RE_ 0x0da // "レ" +#define RO_ 0x0db // "ロ" +#define WA_ 0x0dc // "ワ" +#define WO_ 0x0a6 // "ヲ" +#define N_ 0x0dd // "ン" + +#define GA_ 0x0de // "ガ" +#define GI_ 0x0df // "ギ" +#define GU_ 0x0e0 // "グ" +#define GE_ 0x0e1 // "ゲ" +#define GO_ 0x0e2 // "ゴ" +#define ZA_ 0x0e3 // "ザ" +#define ZI_ 0x0e4 // "ジ" +#define ZU_ 0x0e5 // "ズ" +#define ZE_ 0x0e6 // "ゼ" +#define ZO_ 0x0e7 // "ゾ" +#define DA_ 0x0e8 // "ダ" +#define DI_ 0x0e9 // "ヂ" +#define DU_ 0x0ea // "ヅ" +#define DE_ 0x0eb // "デ" +#define DO_ 0x0ec // "ド" +#define BA_ 0x0ed // "バ" +#define BI_ 0x0ee // "ビ" +#define BU_ 0x0ef // "ブ" +#define BE_ 0x0f0 // "ベ" +#define BO_ 0x0f1 // "ボ" +#define VU_ 0x0f2 // "ヴ" +#define PA_ 0x0f3 // "パ" +#define PI_ 0x0f4 // "ピ" +#define PU_ 0x0f5 // "プ" +#define PE_ 0x0f6 // "ペ" +#define PO_ 0x0f7 // "ポ" + +#define AA_ 0x0a7 // "ァ" +#define II_ 0x0a8 // "ィ" +#define UU_ 0x0a9 // "ゥ" +#define EE_ 0x0aa // "ェ" +#define OO_ 0x0ab // "ォ" +#define YYA_ 0x0ac // "ャ" +#define YYU_ 0x0ad // "ュ" +#define YYO_ 0x0ae // "ョ" +#define TTU_ 0x0af // "ッ" + + +// アルファベット大文字---------------------------- +#define A__ 0x041 // "A" +#define B__ 0x042 // "B" +#define C__ 0x043 // "C" +#define D__ 0x044 // "D" +#define E__ 0x045 // "E" +#define F__ 0x046 // "F" +#define G__ 0x047 // "G" +#define H__ 0x048 // "H" +#define I__ 0x049 // "I" +#define J__ 0x04a // "J" +#define K__ 0x04b // "K" +#define L__ 0x04c // "L" +#define M__ 0x04d // "M" +#define N__ 0x04e // "N" +#define O__ 0x04f // "O" +#define P__ 0x050 // "P" +#define Q__ 0x051 // "Q" +#define R__ 0x052 // "R" +#define S__ 0x053 // "S" +#define T__ 0x054 // "T" +#define U__ 0x055 // "U" +#define V__ 0x056 // "V" +#define W__ 0x057 // "W" +#define X__ 0x058 // "X" +#define Y__ 0x059 // "Y" +#define Z__ 0x05a // "Z" + + +// アルファベット小文字---------------------------- +#define a__ 0x061 // "a" +#define b__ 0x062 // "b" +#define c__ 0x063 // "c" +#define d__ 0x064 // "d" +#define e__ 0x065 // "e" +#define f__ 0x066 // "f" +#define g__ 0x067 // "g" +#define h__ 0x068 // "h" +#define i__ 0x069 // "i" +#define j__ 0x06a // "j" +#define k__ 0x06b // "k" +#define l__ 0x06c // "l" +#define m__ 0x06d // "m" +#define n__ 0x06e // "n" +#define o__ 0x06f // "o" +#define p__ 0x070 // "p" +#define q__ 0x071 // "q" +#define r__ 0x072 // "r" +#define s__ 0x073 // "s" +#define t__ 0x074 // "t" +#define u__ 0x075 // "u" +#define v__ 0x076 // "v" +#define w__ 0x077 // "w" +#define x__ 0x078 // "x" +#define y__ 0x079 // "y" +#define z__ 0x07a // "z" + + +// 数字-------------------------------------------- +#define n0_ 0x030 // "0" +#define n1_ 0x031 // "1" +#define n2_ 0x032 // "2" +#define n3_ 0x033 // "3" +#define n4_ 0x034 // "4" +#define n5_ 0x035 // "5" +#define n6_ 0x036 // "6" +#define n7_ 0x037 // "7" +#define n8_ 0x038 // "8" +#define n9_ 0x039 // "9" + +// 記号-------------------------------------------- +#define spc_ 0x020 // " " +#define bicri_ 0x021 // "!" +#define cyoncyon_ 0x022 // "”" +#define sharp_ 0x023 // "#" +#define dollar_ 0x024 // "#" +#define percent_ 0x025 // "%" +#define and_ 0x026 // "&" +#define cyon_ 0x027 // "’" +#define kakko_ 0x028 // "(" +#define kakkot_ 0x029 // ")" +#define kome_ 0x02a // "*" +#define tasu_ 0x02b // "+" +#define comma_ 0x02c // "," +#define hiku_ 0x02d // "−" +#define period_ 0x02e // "." +#define sura_ 0x02f // "/" + +#define colon_ 0x03a // ":" +#define semicolon_ 0x03b // ";" +#define dainari_ 0x03c // "<" +#define equal_ 0x03d // "=" +#define syounari_ 0x03e // ">" +#define hate_ 0x03f // "?" + +#define atomark_ 0x040 // "@" +#define dkakko_ 0x05b // "[" +#define bsura_ 0x05c // "/" +#define dkakkot_ 0x05d // "]" +#define yama_ 0x05e // "^" +#define uscore_ 0x05f // "_" + +#define bcyon_ 0x060 // "‘" +#define ckakko_ 0x07b // "{" +#define mataha_ 0x07c // "|" +#define ckakkot_ 0x07d // "}" +#define kara_ 0x07e // "〜" + +#define kten_ 0x0a1 // "。" +#define k_kakko_ 0x0a2 // "「" +#define k_kakkot_ 0x0a3 // "」" +#define tten_ 0x0a4 // "、" +#define nakat_ 0x0a5 // "・" +#define bou_ 0x0b0 // "ー" + +#define yazi_ 0x08c // "▼" +*/ + +#endif /* __MY_FONT_H_ */ diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/ownerInfo.c b/build/systemMenu_RED/ARM9/src/DS_Setting/ownerInfo.c new file mode 100644 index 00000000..6d91d5c9 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/ownerInfo.c @@ -0,0 +1,1077 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: ownerInfo.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "misc.h" +#include "DS_Setting.h" +#include "myFontequ.h" + +/* + + ※ニックネームは、現在SJISで保存していますが、NVRAMには各文字コードのHi/Loを逆転した形で格納しています。 + +*/ + +// define data---------------------------------- + +#define OWNER_INFO_ELEM_NUM 3 + + // RETURNボタンLCD領域 +#define RETURN_BUTTON_LT_X 2 +#define RETURN_BUTTON_LT_Y 21 +#define RETURN_BUTTON_RB_X (RETURN_BUTTON_LT_X + 8) +#define RETURN_BUTTON_RB_Y (RETURN_BUTTON_LT_Y + 2) + + // オーナー情報カーソルLCD領域 +#define OWNER_INFO_CSR_LT_X 2 +#define OWNER_INFO_CSR_LT_Y 5 +#define OWNER_INFO_CSR_NEXT_Y_NUM 3 + + // 生年月日情報カーソルLCD領域 +#define DAY_LT_X (OWNER_INFO_CSR_LT_X + 13) +#define DAY_LT_Y (OWNER_INFO_CSR_LT_Y + OWNER_INFO_CSR_NEXT_Y_NUM * 1) + + // 好きな色カーソルLCD領域 +#define FCOLOR_LT_X (OWNER_INFO_CSR_LT_X + 13) +#define FCOLOR_LT_Y (OWNER_INFO_CSR_LT_Y + OWNER_INFO_CSR_NEXT_Y_NUM * 2) + + // ソフトウェアキーボードLCD領域 +#define CLIST_LT_X 4 +#define CLIST_LT_Y 7 +#define CLIST_RB_X (CLIST_LT_X + 24) +#define CLIST_RB_Y (CLIST_LT_Y + 12) + // ボタン先頭LCD領域 +#define BUTTON_TOP_LT_X (CLIST_LT_X + 18) +#define BUTTON_TOP_LT_Y (CLIST_LT_Y + 2) +#define BUTTON_TOP_RB_X (BUTTON_TOP_LT_X + 8) +#define BUTTON_TOP_RB_Y (BUTTON_TOP_LT_Y + 2) + // 入力ネームLCD領域 +#define INPUT_NAME_LT_X 11 +#define INPUT_NAME_LT_Y 3 + // キャラクタコード +#define CHAR_MODE_HKANA 0 +#define CHAR_MODE_KKANA 1 +#define CHAR_MODE_EISUU 2 +#define CHAR_MODE_MAX CHAR_MODE_EISUU + + // ニックネーム未入力キャラ +#define CHAR_USCORE 0x5181 // '_' (0x8151)を逆転させたもの。 + +#define CHAR_LIST_CHAR_NUM 120 + + // ニックネーム入力構造体 +typedef struct Nickname { + u8 input_flag; // 入力フラグ + u8 change_flag; // 変更フラグ + u8 length; // 文字数 + u8 pad; + u16 str[NCD_NICKNAME_LENGTH + 1]; // ニックネームコード +}Nickname; + + // カーソルX,Y位置(キャラ単位) +typedef struct CsrPos { + u16 x; // x + u16 y; // y +}CsrPos; + + // 誕生日情報 +typedef struct Birthday { + int year; // 年(1900-2099) + int month; // 月(1-12) + int day; // 日(1-31) +}Birthday; + + // プロフィール編集ワーク +typedef struct OwnerWork { + u16 sel; + Nickname nickname; // ニックネーム + Birthday birthday; // 生年月日 + int favoriteColor; // 好きな色 + + // ユーザーカラー&生年月日入力ワーク + int seq; // シーケンス番号 + int *tgtp; // 入力ターゲットへのポインタ + InputNumParam inp; // 数値入力関数InputDecimal用パラメータ + + // ニックネーム入力ワーク + u16 char_mode; // 入力キャラクタモード(かな、カナ、英数) + u16 rsv; // 構造体CsrPosのアラインメント調整のためのパディング + CsrPos tpcsr; // TPによって算出したカーソル位置 + CsrPos csr_now; // 現在のカーソル位置(キーとTPの両方から算出した有効な値) + CsrPos csr_old; // 前フレームのカーソル位置 + u16 detach_count; // TPが有効なカーソル位置から離されてからのカウント値 + u16 touch_count; // TPが有効なカーソル位置でタッチされている状態のカウント値 + u16 handleTbl[CHAR_LIST_CHAR_NUM]; // キャラクタリスト用ハンドル格納配列 +}OwnerWork; + +// extern data---------------------------------- + + +// function's prototype------------------------- +void SEQ_OwnerInfo_init(void); +int SEQ_OwnerInfo(void); + +static void SEQ_InputBirthday_init(void); +static int SEQ_InputBirthday(void); +static void SEQ_InputFavoriteColor_init(void); +static int SEQ_InputFavoriteColor(void); +static void DrawBirthday(u16 x, u16 y, u16 color, NvDate *birthp); +static void SEQ_InputNickname_init(void); +static int SEQ_InputNickname(void); +static void ReturnMenu(int save_flag); +static u16 CalcTblIndex(CsrPos *csrp); +static void DeleteName1Char(void); +static void MoveCharCursor(int force_flag); +static BOOL MoveCharCursorTp(CsrPos *csrp); +static void DrawTargetCsrChar(CsrPos *csrp, u16 color); +static void DrawCharacterList(void); +static void SetSoftKeyboardButton(u16 char_mode); +static void SJISCodeExchangeCopy(u16 *srcp, u16 *dstp, u16 length); + +// static variable------------------------------ +static OwnerWork *ow; + +// const data----------------------------------- +static const u16 char_tbl[3][CHAR_LIST_CHAR_NUM]; + +static const u8 *const str_ownerInfoSel[] ATTRIBUTE_ALIGN(2) = { + (const u8 *)"NICKNAME ", + (const u8 *)"BIRTHDAY ", + (const u8 *)"USER COLOR", +}; + +const MenuComponent ownerInfoSel={ + OWNER_INFO_ELEM_NUM, + OWNER_INFO_CSR_LT_X, + OWNER_INFO_CSR_LT_Y, + 0, + OWNER_INFO_CSR_NEXT_Y_NUM, + 23, + WHITE, + HIGHLIGHT_Y, + (const u8 **)&str_ownerInfoSel, +}; + +static const u8 str_button_hkana[] ATTRIBUTE_ALIGN(2) = " かな "; +static const u8 str_button_kkana[] ATTRIBUTE_ALIGN(2) = " カナ "; +static const u8 str_button_eisuu[] ATTRIBUTE_ALIGN(2) = " ABC "; +static const u8 str_button_del[] ATTRIBUTE_ALIGN(2) = " DEL "; +static const u8 str_button_cancel[] ATTRIBUTE_ALIGN(2) = "CANCEL"; +static const u8 str_button_ok[] ATTRIBUTE_ALIGN(2) = " OK "; +static const u16 *str_button[] = { NULL, + NULL, + (const u16 *)str_button_del, + (const u16 *)str_button_cancel, + (const u16 *)str_button_ok, + }; +//static const u16 str_uscore[] = { uscore_, uscore_, uscore_, uscore_, uscore_, uscore_, uscore_, uscore_, EOM_}; + +//====================================================== +// オーナー情報編集 +//====================================================== + +// オーナー情報編集の初期化 +void SEQ_OwnerInfo_init(void) +{ + u16 x,y; + u16 temp[NCD_NICKNAME_LENGTH + 1]; + + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + MI_CpuClearFast(bgBakS,sizeof(bgBakS)); + SVC_CpuClearFast(0xc0, oamBakS, sizeof(oamBakS)); + + ClearAllStringSJIS(); + + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"USER INFO SET"); + (void)DrawStringSJIS( RETURN_BUTTON_LT_X, RETURN_BUTTON_LT_Y,HIGHLIGHT_C, (const u8 *)" RETURN "); + + if(ow == NULL) { + ow = OS_Alloc(sizeof(OwnerWork)); // オーナー情報編集用ワークの確保 +#ifdef __SYSM_DEBUG + if(ow == NULL) OS_Panic("ARM9- Fail to allocate memory...\n"); +#endif /* __SYSM_DEBUG */ + OS_Printf("Alloc :OwnerWork\n"); + SVC_CpuClear(0x0000, ow, sizeof(OwnerWork), 16); + } + + // オーナー情報のチェック + { + u32 dayNum; + + if(GetNCDWork()->owner.nickname.length > NCD_NICKNAME_LENGTH) { + GetNCDWork()->owner.nickname.length = 0; + SVC_CpuClear(0x0000, GetNCDWork()->owner.nickname.str, NCD_NICKNAME_LENGTH * 2, 16); + } + if((GetNCDWork()->owner.birthday.month == 0) || (GetNCDWork()->owner.birthday.month > 12)) { + GetNCDWork()->owner.birthday.month = 1; + } + dayNum = SYSM_GetDayNum( 0, (u32)GetNCDWork()->owner.birthday.month ); + if((GetNCDWork()->owner.birthday.day == 0) || (GetNCDWork()->owner.birthday.day > dayNum)) { + GetNCDWork()->owner.birthday.day = 1; + } + if( GetNCDWork()->owner.favoriteColor >= NCD_FAVORITE_COLOR_MAX_NUM ) { + GetNCDWork()->owner.favoriteColor = 0; + } + } + + // オーナー情報の表示 + x = (u16)(ownerInfoSel.pos_x+13); + y = (u16)ownerInfoSel.pos_y; + SVC_CpuClear(0x0000, temp, sizeof(temp), 16); + ExUTF16_LEtoSJIS_BE( (u8 *)temp, GetNCDWork()->owner.nickname.str, GetNCDWork()->owner.nickname.length); + (void)DrawStringSJIS ( x, y, LIGHTGREEN, temp); + DrawBirthday ( x, (u16)(y + OWNER_INFO_CSR_NEXT_Y_NUM * 1), LIGHTGREEN, &GetNCDWork()->owner.birthday); + ow->favoriteColor = GetNCDWork()->owner.favoriteColor; + (void)DrawDecimalSJIS( x, (u16)(y + OWNER_INFO_CSR_NEXT_Y_NUM * 2), LIGHTGREEN, &ow->favoriteColor, 2, 1); + + DrawMenu(ow->sel, &ownerInfoSel); + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + + GXS_SetVisiblePlane(GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1); +} + + +// オーナー情報編集 +int SEQ_OwnerInfo(void) +{ + BOOL tp_select; + BOOL tp_return = FALSE; + + ReadTpData(); // タッチパネル入力の取得 + + if(tpd.disp.touch) { // [RETURN]ボタン押下チェック + tp_return = InRangeTp(RETURN_BUTTON_LT_X*8, RETURN_BUTTON_LT_Y*8-4, + RETURN_BUTTON_RB_X*8, RETURN_BUTTON_RB_Y*8-4, &tpd.disp); + } + + // オーナー情報の初回起動シーケンス + if(initialSet) { + + pad.trg = 0; + + if(GetNCDWork()->option.input_nickname == 0) { + ow->sel = 0; + pad.trg |= PAD_BUTTON_A; + }else if(GetNCDWork()->option.input_favoriteColor == 0) { + ow->sel = 2; + pad.trg |= PAD_BUTTON_A; + }else if(GetNCDWork()->option.input_birthday == 0) { + ow->sel = 1; + pad.trg |= PAD_BUTTON_A; + }else if ( GetNCDWork()->option.input_nickname + || GetNCDWork()->option.input_favoriteColor + || GetNCDWork()->option.input_birthday ) { + pad.trg |= PAD_BUTTON_B; // メニューに戻らす + } + } + + //-------------------------------------- + // キー入力処理 + //-------------------------------------- + if(pad.trg & PAD_KEY_DOWN){ // カーソルの移動 + if(++ow->sel == OWNER_INFO_ELEM_NUM) ow->sel= 0; + } + if(pad.trg & PAD_KEY_UP){ + if(--ow->sel & 0x80) ow->sel = OWNER_INFO_ELEM_NUM - 1; + } + tp_select=SelectMenuByTp(&ow->sel, &ownerInfoSel); + DrawMenu(ow->sel, &ownerInfoSel); + + if((pad.trg & PAD_BUTTON_A) || (tp_select)) { // メニュー項目への分岐 + + mf_clearRect( RETURN_BUTTON_LT_X, RETURN_BUTTON_LT_Y, 2, 8); + DrawOKCancelButton(); + + switch(ow->sel) { + case 0: + SEQ_InputNickname_init(); + nowProcess = SEQ_InputNickname; + break; + case 1: + SEQ_InputBirthday_init(); + nowProcess = SEQ_InputBirthday; + break; + case 2: + SEQ_InputFavoriteColor_init(); + nowProcess = SEQ_InputFavoriteColor; + break; + } + }else if((pad.trg & PAD_BUTTON_B) || (tp_return)) { // メニューに戻る + OS_Free(ow); // ワークの解放 + ow = NULL; + OS_Printf("Free :OwnerWork\n"); + SEQ_MainMenu_init(); + } + + return 0; +} + + +//====================================================== +// 生年月日入力 +//====================================================== + +// 生年月日入力の初期化 +static void SEQ_InputBirthday_init(void) +{ + // 生年月日の表示 + DrawBirthday((u16)(ownerInfoSel.pos_x + 13), (u16)(ownerInfoSel.pos_y + OWNER_INFO_CSR_NEXT_Y_NUM * 1), WHITE, &GetNCDWork()->owner.birthday); + // 生年月日情報のロード + ow->birthday.month = (int)GetNCDWork()->owner.birthday.month; + ow->birthday.day = (int)GetNCDWork()->owner.birthday.day; + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + ow->seq = 0; +} + + +// 生年月日入力 +static int SEQ_InputBirthday(void) +{ + BOOL tp_ok = FALSE; + BOOL tp_cancel = FALSE; + int x_base, y_base, abs_y_offset, new_seq; + + enum { // 日付入力シーケンス番号 + SEQ_INIT = 0, + SEQ_MONTH_INIT = 2, SEQ_MONTH_SET, + SEQ_DAY_INIT, SEQ_DAY_SET, + SEQ_END, + SEQ_RETURN=64 + }; + + + ReadTpData(); // タッチパネル入力の取得 + + ow->inp.y_offset = 0; + + CheckOKCancelButton(&tp_ok, &tp_cancel); + + if(tpd.disp.touch) { // [CANCEL]ボタン押下チェック + if((ow->seq & 0x01) && (ow->seq < SEQ_END)) { // SEQ_**_SETの時のみ有効 + new_seq = ow->seq; + x_base = (ownerInfoSel.pos_x + 13) * 8; + y_base = (ownerInfoSel.pos_y + OWNER_INFO_CSR_NEXT_Y_NUM * 1) * 8 + 6; + // 入力項目移動のチェック + if( InRangeTp( x_base, (y_base - 6), (x_base + 80), (y_base + 6), &tpd.disp) ) { + if(tpd.disp.x < x_base + 2 * 8) { + new_seq = SEQ_MONTH_SET; + }else if((tpd.disp.x >= x_base + 3 * 8) && (tpd.disp.x < x_base + 5 * 8)) { + new_seq = SEQ_DAY_SET; + }else if(tpd.disp.x >= x_base + 7 * 8) { + } + } + if(ow->seq != new_seq) { + ow->seq = new_seq - 1; + }else { + // 入力値の増減 + if(InRangeTp( ow->inp.pos_x * 8, (y_base - 30), (ow->inp.pos_x + ow->inp.keta_max) * 8, (y_base + 30), &tpd.disp)) { + ow->inp.y_offset = tpd.disp.y - y_base; + abs_y_offset = (ow->inp.y_offset >= 0) ? ow->inp.y_offset : -ow->inp.y_offset; + if(abs_y_offset <= 6) { + ow->inp.y_offset = 0; + }else if(abs_y_offset <= 14){ + ow->inp.y_offset >>= 2; + }else if(abs_y_offset <= 22){ + ow->inp.y_offset >>= 1; + } + } + } + } + } + + // タッチパネル or キー入力によって、カーソル位置が動いた時に、元の位置のカーソルを消す。 + if((ow->seq > 0) && ((ow->seq & 0x01) == 0)) { // SEQ_INITの時は実行しない + (void)DrawDecimalSJIS( ow->inp.pos_x, ow->inp.pos_y, WHITE, ow->tgtp, (u8)ow->inp.keta_max, 4); + } + + // 各シーケンスにおける処理 + switch(ow->seq){ + case SEQ_INIT: + ow->seq = SEQ_MONTH_INIT; + // そのままSEQ_MONTH_INITへ + + case SEQ_MONTH_INIT: + ow->inp.pos_x = DAY_LT_X; + ow->inp.pos_y = DAY_LT_Y; + ow->inp.keta_max = 2; + ow->inp.value_max = 12; + ow->inp.value_min = 1; + ow->inp.y_offset = 0; + ow->tgtp = (int *)&ow->birthday.month; + break; + + case SEQ_DAY_INIT: + ow->inp.pos_x = DAY_LT_X + 3; + ow->inp.keta_max = 2; + ow->inp.value_min = 1; + ow->inp.value_max = (int)SYSM_GetDayNum( 0, (u32)ow->birthday.month ); + // 年・月をもとにその月の日数を算出する。 + if(ow->birthday.day > ow->inp.value_max) { + ow->birthday.day = ow->inp.value_max; + } + ow->inp.y_offset = 0; + ow->tgtp = (int *)&ow->birthday.day; + break; + + case SEQ_MONTH_SET: + case SEQ_DAY_SET: + InputDecimal(ow->tgtp, &ow->inp); + + // 月入力ならば、日数を算出して、現在の入力日が日数を超えていたら修正する。 + if(ow->seq == SEQ_MONTH_SET) { + u32 dayNum = SYSM_GetDayNum( 0, (u32)ow->birthday.month ); + if( dayNum < ow->birthday.day) { + ow->birthday.day = (u8)dayNum; + (void)DrawDecimalSJIS( DAY_LT_X + 3, DAY_LT_Y, WHITE, &ow->birthday.day, 2, 4); + } + } + break; + + case SEQ_END: + GetNCDWork()->owner.birthday.month = (u8 )ow->birthday.month; + GetNCDWork()->owner.birthday.day = (u8 )ow->birthday.day; + GetNCDWork()->option.input_birthday = 1; + GetSYSMWork()->ncd_invalid = 0; + + if ( GetNCDWork()->option.destroyFlashFlag ) { + GetNCDWork()->option.destroyFlashFlag = 0; + } + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData (GetNCDWork()); + + // SEQ_ENDの時はこのままリターンする。 + + case SEQ_RETURN: + SEQ_OwnerInfo_init(); + nowProcess = SEQ_OwnerInfo; + return 0; + } + + if(ow->seq & 0x01) { // SEQ_**_SETの時のみ有効 + if((pad.trg & PAD_BUTTON_A) || (tp_ok)) { + ow->seq = SEQ_END; // Aボタンで決定 + }else if((pad.trg & PAD_BUTTON_B) || (tp_cancel)) { // Bボタンでキャンセル + ow->seq = SEQ_RETURN; + }else if(pad.trg & PAD_KEY_LEFT) { + if(ow->seq == SEQ_MONTH_SET) ow->seq = SEQ_DAY_INIT; + else ow->seq -= 3; + }else if(pad.trg & PAD_KEY_RIGHT) { + if(ow->seq == SEQ_DAY_SET) ow->seq = SEQ_MONTH_INIT; + else ow->seq++; + } + }else { // SEQ_**_INITの時のみ有効 + ow->seq++; + } + return 0; +} + + +// 生年月日の描画 +static void DrawBirthday(u16 x, u16 y, u16 color, NvDate *birthp) +{ + (void)DrawStringSJIS ( (u16)(x + 2), y, color, (const u8 *)"/"); + (void)DrawDecimalSJIS( x, y, color, &birthp->month, 2, 1); + (void)DrawDecimalSJIS( (u16)(x + 3), y, color, &birthp->day, 2, 1); +} + + +//====================================================== +// 好きな色入力 +//====================================================== + +// 好きな色入力の初期化 +static void SEQ_InputFavoriteColor_init(void) +{ + // 好きな色のロード + ow->favoriteColor = (int)GetNCDWork()->owner.favoriteColor; + // 好きな色の表示 + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + ow->seq = 0; + + if( initialSet ) { + (void)DrawStringSJIS( 8, 18, RED, (const u8 *)"Select user color."); + } +} + + +// 好きな色入力 +static int SEQ_InputFavoriteColor(void) +{ + BOOL tp_ok = FALSE; + BOOL tp_cancel = FALSE; + int x_base, y_base, abs_y_offset, new_seq; + + enum { // 日付入力シーケンス番号 + SEQ_INIT = 0, SEQ_SET, + SEQ_END, + SEQ_RETURN=64 + }; + + + ReadTpData(); // タッチパネル入力の取得 + + ow->inp.y_offset = 0; + + CheckOKCancelButton(&tp_ok, &tp_cancel); + + if(tpd.disp.touch) { // [CANCEL]ボタン押下チェック + if((ow->seq & 0x01) && (ow->seq < SEQ_END)) { // SEQ_**_SETの時のみ有効 + new_seq = ow->seq; + x_base = FCOLOR_LT_X * 8; + y_base = FCOLOR_LT_Y * 8 + 6; + // 入力値の増減 + if(InRangeTp( ow->inp.pos_x * 8, (y_base - 30), (ow->inp.pos_x + ow->inp.keta_max) * 8, (y_base + 30), &tpd.disp)) { + ow->inp.y_offset = tpd.disp.y - y_base; + abs_y_offset = (ow->inp.y_offset >= 0) ? ow->inp.y_offset : -ow->inp.y_offset; + if(abs_y_offset <= 6) { + ow->inp.y_offset = 0; + }else if(abs_y_offset <= 14){ + ow->inp.y_offset >>= 2; + }else if(abs_y_offset <= 22){ + ow->inp.y_offset >>= 1; + } + } + } + } + + // 各シーケンスにおける処理 + switch(ow->seq){ + case SEQ_INIT: + ow->inp.pos_x = FCOLOR_LT_X; + ow->inp.pos_y = FCOLOR_LT_Y; + ow->inp.keta_max = 2; + ow->inp.value_max = NCD_FAVORITE_COLOR_MAX_NUM - 1; + ow->inp.value_min = 0; + ow->inp.y_offset = 0; + ow->tgtp = (int *)&ow->favoriteColor; + break; + + case SEQ_SET: + InputDecimal(ow->tgtp, &ow->inp); + break; + + case SEQ_END: + GetNCDWork()->option.input_favoriteColor = 1; + GetNCDWork()->owner.favoriteColor = (u8 )ow->favoriteColor; + GetSYSMWork()->ncd_invalid = 0; + + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData (GetNCDWork()); + + // SEQ_ENDの時はこのままリターンする。 + + case SEQ_RETURN: + SEQ_OwnerInfo_init(); + nowProcess = SEQ_OwnerInfo; + return 0; + } + + if(ow->seq & 0x01) { // SEQ_**_SETの時のみ有効 + if((pad.trg & PAD_BUTTON_A) || (tp_ok)) { + ow->seq = SEQ_END; // Aボタンで決定 + }else if((pad.trg & PAD_BUTTON_B) || (tp_cancel)) { // Bボタンでキャンセル + ow->seq = SEQ_RETURN; + } + }else { // SEQ_**_INITの時のみ有効 + ow->seq++; + } + return 0; +} + + +//====================================================== +// ニックネームの入力 +//====================================================== + +// ニックネーム入力の初期化 +static void SEQ_InputNickname_init(void) +{ + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + MI_CpuClearFast(bgBakS, sizeof(bgBakS)); + + ClearAllStringSJIS(); + + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"INPUT NICKNAME"); +// (void)DrawStringSJIS( INPUT_NAME_LT_Y, WHITE, (const u16 *)str_uscore); + if( initialSet ) { + (void)DrawStringSJIS( 8, 20, RED, (const u8 *)"Input nickname."); + } + + // ニックネームをUTF16からSJISに変換してコピー + SVC_CpuClear(CHAR_USCORE, ow->nickname.str, NCD_NICKNAME_LENGTH * 2, 16); + if(GetSYSMWork()->ncd_invalid == 0) { + ExUTF16_LEtoSJIS_BE( (u8 *)ow->nickname.str, GetNCDWork()->owner.nickname.str, GetNCDWork()->owner.nickname.length); + ow->nickname.length = GetNCDWork()->owner.nickname.length; + ow->nickname.input_flag = 1; + } + ow->nickname.change_flag = 0; + (void)DrawStringSJIS( INPUT_NAME_LT_X, INPUT_NAME_LT_Y, WHITE, (const u16 *)ow->nickname.str); + + ow->char_mode = CHAR_MODE_HKANA; // 「ひらがな」入力をセット + SetSoftKeyboardButton(ow->char_mode); // 初期ボタンのセット + ow->detach_count = 0; + ow->touch_count = 0; + ow->tpcsr.x = 0; + ow->tpcsr.y = 0; + ow->csr_now.x = 0; + ow->csr_now.y = 0; + ow->csr_now.x = 15; + ow->csr_now.y = 5; + DrawCharacterList(); // 入力キャラ一覧の描画 + MoveCharCursor(1); // カーソル表示 + + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + + GXS_SetVisiblePlane(GX_PLANEMASK_BG1); +} + + +// ニックネームの入力 +static int SEQ_InputNickname(void) +{ + BOOL tp_input = FALSE; + u16 tbl_index, charCode; + const u16 *char_listp; + + ow->csr_old = ow->csr_now; // 前フレームのカーソル位置を保存 + + ReadTpData(); // タッチパネル入力の取得 + + tp_input = MoveCharCursorTp(&ow->csr_now); // TP入力によるカーソル移動 + + // カーソル移動 + char_listp = char_tbl[ow->char_mode]; + if(pad.trg & PAD_KEY_UP) { + while(1) { + if(--ow->csr_now.y & 0x8000) ow->csr_now.y = 5; + tbl_index = CalcTblIndex(&ow->csr_now); + if(char_listp[tbl_index]) { + break; + }else if(ow->csr_now.x > 15) { + ow->csr_now.x = 15; + ow->csr_now.y = 6; // 次のループで-1されて5になる。 + } + } + }else if(pad.trg & PAD_KEY_DOWN) { + while(1) { + if(++ow->csr_now.y > 5) ow->csr_now.y = 0; + tbl_index = CalcTblIndex(&ow->csr_now); + if(char_listp[tbl_index]) { + break; + }else if(ow->csr_now.x > 15) { + ow->csr_now.x--; + ow->csr_now.y--; + } + } + } + + if(pad.trg & PAD_KEY_LEFT) { + while(1) { + if(--ow->csr_now.x & 0x8000) ow->csr_now.x = 18; + tbl_index = CalcTblIndex(&ow->csr_now); + if(char_listp[tbl_index]) { + break; + } + } + }else if(pad.trg & PAD_KEY_RIGHT) { + while(1) { + if(++ow->csr_now.x > 18) ow->csr_now.x = 0; + tbl_index = CalcTblIndex(&ow->csr_now); + if(char_listp[tbl_index]) { + break; + } + } + } + + if(pad.trg & PAD_BUTTON_START) { + ow->csr_now.x = 15; + ow->csr_now.y = 5; + } + + // 入力文字切り替え + if(pad.trg & (PAD_BUTTON_R | PAD_BUTTON_L)) { + if(pad.trg & PAD_BUTTON_R) { + if(++ow->char_mode > CHAR_MODE_MAX) ow->char_mode = 0; + }else { + if(--ow->char_mode & 0x8000) ow->char_mode = CHAR_MODE_MAX; + } + SetSoftKeyboardButton(ow->char_mode); + while(1) { + tbl_index = CalcTblIndex(&ow->csr_now); + if(char_tbl[ow->char_mode][tbl_index]) { + break; + } + ow->csr_now.x--; + } + DrawCharacterList(); + } + + charCode = (u16)char_listp[CalcTblIndex(&ow->csr_now)]; + MoveCharCursor(0); + + if((pad.trg & PAD_BUTTON_A)||(tp_input)) { + // 右端コマンド + if((charCode == VAR_BUTTON1_)||(charCode == VAR_BUTTON2_)) {// 入力文字切り替え + ow->char_mode = (u16)(ow->char_mode + 1 + charCode - CODE_BUTTON_TOP_); + if(ow->char_mode > CHAR_MODE_MAX) ow->char_mode -= CHAR_MODE_MAX+1; + SetSoftKeyboardButton(ow->char_mode); + DrawCharacterList(); + }else if(charCode == OK_BUTTON_) { // 決定 + ReturnMenu(1); + }else if(charCode == CANCEL_BUTTON_){ // キャンセル + ReturnMenu(0); + }else if(charCode == DEL_BUTTON_) { // 1文字削除 + DeleteName1Char(); + }else { + if(ow->nickname.length < NCD_NICKNAME_LENGTH) { // 一文字入力 + ow->nickname.str[ow->nickname.length] = (u16)((charCode >> 8) | (charCode << 8)); + // SJIS・ASCII混載文字列の際にこれらを判別できるよう、SJISをHi,Loの順で格納。 + ow->nickname.length++; + ow->nickname.change_flag = 1; + (void)DrawStringSJIS( INPUT_NAME_LT_X, INPUT_NAME_LT_Y, WHITE, ow->nickname.str); + } + } + }else if(pad.trg & PAD_BUTTON_B) { + if(!( (charCode >= CODE_BUTTON_TOP_)&&(charCode < CODE_BUTTON_BOTTOM_) )) { + DeleteName1Char(); // 1文字削除 + }else if(charCode == OK_BUTTON_) { + ReturnMenu(0); // [OK]ボタン上でBボタンならリターン + } + } + + return 0; +} + + +// メインメニューに戻る +static void ReturnMenu(int save_flag) +{ + int i; + + if((save_flag)&&(ow->nickname.change_flag)) { + GetSYSMWork()->ncd_invalid = 0; + GetNCDWork()->option.input_nickname = 1; // ニックネーム入力フラグを立てる。 + + ExSJIS_BEtoUTF16_LE( (u8 *)ow->nickname.str, GetNCDWork()->owner.nickname.str, ow->nickname.length); + // 入力されたネームをSJISからUTF16へ変換する。 + GetNCDWork()->owner.nickname.length = ow->nickname.length; + for(i = ow->nickname.length; i < NCD_NICKNAME_LENGTH; i++) {// 入力された名前以降を0x0000で埋める。 + GetNCDWork()->owner.nickname.str[i] = 0x0000; + } + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData(GetNCDWork()); + } + SEQ_OwnerInfo_init(); + nowProcess = SEQ_OwnerInfo; // オーナー情報編集に戻る +} + +// 1文字削除 +static void DeleteName1Char(void) +{ + if(ow->nickname.length == 0) return; + + ow->nickname.change_flag = 1; + ow->nickname.length--; + ow->nickname.str[ow->nickname.length] = CHAR_USCORE; + (void)DrawStringSJIS( INPUT_NAME_LT_X, INPUT_NAME_LT_Y, WHITE, ow->nickname.str); +} + + +// カーソル位置から対応するキャラ番号を取得 +static u16 CalcTblIndex(CsrPos *csrp) +{ + u16 tbl_index = 0; + u16 x_bak = csrp->x; + + while(x_bak >= 5) { + x_bak -= 5; + tbl_index += 30; + } + tbl_index += x_bak + (csrp->y * 5); + + return tbl_index; +} + + +// カーソル移動 +static void MoveCharCursor(int force_flag) +{ + if((*(u32 *)&ow->csr_now != *(u32 *)&ow->csr_old) || (force_flag)) { + DrawTargetCsrChar(&ow->csr_old, WHITE); + DrawTargetCsrChar(&ow->csr_now, HIGHLIGHT_Y); + } +} + + +// カーソル位置のキャラクタを描画 +static void DrawTargetCsrChar(CsrPos *csrp, u16 color) +{ + u16 index = CalcTblIndex(csrp); + u16 charCode = (u16)char_tbl[ ow->char_mode ][ index ]; + + if( (charCode >= CODE_BUTTON_TOP_) && (charCode < CODE_BUTTON_BOTTOM_) ) { + if(color == WHITE) { + color = HIGHLIGHT_C; + } + } + + if(ChangeColorSJIS(ow->handleTbl[ index ], color) == 0) { + OS_Printf("this handle is not found. %x\n", ow->handleTbl[ index ]); + } +} + + +// TPによるカーソル移動 +static BOOL MoveCharCursorTp(CsrPos *csrp) +{ + int x_bak; + BOOL active = FALSE; + CsrPos temp; + + if(ow->detach_count) { + if(tpd.disp.touch == 0) { + if(++ow->detach_count == TP_CSR_DETACH_COUNT) { + ow->detach_count = 0; + return TRUE; + }else { + return FALSE; + } + } + } + ow->detach_count = 0; + + if(tpd.disp.touch) { + if(InRangeTp(CLIST_LT_X*8, CLIST_LT_Y*8-4, CLIST_RB_X*8-1, CLIST_RB_Y*8-4, &tpd.disp)) { + // 少しマージンあり。 + temp.x = (u16)((tpd.disp.x - CLIST_LT_X * 8) / 8); + temp.y = (u16)((tpd.disp.y - (CLIST_LT_Y * 8 - 4)) / 16); + x_bak = temp.x; // 5文字ごとにある空白列の補正 + while(x_bak >= 5) { + x_bak -= 6; + temp.x--; + } + + if(temp.y == 0) { // 右端余白の補正 + if(temp.x > 18) temp.x = 18; + }else if(temp.x > 15) { + temp.x = 15; + } + if(*(u32 *)&temp == *(u32 *)&ow->tpcsr) { // 今回のTPカーソル位置が前回と同じなら、カウントを進めて、 + if(ow->touch_count < TP_CSR_TOUCH_COUNT) { // 規定値に達したら有効な位置とする。 + ow->touch_count++; + }else { + csrp->x = temp.x; + csrp->y = temp.y; + } + return FALSE; + } + } + }else { // touch == 0 + if(ow->touch_count == TP_CSR_TOUCH_COUNT) { + ow->detach_count = 1; + } + } + ow->tpcsr.x = temp.x; + ow->tpcsr.y = temp.y; + ow->touch_count = 0; + return FALSE; +} + + +// 現在のcharmodeのキャラクタ一覧を描画 +static void DrawCharacterList(void) +{ + u16 i, j, k, x, y, index, button; + const u16 *code; + u16 str[2]; + + // キャラリストの削除 + for( i = 0; i < CHAR_LIST_CHAR_NUM; i++ ) { + if( ow->handleTbl[ i ] ) { + ClearStringSJIS_handle( ow->handleTbl[ i ] ); + } + } + + // キャラクタリストの描画 + code = char_tbl[ow->char_mode]; + str[1] = 0x0000; + index = 0; + button = 0; + for(i = 0; i < 4; i++) { +// buffp = bgBakS + CLIST_LT_X + (CLIST_LT_Y << 5) + (6 * i); + for(j = 0; j < 6; j++) { + x = (u16)(CLIST_LT_X + (i * 6)); + y = (u16)(CLIST_LT_Y + (j * 2)); + for(k = 0; k < 5; k++) { + if(*code != EOM_) { + if( (*code >= CODE_BUTTON_TOP_) && (*code < CODE_BUTTON_BOTTOM_) ) { // ボタン + ow->handleTbl[ index ] = DrawStringSJIS( x, y, HIGHLIGHT_C, str_button[ button++ ]); + }else { // キャラクタ + str[0] = (u16)( (*code >> 8) | ( *code << 8) ); + ow->handleTbl[ index ] = DrawStringSJISEx( x, y, WHITE, str, index ); + } + } + index++; + code++; + x++; + } + } + } + MoveCharCursor(1); +} + + +// ソフトキーボードのボタンを設定 +static void SetSoftKeyboardButton(u16 char_mode) +{ + if(char_mode == 0) { + str_button[0] = (const u16 *)str_button_kkana; // 1 + str_button[1] = (const u16 *)str_button_eisuu; // 2 + }else if(char_mode == 1) { + str_button[0] = (const u16 *)str_button_eisuu; // 2 + str_button[1] = (const u16 *)str_button_hkana; // 0 + }else { + str_button[0] = (const u16 *)str_button_hkana; // 0 + str_button[1] = (const u16 *)str_button_kkana; // 1 + } +} + + +// SJISコードをコードHi/Loを逆転しながらコピー +static void SJISCodeExchangeCopy(u16 *srcp, u16 *dstp, u16 length) +{ + while(length--) { + *dstp++ = (u16)( (*srcp >> 8) | (*srcp << 8) ); + srcp++; + } +} + + +//====================================================== +// ニックネーム入力用キャラテーブル +//====================================================== + +/* + ※SJIS文字を文字定数として記述する場合、以下の2通りで上位・下位コードの格納順序が +   逆になってしまうので、注意すること。 + + u8 str[] = "あいうえお"; 0x82,0xa0,0x82,0xa2...と上位コードが下位バイトに格納される。 + u16 code = 'あ'; 0xa0,0x82 と上位・下位コードがそのまま格納される。 + +*/ + +static const u16 char_tbl[3][CHAR_LIST_CHAR_NUM] = { + { // ひらがな + 'あ', 'い', 'う', 'え', 'お', + 'か', 'き', 'く', 'け', 'こ', + 'さ', 'し', 'す', 'せ', 'そ', + 'た', 'ち', 'つ', 'て', 'と', + 'な', 'に', 'ぬ', 'ね', 'の', + 'は', 'ひ', 'ふ', 'へ', 'ほ', + + 'ま', 'み', 'む', 'め', 'も', + 'や', ' ', 'ゆ', ' ', 'よ', + 'ら', 'り', 'る', 'れ', 'ろ', + 'わ', ' ', 'を', ' ', 'ん', + 'ぁ', 'ぃ', 'ぅ', 'ぇ', 'ぉ', + 'ゃ', ' ', 'ゅ', ' ', 'ょ', + + 'が', 'ぎ', 'ぐ', 'げ', 'ご', + 'ざ', 'じ', 'ず', 'ぜ', 'ぞ', + 'だ', 'ぢ', 'づ', 'で', 'ど', + 'ば', 'び', 'ぶ', 'べ', 'ぼ', + 'ぱ', 'ぴ', 'ぷ', 'ぺ', 'ぽ', + 'っ', '、', '。', '!', 'ー', + + '「', '」', '〜', '・', ' ', + VAR_BUTTON1_, EOM_, EOM_, EOM_, EOM_, + VAR_BUTTON2_, EOM_, EOM_, EOM_, EOM_, + DEL_BUTTON_, EOM_, EOM_, EOM_, EOM_, + CANCEL_BUTTON_, EOM_, EOM_, EOM_, EOM_, + OK_BUTTON_, EOM_, EOM_, EOM_, EOM_, + }, + + { // カタカナ + 'ア', 'イ', 'ウ', 'エ', 'オ', + 'カ', 'キ', 'ク', 'ケ', 'コ', + 'サ', 'シ', 'ス', 'セ', 'ソ', + 'タ', 'チ', 'ツ', 'テ', 'ト', + 'ナ', 'ニ', 'ヌ', 'ネ', 'ノ', + 'ハ', 'ヒ', 'フ', 'ヘ', 'ホ', + + 'マ', 'ミ', 'ム', 'メ', 'モ', + 'ヤ', ' ', 'ユ', ' ', 'ヨ', + 'ラ', 'リ', 'ル', 'レ', 'ロ', + 'ワ', ' ', 'ヲ', ' ', 'ン', + 'ァ', 'ィ', 'ゥ', 'ェ', 'ォ', + 'ャ', ' ', 'ュ', ' ', 'ョ', + + 'ガ', 'ギ', 'グ', 'ゲ', 'ゴ', + 'ザ', 'ジ', 'ズ', 'ゼ', 'ゾ', + 'ダ', 'ヂ', 'ヅ', 'デ', 'ド', + 'バ', 'ビ', 'ブ', 'ベ', 'ボ', + 'パ', 'ピ', 'プ', 'ペ', 'ポ', + 'ッ', '、', '。', '!', 'ー', + + '「', '」', '〜', '・', ' ', + VAR_BUTTON1_, EOM_, EOM_, EOM_, EOM_, + VAR_BUTTON2_, EOM_, EOM_, EOM_, EOM_, + DEL_BUTTON_, EOM_, EOM_, EOM_, EOM_, + CANCEL_BUTTON_, EOM_, EOM_, EOM_, EOM_, + OK_BUTTON_, EOM_, EOM_, EOM_, EOM_, + }, + + { // 英数 + 'A', 'B', 'C', 'D', 'E', + 'F', 'G', 'H', 'I', 'J', + 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', + 'U', 'V', 'W', 'X', 'Y', + 'Z', ' ', ' ', ' ', ' ', + + 'a', 'b', 'c', 'd', 'e', + 'f', 'g', 'h', 'i', 'j', + 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', + 'u', 'v', 'w', 'x', 'y', + 'z', ' ', ' ', ' ', ' ', + + '0', '1', '2', '3', '4', + '5', '6', '7', '8', '9', + '!', ' ', '&', ' ', '/', + ',', ' ', '.', ' ', '−', + '’', ' ', '”', ' ', ' ', + '@', ' ', '(', ' ', ')', + + EOM_, EOM_, EOM_, EOM_, EOM_, + VAR_BUTTON1_, EOM_, EOM_, EOM_, EOM_, + VAR_BUTTON2_, EOM_, EOM_, EOM_, EOM_, + DEL_BUTTON_, EOM_, EOM_, EOM_, EOM_, + CANCEL_BUTTON_, EOM_, EOM_, EOM_, EOM_, + OK_BUTTON_, EOM_, EOM_, EOM_, EOM_, + }, +}; + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/rtcSet.c b/build/systemMenu_RED/ARM9/src/DS_Setting/rtcSet.c new file mode 100644 index 00000000..22f3baa1 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/rtcSet.c @@ -0,0 +1,553 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: rtcSet.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "misc.h" +#include "DS_Setting.h" + +// define data------------------------------------------ + +//#define __RTC_MINUTE_OFFSET // この定義が有効な場合はrtcOffsetは分オフセットで算出されます。また、無効な場合は秒オフセットとなります。 + + // RETURNボタンLCD領域 +#define RETURN_BUTTON_LT_X 2 +#define RETURN_BUTTON_LT_Y 21 +#define RETURN_BUTTON_RB_X (RETURN_BUTTON_LT_X + 8) +#define RETURN_BUTTON_RB_Y (RETURN_BUTTON_LT_Y + 2) + // 日付データLCD領域 +#define DATE_LT_X 5 +#define DATE_LT_Y 10 + // 時刻データLCD領域 +#define TIME_LT_X (DATE_LT_X + 14) +#define TIME_LT_Y DATE_LT_Y + + // RTC設定メニュー要素 +#define RTC_MENU_ELEM_NUM 1 + + // 文字入力タッチパネル用カウンタ +#define S_UPDOWN_COUNT_MAX 16 + // 数値入力タッチパネル用カウンタ +#define D_DOWN_COUNT_MAX -50 +#define D_UP_COUNT_MAX 50 + + + // 日付時刻入力シーケンス用ワーク +typedef struct DateTimeParam { + int seq; // シーケンス番号 + int *tgtp; // 入力対象の変数へのポインタ + RTCDate Date; + RTCTime Time; +}DateTimeParam; + + + // RTC設定シーケンス用ワーク +typedef struct SetRtcWork { + int csr; // カーソル位置 + s64 rtcOffset[2]; // RTCオフセット値([0]:設定変更前の値、[1]:変更後の値) + DateTimeParam dtp; // 日付時刻入力シーケンス用ワーク + InputNumParam inp; // 数値入力インターフェース用ワーク +}SetRtcWork; + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +void SEQ_RtcSet_init(void); +int SEQ_RtcSet(void); +RTCWeek CalcWeekFromDate( u32 year, u32 month, u32 day ); +void InputDecimal(int *tgtp, InputNumParam *inpp); + +static void SEQ_InputRtcDateTime_init(int start); +static int SEQ_InputRtcDateTime(void); +static void TransmitRtcData(DateTimeParam *dtpp, RtcDateTime *rtcp); +static void SelectString( int *tgtp, const u8 **const strpp, InputNumParam *inpp); +static void BcdToHex(int *bcdp); +static void HexToBcd(int *hexp); +static BOOL CheckLeapYear( u32 year ); + +// global variable ------------------------------------- + +// static variable ------------------------------------- +SetRtcWork *pRtcWork; // RTC設定用ワーク + +// const data ----------------------------------------- + +//====================================================== +// 日付&時刻設定 +//====================================================== + +// RTC設定シーケンスの初期化 +void SEQ_RtcSet_init(void) +{ + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + MI_CpuClearFast(bgBakS, sizeof(bgBakS)); + SVC_CpuClearFast(0xc0, oamBakS, sizeof(oamBakS)); + + ClearAllStringSJIS(); + + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"DATE & TIME SET"); + (void)DrawStringSJIS( DATE_LT_X + 3, DATE_LT_Y, WHITE, (const u8 *)"/ / [ ] : :"); + (void)DrawStringSJIS( RETURN_BUTTON_LT_X, RETURN_BUTTON_LT_Y, HIGHLIGHT_C, (const u8 *)" RETURN "); + if( initialSet ) { + if( GetSYSMWork()->rtcStatus & 0x01) { + (void)DrawStringSJIS( 8, 18, RED, (const u8 *)"RTC reset is detected!"); + }else { + (void)DrawStringSJIS( 8, 18, RED, (const u8 *)"Set RTC."); + } + } + + pRtcWork=OS_Alloc(sizeof(SetRtcWork)); // RTC設定用ワークの確保 +#ifdef __SYSM_DEBUG + if(pRtcWork==NULL) OS_Panic("ARM9- Fail to allocate memory...\n"); +#endif /* __SYSM_DEBUG */ + OS_Printf("Alloc :SetRtcWork\n"); + SVC_CpuClear(0x0000, pRtcWork, sizeof(SetRtcWork), 16); + + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + + InitGetAndDrawRtcData( DATE_LT_X, DATE_LT_Y, TIME_LT_X, TIME_LT_Y); // RTCデータ表示位置の指定 + + GXS_SetVisiblePlane(GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1); + +/* if(0){ + s64 offset; + RTCDate date; + RTCTime time; + + date.year = 99; + date.month = 12; + date.day = 31; + time.hour = 23; + time.minute = 59; + time.second = 0; + offset = IPL2i_CalcRtcSecOffset( &date, &time ); // 設定直前のRTC値のオフセットを算出 + OS_Printf( " 99/12/31 23:59:00 offset = %x\n", offset ); + date.year = 100; + date.month = 1; + date.day = 1; + time.hour = 0; + time.minute = 0; + time.second = 0; + offset = IPL2i_CalcRtcSecOffset( &date, &time ); // 設定直前のRTC値のオフセットを算出 + OS_Printf( "100/01/01 00:00:00 offset = %x\n", offset ); + } +*/ +} + + +// RTC設定シーケンス +int SEQ_RtcSet(void) +{ + BOOL tp_set = FALSE; + BOOL tp_return = FALSE; + + ReadTpData(); // タッチパネル入力の取得 + GetAndDrawRtcData(); + + if(tpd.disp.touch) { + tp_set = InRangeTp( DATE_LT_X*8, DATE_LT_Y*8-4, // [RTC設定]領域押下チェック + (TIME_LT_X + 8)*8, (TIME_LT_Y+2)*8-4, &tpd.disp); + // [RETURN]ボタン押下チェック + tp_return = InRangeTp(RETURN_BUTTON_LT_X*8, RETURN_BUTTON_LT_Y*8-4, + RETURN_BUTTON_RB_X*8, RETURN_BUTTON_RB_Y*8-4, &tpd.disp); + } + if( initialSet && !GetNCDWork()->option.input_rtc ) { + tp_set = TRUE; + } + //-------------------------------------- + // キー入力処理 + //-------------------------------------- + if(pad.trg & PAD_KEY_DOWN){ // カーソルの移動 + if(++pRtcWork->csr == RTC_MENU_ELEM_NUM) pRtcWork->csr = 0; + } + if(pad.trg & PAD_KEY_UP){ + if(--pRtcWork->csr < 0) pRtcWork->csr = RTC_MENU_ELEM_NUM - 1; + } + + if((pad.trg & PAD_BUTTON_A) || (tp_set)) { // RTC設定開始 + if(pRtcWork->csr == 0) { + SEQ_InputRtcDateTime_init(1); + nowProcess = SEQ_InputRtcDateTime; + } + }else if((pad.trg & PAD_BUTTON_B) || (tp_return)) { // メニューに戻る + OS_Free(pRtcWork); // RTC設定用ワークの解放 + pRtcWork = NULL; + OS_Printf("Free :SetRtcWork\n"); + SEQ_MainMenu_init(); + } + +#ifdef __SYSM_DEBUG + if(pad.trg & PAD_BUTTON_START) { + ClearRTC(); + OS_Printf("RTC offset in NVRAM is ZERO clear!\n"); + } +#endif /* __SYSM_DEBUG */ + + return 0; +} + + +//====================================================== +// 日付&時刻入力処理 +//====================================================== + +// 日付時刻入力初期化 +static void SEQ_InputRtcDateTime_init(int start) +{ + mf_clearRect( RETURN_BUTTON_LT_X, RETURN_BUTTON_LT_Y, 2, 28); + if(start) { + DrawOKCancelButton(); + pRtcWork->dtp.seq = 0; + }else { + (void)DrawStringSJIS( RETURN_BUTTON_LT_X, RETURN_BUTTON_LT_Y, HIGHLIGHT_C, (const u8 *)" RETURN "); + } + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); +} + + +// 日付時刻入力 +static int SEQ_InputRtcDateTime(void) +{ + BOOL tp_ok = FALSE; + BOOL tp_cancel = FALSE; + int new_seq, x_base, y_base, abs_y_offset; + + enum { // 日付時刻入力シーケンス番号 + SEQ_INIT=0, + SEQ_YEAR_INIT=2, SEQ_YEAR_SET, + SEQ_MONTH_INIT, SEQ_MONTH_SET, + SEQ_DAY_INIT, SEQ_DAY_SET, + SEQ_HOUR_INIT, SEQ_HOUR_SET, + SEQ_MINUTE_INIT, SEQ_MINUTE_SET, + SEQ_SECOND_INIT, SEQ_SECOND_SET, + SEQ_END, + SEQ_RETURN=64 + }; + + ReadTpData(); // タッチパネル入力の取得 + CheckOKCancelButton(&tp_ok, &tp_cancel); // [OK],[CANCEL]ボタン押下チェック + + pRtcWork->inp.y_offset = 0; + if(tpd.disp.touch) { // [CANCEL]ボタン押下チェック + if((pRtcWork->dtp.seq & 0x01) && (pRtcWork->dtp.seq < SEQ_END)) { // SEQ_**_SETの時のみ有効 + new_seq = pRtcWork->dtp.seq; + x_base = DATE_LT_X * 8; + y_base = DATE_LT_Y * 8 + 6; + // 入力項目移動のチェック + if( InRangeTp( x_base, (y_base - 6), (x_base + 22 * 8), (y_base + 6), &tpd.disp) ) { + if(tpd.disp.x < x_base + 28) { + new_seq = SEQ_YEAR_SET; + }else if((tpd.disp.x >= x_base + 4*8) && (tpd.disp.x < x_base + 6*8)) { + new_seq = SEQ_MONTH_SET; + }else if((tpd.disp.x >= x_base + 7*8) && (tpd.disp.x < x_base + 9*8)) { + new_seq = SEQ_DAY_SET; + }else if((tpd.disp.x >= x_base + 14*8) && (tpd.disp.x < x_base + 16*8)) { + new_seq = SEQ_HOUR_SET; + }else if((tpd.disp.x >= x_base + 17*8) && (tpd.disp.x < x_base + 19*8)) { + new_seq = SEQ_MINUTE_SET; + }else if(tpd.disp.x >= x_base + 20*8) { + new_seq = SEQ_SECOND_SET; + } + } + if(pRtcWork->dtp.seq != new_seq) { + pRtcWork->dtp.seq = new_seq - 1; + }else { + // 入力値の増減 + if(InRangeTp( pRtcWork->inp.pos_x * 8, (y_base - 30), (pRtcWork->inp.pos_x + pRtcWork->inp.keta_max)*8, (y_base + 30), &tpd.disp)) { + pRtcWork->inp.y_offset = tpd.disp.y - y_base; + abs_y_offset = (pRtcWork->inp.y_offset >= 0) ? pRtcWork->inp.y_offset : -pRtcWork->inp.y_offset; + if(abs_y_offset <= 6) { + pRtcWork->inp.y_offset = 0; + }else if(abs_y_offset <= 14){ + pRtcWork->inp.y_offset >>= 2; + }else if(abs_y_offset <= 22){ + pRtcWork->inp.y_offset >>= 1; + } + } + } + } + } + + // タッチパネル or キー入力によって、カーソル位置が動いた時に、元の位置のカーソルを消す。 + if((pRtcWork->dtp.seq > 0) && ((pRtcWork->dtp.seq & 0x01) == 0)) { // SEQ_INITの時は実行しない + (void)DrawDecimalSJIS( pRtcWork->inp.pos_x, pRtcWork->inp.pos_y, WHITE, pRtcWork->dtp.tgtp, (u8)pRtcWork->inp.keta_max, 4); + } + + // 各シーケンスの処理 + switch(pRtcWork->dtp.seq){ + + case SEQ_INIT: + pRtcWork->dtp.Date = GetSYSMWork()->rtc[0].Date; + pRtcWork->dtp.Time = GetSYSMWork()->rtc[0].Time; + pRtcWork->dtp.Date.year += 2000; // yearを+2000する。 + pRtcWork->dtp.seq = SEQ_YEAR_INIT; + // ※SEQ_INITは直通でSEQ_YEAR_INITへ + + case SEQ_YEAR_INIT: + pRtcWork->inp.pos_x = DATE_LT_X; + pRtcWork->inp.pos_y = DATE_LT_Y; + pRtcWork->inp.keta_max = 4; + pRtcWork->inp.value_max = 2099; + pRtcWork->inp.value_min = 2000; +// pRtcWork->inp.value_min = 2004; +// if(pRtcWork->dtp.Date.year < 2004) { +// pRtcWork->dtp.Date.year = 2004; +// } + pRtcWork->dtp.tgtp = (int *)&pRtcWork->dtp.Date.year; + break; + + case SEQ_MONTH_INIT: + pRtcWork->inp.pos_x = DATE_LT_X + 4; + pRtcWork->inp.keta_max = 2; + pRtcWork->inp.value_max = 12; + pRtcWork->inp.value_min = 1; + pRtcWork->dtp.tgtp = (int *)&pRtcWork->dtp.Date.month; + break; + + case SEQ_DAY_INIT: + pRtcWork->inp.pos_x = DATE_LT_X + 7; + pRtcWork->inp.keta_max = 2; + pRtcWork->inp.value_max = (int)SYSM_GetDayNum( pRtcWork->dtp.Date.year, pRtcWork->dtp.Date.month ); + // 年・月をもとにその月の日数を算出する。 + pRtcWork->inp.value_min = 1; + if(pRtcWork->dtp.Date.day > pRtcWork->inp.value_max) { + pRtcWork->dtp.Date.day = (u32)pRtcWork->inp.value_max; + } + pRtcWork->dtp.tgtp = (int *)&pRtcWork->dtp.Date.day; + break; + + case SEQ_HOUR_INIT: + pRtcWork->inp.pos_x = TIME_LT_X; + pRtcWork->inp.keta_max = 2; + pRtcWork->inp.value_max = 23; + pRtcWork->inp.value_min = 0; + pRtcWork->dtp.tgtp = (int *)&pRtcWork->dtp.Time.hour; + break; + + case SEQ_MINUTE_INIT: + pRtcWork->inp.pos_x = TIME_LT_X + 3; + pRtcWork->inp.keta_max = 2; + pRtcWork->inp.value_max = 59; + pRtcWork->inp.value_min = 0; + pRtcWork->dtp.tgtp = (int *)&pRtcWork->dtp.Time.minute; + break; + + case SEQ_SECOND_INIT: + pRtcWork->inp.pos_x = TIME_LT_X + 6; + pRtcWork->inp.keta_max = 2; + pRtcWork->inp.value_max = 59; + pRtcWork->inp.value_min = 0; + pRtcWork->dtp.tgtp = (int *)&pRtcWork->dtp.Time.second; + break; + + case SEQ_YEAR_SET: + case SEQ_MONTH_SET: + case SEQ_DAY_SET: + case SEQ_HOUR_SET: + case SEQ_MINUTE_SET: + case SEQ_SECOND_SET: + InputDecimal( pRtcWork->dtp.tgtp, &pRtcWork->inp); + + // 年月日入力ならば、曜日を算出して表示。 + if( (pRtcWork->dtp.seq == SEQ_YEAR_SET) || (pRtcWork->dtp.seq == SEQ_MONTH_SET) || (pRtcWork->dtp.seq == SEQ_DAY_SET) ) { + pRtcWork->dtp.Date.week = CalcWeekFromDate(pRtcWork->dtp.Date.year, pRtcWork->dtp.Date.month, pRtcWork->dtp.Date.day); + (void)DrawStringSJIS( DATE_LT_X + 10, DATE_LT_Y, WHITE, g_strWeek[pRtcWork->dtp.Date.week]); + } + + // 年・月入力ならば、日数を算出して、現在の入力日が日数を超えていたら修正する。 + if( (pRtcWork->dtp.seq == SEQ_YEAR_SET) || (pRtcWork->dtp.seq == SEQ_MONTH_SET) ) { + u32 dayNum = SYSM_GetDayNum( pRtcWork->dtp.Date.year, pRtcWork->dtp.Date.month ); + if( dayNum < pRtcWork->dtp.Date.day) { + pRtcWork->dtp.Date.day = dayNum; + (void)DrawDecimalSJIS( DATE_LT_X + 7, DATE_LT_Y, WHITE, &pRtcWork->dtp.Date.day, 2, 4); + } + } + break; + + case SEQ_END: + pRtcWork->dtp.Date.year -= 2000; // yearを−2000する。 + +/* // RTCへの新しい値の設定 + (void)RTC_GetDateTime(&now_dtp.Date, &now_dtp.Time); // ライト直前に現在のRTC値を取得する。 + (void)RTC_SetDateTime(&pRtcWork->dtp.Date, &pRtcWork->dtp.Time); // 新RTC設定値のセット。 + + if((GetSYSMWork()->rtc[0].Date.year == 99) && (now_dtp.Date.year == 0)) { + now_dtp.Date.year = 100; // 設定前〜設定完了の間にRTCが一周してしまったら、yearは100としてoffsetを計算する。 + } + // RTC設定時は、今回の設定でどれだけRTC値が変化したか(秒オフセット単位)を算出してNVRAMに保存する。(とりあえず実装) + pRtcWork->rtcOffset[0] = IPL2i_CalcRtcSecOffset( &now_dtp.Date, &now_dtp.Time ); // 現在のRTC値のオフセットを算出 + pRtcWork->rtcOffset[1] = IPL2i_CalcRtcSecOffset( &pRtcWork->dtp.Date, &pRtcWork->dtp.Time ); // 新しくセットされたRTC値のオフセットを算出 + GetNCDWork()->option.rtcOffset += pRtcWork->rtcOffset[1] - pRtcWork->rtcOffset[0]; + // 新RTC_ofs と 現在のRTC_ofs の差分の値を加算。 +*/ + + pRtcWork->dtp.Time.second = 0; + NCD_SetRtcOffset( SYSM_CalcRtcOffsetAndSetDateTime( &pRtcWork->dtp.Date, &pRtcWork->dtp.Time ) ); + + GetSYSMWork()->rtc[0].Date = pRtcWork->dtp.Date; + GetSYSMWork()->rtc[0].Time = pRtcWork->dtp.Time; + GetSYSMWork()->ncd_invalid = 0; + GetNCDWork()->option.input_rtc = 1; // RTC入力フラグを立てる。 + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData (GetNCDWork()); + + // SEQ_ENDの時はこのままリターンする。 + + case SEQ_RETURN: + nowProcess = SEQ_RtcSet; + SEQ_InputRtcDateTime_init(0); // 日付入力画面のクリア + return 0; + } + + if(pRtcWork->dtp.seq & 0x01) { // SEQ_**_SETの時のみ有効 + if((pad.trg & PAD_BUTTON_A) || (tp_ok)) { + pRtcWork->dtp.seq = SEQ_END; // Aボタンで決定 + }else if((pad.trg & PAD_BUTTON_B) || (tp_cancel)) { // Bボタンでキャンセル + pRtcWork->dtp.seq = SEQ_RETURN; + }else if(pad.trg & PAD_KEY_LEFT) { + if(pRtcWork->dtp.seq == SEQ_YEAR_SET) pRtcWork->dtp.seq = SEQ_SECOND_INIT; + else pRtcWork->dtp.seq -= 3; + }else if(pad.trg & PAD_KEY_RIGHT) { + if(pRtcWork->dtp.seq == SEQ_SECOND_SET) pRtcWork->dtp.seq = SEQ_YEAR_INIT; + else pRtcWork->dtp.seq++; + } + }else { // SEQ_**_INITの時のみ有効 + pRtcWork->dtp.seq++; + } + return 0; +} + + +/* +// うるう年の判定 (うるう年:1、通常の年:0リターン) +BOOL CheckLeapYear( u32 year) +{ + if((year & 0x03) == 0) { // うるう年は、「4で割り切れ かつ 100で割り切れない年」 + CP_SetDiv32_32(year, 100); // 「400で割り切れる年」 + if(CP_GetDivRemainder32() != 0) { + return TRUE; + }else { + CP_SetDiv32_32(year, 400); + if(CP_GetDivRemainder32() == 0) { + return TRUE; + } + } + } + return FALSE; +} +*/ + +// 日付から曜日を求める。 +RTCWeek CalcWeekFromDate( u32 year, u32 month, u32 day ) +{ + if(month == 1 || month == 2 ){ + year--; + month += 12; + } + return (RTCWeek)( (year + year/4 - year/100 + year/400 + (13*month + 8)/5 + day) % 7 ); +} + + +/* +// 文字列によるパラメータ選択 +static void SelectString(int *tgtp, const u8 **const srtpp, InputNumParam *inpp) +{ + BOOL value_up = FALSE; + BOOL value_down = FALSE; + + if(inpp->y_offset == 0) { + inpp->up_count = S_UPDOWN_COUNT_MAX; + }else { + inpp->up_count ++; + if(inpp->up_count > S_UPDOWN_COUNT_MAX) { + inpp->up_count = 0; + if(inpp->y_offset < 0) value_up = TRUE; + else value_down = TRUE; + } + } + + if((pad.trg & PAD_KEY_DOWN) || (value_down)) { // 表示文字列切り替え + if(++*tgtp>inpp->value_max) *tgtp = 0; + }else if((pad.trg & PAD_KEY_UP) || (value_up)) { + if(--*tgtp & 0x8000) *tgtp = inpp->value_max; + } + + (void)DrawStringSJIS( inpp->pos_x, inpp->pos_y, HIGHLIGHT_Y, srtpp[*tgtp]); // 現在選択している文字列を表示 +} +*/ + +// 10進数数値入力 +void InputDecimal(int *tgtp, InputNumParam *inpp) +{ + BOOL value_up = FALSE; + BOOL value_down = FALSE; + + if(inpp->y_offset == 0) { + inpp->up_count = D_UP_COUNT_MAX; + inpp->down_count = D_DOWN_COUNT_MAX; + }else if(inpp->y_offset < 0) { + inpp->down_count += inpp->y_offset; + if(inpp->down_count < D_DOWN_COUNT_MAX) { + inpp->down_count = 0; + value_down = TRUE; + } + }else { // y_offset > 0 + inpp->up_count += inpp->y_offset; + if(inpp->up_count > D_UP_COUNT_MAX) { + inpp->up_count = 0; + value_up = TRUE; + } + } + + // キー入力に応じて対象値を増減 + if( (value_down) || (pad.trg & PAD_KEY_UP) + || ((pad.cont & PAD_KEY_UP) && (pad.cont & PAD_BUTTON_R)) ) { + if(--*tgtp < inpp->value_min) { + *tgtp = inpp->value_max; + } + }else if( (value_up) || (pad.trg & PAD_KEY_DOWN) + || ((pad.cont & PAD_KEY_DOWN) && (pad.cont & PAD_BUTTON_R)) ) { + if(++*tgtp > inpp->value_max) { + *tgtp = inpp->value_min; + } + } + + (void)DrawDecimalSJIS( inpp->pos_x, inpp->pos_y, HIGHLIGHT_Y, tgtp, (u8)inpp->keta_max, 4); + // 対象値をハイライト表示 +} + + +// RTC設定のクリア +void ClearRTC( void ) +{ + SVC_CpuClear(0x0000, &GetSYSMWork()->rtc[0].Time, sizeof(RTCTime), 16); + GetSYSMWork()->rtc[0].Date.year = 0; + GetSYSMWork()->rtc[0].Date.month = 1; + GetSYSMWork()->rtc[0].Date.day = 1; + (void)RTC_SetDateTime( &GetSYSMWork()->rtc[0].Date, &GetSYSMWork()->rtc[0].Time); + GetNCDWork()->option.input_rtc = 0; + GetNCDWork()->option.rtcOffset = 0; + NCD_SetRtcLastSetYear( 0 ); + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData (GetNCDWork()); +} + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/settingMenu.c b/build/systemMenu_RED/ARM9/src/DS_Setting/settingMenu.c new file mode 100644 index 00000000..af941f9a --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/settingMenu.c @@ -0,0 +1,308 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: mainMenu.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "main.h" +#include "DS_Setting.h" +#include "spi.h" + +// define data------------------------------------------ + // キャンセルボタンLCD領域 +#define CANCEL_BUTTON_LT_X 12 +#define CANCEL_BUTTON_LT_Y 21 +#define CANCEL_BUTTON_RB_X (CANCEL_BUTTON_LT_X + 8) +#define CANCEL_BUTTON_RB_Y (CANCEL_BUTTON_LT_Y + 2) + // OKボタンLCD領域 +#define OK_BUTTON_LT_X 22 +#define OK_BUTTON_LT_Y 21 +#define OK_BUTTON_RB_X (OK_BUTTON_LT_X + 8) +#define OK_BUTTON_RB_Y (OK_BUTTON_LT_Y + 2) + + +#define MAIN_MENU_ELEM_NUM 6 // メインメニューの項目数 + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +void SEQ_MainMenu_init(void); +int SEQ_MainMenu(void); +BOOL SelectMenuByTp(u16 *nowCsr, const MenuComponent *menu); +//BOOL InRangeTp(u16 lt_x,u16 lt_y,u16 rb_x,u16 rb_y, TPData *tgt); +BOOL InRangeTp(int lt_x, int lt_y, int rb_x, int rb_y, TPData *tgt); + +static void SEQ_SettingEnd_init( void ); +static int SEQ_SettingEnd( void ); + +// global variable ------------------------------------- +u16 csrMenu = 0; // メニューのカーソル位置(bm_main.cで参照してるので、グローバル) +BOOL initialSet = FALSE; + +// static variable ------------------------------------- +static const u8 *str_MainMenu[MAIN_MENU_ELEM_NUM]; // メインメニュー用文字テーブルへのポインタリスト + +// const data ----------------------------------------- + + +//=============================================== +// mainMenu.c +//=============================================== +const u8 *const str_MeinMenuElemTbl[ MAIN_MENU_ELEM_NUM ][ LANG_CODE_MAX ] = { + { + (const u8 *)"ユーザー じょうほう   ", + (const u8 *)"USER INFORMATION ", + (const u8 *)"USER INFORMATION(F)", + (const u8 *)"USER INFORMATION(G)", + (const u8 *)"USER INFORMATION(I)", + (const u8 *)"USER INFORMATION(S)", + }, + { + (const u8 *)"ひづけ & じこく    ", + (const u8 *)"DATE & TIME ", + (const u8 *)"DATE & TIME(F) ", + (const u8 *)"DATE & TIME(G) ", + (const u8 *)"DATE & TIME(I) ", + (const u8 *)"DATE & TIME(S) ", + }, + { + (const u8 *)"げんご          ", + (const u8 *)"LANGUAGE ", + (const u8 *)"LANGUAGE(F) ", + (const u8 *)"LANGUAGE(G) ", + (const u8 *)"LANGUAGE(I) ", + (const u8 *)"LANGUAGE(S) ", + }, + { + (const u8 *)"AGB モード        ", + (const u8 *)"AGB MODE ", + (const u8 *)"AGB MODE(F) ", + (const u8 *)"AGB MODE(G) ", + (const u8 *)"AGB MODE(I) ", + (const u8 *)"AGB MODE(S) ", + }, + { + (const u8 *)"タッチパネルほせい     ", + (const u8 *)"TOUCH PANEL ", + (const u8 *)"TOUCH PANEL(F) ", + (const u8 *)"TOUCH PANEL(G) ", + (const u8 *)"TOUCH PANEL(I) ", + (const u8 *)"TOUCH PANEL(S) ", + }, + { + (const u8 *)"きどうモード        ", + (const u8 *)"AUTO BOOT ", + (const u8 *)"AUTO BOOT(F) ", + (const u8 *)"AUTO BOOT(G) ", + (const u8 *)"AUTO BOOT(I) ", + (const u8 *)"AUTO BOOT(S) ", + }, +}; + +const MenuComponent mainMenu = { + MAIN_MENU_ELEM_NUM, + 2, + 6, + 0, + 2, + 17, + WHITE, + HIGHLIGHT_Y, + (const u8 **)&str_MainMenu, +}; + +//====================================================== +// メインメニュー +//====================================================== + +// メインメニューの初期化 +void SEQ_MainMenu_init(void) +{ +#ifdef __DIRECT_BOOT_BMENU_ENABLE + // 各種設定が未設定時のダイレクト起動。 + { + if(GetNCDWork()->option.input_language == 0) { // 言語設定がまだ。 + initialSet = TRUE; + csrMenu = 3; + SEQ_LangSelect_init(); + nowProcess = SEQ_LangSelect; + return; + }else if(GetNCDWork()->option.input_tp == 0) { // TPキャリブレーションがまだ。 + initialSet = TRUE; + csrMenu = 5; + SEQ_TP_Calibration_init(); + nowProcess = SEQ_TP_Calibration; + return ; + }else if(GetNCDWork()->option.input_rtc == 0) { // RTC設定がまだ。 + ClearRTC(); + initialSet = TRUE; + csrMenu = 2; + SEQ_RtcSet_init(); + nowProcess = SEQ_RtcSet; + return; + }else if( (GetNCDWork()->option.input_nickname == 0) // ニックネームまたは好きな色入力がまだ。 + || (GetNCDWork()->option.input_favoriteColor == 0) ) { + initialSet = TRUE; + csrMenu = 1; + SEQ_OwnerInfo_init(); + nowProcess = SEQ_OwnerInfo; + return; + } + + if( initialSet ) { + SEQ_SettingEnd_init(); + nowProcess = SEQ_SettingEnd; + return; + } + } +#endif /* __DIRECT_BOOT_BMENU_ENABLE */ + + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + SVC_CpuClearFast(0x0000, bgBakS, sizeof(bgBakS)); + SVC_CpuClearFast(0xc0, oamBakS, sizeof(oamBakS)); + + ClearAllStringSJIS(); + +#ifdef __NCD_CLEAR_ENABLE + (void)DrawStringSJIS( 18, 21, LIGHTGREEN, (const u8 *)"[START]:NCD clear."); +#endif /* __NCD_CLEAR_ENABLE */ + + // NITRO設定データのlanguageに応じたメインメニュー構成言語の切り替え + { + int i; + NvLangCode langCode = LANG_ENGLISH; + if(GetSYSMWork()->ncd_invalid == 0) { + langCode = (NvLangCode)GetNCDWork()->option.language; + } + for(i = 0; i < MAIN_MENU_ELEM_NUM; i++) { + str_MainMenu[i] = str_MeinMenuElemTbl[i][langCode]; + } + } + DrawMenu(csrMenu, &mainMenu); + + SVC_CpuClear(0x0000,&tpd,sizeof(TpWork),16); + + GXS_SetVisiblePlane(GX_PLANEMASK_BG1); + + nowProcess = SEQ_MainMenu; +} + + +// メインメニュー +int SEQ_MainMenu(void) +{ + BOOL tp_select; + + ReadTpData(); // タッチパネル入力の取得 + + //-------------------------------------- + // キー入力処理 + //-------------------------------------- + if(pad.trg & PAD_KEY_DOWN){ // カーソルの移動 + if(++csrMenu == MAIN_MENU_ELEM_NUM) csrMenu=0; + } + if(pad.trg & PAD_KEY_UP){ + if(--csrMenu & 0x80) csrMenu=MAIN_MENU_ELEM_NUM-1; + } + tp_select=SelectMenuByTp(&csrMenu, &mainMenu); + DrawMenu(csrMenu, &mainMenu); + + if((pad.trg & PAD_BUTTON_A)||(tp_select)) { // メニュー項目への分岐 + switch(csrMenu) { + case 0: + SEQ_OwnerInfo_init(); + nowProcess=SEQ_OwnerInfo; + break; + case 1: + SEQ_RtcSet_init(); + nowProcess=SEQ_RtcSet; + break; + case 2: + SEQ_LangSelect_init(); + nowProcess=SEQ_LangSelect; + break; + case 3: + SEQ_AgbLcdSelect_init(); + nowProcess=SEQ_AgbLcdSelect; + break; + case 4: + SEQ_TP_Calibration_init(); + nowProcess=SEQ_TP_Calibration; + break; + case 5: + SEQ_AutoBootSelect_init(); + nowProcess=SEQ_AutoBootSelect; + break; + } + } + +#ifdef __NCD_CLEAR_ENABLE + if(pad.trg & PAD_BUTTON_START) { + SVC_CpuClearFast(0x0000, GetNCDWork(), sizeof(NitroConfigData)); + (void)SPI_NvramWriteEnable(); + SVC_WaitVBlankIntr(); + (void)SPI_NvramPageErase(0x3fe00); + SVC_WaitVBlankIntr(); + (void)SPI_NvramWriteEnable(); + SVC_WaitVBlankIntr(); + (void)SPI_NvramPageErase(0x3ff00); + SVC_WaitVBlankIntr(); + (void)SPI_NvramWriteDisable(); + OS_Printf("NitroConfigData zero clear!!\n"); + } +#endif /* __NCD_CLEAR_ENABLE */ + + return 0; +} + + +// OK / CANCELボタンの描画 +void DrawOKCancelButton(void) +{ + (void)DrawStringSJIS( CANCEL_BUTTON_LT_X, CANCEL_BUTTON_LT_Y,HIGHLIGHT_C, (const u8 *)" CANCEL "); + (void)DrawStringSJIS( OK_BUTTON_LT_X, OK_BUTTON_LT_Y, HIGHLIGHT_C, (const u8 *)" OK "); +} + + +// OK or CANCELボタン押下チェック +void CheckOKCancelButton(BOOL *tp_ok, BOOL *tp_cancel) +{ + *tp_cancel = InRangeTp(CANCEL_BUTTON_LT_X*8, CANCEL_BUTTON_LT_Y*8-4, + CANCEL_BUTTON_RB_X*8, CANCEL_BUTTON_RB_Y*8-4, &tpd.disp); + *tp_ok = InRangeTp(OK_BUTTON_LT_X*8, OK_BUTTON_LT_Y*8-4, + OK_BUTTON_RB_X*8, OK_BUTTON_RB_Y*8-4, &tpd.disp); +} + + +//--------------------------------------------------------- +// +// 設定終了 +// +//--------------------------------------------------------- + +static void SEQ_SettingEnd_init( void ) +{ + ClearAllStringSJIS(); + (void)DrawStringSJIS( 6, 10, WHITE, (const u8 *)" Initial setting completed."); + (void)DrawStringSJIS( 6, 12, WHITE, (const u8 *)" Please reboot."); +} + + +static int SEQ_SettingEnd( void ) +{ + return 0; +} + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/tpCalib.c b/build/systemMenu_RED/ARM9/src/DS_Setting/tpCalib.c new file mode 100644 index 00000000..cdfbc1fb --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/tpCalib.c @@ -0,0 +1,516 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: tpCalib.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "misc.h" +#include "DS_Setting.h" + +// define data------------------------------------------ + // OKボタンLCD領域 +#define OK_BUTTON_LT_X 2 +#define OK_BUTTON_LT_Y 20 +#define OK_BUTTON_RB_X (OK_BUTTON_LT_X + 8) +#define OK_BUTTON_RB_Y (OK_BUTTON_LT_Y + 2) + + // キャンセルボタンLCD領域 +#define CANCEL_BUTTON_LT_X 11 +#define CANCEL_BUTTON_LT_Y 20 +#define CANCEL_BUTTON_RB_X (CANCEL_BUTTON_LT_X+8) +#define CANCEL_BUTTON_RB_Y (CANCEL_BUTTON_LT_Y+2) + + // リトライボタンLCD領域 +#define RETRY_BUTTON_LT_X 20 +#define RETRY_BUTTON_LT_Y 20 +#define RETRY_BUTTON_RB_X (RETRY_BUTTON_LT_X+8) +#define RETRY_BUTTON_RB_Y (RETRY_BUTTON_LT_Y+2) + + // キャリブレーション用OBJデータ +const u16 bitmapOBJPoint[8 * 8 * 5]; + + // 各種キャラクタデータサイズ +#define IMAGE_DATA (bitmapOBJPoint) +#define IMAGE_DATA_SIZE (sizeof(bitmapOBJPoint)) +#define MY_CHAR_SIZE (sizeof(myChar)) + + // NITRO-LCDサイズ +#define DISP_X_SIZE 256 +#define DISP_Y_SIZE 192 + + // キャリブレーションシーケンス番号(CalibWork.seqの値) +enum { + SEQ_INIT=0, SEQ_INTERVAL_0, + SEQ_CALIBRATE_1, SEQ_INTERVAL_1, + SEQ_CALIBRATE_2, SEQ_INTERVAL_2, + SEQ_CHECK_PARAM, SEQ_INTERVAL_3, + SEQ_GET_POINT +}; + + // キャリブレーション設定ワーク +typedef struct CalibWork { + u32 seq; + u16 release_count; + u16 touch_count; + u16 last_x; + u16 last_y; + TPData sample[2]; + TPCalibrateParam calibrate; +}CalibWork; + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +void SEQ_TP_Calibration_init(void); +int SEQ_TP_Calibration(void); + +static void DisplayInit(); +static BOOL GetSamplePointNow(TPData *data); +static BOOL WaitPanelReleaseNow( void ); +static void ReturnMenu(void); + +// global variable ------------------------------------- + +// static variable ------------------------------------- +static CalibWork *cw; + +// const data ----------------------------------------- + +//====================================================== +// function's description +//====================================================== + +/*---------------------------------------------------------------------------* + Name: SetPoint8x8 + + Description: Display a 8x8 OBJ on indicated point. + + Arguments: x - position X. + y - position Y. + + Returns: None. + *---------------------------------------------------------------------------*/ +static inline void SetPoint8x8(u16 pos_x, u16 pos_y) +{ + G2_SetOBJAttr( &oamBakS[0], // OAM number + pos_x - 4, // X position + pos_y - 4, // Y position + 0, // Priority + GX_OAM_MODE_BITMAPOBJ, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_8x8, // 8x8 size + GX_OAM_COLOR_16, // 16 color + 0x60, // charactor + 15, // alpha + 0); +} + + +/*---------------------------------------------------------------------------* + Name: SetPoint16x16 + + Description: Display a 16x16 OBJ on indicated point. + + Arguments: x - position X. + y - position Y. + + Returns: None. + *---------------------------------------------------------------------------*/ +static inline void SetPoint16x16(u16 pos_x, u16 pos_y) +{ + G2_SetOBJAttr( &oamBakS[0], // OAM number + pos_x - 8, // X position + pos_y - 8, // Y position + 0, // Priority + GX_OAM_MODE_BITMAPOBJ, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_16x16, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 0x61, // charactor + 15, // alpha + 0); +} + + +/*---------------------------------------------------------------------------* + Name: DisplayInit + + Description: Graphics Initialization + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +static void DisplayInit() +{ + GXS_SetOBJVRamModeBmp(GX_OBJVRAMMODE_BMP_1D_128K); // 2D mapping OBJ + /* Load charactor bitmap data */ + GXS_LoadOBJ( (const void *)IMAGE_DATA, 0x3000 /* 0 */, IMAGE_DATA_SIZE ); // Transfer OBJ bitmap data to VRAM +} + + +/*---------------------------------------------------------------------------* + Name: GetSamplePointNow + + Description: Get touched point by OneTime Sampling. + This function use TP_RequestSampling() and TP_WaitRawResult() + + Arguments: None. + + Returns: data - getton TouchPanel data. + BOOL - if touched and got point this function returns TRUE. + else FALSE. + *---------------------------------------------------------------------------*/ +static BOOL GetSamplePointNow(TPData *data) +{ + TPData temp; + + enum { + OK_COUNT = 4, OK_RANGE = 50 + }; + + // Detect a point pushed during definite time. + while (TP_RequestRawSampling( &temp )) { }; + + if (! temp.touch ) { + cw->touch_count = 0; + return FALSE; + } + + if ( temp.validity != TP_VALIDITY_VALID ) { + cw->touch_count = 0; + return FALSE; + } + + OS_Printf("( %d, %d )\n", temp.x, temp.y); + + cw->touch_count++; + if ( cw->touch_count == 1 ) { + cw->last_x = temp.x; + cw->last_y = temp.y; + return FALSE; + } + + // if jump point from last frame, reset count. + if ( (s32)(cw->last_x - temp.x) < - OK_RANGE || + (s32)(cw->last_x - temp.x) > OK_RANGE ) + { + cw->touch_count = 1; + cw->last_x = temp.x; + cw->last_y = temp.y; + return FALSE; + } + + if ( (s32)(cw->last_y - temp.y) < - OK_RANGE || + (s32)(cw->last_y - temp.y) > OK_RANGE ) + { + cw->touch_count = 1; + cw->last_x = temp.x; + cw->last_y = temp.y; + return FALSE; + } + + // if the point pressed during OK_COUNT, detect finish. + if ( cw->touch_count == OK_COUNT ) { + data->x = (u16) ( (temp.x + cw->last_x) / 2 ); + data->y = (u16) ( (temp.y + cw->last_y) / 2 ); + data->touch = TP_TOUCH_ON; + data->validity = TP_VALIDITY_VALID; + cw->touch_count=0; + return TRUE; + } + + cw->last_x = temp.x; + cw->last_y = temp.y; + return FALSE; +} + + +/*---------------------------------------------------------------------------* + Name: WaitPanelReleaseNow + + Description: Wait to released TouchPanel, using OneTime Sampling. + This function is using TP_RequestSampling() and TP_WaitRawResult(). + + Arguments: None. + + Returns: BOOL - if TouchPanel is released , this returns TRUE. + else FALSE. + + *---------------------------------------------------------------------------*/ +static BOOL WaitPanelReleaseNow( void ) +{ + TPData temp; + + enum { + INTERVAL_CNT = 10 + }; + + while (TP_RequestRawSampling( &temp )) { + SVC_WaitByLoop(0x400); + }; + + if ( temp.touch ) { + cw->release_count = 0; + return FALSE; + } + + cw->release_count++; + if ( cw->release_count >= INTERVAL_CNT ) { + cw->release_count = 0; + return TRUE; + } else { + return FALSE; + } +} + + +/*---------------------------------------------------------------------------* + Name: SEQ_TP_Calibration + + Description: Initialization and main loop + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ +int SEQ_TP_Calibration(void) +{ + BOOL tp_ok = FALSE; + BOOL tp_cancel = FALSE; + BOOL tp_retry = FALSE; + + switch (cw->seq) { + case SEQ_INIT: + mf_clearRect(0, 20, 4, 32); + cw->seq=SEQ_INTERVAL_0; + (void)DrawStringSJIS( 2, 21, CYAN,(const u8 *)"[B]:CANCEL"); + break; + + case SEQ_INTERVAL_0: + // wait release TouchPanel + if ( WaitPanelReleaseNow() ) { + cw->seq=SEQ_CALIBRATE_1; + } + break; + + case SEQ_CALIBRATE_1: + // detect first point. + SetPoint8x8(32, 32); + if ( GetSamplePointNow(&cw->sample[0]) ) { + OS_Printf("OK! ( %d, %d )\n", cw->sample[0].x, cw->sample[0].y); + cw->seq = SEQ_INTERVAL_1; + } + break; + + case SEQ_INTERVAL_1: + // wait release TouchPanel + if ( WaitPanelReleaseNow() ) { + cw->seq = SEQ_CALIBRATE_2; + } + break; + + case SEQ_CALIBRATE_2: + // detect second point. + SetPoint8x8( DISP_X_SIZE - 32, DISP_Y_SIZE - 32 ); + if ( GetSamplePointNow(&cw->sample[1]) ) { + OS_Printf("OK! ( %d, %d )\n", cw->sample[1].x, cw->sample[1].y); + // Calculate and set calibration parameter from two detected point. + (void)TP_CalcCalibrateParam( &cw->calibrate, + cw->sample[0].x, cw->sample[0].y, 32, 32, + cw->sample[1].x, cw->sample[1].y, DISP_X_SIZE - 32, DISP_Y_SIZE - 32 ); + TP_SetCalibrateParam( &cw->calibrate ); + + OS_Printf("Calibrate param: \n"); + OS_Printf("\tx = %d, xDotSize = %d\n", cw->calibrate.x0, cw->calibrate.xDotSize / 0x100); + OS_Printf("\ty = %d, yDotSize = %d\n", cw->calibrate.y0, cw->calibrate.yDotSize / 0x100); + OS_Printf("Check calibrate param\n"); + + cw->seq = SEQ_INTERVAL_2; + } + break; + + case SEQ_INTERVAL_2: + // Wait release TouchPanel + if ( WaitPanelReleaseNow() ) { + cw->seq = SEQ_CHECK_PARAM; + } + break; + + case SEQ_CHECK_PARAM: + // Verify Calibrattion Parameter. + SetPoint8x8( DISP_X_SIZE / 2, DISP_Y_SIZE / 2 ); + if ( GetSamplePointNow(&tpd.raw) ) { + TP_GetUnCalibratedPoint( &tpd.disp.x, &tpd.disp.y, DISP_X_SIZE / 2, DISP_Y_SIZE / 2 ); + cw->seq = SEQ_GET_POINT; + mf_clearRect( 2, 21, 2, 10); + (void)DrawStringSJIS( OK_BUTTON_LT_X, OK_BUTTON_LT_Y, HIGHLIGHT_C, (const u8 *)" OK "); + (void)DrawStringSJIS( CANCEL_BUTTON_LT_X, CANCEL_BUTTON_LT_Y, HIGHLIGHT_C, (const u8 *)" CANCEL "); + (void)DrawStringSJIS( RETRY_BUTTON_LT_X, RETRY_BUTTON_LT_Y, HIGHLIGHT_C, (const u8 *)" RETRY "); + (void)DrawStringSJIS( (u16)(OK_BUTTON_LT_X + 2), (u16)(OK_BUTTON_LT_Y + 2), CYAN,(const u8 *)"[A]"); + (void)DrawStringSJIS( (u16)(CANCEL_BUTTON_LT_X + 2), (u16)(CANCEL_BUTTON_LT_Y + 2), CYAN,(const u8 *)"[B]"); + (void)DrawStringSJIS( (u16)(RETRY_BUTTON_LT_X), (u16)(RETRY_BUTTON_LT_Y + 2), CYAN,(const u8 *)"[START]"); + { + s32 xRange, yRange; + xRange = tpd.raw.x - tpd.disp.x; + yRange = tpd.raw.y - tpd.disp.y; + OS_Printf("OK! ( %d, %d )\n", tpd.raw.x, tpd.raw.y); + OS_Printf("Raw ( %d, %d )\n", tpd.disp.x, tpd.disp.y); + OS_Printf("\txRange = %d, yRange = %d\n", xRange, yRange); + } + } + break; + + case SEQ_GET_POINT: + // Draw Marker by calibrated point. + while ( TP_RequestRawSampling( &tpd.raw ) ) { + SVC_WaitByLoop(0x400); + } + TP_GetCalibratedPoint( &tpd.disp, &tpd.raw ); + + if ( tpd.raw.touch ) { + SetPoint16x16( tpd.disp.x, tpd.disp.y ); + + // [OK] [CANCEL] [RETRY]ボタン押下チェック + tp_ok = InRangeTp(OK_BUTTON_LT_X*8, OK_BUTTON_LT_Y*8-4, + OK_BUTTON_RB_X*8, OK_BUTTON_RB_Y*8-4, &tpd.disp); + tp_cancel = InRangeTp(CANCEL_BUTTON_LT_X*8, CANCEL_BUTTON_LT_Y*8-4, + CANCEL_BUTTON_RB_X*8, CANCEL_BUTTON_RB_Y*8-4, &tpd.disp); + tp_retry = InRangeTp(RETRY_BUTTON_LT_X*8, RETRY_BUTTON_LT_Y*8-4, + RETRY_BUTTON_RB_X*8, RETRY_BUTTON_RB_Y*8-4, &tpd.disp); + + if(tpd.raw.validity==TP_VALIDITY_VALID) { + OS_Printf("( %3d, %3d ) -> ( %4d, %4d )\n", tpd.disp.x, tpd.disp.y, tpd.raw.x, tpd.raw.y); + } + } + + if((pad.trg & PAD_BUTTON_A) || (tp_ok)) { + GetSYSMWork()->ncd_invalid = 0; + GetNCDWork()->option.input_tp = 1; // タッチパネル入力フラグを立てる。 + GetNCDWork()->tp.raw_x1 = cw->sample[0].x; + GetNCDWork()->tp.raw_y1 = cw->sample[0].y; + GetNCDWork()->tp.dx1 = 32; + GetNCDWork()->tp.dy1 = 32; + GetNCDWork()->tp.raw_x2 = cw->sample[1].x; + GetNCDWork()->tp.raw_y2 = cw->sample[1].y; + GetNCDWork()->tp.dx2 = DISP_X_SIZE - 32; + GetNCDWork()->tp.dy2 = DISP_Y_SIZE - 32; + // :::::::::::::::::::::::::::::::::::::::::::::: + // NVRAMへの書き込み + // :::::::::::::::::::::::::::::::::::::::::::::: + (void)NVRAMm_WriteNitroConfigData (GetNCDWork()); + + ReturnMenu(); + return 0; + }else if((pad.trg & PAD_BUTTON_START) || (tp_retry)) { + cw->seq = SEQ_INIT; + } + break; + } + + /* flush cache of OAM buffers to main memory */ + DC_FlushRange( oamBakS, sizeof(oamBakS) ); + + GXS_LoadOAM( oamBakS, 0, sizeof(oamBakS) ); + MI_DmaFill32( 3, oamBakS, 192, sizeof(oamBakS) ); // Clear OAM buffer + + // Bボタンキャンセル + if((pad.trg & PAD_BUTTON_B) || (tp_cancel)){ + (void)TP_CalcCalibrateParam(&cw->calibrate, + GetNCDWork()->tp.raw_x1, GetNCDWork()->tp.raw_y1, (u16)GetNCDWork()->tp.dx1, (u16)GetNCDWork()->tp.dy1, + GetNCDWork()->tp.raw_x2, GetNCDWork()->tp.raw_y2, (u16)GetNCDWork()->tp.dx2, (u16)GetNCDWork()->tp.dy2); + TP_SetCalibrateParam(&cw->calibrate); + ReturnMenu(); + return 0; + } + + return 0; +} + + +// メニューに戻る +static void ReturnMenu(void) +{ + OS_Free(cw); // キャリブレーション用変数の開放 + cw = NULL; + OS_Printf("Free :CalibWork\n"); + SEQ_MainMenu_init(); +} + + +// キャリブレーション設定の初期化 +void SEQ_TP_Calibration_init(void) +{ + GXS_SetVisiblePlane(GX_PLANEMASK_NONE); + + MI_CpuClearFast(bgBakS, sizeof(bgBakS)); + + ClearAllStringSJIS(); + + (void)DrawStringSJIS( 1, 0, YELLOW, (const u8 *)"TOUCH PANEL CALIBRATION"); + if( initialSet ) { + (void)DrawStringSJIS( 8, 18, RED, (const u8 *)"Calibrate touch panel."); + } + + DisplayInit(); + + GXS_SetVisiblePlane(GX_PLANEMASK_OBJ | GX_PLANEMASK_BG1); + + cw=OS_Alloc(sizeof(CalibWork)); // キャリブレーション用変数の確保 +#ifdef __IPL2_DEBUG + if(cw==NULL) OS_Panic("ARM9- Fail to allocate memory...\n"); +#endif /* __IPL2_DEBUG */ + OS_Printf("Alloc :CalibWork\n"); + SVC_CpuClear(0x0000, cw, sizeof(CalibWork), 16); + SVC_CpuClear(0x0000, &tpd, sizeof(TpWork), 16); + cw->seq = SEQ_INIT; +} + + +// タッチパネル設定ポイント キャラデータ +const u16 bitmapOBJPoint[8 * 8 * 5] = { + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, // 0 char + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, // 0 char + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, // 0 char + 0xFFFF, 0xFFFF, 0xFFFF, 0x801F, 0x801F, 0xFFFF, 0xFFFF, 0xFFFF, // 0 char + 0xFFFF, 0xFFFF, 0xFFFF, 0x801F, 0x801F, 0xFFFF, 0xFFFF, 0xFFFF, // 0 char + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, // 0 char + 0xFFFF, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0xFFFF, // 0 char + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, // 0 char + + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, // 1 char + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, // 1 char + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, // 1 char + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 1 char + + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 2 char + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 2 char + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 2 char + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x801F, 0x801F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 2 char + + 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x801F, 0x801F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 3 char + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 3 char + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 3 char + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 3 char + + 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, // 4 char + 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0x0000, 0x0000, 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, // 4 char + 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, // 4 char + 0x0000, 0x0000, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0000, 0x0000, // 4 char +}; + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/unicode.c b/build/systemMenu_RED/ARM9/src/DS_Setting/unicode.c new file mode 100644 index 00000000..8e6f2884 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/unicode.c @@ -0,0 +1,567 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: unicode.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "unicode.h" +#include "font.h" + +// define data------------------------------------------ +#define TBL8140_ELEM_NUM 0xbd // 8140tblの要素数 +#define TBL849f_ELEM_NUM 0x20 // 849ftblの要素数 + +typedef struct SjisUtf16Pare { + u16 sjis; + u16 unicode; +}SjisUtf16Pare; + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +static u16 SearchUnicodeTable(u16 unicode, SjisUtf16Pare *tblp, int elem_num); + +// global variable ------------------------------------- + +// static variable ------------------------------------- + +// const data ----------------------------------------- +static const SjisUtf16Pare tblSJIS_UTF16_8140[ TBL8140_ELEM_NUM ]; +static const SjisUtf16Pare tblSJIS_UTF16_849f[ TBL849f_ELEM_NUM ]; + + +//====================================================== +// SJIS-BEからUTF16-LEへの変換 +//====================================================== +void ExSJIS_BEtoUTF16_LE(u8 *sjisp, u16 *unip, u16 length) +{ + u16 code; + + while( (*sjisp) && (length-- > 0) ) { + if( ((*sjisp >= SJIS_HIGHER_CODE1_MIN) && (*sjisp <= SJIS_HIGHER_CODE1_MAX)) + ||((*sjisp >= SJIS_HIGHER_CODE2_MIN) && (*sjisp <= SJIS_HIGHER_CODE2_MAX)) ) { // SJISか? + code = (u16)( (u16)*sjisp++ << 8 ); + code |= (u16)*sjisp++; + }else { // ASCII + code = (u16)*sjisp++; + } + + if(code == 0x005c) + { + *unip = 0x00a5; // \ + + }else if(code == 0x007e) + { + *unip = 0x203e; // ~ + + }else if( (code == 0x000d) || (code == 0x000a) ) { + *unip = code; // 改行コード + + }else if( (code >= 0x0020) && (code < 0x007e) ) // ' ' 〜 } + { + *unip = code; + + }else if( (code >= 0x00a1) && (code <= 0x00df) ) // 。 〜 ゚ + { + *unip = (u16)( (code - 0x00a1) + 0xff61 ); + + }else if( (code >= 0x8140) && (code <= 0x81fc) ) // ' ' 〜 ○ + { + // バラバラなので、テーブル引き + *unip = tblSJIS_UTF16_8140[ code - 0x8140 ].unicode; + + }else if( (code >= 0x824f) && (code <= 0x8258) ) // 0 〜 9 + { + *unip = (u16)( (code - 0x824f) + 0xff10 ); + + }else if( (code >= 0x8260) && (code <= 0x8279) ) // A 〜 Z + { + *unip = (u16)( (code - 0x8260) + 0xff21 ); + + }else if( (code >= 0x8281) && (code <= 0x829a) ) // a 〜 z + { + *unip = (u16)( (code - 0x8281) + 0xff41 ); + + }else if( (code >= 0x829f) && (code <= 0x82f1) ) // ぁ 〜 ん + { + *unip = (u16)( (code - 0x829f) + 0x3041 ); + + }else if( (code >= 0x8340) && (code <= 0x8396) ) // ァ 〜 ヶ ※0x837fは抜け + { + *unip = (u16)( (code - 0x8340) + 0x30a1 ); + if( code == 0x837f ) { + *unip = 0x3000; + }else if( code > 0x837f ) { + (*unip)--; + } + + }else if( (code >= 0x839f) && (code <= 0x83b6) ) // Α 〜 Ω + { + *unip = (u16)( (code - 0x839f) + 0x0391 ); + if(code >= 0x83b0) (*unip)++; + + }else if( (code >= 0x83bf) && (code <= 0x83d6) ) // α 〜 ω + { + *unip = (u16)( (code - 0x83bf) + 0x03b1 ); + if (code >= 0x83d0) (*unip)++; + + }else if( (code >= 0x8440) && (code <= 0x8460) ) // А 〜 Я + { + *unip = (u16)( (code - 0x8440) + 0x0410 ); + if( code == 0x8446 ) { + *unip = 0x0401; + }else if( code > 0x8446 ){ + (*unip)--; + } + + }else if( (code >= 0x8470) && (code <= 0x8491) ) // а 〜 я ※0x847fは抜け + { + *unip = (u16)( (code - 0x8470) + 0x0430 ); + if( code == 0x8476 ) { + *unip = 0x0451; + }else if( code == 0x847f ) { + *unip = 0x3000; + }else if( code > 0x8476 ){ + (*unip)--; + if( code > 0x847f ){ + (*unip)--; + } + } + + }else if( (code >= 0x849f) && (code <= 0x84be) ) // ─ 〜 ╂ + { + // バラバラなので、テーブル引き + *unip = tblSJIS_UTF16_849f[ code - 0x849f ].unicode; + }else { + *unip = 0x3000; + } + + unip++; + } +} + + +//====================================================== +// UTF16-LEからSJIS-BEへの変換 +//====================================================== +void ExUTF16_LEtoSJIS_BE(u8 *sjisp, u16 *unip, u16 length) +{ + u16 code, sjis_le; + + while( (*unip) && (length-- > 0) ) { + code = *unip++; + sjis_le = 0; + + if(code == 0x00a5) + { + sjis_le = 0x005c; // \ + + }else if(code == 0x005c) + { + sjis_le = 0x815f; // \ + + }else if(code == 0x203e) + { + sjis_le = 0x007e; // ~ + + }else if( (code == 0x000d) || (code == 0x000a) ) { + sjis_le = code; // 改行コード + + }else if( (code >= 0x0020) && (code < 0x007e) ) // ' ' 〜 } + { + sjis_le = code; + + }else if( (code >= 0x00a2) && (code <= 0x00f7) ) + { // Unicode = 0x00a2 - 0x00f7 は、 SJIS = 0x814c - 0x81f7に配置 + sjis_le = SearchUnicodeTable(code, (SjisUtf16Pare *)&tblSJIS_UTF16_8140[0xc], 0x81f7 - 0x814c); + + }else if( (code >= 0xff61) && (code <= 0xff9f) ) // 。 〜 ゚ + { + sjis_le = (u16)( (code - 0xff61) + 0x00a1 ); + + }else if(code == 0x4edd) { + sjis_le = 0x8157; + + }else if( (code >= 0xff01) && (code <= 0xffe5) ) + { + if( (code >= 0xff10) && (code <= 0xff19) ) // 0 〜 9 + { + sjis_le = (u16)( (code - 0xff10) + 0x824f ); + + }else if( (code >= 0xff21) && (code <= 0xff3a) ) // A 〜 Z + { + sjis_le = (u16)( (code - 0xff21) + 0x8260 ); + + }else if( (code >= 0xff41) && (code <= 0xff5a) ) // a 〜 z + { + sjis_le = (u16)( (code - 0xff41) + 0x8281 ); + }else { // Unicode = 0xff01 - 0xffe5 は、 SJIS = 0x8143 - 0x8197に配置 + sjis_le = SearchUnicodeTable(code, (SjisUtf16Pare *)&tblSJIS_UTF16_8140[3], 0x8197 - 0x8143); + } + + }else if( (code >= 0x3000) && (code <= 0x30fe) ) + { + if( (code >= 0x3041) && (code <= 0x3093) ) // ぁ 〜 ん + { + sjis_le = (u16)( (code - 0x3041) + 0x829f ); + + }else if( (code >= 0x30a1) && (code <= 0x30f6) ) // ァ 〜 ヶ ※0x837fは抜け + { + sjis_le = (u16)( (code - 0x30a1) + 0x8340 ); + if( code >= 0x30e0 ) { + (sjis_le)++; + } + }else { // Unicode = 0x3000 - 0x30fe は、 SJIS = 0x8140 - 0x81acに配置 + sjis_le = SearchUnicodeTable(code, (SjisUtf16Pare *)&tblSJIS_UTF16_8140[0], 0x81ac - 0x8140); + } + + }else if( (code >= 0x0391) && (code <= 0x03a9) ) // Α 〜 Ω + { + sjis_le = (u16)( (code - 0x0391) + 0x839f ); + if(code >= 0x03a3) (sjis_le)--; + + }else if( (code >= 0x03b1) && (code <= 0x03c9) ) // α 〜 ω + { + sjis_le = (u16)( (code - 0x03b1) + 0x83bf ); + if (code >= 0x03c3) (sjis_le)--; + + }else if( code == 0x0401 ) + { + sjis_le = 0x8446; + + }else if( (code >= 0x0410) && (code <= 0x042f) ) // А 〜 Я + { + sjis_le = (u16)( (code - 0x0410) + 0x8440 ); + if( code >= 0x0416 ){ + (sjis_le)++; + } + + }else if( (code >= 0x0430) && (code <= 0x044f) ) // а 〜 я ※0x847fは抜け + { + sjis_le = (u16)( (code - 0x0430) + 0x8470 ); + if( code >= 0x0436 ){ + (sjis_le)++; + if( code >= 0x043e ){ + (sjis_le)++; + } + } + + }else if( code == 0x0451 ) + { + sjis_le = 0x8476; + + }else if( (code >= 0x2500) && (code <= 0x254b) ) // ─ 〜 ╂ + { + sjis_le = SearchUnicodeTable(code, (SjisUtf16Pare *)&tblSJIS_UTF16_849f, TBL849f_ELEM_NUM); + + }else if( ( (code >= 0x2010) && (code <= 0x2312) ) || ( (code >= 0x25a0) && (code <= 0x266f) ) ) + { // 上記コードは、 SJIS = 0x815c - 0x81fcに配置 + sjis_le = SearchUnicodeTable(code, (SjisUtf16Pare *)&tblSJIS_UTF16_8140[0x815c - 0x8140], 0x81fc - 0x815c); + + }else + { + sjis_le = 0x8140; + } + + // 変換したSJISコードをバッファに格納 + if( sjis_le & 0xff00) { // ASCIIコードでなければ、ビッグエンディアン形式で格納。 + *sjisp++ = (u8)(sjis_le >> 8); + } + *sjisp++ = (u8)(sjis_le); + } +} + + +// Unicode -> SJISへのテーブル引き +static u16 SearchUnicodeTable(u16 unicode, SjisUtf16Pare *tblp, int elem_num) +{ + elem_num++; + while(elem_num--) { + if(tblp->unicode == unicode) { + return tblp->sjis; + } + tblp++; + } + return 0x8140; +} + + +//====================================================== +// SJIS-BE <-> UTF16-LE変換のチェック +//====================================================== +void CheckSJIS_BEtoUTF16_LE(void) +{ + u16 sjis, sjis_be, rev_sjis, sjis_le; + u16 unicode; + + // ASCIIコードのチェック + for ( sjis = 0; sjis < 0x00ff; sjis++ ) { + unicode = 0; + rev_sjis = 0; + ExSJIS_BEtoUTF16_LE( (u8 *)&sjis, &unicode, 1); + ExUTF16_LEtoSJIS_BE( (u8 *)&rev_sjis, &unicode, 1); + sjis_le = (u16)( (rev_sjis >> 8) | (rev_sjis << 8) ); + OS_Printf("0x%x\t-> 0x%x\t-> 0x%x\n", sjis, unicode, sjis_le); + } + + // SJISコードのチェック + for ( sjis = 0x8140; sjis < 0x84ff; sjis++ ) { + unicode = 0; + rev_sjis = 0; + sjis_be = (u16)( (sjis >> 8) | (sjis << 8) ); + ExSJIS_BEtoUTF16_LE( (u8 *)&sjis_be, &unicode, 1); + ExUTF16_LEtoSJIS_BE( (u8 *)&rev_sjis, &unicode, 1); + sjis_le = (u16)( (rev_sjis >> 8) | (rev_sjis << 8) ); + OS_Printf("0x%x\t-> 0x%x\t-> 0x%x\n", sjis, unicode, sjis_le); + } +} + + +//====================================================== +// SJISコード->Unicodeテーブル +//====================================================== + +// 0x8140〜 +static const SjisUtf16Pare tblSJIS_UTF16_8140[ TBL8140_ELEM_NUM ] = { + { 0x8140, 0x3000 }, //   + { 0x8141, 0x3001 }, // 、 + { 0x8142, 0x3002 }, // 。 + { 0x8143, 0xFF0C }, // , + { 0x8144, 0xFF0E }, // . + { 0x8145, 0x30FB }, // ・ + { 0x8146, 0xFF1A }, // : + { 0x8147, 0xFF1B }, // ; + { 0x8148, 0xFF1F }, // ? + { 0x8149, 0xFF01 }, // ! + { 0x814A, 0x309B }, // ゛ + { 0x814B, 0x309C }, // ゜ + { 0x814C, 0x00B4 }, // ´ + { 0x814D, 0xFF40 }, // ` + { 0x814E, 0x00A8 }, // ¨ + { 0x814F, 0xFF3E }, // ^ + { 0x8150, 0xFFE3 }, //  ̄ + { 0x8151, 0xFF3F }, // _ + { 0x8152, 0x30FD }, // ヽ + { 0x8153, 0x30FE }, // ヾ + { 0x8154, 0x309D }, // ゝ + { 0x8155, 0x309E }, // ゞ + { 0x8156, 0x3003 }, // 〃 + { 0x8157, 0x4EDD }, // 仝 + { 0x8158, 0x3005 }, // 々 + { 0x8159, 0x3006 }, // 〆 + { 0x815A, 0x3007 }, // 〇 + { 0x815B, 0x30FC }, // ー + { 0x815C, 0x2015 }, // ― + { 0x815D, 0x2010 }, // ‐ + { 0x815E, 0xFF0F }, // / + { 0x815F, 0x005C }, // \ + { 0x8160, 0x301C }, // 〜 + { 0x8161, 0x2016 }, // ‖ + { 0x8162, 0xFF5C }, // | + { 0x8163, 0x2026 }, // … + { 0x8164, 0x2025 }, // ‥ + { 0x8165, 0x2018 }, // ‘ + { 0x8166, 0x2019 }, // ’ + { 0x8167, 0x201C }, // “ + { 0x8168, 0x201D }, // ” + { 0x8169, 0xFF08 }, // ( + { 0x816A, 0xFF09 }, // ) + { 0x816B, 0x3014 }, // 〔 + { 0x816C, 0x3015 }, // 〕 + { 0x816D, 0xFF3B }, // [ + { 0x816E, 0xFF3D }, // ] + { 0x816F, 0xFF5B }, // { + { 0x8170, 0xFF5D }, // } + { 0x8171, 0x3008 }, // 〈 + { 0x8172, 0x3009 }, // 〉 + { 0x8173, 0x300A }, // 《 + { 0x8174, 0x300B }, // 》 + { 0x8175, 0x300C }, // 「 + { 0x8176, 0x300D }, // 」 + { 0x8177, 0x300E }, // 『 + { 0x8178, 0x300F }, // 』 + { 0x8179, 0x3010 }, // 【 + { 0x817A, 0x3011 }, // 】 + { 0x817B, 0xFF0B }, // + + { 0x817C, 0x2212 }, // − + { 0x817D, 0x00B1 }, // ± + { 0x817E, 0x00D7 }, // × + { 0x817F, 0x3000 }, // + { 0x8180, 0x00F7 }, // ÷ + { 0x8181, 0xFF1D }, // = + { 0x8182, 0x2260 }, // ≠ + { 0x8183, 0xFF1C }, // < + { 0x8184, 0xFF1E }, // > + { 0x8185, 0x2266 }, // ≦ + { 0x8186, 0x2267 }, // ≧ + { 0x8187, 0x221E }, // ∞ + { 0x8188, 0x2234 }, // ∴ + { 0x8189, 0x2642 }, // ♂ + { 0x818A, 0x2640 }, // ♀ + { 0x818B, 0x00B0 }, // ° + { 0x818C, 0x2032 }, // ′ + { 0x818D, 0x2033 }, // ″ + { 0x818E, 0x2103 }, // ℃ + { 0x818F, 0xFFE5 }, // ¥ + { 0x8190, 0xFF04 }, // $ + { 0x8191, 0x00A2 }, // ¢ + { 0x8192, 0x00A3 }, // £ + { 0x8193, 0xFF05 }, // % + { 0x8194, 0xFF03 }, // # + { 0x8195, 0xFF06 }, // & + { 0x8196, 0xFF0A }, // * + { 0x8197, 0xFF20 }, // @ + { 0x8198, 0x00A7 }, // § + { 0x8199, 0x2606 }, // ☆ + { 0x819A, 0x2605 }, // ★ + { 0x819B, 0x25CB }, // ○ + { 0x819C, 0x25CF }, // ● + { 0x819D, 0x25CE }, // ◎ + { 0x819E, 0x25C7 }, // ◇ + { 0x819F, 0x25C6 }, // ◆ + { 0x81A0, 0x25A1 }, // □ + { 0x81A1, 0x25A0 }, // ■ + { 0x81A2, 0x25B3 }, // △ + { 0x81A3, 0x25B2 }, // ▲ + { 0x81A4, 0x25BD }, // ▽ + { 0x81A5, 0x25BC }, // ▼ + { 0x81A6, 0x203B }, // ※ + { 0x81A7, 0x3012 }, // 〒 + { 0x81A8, 0x2192 }, // → + { 0x81A9, 0x2190 }, // ← + { 0x81AA, 0x2191 }, // ↑ + { 0x81AB, 0x2193 }, // ↓ + { 0x81AC, 0x3013 }, // 〓 + { 0x81AD, 0x3000 }, // + { 0x81AE, 0x3000 }, // + { 0x81AF, 0x3000 }, // + { 0x81B0, 0x3000 }, // + { 0x81B1, 0x3000 }, // + { 0x81B2, 0x3000 }, // + { 0x81B3, 0x3000 }, // + { 0x81B4, 0x3000 }, // + { 0x81B5, 0x3000 }, // + { 0x81B6, 0x3000 }, // + { 0x81B7, 0x3000 }, // + { 0x81B8, 0x2208 }, // ∈ + { 0x81B9, 0x220B }, // ∋ + { 0x81BA, 0x2286 }, // ⊆ + { 0x81BB, 0x2287 }, // ⊇ + { 0x81BC, 0x2282 }, // ⊂ + { 0x81BD, 0x2283 }, // ⊃ + { 0x81BE, 0x222A }, // ∪ + { 0x81BF, 0x2229 }, // ∩ + { 0x81C0, 0x3000 }, // + { 0x81C1, 0x3000 }, // + { 0x81C2, 0x3000 }, // + { 0x81C3, 0x3000 }, // + { 0x81C4, 0x3000 }, // + { 0x81C5, 0x3000 }, // + { 0x81C6, 0x3000 }, // + { 0x81C7, 0x3000 }, // + { 0x81C8, 0x2227 }, // ∧ + { 0x81C9, 0x2228 }, // ∨ + { 0x81CA, 0x00AC }, // ¬ + { 0x81CB, 0x21D2 }, // ⇒ + { 0x81CC, 0x21D4 }, // ⇔ + { 0x81CD, 0x2200 }, // ∀ + { 0x81CE, 0x2203 }, // ∃ + { 0x81CF, 0x3000 }, // + { 0x81D0, 0x3000 }, // + { 0x81D1, 0x3000 }, // + { 0x81D2, 0x3000 }, // + { 0x81D3, 0x3000 }, // + { 0x81D4, 0x3000 }, // + { 0x81D5, 0x3000 }, // + { 0x81D6, 0x3000 }, // + { 0x81D7, 0x3000 }, // + { 0x81D8, 0x3000 }, // + { 0x81D9, 0x3000 }, // + { 0x81DA, 0x2220 }, // ∠ + { 0x81DB, 0x22A5 }, // ⊥ + { 0x81DC, 0x2312 }, // ⌒ + { 0x81DD, 0x2202 }, // ∂ + { 0x81DE, 0x2207 }, // ∇ + { 0x81DF, 0x2261 }, // ≡ + { 0x81E0, 0x2252 }, // ≒ + { 0x81E1, 0x226A }, // ≪ + { 0x81E2, 0x226B }, // ≫ + { 0x81E3, 0x221A }, // √ + { 0x81E4, 0x223D }, // ∽ + { 0x81E5, 0x221D }, // ∝ + { 0x81E6, 0x2235 }, // ∵ + { 0x81E7, 0x222B }, // ∫ + { 0x81E8, 0x222C }, // ∬ + { 0x81E9, 0x3000 }, // + { 0x81EA, 0x3000 }, // + { 0x81EB, 0x3000 }, // + { 0x81EC, 0x3000 }, // + { 0x81EE, 0x3000 }, // + { 0x81EE, 0x3000 }, // + { 0x81EF, 0x3000 }, // + { 0x81F0, 0x212B }, // Å + { 0x81F1, 0x2030 }, // ‰ + { 0x81F2, 0x266F }, // ♯ + { 0x81F3, 0x266D }, // ♭ + { 0x81F4, 0x266A }, // ♪ + { 0x81F5, 0x2020 }, // † + { 0x81F6, 0x2021 }, // ‡ + { 0x81F7, 0x00B6 }, // ¶ + { 0x81F8, 0x3000 }, // + { 0x81F9, 0x3000 }, // + { 0x81FA, 0x3000 }, // + { 0x81FB, 0x3000 }, // + { 0x81FC, 0x25EF }, // ◯ +}; + + +// 0x849f〜 +// Unicodeでは、0x2500-0x254bの間 +static const SjisUtf16Pare tblSJIS_UTF16_849f[ TBL849f_ELEM_NUM ] = { + { 0x849F, 0x2500 }, // ─ + { 0x84A0, 0x2502 }, // │ + { 0x84A1, 0x250C }, // ┌ + { 0x84A2, 0x2510 }, // ┐ + { 0x84A3, 0x2518 }, // ┘ + { 0x84A4, 0x2514 }, // └ + { 0x84A5, 0x251C }, // ├ + { 0x84A6, 0x252C }, // ┬ + { 0x84A7, 0x2524 }, // ┤ + { 0x84A8, 0x2534 }, // ┴ + { 0x84A9, 0x253C }, // ┼ + { 0x84AA, 0x2501 }, // ━ + { 0x84AB, 0x2503 }, // ┃ + { 0x84AC, 0x250F }, // ┏ + { 0x84AD, 0x2513 }, // ┓ + { 0x84AE, 0x251B }, // ┛ + { 0x84AF, 0x2517 }, // ┗ + { 0x84B0, 0x2523 }, // ┣ + { 0x84B1, 0x2533 }, // ┳ + { 0x84B2, 0x252B }, // ┫ + { 0x84B3, 0x253B }, // ┻ + { 0x84B4, 0x254B }, // ╋ + { 0x84B5, 0x2520 }, // ┠ + { 0x84B6, 0x252F }, // ┯ + { 0x84B7, 0x2528 }, // ┨ + { 0x84B8, 0x2537 }, // ┷ + { 0x84B9, 0x253F }, // ┿ + { 0x84BA, 0x251D }, // ┝ + { 0x84BB, 0x2530 }, // ┰ + { 0x84BC, 0x2525 }, // ┥ + { 0x84BD, 0x2538 }, // ┸ + { 0x84BE, 0x2542 }, // ╂ +}; + diff --git a/build/systemMenu_RED/ARM9/src/DS_Setting/unicode.h b/build/systemMenu_RED/ARM9/src/DS_Setting/unicode.h new file mode 100644 index 00000000..b5592556 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/DS_Setting/unicode.h @@ -0,0 +1,40 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: unicode.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __UNICODE_H_ +#define __UNICODE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// define data---------------------------------- + +// function's prototype declaration------------- +void ExSJIS_BEtoUTF16_LE(u8 *sjisp, u16 *unip, u16 length); +void ExUTF16_LEtoSJIS_BE(u8 *sjisp, u16 *unip, u16 length); +void CheckSJIS_BEtoUTF16_LE(void); + + +#ifdef __cplusplus +} +#endif + +#endif // __UNICODE_H_ + diff --git a/build/systemMenu_RED/ARM9/src/Logo/logoData.c b/build/systemMenu_RED/ARM9/src/Logo/logoData.c new file mode 100644 index 00000000..98fad436 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/Logo/logoData.c @@ -0,0 +1,204 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: logoData.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "main.h" + +// define data----------------------------------------------------------- +#define NIN_LOGO_LENGTH 0x9c // Nintendoロゴデータサイズ + +#define OAM_OBJ_BLEND 0x00000400 // OBJ半透明モード +#define OAM_SIZE_64x32 0xc0004000 // OBJ 64x32ドット +#define OAM_COLOR_256 0x00002000 // 256色 選択 +#define OAM_AFFINE_NONE 0x00000000 // アフィン無効モード +#define OAM_V_POS_SHIFT 0 +#define OAM_H_POS_SHIFT 16 +#define OAM_AFFINE_NO_SHIFT 25 +#define OAM_PRIORITY_SHIFT 10 +#define OAM_PLTT_SHIFT 12 + + +// extern data----------------------------------------------------------- + +// function's prototype-------------------------------------------------- +void LoadLogoData( void ); +static void UnCompNintendoLogo( u16 *NintendoLogoDatap, u16 *dstp, u32 *temp ); +static void SVC_DiffUnFilter16_16( u16 *srcp,u16 *dstp ); +static s32 MEMB_InitFunc( const u8 *devicep, void *ramp, const void *paramp ); +static s32 MEMB_TerminateFunc( const u8 *devicep ); +static u8 MEMB_ByteStreamFunc( const u8 *devicep ); +static u32 MEMB_WordStreamFunc( const u8 *devicep ); + +// global variable------------------------------------------------------- + +// static variable------------------------------------------------------- + +// const data------------------------------------------------------------ +const u32 OamLogoData[ 2 ][ 2 ] = { + { + OAM_OBJ_BLEND | OAM_SIZE_64x32 | OAM_AFFINE_NONE | OAM_COLOR_256 | + 71 << OAM_H_POS_SHIFT | + 88 << OAM_V_POS_SHIFT | + 0 << OAM_AFFINE_NO_SHIFT, + 0 << 1 | 5 << OAM_PLTT_SHIFT | 2 << OAM_PRIORITY_SHIFT + }, + + { + OAM_OBJ_BLEND | OAM_SIZE_64x32 | OAM_AFFINE_NONE | OAM_COLOR_256 | + 71 + 64 << OAM_H_POS_SHIFT | + 88 << OAM_V_POS_SHIFT | + 0 << OAM_AFFINE_NO_SHIFT, + 8 << 1 | 5 << OAM_PLTT_SHIFT | 2 << OAM_PRIORITY_SHIFT + }, +}; + +static const MIReadStreamCallbacks memb_ifp={ + MEMB_InitFunc, + MEMB_TerminateFunc, + MEMB_ByteStreamFunc, + NULL, + MEMB_WordStreamFunc, +}; + +static const MIUnpackBitsParam Nin_UnPackBitsParam={ + (8*8/2)*( 7*2), 1, 8, 0x1e, 0 +}; + +static const u8 Nin_Char_Diff_Huff_Table[] = { + 0x24,0xd4,0x00,0x00, + 0x0f,0x40,0x00,0x00,0x00,0x01,0x81,0x82,0x82,0x83,0x0f,0x83,0x0c,0xc3,0x03,0x83, + 0x01,0x83,0x04,0xc3,0x08,0x0e,0x02,0xc2,0x0d,0xc2,0x07,0x0b,0x06,0x0a,0x05,0x09, +}; + +static const u8 Nin_Char_Diff_Huff[] ATTRIBUTE_ALIGN( 2 ) = { + 0x24, 0xff, 0xae, 0x51, 0x69, 0x9a, 0xa2, 0x21, 0x3d, 0x84, 0x82, 0x0a, 0x84, 0xe4, 0x09, 0xad, + 0x11, 0x24, 0x8b, 0x98, 0xc0, 0x81, 0x7f, 0x21, 0xa3, 0x52, 0xbe, 0x19, 0x93, 0x09, 0xce, 0x20, + 0x10, 0x46, 0x4a, 0x4a, 0xf8, 0x27, 0x31, 0xec, 0x58, 0xc7, 0xe8, 0x33, 0x82, 0xe3, 0xce, 0xbf, + 0x85, 0xf4, 0xdf, 0x94, 0xce, 0x4b, 0x09, 0xc1, 0x94, 0x56, 0x8a, 0xc0, 0x13, 0x72, 0xa7, 0xfc, + 0x9f, 0x84, 0x4d, 0x73, 0xa3, 0xca, 0x9a, 0x61, 0x58, 0x97, 0xa3, 0x27, 0xfc, 0x03, 0x98, 0x76, + 0x23, 0x1d, 0xc7, 0x61, 0x03, 0x04, 0xae, 0x56, 0xbf, 0x38, 0x84, 0x00, 0x40, 0xa7, 0x0e, 0xfd, + 0xff, 0x52, 0xfe, 0x03, 0x6f, 0x95, 0x30, 0xf1, 0x97, 0xfb, 0xc0, 0x85, 0x60, 0xd6, 0x80, 0x25, + 0xa9, 0x63, 0xbe, 0x03, 0x01, 0x4e, 0x38, 0xe2, 0xf9, 0xa2, 0x34, 0xff, 0xbb, 0x3e, 0x03, 0x44, + 0x78, 0x00, 0x90, 0xcb, 0x88, 0x11, 0x3a, 0x94, 0x65, 0xc0, 0x7c, 0x63, 0x87, 0xf0, 0x3c, 0xaf, + 0xd6, 0x25, 0xe4, 0x8b, 0x38, 0x0a, 0xac, 0x72, 0x21, 0xd4, 0xf8, 0x07, 0x56, 0xcf, 0x00, 0x00, +}; + + +// ============================================================================ +// ロゴデータロード +// ============================================================================ +void LoadLogoData(void) +{ + u32 temp[ 0x500 / sizeof(u32) ]; + u16 *pBuff = NNS_FndAllocFromAllocator( &g_allocator, 0x1000 ); + MI_CpuClear32( pBuff, 0x1000 ); + + if( pBuff == NULL ) { + OS_TPrintf( " %s : memory allocate error.\n", __FUNCTION__ ); + return; + } + + UnCompNintendoLogo( (u16 *)Nin_Char_Diff_Huff, pBuff, temp ); // NintendoロゴをpBuffに展開 + MI_CpuCopy32( pBuff, (u32 *)HW_OBJ_VRAM, 0x340 ); // OBJ-VRAMにロード + MI_CpuCopy32( (void *)( (u32)pBuff + 0x340 ), (u32 *)( HW_OBJ_VRAM + 0x400 ), 8*8*13 ); + + *(vu16 *)( HW_OBJ_PLTT + 0x3e ) = 0x0000; // OBJパレットセット + *(vu16 *)HW_BG_PLTT = 0xffff; // バックドロップを「白」にする。 + + MI_CpuCopy32( OamLogoData, (u32 *)HW_OAM, sizeof(OamLogoData) ); // Nintendoロゴ用OAMデータセット + NNS_FndFreeToAllocator( &g_allocator, pBuff ); +} + + +// Nintendoロゴ展開ルーチン (r0=ロゴ圧縮データ r1=展開先アドレス) +#include + +asm void UnCompNintendoLogo(u16 *NintendoLogoDatap, u16 *dstp, u32 *temp) +{ + push {r0-r2,r4, lr} + + ldr r0, =Nin_Char_Diff_Huff_Table + mov r2, #0x0e + lsl r2, r2, #8 + add r1, r1, r2 // 引数1+0xe00 + mov r4, r1 + mov r2, #36 + bl MIi_CpuCopy16 // Nintendoロゴの圧縮テーブル部分のみをコピーしてくる + + ldr r0, [sp, #0] // 引数0(NinLogoBak[36]) + mov r2, #36 + add r1, r4, r2 // 引数1+0xe00+36 + mov r2, #NIN_LOGO_LENGTH + bl MIi_CpuCopy16 // 引数0からNintendoロゴデータ本体をコピーしてくる + + mov r0, r4 // 引数1+0xe00 + ldr r1, [sp, #4] // 引数1 + ldr r2, [sp, #8] // 引数2 + ldr r3, =memb_ifp + bl SVC_UncompressHuffmanFromDevice // ハフマン展開 + + ldr r0, [sp, #4] + ldr r2, =0x0000d082 + str r2, [r0,#0] + + mov r1, r4 // 引数1+0xe00 + bl SVC_DiffUnFilter16_16 // Diff展開 + + mov r0, r4 // 引数1+0xe00 + ldr r1, [sp, #4] // 引数1 + ldr r2, =Nin_UnPackBitsParam + bl SVC_UnpackBits // ビット展開 + + pop {r0-r2,r4, pc} +} + + +// 差分フィルタ展開システムコール(16Bit→16Bit) (r0=Srcp, r1=Destp) +static asm void SVC_DiffUnFilter16_16(u16 *srcp,u16 *dstp) +{ + swi 24 + bx lr +} +#include + + +// ============================================================================ +// バイトアクセス可能メモリ用アクセスルーチン群 +// ============================================================================ +static s32 MEMB_InitFunc(const u8 *devicep, void *ramp, const void *paramp) +{ +#pragma unused(ramp) + if(paramp) return (s32)MEMB_WordStreamFunc(devicep); + else return 0; +} + +static s32 MEMB_TerminateFunc(const u8 *devicep) +{ +#pragma unused(devicep) + return 0; +} + +static u8 MEMB_ByteStreamFunc(const u8 *devicep) +{ + return *devicep; +} + +static u32 MEMB_WordStreamFunc(const u8 *devicep) +{ + return *(u32 *)devicep; +} + diff --git a/build/systemMenu_RED/ARM9/src/Logo/logoDemo.c b/build/systemMenu_RED/ARM9/src/Logo/logoDemo.c new file mode 100644 index 00000000..d023bfef --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/Logo/logoDemo.c @@ -0,0 +1,130 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: logoDemo.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include "logoDemo.h" + +// define data-------------------------------------------------------- + +#define LOGO_DISP_FRAME 60 // ロゴ表示フレーム数 + +// ロゴ表示ステータス構造体 +typedef struct LogoStatus { + s32 state; + BOOL enable; + s32 value_A; + s32 value_B; + s32 mainCounter; +}LogoStatus; + +// extern data-------------------------------------------------------- +extern void LoadLogoData( void ); + +// function's prototype----------------------------------------------- + +// static variables--------------------------------------------------- +static LogoStatus s_logo = { 0, TRUE, 0, 0, 0 }; + +// const data--------------------------------------------------------- + +static void LogoInit( void ) +{ + // 画面OFF + GX_DispOff(); + GXS_DispOff(); + + // VRAM割り当て&クリア + GX_SetBankForOBJ( GX_VRAM_OBJ_128_A ); //  〃     OBJ用 + GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS, GX_BGMODE_0, GX_BG0_AS_2D ); + MI_CpuClearFast( (void *)HW_OBJ_VRAM, 0x1000 ); // OBJ-VRAM クリア + MI_DmaFill32( 3, (void *)HW_OAM, 192, HW_OAM_SIZE ); // OAM クリア + + // 画面設定 + GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS, GX_BGMODE_2, GX_BG0_AS_2D ); + GX_SetOBJVRamModeChar( GX_OBJVRAMMODE_CHAR_2D ); + G2_SetBlendAlpha( GX_BLEND_PLANEMASK_OBJ, GX_BLEND_PLANEMASK_BD, s_logo.value_A, s_logo.value_B ); + GX_SetVisiblePlane( GX_PLANEMASK_OBJ ); + + // ロゴデータロード + LoadLogoData(); + + s_logo.value_A = 0; + s_logo.value_B = 16; + + // メイン画面のみON + GX_DispOn(); +} + + +// ロゴメイン +int LogoMain() +{ + if( !IsLogoEnable() ) { + return 1; + } + + switch( s_logo.state ) { + case 0: // 初期設定 + LogoInit(); + + s_logo.mainCounter = 0; + s_logo.state++; + break; + + case 1: // Nintendoロゴフェードイン + if( s_logo.mainCounter++ < 16 ){ // Nintendoロゴ 表示 + G2_ChangeBlendAlpha( ++s_logo.value_A, --s_logo.value_B ); + }else { + s_logo.mainCounter = 0; + s_logo.state++; + } + break; + + + case 2: // Nintendoロゴ表示 + if( s_logo.mainCounter++ == LOGO_DISP_FRAME ) { + s_logo.mainCounter = 0; + s_logo.state++; + } + break; + + case 3: // Nintendoロゴフェードアウト + if( s_logo.mainCounter++ < 16 ) { + G2_ChangeBlendAlpha( --s_logo.value_A, ++s_logo.value_B ); + }else { + return 1; + } + break; + + default: + break; + } + + return 0; +} + + +// ロゴ表示をOFFにする。 +void SetLogoEnable( BOOL enable ) +{ + s_logo.enable = enable; +} + +// ロゴ表示状態取得 +BOOL IsLogoEnable(void) +{ + return s_logo.enable; +} diff --git a/build/systemMenu_RED/ARM9/src/Logo/logoDemo.h b/build/systemMenu_RED/ARM9/src/Logo/logoDemo.h new file mode 100644 index 00000000..251087d9 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/Logo/logoDemo.h @@ -0,0 +1,36 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: logoDemo.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef _LOGO_DEMO_H +#define _LOGO_DEMO_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern void LoadLogo( void ); +extern int LogoMain( void ); +extern void SetLogoEnable( BOOL enable ); +extern BOOL IsLogoEnable( void ); + +#ifdef __cplusplus +} +#endif + +#endif /* _LOGO_DEMO_H */ diff --git a/build/systemMenu_RED/ARM9/src/launcher.c b/build/systemMenu_RED/ARM9/src/launcher.c new file mode 100644 index 00000000..1e6e5d7e --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/launcher.c @@ -0,0 +1,244 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: launcher.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "main.h" +#include "logoDemo.h" +#include "DS_Setting.h" + + +// define data------------------------------------------ +#define LAUNCHER_ELEMENT_NUM 4 // ロゴメニューの項目数 + +#define B_LIGHT_BUTTON_TOP_X 24 +#define B_LIGHT_BUTTON_TOP_Y 21 +#define B_LIGHT_BUTTON_BOTTOM_X ( B_LIGHT_BUTTON_TOP_X + 7 ) +#define B_LIGHT_BUTTON_BOTTOM_Y ( B_LIGHT_BUTTON_TOP_Y + 2 ) + + +// extern data------------------------------------------ + +// function's prototype declaration--------------------- +static void DrawBackLightSwitch(void); +static void DrawLauncher(u16 nowCsr, const MenuParam *pMenu); + +// global variable ------------------------------------- + +// static variable ------------------------------------- +static u16 s_csr = 0; // メニューのカーソル位置 +static const u16 *s_pStrLauncher[ LAUNCHER_ELEMENT_NUM ]; // ロゴメニュー用文字テーブルへのポインタリスト + +// const data ----------------------------------------- +//=============================================== +// Launcher.c +//=============================================== +static const u16 *const s_pStrLauncherElemTbl[ LAUNCHER_ELEMENT_NUM ][ LANG_CODE_MAX ] = { + { + (const u16 *)L"DSカード", + (const u16 *)L"DS Card", + (const u16 *)L"DS Card(F)", + (const u16 *)L"DS Card(G)", + (const u16 *)L"DS Card(I)", + (const u16 *)L"DS Card(S)", + }, + { + (const u16 *)L"ピクトチャット", + (const u16 *)L"PictoChat", + (const u16 *)L"PictoChat(F)", + (const u16 *)L"PictoChat(G)", + (const u16 *)L"PictoChat(I)", + (const u16 *)L"PictoChat(S)", + }, + { + (const u16 *)L"DSダウンロードプレイ", + (const u16 *)L"DS Download Play", + (const u16 *)L"DS Download Play(F)", + (const u16 *)L"DS Download Play(G)", + (const u16 *)L"DS Download Play(I)", + (const u16 *)L"DS Download Play(S)", + }, + { + (const u16 *)L"本体設定", + (const u16 *)L"Machine Settings", + (const u16 *)L"Machine Settings(F)", + (const u16 *)L"Machine Settings(G)", + (const u16 *)L"Machine Settings(I)", + (const u16 *)L"Machine Settings(S)", + }, +}; + +static MenuPos s_launcherPos[] = { + { TRUE, 4 * 8, 8 * 8 }, + { TRUE, 4 * 8, 10 * 8 }, + { TRUE, 4 * 8, 12 * 8 }, + { TRUE, 4 * 8, 14 * 8 }, + { TRUE, 4 * 8, 16 * 8 }, +}; + +static const MenuParam s_launcherParam = { + LAUNCHER_ELEMENT_NUM, + TXT_COLOR_BLACK, + TXT_COLOR_GREEN, + TXT_COLOR_RED, + &s_launcherPos[0], + (const u16 **)&s_pStrLauncher, +}; + +static const u16 *const str_backlight[] = { + (const u16 *)L"BLT:ON ", + (const u16 *)L"BLT:OFF", +}; + +//====================================================== +// ランチャー +//====================================================== + +// ランチャーの初期化 +void LauncherInit(void) +{ + NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_WHITE ); + + GX_DispOn(); + + DrawBackLightSwitch(); + + PrintfSJIS( 0, 0, TXT_COLOR_BLUE, "TWL-SYSTEM MENU ver.%06x", SYSMENU_VER ); + + // NITRO設定データのlanguageに応じたメインメニュー構成言語の切り替え + { + int i; + NvLangCode langCode = LANG_ENGLISH; + if( GetSYSMWork()->ncd_invalid == 0 ) { + langCode = (NvLangCode)GetNCDWork()->option.language; + } + for( i = 0; i < LAUNCHER_ELEMENT_NUM; i++ ) { + s_pStrLauncher[ i ] = s_pStrLauncherElemTbl[ i ][ langCode ]; + } + } + + if( !SYSM_IsNITROCard() ) { + s_launcherPos[ 0 ].enable = FALSE; // DSカードが無い時は、先頭要素を無効にする。 + } + + InitGetAndDrawRtcData( RTC_DATE_TOP_X, RTC_DATE_TOP_Y, RTC_TIME_TOP_X, RTC_TIME_TOP_Y ); + + DrawLauncher( s_csr, &s_launcherParam ); + + SVC_CpuClear( 0x0000, &tpd, sizeof(TpWork), 16 ); + + GX_SetVisiblePlane( GX_PLANEMASK_BG0 ); +} + + +// ランチャーメイン +IPL2BootType LauncherMain( BOOL boot_decision ) +{ +#pragma unused( boot_decision ) + + static BOOL touch_bl = FALSE; + BOOL tp_bl_on_off = FALSE; + BOOL tp_select = FALSE; + u16 csr_old; + + // RTC情報の取得&表示 + GetAndDrawRtcData(); + + //-------------------------------------- + // バックライトON,OFF制御 + //-------------------------------------- + if(tpd.disp.touch) { + BOOL range = InRangeTp( B_LIGHT_BUTTON_TOP_X*8, B_LIGHT_BUTTON_TOP_Y*8-4, + B_LIGHT_BUTTON_BOTTOM_X*8, B_LIGHT_BUTTON_BOTTOM_Y*8-4, &tpd.disp ); + if( range && !touch_bl ) { + touch_bl = TRUE; + tp_bl_on_off = TRUE; + } + }else { + touch_bl = FALSE; + } + + if( (pad.trg & PAD_BUTTON_R) || (tp_bl_on_off) ) { + GetNCDWork()->option.backLightOffFlag ^= 0x01; + DrawBackLightSwitch(); + } + + //-------------------------------------- + // キー入力処理 + //-------------------------------------- + if(pad.trg & PAD_KEY_DOWN){ // カーソルの移動 + if( ++s_csr == LAUNCHER_ELEMENT_NUM ) { + s_csr = 0; + } + } + if( pad.trg & PAD_KEY_UP ){ + if( --s_csr & 0x80 ) { + s_csr = LAUNCHER_ELEMENT_NUM - 1; + } + } + csr_old = s_csr; + tp_select = SelectMenuByTP( &s_csr, &s_launcherParam ); + + DrawLauncher( s_csr, &s_launcherParam ); + + if( ( pad.trg & PAD_BUTTON_A ) || ( tp_select ) ) { // メニュー項目への分岐 + if( s_launcherPos[ 0 ].enable ) { + NNS_G2dCharCanvasClear( &gCanvas, TXT_COLOR_WHITE ); + return (IPL2BootType)( s_csr + 1 ); + } + } + + return (IPL2BootType)0; +} + + +// ランチャー描画 +static void DrawLauncher(u16 nowCsr, const MenuParam *pMenu) +{ + int i; + int color; + + for( i = 0; i < pMenu->num; i++ ) { + if(i == nowCsr) { + if( !pMenu->pos[ i ].enable ) { + color = pMenu->disable_color; + }else { + color = pMenu->select_color; + } + }else { + color = pMenu->normal_color; + } + PutStringUTF16( pMenu->pos[ i ].x, pMenu->pos[ i ].y, color, (pMenu->str_elem)[ i ] ); + } +} + + +// バックライトスイッチの表示 +static void DrawBackLightSwitch(void) +{ + u16 color; + + if( GetNCDWork()->option.backLightOffFlag ) { + color = TXT_COLOR_BLACK; + }else { + color = TXT_COLOR_RED; + } + + PutStringUTF16( B_LIGHT_BUTTON_TOP_X, B_LIGHT_BUTTON_TOP_Y, color, + str_backlight[ GetNCDWork()->option.backLightOffFlag ] ); +} + + diff --git a/build/systemMenu_RED/ARM9/src/main.c b/build/systemMenu_RED/ARM9/src/main.c new file mode 100644 index 00000000..3f34c0ea --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/main.c @@ -0,0 +1,409 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: main.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include "main.h" +#include "logoDemo.h" +#include "DS_Setting.h" +#include "DS_DownloadPlay.h" +#include "DS_Chat.h" + +// extern data----------------------------------------------------------------- + +// define data----------------------------------------------------------------- + +// function's prototype------------------------------------------------------- +static void InitAllocator( NNSFndAllocator* pAllocator ); +static void InitAllocSystem( void ); +static BOOL CheckBootStatus( void ); +static void INTR_VBlank( void ); + +// global variable------------------------------------------------------------- +NNSFndAllocator g_allocator; + +// static variable------------------------------------------------------------- +static BannerFile banner; // バナーデータ + +// const data------------------------------------------------------------------ + +#if 0 +typedef struct CardStatus { + u16 primarySlot; // PULLOUT, DETECT, VALID, INVALID + u16 secondarySlot; // 同上。 +}CardStatus; + +typedef struct TitleProperty { // この情報は、ランチャー時には認証通ってないけど、起動時には認証通すので大丈夫だろう。 + u64 titleID; // アプリケーション識別ID + u32 platform; // NTR, TWL (HYBLIDはTWLを返す) + void *pBanner; // 固定長フォーマットなら偽造されても大丈夫だろう。 +}TitleProperty; + + +void TwlMain( void ) +{ + u32 state = START; + u32 filter_flag; + TitleProperty *pBootTitle = NULL; + + // 初期化 + SYSM_Init(); // SYSM_CreateCardThread();も含む + + // 本体設定データのリード + SYSM_ReadTWLSetting( pTWLSetting ); + + // リセットパラメータの取得。(PMICの値&メインメモリの値) + SYSM_GetResetParam( pResetParam ); + if( pResetParam->pBootTitle ) { // アプリ直接起動の指定があったらロゴデモを飛ばして起動 + pBootTitle = pResetParam->pBootTitle; + state = BOOT; + } + + // NANDアプリリストの取得 + filter_flag = ALL_APP; + SYSM_GetNandTitleList( pTitleList_Nand, filter_flag ); // filter_flag : ALL, ALL_APP, SYS_APP, USER_APP, Data only, 等の条件を指定してタイトルリストを取得する。 + // return : *TitleProperty Array + // コンテント(リソース)ファイルのリード + SYSM_ReadContentFile( ContentID ); + // 共有コンテントファイルのリード + SYSM_ReadSharedContentFile( ContentID ); + + while( 1 ) { + CardStatus cardStatus = SYSM_GetCardTitleList( pTitleList_Card ); // カードアプリリストの取得(スレッドで随時カード挿抜を通知されるものをメインループで取得) + + switch( state ) { + case START: + LogoInit(); + state = LOGODEMO; + break; + case LOGODEMO: + if( LogoDemo() ) { + LauncherInit( pTitleList_Nand, pTitleList_Card ); + state = LAUNCHER; + } + break; + case LAUNCHER: + pBootTitle = Launcher( pTitleList_Card, cardStatus ); + if( pBootTitle ) { + state = BOOT; + } + break; + case BOOT: + if( pBootTitle ) { + if( SYSM_CheckTitlePointer( pBootTitle ) && // ポインタチェック + SYSM_AuthAndLoadTitle ( pBootTitle ) ) { // ROMヘッダ認証 + SYSM_Finalize(); // 終了処理 + return; + } + state = STOP; + } + break; + case STOP: + break; + } + } +#endif + +extern void SampleMain(void); + +// ============================================================================ +// function's description +// ============================================================================ +void TwlMain(void) +{ + typedef enum PrgState { + STATE_START = 1, + STATE_LOGO_DISP, + STATE_LOGO_MENU, + STATE_WAIT_BOOT + }PrgState; + + PrgState prg_state = STATE_START; + BOOL boot_decision = FALSE; + + // 初期化---------------------------------- + SYSM_Init(); // システムメニュー関連データの初期化(TwlMainの先頭でコールして下さい。) + + OS_Init(); + + (void)OS_EnableIrq(); + (void)OS_EnableInterrupts(); + + FS_Init( FS_DMA_NOT_USE ); + GX_Init(); + GX_SetPower(GX_POWER_ALL); // 各ロジック パワーON + + // 割り込み許可---------------------------- + (void)OS_SetIrqFunction(OS_IE_V_BLANK, INTR_VBlank); + (void)OS_EnableIrqMask(OS_IE_V_BLANK); + (void)GX_VBlankIntr(TRUE); + + // デバイス初期化------------------------------- +#ifndef __TP_OFF + TP_Init(); +#endif + (void)RTC_Init(); + + // システムの初期化------------------ + InitAllocator( &g_allocator ); + CMN_InitFileSystem( &g_allocator ); + +// InitAllocSystem(); + + // ARM7初期化待ち-------------------------- + if( SYSM_WaitARM7Init() ) { // ARM7側の初期化が終わるのを待ってからメインループ開始 + return; // TRUEが返されたら、デバッガブートなのでリターン + } + + // メインループ---------------------------- + while(1){ + OS_WaitIrq(1, OS_IE_V_BLANK); // Vブランク割り込み待ち + ReadKeyPad(); // キー入力の取得 + + if(SYSM_IsTPReadable()) { + ReadTpData(); // TP入力の取得 + } + +// if(SYSM_Main()) { // IPL2システムのメイン +// return; // TRUEが帰ってきたらメインループからリターン(NITROゲーム起動等) +// } + + switch(prg_state) { + case STATE_START: + boot_decision = CheckBootStatus(); // ブート状態をチェックする。(ショートカット起動やコンパイルスイッチによる強制起動) +// if( !SYSM_GetBannerFile( &banner ) ) { // バナーデータのリード +// OS_Printf("ROM banner data read failed.\n"); +// } + prg_state = STATE_LOGO_DISP; + break; + + //----------------------------------- + // NITROロゴ表示 + //----------------------------------- + case STATE_LOGO_DISP: + // 自動起動ONの時のキーショートカット処理 + if( GetNCDWork()->option.autoBootFlag ) { // TPタッチされるか、Bボタンが押下されたら今回の自動起動をOFFにする。 + + ReadTpDataLogoDirectBootCancel(); // ※red_ipl2特有の処理。red_ipl2のTP仕様は特許にひっかかっているので使えないが、ここだけは有効にしたいので、無理やり実装。 + + if( (tpd.disp.touch) || (pad.trg & PAD_BUTTON_B) ) { + boot_decision = 0; + SYSM_ClearBootFlag( BFLG_BOOT_NITRO | BFLG_BOOT_AGB | BFLG_BOOT_BMENU ); + } + } + + if( LogoMain() ) { // ロゴ表示ルーチン(※BFLG_GAMEBOY_LOGO_OFFの時は即終了) + InitBG(); // BG初期化 + LauncherInit(); // ブート未決定時のみロゴメニューを初期化する。 + + prg_state = STATE_LOGO_MENU; + } + break; // ※NITROカードが正当でない場合は、このまま無限ループ。 + + //----------------------------------- + // ロゴメニューで起動モード選択 + //----------------------------------- + case STATE_LOGO_MENU: + { + IPL2BootType command = LauncherMain( boot_decision ); + + switch(command) { + case BOOT_TYPE_UNSOLVED: + break; + + case BOOT_TYPE_NITRO: +// if( !SYSM_BootNITRO() ) { +// (void)DrawStringSJIS( 4, 20, RED, (const u8 *)"This NITRO card is invalid!!"); +// } + break; + + case BOOT_TYPE_PICT_CHAT: +// (void)SYSM_BootPictChat(); + break; + + case BOOT_TYPE_WIRELESS_BOOT: +// (void)SYSM_BootDSDownloadPlay(); + break; + + case BOOT_TYPE_BMENU: +// (void)SYSM_BootMachineSetting(); + break; + + default: + OS_Panic( "ERROR: boot code failed : %d\n", command ); + } + if(command) { + prg_state = STATE_WAIT_BOOT; + } + } + break; + case STATE_WAIT_BOOT: +// SYSM_PermitToBootSelectedTarget(); + break; + } + + if ( PAD_DetectFold() == TRUE ) { // スリープモードへの遷移 +// SYSM_FinalizeCardPulledOut(); + SYSM_GoSleepMode(); +// (void)SYSM_IsCardPulledOut(); // カード抜け検出コマンド発行 +// SYSM_FinalizeCardPulledOut(); + // カード抜け検出 +// if ( SYSM_IsCardPulledOut() ) { + if ( 0 ) { + (void)PM_ForceToPowerOff(); + } + } + +// if (SYSM_IsCardPulledOut()) { // カード抜け検出 + if ( 0 ) { + OS_Printf("Card is pulled out.\n"); + OS_Terminate(); + } + + OS_PrintServer(); // ARM7からのプリントデバッグを処理する + + //---- BG-VRAMの更新 +// DC_FlushRange ( bgBakS, sizeof(bgBakS) ); +// MI_CpuCopyFast( bgBakS, (void*)(HW_DB_BG_VRAM+0xf000), sizeof(bgBakS) ); + } +} + + +// アロケータの初期化 +static void InitAllocator( NNSFndAllocator* pAllocator ) +{ + u32 arenaLow = MATH_ROUNDUP ((u32)OS_GetMainArenaLo(), 16); + u32 arenaHigh = MATH_ROUNDDOWN((u32)OS_GetMainArenaHi(), 16); + u32 heapSize = arenaHigh - arenaLow; + void* heapMemory = OS_AllocFromMainArenaLo(heapSize, 16); + NNSFndHeapHandle heapHandle; + SDK_NULL_ASSERT( pAllocator ); + + heapHandle = NNS_FndCreateExpHeap(heapMemory, heapSize); + SDK_ASSERT( heapHandle != NNS_FND_HEAP_INVALID_HANDLE ); + + NNS_FndInitAllocatorForExpHeap(pAllocator, heapHandle, 4); +} + +#if 0 +// mallocシステムの初期化 +static void InitAllocSystem(void) +{ + void* tempLo; + OSHeapHandle hh; + + tempLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 16); + OS_SetArenaLo(OS_ARENA_MAIN, tempLo); + OS_TPrintf( "ArenaLo : %08x ArenaHi : %08x\n", OS_GetMainArenaLo(), OS_GetMainArenaHi() ); + + hh = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi()); + if(hh < 0) { + OS_Panic("ARM9: Fail to create heap...\n"); + } + hh = OS_SetCurrentHeap(OS_ARENA_MAIN, hh); +} +#endif + +// ブート状態を確認し、ロゴ表示有無を判断する------- +static BOOL CheckBootStatus(void) +{ + BOOL boot_decision = FALSE; // 「ブート内容未定」に + BOOL other_shortcut_off = FALSE; + + //----------------------------------------------------- + // デバッグ用コンパイルスイッチによる挙動 + //----------------------------------------------------- + { +#ifdef __FORCE_BOOT_BMENU // ※ブートメニュー強制起動スイッチがONか? + SYSM_SetBootFlag( BFLG_BOOT_BMENU ); + return TRUE; // 「ブート内容決定」でリターン +#endif /* __FORCE_BOOT_BMENU */ + +#ifdef __LOGO_SKIP // ※デバッグ用ロゴスキップ + SetLogoEnable( FALSE ); // ロゴ表示スキップ +#endif /* __LOGO_SKIP */ + } + + + //----------------------------------------------------- + // NITRO設定データ未入力時の設定メニューショートカット起動 + //----------------------------------------------------- +#ifdef __DIRECT_BOOT_BMENU_ENABLE // ※NITRO設定データ未入力時のブートメニュー直接起動スイッチがONか? + if( ( (GetNCDWork()->option.input_tp == 0) + ||(GetNCDWork()->option.input_language == 0) + ||(GetNCDWork()->option.input_rtc == 0) + ||(GetNCDWork()->option.input_favoriteColor == 0) + ||(GetNCDWork()->option.input_nickname == 0) ) ) { // TP,言語,RTC,ニックネームがセットされていなければ、ロゴ表示もゲームロードも行わず、ブートメニューをショートカット起動。 + + if( ( pad.cont & PAD_PRODUCTION_NITRO_SHORTCUT ) == PAD_PRODUCTION_NITRO_SHORTCUT ) { + other_shortcut_off = TRUE; // 量産工程用のキーショートカットが押されていたら、設定メニュー起動はなし。 + }else if( !SYSM_IsInspectNITROCard() ) { // 但し、量産用のキーショートカットが押されている時か、NITRO検査カードがささっている時は、ブートメニューへのショートカット起動は行わない。 + SYSM_SetBootFlag( BFLG_BOOT_BMENU ); + SetLogoEnable( FALSE ); + return TRUE; // 「ブート内容決定」でリターン + } + } +#endif /* __DIRECT_BOOT_BMENU_ENABLE */ + + + //----------------------------------------------------- + // キーショートカット起動 + //----------------------------------------------------- + if( !other_shortcut_off && !GetNCDWork()->option.autoBootFlag ) { + // 他ショートカットONかつオート起動OFFの時 + u32 nowBootFlag = 0; + + if(pad.cont & PAD_BUTTON_R){ // Rボタン押下起動なら、ロゴ表示なしでAGBゲームへ + SetLogoEnable( FALSE ); + nowBootFlag = BFLG_BOOT_AGB; + }else if(pad.cont & PAD_BUTTON_L){ // Lボタン押下起動なら、ロゴ表示後にNITROゲームへ + nowBootFlag = BFLG_BOOT_NITRO; + }else if(pad.cont & PAD_BUTTON_B){ // Bボタン押下起動なら、ロゴ表示後にブートメニューへ + nowBootFlag = BFLG_BOOT_BMENU; + } + if( nowBootFlag ) { + SYSM_SetBootFlag( nowBootFlag ); + return TRUE; // 「ブート内容決定」でリターン + } + } + + + //----------------------------------------------------- + // 自動起動オプション有効時の挙動 + //----------------------------------------------------- +#ifndef __SYSM_DEBUG + if( GetNCDWork()->option.autoBootFlag ) { + if ( SYSM_IsNITROCard() ) { // NITROカードのみの時はNITRO起動 + SYSM_SetBootFlag( BFLG_BOOT_NITRO ); + return TRUE; // 「ブート内容決定」でリターン + } + } +#endif /* __SYSM_DEBUG */ + + return FALSE; // 「ブート内容未定」でリターン +} + + +// ============================================================================ +// 割り込み処理 +// ============================================================================ + +// Vブランク割り込み +static void INTR_VBlank(void) +{ + OS_SetIrqCheckFlag(OS_IE_V_BLANK); // Vブランク割込チェックのセット +} + diff --git a/build/systemMenu_RED/ARM9/src/main.h b/build/systemMenu_RED/ARM9/src/main.h new file mode 100644 index 00000000..17714990 --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/main.h @@ -0,0 +1,183 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: main.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __MAIN_H__ +#define __MAIN_H__ + +#include +#include +#include "misc.h" + +#define NNS_G2D_UNICODE +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// define data---------------------------------------------------------- + +// DrawText での左上寄せ +#define TXT_DRAWTEXT_FLAG_DEFAULT (NNS_G2D_VERTICALORIGIN_TOP | NNS_G2D_HORIZONTALORIGIN_LEFT | NNS_G2D_HORIZONTALALIGN_LEFT) + +// TXTColorPalette の色名 16色パレットへのロードを想定 +enum +{ + // パレット0 TXT_CPALETTE_MAIN + TXT_COLOR_NULL=0, + TXT_COLOR_WHITE, + TXT_COLOR_BLACK, + TXT_COLOR_RED, + TXT_COLOR_GREEN, + TXT_COLOR_BLUE, + TXT_COLOR_CYAN, + TXT_COLOR_MAGENTA, + TXT_COLOR_YELLOW, + + // パレット1 TXT_CPALETTE_USERCOLOR + TXT_UCOLOR_NULL=0, + TXT_UCOLOR_GRAY, + TXT_UCOLOR_BROWN, + TXT_UCOLOR_RED, + TXT_UCOLOR_PINK, + TXT_UCOLOR_ORANGE, + TXT_UCOLOR_YELLOW, + TXT_UCOLOR_LIMEGREEN, + TXT_UCOLOR_DARKGREEN, + TXT_UCOLOR_SEAGREEN, + TXT_UCOLOR_TURQUOISE, + TXT_UCOLOR_BLUE, + TXT_UCOLOR_DARKBLUE, + TXT_UCOLOR_PURPLE, + TXT_UCOLOR_VIOLET, + TXT_UCOLOR_MAGENTA, + + // パレット TXT_CPALETTE_4BPP + TXT_COLOR_4BPP_NULL=0, + TXT_COLOR_4BPP_BG=1, + TXT_COLOR_4BPP_TEXT=1 +}; + + +// 時計表示場所 +#define RTC_DATE_TOP_X ( 18 * 8 ) +#define RTC_DATE_TOP_Y ( 2 * 8 ) +#define RTC_TIME_TOP_X ( 25 * 8 ) +#define RTC_TIME_TOP_Y ( 4 * 8 ) + + // IPL2のブートタイプ指定 +typedef enum IPL2BootType { + BOOT_TYPE_UNSOLVED = 0, + BOOT_TYPE_NITRO, + BOOT_TYPE_PICT_CHAT, + BOOT_TYPE_WIRELESS_BOOT, + BOOT_TYPE_BMENU +}IPL2BootType; + + +// キーデータワーク +typedef struct { + u16 trg; // トリガ入力 + u16 cont; // ベタ 入力 +}KeyWork; + + +// タッチパネルワーク +typedef struct { + int detached; // 今回のデータ入力でタッチが離れたことを示す。 + TPData disp; // 今回の入力値(LCD座標) + TPData raw; // 今回の入力値(TP 座標) + TPData last; // 前回の入力値(LCD座標) +}TpWork; + + +// メニュー構成パラメータ構造体 +typedef struct MenuComponent { + int num; + int pos_x; + int pos_y; + int next_x_num; + int next_y_num; + int name_length; + int normal_color; + int select_color; + const u8 **str_elem; +}MenuComponent; + + +typedef struct MenuPos { + BOOL enable; + int x; + int y; +}MenuPos; + +// メニュー構成パラメータ構造体 +typedef struct MenuParam { + int num; + int normal_color; + int select_color; + int disable_color; + MenuPos *pos; + const u16 **str_elem; +}MenuParam; + + +// global variables-------------------------------------------------- +extern GXOamAttr oamBakS[ 128 ]; // OAM バックアップ +extern u16 bgBakM[ 32*24 ]; // BG バックアップ +extern u16 bgBakS[ 32*24 ]; // BG バックアップ +extern TpWork tpd; // タッチパネルデータ +extern KeyWork pad; // キーパッド入力データ +extern const u8 *const g_strWeek[ 7 ]; + +extern NNSFndAllocator g_allocator; +extern NNSG2dFont gFont; // フォント +extern NNSG2dCharCanvas gCanvas; // CharCanvas +extern NNSG2dTextCanvas gTextCanvas; // TextCanvas + +// function------------------------------------------------------------- +void LauncherInit( void ); +IPL2BootType LauncherMain( BOOL boot_decision ); + + +void InitBG( void ); +void PutStringUTF16( int x, int y, int color, const u16 *strUTF16 ); +void PrintfSJIS( int x, int y, int color, const char *fmt, ... ); + +void ReadKeyPad( void ); +void ReadTpData( void ); +void ReadTpDataLogoDirectBootCancel( void ); +BOOL WaitDetachTP( void ); +void StartDetachTP( void ); +void SetBannerIconOBJ( BannerFileV1 *bannerp ); + +void DrawMenu( u16 nowCsr, const MenuComponent *menu ); +BOOL SelectMenuByTp( u16 *nowCsr, const MenuComponent *menu ); +BOOL SelectMenuByTP( u16 *nowCsr, const MenuParam *pMenu ); +BOOL InRangeTp( int top_x, int top_y, int bottom_x, int bottom_y, TPData *tgt ); + +void InitGetAndDrawRtcData( int drawDatePos_x, int drawDatePos_y, int drawTimePos_x, int drawTimePos_y ); +void GetAndDrawRtcData( void ); + +#ifdef __cplusplus +} +#endif + +#endif // __MAIN_H__ diff --git a/build/systemMenu_RED/ARM9/src/mainFunc.c b/build/systemMenu_RED/ARM9/src/mainFunc.c new file mode 100644 index 00000000..3718c83e --- /dev/null +++ b/build/systemMenu_RED/ARM9/src/mainFunc.c @@ -0,0 +1,626 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: mainFunc.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#include +#include +#include "main.h" + +#include "DS_Setting.h" +#include "logoDemo.h" +#include "misc.h" + +// define data----------------------------------------------------------------- +#define NTR_IPL_FONT_DATA "data/NTR_IPL_font_m.NFTR" + +#define STRING_LENGTH_MAX 256 + +#define GRAY(x) GX_RGB(x, x, x) + +enum +{ + TXT_CPALETTE_MAIN, + TXT_CPALETTE_USERCOLOR, + TXT_CPALETTE_4BPP, + TXT_NUM_CPALEETE +}; + +// デモ共通のカラーパレット +GXRgb TXTColorPalette[TXT_NUM_CPALEETE * 16] = +{ + GX_RGB( 0, 0, 0), GX_RGB(31, 31, 31), GX_RGB( 0, 0, 0), GX_RGB(31, 0, 0), + GX_RGB( 0, 31, 0), GX_RGB( 0, 0, 31), GX_RGB( 0, 31, 31), GX_RGB(31, 0, 31), + GX_RGB(31, 31, 0), GX_RGB( 0, 0, 0), GX_RGB( 0, 0, 0), GX_RGB( 0, 0, 0), + GX_RGB( 0, 0, 0), GX_RGB( 0, 0, 0), GX_RGB( 0, 0, 0), GX_RGB( 0, 0, 0), + + GX_RGB( 0, 0, 0), GX_RGB(12, 16, 19), GX_RGB(23, 9, 0), GX_RGB(31, 0, 3), + GX_RGB(31, 17, 31), GX_RGB(31, 18, 0), GX_RGB(30, 28, 0), GX_RGB(21, 31, 0), + GX_RGB( 0, 20, 7), GX_RGB( 9, 27, 17), GX_RGB( 6, 23, 30), GX_RGB( 0, 11, 30), + GX_RGB( 0, 0, 18), GX_RGB(17, 0, 26), GX_RGB(26, 0, 29), GX_RGB(31, 0, 18), + + GRAY(31), GRAY(29), GRAY(27), GRAY(25), + GRAY(23), GRAY(21), GRAY(19), GRAY(17), + GRAY(15), GRAY(14), GRAY(12), GRAY(10), + GRAY( 8), GRAY( 6), GRAY( 3), GRAY( 0), +}; + +// extern data----------------------------------------------------------------- + +// define data----------------------------------------------------------------- +#define CANVAS_WIDTH 32 // 文字描画域の幅 (キャラクタ単位) +#define CANVAS_HEIGHT 24 // 文字描画域の高さ (キャラクタ単位) +#define CANVAS_LEFT 0 // 文字描画域の位置X (キャラクタ単位) +#define CANVAS_TOP 0 // 文字描画域の位置Y (キャラクタ単位) + +#define TEXT_HSPACE 1 // 文字列描画時の文字間 (ピクセル単位) +#define TEXT_VSPACE 1 // 文字列描画時の行間 (ピクセル単位) + +#define CHARACTER_OFFSET 0 // 使用するキャラクタ列の開始番号 + +// RTCデータ表示位置ワーク +typedef struct RtcDrawPos{ + int date_x; + int date_y; + int time_x; + int time_y; +}RtcDrawPos; + +// function's prototype------------------------------------------------------- +static void InitScreen( void ); +static void InitCanvas( void ); +static void GetAndDrawRtcDataCore( BOOL forceGetFlag ); + +// global variable------------------------------------------------------------- +GXOamAttr oamBakS[ 128 ] ATTRIBUTE_ALIGN(32); // OAM バックアップ +GXOamAttr oamBakS[ 128 ] ATTRIBUTE_ALIGN(32); // OAM バックアップ +u16 bgBakM[ 32 * 24 ] ATTRIBUTE_ALIGN(32); // BG バックアップ +u16 bgBakS[ 32 * 24 ] ATTRIBUTE_ALIGN(32); // BG バックアップ +KeyWork pad; // キーパッド入力データ +TpWork tpd; // タッチパネル入力データ + +NNSG2dFont gFont; // フォント +NNSG2dCharCanvas gCanvas; // CharCanvas +NNSG2dTextCanvas gTextCanvas; // TextCanvas + +// static variable------------------------------------------------------------- +static int s_detach_count; +static RtcDrawPos s_rtcPos; +static RTCDate s_rtcDate; +static RTCTime s_rtcTime; +static u16 s_vcount; + +static char s_strBuffer[ STRING_LENGTH_MAX * 2 ] ATTRIBUTE_ALIGN(2); +static u16 s_strBufferUTF16[ STRING_LENGTH_MAX ]; + +// const data------------------------------------------------------------------ + +// 曜日データ表示用文字コード +const u8 *const g_strWeek[] ATTRIBUTE_ALIGN(2) = { + (const u8 *)"SUN", + (const u8 *)"MON", + (const u8 *)"TUE", + (const u8 *)"WED", + (const u8 *)"THU", + (const u8 *)"FRI", + (const u8 *)"SAT", +}; + +// ============================================================================ +// function's description +// ============================================================================ + +// BG初期化 +void InitBG(void) +{ + // 画面OFF + GX_DispOff(); + GXS_DispOff(); + + // VRAMの割り当てを全て解除 + GX_DisableBankForBG(); + GX_DisableBankForOBJ(); + GX_DisableBankForSubBG(); + GX_DisableBankForSubOBJ(); + + // メイン2Dエンジンの出力を下画面に + GX_SetDispSelect( GX_DISP_SELECT_SUB_MAIN ); + + // メインLCD + { + // VRAM割り当て + GX_SetBankForBG ( GX_VRAM_BG_128_A ); + GX_SetBankForOBJ( GX_VRAM_OBJ_128_B ); + + MI_CpuClearFast( (void *)HW_BG_VRAM, 0x20000 ); // BG -VRAM クリア + MI_CpuClearFast( (void *)HW_OBJ_VRAM, 0x20000 ); // OBJ-VRAM クリア + MI_CpuClearFast( (void *)HW_PLTT, HW_PLTT_SIZE ); // パレット クリア // NitroSDKではcrt0.cでクリアしている。 + MI_DmaFill32( 3, (void *)HW_OAM, 192, HW_OAM_SIZE ); // OAM クリア // NitroSDKではcrt0.cでクリアしている。 + + // カラーパレットを設定 + GX_LoadBGPltt(TXTColorPalette, 0, sizeof(TXTColorPalette)); + + // BGモード設定 + GX_SetGraphicsMode( GX_DISPMODE_GRAPHICS, GX_BGMODE_4, GX_BG0_AS_2D ); + + GX_SetBGScrOffset ( GX_BGSCROFFSET_0x10000 ); + GX_SetBGCharOffset( GX_BGCHAROFFSET_0x00000 ); + + InitScreen(); + InitCanvas(); + } + // サブLCD +/* + { + GXS_SetOBJVRamModeChar(GX_OBJVRAMMODE_CHAR_1D_32K); + GX_SetBankForSubBG ( GX_VRAM_SUB_BG_128_C ); // VRAM-C for BGs + GX_SetBankForSubOBJ( GX_VRAM_SUB_OBJ_128_D ); // VRAM-D for BGs + GXS_SetGraphicsMode( GX_BGMODE_0 ); // BGMODE is 0 + GXS_SetVisiblePlane( GX_PLANEMASK_BG1 ); // display only BG #0 + G2S_SetBG1Control( GX_BG_SCRSIZE_TEXT_256x256, // 256pix x 256pix text + GX_BG_COLORMODE_16, // use 256 colors mode + GX_BG_SCRBASE_0xf000, // screen base offset + 0x0000 is the address for BG #0 screen + GX_BG_CHARBASE_0x00000, // character base offset + 0x04000 is the address for BG #0 characters + GX_BG_EXTPLTT_01 // use BGExtPltt slot #0 if BGExtPltt is enabled + ); + G2S_SetBG1Priority( 3 ); + G2S_BG1Mosaic( FALSE ); + MI_DmaFill32( 3, (void *)HW_DB_OAM, 192, HW_OAM_SIZE ); // OAM クリア + MI_CpuClearFast( (void *)HW_DB_BG_VRAM, 0x20000 ); // BG -VRAM クリア + MI_CpuClearFast( (void *)HW_DB_OBJ_VRAM, 0x20000 ); // OBJ -VRAM クリア + MI_CpuCopyFast( myPlttData, (void *)HW_DB_BG_PLTT, sizeof(myPlttData) ); // BGパレット セット + MI_CpuCopyFast( myPlttData, (void *)HW_DB_BG_PLTT, sizeof(myPlttData) ); // OBJパレット セット + } +*/ +} + + +// スクリーン初期化 +static void InitScreen( void ) +{ + // BG 0 を設定 + G2_SetBG0Control( + GX_BG_SCRSIZE_TEXT_256x256, // スクリーンサイズ 256x256 + GX_BG_COLORMODE_16, // カラーモード 16色 + GX_BG_SCRBASE_0xf800, // スクリーンベース + GX_BG_CHARBASE_0x00000, // キャラクタベース + GX_BG_EXTPLTT_01 // 拡張パレットスロット + ); + + // BG0 を可視に + GX_SetVisiblePlane( GX_PLANEMASK_BG0 ); +} + + +// 文字列描画の初期化 +static void InitCanvas( void ) +{ + // フォントを読み込みます + { + void* pFontFile; + u32 size = CMN_LoadFile( &pFontFile, NTR_IPL_FONT_DATA, &g_allocator); + NNS_G2D_ASSERT( size > 0 ); + NNS_G2dFontInitUTF16(&gFont, pFontFile); +// NNS_G2dPrintFont(&gFont); + } + + // CharCanvas の初期化 + NNS_G2dCharCanvasInitForBG( + &gCanvas, + (GXCharFmt16*)G2_GetBG0CharPtr() + CHARACTER_OFFSET, + CANVAS_WIDTH, + CANVAS_HEIGHT, + NNS_G2D_CHARA_COLORMODE_16 + ); + + // TextCanvasの初期化 + NNS_G2dTextCanvasInit( + &gTextCanvas, + &gCanvas, + &gFont, + TEXT_HSPACE, + TEXT_VSPACE + ); + + // スクリーンを設定 + NNS_G2dMapScrToCharText( + G2_GetBG0ScrPtr(), + CANVAS_WIDTH, + CANVAS_HEIGHT, + CANVAS_LEFT, + CANVAS_TOP, + NNS_G2D_TEXT_BG_WIDTH_256, + CHARACTER_OFFSET, + TXT_CPALETTE_MAIN + ); +} + + +// UTF16での直接文字表示 +void PutStringUTF16( int x, int y, int color, const u16 *strUTF16 ) +{ + NNS_G2dTextCanvasDrawText( &gTextCanvas, x, y, color, TXT_DRAWTEXT_FLAG_DEFAULT, + strUTF16 ); +} + + +// SJISでPrintf形式で文字表示(内部でUTF16に変換) +void PrintfSJIS( int x, int y, int color, const char *fmt, ... ) +{ + int srcLen; + int dstLen = sizeof(s_strBufferUTF16); + va_list vlist; + va_start(vlist, fmt); + srcLen = STD_TVSNPrintf( s_strBuffer, sizeof(s_strBuffer), fmt, vlist); + va_end(vlist); + s_strBuffer[ srcLen ] = 0; + + (void)STD_ConvertStringSjisToUnicode( s_strBufferUTF16, &dstLen, s_strBuffer, &srcLen, NULL ); + s_strBufferUTF16[ dstLen ] = 0; + + NNS_G2dTextCanvasDrawText(&gTextCanvas, x, y, color, TXT_DRAWTEXT_FLAG_DEFAULT, + s_strBufferUTF16 ); +} + + +// キー入力読み出し-------------------------------- +void ReadKeyPad(void) +{ + u16 readData = PAD_Read(); + pad.trg = (u16)(readData & (readData ^ pad.cont)); // トリガ 入力 + pad.cont = readData; // ベタ 入力 +} + + +// タッチパネルデータの取得----------------------- +void ReadTpData(void) +{ +#ifndef __TP_OFF +#ifdef __TP_CALIBLATE_ONLY_ENABLE + return; +#endif /* __TP_CALIBLATE_ONLY_ENABLE */ + + + TP_GetCalibratedPoint( &tpd.last, &tpd.raw ); // 前回のTPデータを退避 + + if( TP_RequestRawSampling(&tpd.raw) ) { // タッチパネルのサンプリング + SVC_CpuClear(0x0000, &tpd.raw, sizeof(tpd.raw), 16); // SPI-busyでデータ取得に失敗した時は”データなし”でリターン。 + return; + } + TP_GetCalibratedPoint( &tpd.disp, &tpd.raw ); // TP座標からLCD座標に変換。 + + if( !WaitDetachTP() ) { // TPデタッチ待ちを行う。 + SVC_CpuClear(0x0000, &tpd.disp, sizeof(tpd.disp), 16); // SPI-busyでデータ取得に失敗した時は”データなし”でリターン。 + return; + } +#if 1 + if(tpd.disp.touch) { // 現在のTPデータを表示 + switch ( tpd.disp.validity ) { + case TP_VALIDITY_VALID: + OS_Printf("( %3d, %3d ) -> ( %3d, %3d )\n", tpd.raw.x, tpd.raw.y, tpd.disp.x, tpd.disp.y); + break; + case TP_VALIDITY_INVALID_X: + OS_Printf("( *%3d, %3d ) -> ( *%3d, %3d )\n", tpd.raw.x, tpd.raw.y, tpd.disp.x, tpd.disp.y); + break; + case TP_VALIDITY_INVALID_Y: + OS_Printf("( %3d, *%3d ) -> ( %3d, *%3d )\n", tpd.raw.x, tpd.raw.y, tpd.disp.x, tpd.disp.y); + break; + case TP_VALIDITY_INVALID_XY: + OS_Printf("( *%3d, *%3d ) -> ( *%3d, *%3d )\n", tpd.raw.x, tpd.raw.y, tpd.disp.x, tpd.disp.y); + break; + } + } +#endif +#endif /* __TP_OFF */ +} + + +// ロゴメニューの直接ブート時のキャンセルのみタッチパネルを有効にする。 +void ReadTpDataLogoDirectBootCancel(void) +{ +#ifndef __TP_OFF + TP_GetCalibratedPoint( &tpd.last, &tpd.raw ); // 前回のTPデータを退避 + if( TP_RequestRawSampling(&tpd.raw) ) { // タッチパネルのサンプリング + SVC_CpuClear(0x0000, &tpd.raw, sizeof(tpd.raw), 16); // SPI-busyでデータ取得に失敗した時は”データなし”でリターン。 + return; + } + TP_GetCalibratedPoint( &tpd.disp, &tpd.raw ); // TP座標からLCD座標に変換。 +#endif /* __TP_OFF */ +} + + +// TPデタッチを待つ +BOOL WaitDetachTP( void ) +{ + // s_detach_countが始動していたら、カウント判定。 + if(s_detach_count > 0) { + if(tpd.disp.touch == 0) { // TPが押されていなければ、カウント進行し規定値で再入力を受け付ける。 + s_detach_count--; + }else { + s_detach_count = TP_CSR_DETACH_COUNT; + } + return FALSE; + } + return TRUE; +} + + +// TPデタッチ待ちの開始 +void StartDetachTP( void ) +{ + s_detach_count = TP_CSR_DETACH_COUNT; +} + + +// バナーアイコンOBJのロード +void SetBannerIconOBJ( BannerFileV1 *bannerp ) +{ + GXS_LoadOBJPltt( bannerp->pltt, 15, BNR_PLTT_SIZE ); + MI_CpuCopyFast( bannerp->image, (void *)(HW_DB_OBJ_VRAM + 0x20), BNR_IMAGE_SIZE ); + G2_SetOBJAttr( (GXOamAttr*)&oamBakS[ 1 ], // OAM pointer + 32, // X position + 32, // Y position + 0, // Priority + GX_OAM_MODE_NORMAL, // Bitmap mode + FALSE, // mosaic off + GX_OAM_EFFECT_NONE, // affine off + GX_OAM_SHAPE_32x32, // 16x16 size + GX_OAM_COLOR_16, // 16 color + 1, // charactor + 15, // palette + 0); // affine +} + + +//====================================================== +// メニュー制御 +//====================================================== + +// メニュー描画 +void DrawMenu(u16 nowCsr, const MenuComponent *menu) +{ + int i; + int color; + + for( i = 0; i < menu->num; i++) { + if(i == nowCsr) color = menu->select_color; + else color = menu->normal_color; + + PutStringUTF16( menu->pos_x, (int)menu->pos_y + i * menu->next_y_num, color, (const u16 *)(menu->str_elem)[i] ); +// (void)DrawStringSJIS( menu->pos_x, (u16)(menu->pos_y + i * menu->next_y_num), color, (menu->str_elem)[i]); + } +} + + +// タッチパネルによるメニュー選択 +BOOL SelectMenuByTp(u16 *nowCsr, const MenuComponent *menu) +{ + u16 i, lt_x, lt_y, rb_x, rb_y; + TPData *target; + static u16 detach_count = 0; + static u16 csr_old = 0xff; + static u16 same_csr_count = 0; + + // detach_countが始動していたら、カウント判定。 + if(detach_count > 0) { + if(tpd.disp.touch == 0) { // TPが押されていなければ、カウント進行し、10カウントでメニュー選択 + if(++detach_count == TP_CSR_DETACH_COUNT) { + detach_count = 0; + return TRUE; + }else { + return FALSE; + } + } + } + + detach_count=0; // detachカウント値のクリア + + // 通常は、TPデータがメニュー上にあるかどうかを判定。 + lt_x = (u16)(menu->pos_x * 8); // メニュー要素先頭のLCD座標を算出 + lt_y = (u16)(menu->pos_y * 8 - 4); + rb_x = (u16)((menu->pos_x + menu->name_length) * 8); + rb_y = (u16)(menu->pos_y * 8 + 12); // ※Y座標は±4のマージン + + if(tpd.disp.touch) target = &tpd.disp; + else target = &tpd.last; + +// (void)DrawDecimalSJIS( 20 , 4, WHITE, &csr_old, 2, 2); +// (void)DrawDecimalSJIS( 20 , 5, WHITE, &same_csr_count, 2, 2); +// (void)DrawDecimalSJIS( 20 , 6, WHITE, &detach_count, 2, 2); + + for(i = 0; i < menu->num; i++) { + if(tpd.disp.touch) { // タッチパネルがメニューの要素上でタッチされているなら、 + if(InRangeTp(lt_x, lt_y, rb_x, rb_y, target)) { + if(tpd.disp.validity == TP_VALIDITY_VALID) { // カーソルをその要素に移動 + if(csr_old == i) { + if(same_csr_count < TP_CSR_TOUCH_COUNT) { + same_csr_count++; + }else { + *nowCsr = i; + } + return FALSE; + }else { + csr_old = i; + } + break; + } + } + }else { // touch==0 + if(same_csr_count == TP_CSR_TOUCH_COUNT) { + detach_count = 1; + break; + } + } + lt_y += (u16)(menu->next_y_num * 8); + rb_y += (u16)(menu->next_y_num * 8); + } + same_csr_count = 0; + return FALSE; +} + + +// タッチパネルによるメニュー選択 +BOOL SelectMenuByTP( u16 *nowCsr, const MenuParam *pMenu ) +{ + u16 i; + TPData *target; + static u16 detach_count = 0; + static u16 csr_old = 0xff; + static u16 same_csr_count = 0; + + // detach_countが始動していたら、カウント判定。 + if( detach_count > 0 ) { + if( tpd.disp.touch == 0 ) { // TPが押されていなければ、カウント進行し、10カウントでメニュー選択 + if( ++detach_count == TP_CSR_DETACH_COUNT ) { + detach_count = 0; + return TRUE; + }else { + return FALSE; + } + } + } + detach_count=0; // detachカウント値のクリア + + // 通常は、TPデータがメニュー上にあるかどうかを判定。 + if( tpd.disp.touch ) target = &tpd.disp; + else target = &tpd.last; + + for( i = 0; i < pMenu->num; i++ ) { + if( tpd.disp.touch ) { // タッチパネルがメニューの要素上でタッチされているなら、 + NNSG2dTextRect rect = NNS_G2dTextCanvasGetTextRect( &gTextCanvas, (pMenu->str_elem)[ i ] ); + u16 top_x = (u16)( pMenu->pos[ i ].x ); // メニュー要素のLCD座標を算出 + u16 top_y = (u16)( pMenu->pos[ i ].y - 4 ); + u16 bottom_x = (u16)( top_x + rect.width ); + u16 bottom_y = (u16)( top_y + rect.height + 4 ); // ※Y座標は±4のマージン + + OS_TPrintf( "MENU[ %d ] : top_x = %02d top_y = %02d bot_x = %02d bot_y = %02d : ", + i, top_x, top_y, bottom_x, bottom_y ); + + if( InRangeTp( top_x, top_y, bottom_x, bottom_y, target ) ) { + OS_TPrintf( "InRange\n" ); + if( tpd.disp.validity == TP_VALIDITY_VALID ) { // カーソルをその要素に移動 + if( csr_old == i ) { + if( same_csr_count < TP_CSR_TOUCH_COUNT ) { + same_csr_count++; + }else { + *nowCsr = i; + } + return FALSE; + }else { + csr_old = i; + } + break; + } + }else { + OS_TPrintf( "OutRange\n" ); + } + }else { // touch==0 + if( same_csr_count == TP_CSR_TOUCH_COUNT ) { + detach_count = 1; + break; + } + } + } + same_csr_count = 0; + return FALSE; +} + + +// 現在のタッチパネル座標が指定領域内にあるかどうかを返す。 +BOOL InRangeTp( int top_x, int top_y, int bottom_x, int bottom_y, TPData *tgt ) +{ + if( ( tgt->x >= top_x ) && + ( tgt->x <= bottom_x ) && + ( tgt->y >= top_y ) && + ( tgt->y <= bottom_y ) ) { + return TRUE; + }else { + return FALSE; + } +} + + +//=============================================== +// RTCアクセスルーチン +//=============================================== + +// RTCデータ取得&表示の初期化 +void InitGetAndDrawRtcData( int drawDatePos_x, int drawDatePos_y, int drawTimePos_x, int drawTimePos_y) +{ + s_vcount = 0; + s_rtcPos.date_x = drawDatePos_x; + s_rtcPos.date_y = drawDatePos_y; + s_rtcPos.time_x = drawTimePos_x; + s_rtcPos.time_y = drawTimePos_y; + + (void)RTC_GetDateTime( &s_rtcDate, &s_rtcTime); + GetAndDrawRtcDataCore( TRUE ); +} + + +void GetAndDrawRtcData( void ) +{ + GetAndDrawRtcDataCore( FALSE ); +} + + +// RTC情報の取得&表示 +static void GetAndDrawRtcDataCore( BOOL forceGetFlag ) +{ + u32 year; + RTCDate date_old; + RTCTime time_old; + + // RTC情報の取得 + if( forceGetFlag || ( s_vcount++ == 60 ) ) { + s_vcount = 0; + MI_CpuCopy16( &s_rtcDate, &date_old, sizeof(RTCDate) ); + MI_CpuCopy16( &s_rtcTime, &time_old, sizeof(RTCTime) ); + + (void)RTC_GetDateTime( &s_rtcDate, &s_rtcTime ); + + // 前RTC情報の消去 + { + year = s_rtcDate.year + 2000; + PrintfSJIS( s_rtcPos.date_x, s_rtcPos.date_y, TXT_COLOR_WHITE, "%d/%02d/%02d[%3s]", + year, + date_old.month, + date_old.day, + g_strWeek[ date_old.week ] + ); + PrintfSJIS( s_rtcPos.time_x, s_rtcPos.time_y, TXT_COLOR_WHITE, "%02d:%02d:%02d", + time_old.hour, + time_old.minute, + time_old.second + ); + } + // RTC情報の表示 + { + year = s_rtcDate.year + 2000; + PrintfSJIS( s_rtcPos.date_x, s_rtcPos.date_y, TXT_COLOR_BLACK, "%d/%02d/%02d[%3s]", + year, + s_rtcDate.month, + s_rtcDate.day, + g_strWeek[ s_rtcDate.week ] + ); + PrintfSJIS( s_rtcPos.time_x, s_rtcPos.time_y, TXT_COLOR_BLACK, "%02d:%02d:%02d", + s_rtcTime.hour, + s_rtcTime.minute, + s_rtcTime.second + ); + } + } +} + diff --git a/build/systemMenu_RED/Makefile b/build/systemMenu_RED/Makefile new file mode 100644 index 00000000..02cacbf9 --- /dev/null +++ b/build/systemMenu_RED/Makefile @@ -0,0 +1,30 @@ +#! make -f +#---------------------------------------------------------------------------- +# Project: TwlIPL +# File: Makefile +# +# Copyright 2007 Nintendo. All rights reserved. +# +# These coded instructions, statements, and computer programs contain +# proprietary information of Nintendo of America Inc. and/or Nintendo +# Company Ltd., and are protected by Federal copyright law. They may +# not be disclosed to third parties or copied or duplicated in any form, +# in whole or in part, without the prior written consent of Nintendo. +# +# $Date:: 2007-10-03#$ +# $Rev: 1319 $ +# $Author: kitase_hirotake $ +#---------------------------------------------------------------------------- + +include $(TWLSDK_ROOT)/build/buildtools/commondefs + +#---------------------------------------------------------------------------- + +SUBDIRS = ARM9 + +#---------------------------------------------------------------------------- + +include $(TWLSDK_ROOT)/build/buildtools/modulerules + + +#===== End of Makefile ===== diff --git a/include/sysmenu.h b/include/sysmenu.h new file mode 100644 index 00000000..80dbc8f5 --- /dev/null +++ b/include/sysmenu.h @@ -0,0 +1,33 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: sysmenu.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: 2007-09-06$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ +#ifndef SYSMENU_H_ +#define SYSMENU_H_ + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +/* SYSMENU_H_ */ +#endif diff --git a/include/sysmenu/acsign.h b/include/sysmenu/acsign.h new file mode 100644 index 00000000..f334333e --- /dev/null +++ b/include/sysmenu/acsign.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - ACSIGN + File: acsign.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: 2007-09-06$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef SYSM_ACSIGN_H_ +#define SYSM_ACSIGN_H_ + +#ifdef SDK_ARM9 +#include +#include +#endif // SDK_ARM9 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* SYSM_ACSIGN_H_ */ +#endif diff --git a/include/sysmenu/acsign/ARM9/acsign.h b/include/sysmenu/acsign/ARM9/acsign.h new file mode 100644 index 00000000..eff3b534 --- /dev/null +++ b/include/sysmenu/acsign/ARM9/acsign.h @@ -0,0 +1,59 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: acsign.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef _ACSIGN_H_ +#define _ACSIGN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined( RSA_ENC_DEC ) +#define ACSIGN_BUFFER ((160/8)*4) // 出力バッファ量 +#else +#define ACSIGN_BUFFER ((160/8)*1) // 出力バッファ量 +#endif + +// +int ACSign_Decrypto( + void* buffer, // 出力領域 + void* sgn_ptr, // データへのポインタ + void* key_ptr // キーへのポインタ + ); + +// +int ACSign_Digest( + void* buffer, // 出力領域 + void* romh_ptr, // データへのポインタ + void* mbin_ptr, // データへのポインタ + int mbin_len, // データの長さ + void* sbin_ptr, // データへのポインタ + int sbin_len, // データの長さ + u32 serial_num // シリアルナンバー + ); + +// +int ACSign_Compare( + void* dercypto, // ACSign_Decryptoの出力 + void* digest // ACSign_Digestの出力 + ); + +#ifdef __cplusplus +} +#endif + +#endif //_ACSIGN_H_ diff --git a/include/sysmenu/acsign/ARM9/acsign_util.h b/include/sysmenu/acsign/ARM9/acsign_util.h new file mode 100644 index 00000000..dd09d6bf --- /dev/null +++ b/include/sysmenu/acsign/ARM9/acsign_util.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: acsign_util.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef _ACSIGN_UTIL_H_ +#define _ACSIGN_UTIL_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define AUTH_BUFFER_LEN 20 + +extern int ACSignDecrpto(void *output_buffer, MBDownloadFileInfo *download_file_info_buf); +extern int ACSignDigest(void *input_buffer, MBDownloadFileInfo *download_file_info_buf); + + +#ifdef __cplusplus +} +#endif + +#endif //_ACSIGN_UTIL_H_ diff --git a/include/sysmenu/banner.h b/include/sysmenu/banner.h new file mode 100644 index 00000000..3479150d --- /dev/null +++ b/include/sysmenu/banner.h @@ -0,0 +1,111 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: banner.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef BANNER_H_ +#define BANNER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifndef BANNER_ROM_OFFSET +#define BANNER_ROM_OFFSET (HW_ROM_HEADER_BUF + 0x68) +#endif + +#define BNR_VER_MIN 1 +#define BNR_VER_MAX 3 +#define BNR_HEADER_RSV_SIZE 24 + +#define BNR_CHINESE_SUPPORT_VER 2 +#define BNR_HANGUL_SUPPORT_VER 3 + +typedef enum +{ + BNR_JAPANESE = 0, + BNR_ENGLISH = 1, + BNR_FRENCH = 2, + BNR_GERMAN = 3, + BNR_ITALIAN = 4, + BNR_SPANISH = 5, + BNR_CHINESE = 6, + BNR_HANGUL = 7, + BNR_LANG_NUM +} BannerFileLangIdx; + +#define BNR_LANG_NUM_V1 6 +#define BNR_LANG_NUM_V2 1 +#define BNR_LANG_NUM_V3 1 + + +#define BNR_HEADER_SIZE 32 +#define BNR_VER_OFFSET 0 +#define BNR_V1_CRC16_OFFSET 2 +#define BNR_IMAGE_OFFSET BNR_HEADER_SIZE +#define BNR_IMAGE_SIZE (32 * 32 / (8/4)) +#define BNR_PLTT_OFFSET (BNR_IMAGE_OFFSET + BANNER_IMAGE_SIZE) +#define BNR_PLTT_NUM 16 +#define BNR_PLTT_SIZE (BNR_PLTT_NUM * 2) +#define BNR_LANG_OFFSET (BNR_PLTT_OFFSET + BANNER_PLTT_SIZE) +#define BNR_LANG_LENGTH 128 +#define BNR_LANG_SIZE (BNR_LANG_LENGTH * 2) + +typedef struct +{ + u8 version; + u8 reserved_A; + u16 crc16_v1; + u16 crc16_v2; + u16 crc16_v3; + u8 reserved_B[BNR_HEADER_RSV_SIZE]; +} BannerHeader; + +typedef struct +{ + u8 image[BNR_IMAGE_SIZE]; + GXRgba pltt[BNR_PLTT_NUM]; + + u16 gameName[BNR_LANG_NUM_V1][BNR_LANG_LENGTH]; +} BannerFileV1; + +typedef struct +{ + u16 gameName[BNR_LANG_NUM_V2][BNR_LANG_LENGTH]; +} BannerFileV2; + +typedef struct +{ + u16 gameName[BNR_LANG_NUM_V3][BNR_LANG_LENGTH]; +} BannerFileV3; + +typedef struct +{ + BannerHeader h; + BannerFileV1 v1; + BannerFileV2 v2; + BannerFileV3 v3; +} BannerFile; + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* BANNER_H_ */ +#endif diff --git a/include/sysmenu/machineSettings.h b/include/sysmenu/machineSettings.h new file mode 100644 index 00000000..be955cd0 --- /dev/null +++ b/include/sysmenu/machineSettings.h @@ -0,0 +1,32 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: machineSettings.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: 2007-09-06$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef SYSM_MACHINE_SETTINGS_H_ +#define SYSM_MACHINE_SETTINGS_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* SYSM_MACHINE_SETTINGs_H_ */ +#endif diff --git a/include/sysmenu/machineSettings/common/nitroSettings.h b/include/sysmenu/machineSettings/common/nitroSettings.h new file mode 100644 index 00000000..27cb25c2 --- /dev/null +++ b/include/sysmenu/machineSettings/common/nitroSettings.h @@ -0,0 +1,490 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: NitroSettings.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + + +#ifndef NITRO_SETTINGS_H_ +#define NITRO_SETTINGS_H_ +#if defined(SDK_CW) // NitroConfigDataにビットフィールドを使っているので、コンパイラ依存で不具合が発生する可能性がある。 + // よって、CW以外のコンパイラの場合は、このヘッダを無効にしてエラーを出させるようにして再確認する。 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// define data ------------------------------------ +#define NITRO_CONFIG_DATA_VERSION 5 // NITRO設定データフォーマットバージョン +#define NITRO_CONFIG_DATA_EX_VERSION 1 // 拡張NITRO設定データフォーマットバージョン +#define NCD_NICKNAME_LENGTH 10 // ニックネーム長 +#define NCD_COMMENT_LENGTH 26 // コメント長 +#define NCD_FAVORITE_COLOR_MAX_NUM 16 // 好きな色の最大数 + +// 言語設定コード +typedef enum NvLangCode{ + LANG_JAPANESE =0, // 日本語 + LANG_ENGLISH =1, // 英語 + LANG_FRENCH =2, // フランス語 + LANG_GERMAN =3, // ドイツ語 + LANG_ITALIAN =4, // イタリア語 + LANG_SPANISH =5, // スペイン語 +#ifdef IPL2_DEST_CHINA + LANG_CHINESE =6, // 中国語 +#endif // IPL2_DEST_CHINA +#ifdef IPL2_DEST_KOREA + LANG_CHINESE =6, // 中国語 + LANG_HANGUL =7, // 韓国語 +#endif // IPL2_DEST_KOREA + LANG_CODE_MAX +}NvLangCode; + +#define LANG_CODE_MAX_WW ( LANG_SPANISH + 1 ) +#define LANG_BITMAP_WW ( ( 0x0001 << LANG_JAPANESE ) \ + | ( 0x0001 << LANG_ENGLISH ) \ + | ( 0x0001 << LANG_FRENCH ) \ + | ( 0x0001 << LANG_GERMAN ) \ + | ( 0x0001 << LANG_ITALIAN ) \ + | ( 0x0001 << LANG_SPANISH ) ) // 通常版での対応言語ビットマップ + +#define VALID_LANG_BITMAP LANG_BITMAP_WW // 本IPL2の対応言語ビットマップ + + +// 日付データ +typedef struct NvDate{ + u8 month; // 月:01〜12 + u8 day; // 日:01〜31 +}NvDate; // 2byte + +// ニックネーム +typedef struct NvNickname{ + u16 str[NCD_NICKNAME_LENGTH]; // ニックネーム(Unicode(UTF16)で最大10文字、終端コードなし) + u8 length; // 文字数 + u8 rsv; +}NvNickname; // 22byte + +// コメント +typedef struct NvComment{ + u16 str[NCD_COMMENT_LENGTH]; //コメント(Unicode(UTF16)で最大26文字、終端コードなし) + u8 length; // 文字数 + u8 rsv; +}NvComment; // 54byte + +// オーナー情報 +typedef struct NvOwnerInfo{ + u8 favoriteColor : 4; // 好きな色 + u8 rsv : 4; // 予約。 + NvDate birthday; // 生年月日 + u8 pad; + NvNickname nickname; // ニックネーム + NvComment comment; // コメント +}NvOwnerInfo; // 80byte + +// IPL用目覚まし時計データ +typedef struct NvAlarm{ + u8 hour; // アラーム時:00〜23 + u8 minute; // アラーム分:00〜59 + u8 rsv1; // 予約 + u8 pad; + u16 alarmOn : 1; // アラームON,OFF(0:OFF, 1:ON) + u16 rsv2 : 15; // 予約 +}NvAlarm; // 6byte + +// タッチパネルキャリブレーションデータ +typedef struct NvTpCalibData{ + u16 raw_x1; // 第1キャリブレーション点のTP取得値X + u16 raw_y1; //     〃        TP取得値Y + u8 dx1; //     〃        LCD座標 X + u8 dy1; //     〃        LCD座標 Y + u16 raw_x2; // 第2キャリブレーション点のTP取得値X + u16 raw_y2; //     〃        TP取得値Y + u8 dx2; //     〃        LCD座標 X + u8 dy2; //     〃        LCD座標 Y +}NvTpCalibData; // 12byte + +// オプション情報 +typedef struct NvOption{ + u16 language : 3; // 言語コード(LANG_SPANISHまでの標準言語コードが入る) + u16 agbLcd : 1; // AGBモードで起動する時にどちらのLCDで起動するか?(0:TOP,1:BOTTOM) + u16 backLightBrightness : 2; // バックライト輝度データ + u16 autoBootFlag : 1; // 起動シーケンスで、メニュー停止なしで自動起動するかどうか?(0:OFF, 1:ON) + u16 backLightOffFlag : 1; // バックライトON,OFFフラグ(0:ON, 1:OFF) + u16 rsv2 : 1; // 予約 + u16 destroyFlashFlag : 1; // フラッシュ壊れシーケンス中フラグ + u16 input_birthday : 1; // 誕生日が入力されたか? + u16 input_favoriteColor : 1; // 好きな色が入力されたか? + u16 input_tp : 1; // タッチパネルがキャリブレーションされたか?( 〃 ) + u16 input_language : 1; // 言語入力がされたか?  (0:未設定, 1:設定済み) + u16 input_rtc : 1; // RTC設定がされたか? ( 〃      ) + u16 input_nickname : 1; // ニックネームが入力されたか? ( 〃      ) + u8 rtcLastSetYear; // RTCの前回設定年 + u8 rtcClockAdjust; // RTCクロック調整値 + s64 rtcOffset; // RTC設定時のオフセット値(ユーザーがRTC設定を変更する度にその値に応じて増減します。) +}NvOption; // 12byte + +// NITRO各種設定データ +typedef struct NitroConfigData{ + u8 version; // フラッシュ格納データフォーマットのバージョン + u8 pad; + NvOwnerInfo owner; // オーナー情報 + NvAlarm alarm; // IPL用目覚まし時計データ + NvTpCalibData tp; // タッチパネルキャリブレーションデータ + NvOption option; // オプション +}NitroConfigData; // 112byte + +// NITRO各種設定データのNVRAM保存時フォーマット +typedef struct NCDStore{ + NitroConfigData ncd; // NITRO各種設定データ + u16 saveCount; // 0x00-0x7fをループしてカウントし、カウント値が新しいデータが有効。 + u16 crc16; // NITRO各種設定データの16bitCRC + u8 pad[ 128 - sizeof(NitroConfigData) - 4]; +}NCDStore; // 128byte // ※本来なら、saveCountとcrc16は256byteの最後に付加して、間にパディングを埋める方がいい。 + + +//---------------------------------------------- +// IPL2中国・韓国版での拡張フォーマット +//---------------------------------------------- +// 拡張NITRO設定データ +typedef struct NitroConfigDataEx{ + u8 version; // バージョン + u8 language; // 言語コード(LANG_CHINESE以降に拡張された値が入る。) + u16 valid_language_bitmap; // 本IPL2で有効な言語コードを示したビットマップ + u8 pad[ 256 - sizeof(NitroConfigData) - 4 - 4 - 2 ]; // 4:saveCount+crc16, 2:NCDEx.version+NCDEx.language, 2:crc16_ex +}NitroConfigDataEx; // 138bytes + +// NITRO各種設定データのNVRAM保存時フォーマット +typedef struct NCDStoreEx{ + NitroConfigData ncd; // NITRO各種設定データ + u16 saveCount; // 0x00-0x7fをループしてカウントし、カウント値が新しいデータが有効。 + u16 crc16; // NITRO各種設定データの16bitCRC + NitroConfigDataEx ncd_ex; + u16 crc16_ex; +}NCDStoreEx; // 256byte // ※本来なら、saveCountとcrc16は256byteの最後に付加して、間にパディングを埋める方がいい。 + + +//========================================================= +// NVRAMへのリードライト関数 +//========================================================= +#ifdef SDK_ARM9 +extern int NVRAMm_ReadNitroConfigData (NitroConfigData *dstp); +extern void NVRAMm_WriteNitroConfigData(NitroConfigData *dstp); +#endif + + +//========================================================= +// NITRO設定データへのアクセス関数 +//========================================================= +extern NitroConfigDataEx ncdEx; + +#define GetNCDWork() ( (NitroConfigData *)( HW_NVRAM_USER_INFO ) ) +#define GetNCDExWork() ( &ncdEx ) + // NITRO設定データ領域のアドレス獲得 + +extern void NCD_ClearOwnerInfo( void ); // ニックネーム・誕生日・好きな色のクリア + +//========================================================= +// データ取得 +//========================================================= + +//----------------------------------- +// オーナー情報全体の取得。 +static inline NvOwnerInfo *NCD_GetOwnerInfo(void) +{ + return &GetNCDWork()->owner; +} + +// 好きな色の取得。 +static inline u8 NCD_GetFavoriteColor(void) +{ + return (u8)GetNCDWork()->owner.favoriteColor; +} + +// 誕生日の取得。 +static inline NvDate *NCD_GetBirthday(void) +{ + return &GetNCDWork()->owner.birthday; +} + +// ニックネームの取得。 +static inline NvNickname *NCD_GetNickname(void) +{ + return &GetNCDWork()->owner.nickname; +} + +// コメントの取得。 +static inline NvComment *NCD_GetComment(void) +{ + return &GetNCDWork()->owner.comment; +} + + +//----------------------------------- +// アラーム情報の取得。 +static inline NvAlarm *NCD_GetAlarmData(void) +{ + return &GetNCDWork()->alarm; +} + + +//----------------------------------- +// タッチパネルキャリブレーションデータの取得。 +static inline NvTpCalibData *NCD_GetTPCalibration(void) +{ + return &GetNCDWork()->tp; +} + + +//----------------------------------- +// オプション情報の取得。 + +// 言語コードの取得 +static inline NvLangCode NCD_GetLanguage(void) +{ + return (NvLangCode)GetNCDExWork()->language; +} + +static inline NvLangCode NCD_GetLanguageOrg(void) +{ + return (NvLangCode)GetNCDWork()->option.language; +} + +// RTCオフセット値の取得 +static inline s64 NCD_GetRtcOffset(void) +{ + return GetNCDWork()->option.rtcOffset; +} + +// RTCクロック調整値の取得 +static inline u8 NCD_GetRtcClockAdjust(void) +{ + return GetNCDWork()->option.rtcClockAdjust; +} + +// RTCの前回セットした年の取得 +static inline u8 NCD_GetRtcLastSetYear(void) +{ + return GetNCDWork()->option.rtcLastSetYear; +} + +// 起動シーケンスの自動起動ONか?(0:OFF, 1:ON) +static inline int NCD_GetAutoBootFlag(void) +{ + return (int)GetNCDWork()->option.autoBootFlag; +} + +// バックライト輝度取得(0-3) +static inline int NCD_GetBackLightBrightness(void) +{ + return (int)GetNCDWork()->option.backLightBrightness; +} + +// フラッシュ壊れシーケンス中かどうか? +static inline int NCD_GetDestroyFlash(void) +{ + return (int)GetNCDWork()->option.destroyFlashFlag; +} + +// 誕生日データがセットされているか? +static inline int NCD_GetInputBirthday(void) +{ + return (int)GetNCDWork()->option.input_birthday; +} + +// 好きな色データがセットされているか? +static inline int NCD_GetInputFavoriteColor(void) +{ + return (int)GetNCDWork()->option.input_favoriteColor; +} + +// TPキャリブレーションデータがセットされているか? +static inline int NCD_GetInputTP(void) +{ + return (int)GetNCDWork()->option.input_tp; +} + +// 言語コードがセットされているか? +static inline int NCD_GetInputLanguage(void) +{ + return (int)GetNCDWork()->option.input_language; +} + +// RTCデータがセットされているか? +static inline int NCD_GetInputRTC(void) +{ + return (int)GetNCDWork()->option.input_rtc; +} + +// オーナー情報のニックネームがセットされているか? +static inline int NCD_GetInputNickname(void) +{ + return (int)GetNCDWork()->option.input_nickname; +} + +//========================================================= +// データセット +//========================================================= +//----------------------------------- +// オーナー情報全体のセット。 +static inline void NCD_SetOwnerInfo(NvOwnerInfo *owinfop) +{ + SVC_CpuCopy( owinfop, &GetNCDWork()->owner, sizeof(NvOwnerInfo), 16); +} + +// 好きな色のセット。 +static inline void NCD_SetFavoriteColor(u8 favoriteColor) +{ + GetNCDWork()->owner.favoriteColor = favoriteColor; +} + +// 誕生日のセット。 +static inline void NCD_SetBirthday(NvDate *birthp) +{ + GetNCDWork()->owner.birthday.month = birthp->month; + GetNCDWork()->owner.birthday.day = birthp->day; +} + +// ニックネームのセット。 +static inline void NCD_SetNickname(NvNickname *namep) +{ + SVC_CpuCopy( namep, &GetNCDWork()->owner.nickname, sizeof(NvNickname), 16); +} + +// コメントのセット。 +static inline void NCD_SetComment(NvComment *commentp) +{ + SVC_CpuCopy( commentp, &GetNCDWork()->owner.comment, sizeof(NvComment), 16); +} + + +//----------------------------------- +// アラーム情報のセット。 +static inline void NCD_SetAlarmData(NvAlarm *alarmp) +{ + SVC_CpuCopy( alarmp, &GetNCDWork()->alarm, sizeof(NvAlarm), 16); +} + + +//----------------------------------- +// タッチパネルキャリブレーションデータのセット。 +static inline void NCD_SetTPCalibration(NvTpCalibData *tp_calibp) +{ + SVC_CpuCopy( tp_calibp, &GetNCDWork()->tp, sizeof(NvTpCalibData), 16); +} + + +//----------------------------------- +// オプション情報のセット。 + +// 言語コードのセット +static inline void NCD_SetLanguage(NvLangCode language) +{ +#ifdef IPL2_DEST_WW + GetNCDWork()->option.language = language; +#else // IPL2_DEST_WW + GetNCDExWork()->language = language; + GetNCDExWork()->valid_language_bitmap = VALID_LANG_BITMAP; + + if( language >= LANG_CODE_MAX_WW ) { + GetNCDWork()->option.language = LANG_ENGLISH; + }else { + GetNCDWork()->option.language = language; + } +#endif // IPL2_DEST_WW +} + +// RTCオフセット値のセット +static inline void NCD_SetRtcOffset(s64 rtcOffset) +{ + GetNCDWork()->option.rtcOffset = rtcOffset; +} + +// RTCクロック調整値のセット +static inline void NCD_SetRtcClockAdjust(u8 rtcClockAdjust) +{ + GetNCDWork()->option.rtcClockAdjust = rtcClockAdjust; +} + + +// RTCのLastSetYearへのセット +static inline void NCD_SetRtcLastSetYear(u8 rtcLastSetYear) +{ + GetNCDWork()->option.rtcLastSetYear = rtcLastSetYear; +} + + +// 起動シーケンスの自動起動ON,OFFフラグをセット。 +static inline void NCD_SetAutoBootFlag(BOOL autoBootFlag) +{ + GetNCDWork()->option.autoBootFlag = (u16)autoBootFlag; +} + +// バックライト輝度情報をセット。 +static inline void NCD_SetBackLightBrightness(BOOL backLightBrightness ) +{ + GetNCDWork()->option.backLightBrightness = (u16)backLightBrightness; +} + +// フラッシュ壊れシーケンス中かどうかのフラグセット。 +static inline void NCD_SetDestroyFlash(BOOL destroy) +{ + GetNCDWork()->option.destroyFlashFlag = (u16)destroy; +} + +// 誕生日データの入力済みフラグセット。 +static inline void NCD_SetInputBirthday(BOOL input) +{ + GetNCDWork()->option.input_birthday = (u16)input; +} + +// 好きな色データの入力済みフラグセット。 +static inline void NCD_SetInputFavoriteColor(BOOL input) +{ + GetNCDWork()->option.input_favoriteColor = (u16)input; +} + +// TPキャリブレーションデータの入力済みフラグセット。 +static inline void NCD_SetInputTP(BOOL input) +{ + GetNCDWork()->option.input_tp = (u16)input; +} + +// 言語コードの入力済みフラグセット。 +static inline void NCD_SetInputLanguage(BOOL input) +{ + GetNCDWork()->option.input_language = (u16)input; +} + +// RTCデータの入力済みフラグセット。 +static inline void NCD_SetInputRTC(BOOL input) +{ + GetNCDWork()->option.input_rtc = (u16)input; +} + +// オーナー情報のニックネームの入力済みフラグセット。 +static inline void NCD_SetInputNickname(BOOL input) +{ + GetNCDWork()->option.input_nickname = (u16)input; +} + + + +#ifdef __cplusplus +} +#endif + +#endif // SDK_CW +#endif // NITRO_SETTINGS_H_ diff --git a/include/sysmenu/mb_loader.h b/include/sysmenu/mb_loader.h new file mode 100644 index 00000000..d5a1933b --- /dev/null +++ b/include/sysmenu/mb_loader.h @@ -0,0 +1,32 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - MB_LOADER + File: mb_loader.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: 2007-09-06$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef SYSM_MB_LOADER_H_ +#define SYSM_MB_LOADER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* SYSM_MB_LOADER_H_ */ +#endif diff --git a/include/sysmenu/mb_loader/common/mb_loader.h b/include/sysmenu/mb_loader/common/mb_loader.h new file mode 100644 index 00000000..9b853e62 --- /dev/null +++ b/include/sysmenu/mb_loader/common/mb_loader.h @@ -0,0 +1,86 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: mb_loader.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#if !defined(_LOADER_H_) +#define _LOADER_H_ + +#include +#include // twl/mb.hがない。 + +#ifdef __cplusplus +extern "C" { +#endif + +#define PXI_FIFO_TAG_MB PXI_FIFO_TAG_USER_0 +/* + 実装の際、他のFIFO_TAGとかちあわないTAG番号に指定してください。 +*/ + +/*---------------------------------------------------------------------------* + Type definition + *---------------------------------------------------------------------------*/ + +typedef void (*MB_LoaderCallback)(void); + +/*---------------------------------------------------------------------------* + functions + *---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------* + Name: LOADER_Init + + Description: ローダーの初期化 + + Arguments: callback - ブートの準備が出来たときに返すコールバック + + Returns: None. + *---------------------------------------------------------------------------*/ + +void LOADER_Init(MB_LoaderCallback callback); + + +/*---------------------------------------------------------------------------* + Name: LOADER_Start + + Description: ローダーのスタート + + Arguments: None. + + Returns: None. + *---------------------------------------------------------------------------*/ + +void LOADER_Start( void ); + + +/*---------------------------------------------------------------------------* + Name: MIm_CpuCopy32 + + Description: ローダー用のCpuCopy32関数 + + Arguments: + + Returns: TRUE - success FALSE - failed + *---------------------------------------------------------------------------*/ + +void MIm_CpuCopy32( register const void *srcp, register void *destp, register u32 size ); + + +#ifdef __cplusplus +} +#endif + +#endif /* _LOADER_H_ */ diff --git a/include/sysmenu/memorymap.h b/include/sysmenu/memorymap.h new file mode 100644 index 00000000..cfa4bf0e --- /dev/null +++ b/include/sysmenu/memorymap.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - memorymap + File: memorymap.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: 2007-09-06$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef SYSM_MEMORYMAP_H_ +#define SYSM_MEMORYMAP_H_ + + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* SYSM_MEMORYMAP_H_ */ +#endif diff --git a/include/sysmenu/mmap.h b/include/sysmenu/mmap.h new file mode 100644 index 00000000..9aab1562 --- /dev/null +++ b/include/sysmenu/mmap.h @@ -0,0 +1,57 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: mmap.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __MMAP_H__ +#define __MMAP_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// define data ------------------------------------ + +#define RETURN_FROM_MAIN_ARM9_FUNCP 0x023fee00 // NITROゲームブート時のARM9最終処理の動作アドレス +#define RETURN_FROM_MAIN_ARM7_FUNCP 0x0380f600 // NITROゲームブート時のARM7最終処理の動作アドレス + +#define SYSM_ADDR_TOP 0x02300000 // SYSMが配置される先頭アドレス +#define SYSM_ADDR_BOTTOM 0x023fe000 // SYSMが配置される最終アドレス + +#define SYSM_ARM9_MMEM_ENTRY_ADDR_LIMIT ( SYSM_ADDR_TOP - 0x80000 ) // 0x02800000 + +#define SYSM_ARM9_LOAD_MMEM_LAST_ADDR ( SYSM_ADDR_TOP - 0x80000 ) // SYSMがロード可能なNITROカード初期ブートコードのメインメモリ最終アドレス +#define SYSM_ARM7_LOAD_MMEM_LAST_ADDR ( SYSM_ADDR_BOTTOM ) // SYSMがロード可能なNITROカード初期ブートコードのメインメモリ最終アドレス +#define SYSM_ARM7_LOAD_WRAM_LAST_ADDR ( RETURN_FROM_MAIN_ARM7_FUNCP & ~0x0fff ) // SYSMがロード可能なNITROカード初期ブートコードのメインメモリ最終アドレス +#define SYSM_ARM7_LOAD_BUF_ADDR ( SYSM_ADDR_TOP - 0x40000 ) // SYSMがNITROカードARM7初期ブートコードのロードを行う際のロードバッファアドレス +#define SYSM_ARM7_LOAD_BUF_SIZE ( SYSM_ADDR_TOP - SYSM_ARM7_LOAD_BUF_ADDR ) // SYSMのNITROカードARM7コードロードバッファサイズ + +#define UNCOMP_TEMP_BUF ( SYSM_ARM7_LOAD_BUF_ADDR ) // 圧縮展開用データ一時格納バッファアドレス +#define UNCOMP_TEMP_BUF_SIZE ( SYSM_ARM7_LOAD_BUF_SIZE ) // 圧縮展開用データ一時格納バッファサイズ + +#define NITRO_CARD_SECURE_SIZE 0x4000 // NITROカードのセキュア領域サイズ(16Kbytes) + +#define SYSROM9_NINLOGO_ADR 0xffff0020 // ARM9システムROM内の任天堂ロゴ格納アドレス +#define AGB_CARTRIDGE_NIN_LOGO_DATA (HW_CTRDG_ROM + 4) // AGBカートリッジのNintendoロゴデータ格納アドレス + + +#ifdef __cplusplus +} +#endif + +#endif // __MMAP_H__ + diff --git a/include/sysmenu/rom_header.h b/include/sysmenu/rom_header.h new file mode 100644 index 00000000..b09e1f21 --- /dev/null +++ b/include/sysmenu/rom_header.h @@ -0,0 +1,175 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: rom_header.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef _ROM_HEADER_H_ +#define _ROM_HEADER_H_ + +#include + + +#ifdef __cplusplus +extern "C" { +#endif + +#define NINTENDO_LOGO_LENGTH 0x9c // Nintendoロゴデータサイズ + +//---------------------------------------------------------------------- +// ファイルネームテーブル +//---------------------------------------------------------------------- + +typedef struct ROM_FNT{ + char entry_name[FS_FILE_NAME_MAX]; // ファイル名 (終端 \0 は省く) +} ROM_FNT; + +//---------------------------------------------------------------------- +// ファイルアロケーションテーブル +//---------------------------------------------------------------------- +typedef struct { + void *top; // ファイルの先頭 ROM アドレス + void *bottom; // ファイルの最終 ROM アドレス +} ROM_FAT; + +//---------------------------------------------------------------------- +// オーバーレイテーブル +//---------------------------------------------------------------------- +typedef struct { + u32 id; // オーバーレイ ID + void *ram_address; // ロード先頭位置 + u32 ram_size; // ロードサイズ + u32 bss_size; // bss 領域サイズ + void *sinit_init; // static initializer 先頭アドレス + void *sinit_init_end; // static initializer 最終アドレス + u32 file_id; // オーバーレイファイルID + u32 rsv; // 予約。 +} ROM_OVT; + +//---------------------------------------------------------------------- +// ROMヘッダ +//---------------------------------------------------------------------- +typedef struct { + // + // 0x000 System Reserved + // + char title_name[12]; // Soft title name + u32 game_code; // Game code + + u16 maker_code; // Maker code + u8 machine_code; // Machine code + u8 rom_type; // Rom type + u8 rom_size; // Rom size + + u8 agbRomCycle1st; // 1セグのAGBRomアクセスサイクル1st. + u8 agbRomCycle2nd; // 1セグのAGBRomアクセスサイクル2nd. + u8 reserved_A[7]; // System Reserved A ( Set ALL 0 ) + + u8 soft_version; // Soft version + u8 comp_arm9_boot_area:1; // Compress arm9 boot area + u8 comp_arm7_boot_area:1; // Compress arm7 boot area + u8 inspectCard:1; // 検査カードフラグ + u8 disableClearMemoryPad:1; // IPL2メモリパッドクリア・ディセーブルフラグ + u8 enableAgbRomCycle:1; + u8 :2; + u8 disableDetectPullOut:1; // カード抜け検出ディセーブルフラグ + + // + // 0x020 for Static modules (Section:B) + // + // ARM9 + u32 main_rom_offset; // ROM offset + void* main_entry_address; // Entry point + void* main_ram_address; // RAM address + u32 main_size; // Module size + + // ARM7 + u32 sub_rom_offset; // ROM offset + void* sub_entry_address; // Entry point + void* sub_ram_address; // RAM address + u32 sub_size; // Module size + + // + // 0x040 for File Name Table[FNT] (Section:C) + // + ROM_FNT* fnt_offset; // ROM offset + u32 fnt_size; // Table size + + // + // 0x048 for File Allocation Table[FAT] (Section:E) + // + ROM_FAT* fat_offset; // ROM offset + u32 fat_size; // Table size + + // + // 0x050 for Overlay Tables[OVT] (Section:D) + // + // ARM9 + ROM_OVT* main_ovt_offset; // ROM offset + u32 main_ovt_size; // Table size + + // ARM7 + ROM_OVT* sub_ovt_offset; // ROM offset + u32 sub_ovt_size; // Table size + + // 0x060 for ROM control parameter + u32 game_cmd_param; // Game command parameter + u32 secure_cmd_param; // Secure command parameter + + u32 banner_offset; // Banner ROM offset + + u16 secure_area_crc16; // Secure area CRC-16 + u16 secure_cmd_latency; // Secure command latency ((param+2)*256 system cycles) + u8 ctrl_reserved_B[16]; // Ctrl Reserved B (Set 0) + + // 0x080 - 0x0C0 System Reserved + u32 total_rom_size; + u8 reserved_B[60]; // System Reserved B (Set 0) + + // 0x0C0 for NINTENDO logo data + u8 nintendo_logo[ NINTENDO_LOGO_LENGTH ]; // NINTENDO logo data + u16 nintendo_logo_crc16; // CRC-16 + + // 0x15E ROM header CRC-16 + u16 header_crc16; // ROM header CRC-16 + + // + // 0x0160 - 0x0180 System Reserved + // + u32 dbgRomAddr; // デバッガモニタROMアドレス + s32 dbgRomSize; // デバッガモニタROMサイズ + u32 dbgArm9RamAddr; // デバッガモニタARM9-RAMアドレス + u32 dbgArm7RamAddr; // デバッガモニタARM7-RAMアドレス + u8 reserved_C[16]; // Debugger Reserved (Set ALL 0) + +} RomHeader; + + +//---------------------------------------------------------------------- +// ROMヘッダアドレス獲得 +//---------------------------------------------------------------------- + +#define GetRomHeaderAddr() ((RomHeader *)HW_ROM_HEADER_BUF) + +//・ROMヘッダアドレスを獲得します。 + + +#ifdef __cplusplus + +#endif + +#endif // _ROM_HEADER_H_ + + + diff --git a/include/sysmenu/sysmenu_lib.h b/include/sysmenu/sysmenu_lib.h new file mode 100644 index 00000000..d0565c02 --- /dev/null +++ b/include/sysmenu/sysmenu_lib.h @@ -0,0 +1,35 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL - SYSMENU_LIB + File: sysmenu_lib.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: 2007-09-06$ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef SYSM_SYSMENU_LIB_H_ +#define SYSM_SYSMENU_LIB_H_ + +#ifdef SDK_ARM9 +#include +#include +#endif // SDK_ARM9 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +/* SYSM_SYSMENU_LIB_H_ */ +#endif diff --git a/include/sysmenu/sysmenu_lib/ARM9/cmn.h b/include/sysmenu/sysmenu_lib/ARM9/cmn.h new file mode 100644 index 00000000..9640c416 --- /dev/null +++ b/include/sysmenu/sysmenu_lib/ARM9/cmn.h @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: mainFunc.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef CMN_H_ +#define CMN_H_ + + +#include +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +// define data--------------------------------------------- +#define ARY_SIZEOF(ary) ( sizeof(ary) / sizeof( (ary)[0] ) ) +#define ROUNDUP_DIV(a, b) (( (a) + ((b) - 1) ) / (b)) + + +// function------------------------------------------------ +void CMN_InitAllocator( NNSFndAllocator* pAllocator ); +void CMN_InitFileSystem( NNSFndAllocator* pAllocator ); +void CMN_ClearVram( void ); +u32 CMN_LoadFile(void** ppFile, const char* fpath, NNSFndAllocator* pAlloc); +void CMN_UnloadFile(void* pFile, NNSFndAllocator* pAlloc); +NNSFndArchive* CMN_LoadArchive(const char* name, const char* path, NNSFndAllocator* pAllocator); +void CMN_RemoveArchive(NNSFndArchive* archive, NNSFndAllocator* pAllocator); + + +#ifdef __cplusplus +}/* extern "C" */ +#endif + +#endif // CMN_H_ + diff --git a/include/sysmenu/sysmenu_lib/ARM9/sysmenu_api.h b/include/sysmenu/sysmenu_lib/ARM9/sysmenu_api.h new file mode 100644 index 00000000..d79af41a --- /dev/null +++ b/include/sysmenu/sysmenu_lib/ARM9/sysmenu_api.h @@ -0,0 +1,94 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: SYSM_lib.h + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __SYSM_LIB_H__ +#define __SYSM_LIB_H__ + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// define data---------------------------------------------------------- + +#define SYSM_CTRDG_DMA_NO 0 // カートリッジ周辺機器情報の読み込みに使用するDMA番号です。 + // 同時に使用するDMA番号の中で最も優先が高い番号にして下さい。 + // 他のDMAへ割り込まれると、読み込みに失敗する可能性があります。 + + +// global variable------------------------------------------------------ + +// function------------------------------------------------------------- +extern void SYSM_Init( void ); +extern BOOL SYSM_WaitARM7Init( void ); +extern s32 SYSM_Main( void ); + +extern void SYSM_PermitToBootSelectedTarget( void ); +extern void SYSM_LoadSYSMData( void ); +extern BOOL SYSM_BootNITRO( void ); +extern void SYSM_BootPictChat( void ); +extern void SYSM_BootDSDownloadPlay( void ); +extern void SYSM_BootMachineSetting( void ); + +extern BOOL SYSM_ReadBannerFile( BannerFile *banner ); +extern BOOL SYSM_IsTPReadable( void ); + +extern BOOL SYSM_CheckNinLogo( u16 *logo_cardp ); +extern void SYSM_LoadNintendoLogo2D( u16 *ninLogoDatap, u16 *dstp, u16 color, u32 *tempBuffp ); // tempBuffpには0x700byte必要です。 +extern void SYSM_LoadNintendoLogo1D( u16 *ninLogoDatap, u16 *dstp, u16 color, u32 *tempBuffp ); // 同上。 + +extern void SYSM_SetBootFlag( u32 value ); +extern void SYSM_ClearBootFlag( u32 value ); + + +extern void SYSM_GoSleepMode( void ); +extern void PMm_SetBackLightBrightness( void ); + + +extern void NCD_ClearOwnerInfo( void ); // ニックネーム・誕生日・好きな色のクリア +extern BOOL SYSM_CheckRTCDate( RTCDate *datep ); +extern BOOL SYSM_CheckRTCTime( RTCTime *timep ); +extern s64 SYSM_CalcRtcOffsetAndSetDateTime( RTCDate *newDate, RTCTime *newTime ); +extern u32 SYSM_GetDayNum( u32 year, u32 month ); +extern BOOL SYSM_IsLeapYear100( u32 year ); + +extern BOOL SYSM_IsDebuggerBannerViewMode( void ); + +// ※以下の関数は、SYSM_Mainがコールされた後に正しい値が取得できるようになります。 + +// NITROカードが差さっているか? +static inline BOOL SYSM_IsNITROCard( void ) +{ + return (SYSM_GetBootFlag() & BFLG_EXIST_NITRO_CARD) ? TRUE : FALSE; +} + +// 検査用NITROカードが差さっているか? +static inline BOOL SYSM_IsInspectNITROCard( void ) +{ + return ( (SYSM_IsNITROCard()) && (GetRomHeaderAddr()->inspectCard) ); +} + + +#ifdef __cplusplus +} +#endif + +#endif // __SYSM_LIB_H__ diff --git a/include/sysmenu/sysmenu_work.h b/include/sysmenu/sysmenu_work.h new file mode 100644 index 00000000..db942bc3 --- /dev/null +++ b/include/sysmenu/sysmenu_work.h @@ -0,0 +1,246 @@ +/*---------------------------------------------------------------------------* + Project: TwlIPL + File: sysmenu_work.c + + Copyright 2007 Nintendo. All rights reserved. + + These coded instructions, statements, and computer programs contain + proprietary information of Nintendo of America Inc. and/or Nintendo + Company Ltd., and are protected by Federal copyright law. They may + not be disclosed to third parties or copied or duplicated in any form, + in whole or in part, without the prior written consent of Nintendo. + + $Date:: $ + $Rev$ + $Author$ + *---------------------------------------------------------------------------*/ + +#ifndef __SYSMENU_WORK_H__ +#define __SYSMENU_WORK_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// compile switch --------------------------------- +#ifndef SDK_FINALROM + +//#define __SYSM_DEBUG + +#endif // SDK_FINALROM + +//#define __DEBUG_SECURITY_CODE // PassMeのセキュリティコード確認用スイッチ + + +// define data ------------------------------------ +#define SYSMENU_VER 0x071029 // SystemMenuバージョン + +#define PXI_FIFO_TAG_SYSM PXI_FIFO_TAG_USER_1 // SystemMenu用のFIFOタグ + +#define PAD_PRODUCTION_NITRO_SHORTCUT ( PAD_BUTTON_A | PAD_BUTTON_B \ + | PAD_BUTTON_X | PAD_BUTTON_Y | PAD_BUTTON_R ) +#define PAD_PRODUCTION_AGB_SHORTCUT ( PAD_BUTTON_A | PAD_BUTTON_B \ + | PAD_BUTTON_X | PAD_BUTTON_Y | PAD_BUTTON_L ) + // 量産工程で使用するNITRO初回起動設定をキャンセルするショートカットキー + + + // bootFlagの値 +#define BFLG_EXIST_AGB_CARTRIDGE 0x00000001 +#define BFLG_EXIST_NITRO_CARD 0x00000002 +#define BFLG_ILLEGAL_NITRO_CARD 0x00000004 +#define BFLG_ILLEGAL_BMENU 0x00000008 +#define BFLG_BOOT_AGB 0x00000010 +#define BFLG_BOOT_NITRO 0x00000020 +#define BFLG_BOOT_BMENU 0x00000040 +#define BFLG_BOOT_PICT_CHAT 0x00000080 +#define BFLG_BOOT_WIRELESS_BOOT 0x00000100 +#define BFLG_LOAD_CARD_COMPLETED 0x00000200 +#define BFLG_LOAD_BMENU_COMPLETED 0x00000400 +#define BFLG_LOAD_SYSM_DATA_COMPLETED 0x00000800 +#define BFLG_REQ_UNCOMP_BMENU 0x00001000 +#define BFLG_REQ_UNCOMP_SYSM_DATA 0x00002000 +#define BFLG_ARM7_INIT_COMPLETED 0x00004000 +#define BFLG_READ_NCD_COMPLETED 0x00008000 +#define BFLG_SHORTCUT_CHECK_COMPLETED 0x00010000 +#define BFLG_HOT_START 0x00020000 +#define BFLG_BOOT_1SEG 0x00040000 +#define BFLG_PERMIT_TO_BOOT 0x08000000 +#define BFLG_SYSM_DATA_ENABLE 0x10000000 +#define BFLG_CARD_CHECKED 0x20000000 +#define BFLG_WM_INITIALIZED 0x40000000 +#define BFLG_BOOT_DECIDED 0x80000000 + +#define CLONE_BOOT_MODE 1 +#define OTHER_BOOT_MODE 2 + + // mainp_stateの値 +typedef enum MainpState { + MAINP_STATE_INIT = 1, + MAINP_STATE_START, + MAINP_STATE_WAIT_BOOT_DECISION, + MAINP_STATE_WAIT_NITRO_GAME_LOAD, + MAINP_STATE_WAIT_READY_CHANGE_AGB, + MAINP_STATE_WAIT_BMENU_LOAD, + MAINP_STATE_WAIT_BOOT_REQ, + MAINP_STATE_WAIT_START_NITRO_GAME_REQ, + MAINP_STATE_BOOT_SELECTED_TARGET, + MAINP_STATE_BOOT_AGB_REQ +}MainpState; + + + // subp_stateの値 +typedef enum SubpState { + SUBP_STATE_INIT = 1, + SUBP_STATE_STAY, + SUBP_STATE_CLEAR_MAIN_MEMORY, + SUBP_STATE_BOOT_NITRO_GAME_INIT, + SUBP_STATE_LOAD_NITRO_GAME, + SUBP_STATE_LOAD_BMENU, + SUBP_STATE_BOOT_NITRO_GAME, + SUBP_STATE_WAIT_START_BMENU_REQ, + SUBP_STATE_START_BMENU, + SUBP_STATE_BOOT_AGB, + SUBP_STATE_BOOT_AGB_ACK, + SUBP_STATE_BOOT_FAILED, + SUBP_STATE_MB_BOOT, + SUBP_STATE_TERMINATE_WM +}SubpState; + + + // SYSMi_SendMessageToARM7(int msg)でARM9からARM7に通知するメッセージ + // ARM7からのメッセージも含む +typedef enum SYSMMsg { + MSG_INVALID = 0, // 無効データ。 + + MSG_UNCOMP_SYSM_DATA, // ARM9にSYSM_dataを圧縮展開するよう要求。 + MSG_UNCOMP_BMENU, // ARM9にbmenuを圧縮展開するよう要求。 + + MSG_BOOT_TYPE_NITRO, // ARM7に「NITROゲーム起動」を通知。 + MSG_BOOT_TYPE_AGB, // ARM7に「AGB起動」を通知。 +#ifndef __DS_CHAT_OFF + MSG_BOOT_TYPE_PICT_CHAT, // ARM7に「絵チャット起動」を通知。 +#endif + MSG_BOOT_TYPE_WIRELESS_BOOT, // ARM7に「無線マルチブート起動」を通知。 + MSG_BOOT_TYPE_BMENU, // ARM7に「ブートメニュー起動」を通知。 + MSG_START_BMENU, // ARM7に「ブートメニュー開始」を通知。 + MSG_TERMINATE_WM // ARM7に「WM終了」を通知。 +}SYSMMsg; + + +//---------------------------------------------------------------------- +// データ型定義 +//---------------------------------------------------------------------- + +#ifdef SDK_ARM7 // ※ARM7では、SDKのrtc/ARM9/api.h定義のこのデータはインクルードされないので、ここで定義。 +// 曜日定義 +typedef enum RTCWeek +{ + RTC_WEEK_SUNDAY = 0 , // 日曜日 + RTC_WEEK_MONDAY , // 月曜日 + RTC_WEEK_TUESDAY , // 火曜日 + RTC_WEEK_WEDNESDAY , // 水曜日 + RTC_WEEK_TURSDAY , // 木曜日 + RTC_WEEK_FRIDAY , // 金曜日 + RTC_WEEK_SATURDAY , // 土曜日 + RTC_WEEK_MAX + +} RTCWeek; + +// 午前・午後定義 +typedef enum RTCNoon +{ + RTC_NOON_AM = 0, // 午前 + RTC_NOON_PM , // 午後 + RTC_NOON_MAX + +} RTCNoon; + +// 日付構造体 +typedef struct RTCDate +{ + u32 year; // 年 ( 0 ~ 99 ) + u32 month; // 月 ( 1 ~ 12 ) + u32 day; // 日 ( 1 ~ 31 ) + RTCWeek week; // 曜日 + +} RTCDate; + +// 時刻構造体 +typedef struct RTCTime +{ + u32 hour; // 時 ( 0 ~ 23 ) + u32 minute; // 分 ( 0 ~ 59 ) + u32 second; // 秒 ( 0 ~ 59 ) +} RTCTime; +#endif // SDK_ARM7 + + +// スピンロック変数構造体 +typedef struct LockVariable{ + OSLockWord lock; + vu32 value; +}LockVariable; + + +// RTC日付時刻構造体 +typedef struct RtcDateTime { + RTCDate Date; + RTCTime Time; +}RtcDateTime; + + +// SYSM共有ワーク構造体 +typedef struct SYSM_work{ + u32 card_arm7_ram_adr; // NITROカードARM7初期ブートコードのRAMロードアドレス + int ncd_invalid; // NITRO設定データ無効フラグ + u32 ncd_rom_adr; // NITRO設定データのROMアドレス + u32 bm_arm7_ram_adr; // ブートメニューARM9RAMアドレス + u32 bm_arm7_comp_adr; // ブートメニューARM7の圧縮バイナリRAMアドレス + u16 sysm_data_crc16; + u16 bm_crc16; + u8 sysm_type; + u8 pmic_type; // デバッガのみで使用。 + u8 clone_boot_mode; + + + u8 rtcStatus; + u16 cardHeaderCrc16; + u16 rsv; + BOOL isOnDebugger; + BOOL enableCardNormalOnly; + u32 nCardID; // NORMALカードID(LoadCardHeader() で取得) + + volatile MainpState mainp_state; // ARM9プログラムステート + volatile SubpState subp_state; // ARM7プログラムステート + LockVariable boot_flag; // ブート状態フラグ(SYSM_GetBootFlag(),SetBootFlag()でアクセスを行います。) + RtcDateTime rtc[2]; // RTC時間データ([0]:起動時の値、[1]:ゲームブート直前の値) +// u32 mb_flag; +// u32 mb_ggid; +}SYSM_work; + + +//---------------------------------------------------------------------- +// SYSM共有ワーク領域のアドレス獲得 +//---------------------------------------------------------------------- + +#define GetSYSMWork() ( (SYSM_work *)HW_RED_RESERVED ) + +//・SYSM共有ワーク領域のアドレスを獲得します。 + +//---------------------------------------------------------------------- +// bootFlagのリード +//---------------------------------------------------------------------- +#define SYSM_GetBootFlag() ( *(vu32 *)&GetSYSMWork()->boot_flag.value ) + +//・bootFlag値を獲得します。 + + +#ifdef __cplusplus +} +#endif + +#endif // __SYSMENU_WORK_H__ +