gintctl/src/gint/drivers.c

330 lines
9.1 KiB
C

#include <gint/gint.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/drivers.h>
#include <gint/drivers/states.h>
#include <gint/clock.h>
#include <gint/hardware.h>
#include <gint/mpu/tmu.h>
#include <gint/mpu/dma.h>
#include <gintctl/gint.h>
#include <gintctl/util.h>
#include <gintctl/assets.h>
#include <string.h>
//---
// Driver list and information
//---
static void draw_list(int offset, int maximum)
{
#ifdef FXCG50
row_print(1, 2, "Id");
row_print(1, 5, "Name");
row_print(1, 13, "Size");
row_print(1, 18, "Flags");
#endif
font_t const *old_font = dfont(_(&font_mini, dfont_default()));
for(int i=offset; i < (int)gint_driver_count() && i < offset+maximum; i++)
{
gint_driver_t *d = &gint_drivers[i];
uint8_t flags = gint_driver_flags[i];
int y = _(10+6*(i-offset), row_y(i-offset+2));
dprint(_( 2,row_x(2)), y, C_BLACK, "%d", i);
dprint(_(12,row_x(5)), y, C_BLACK, "%s", d->name);
dprint(_(36,row_x(13)), y, C_BLACK, "%d", d->state_size);
dprint(_(52,row_x(18)), y, C_BLACK, "%s%s%s",
(flags & GINT_DRV_CLEAN) ? "CLEAN " : "",
(flags & GINT_DRV_FOREIGN_POWERED) ? _("FP ","FOREIGN_POW. ") : "",
(flags & GINT_DRV_SHARED) ? "SHARED " : ""
);
}
dfont(old_font);
if((int)gint_driver_count() > maximum) scrollbar_px(_(8,50), _(55,200), 0,
gint_driver_count(), offset, maximum);
}
//---
// State management
//---
static void draw_state(gint_world_t world, int i)
{
font_t const *old_font = dfont(_(&font_mini, dfont_default()));
if(i > 0)
dprint(_(86,10), _(57,row_y(1)), C_BLACK, "<");
if(i < (int)gint_driver_count() - 1)
dprint(DWIDTH - _(4,16), _(57,row_y(1)), C_BLACK, ">");
dprint_opt(_(106, DWIDTH / 2), _(57, row_y(1)), C_BLACK, C_NONE,
DTEXT_CENTER, DTEXT_TOP, "%s", gint_drivers[i].name);
if(gint_driver_flags[i] & GINT_DRV_SHARED)
{
dprint_opt(DWIDTH / 2, DHEIGHT / 2, C_BLACK, C_NONE, DTEXT_CENTER,
DTEXT_MIDDLE, "Device is shared");
return;
}
if(world == gint_world_addin && (gint_driver_flags[i] & GINT_DRV_CLEAN))
{
dprint_opt(DWIDTH / 2, DHEIGHT / 2, C_BLACK, C_NONE, DTEXT_CENTER,
DTEXT_MIDDLE, "Device is clean");
return;
}
if(!strcmp(gint_drivers[i].name, "CPG"))
{
cpg_state_t const *s = world[i];
if(isSH3()) row_print(_(1,3), 1, "No state");
else row_print(_(1,3), 1, "SSCGCR: %08X", s->SSCGCR);
}
else if(!strcmp(gint_drivers[i].name, "CPU"))
{
cpu_state_t const *s = world[i];
row_print(_(1,3), 1, "SR: %08X", s->SR);
row_print(_(2,4), 1, "VBR: %08X", s->VBR);
row_print(_(3,5), 1, "CPUOPM: %08X", s->CPUOPM);
}
else if(!strcmp(gint_drivers[i].name, "DMA"))
{
dma_state_t const *s = world[i];
#ifdef FX9860G
for(int i = 0; i < 6; i++) {
dprint(1, 1+6*i, C_BLACK, "%d: %08X->%08X %08X",
i, s->ch[i].SAR, s->ch[i].DAR, s->ch[i].CHCR);
}
dprint(1, 43, C_BLACK, "OR: %08X", s->OR);
#endif
#ifdef FXCG50
for(int i = 0; i < 6; i++) {
int y=3+5*(i/3), x=1+16*(i%3);
row_print(y, x, "%d:", i);
row_print(y, x+2, "SAR");
row_print(y, x+7, "%08X", s->ch[i].SAR);
row_print(y+1, x+2, "DAR");
row_print(y+1, x+7, "%08X", s->ch[i].DAR);
row_print(y+2, x+2, "TCR");
row_print(y+2, x+7, "%08X", s->ch[i].TCR);
row_print(y+3, x+2, "CHCR");
row_print(y+3, x+7, "%08X", s->ch[i].CHCR);
}
row_print(13, 1, "OR: %08X\n", s->OR);
#endif
}
else if(!strcmp(gint_drivers[i].name, "INTC"))
{
intc_state_t const *s = world[i];
#ifdef FX9860G
for(int i = 0; i < 12; i++) {
dprint(1+32*(i%4),1+6*(i/4), C_BLACK, "%c:%04X", 'A'+i, s->IPR[i]);
}
for(int i = 0; i < 13; i++) {
dprint(1+32*(i%4),25+6*(i/4), C_BLACK, "%d:%02X", i, s->MSK[i]);
}
#endif
#ifdef FXCG50
for(int i = 0; i < 12; i++) {
row_print(3+i/4, 1+11*(i%4), "IPR%c:", 'A'+i);
row_print(3+i/4, 6+11*(i%4), "%04X", s->IPR[i]);
}
for(int i = 0; i < 13; i++) {
row_print(7+i/4, 1+11*(i%4), "IMR%d:", i);
row_print(7+i/4, 7+11*(i%4), "%02X", s->MSK[i]);
}
#endif
}
else if(!strcmp(gint_drivers[i].name, "KEYSC"))
{
row_print(_(1,3), 1, "No state");
}
else if(!strcmp(gint_drivers[i].name, "MMU"))
{
mmu_state_t const *s = world[i];
row_print(_(1,3), 1, "PASCR: %08X", s->PASCR);
row_print(_(2,4), 1, "IRMCR: %08X", s->IRMCR);
}
else if(!strcmp(gint_drivers[i].name, "R61524"))
{
r61524_state_t const *s = world[i];
row_print(3, 1, "HSA..HEA: %d..%d", s->HSA, s->HEA);
row_print(4, 1, "VSA..VEA: %d..%d", s->VSA, s->VEA);
}
else if(!strcmp(gint_drivers[i].name, "RTC"))
{
rtc_state_t const *s = world[i];
row_print(_(1,3), 1, "RCR1: %02X RCR2: %02X", s->RCR1, s->RCR2);
}
else if(!strcmp(gint_drivers[i].name, "SPU"))
{
spu_state_t const *s = world[i];
#ifdef FX9860G
dprint(1, 1, C_BLACK, "PBANKC0: %08X", s->PBANKC0);
dprint(1, 7, C_BLACK, "PBANKC1: %08X", s->PBANKC1);
dprint(1, 13, C_BLACK, "XBANKC0: %08X", s->XBANKC0);
dprint(1, 19, C_BLACK, "XBANKC1: %08X", s->XBANKC1);
#endif
#ifdef FXCG50
row_print(3,1, "PBANKC0: %08X PBANKC1: %08X", s->PBANKC0, s->PBANKC1);
row_print(4,1, "XBANKC0: %08X XBANKC1: %08X", s->XBANKC0, s->XBANKC1);
#endif
}
else if(!strcmp(gint_drivers[i].name, "T6K11"))
{
t6k11_state_t const *s = world[i];
dprint(1, 1, C_BLACK, "STRD: %02X", s->STRD);
dprint(1, 7, C_BLACK, "RESET:%d", (s->STRD & 0x08) != 0);
dprint(1, 13, C_BLACK, "N/F:%d", (s->STRD & 0x04) != 0);
dprint(1, 19, C_BLACK, "X/Y:%d", (s->STRD & 0x02) != 0);
dprint(1, 25, C_BLACK, "U/D:%d", (s->STRD & 0x01) != 0);
}
else if(!strcmp(gint_drivers[i].name, "TMU"))
{
tmu_state_t const *s = world[i];
for(int k = 0; k < 9; k++) {
#ifdef FX9860G
if(k < 3) dprint(1, 6*k, C_BLACK, "TMU%d: CNT:%08X TCR:%04X %s",
k, s->t[k].TCNT, s->t[k].TCR, (s->TSTR & (1<<k) ? "STR" : ""));
else dprint(1, 6*k, C_BLACK, "E%d: TCNT:%08X TCR:%02X TSTR:%02X",
k-3, s->t[k].TCNT, s->t[k].TCR, s->t[k].TSTR);
#endif
#ifdef FXCG50
row_print(k+3, 1, "%sTMU%d:", (k<3 ? "" : "E"), (k<3 ? k : k-3));
if(k < 3) row_print(k+3, 8, "%08X/%08X TCR:%04X",
s->t[k].TCNT, s->t[k].TCOR, s->t[k].TCR);
else row_print(k+3, 8,"%08X/%08X TCR:%02X TSTR:%02X",
s->t[k].TCNT, s->t[k].TCOR, s->t[k].TCR, s->t[k].TSTR);
#endif
}
}
else if(!strcmp(gint_drivers[i].name, "USB"))
{
row_print(_(1,3), 1, "In USB test");
}
dfont(old_font);
}
//---
// Manual switches with performance statistics
//---
struct switch_stats {
/* Number of empty world switches */
int world_switch_count;
/* Number of return-to-menu */
int return_to_menu_count;
/* TODO: Performance statistics for each driver */
};
static void draw_manual(struct switch_stats *stats)
{
#ifdef FX9860G
row_print(2, 1, "World switches: %d", stats->world_switch_count);
row_print(3, 1, "Return-to-menu: %d", stats->return_to_menu_count);
// row_print(4, 1, "Switch time: %d µs", stats->world_switch_time);
row_print(5, 1, "[1]: World switch");
row_print(6, 1, "[2]: Return-to-menu");
row_print(7, 1, "[3]: Measure perf");
#endif
#ifdef FXCG50
row_print(1, 1, "World switches performed: %d",
stats->world_switch_count);
row_print(2, 1, "Return-to-menu performed: %d",
stats->return_to_menu_count);
row_print(11, 1, "[1]: Standard world switch");
row_print(12, 1, "[2]: Return-to-menu with gint_osmenu()");
row_print(13, 1, "[3]: World switch with shared libprof (TODO)");
#endif
}
//---
// Main test
//---
/* gintctl_gint_drivers(): Test the gint driver logic and world switch */
void gintctl_gint_drivers(void)
{
int key=0, tab=0, list_scroll=0, list_max=_(7,12), selected_driver=0;
struct switch_stats stats = { 0 };
while(key != KEY_EXIT)
{
dclear(C_WHITE);
#ifdef FX9860G
if(tab == 0 || tab == 3) row_print(1, 1, "Drivers and worlds");
dimage(0, 56, &img_opt_gint_drivers);
#endif
#ifdef FXCG50
row_title("Drivers and world switches");
fkey_menu(1, "DRIVERS");
fkey_menu(2, "OS");
fkey_menu(3, "ADDIN");
fkey_menu(4, "MANUAL");
#endif
if(tab == 0) draw_list(list_scroll, list_max);
if(tab == 1) draw_state(gint_world_os, selected_driver);
if(tab == 2) draw_state(gint_world_addin, selected_driver);
if(tab == 3) draw_manual(&stats);
dupdate();
key = getkey().key;
if(key == KEY_F1) tab = 0;
if(key == KEY_F2) tab = 1;
if(key == KEY_F3) tab = 2;
if(key == KEY_F4) tab = 3;
/* Action for list tab */
if(tab == 0 && key == KEY_UP && list_scroll > 0)
list_scroll--;
if(tab == 0 && key == KEY_DOWN && list_scroll <
(int)gint_driver_count() - list_max)
list_scroll++;
/* Actions for OS state tab */
if((tab == 1 || tab == 2) && key == KEY_LEFT && selected_driver > 0)
selected_driver--;
if((tab == 1 || tab == 2) && key == KEY_RIGHT
&& selected_driver < (int)gint_driver_count()-1)
selected_driver++;
/* Actions for the manual tab */
if(tab == 3 && key == KEY_1)
gint_world_switch(GINT_CALL_INC(&stats.world_switch_count));
if(tab == 3 && key == KEY_2)
{
/* TODO: Should render next frame in advance for seamless return */
stats.return_to_menu_count++;
dupdate();
gint_osmenu();
/* Wait for KEY_2 to be released before calling next getkey() */
while(keydown(KEY_2)) waitevent(NULL);
}
if(tab == 3 && key == KEY_3)
{
/* TODO: World switch with performance statistics */
}
}
}