diff --git a/Makefile b/Makefile index 1501fd9..f75cc23 100644 --- a/Makefile +++ b/Makefile @@ -80,7 +80,7 @@ CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) BMPFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.bmp))) PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) -BINFILES := load.bin bootstub.bin +BINFILES := load.bin bootstub.bin exceptionstub.bin #--------------------------------------------------------------------------------- # use CXX for linking C++ projects, CC for standard C @@ -117,9 +117,9 @@ endif export GAME_TITLE := $(TARGET) -.PHONY: bootloader bootstub clean arm7/$(TARGET).elf arm9/$(TARGET).elf +.PHONY: bootloader bootstub exceptionstub clean arm7/$(TARGET).elf arm9/$(TARGET).elf -all: bootloader bootstub $(TARGET).nds +all: bootloader bootstub exceptionstub $(TARGET).nds dist: all @rm -fr hbmenu @@ -160,6 +160,7 @@ clean: @rm -fr $(TARGET).arm9.elf @$(MAKE) -C bootloader clean @$(MAKE) -C bootstub clean + @$(MAKE) -C nds-exception-stub clean @$(MAKE) -C arm9 clean @$(MAKE) -C arm7 clean @@ -167,7 +168,10 @@ data: @mkdir -p data bootloader: data - @$(MAKE) -C bootloader + @$(MAKE) -C bootloader LOADBIN=$(CURDIR)/data/load.bin + +exceptionstub: data + @$(MAKE) -C nds-exception-stub STUBBIN=$(CURDIR)/data/exceptionstub.bin bootstub: data @$(MAKE) -C bootstub diff --git a/nds-exception-stub/.gitignore b/nds-exception-stub/.gitignore new file mode 100644 index 0000000..dbbe774 --- /dev/null +++ b/nds-exception-stub/.gitignore @@ -0,0 +1,5 @@ +*.elf +*.bin +build + +!/data/font.bin diff --git a/nds-exception-stub/Makefile b/nds-exception-stub/Makefile new file mode 100644 index 0000000..8baf423 --- /dev/null +++ b/nds-exception-stub/Makefile @@ -0,0 +1,145 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +include $(DEVKITARM)/ds_rules + +#--------------------------------------------------------------------------------- +# TARGET is the name of the output +# BUILD is the directory where object files & intermediate files will be placed +# SOURCES is a list of directories containing source code +# INCLUDES is a list of directories containing extra header files +# DATA is a list of directories containing binary files embedded using bin2o +# GRAPHICS is a list of directories containing image files to be converted with grit +#--------------------------------------------------------------------------------- +TARGET := $(shell basename $(CURDIR)) +BUILD := build +SOURCES := source +INCLUDES := include ../include +DATA := data +GRAPHICS := gfx + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- + +ARCH := -mthumb -mthumb-interwork -flto -Os + +CFLAGS := -g -Wall \ + -march=armv5te -mtune=arm946e-s -fomit-frame-pointer\ + -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM9 +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions + +ASFLAGS := -g $(ARCH) +LDFLAGS = -nostartfiles -T../exceptionstub.ld -Wl,--section-start,.crt0=0x2ffa000 -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +#--------------------------------------------------------------------------------- +# any extra libraries we wish to link with the project (order is important) +#--------------------------------------------------------------------------------- +LIBS := -lnds9 + + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(LIBNDS) + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export STUBBIN ?= $(CURDIR)/$(TARGET).bin +export STUBELF := $(CURDIR)/$(TARGET).elf + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) \ + $(foreach dir,$(GRAPHICS),$(CURDIR)/$(dir)) + +export DEPSDIR := $(CURDIR)/$(BUILD) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +PNGFILES := $(foreach dir,$(GRAPHICS),$(notdir $(wildcard $(dir)/*.png))) +BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) + +#--------------------------------------------------------------------------------- +# use CXX for linking C++ projects, CC for standard C +#--------------------------------------------------------------------------------- +ifeq ($(strip $(CPPFILES)),) +#--------------------------------------------------------------------------------- + export LD := $(CC) +#--------------------------------------------------------------------------------- +else +#--------------------------------------------------------------------------------- + export LD := $(CXX) +#--------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------- + +export OFILES := $(addsuffix .o,$(BINFILES)) \ + $(PNGFILES:.png=.o) \ + $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) + +export INCLUDE := $(foreach dir,$(INCLUDES),-iquote $(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I$(CURDIR)/$(BUILD) + +export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) + +icons := $(wildcard *.bmp) + +ifneq (,$(findstring $(TARGET).bmp,$(icons))) + export GAME_ICON := $(CURDIR)/$(TARGET).bmp +else + ifneq (,$(findstring icon.bmp,$(icons))) + export GAME_ICON := $(CURDIR)/icon.bmp + endif +endif + +.PHONY: $(BUILD) clean + +#--------------------------------------------------------------------------------- +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).elf $(TARGET).bin + +#--------------------------------------------------------------------------------- +else + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(STUBBIN) : $(STUBELF) + $(OBJCOPY) -O binary $< $@ + @echo built ... $(notdir $@) + +$(STUBELF) : $(OFILES) + +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + $(bin2o) + +-include $(DEPSDIR)/*.d + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/nds-exception-stub/data/font.bin b/nds-exception-stub/data/font.bin new file mode 100644 index 0000000..73436fc Binary files /dev/null and b/nds-exception-stub/data/font.bin differ diff --git a/nds-exception-stub/exceptionstub.ld b/nds-exception-stub/exceptionstub.ld new file mode 100644 index 0000000..0c08eef --- /dev/null +++ b/nds-exception-stub/exceptionstub.ld @@ -0,0 +1,202 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +MEMORY { + ewram : ORIGIN = 0x02000000, LENGTH = 16M +} + + +PHDRS { + main PT_LOAD FLAGS(7); +} + +SECTIONS +{ + + .crt0 : + { + __text_start = . ; + KEEP (*(.crt0)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0x00 + + .plt : { *(.plt) } >ewram :main = 0xff + + .init : + { + KEEP (*(SORT_NONE(.init))) + } >ewram :main + + .text : /* ALIGN (4): */ + { + *(EXCLUDE_FILE(*.itcm* *.vectors* *.twl*) .text) + *(EXCLUDE_FILE(*.itcm* *.vectors* *.twl*) .stub) + *(EXCLUDE_FILE(*.itcm* *.vectors* *.twl*) .text.*) + /* .gnu.warning sections are handled specially by elf32.em. */ + *(EXCLUDE_FILE(*.twl*) .gnu.warning) + *(EXCLUDE_FILE(*.twl*) .gnu.linkonce.t*) + *(.glue_7) + *(.glue_7t) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0xff + + .fini : + { + KEEP (*(.fini)) + } >ewram :main =0xff + + __text_end = . ; + + .rodata : + { + *(EXCLUDE_FILE(*.twl*) .rodata) + *all.rodata*(*) + *(EXCLUDE_FILE(*.twl*) .roda) + *(EXCLUDE_FILE(*.twl*) .rodata.*) + *(EXCLUDE_FILE(*.twl*) .gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0xff + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ewram :main + __exidx_start = .; + ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ewram :main + __exidx_end = .; + + /* Ensure the __preinit_array_start label is properly aligned. We + could instead move the label definition inside the section, but + the linker would then create the section even if it turns out to + be empty, which isn't pretty. */ + + . = ALIGN(32 / 8); + + PROVIDE (__preinit_array_start = .); + .preinit_array : { KEEP (*(.preinit_array)) } >ewram :main = 0xff + PROVIDE (__preinit_array_end = .); + PROVIDE (__init_array_start = .); + .init_array : + { + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + } >ewram :main = 0xff + PROVIDE (__init_array_end = .); + PROVIDE (__fini_array_start = .); + .fini_array : + { + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + } >ewram :main = 0xff + + PROVIDE (__fini_array_end = .); + + .ctors : + { + /* gcc uses crtbegin.o to find the start of the constructors, so + we make sure it is first. Because this is a wildcard, it + doesn't matter if the user does not actually link against + crtbegin.o; the linker won't look for a file to match a + wildcard. The wildcard also means that it doesn't matter which + directory crtbegin.o is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0xff + + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0xff + + .eh_frame : + { + KEEP (*(.eh_frame)) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0xff + + .gcc_except_table : + { + *(.gcc_except_table) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0xff + .jcr : { KEEP (*(.jcr)) } >ewram :main = 0 + .got : { *(.got.plt) *(.got) *(.rel.got) } >ewram :main = 0 + + .ewram ALIGN(4) : + { + __ewram_start = ABSOLUTE(.) ; + *(.ewram) + *ewram.*(.text) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + } >ewram :main = 0xff + + + .data ALIGN(4) : + { + __data_start = ABSOLUTE(.); + *(EXCLUDE_FILE(*.twl*) .data) + *(EXCLUDE_FILE(*.twl*) .data.*) + *(EXCLUDE_FILE(*.twl*) .gnu.linkonce.d*) + CONSTRUCTORS + . = ALIGN(4); + __data_end = ABSOLUTE(.) ; + } >ewram :main = 0xff + + __bss_vma = . ; + + .bss __bss_vma (NOLOAD): + { + __bss_start = ABSOLUTE(.); + __bss_start__ = ABSOLUTE(.); + *(EXCLUDE_FILE(*.twl*) .dynbss) + *(EXCLUDE_FILE(*.twl*) .gnu.linkonce.b*) + *(EXCLUDE_FILE(*.twl*) .bss*) + *(EXCLUDE_FILE(*.twl*) COMMON) + . = ALIGN(4); /* REQUIRED. LD is flaky without it. */ + __bss_end__ = ABSOLUTE(.) ; + __end__ = ABSOLUTE(.) ; + } >ewram :NONE + + + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + .stack 0x80000 : { _stack = .; *(.stack) } + /* These must appear regardless of . */ +} diff --git a/nds-exception-stub/source/display.c b/nds-exception-stub/source/display.c new file mode 100644 index 0000000..442d8cf --- /dev/null +++ b/nds-exception-stub/source/display.c @@ -0,0 +1,442 @@ +/*--------------------------------------------------------------------------------- + + Copyright (C) 2005 - 2017 + Dave Murphy (WinterMute) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source + distribution. + +---------------------------------------------------------------------------------*/ +#include + +#include "font_bin.h" + +typedef struct con { + int x,y; +} consoleVars; + + +static consoleVars topCON = {0,0} , btmCON = {0,0}; + +static consoleVars *currentCON = &topCON; + + +//--------------------------------------------------------------------------------- +void setScreen(int screen) { +//--------------------------------------------------------------------------------- + currentCON = (screen == 0 ) ? &btmCON : &topCON; +} + +//--------------------------------------------------------------------------------- +// upcvt_4bit() +// Convert a 1-bit font to GBA 4-bit format. +//--------------------------------------------------------------------------------- +void upcvt_4bit(void *dst, const u8 *src, u32 len) { +//--------------------------------------------------------------------------------- + u32 *out = dst; + + for(; len > 0; len--) { + u32 dst_bits = 0; + u32 src_bits = *src++; + u32 x; + + for(x = 0; x < 8; x++) { + dst_bits <<= 4; + dst_bits |= src_bits & 1; + src_bits >>= 1; + } + *out++ = dst_bits; + } +} + +//--------------------------------------------------------------------------------- +static void newRow() { +//--------------------------------------------------------------------------------- + currentCON->y++; + currentCON->x = 0; + if (currentCON->y > 23) { + u32 *src = (u32*)(BG_MAP_RAM(4) + 32); + u32 *dst = (u32*)BG_MAP_RAM(4); + memcpy(dst,src,64*24); + currentCON->y = 23; + } +} + +//--------------------------------------------------------------------------------- +static void writeChar(char c) { +//--------------------------------------------------------------------------------- + u16 *mapcell = BG_MAP_RAM(4) + currentCON->x + (currentCON->y * 32); + switch(c) { + + case 10: + newRow(); + case 13: + currentCON->x = 0; + break; + default: + *mapcell = c; + currentCON->x++; + break; + } + if (currentCON->x > 31) newRow(); +} + +//--------------------------------------------------------------------------------- +static void writeString(char *str, int len) { +//--------------------------------------------------------------------------------- + while(len--) { + writeChar(*str++); + } +} + +//--------------------------------------------------------------------------------- +void setCursor(int row, int column) { +//--------------------------------------------------------------------------------- + currentCON->x = column; + currentCON->y = row; +} + +void getCursor(int *row, int*column) { + *column = currentCON->x; + *row = currentCON->y; +} + +//--------------------------------------------------------------------------------- +void initDisplay() { +//--------------------------------------------------------------------------------- + videoSetMode(MODE_0_2D | DISPLAY_BG0_ACTIVE); + videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE); + + upcvt_4bit(BG_TILE_RAM(0),font_bin,font_bin_size); + upcvt_4bit(BG_TILE_RAM_SUB(0),font_bin,font_bin_size); + BGCTRL[0] = BG_MAP_BASE(4) | BG_TILE_BASE(0) | BG_COLOR_16 | BG_32x32; + BGCTRL_SUB[0] = BG_MAP_BASE(4) | BG_TILE_BASE(0) | BG_COLOR_16 | BG_32x32; + + u16 *top = BG_MAP_RAM(4); + u16 *btm = BG_MAP_RAM_SUB(4); + int i; + for ( i = 0; i < 32*32; i++ ) { + *top++ = 0x20; + *btm++ = 0x20; + } + BG_PALETTE[0]=RGB5(31,0,0); + BG_PALETTE[1]=RGB5(31,31,31); + BG_PALETTE_SUB[0]=RGB5(31,0,0); + BG_PALETTE_SUB[1]=RGB5(31,31,31); + +} + +//--------------------------------------------------------------------------------- +u32 vramDefault() { +//--------------------------------------------------------------------------------- + u32 tmp = VRAM_CR; + vramSetBankA(VRAM_A_MAIN_BG); + vramSetBankC(VRAM_C_SUB_BG); + return tmp; +} + +/* + * linux/lib/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include +#include + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ + +#define do_div(n,base) ({ \ +int __res; \ +__res = ((unsigned long) n) % (unsigned) base; \ +n = ((unsigned long) n) / (unsigned) base; \ +__res; }) + +static char * number(char * str, long num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[66]; + const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; + int i; + + if (type & LARGE) + digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + if (type & LEFT) + type &= ~ZEROPAD; + if (base < 2 || base > 36) + return 0; + c = (type & ZEROPAD) ? '0' : ' '; + sign = 0; + if (type & SIGN) { + if (num < 0) { + sign = '-'; + num = -num; + size--; + } else if (type & PLUS) { + sign = '+'; + size--; + } else if (type & SPACE) { + sign = ' '; + size--; + } + } + if (type & SPECIAL) { + if (base == 16) + size -= 2; + else if (base == 8) + size--; + } + i = 0; + if (num == 0) + tmp[i++]='0'; + else while (num != 0) + tmp[i++] = digits[do_div(num,base)]; + if (i > precision) + precision = i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type & SPECIAL) { + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + } + if (!(type & LEFT)) + while (size-- > 0) + *str++ = c; + while (i < precision--) + *str++ = '0'; + while (i-- > 0) + *str++ = tmp[i]; + while (size-- > 0) + *str++ = ' '; + return str; +} + +int kvsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + unsigned long num; + int i, base; + char * str; + const char *s; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + ++fmt; + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + /* default base */ + base = 10; + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + continue; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + continue; + + case 'p': + if (field_width == -1) { + field_width = 2*sizeof(void *); + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + continue; + + + case 'n': + if (qualifier == 'l') { + long * ip = va_arg(args, long *); + *ip = (str - buf); + } else { + int * ip = va_arg(args, int *); + *ip = (str - buf); + } + continue; + + case '%': + *str++ = '%'; + continue; + + /* integer number formats - set up the flags and "break" */ + case 'o': + base = 8; + break; + + case 'X': + flags |= LARGE; + case 'x': + base = 16; + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + break; + + default: + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + continue; + } + if (qualifier == 'l') + num = va_arg(args, unsigned long); + else if (qualifier == 'h') { + num = (unsigned short) va_arg(args, int); + if (flags & SIGN) + num = (short) num; + } else if (flags & SIGN) + num = va_arg(args, int); + else + num = va_arg(args, unsigned int); + str = number(str, num, base, field_width, precision, flags); + } + *str = '\0'; + return str-buf; +} + +#define __DOUTBUFSIZE 256 + +char __outstr[__DOUTBUFSIZE]; + +//--------------------------------------------------------------------------------- +void kprintf(const char *str, ...) { +//--------------------------------------------------------------------------------- + + int len; + + va_list args; + + va_start(args, str); + len=kvsprintf(__outstr,str,args); + va_end(args); + + writeString(__outstr, len); +} + diff --git a/nds-exception-stub/source/display.h b/nds-exception-stub/source/display.h new file mode 100644 index 0000000..a8cc5cb --- /dev/null +++ b/nds-exception-stub/source/display.h @@ -0,0 +1,13 @@ +#ifndef _display_h_ +#define _display_h_ + +#define TOPSCREEN 0 +#define BTMSCREEM 0 + +void initDisplay(); +void kprintf(const char *str, ...); +void setCursor(int row, int column); +void getCursor(int *row, int *column); +void setScreen(int screen); + +#endif diff --git a/nds-exception-stub/source/gurumeditation.c b/nds-exception-stub/source/gurumeditation.c new file mode 100644 index 0000000..f6ca029 --- /dev/null +++ b/nds-exception-stub/source/gurumeditation.c @@ -0,0 +1,271 @@ +/*--------------------------------------------------------------------------------- + + Copyright (C) 2005 - 2017 + Dave Murphy (WinterMute) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source + distribution. + +---------------------------------------------------------------------------------*/ + +#include +#include + +#include +#include +#include +#include + +#include "display.h" + +//--------------------------------------------------------------------------------- +unsigned long ARMShift(unsigned long value,unsigned char shift) { +//--------------------------------------------------------------------------------- + // no shift at all + if (shift == 0x0B) return value ; + int index ; + if (shift & 0x01) { + // shift index is a register + index = exceptionRegisters[(shift >> 4) & 0x0F]; + } else { + // constant shift index + index = ((shift >> 3) & 0x1F) ; + } ; + int i ; + bool isN ; + switch (shift & 0x06) { + case 0x00: + // logical left + return (value << index) ; + case 0x02: + // logical right + return (value >> index) ; + case 0x04: + // arithmetical right + isN = (value & 0x80000000) ; + value = value >> index ; + if (isN) { + for (i=31;i>31-index;i--) { + value = value | (1 << i) ; + } ; + } ; + return value ; + case 0x06: + // rotate right + index = index & 0x1F; + value = (value >> index) | (value << (32-index)); + return value; + }; + return value; +} + + +//--------------------------------------------------------------------------------- +u32 getExceptionAddress( u32 opcodeAddress, u32 thumbState) { +//--------------------------------------------------------------------------------- + + int Rf, Rb, Rd, Rn, Rm; + + if (thumbState) { + // Thumb + + unsigned short opcode = *(unsigned short *)opcodeAddress ; + // ldr r,[pc,###] 01001ddd ffffffff + // ldr r,[r,r] 0101xx0f ffbbbddd + // ldrsh 0101xx1f ffbbbddd + // ldr r,[r,imm] 011xxfff ffbbbddd + // ldrh 1000xfff ffbbbddd + // ldr r,[sp,###] 1001xddd ffffffff + // push 1011x10l llllllll + // ldm 1100xbbb llllllll + + + if ((opcode & 0xF800) == 0x4800) { + // ldr r,[pc,###] + s8 offset = opcode & 0xff; + return exceptionRegisters[15] + offset; + } else if ((opcode & 0xF200) == 0x5000) { + // ldr r,[r,r] + Rb = (opcode >> 3) & 0x07 ; + Rf = (opcode >> 6) & 0x07 ; + return exceptionRegisters[Rb] + exceptionRegisters[Rf]; + + } else if ((opcode & 0xF200) == 0x5200) { + // ldrsh + Rb = (opcode >> 3) & 0x07; + Rf = (opcode >> 6) & 0x03; + return exceptionRegisters[Rb] + exceptionRegisters[Rf]; + + } else if ((opcode & 0xE000) == 0x6000) { + // ldr r,[r,imm] + Rb = (opcode >> 3) & 0x07; + Rf = (opcode >> 6) & 0x1F ; + return exceptionRegisters[Rb] + (Rf << 2); + } else if ((opcode & 0xF000) == 0x8000) { + // ldrh + Rb = (opcode >> 3) & 0x07 ; + Rf = (opcode >> 6) & 0x1F ; + return exceptionRegisters[Rb] + (Rf << 2); + } else if ((opcode & 0xF000) == 0x9000) { + // ldr r,[sp,#imm] + s8 offset = opcode & 0xff; + return exceptionRegisters[13] + offset; + } else if ((opcode & 0xF700) == 0xB500) { + // push/pop + return exceptionRegisters[13]; + } else if ((opcode & 0xF000) == 0xC000) { + // ldm/stm + Rd = (opcode >> 8) & 0x07; + return exceptionRegisters[Rd]; + } + } else { + // arm32 + unsigned long opcode = *(unsigned long *)opcodeAddress ; + + // SWP xxxx0001 0x00nnnn dddd0000 1001mmmm + // STR/LDR xxxx01xx xxxxnnnn ddddffff ffffffff + // STRH/LDRH xxxx000x x0xxnnnn dddd0000 1xx1mmmm + // STRH/LDRH xxxx000x x1xxnnnn ddddffff 1xx1ffff + // STM/LDM xxxx100x xxxxnnnn llllllll llllllll + + if ((opcode & 0x0FB00FF0) == 0x01000090) { + // SWP + Rn = (opcode >> 16) & 0x0F; + return exceptionRegisters[Rn]; + } else if ((opcode & 0x0C000000) == 0x04000000) { + // STR/LDR + Rn = (opcode >> 16) & 0x0F; + if (opcode & 0x02000000) { + // Register offset + Rm = opcode & 0x0F; + if (opcode & 0x01000000) { + unsigned short shift = (unsigned short)((opcode >> 4) & 0xFF) ; + // pre indexing + long Offset = ARMShift(exceptionRegisters[Rm],shift); + // add or sub the offset depending on the U-Bit + return exceptionRegisters[Rn] + ((opcode & 0x00800000)?Offset:-Offset); + } else { + // post indexing + return exceptionRegisters[Rn]; + } + } else { + // Immediate offset + unsigned long Offset = (opcode & 0xFFF) ; + if (opcode & 0x01000000) { + // pre indexing + // add or sub the offset depending on the U-Bit + return exceptionRegisters[Rn] + ((opcode & 0x00800000)?Offset:-Offset); + } else { + // post indexing + return exceptionRegisters[Rn]; + } + } + } else if ((opcode & 0x0E400F90) == 0x00000090) { + // LDRH/STRH with register Rm + Rn = (opcode >> 16) & 0x0F; + Rd = (opcode >> 12) & 0x0F; + Rm = opcode & 0x0F; + unsigned short shift = (unsigned short)((opcode >> 4) & 0xFF); + long Offset = ARMShift(exceptionRegisters[Rm],shift); + // add or sub the offset depending on the U-Bit + return exceptionRegisters[Rn] + ((opcode & 0x00800000)?Offset:-Offset); + } else if ((opcode & 0x0E400F90) == 0x00400090) { + // LDRH/STRH with immediate offset + Rn = (opcode >> 16) & 0x0F; + Rd = (opcode >> 12) & 0x0F; + unsigned long Offset = (opcode & 0xF) | ((opcode & 0xF00)>>8) ; + // add or sub the offset depending on the U-Bit + return exceptionRegisters[Rn] + ((opcode & 0x00800000)?Offset:-Offset) ; + } else if ((opcode & 0x0E000000) == 0x08000000) { + // LDM/STM + Rn = (opcode >> 16) & 0x0F; + return exceptionRegisters[Rn]; + } + } + return 0; +} + +static const char *registerNames[] = + { "r0","r1","r2","r3","r4","r5","r6","r7", + "r8 ","r9 ","r10","r11","r12","sp ","lr ","pc " }; + + +u32 __itcm_start = 0; + +//--------------------------------------------------------------------------------- +void guruMeditation() { +//--------------------------------------------------------------------------------- + kprintf(" Guru Meditation Error!\n"); + u32 currentMode = getCPSR() & 0x1f; + u32 thumbState = ((*(u32*)0x02FFFD90) & 0x20); + + u32 codeAddress, exceptionAddress = 0; + + int offset = 8; + + if ( currentMode == 0x17 ) { + kprintf (" data abort!\n\n"); + codeAddress = exceptionRegisters[15] - offset; + if ( (codeAddress > 0x02000000 && codeAddress < 0x03000000) ) + exceptionAddress = getExceptionAddress( codeAddress, thumbState); + else + exceptionAddress = codeAddress; + + } else { + if (thumbState) + offset = 2; + else + offset = 4; + kprintf(" undefined instruction!\n\n"); + codeAddress = exceptionRegisters[15] - offset; + exceptionAddress = codeAddress; + } + + kprintf(" pc: %08X addr: %08X\n\n",codeAddress,exceptionAddress); + + int i; + for ( i=0; i < 8; i++ ) { + kprintf( " %s: %08X %s: %08X\n", + registerNames[i], exceptionRegisters[i], + registerNames[i+8],exceptionRegisters[i+8]); + } + kprintf("\ncpsr: %08X\n",getCPSR()); + u32 *stack = (u32 *)exceptionRegisters[13]; + for ( i=0; i<8; i++ ) { + setCursor(8-i+16,2); + kprintf( "%08X: %08X %08X", (u32)&stack[i*2],stack[i*2], stack[(i*2)+1] ); + } +} + +void __attribute__((weak)) initSystem(void); + +//--------------------------------------------------------------------------------- +void excepthandler() { +//--------------------------------------------------------------------------------- + REG_MASTER_BRIGHT = 0; + REG_MASTER_BRIGHT_SUB = 0; + initSystem(); + initDisplay(); + guruMeditation(); + while(1); +} + +//--------------------------------------------------------------------------------- +void installException() { +//--------------------------------------------------------------------------------- + setExceptionHandler(excepthandler); +} diff --git a/nds-exception-stub/source/start.s b/nds-exception-stub/source/start.s new file mode 100644 index 0000000..061723b --- /dev/null +++ b/nds-exception-stub/source/start.s @@ -0,0 +1,109 @@ +/*--------------------------------------------------------------------------------- + + Copyright (C) 2005 - 2017 + Dave Murphy (WinterMute) + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + 3. This notice may not be removed or altered from any source + distribution. + +---------------------------------------------------------------------------------*/ + +@--------------------------------------------------------------------------------- +@ DS processor selection +@--------------------------------------------------------------------------------- + .arch armv5te + .cpu arm946e-s +@--------------------------------------------------------------------------------- + + +@--------------------------------------------------------------------------------- + .section ".crt0","ax" + .global _start +@--------------------------------------------------------------------------------- + .align 4 + .arm +@--------------------------------------------------------------------------------- +_start: +@--------------------------------------------------------------------------------- + push {lr} + + ldr r0, =__bss_start__ @ Clear BSS section + ldr r1, =__bss_end__ + sub r1, r1, r0 + bl ClearMem + + ldr r0, =installException + blx r0 + + pop {lr} + + bx lr + + .pool + +@--------------------------------------------------------------------------------- +@ Clear memory to 0x00 if length != 0 +@ r0 = Start Address +@ r1 = Length +@--------------------------------------------------------------------------------- +ClearMem: +@--------------------------------------------------------------------------------- + mov r2, #3 @ Round down to nearest word boundary + add r1, r1, r2 @ Shouldn't be needed + bics r1, r1, r2 @ Clear 2 LSB (and set Z) + bxeq lr @ Quit if copy size is 0 + + mov r2, #0 +ClrLoop: + stmia r0!, {r2} + subs r1, r1, #4 + bne ClrLoop + + bx lr + + +@--------------------------------------------------------------------------------- +@ Copy memory if length != 0 +@ r1 = Source Address +@ r2 = Dest Address +@ r4 = Dest Address + Length +@--------------------------------------------------------------------------------- +CopyMemCheck: +@--------------------------------------------------------------------------------- + sub r3, r4, r2 @ Is there any data to copy? +@--------------------------------------------------------------------------------- +@ Copy memory +@ r1 = Source Address +@ r2 = Dest Address +@ r3 = Length +@--------------------------------------------------------------------------------- +CopyMem: +@--------------------------------------------------------------------------------- + mov r0, #3 @ These commands are used in cases where + add r3, r3, r0 @ the length is not a multiple of 4, + bics r3, r3, r0 @ even though it should be. + bxeq lr @ Length is zero, so exit +CIDLoop: + ldmia r1!, {r0} + stmia r2!, {r0} + subs r3, r3, #4 + bne CIDLoop + + bx lr + + .align 2 +