some gint and performance tests

This commit is contained in:
Lephe 2019-07-17 12:59:17 -04:00
parent 92fd107478
commit f56201af6c
16 changed files with 1184 additions and 118 deletions

View File

@ -8,13 +8,13 @@
# Compiler flags
cf := -mb -ffreestanding -nostdlib -Wall -Wextra -std=c11 -Os \
-fstrict-volatile-bitfields
-fstrict-volatile-bitfields -I include
cf-fx := $(cf) -m3 -DFX9860G
cf-cg := $(cf) -m4-nofpu -DFXCG50
# Linker flags
lf-fx := -Tfx9860g.ld -lgint-fx -lgcc -Wl,-Map=build.fx/map
lf-cg := -Tfxcg50.ld -lgint-cg -lgcc -Wl,-Map=build.cg/map -L. -lfxcg
lf-fx := -Tfx9860g.ld -lprof -lgint-fx -lgcc -Wl,-Map=build.fx/map
lf-cg := -Tfxcg50.ld -lprof -lgint-cg -lgcc -Wl,-Map=build.cg/map -L. -lfxcg
dflags = -MMD -MT $@ -MF $(@:.o=.d) -MP
cpflags := -R .bss -R .gint_bss
@ -32,8 +32,8 @@ target-fx := gintctl.g1a
target-cg := gintctl.g3a
# Source and object files
src := $(wildcard *.c)
res := $(wildcard resources/*)
src := $(shell find src -name '*.c')
res := $(wildcard resources/*.png)
obj-fx := $(src:%.c=build.fx/%.o) $(res:resources/%=build.fx/%.o)
obj-cg := $(src:%.c=build.cg/%.o) $(res:resources/%=build.cg/%.o)
@ -63,21 +63,22 @@ $(target-cg): $(obj-cg) $(deps-cg)
mkg3a $(g3af) $(bin) $@
# C sources
build.fx/%.o: %.c | build.fx/
build.fx/%.o: %.c
@ mkdir -p $(dir $@)
sh3eb-elf-gcc -c $< -o $@ $(cf-fx) $(dflags)
build.cg/%.o: %.c | build.cg/
build.cg/%.o: %.c
@ mkdir -p $(dir $@)
sh4eb-elf-gcc -c $< -o $@ $(cf-cg) $(dflags)
# Images
build.fx/%.png.o: resources/%.png | build.fx/
build.fx/%.png.o: resources/%.png
@ mkdir -p $(dir $@)
fxconv -i $< -o $@ name:$*
build.cg/%.png.o: resources/%.png | build.cg/
build.cg/%.png.o: resources/%.png
@ echo -e "\e[31;1mWARNING: conversion for fxcg50 not supported yet\e[0m"
@ mkdir -p $(dir $@)
fxconv -i $< -o $@ name:$*
%/:
@ mkdir -p $@
#
# Cleaning and utilities
#
@ -96,8 +97,8 @@ distclean: clean
install-fx: $(target-fx)
p7 send -f $<
install-cg: $(target-cg)
@ while [[ ! -h /dev/Prizm1 ]]; do sleep 1; done
@ mount /dev/Prizm1
@ while [[ ! -h /dev/Prizm1 ]]; do sleep 0.25; done
@ while ! mount /dev/Prizm1; do sleep 0.25; done
@ rm -f /mnt/prizm/$<
@ cp $< /mnt/prizm
@ umount /dev/Prizm1

14
include/gintctl/gint.h Normal file
View File

@ -0,0 +1,14 @@
//---
// gintctl:gint - gint feature tests
//---
#ifndef GINTCTL_GINT
#define GINTCTL_GINT
/* gintctl_gint_hardware(): Detected hardware configuration */
void gintctl_gint_hardware(void);
/* gintctl_gint_timer(): Show the timer status in real-time */
void gintctl_gint_timer(void);
#endif /* GINTCTL_GINT */

45
include/gintctl/menu.h Normal file
View File

@ -0,0 +1,45 @@
//---
// gintctl:menu - Interactive list menus
//---
#ifndef GINTCTL_MENU
#define GINTCTL_MENU
#include <stddef.h>
#include <gint/keycodes.h>
/* struct menuentry: Selectable list element */
struct menuentry {
char const *name;
void (*function)(void);
};
struct menu {
char const *name;
int len;
int offset;
int pos;
int visible;
struct menuentry entries[];
};
/* menu_init(): Initialize a menu list
@menu Any list menu, even unitialized
@visible Number of lines that can be shown simultaneously */
void menu_init(struct menu *menu, int visible);
/* menu_move(): Move the cursor in a menu
@menu Initialized list menu
@key Either KEY_UP, indicating up, or KEY_DOWN indicating down
@wrap Allow wrap-around */
void menu_move(struct menu *menu, int key, int wrap);
/* menu_show(): Render a list menu */
void menu_show(struct menu const *menu);
/* menu_exec(): Execute the currently-selected function of a menu */
void menu_exec(struct menu const *menu);
#endif /* GINTCTL_MENU */

14
include/gintctl/perf.h Normal file
View File

@ -0,0 +1,14 @@
//---
// gintctl:perf - Performance and benchmarks
//---
#ifndef GINTCTL_PERF
#define GINTCTL_PERF
/* gintctl_perf_libprof(): Basic libprof tests using timers */
void gintctl_perf_libprof(void);
/* gintctl_perf_render(): Profile the display primitives */
void gintctl_perf_render(void);
#endif /* GINTCTL_PERF */

View File

@ -0,0 +1,24 @@
//---
// gintctl:prof-contexts - All contexts under which profiling is used
//---
#ifndef GINTCTL_PROF_CONTEXTS
#define GINTCTL_PROF_CONTEXTS
/* libprof requires its user to declare the number of execution contexts that
are being profiled. The number and IDs is maintained here */
enum {
PROFCTX_BASICS = 0,
PROFCTX_DCLEAR,
PROFCTX_DUPDATE,
PROFCTX_DRECT1,
PROFCTX_DRECT2,
PROFCTX_DRECT3,
/* Last element and bound checker */
PROFCTX_COUNT,
};
#endif /* GINTCTL_PROF_CONTEXTS */

68
include/gintctl/util.h Normal file
View File

@ -0,0 +1,68 @@
//---
// gintctl:util - Utility functions
//---
#ifndef GINTCTL_UTIL
#define GINTCTL_UTIL
#include <stdarg.h>
//---
// Platform disambiguation functions
//---
#ifdef FX9860G
#define _(fx,cg) fx
#endif
#ifdef FXCG50
#define _(fx,cg) cg
#endif
//---
// Row manipulation functions
//---
/* row_title(): Render the main title */
void row_title(char const *format, ...);
/* row_print(): Formatted printing in a predefined row */
void row_print(int row, int x, char const *format, ...);
/* row_highlight(): Invert a row's pixels to highlight it */
void row_highlight(int row);
/* row_right(): Print at the last column of a row */
void row_right(int row, char const *character);
/* scrollbar(): Show a scrollbar */
void scrollbar(int offset, int length);
/* row_count(): Number of rows available to row_print() */
int row_count(void);
//---
// General (x,y) printing
//---
/* print(): Formatted printing shorthand */
void print(int x, int y, char const *format, ...);
//---
// F-key rendering
//---
#ifdef FXCG50
/* fkey_action(): A black-on-white F-key */
void fkey_action(int position, char const *text);
/* fkey_button(): A rectangular F-key */
void fkey_button(int position, char const *text);
/* fkey_menu(): A rectangular F-key with the bottom right corner removed */
void fkey_menu(int position, char const *text);
#endif /* FXCG50 */
#endif /* GINTCTL_UTIL */

131
main.c
View File

@ -18,27 +18,6 @@ extern void Bdisp_AllClr_VRAM();
#define color_white 0xffff
#endif
/* print() - formatted printing shorthand */
static void print(int x, int y, const char *format, ...)
{
char str[45];
va_list args;
va_start(args, format);
vsprintf(str + 2, format, args);
#ifdef FX9860G
dtext(6 * (x - 1) + 1, 7 * (y - 1), str + 2, color_black, color_white);
#endif
#ifdef FXCG50
PrintXY(x, y, str, 0, 0);
#endif
va_end(args);
}
void print_bin(int x, int y, uint32_t bin, int digits)
{
char str[33];
@ -53,66 +32,7 @@ void print_bin(int x, int y, uint32_t bin, int digits)
print(x, y, str);
}
void debug(uint32_t event_code)
{
print(1, 6, "%8x", event_code);
dupdate();
}
void debug_exc(uint32_t event_code)
{
uint32_t spc;
__asm__("stc spc, %0": "=r"(spc));
print(1, 1, "EXCEPTION==%8x==", event_code);
print(1, 2, "SPC=%8x=========", spc);
if(isSH4())
{
volatile uint32_t *TEA = (void *)0xff00000c;
print(1, 3, "TEA=%8x=========", *TEA);
}
dupdate();
}
#if 0
volatile int delay_one_ended = 0;
int stop(__attribute__((unused)) void *arg)
{
delay_one_ended = 1;
return 1;
}
void delay_one(void)
{
int delay_us = 50000;
static int tid = 1;
/* if(tid == (isSH3() ? 3 : 7)) tid = (tid + 1) % timer_count();
delay_one_ended = 0;
timer_setup(tid, timer_delay(tid,delay_us), timer_default, stop, NULL);
timer_start(tid);
while(!delay_one_ended) __asm__("sleep");
timer_free(tid); */
// tid = (tid + 1) % timer_count();
}
void delay(int k)
{
for(int i = k; i > 0; i--)
{
#ifdef FX9860G
Bdisp_ClearLineVRAM(127, 0, 127, 63);
Bdisp_DrawLineVRAM(127, 0, 127, (63 * i) / k);
Bdisp_PutDisp_DD();
#endif
delay_one();
}
}
#include <gint/timer.h>
int callback(void *arg)
{
volatile int *counter = arg;
@ -124,7 +44,7 @@ void test_clock(void)
{
const clock_frequency_t *freq = clock_freq();
Bdisp_AllClr_VRAM();
dclear(color_white);
print(1, 1, "FLL: %8d", freq->FLL);
print(1, 2, "PLL: %8d", freq->PLL);
@ -135,28 +55,27 @@ void test_clock(void)
print(1, 6, "Iphi = %10d", freq->Iphi_f);
print(1, 7, "Pphi = %10d", freq->Pphi_f);
Bdisp_PutDisp_DD();
delay(100);
dupdate();
getkey();
volatile unsigned int *FRQCRA = (void *)0xa4150000;
volatile unsigned int *FRQCRB = (void *)0xa4150004;
volatile unsigned int *PLLCR = (void *)0xa4150024;
volatile unsigned int *FLLFRQ = (void *)0xa4150050;
Bdisp_AllClr_VRAM();
dclear(color_white);
print(1, 1, "%8x", *FRQCRA);
print(1, 2, "%8x", *FRQCRB);
print(1, 3, "%8x", *PLLCR);
print(1, 4, "%8x", *FLLFRQ);
Bdisp_PutDisp_DD();
delay(100);
dupdate();
getkey();
}
void test_timer_simultaneous(void)
{
volatile int counters[9] = { 0 };
int count = timer_count();
Bdisp_AllClr_VRAM();
for(int tid = 0; tid < count; tid++)
{
@ -176,12 +95,12 @@ void test_timer_simultaneous(void)
for(int i = 0; i < limit; i++)
{
Bdisp_AllClr_VRAM();
dclear(color_white);
for(int k = 0; k < 9; k++)
print(2 * k + 1, 1, "%1x", counters[k]);
print(1, 8, "%4d", i);
Bdisp_PutDisp_DD();
dupdate();
}
for(int tid = 0; tid < count; tid++) timer_free(tid);
@ -204,7 +123,7 @@ void test_rtc_time(void)
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday",
};
Bdisp_AllClr_VRAM();
dclear(color_white);
rtc_get_time(&time);
print(1, 1, "%2d:%2d:%2d",
@ -214,7 +133,7 @@ void test_rtc_time(void)
days[time.week_day]);
print(1, 8, "%4d", i);
Bdisp_PutDisp_DD();
dupdate();
}
}
@ -581,13 +500,37 @@ void fx_frame2(void)
typedef void asm_text_t(uint32_t *v1, uint32_t *v2, uint32_t *op, int height);
extern asm_text_t *topti_asm_text[8];
static void show_bootlog(void)
{
extern char gint_bootlog[22*9];
int i = 0;
for(int y = 0; y < 9; y++)
{
for(int x = 0; x < 21; x++)
{
if(!gint_bootlog[i]) gint_bootlog[i] = ' ';
i++;
}
gint_bootlog[i] = 0;
i++;
}
dclear(color_white);
for(int y = 0; y < 9; y++)
print(1, y + 1, gint_bootlog + 22 * y);
dupdate();
getkey();
}
int main(GUNUSED int isappli, GUNUSED int optnum)
{
getkey();
#ifdef FX9860G
extern image_t pattern;
extern image_t pattern2;
// extern image_t pattern;
// extern image_t pattern2;
/* image_t *img = &pattern;

BIN
res-cg/opt_main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 770 B

BIN
resources/opt_main.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

239
src/gint/hardware.c Normal file
View File

@ -0,0 +1,239 @@
#include <gint/hardware.h>
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gintctl/gint.h>
#include <gintctl/util.h>
#define put(...) row_print(++(*row), 1, __VA_ARGS__)
#define load_barrier(x) { \
if(!((x) & HW_LOADED)) { \
put(" (not loaded)"); \
return; \
} \
}
/* MPU type and processor version */
static void hw_mpucpu(int *row)
{
char const *mpu_names[] = {
#ifdef FX9860G
"Unknown",
"SH-3 SH7337",
"SH-4A SH7305",
"SH-3 SH7355",
"SH-4A SH7724",
#else
"Unknown MPU product",
"SH-3-based SH7337",
"SH-4A-based SH7305",
"SH-3-based SH7355",
"SH-4A-based SH7724",
#endif
};
int mpu = gint[HWMPU];
put(_("MPU and CPU","MPU product and CPU features:"));
if(mpu < 0 || mpu > 4) put(" <MPUID %d>", mpu);
else put(" %s", mpu_names[mpu]);
if(!isSH4()) return;
put(_(" PVR"," Processor Version Register") ": %08x", gint[HWCPUVR]);
put(_(" PRR"," Product Register") ": %08x", gint[HWCPUPR]);
}
/* Memory */
static void hw_memory(int *row)
{
int mmu = gint[HWMMU];
int rom = gint[HWROM];
int ram = gint[HWRAM];
int uram = gint[HWURAM];
put("Memory and MMU" _(,":"));
load_barrier(mmu);
put(" ROM: %dM", rom >> 20);
#ifdef FX9860G
put(" RAM: %dk (%dk user)", ram >> 10, uram >> 10);
#else
put(" RAM: %dM (%dk mapped in userspace)", ram >> 20, uram >> 10);
#endif
if(mmu & HWMMU_UTLB) put(" TLB is unified");
if(mmu & HWMMU_FITTLB) put(
_(" Add-in fits in TLB"," Add-in is fully mapped in the TLB"));
}
/* Clock Pulse generator */
static void hw_cpg(int *row)
{
int cpg = gint[HWCPG];
put("Clock Pulse Generator" _(,":"));
load_barrier(cpg);
if(cpg & HWCPG_COMP) put(
_(" Input freq known"," Input clock frequency is known"));
if(cpg & HWCPG_EXT) put(
_(" CPG is extended"," SH7724-style extended module"));
}
/* Direct Memory Access Controller */
static void hw_dma(int *row)
{
int dma = gint[HWDMA];
put("Direct Memory Access" _(," Controller:"));
load_barrier(dma);
put(" (loaded)");
}
/* Timer Unit */
static void hw_tmu(int *row)
{
int tmu = gint[HWTMU];
put("Timer Unit" _(,":"));
load_barrier(tmu);
put(" (loaded)");
}
/* Extra Timer Unit */
static void hw_etmu(int *row)
{
int etmu = gint[HWETMU];
put("Extra Timer Unit" _(,":"));
load_barrier(etmu);
if(etmu & HWETMU_1)
{
put(" Extra timers: 1");
put(" Operational: %c", (etmu & HWETMU_OK0 ? 'y' : 'n'));
}
else if(etmu & HWETMU_6)
{
char operational[7] = { 0 };
for(int i = 0; i < 6; i++)
operational[i] = etmu & (1 << (i + 2)) ? 'y' : 'n';
put(" Extra timers: 6");
put(" Operational: %s", operational);
}
}
/* Real-Time Clock */
static void hw_rtc(int *row)
{
int rtc = gint[HWRTC];
put("Real-Time Clock" _(,":"), rtc);
load_barrier(rtc);
if(rtc & HWRTC_TIMER) put(" timer enabled");
}
/* Keyboard */
static void hw_keyboard(int *row)
{
int kbd = gint[HWKBD];
put("Keyboard" _(,":"), kbd);
load_barrier(kbd);
if(kbd & HWKBD_IO)
{
put(_(" I/O driven","Driven by I/O port scanning"));
put(kbd & HWKBD_WDD
? _(" Watchdog delay"," Watchdog timer I/O delays")
: _(" Active delay"," Active-waiting I/O delays"));
}
if(kbd & HWKBD_KSI)
{
put(_(" Key scan interface",
" Driven by SH7305-style key scan interface"));
}
put(_(" Scans at %dHz"," Scans keys at %dHz"), gint[HWKBDSF]);
}
/* Display driver */
static void hw_display(int *row)
{
int dd = gint[HWDD];
put("Display" _(,":"));
load_barrier(dd);
#ifdef FXCG50
if(dd & HWDD_KNOWN) put(" Known R61524-type model");
if(dd & HWDD_FULL) put(" Fullscreen mode enabled (no borders)");
#endif
#ifdef FX9860G
if(dd & HWDD_CONTRAST) put(" Contrast known");
#endif
if(dd & HWDD_LIGHT) put(_(" Backlight supported",
" Backlight configuration is enabled"));
}
static int display_data(int offset)
{
int row_value = -offset;
int *row = &row_value;
hw_mpucpu(row);
put("");
hw_memory(row);
put("");
hw_cpg(row);
put("");
hw_dma(row);
put("");
hw_tmu(row);
hw_etmu(row);
put("");
hw_rtc(row);
put("");
hw_keyboard(row);
put("");
hw_display(row);
return row_value + offset;
}
/* gintctl_hardware(): Show the hardware screen */
void gintctl_gint_hardware(void)
{
int offset = 0;
int max, key = 0;
while(key != KEY_EXIT)
{
dclear(C_WHITE);
row_title(_("Hardware", "Hardware and loaded drivers"));
max = display_data(offset);
scrollbar(offset, max);
dupdate();
key = getkey().key;
if(key == KEY_UP && offset > 0) offset--;
if(key == KEY_DOWN && max - offset > row_count()) offset++;
}
}

109
src/gint/timer.c Normal file
View File

@ -0,0 +1,109 @@
#include <gint/mpu/tmu.h>
#include <gint/std/stdio.h>
#include <gint/timer.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gintctl/util.h>
#include <gintctl/gint.h>
/* tmu_print(): Print a TMU's details */
void tmu_print(int x, int y, char const *name, tmu_t *tmu, int running)
{
int dx = _(27,45), dy = _(8,14);
print(x, y, "%s:", name);
if(!tmu)
{
print(x, y + dy, "(null)");
return;
}
print(x, y + dy, "TCOR");
print(x + dx, y + dy, "%08x", tmu->TCOR);
print(x, y + 2 * dy, "TCNT");
print(x + dx, y + 2 * dy, "%08x", tmu->TCNT);
print(x, y + 3 * dy, "%s%s%s",
tmu->TCR.UNIE ? "UNIE " : "",
tmu->TCR.UNF ? "UNF " : "",
running ? "TSTR " : ""
);
}
/* etmu_print(): Print an ETMU's details */
void etmu_print(int x, int y, char const *name, etmu_t *etmu)
{
int dx = _(27,45), dy = _(8,14);
print(x, y, "%s:", name);
if(!etmu)
{
print(x, y + dy, "(null)");
return;
}
print(x, y + dy, "TCOR");
print(x + dx, y + dy, "%08x", etmu->TCOR);
print(x, y + 2 * dy, "TCNT");
print(x + dx, y + 2 * dy, "%08x", etmu->TCNT);
print(x, y + 3 * dy, "%s%s%s",
etmu->TCR.UNIE ? "UNIE " : "",
etmu->TCR.UNF ? "UNF " : "",
etmu->TSTR ? "TSTR " : ""
);
}
/* gintctl_gint_timer(): Show the timer status in real-time */
void gintctl_gint_timer(void)
{
/* In this program we'll display the timer status at "full speed" and
hence ask getkey() to never wait. (The processor is still sleeping
during the DMA transfer to the screen on fxcg50, limiting the
program to ~90 FPS.) */
int key = 0, timeout = 1;
while(key != KEY_EXIT)
{
dclear(C_WHITE);
#ifdef FX9860G
#warning gintctl_gint_timer not implemented yet
#endif
#ifdef FXCG50
row_title("Timer status");
volatile uint8_t *TSTR;
timer_address(0, &TSTR);
tmu_print(6, 24, "TMU0", timer_address(0, NULL),*TSTR & 0x1);
tmu_print(138, 24, "TMU1", timer_address(1, NULL),*TSTR & 0x2);
tmu_print(270, 24, "TMU2", timer_address(2, NULL),*TSTR & 0x4);
etmu_print(6, 84, "ETMU0", timer_address(3, NULL));
etmu_print(138, 84, "ETMU1", timer_address(4, NULL));
etmu_print(270, 84, "ETMU2", timer_address(5, NULL));
etmu_print(6, 144, "ETMU3", timer_address(6, NULL));
etmu_print(138, 144, "ETMU4", timer_address(7, NULL));
etmu_print(270, 144, "ETMU5", timer_address(8, NULL));
fkey_button(1, "SLEEP");
#endif
dupdate();
key = getkey_opt(GETKEY_DEFAULT, &timeout).key;
/* On F1, pretend to sleep and just see what happens */
if(key == KEY_F1)
{
volatile int flag = 0;
int free = timer_setup(5, timer_delay(5, 1000000), 0,
timer_timeout, &flag);
if(free >= 0) timer_start(5);
}
}
}

View File

@ -1,4 +1,19 @@
#define GINT_NEED_VRAM
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/syscalls.h>
#include <gint/gint.h>
#include <gint/hardware.h>
#include <gintctl/util.h>
#include <gintctl/menu.h>
#include <gintctl/prof-contexts.h>
#include <gintctl/gint.h>
#include <gintctl/perf.h>
#include <libprof.h>
/* Drawing functions:
* ...
@ -8,16 +23,175 @@
* Do more in-depth things than previous application
* Stress testing for number of interrupts
* ...
Boot log:
* Displays boot log on full screen
* F1 for details (get live explanation and detect problems)
* F2 to save to file */
TODO:
* Add-in size and mappings
* Interrupt controller state?
* Clock frequencies
* F2 to save hardware data to file */
void locate(int x, int y, const char *str)
/* gint test menu */
struct menu menu_gint = {
_("gint tests", "gint features and driver tests"), .entries = {
{ "Hardware", gintctl_gint_hardware },
{ "Boot log", NULL },
{ "Keyboard", NULL },
{ "Timers", gintctl_gint_timer },
{ "Real-time clock", NULL },
{ "Image rendering", NULL },
{ "Text rendering", NULL },
#ifdef FX9860G
{ "Gray engine", NULL },
#endif
{ NULL, NULL },
}};
/* Performance menu */
struct menu menu_perf = {
_("Performance", "Performance benchmarks"), .entries = {
{ "libprof basics", gintctl_perf_libprof },
{ "Rendering primitives", gintctl_perf_render },
{ NULL, NULL },
}};
void exch_debug_thing(__attribute__((unused)) int code)
{
#ifdef FX9860G
dtext(6*(x-1), 7*(y-1), str);
#else
PrintXY(x, y, str - 2, 0, 0);
#endif
#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
//---
/* gintctl_main(): Show the main tab */
void gintctl_main(void)
{
#ifdef FX9860G
row_title("gint @%07x", GINT_VERSION);
row_print(2, 1, "F2:gint tests");
row_print(3, 1, "F3:MPU registers");
row_print(4, 1, "F4:Memory map/dump");
row_print(5, 1, "F5:Performance");
#endif /* FX9860G */
#ifdef FXCG50
row_title("gint @%07x for fx-CG 50", GINT_VERSION);
row_print(1, 1, "F2: gint features and driver tests");
row_print(2, 1, "F3: MPU register browser");
row_print(3, 1, "F4: Hexadecimal memory editor");
row_print(4, 1, "F5: Performance benchmarks");
#ifdef GINT_BOOTLOG
extern char gint_bootlog[22 * 8];
extern font_t *gint_default_font;
for(int i = 1; i < 8; i++) dtext(8, 85 + 13 * i, gint_bootlog + 22 * i,
C_BLACK, C_NONE);
#endif /* GINT_BOOTLOG */
#endif /* FXCG50 */
}
int main(GUNUSED int isappli, GUNUSED int optnum)
{
/* Initialize menu metadata */
menu_init(&menu_gint, row_count());
menu_init(&menu_perf, row_count());
/* Start the profiling library */
prof_init(PROFCTX_COUNT, 2);
int tab = 1, key = 0;
struct menu *menu = NULL;
while(key != KEY_EXIT)
{
dclear(C_WHITE);
if(tab == 1) gintctl_main();
else if(menu) menu_show(menu);
else row_title("Nothing, essentially");
#ifdef FX9860G
extern image_t opt_main;
dimage(0, 56, &opt_main);
#else
fkey_action(1, "INFO");
fkey_menu(2, "GINT");
fkey_menu(3, "REGS");
fkey_button(4, "MEMORY");
fkey_menu(5, "PERF");
#endif
dupdate();
key = getkey().key;
if(key == KEY_F1)
tab = 1, menu = NULL;
if(key == KEY_F2)
tab = 2, menu = &menu_gint;
if(key == KEY_F3)
tab = 3, menu = NULL;
if(key == KEY_F4)
/* TODO: Launch memory explorer */ { }
if(key == KEY_F5)
tab = 5, menu = &menu_perf;
if(!menu) continue;
if(key == KEY_UP || key == KEY_DOWN)
menu_move(menu, key, 0);
if(key == KEY_EXE)
menu_exec(menu);
}
prof_quit();
return 0;
}

76
src/menu.c Normal file
View File

@ -0,0 +1,76 @@
#include <gint/defs/util.h>
#include <gintctl/menu.h>
#include <gintctl/util.h>
/* menu_init(): Initialize a menu list */
void menu_init(struct menu *menu, int visible)
{
menu->len = 0;
while(menu->entries[menu->len].name) menu->len++;
menu->offset = 0;
menu->pos = 0;
menu->visible = visible;
}
/* menu_move(): Move the cursor in a menu */
void menu_move(struct menu *menu, int key, int wrap)
{
int max_offset = max(menu->len - menu->visible, 0);
if(key == KEY_UP && menu->pos > 0)
{
menu->pos--;
menu->offset = min(menu->offset, menu->pos);
}
else if(key == KEY_UP && !menu->pos && wrap)
{
menu->pos = menu->len - 1;
menu->offset = max_offset;
}
if(key == KEY_DOWN && menu->pos + 1 < menu->len)
{
menu->pos++;
if(menu->pos > menu->offset + menu->visible - 1
&& menu->offset + 1 < max_offset)
{
menu->offset++;
}
}
else if(key == KEY_DOWN && menu->pos + 1 == menu->len && wrap)
{
menu->pos = 0;
menu->offset = 0;
}
}
/* menu_show(): Render a list menu */
void menu_show(struct menu const *menu)
{
struct menuentry const *items = menu->entries;
int offset = menu->offset, pos = menu->pos;
int i = 0;
row_title(menu->name);
while(i+1 <= menu->visible && items[offset+i].name)
{
row_print(i+1, 2, items[offset+i].name);
i++;
}
if(offset > 0) row_right(1, "^");
if(items[offset+i].name) row_right(row_count(), "v");
int selected = pos - offset + 1;
if(selected >= 1 && selected <= menu->visible) row_highlight(selected);
}
/* menu_exec(): Execute the currently-selected function of a menu */
void menu_exec(struct menu const *menu)
{
void (*fun)(void) = menu->entries[menu->pos].function;
if(fun) fun();
}

69
src/perf/libprof.c Normal file
View File

@ -0,0 +1,69 @@
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gint/clock.h>
#include <gintctl/util.h>
#include <gintctl/prof-contexts.h>
#include <gintctl/perf.h>
#include <libprof.h>
/* Waits 1s and returns the libprof output in microseconds */
static uint32_t run_test(void)
{
int ctx = PROFCTX_BASICS;
prof_clear(ctx);
prof_enter(ctx);
static int delay = 100000;
sleep_us(1, delay);
prof_leave(ctx);
delay += 256;
return prof_time(ctx);
}
/* gintctl_perf_libprof(): Test the libprof implementation */
void gintctl_perf_libprof(void)
{
int key = 0, test = 0;
uint32_t elapsed = 0;
while(key != KEY_EXIT)
{
dclear(C_WHITE);
row_title("libprof basics");
#ifdef FX9860G
#warning gintctl_perf_libprof incomplete on fx9860g
row_print(2, 2, "Checks that libprof");
row_print(3, 2, "Press F1 to start.");
row_print(5, 2, "Delay: 1s");
if(test == 1) row_print(6, 2, "Elapsed: %8xus", elapsed);
#endif
#ifdef FXCG50
row_print(1, 1, "This program shows the execution time "
"measured");
row_print(2, 1, "by libprof for a 100 ms sleep, with 256us "
"added");
row_print(3, 1, "each time.");
row_print(5, 1, "Press F1 to start the test.");
if(test) row_print(7, 1, "Elapsed: %.1j ms (%#08x us)",
elapsed / 100, elapsed);
if(test) row_print(8, 1, "Tests: %d", test);
fkey_button(1, "START");
#endif
dupdate();
key = getkey().key;
if(key == KEY_F1) elapsed = run_test(), test++;
}
}

97
src/perf/render.c Normal file
View File

@ -0,0 +1,97 @@
#include <gint/keyboard.h>
#include <gint/display.h>
#include <gintctl/util.h>
#include <gintctl/prof-contexts.h>
#include <gintctl/perf.h>
#include <libprof.h>
struct elapsed {
uint32_t clear;
uint32_t update;
uint32_t rect1, rect2, rect3;
};
static void run_test(struct elapsed *time)
{
#define test(ctx, out, command) { \
prof_clear(ctx); \
prof_enter(ctx); \
command; \
prof_leave(ctx); \
out = prof_time(ctx); \
}
test(PROFCTX_DUPDATE, time->update,
dupdate()
);
test(PROFCTX_DCLEAR, time->clear,
dclear(C_WHITE)
);
test(PROFCTX_DRECT1, time->rect1,
drect(0, 0, 31, 31, C_WHITE)
);
test(PROFCTX_DRECT2, time->rect2,
drect(1, 1, 32, 32, C_WHITE)
);
test(PROFCTX_DRECT3, time->rect3,
drect(0, 0, 395, 223, C_WHITE)
);
#undef test
}
/* gintctl_perf_render(): Profile the display primitives */
void gintctl_perf_render(void)
{
int key = 0, test = 0;
struct elapsed time = {};
while(key != KEY_EXIT)
{
dclear(C_WHITE);
row_title("Rendering primitives");
#ifdef FX9860G
#warning gintctl_perf_render not implemented on fx9860g
#endif
#ifdef FXCG50
row_print(1, 1, "This program measures the execution time of");
row_print(2, 1, "common drawing functions.");
row_print(4, 1, "Press F1 to start the test.");
if(test)
{
print(6, 90, "dclear:");
print(6, 105, "%.1j ms", time.clear / 100);
print(6, 120, "%05x us", time.clear);
print(83, 90, "dupdate:");
print(83, 105, "%.1j ms", time.update / 100);
print(83, 120, "%05x us", time.update);
print(160, 90, "rect1:");
print(160, 105, "%.1j ms", time.rect1 / 100);
print(160, 120, "%05x us", time.rect1);
print(237, 90, "rect2:");
print(237, 105, "%.1j ms", time.rect2 / 100);
print(237, 120, "%05x us", time.rect2);
print(314, 90, "rect3:");
print(314, 105, "%.1j ms", time.rect3 / 100);
print(314, 120, "%05x us", time.rect3);
}
fkey_button(1, "START");
#endif
dupdate();
key = getkey().key;
if(key == KEY_F1) run_test(&time), test = 1;
}
}

193
src/util.c Normal file
View File

@ -0,0 +1,193 @@
#define GINT_NEED_VRAM
#include <gint/display.h>
#include <gint/std/stdio.h>
#include <gintctl/util.h>
/* Short-shorthand for calling out vsprintf() */
#define shortprint(str, format) { \
va_list _args; \
va_start(_args, format); \
vsprintf(str, format, _args); \
va_end(_args); \
}
//---
// Row manipulation functions
//---
#ifdef FX9860G
#define ROW_X 1
#define ROW_W 6
#define ROW_Y 8
#define ROW_YPAD 0
#define ROW_H 8
#define ROW_COUNT 6
#endif /* FX9860G */
#ifdef FXCG50
#define ROW_X 6
#define ROW_W 0
#define ROW_Y 20
#define ROW_YPAD 2
#define ROW_H 14
#define ROW_COUNT 14
#endif /* FXCG50 */
/* row_title(): Render the main title */
void row_title(char const *format, ...)
{
char str[80];
shortprint(str, format);
#ifdef FX9860G
dtext(1, 0, str, C_BLACK, C_NONE);
#endif
#ifdef FXCG50
dtext(ROW_X, 3, str, C_BLACK, C_NONE);
uint32_t *long_vram = (void *)vram;
for(int i = 0; i < 198 * 16; i++) long_vram[i] = ~long_vram[i];
#endif
}
/* row_print(): Formatted printing in a predefined row */
void row_print(int row, int x, char const *format, ...)
{
if(row < 1 || row > ROW_COUNT) return;
char str[80];
shortprint(str, format);
dtext(ROW_X + ROW_W * (x - 1), ROW_Y + ROW_H * (row - 1) + ROW_YPAD,
str, C_BLACK, C_NONE);
}
/* row_highlight(): Invert a row's pixels to highlight it */
void row_highlight(int row)
{
int y1 = ROW_Y + ROW_H * (row - 1);
int y2 = y1 + ROW_H;
#ifdef FX9860G
drect(0, y1, 127, y2 - 1, C_INVERT);
#endif
#ifdef FXCG50
uint32_t *long_vram = (void *)vram;
for(int i = 198 * y1; i < 198 * y2; i++) long_vram[i] = ~long_vram[i];
#endif
}
/* row_right(): Print at the last column of a row */
void row_right(int row, char const *character)
{
#ifdef FX9860G
row_print(row, 21, character);
#endif
#ifdef FXCG50
dtext(370, ROW_Y + ROW_H * (row - 1) + ROW_YPAD, character,
C_BLACK, C_NONE);
#endif
}
/* scrollbar(): Show a scrollbar */
void scrollbar(int offset, int length)
{
int area_x = _(127, 391);
int area_width = _(1, 2);
int area_top = ROW_Y;
int area_height = ROW_H * ROW_COUNT;
int bar_top = (offset * area_height) / length;
int bar_height = (ROW_COUNT * area_height) / length;
drect(area_x, area_top + bar_top, area_x + area_width - 1,
area_top + bar_top + bar_height, C_BLACK);
}
/* row_count(): Number of rows available to row_print() */
int row_count(void)
{
return ROW_COUNT;
}
//---
// General (x,y) printing
//---
/* print(): Formatted printing shorthand */
void print(int x, int y, char const *format, ...)
{
char str[80];
shortprint(str, format);
dtext(x, y, str, C_BLACK, C_NONE);
}
#ifdef FXCG50
/* printw(): Print in white */
void printw(int x, int y, char const *format, ...)
{
char str[80];
va_list args;
va_start(args, format);
vsprintf(str, format, args);
dtext(x, y, str, C_WHITE, C_NONE);
va_end(args);
}
/* fkey_action(): A black-on-white F-key */
void fkey_action(int position, char const *text)
{
int width;
dsize(text, NULL, &width, NULL);
int x = 4 + 65 * (position - 1);
int y = 207;
int w = 63;
dline(x + 1, y, x + w - 2, y, C_BLACK);
dline(x + 1, y + 14, x + w - 2, y + 14, C_BLACK);
drect(x, y + 1, x + 1, y + 13, C_BLACK);
drect(x + w - 2, y + 1, x + w - 1, y + 13, C_BLACK);
dtext(x + ((w - width) >> 1), y + 3, text, C_BLACK, C_NONE);
}
/* fkey_button(): A rectangular F-key */
void fkey_button(int position, char const *text)
{
int width;
dsize(text, NULL, &width, NULL);
int x = 4 + 65 * (position - 1);
int y = 207;
int w = 63;
dline(x + 1, y, x + w - 2, y, C_BLACK);
dline(x + 1, y + 14, x + w - 2, y + 14, C_BLACK);
drect(x, y + 1, x + w - 1, y + 13, C_BLACK);
dtext(x + ((w - width) >> 1), y + 3, text, C_WHITE, C_NONE);
}
/* fkey_menu(): A rectangular F-key with the bottom right corner removed */
void fkey_menu(int position, char const *text)
{
int x = 4 + 65 * (position - 1);
int y = 207;
int w = 63;
fkey_button(position, text);
dline(x + w - 1, y + 10, x + w - 5, y + 14, C_WHITE);
dline(x + w - 1, y + 11, x + w - 4, y + 14, C_WHITE);
dline(x + w - 1, y + 12, x + w - 3, y + 14, C_WHITE);
dline(x + w - 1, y + 13, x + w - 2, y + 14, C_WHITE);
}
#endif /* FXCG50 */