some gint and performance tests
This commit is contained in:
parent
92fd107478
commit
f56201af6c
29
Makefile
29
Makefile
|
@ -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
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
131
main.c
|
@ -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;
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 770 B |
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
|
@ -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++;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
194
src/gintctl.c
194
src/gintctl.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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++;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 */
|
Loading…
Reference in New Issue