diff --git a/Makefile b/Makefile index ee52a24..94fd233 100644 --- a/Makefile +++ b/Makefile @@ -10,41 +10,70 @@ include project.cfg # Compiler flags -cf := -mb -ffreestanding -nostdlib -Wall -Wextra \ - -fstrict-volatile-bitfields $(CFLAGS) -cf-fx := $(cf) -m3 -DFX9860G -cf-cg := $(cf) -m4-nofpu -DFXCG50 +CFLAGSFX := $(CFLAGS) $(CFLAGS_FX) $(INCLUDE) +CFLAGSCG := $(CFLAGS) $(CFLAGS_CG) $(INCLUDE) # Linker flags -lf-fx := $(LDFLAGS) -Tfx9860g.ld -lgint-fx -lgcc -Wl,-Map=build-fx/map -lf-cg := $(LDFLAGS) -Tfxcg50.ld -lgint-cg -lgcc -Wl,-Map=build-cg/map +LDFLAGSFX := $(LDFLAGS) $(LDFLAGS_FX) +LDFLAGSCG := $(LDFLAGS) $(LDFLAGS_CG) -dflags = -MMD -MT $@ -MF $(@:.o=.d) -MP -cpflags := -R .bss -R .gint_bss +# Dependency list generation flags +depflags = -MMD -MT $@ -MF $(@:.o=.d) -MP +# ELF to binary flags +BINFLAGS := -R .bss -R .gint_bss -g1af := -i "$(ICON_FX)" -n "$(NAME)" --internal="$(INTERNAL)" -g3af := -n basic:"" -i uns:"$(ICON_CG_UNS)" -i sel:"$(ICON_CG_SEL)" +# G1A and G3A generation flags +NAME_G1A ?= $(NAME) +NAME_G3A ?= $(NAME) +G1AF := -i "$(ICON_FX)" -n "$(NAME_G1A)" --internal="$(INTERNAL)" +G3AF := -n basic:"$(NAME_G3A)" -i uns:"$(ICON_CG_UNS)" -i sel:"$(ICON_CG_SEL)" + +ifeq "$(TOOLCHAIN_FX)" "" +TOOLCHAIN_FX := sh3eb-elf +endif + +ifeq "$(TOOLCHAIN_CG)" "" +TOOLCHAIN_CG := sh4eb-elf +endif + +# fxconv flags +FXCONVFX := --fx --toolchain=$(TOOLCHAIN_FX) +FXCONVCG := --cg --toolchain=$(TOOLCHAIN_CG) # # File listings # -null := -filename := $(subst $(null) $(null),-,$(NAME)) +NULL := +TARGET := $(subst $(NULL) $(NULL),-,$(NAME)) -elf = $(dir $<)$(filename).elf -bin = $(dir $<)$(filename).bin -target-fx := $(filename).g1a -target-cg := $(filename).g3a +ifeq "$(TARGET_FX)" "" +TARGET_FX := $(TARGET).g1a +endif + +ifeq "$(TARGET_CG)" "" +TARGET_CG := $(TARGET).g3a +endif + +ELF_FX := build-fx/$(shell basename -s .g1a $(TARGET_FX)).elf +BIN_FX := $(ELF_FX:.elf=.bin) + +ELF_CG := build-cg/$(shell basename -s .g3a $(TARGET_CG)).elf +BIN_CG := $(ELF_CG:.elf=.bin) # Source files -src := $(wildcard src/*.c src/*/*.c src/*/*/*.c src/*/*/*/*.c) +src := $(wildcard src/*.[csS] \ + src/*/*.[csS] \ + src/*/*/*.[csS] \ + src/*/*/*/*.[csS]) assets-fx := $(wildcard assets-fx/*/*) assets-cg := $(wildcard assets-cg/*/*) # Object files -obj-fx := $(src:%.c=build-fx/%.o) $(assets-fx:assets-fx/%=build-fx/assets/%.o) -obj-cg := $(src:%.c=build-cg/%.o) $(assets-cg:assets-cg/%=build-cg/assets/%.o) +obj-fx := $(src:%=build-fx/%.o) \ + $(assets-fx:assets-fx/%=build-fx/assets/%.o) +obj-cg := $(src:%=build-cg/%.o) \ + $(assets-cg:assets-cg/%=build-cg/assets/%.o) # Additional dependencies deps-fx := $(ICON_FX) @@ -65,46 +94,68 @@ endif all: $(all) -all-fx: $(target-fx) -all-cg: $(target-cg) +all-fx: $(TARGET_FX) +all-cg: $(TARGET_CG) -$(target-fx): $(obj-fx) $(deps-fx) +$(TARGET_FX): $(obj-fx) $(deps-fx) + @ mkdir -p $(dir $@) + $(TOOLCHAIN_FX)-gcc -o $(ELF_FX) $(obj-fx) $(CFLAGSFX) $(LDFLAGSFX) + $(TOOLCHAIN_FX)-objcopy -O binary $(BINFLAGS) $(ELF_FX) $(BIN_FX) + fxg1a $(BIN_FX) -o $@ $(G1AF) - sh3eb-elf-gcc -o $(elf) $(obj-fx) $(cf-fx) $(lf-fx) - sh3eb-elf-objcopy -O binary $(cpflags) $(elf) $(bin) - fxg1a $(bin) -o $@ $(g1af) - -$(target-cg): $(obj-cg) $(deps-cg) - - sh4eb-elf-gcc -o $(elf) $(obj-cg) $(cf-cg) $(lf-cg) - sh4eb-elf-objcopy -O binary $(cpflags) $(elf) $(bin) - mkg3a $(g3af) $(bin) $@ +$(TARGET_CG): $(obj-cg) $(deps-cg) + @ mkdir -p $(dir $@) + $(TOOLCHAIN_CG)-gcc -o $(ELF_CG) $(obj-cg) $(CFLAGSCG) $(LDFLAGSCG) + $(TOOLCHAIN_CG)-objcopy -O binary $(BINFLAGS) $(ELF_CG) $(BIN_CG) + mkg3a $(G3AF) $(BIN_CG) $@ # C sources -build-fx/%.o: %.c +build-fx/%.c.o: %.c @ mkdir -p $(dir $@) - sh3eb-elf-gcc -c $< -o $@ $(cf-fx) $(dflags) -build-cg/%.o: %.c + $(TOOLCHAIN_FX)-gcc -c $< -o $@ $(CFLAGSFX) $(depflags) +build-cg/%.c.o: %.c @ mkdir -p $(dir $@) - sh4eb-elf-gcc -c $< -o $@ $(cf-cg) $(dflags) + $(TOOLCHAIN_CG)-gcc -c $< -o $@ $(CFLAGSCG) $(depflags) + +# Assembler sources +build-fx/%.s.o: %.s + @ mkdir -p $(dir $@) + $(TOOLCHAIN_FX)-gcc -c $< -o $@ +build-cg/%.s.o: %.s + @ mkdir -p $(dir $@) + $(TOOLCHAIN_CG)-gcc -c $< -o $@ + +# Preprocessed assembler sources +build-fx/%.S.o: %.S + @ mkdir -p $(dir $@) + $(TOOLCHAIN_FX)-gcc -c $< -o $@ $(INCLUDE) +build-cg/%.S.o: %.S + @ mkdir -p $(dir $@) + $(TOOLCHAIN_CG)-gcc -c $< -o $@ $(INCLUDE) # Images build-fx/assets/img/%.o: assets-fx/img/% @ mkdir -p $(dir $@) - fxconv -i $< -o $@ --fx name:img_$(basename $*) - + fxconv -i $< -o $@ $(FXCONVFX) name:img_$(basename $*) $(IMG.$*) build-cg/assets/img/%.o: assets-cg/img/% @ mkdir -p $(dir $@) - fxconv -i $< -o $@ --cg name:img_$(basename $*) + fxconv -i $< -o $@ $(FXCONVCG) name:img_$(basename $*) $(IMG.$*) # Fonts build-fx/assets/fonts/%.o: assets-fx/fonts/% @ mkdir -p $(dir $@) - fxconv -f $< -o $@ name:font_$(basename $*) $(FONT.$*) - + fxconv -f $< -o $@ $(FXCONVFX) name:font_$(basename $*) $(FONT.$*) build-cg/assets/fonts/%.o: assets-cg/fonts/% @ mkdir -p $(dir $@) - fxconv -f $< -o $@ name:font_$(basename $*) $(FONT.$*) + fxconv -f $< -o $@ $(FXCONVCG) name:font_$(basename $*) $(FONT.$*) + +# Binaries +build-fx/assets/bin/%.o: assets-fx/bin/% + @ mkdir -p $(dir $@) + fxconv -b $< -o $@ $(FXCONVFX) name:bin_$(basename $*) $(BIN.$*) +build-cg/assets/bin/%.o: assets-cg/bin/% + @ mkdir -p $(dir $@) + fxconv -b $< -o $@ $(FXCONVCG) name:bin_$(basename $*) $(BIN.$*) # # Cleaning and utilities @@ -116,14 +167,23 @@ build-fx/%.d: ; build-cg/%.d: ; .PRECIOUS: build-fx build-cg build-fx/%.d build-cg/%.d %/ -clean: - @ rm -rf build* -distclean: clean - @ rm -f $(target-fx) $(target-cg) +clean-fx: + @ rm -rf build-fx/ +clean-cg: + @ rm -rf build-cg/ -install-fx: $(target-fx) +distclean-fx: clean-fx + @ rm -f $(TARGET_FX) +distclean-cg: clean-cg + @ rm -f $(TARGET_CG) + +clean: clean-fx clean-cg + +distclean: distclean-fx distclean-cg + +install-fx: $(TARGET_FX) p7 send -f $< -install-cg: $(target-cg) +install-cg: $(TARGET_CG) @ while [[ ! -h /dev/Prizm1 ]]; do sleep 0.25; done @ while ! mount /dev/Prizm1; do sleep 0.25; done @ rm -f /mnt/prizm/$< diff --git a/assets-cg/swift-half.png b/assets-cg/swift-half.png new file mode 100644 index 0000000..7a4fee4 Binary files /dev/null and b/assets-cg/swift-half.png differ diff --git a/assets-cg/swift.png b/assets-cg/swift.png new file mode 100644 index 0000000..106b360 Binary files /dev/null and b/assets-cg/swift.png differ diff --git a/assets-cg/swords2.png b/assets-cg/swords2.png new file mode 100644 index 0000000..fb122ee Binary files /dev/null and b/assets-cg/swords2.png differ diff --git a/assets-fx/img/opt_dump.png b/assets-fx/img/opt_dump.png new file mode 100644 index 0000000..67bd0f0 Binary files /dev/null and b/assets-fx/img/opt_dump.png differ diff --git a/assets-fx/img/opt_gint_ram.png b/assets-fx/img/opt_gint_ram.png new file mode 100644 index 0000000..eb80d1e Binary files /dev/null and b/assets-fx/img/opt_gint_ram.png differ diff --git a/assets-fx/img/opt_mem.png b/assets-fx/img/opt_mem.png index af226bb..f8de1f3 100644 Binary files a/assets-fx/img/opt_mem.png and b/assets-fx/img/opt_mem.png differ diff --git a/include/gintctl/gint.h b/include/gintctl/gint.h index 827a0b5..f584df2 100644 --- a/include/gintctl/gint.h +++ b/include/gintctl/gint.h @@ -8,12 +8,25 @@ /* gintctl_gint_hardware(): Detected hardware configuration */ void gintctl_gint_hardware(void); +/* gintctl_gint_ram(): Determine the size of some memory areas */ +void gintctl_gint_ram(void); + +/* gintctl_gint_dump(): Dump memory to filesystem */ +void gintctl_gint_dump(void); + /* gintctl_gint_timer(): Show the timer status in real-time */ void gintctl_gint_timer(void); /* gintctl_gint_bopti(): Test image rendering */ void gintctl_gint_bopti(void); +#ifdef FXCG50 + +/* gintctl_gint_dma(): Test the Direct Access Memory Controller */ +void gintctl_gint_dma(void); + +#endif + #ifdef FX9860G /* gintctl_gint_gray(): Gray engine tuning */ @@ -24,4 +37,7 @@ void gintctl_gint_grayrender(void); #endif /* FX9860G */ +/* gintctl_gint_printf(): printf() function */ +void gintctl_gint_printf(void); + #endif /* GINTCTL_GINT */ diff --git a/include/gintctl/prof-contexts.h b/include/gintctl/prof-contexts.h index f8c71d0..06f76bd 100644 --- a/include/gintctl/prof-contexts.h +++ b/include/gintctl/prof-contexts.h @@ -11,12 +11,7 @@ enum { PROFCTX_BASICS = 0, PROFCTX_EMPTY, - - PROFCTX_DCLEAR, - PROFCTX_DUPDATE, - PROFCTX_DRECT1, - PROFCTX_DRECT2, - PROFCTX_DRECT3, + PROFCTX_RENDER, /* Last element and bound checker */ PROFCTX_COUNT, diff --git a/project.cfg b/project.cfg index e14bd80..aca2c74 100644 --- a/project.cfg +++ b/project.cfg @@ -3,9 +3,19 @@ #--- # Project name, should be at most 8 bytes long. -NAME = gintctl +# (You can also specify NAME_G1A or NAME_G3A to override individually.) +NAME := gintctl +NAME_G3A := + # Internal name, should be '@' followed by at most 7 uppercase letters. -INTERNAL = @GINTCTL +# WARNING: If this convention is not followed, the add-in might not appear in +# the main menu of the calculator! +INTERNAL := @GINTCTL + +# Output file name. The default is to take , replace spaces with dashes, +# and add .g1a (or .g3a). You can specify a different folder if you want. +TARGET_FX := +TARGET_CG := # fx-9860G icon location ICON_FX = assets-fx/icon.png @@ -13,10 +23,63 @@ ICON_FX = assets-fx/icon.png ICON_CG_UNS = assets-cg/icon-uns.png ICON_CG_SEL = assets-cg/icon-sel.png -# Additional compiler flags -CFLAGS = -std=c11 -Os -I include -# Additional linker flags -LDFLAGS = -lprof +#--- +# Toolchain selection +#--- + +# Toolchain for fx9860g. Please see also CFLAGS_FX below. +TOOLCHAIN_FX := sh-elf + +# Toolchain for fxcg50. Please see also CFLAGS_CG below. +TOOLCHAIN_CG := sh-elf + +#--- +# Compiler flags +#--- + +# Base compiler flags for the fxSDK, you usually want to keep these. +CFLAGS := -mb -ffreestanding -nostdlib -fstrict-volatile-bitfields + +# Platform-specific compiler flags. +# <> If you are using sh3eb-elf, use -m3. (You can do this on both FX and CG.) +# <> If you are using sh4eb-elf, use -m4-nofpu. (Not ideal on FX but works.) +# <> If you are using sh4eb-nofpu-elf, then your compiler will likely use the +# FPU and cause problems on the calculator. Consider another configuration. +# <> If you are using an sh-elf with several targets, specify whichever you +# support. I recommend -m3 on FX and -m4-nofpu on CG. +# Please see also TOOLCHAIN_FX and TOOLCHAIN_CG above. +CFLAGS_FX := -D FX9860G -m3 +CFLAGS_CG := -D FXCG50 -m4-nofpu + +# Additional compiler flags, change to your own taste! +CFLAGS += -Wall -Wextra -Os + +# Include paths. Add one -I option for each folder from which you want to +# be able to include files with #include<>. +INCLUDE := -I include + +# Libraries. Add one -l option for each library you are using, and also +# suitable -L options if you have library files in custom folders. To use +# fxlib, add libfx.a to the project directory and use "-L . -lfx". +LIBS := -lprof + +# Base linker flags for the fxSDK, you usually want to keep these. +LDFLAGS_FX := -T fx9860g.ld -lgint-fx $(LIBS) -lgint-fx -lgcc +LDFLAGS_CG := -T fxcg50.ld -lgint-cg $(LIBS) -lgint-cg -lgcc + +# Additional linker flags, if you need any. +LDFLAGS := + +# Additional platform-specific linker flags. +LDFLAGS_FX += -Wl,-Map=build-fx/map +LDFLAGS_CG += -Wl,-Map=build-cg/map + +#--- +# File conversion parameters +#--- # Parameters for the hexadecimal font on fx9860g FONT.hexa.png = charset:print grid.size:3x5 grid.padding:1 + +IMG.swift.png = profile:p4 +IMG.swords.png = profile:p8 diff --git a/src/gint/bopti.c b/src/gint/bopti.c index 1fc77b0..73b5b9f 100644 --- a/src/gint/bopti.c +++ b/src/gint/bopti.c @@ -1,3 +1,4 @@ +#define GINT_NEED_VRAM #include #include #include @@ -17,9 +18,8 @@ void gintctl_gint_bopti(void) while(key != KEY_EXIT) { dclear(C_WHITE); - bopti_render_noclip(0, 0, &img_swift, 0, 0, 396, 224); - bopti_render_clip(x, y, &img_swords, 0, 0, img_swords.width, - img_swords.height); + dimage(0, 0, &img_swift); + dimage(x, y, &img_swords); dupdate(); key = getkey().key; diff --git a/src/gint/dma.c b/src/gint/dma.c new file mode 100644 index 0000000..4781e1f --- /dev/null +++ b/src/gint/dma.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include + +#include +#include + +#ifdef FXCG50 + +#define DMA SH7305_DMA +#define dprint(x, y, ...) dprint(x, y, C_BLACK, C_NONE, __VA_ARGS__) + +void show_dma(int x, int y, int channel) +{ + sh7305_dma_channel_t *addr[6] = { + &DMA.DMA0, &DMA.DMA1, &DMA.DMA2, + &DMA.DMA3, &DMA.DMA4, &DMA.DMA5, + }; + sh7305_dma_channel_t *dma = addr[channel]; + + #ifdef FX9860G + dma->SAR = 0x12345678; + dma->DAR = 0x9abcdef0; + dma->TCR = 0x12481248; + + int dx=60, dy=8; + dprint(x, y, "DMA%d:", channel); + dprint(x, y+1*dy, "%08X", (uint32_t)dma); + dprint(x+dx, y+1*dy, "%08X", dma->DAR); + dprint(x, y+2*dy, "%08X", dma->TCR); + dprint(x+dx, y+2*dy, "%08X", dma->CHCR); + #endif + + #ifdef FXCG50 + int dx=45, dy=14; + dprint(x, y, "DMA%d:", channel); + dprint(x, y+1*dy, "SAR"); + dprint(x+dx, y+1*dy, "%08X", dma->SAR); + dprint(x, y+2*dy, "DAR"); + dprint(x+dx, y+2*dy, "%08X", dma->DAR); + dprint(x, y+3*dy, "TCR"); + dprint(x+dx, y+3*dy, "%08X", dma->TCR); + dprint(x, y+4*dy, "CHCR"); + dprint(x+dx, y+4*dy, "%08X", dma->CHCR); + #endif +} + +/* gintctl_gint_dma(): Test the Direct Access Memory Controller */ +void gintctl_gint_dma(void) +{ + /* Here we'll display the DMA status at "full speed", only limited by + the dupdate() time. */ + int key = 0, timeout = 1; + + /* Test channel, interrupts, and source */ + int channel = 0, interrupts = 0, source = 0; + /* Number of successful attempts */ + int successes = 0; + + #ifdef FX9860G + /* Currently visible channel */ + int view = 0; + #endif + + while(key != KEY_EXIT) + { + dclear(C_WHITE); + + #ifdef FX9860G + show_dma(1, 1, view); + + dprint(1, 32, "Channel %d", channel); + dprint(1, 40, "Interrupts %s", interrupts ? "Yes" : "No"); + dprint(1, 48, "Source %s", source ? "IL" : "RAM"); + dprint(103, 40, "%d", successes); + + extern image_t img_opt_gint_dma; + dimage(0, 56, &img_opt_gint_dma); + #endif + + #ifdef FXCG50 + row_title("Direct Memory Access status"); + + show_dma(6, 24, 0); + show_dma(138, 24, 1); + show_dma(270, 24, 2); + + dprint(6, 102, "DMAOR: %08X", DMA.OR); + + dprint(6, 130, "Channel"); + dprint(96, 130, "%d", channel); + dprint(6, 144, "Interrupt"); + dprint(96, 144, "%s", interrupts ? "Yes" : "No"); + dprint(6, 158, "Source"); + dprint(96, 158, "%s", source ? "IL" : "RAM"); + + fkey_button(1, "RUN"); + + fkey_action(4, "CHANNEL"); + fkey_action(5, "INT"); + fkey_action(6, "SOURCE"); + #endif + + dupdate(); + key = getkey_opt(GETKEY_DEFAULT, &timeout).key; + + /* On F1, start a DMA transfer and see what happens */ + if(key == KEY_F1) + { + void *src = (void *)(source ? 0xe5200000 : 0x88000000); + void *dst = gint_vram; + int blocks = 256; + + if(interrupts) + { + dma_transfer(channel, DMA_4B, blocks, + src, DMA_INC, dst, DMA_INC); + dma_transfer_wait(channel); + } + else dma_transfer_noint(channel, DMA_4B, blocks, + src, DMA_INC, dst, DMA_INC); + + successes++; + } + + #ifdef FX9860G + /* On F2, switch the visible channel */ + if(key == KEY_F2) view = (view + 1) % 6; + #endif + + /* On F4, F5 and F6, change parameters */ + if(key == KEY_F4) channel = (channel + 1) % 6; + if(key == KEY_F5) interrupts = !interrupts; + if(key == KEY_F6) source = !source; + } +} + +#endif /* FXCG50 */ diff --git a/src/gint/dump.c b/src/gint/dump.c new file mode 100644 index 0000000..98f0305 --- /dev/null +++ b/src/gint/dump.c @@ -0,0 +1,112 @@ +#include +#include +#include +#include + +#include +#include + +struct region { + char const *name; + uint32_t start; + uint32_t end; +}; + +static struct region const regs[] = { + { "ROM", 0x80000000, 0x807fffff }, + { "RAM", 0x88000000, 0x88040000 }, + { "RS", 0xfd800000, 0xfd8007ff }, +}; + +static void filename(char *out, int region_id, int rom_segment) +{ + if(region_id == 0) + { + sprintf(out, "ROM-%d.bin", rom_segment); + } + else + { + sprintf(out, "%s.bin", regs[region_id].name); + } +} + +#ifdef FX9860G +static void dump(int region_id, int rom_segment) +{ + uint32_t start = regs[region_id].start; + int size = regs[region_id].end + 1 - start; + + if(region_id == 0) + { + start += rom_segment << 20; + size = 1 << 20; + } + + /* Make sure the size is *even* */ + size &= ~1; + + uint16_t file[30]; + char file_u8[30] = "\\\\fls0\\"; + + filename(file_u8 + 7, region_id, rom_segment); + for(int i = 0; i < 30; i++) file[i] = file_u8[i]; + + BFile_Remove(file); + BFile_Create(file, BFile_File, &size); + + int fd = BFile_Open(file, BFile_WriteOnly); + BFile_Write(fd, (void *)start, size); + BFile_Close(fd); +} +#endif + +/* gintctl_gint_dump(): Dump memory to filesystem */ +void gintctl_gint_dump(void) +{ + int region_id=0, rom_segment=0; + char output_file[20]; + + int key = 0; + while(key != KEY_EXIT) + { + filename(output_file, region_id, rom_segment); + + dclear(C_WHITE); + + #ifdef FX9860G + row_print(1, 1, "Memory dump"); + + row_print(3, 1, "Region: %s", regs[region_id].name); + if(region_id == 0) + row_print(4, 1, "Segment: %d", rom_segment); + row_print(5, 1, "File: %s", output_file); + + extern image_t img_opt_dump; + dimage(0, 56, &img_opt_dump); + #endif + + #ifdef FXCG50 + row_title("Memory dump to filesystem"); + + fkey_button(1, "ROM"); + fkey_button(2, "RAM"); + fkey_button(3, "RS"); +// fkey_action(6, "DUMP"); + #endif + + dupdate(); + + key = getkey().key; + if(key == KEY_F1) + { + if(region_id == 0) rom_segment = (rom_segment + 1) % 8; + region_id = 0; + } + if(key == KEY_F2) region_id = 1; + if(key == KEY_F3) region_id = 2; + + #ifdef FX9860G + if(key == KEY_F6) dump(region_id, rom_segment); + #endif + } +} diff --git a/src/gint/hardware.c b/src/gint/hardware.c index c39ad37..d91cda3 100644 --- a/src/gint/hardware.c +++ b/src/gint/hardware.c @@ -84,12 +84,14 @@ static void hw_cpg(int *row) /* Direct Memory Access Controller */ static void hw_dma(int *row) { + #ifdef FXCG50 int dma = gint[HWDMA]; put("Direct Memory Access" _(," Controller:")); load_barrier(dma); put(" (loaded)"); + #endif } /* Timer Unit */ @@ -197,8 +199,10 @@ static int display_data(int offset) hw_cpg(row); put(""); + #ifdef FXCG50 hw_dma(row); put(""); + #endif hw_tmu(row); hw_etmu(row); diff --git a/src/gint/printf.c b/src/gint/printf.c new file mode 100644 index 0000000..cb7affb --- /dev/null +++ b/src/gint/printf.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include + +#include +#include + +static int passed = 0; +static int total = 0; + +static struct { + char const *format; + char const *expected; +} fails[10]; + +static void check(char const *expected, char const *format, ...) +{ + va_list args; + va_start(args, format); + + char buffer[128]; + vsnprintf(buffer, 128, format, args); + + va_end(args); + + total++; + + if(!strcmp(buffer, expected)) + { + passed++; + } + else if(total - passed <= 10) + { + fails[total - passed - 1].format = format; + fails[total - passed - 1].expected = expected; + } +} + +static void check_all(void) +{ + passed = 0; + total = 0; + + /* Base cases with length and precision */ + check("-849", "%d", -849); + check(" 78372", "%7i", 78372); + check("65536", "%3d", 65536); + check(" 0017", "%6.4d", 17); + check(" -1876", "%6.3d", -1876); + + /* Sign */ + check("+15", "%+i", 15); + check(" 78372", "% 7i", 78372); + check(" 65536", "% d", 65536); + + /* Alignment */ + check("0017 ", "%-6.4d", 17); + check("+0017 ", "%-+6.4i", 17); + + /* Bases */ + check("3255", "%d", 0xcb7); + check("cb7", "%x", 0xcb7); + check("CB7", "%X", 0xcb7); + check("6267", "%o", 0xcb7); + + /* Argument size */ + check("10000000000", "%lld", 10000000000ll); + check("123456789ab", "%llx", 0x123456789abull); + + /* Alternative prefixes */ + check("0x7b", "%#x", 0x7b); + check("0X7B", "%#X", 0x7b); + check("0377", "%#o", 255); + + /* Pointers */ + check("0xa44b0000", "%p", (void *)0xa44b0000); + + /* Characters and strings */ + check("HellWrld!", "%s", "HellWrld!"); + check("Hello ", "%-8.5s", "Hello, World!"); + check("d", "%c", 100); + check(" #", "%6c", '#'); +} + +/* gintctl_gint_printf(): printf() function */ +void gintctl_gint_printf(void) +{ + int key = 0; + while(key != KEY_EXIT) + { + dclear(C_WHITE); + + #ifdef FX9860G + row_print(1, 1, "printf() tests"); + row_print(3, 1, "passed: %d/%d", passed, total); + #endif + + #ifdef FXCG50 + row_title("Unit tests for the printf() family"); + + row_print(1, 1, "Passed: %d/%d", passed, total); + + for(int i = 0; i < 10 && i <= total - passed - 1; i++) + { + int y = 22 + 14 * (i + 2); + dtext(6, y, fails[i].format, C_BLACK, C_NONE); + dtext(86, y, fails[i].expected, C_BLACK, C_NONE); + } + + fkey_button(1, "RUN"); + #endif + + dupdate(); + + key = getkey().key; + if(key == KEY_F1) check_all(); + } +} diff --git a/src/gint/ram.c b/src/gint/ram.c new file mode 100644 index 0000000..bde689b --- /dev/null +++ b/src/gint/ram.c @@ -0,0 +1,128 @@ +#include +#include +#include + +#include +#include + +static int writable(uint8_t volatile *mem) +{ + int save = *mem; + *mem = save ^ 0xff; + + /* Read the written value and restore the pointed byte */ + int measured = *mem; + *mem = save; + + /* The address is writable iff we succeeded in storing ~save */ + return (measured == (save ^ 0xff)); +} + +static int same_location(uint8_t volatile *m1, uint8_t volatile *m2) +{ + uint8_t s1=*m1, s2=*m2; + + *m1 = s1 ^ 0xf0; + int equal1 = (*m2 == *m1); + + *m1 = s1 ^ 0x0f; + int equal2 = (*m2 == *m1); + + *m1 = s1 ^ 0xff; + int equal3 = (*m2 == *m1); + + *m1 = s1; + *m2 = s2; + + return equal1 && equal2 && equal3; +} + +static uint32_t region_size(uint8_t volatile *mem, int *reason) +{ + uint32_t size = 0; + + while(size <= 16384) + { + if(!writable(mem+size)) + { + *reason = 1; + break; + } + if(size > 0 && same_location(mem, mem+size)) + { + *reason = 2; + break; + } + size++; + } + + return size; +} + +/* gintctl_gint_ram(): Determine the size of some memory areas */ +void gintctl_gint_ram(void) +{ + uint8_t *ILRAM = (void *)0xe5200000; + uint8_t *XRAM = (void *)0xe5007000; + uint8_t *YRAM = (void *)0xe5017000; + uint8_t *MERAM = (void *)0xe8080000; + + /* Size of these sections */ + uint32_t IL=0, X=0, Y=0, ME=0; + /* Reason why the region stops (1=not writable, 2=wraps around) */ + int ILr=0, Xr=0, Yr=0, MEr=0; + + GUNUSED char const *reasons[] = { + "Not tested yet", + "Not writable past %d bytes", + "Wraps around after %d bytes", + }; + + int key = 0; + while(key != KEY_EXIT) + { + dclear(C_WHITE); + + #ifdef FX9860G + row_print(1, 1, "On-chip memory"); + + row_print(3, 2, "ILRAM: %d bytes", IL); + row_print(4, 2, "XRAM: %d bytes", X); + row_print(5, 2, "YRAM: %d bytes", Y); + row_print(6, 2, "MERAM: %d bytes", ME); + + extern image_t img_opt_gint_ram; + dimage(0, 56, &img_opt_gint_ram); + #endif + + #ifdef FXCG50 + row_title("On-chip memory discovery"); + + row_print(1, 1, "This program measures the size of on-chip"); + row_print(2, 1, "memory sections by checking how far it can " + "write."); + + dprint(6, 78, C_BLACK, C_NONE, "ILRAM:"); + dprint(6, 92, C_BLACK, C_NONE, "XRAM:"); + dprint(6, 106, C_BLACK, C_NONE, "YRAM:"); + dprint(6, 120, C_BLACK, C_NONE, "MERAM:"); + dprint(61, 78, C_BLACK, C_NONE, reasons[ILr], IL); + dprint(61, 92, C_BLACK, C_NONE, reasons[Xr], X); + dprint(61, 106, C_BLACK, C_NONE, reasons[Yr], Y); + dprint(61, 120, C_BLACK, C_NONE, reasons[MEr], ME); + + fkey_button(1, "ILRAM"); + fkey_button(2, "XRAM"); + fkey_button(3, "YRAM"); + fkey_button(4, "MERAM"); + #endif + + dupdate(); + + key = getkey().key; + if(key == KEY_F1) IL = region_size(ILRAM, &ILr); + if(key == KEY_F2) X = region_size(XRAM, &Xr); + if(key == KEY_F3) Y = region_size(YRAM, &Yr); + if(key == KEY_F4) ME = region_size(MERAM, &MEr); + } +} diff --git a/src/gintctl.c b/src/gintctl.c index 8e9f9bb..8a7e098 100644 --- a/src/gintctl.c +++ b/src/gintctl.c @@ -35,9 +35,13 @@ struct menu menu_gint = { _("gint tests", "gint features and driver tests"), .entries = { { "Hardware", gintctl_gint_hardware }, - { "Boot log", NULL }, + { "RAM discovery", gintctl_gint_ram }, + { "Memory dump", gintctl_gint_dump }, { "Keyboard", NULL }, { "Timers", gintctl_gint_timer }, + #ifdef FXCG50 + { "DMA Control", gintctl_gint_dma }, + #endif { "Real-time clock", NULL }, { "Image rendering", gintctl_gint_bopti }, { "Text rendering", NULL }, @@ -45,6 +49,7 @@ struct menu menu_gint = { { "Gray engine", gintctl_gint_gray }, { "Gray rendering", gintctl_gint_grayrender }, #endif + { "printf family", gintctl_gint_printf }, { NULL, NULL }, }}; @@ -57,57 +62,6 @@ struct menu menu_perf = { { NULL, NULL }, }}; -void exch_debug_thing(__attribute__((unused)) int code) -{ - #ifdef FXCG50 - - uint32_t TEA = *((volatile uint32_t *)0xff00000c); - uint32_t TRA = *((volatile uint32_t *)0xff000020); - uint32_t PC; - - __asm__("stc spc, %0" : "=r"(PC)); - TRA = TRA >> 2; - - dclear(C_WHITE); - - print(6, 3, "An exception occured! (System ERROR)"); - - uint32_t *long_vram = (void *)vram; - for(int i = 0; i < 198 * 16; i++) long_vram[i] = ~long_vram[i]; - - char const *name = ""; - if(code == 0x040) name = "TLB miss (nonexisting address) on read"; - if(code == 0x060) name = "TLB miss (nonexisting address) on write"; - if(code == 0x0e0) name = "Read address error (probably alignment)"; - if(code == 0x100) name = "Write address error (probably alignment)"; - if(code == 0x160) name = "Unconditional trap"; - if(code == 0x180) name = "Illegal instruction"; - if(code == 0x1a0) name = "Illegal delay slot instruction"; - - print(6, 25, "%03x %s", code, name); - - print(6, 45, "PC"); - print(38, 45, "= %08x", PC); - print(261, 45, "(Error location)"); - - print(6, 60, "TEA"); - print(38, 60, "= %08x", TEA); - print(234, 60, "(Offending address)"); - - print(6, 75, "TRA"); - print(38, 75, "= %#x", TRA); - print(281, 75, "(Trap number)"); - - print(6, 95, "An unrecoverable error ocurred in the add-in."); - print(6, 108, "Please press the RESET button to restart the"); - print(6, 121, "calculator."); - - dupdate_noint(); - #endif - - while(1); -} - //--- // Main application //--- diff --git a/src/mem/mem.c b/src/mem/mem.c index c4624a9..5b2db95 100644 --- a/src/mem/mem.c +++ b/src/mem/mem.c @@ -1,27 +1,87 @@ #include #include #include +#include #include #include -int c(int c) +/* Code of exception that occurs during a memory access */ +static uint32_t exception = 0; +/* Exception-catching function */ +static int catch_exc(uint32_t code) { - return (c >= 0x20 && c < 0x7f) ? c : '.'; + if(code == 0x040 || code == 0x0e0) + { + exception = code; + gint_exc_skip(1); + return 0; + } + return 1; +} + +int line(uint8_t *mem, char *header, char *bytes, char *ascii, int n) +{ + /* First do a naive access to the first byte, and record possible + exceptions - TLB miss read and CPU read error. + I use a volatile asm statement so that the read can't be optimized + away by the compiler. */ + exception = 0; + gint_exc_catch(catch_exc); + uint8_t z; + __asm__ volatile( + "mov.l %1, %0" + : "=r"(z) + : "m"(*mem)); + gint_exc_catch(NULL); + + sprintf(header, "%08X:", (uint32_t)mem); + + if(exception == 0x040) + { + sprintf(bytes, "TLB error"); + *ascii = 0; + return 1; + } + if(exception == 0x0e0) + { + sprintf(bytes, "Read error"); + *ascii = 0; + return 1; + } + + for(int k = 0; k < n; k++) + { + int c = mem[k]; + ascii[k] = (c >= 0x20 && c < 0x7f) ? c : '.'; + } + ascii[n] = 0; + + for(int k = 0; 2 * k < n; k++) + { + sprintf(bytes + 5 * k, "%02X%02X ", mem[2*k], mem[2*k+1]); + } + return 0; } /* gintctl_mem(): Memory browser */ void gintctl_mem(void) { - uint32_t base = 0x88010758; - int key = 0, ascii = 0; + uint32_t base = 0x88000000; + int key = 0; #ifdef FX9860G extern font_t font_hexa; font_t const *old_font = dfont(&font_hexa); + int view_ascii = 0; + #endif char header[12]; - char bytes[24]; + char bytes[48]; + char ascii[24]; + + int size = 8; + int lines = _(9,14); while(key != KEY_EXIT) { @@ -30,48 +90,67 @@ void gintctl_mem(void) uint32_t addr = base; uint8_t *mem = (void *)addr; - for(int i = 0; i <= 8; i++) + for(int i = 0; i < lines; i++) { - if(!ascii) + int status = line(mem, header, bytes, ascii, size); + + #ifdef FX9860G + dtext( 5, 6*i + 1, view_ascii ? ascii : header, + C_BLACK, C_NONE); + dtext(45, 6*i + 1, bytes, C_BLACK, C_NONE); + #endif + + #ifdef FXCG50 + dtext(25, 26 + 12*i, header, C_BLACK, C_NONE); + dtext(110, 26 + 12*i, bytes, status ? C_RED : C_BLACK, + C_NONE); + + for(int k = size - 1; k >= 0; k--) { - sprintf(header, "%08X:", addr); - } - else - { - for(int k = 0; k < 8; k++) - header[k] = c(mem[k]); - header[8] = 0; + ascii[k+1] = 0; + dtext(275 + 9*k, 26 + 12*i, ascii + k, C_BLACK, + C_NONE); } + #endif - sprintf(bytes, "%02X%02X %02X%02X %02X%02X %02X%02X", - mem[0], mem[1], mem[2], mem[3], - mem[4], mem[5], mem[6], mem[7] - ); - - dtext( 5, 6 * i + 1, header, C_BLACK, C_NONE); - dtext(45, 6 * i + 1, bytes, C_BLACK, C_NONE); - - mem += 8; - addr += 8; + mem += size; + addr += size; } + #ifdef FX9860G extern image_t img_opt_mem; dsubimage(0, 56, &img_opt_mem, 0, 0, 128, 8, DIMAGE_NONE); - if(ascii) - { - dsubimage(107, 56, &img_opt_mem, 107, 9, 21, 8, DIMAGE_NONE); - } + if(view_ascii) dsubimage(23, 56, &img_opt_mem, 23, 9, 21, 8, + DIMAGE_NONE); + #endif + + #ifdef FXCG50 + row_title("Memory browser"); + fkey_button(1, "JUMP"); + fkey_action(3, "ROM"); + fkey_action(4, "RAM"); + fkey_action(5, "ILRAM"); + fkey_action(6, "ADDIN"); + #endif dupdate(); key = getkey().key; - if(key == KEY_UP) base -= 72; - if(key == KEY_DOWN) base += 72; + if(key == KEY_UP) base -= size * lines; + if(key == KEY_DOWN) base += size * lines; - if(key == KEY_F6) ascii = !ascii; + #ifdef FX9860G + if(key == KEY_F2) view_ascii = !view_ascii; + #endif + + if(key == KEY_F3) base = 0x80000000; + if(key == KEY_F4) base = 0x88000000; + if(key == KEY_F5) base = 0xe5200000; + if(key == KEY_F6) base = 0x00300000; } + #ifdef FX9860G dfont(old_font); #endif } diff --git a/src/perf/render.c b/src/perf/render.c index 4183314..7cf8c55 100644 --- a/src/perf/render.c +++ b/src/perf/render.c @@ -12,34 +12,43 @@ struct elapsed { uint32_t clear; uint32_t update; uint32_t rect1, rect2, rect3; + uint32_t fs_r5g6b5; }; static void run_test(struct elapsed *time) { - #define test(ctx, out, command) { \ - prof_clear(ctx); \ - prof_enter(ctx); \ + #define test(out, command) { \ + prof_clear(PROFCTX_RENDER); \ + prof_enter(PROFCTX_RENDER); \ command; \ - prof_leave(ctx); \ - out = prof_time(ctx); \ + prof_leave(PROFCTX_RENDER); \ + out = prof_time(PROFCTX_RENDER); \ } - test(PROFCTX_DUPDATE, time->update, + extern image_t img_swift; + + test(time->update, dupdate() ); - test(PROFCTX_DCLEAR, time->clear, + test(time->clear, dclear(C_WHITE) ); - test(PROFCTX_DRECT1, time->rect1, + test(time->rect1, drect(0, 0, 31, 31, C_WHITE) ); - test(PROFCTX_DRECT2, time->rect2, + test(time->rect2, drect(1, 1, 32, 32, C_WHITE) ); - test(PROFCTX_DRECT3, time->rect3, + test(time->rect3, drect(0, 0, _(127,395), _(63,223), C_WHITE) ); + #ifdef FXCG50 + test(time->fs_r5g6b5, + dimage(0, 0, &img_swift) + ); + #endif + #undef test } @@ -102,6 +111,9 @@ void gintctl_perf_render(void) print(314, 90, "rect3:"); print(314, 105, "%s", printtime(time.rect3)); + + print(6, 130, "fullscreen img:"); + print(6, 145, "%s", printtime(time.fs_r5g6b5)); } fkey_button(1, "START"); diff --git a/src/regs/regs.c b/src/regs/regs.c index 19b7945..48feb89 100644 --- a/src/regs/regs.c +++ b/src/regs/regs.c @@ -40,4 +40,14 @@ void gintctl_regs(void) dupdate(); getkey(); + + dclear(C_WHITE); + row_title("Register browser"); + + row_print(2, 1, "RAMCR: %08x", *(uint32_t *)0xff000074); + row_print(3, 1, "SAR0: %08x", *(uint32_t *)0xfe008020); + row_print(4, 1, "CHCR0: %08x", *(uint32_t *)0xfe00802c); + + dupdate(); + getkey(); } diff --git a/src/util.c b/src/util.c index 01080be..0b6ce8d 100644 --- a/src/util.c +++ b/src/util.c @@ -1,4 +1,3 @@ -#define GINT_NEED_VRAM #include #include @@ -46,7 +45,7 @@ void row_title(char const *format, ...) #ifdef FXCG50 dtext(ROW_X, 3, str, C_BLACK, C_NONE); - uint32_t *long_vram = (void *)vram; + uint32_t *long_vram = (void *)gint_vram; for(int i = 0; i < 198 * 16; i++) long_vram[i] = ~long_vram[i]; #endif } @@ -74,7 +73,7 @@ void row_highlight(int row) #endif #ifdef FXCG50 - uint32_t *long_vram = (void *)vram; + uint32_t *long_vram = (void *)gint_vram; for(int i = 198 * y1; i < 198 * y2; i++) long_vram[i] = ~long_vram[i]; #endif }