update to the new driver system

Follows most of the changes made to the gint driver system.

* Replace test gint/switch with a new test gint/drivers which shows
  driver metadata, flags, and world states.
* Enable the DMA Control test on SH4-based fx-9860G.
* Enable the Memory Speed test on SH4-based fx-9860G.
* Enable the Memory Speed test on SH3-based fx-9860G although there's
  barely anything useful for that platform.
* Update all tests to the GINT_CALL API when useful.
* Use public world buffers and public driver state structures to show
  world states without having to coordinate the gint and gintctl code.
This commit is contained in:
Lephenixnoir 2021-04-24 16:11:47 +02:00
parent b63d58515c
commit 5586985a3d
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
18 changed files with 503 additions and 444 deletions

View File

@ -22,6 +22,7 @@ set(SOURCES
src/gint/bopti.c
src/gint/cpumem.c
src/gint/dma.c
src/gint/drivers.c
src/gint/dsp.c
src/gint/dsp.s
src/gint/dump.c
@ -31,7 +32,6 @@ set(SOURCES
src/gint/ram.c
src/gint/rtc.c
src/gint/spuram.c
src/gint/switch.c
src/gint/timer.c
src/gint/timer_callbacks.c
src/gint/tlb.c
@ -70,6 +70,8 @@ set(ASSETS_fx
assets-fx/img/opt_dump.png
assets-fx/img/opt_gint_bopti.png
assets-fx/img/opt_gint_cpumem.png
assets-fx/img/opt_gint_dma.png
assets-fx/img/opt_gint_drivers.png
assets-fx/img/opt_gint_gray.png
assets-fx/img/opt_gint_keyboard.png
assets-fx/img/opt_gint_kmalloc.png
@ -84,10 +86,9 @@ set(ASSETS_fx
assets-fx/img/opt_main.png
assets-fx/img/opt_mem.png
assets-fx/img/opt_perf_libprof.png
assets-fx/img/opt_perf_memory.png
assets-fx/img/opt_perf_memory_sh3.png
assets-fx/img/opt_perf_render.png
assets-fx/img/opt_switch_ctx.png
assets-fx/img/opt_switch_ctx_sh3.png
assets-fx/img/opt_switch.png
assets-fx/img/profile_gray_alpha.png
assets-fx/img/profile_gray.png
assets-fx/img/profile_mono_alpha.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -25,6 +25,7 @@ extern bopti_image_t
img_opt_dump,
img_opt_gint_bopti,
img_opt_gint_cpumem,
img_opt_gint_drivers,
img_opt_gint_gray,
img_opt_gint_keyboard,
img_opt_gint_kmalloc,
@ -39,10 +40,9 @@ extern bopti_image_t
img_opt_main,
img_opt_mem,
img_opt_perf_libprof,
img_opt_perf_memory,
img_opt_perf_memory_sh3,
img_opt_perf_render,
img_opt_switch_ctx,
img_opt_switch_ctx_sh3,
img_opt_switch,
img_profile_gray_alpha,
img_profile_gray,
img_profile_mono_alpha,

View File

@ -20,8 +20,8 @@ void gintctl_gint_spuram(void);
/* gintctl_gint_dump(): Dump memory to filesystem */
void gintctl_gint_dump(void);
/* gintctl_gint_switch(): Test the gint switch-in-out procedures */
void gintctl_gint_switch(void);
/* gintctl_gint_drivers(): Test the gint driver logic and world switch */
void gintctl_gint_drivers(void);
/* gintctl_gint_tlb(): TLB miss handler and TLB management */
void gintctl_gint_tlb(void);
@ -35,6 +35,9 @@ void gintctl_gint_timer(void);
/* gintctl_gint_timer_callbacks(): Stunts in the environment of callbacks */
void gintctl_gint_timer_callbacks(void);
/* gintctl_gint_dma(): Test the Direct Access Memory Controller */
void gintctl_gint_dma(void);
/* gintctl_gint_rtc(): Configure RTC and check timer speed */
void gintctl_gint_rtc(void);
@ -50,13 +53,6 @@ void gintctl_gint_kmalloc(void);
/* gintctl_gint_usb(): USB communication */
void gintctl_gint_usb(void);
#ifdef FXCG50
/* gintctl_gint_dma(): Test the Direct Access Memory Controller */
void gintctl_gint_dma(void);
#endif /* FXCG50 */
#ifdef FX9860G
/* gintctl_gint_gray(): Gray engine tuning */

View File

@ -3,28 +3,26 @@
#include <gint/mpu/dma.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/mmu.h>
#include <gintctl/util.h>
#include <gintctl/gint.h>
#ifdef FXCG50
#define DMA SH7305_DMA
#define dprint(x, y, ...) dprint(x, y, C_BLACK, __VA_ARGS__)
void show_dma(int x, int y, int channel, sh7305_dma_channel_t *dma)
void show_dma(int x, int y, GUNUSED int channel, sh7305_dma_channel_t *dma)
{
#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, y, "SAR:");
dprint(x, y+1*dy, "DAR:");
dprint(x, y+2*dy, "TCR:");
dprint(x, y+3*dy, "CHCR:");
dprint(x+dx, y, "%08X", dma->SAR);
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);
dprint(x+dx, y+2*dy, "%08X", dma->TCR);
dprint(x+dx, y+3*dy, "%08X", dma->CHCR);
#endif
#ifdef FXCG50
@ -44,28 +42,30 @@ void show_dma(int x, int y, int channel, sh7305_dma_channel_t *dma)
/* 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;
/* We'll display the DMA status at "full speed", without sleeping. */
int key=0, timeout=1;
/* Test channel, interrupts, and source; successful attempts */
int channel=0, interrupts=0, source=0, successes=0;
/* Get the physical VRAM address */
void *vram_address = gint_vram;
#ifdef FX9860G
/* Currently visible channel */
int view = 0;
uint32_t virt_page = (uint32_t)vram_address & 0xfffff000;
uint32_t phys_page = 0x80000000 + mmu_translate(virt_page, NULL);
vram_address = (void *)phys_page + (vram_address - (void *)virt_page);
#endif
sh7305_dma_channel_t *addr[6] = {
&DMA.DMA0, &DMA.DMA1, &DMA.DMA2, &DMA.DMA3, &DMA.DMA4, &DMA.DMA5,
};
while(key != KEY_EXIT)
{
dclear(C_WHITE);
#ifdef FX9860G
show_dma(1, 1, view);
dprint(1, 32, "Channel %d", channel);
show_dma(1, 0, channel, addr[channel]);
dprint(1, 32, "Channel DMA%d", channel);
dprint(1, 40, "Interrupts %s", interrupts ? "Yes" : "No");
dprint(1, 48, "Source %s", source ? "IL" : "RAM");
dprint(103, 40, "%d", successes);
@ -75,11 +75,6 @@ void gintctl_gint_dma(void)
#endif
#ifdef FXCG50
sh7305_dma_channel_t *addr[6] = {
&DMA.DMA0, &DMA.DMA1, &DMA.DMA2,
&DMA.DMA3, &DMA.DMA4, &DMA.DMA5,
};
row_title("Direct Memory Access status");
show_dma(6, 24, 0, addr[0]);
@ -105,11 +100,11 @@ void gintctl_gint_dma(void)
dupdate();
key = getkey_opt(GETKEY_DEFAULT, &timeout).key;
/* On F1, start a DMA transfer and see what happens */
/* On F1, start a 1024-byte DMA transfer and see what happens */
if(key == KEY_F1)
{
void *src = (void *)(source ? 0xe5200000 : 0x88000000);
void *dst = gint_vram;
void *dst = vram_address;
int blocks = 256;
if(interrupts)
@ -124,16 +119,8 @@ void gintctl_gint_dma(void)
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 */

328
src/gint/drivers.c Normal file
View File

@ -0,0 +1,328 @@
#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 <gint/std/string.h>
#include <gintctl/gint.h>
#include <gintctl/util.h>
#include <gintctl/assets.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 */
}
}
}

View File

@ -15,13 +15,6 @@ struct region {
int segment_count;
};
struct {
int region;
int segment;
char filename[30];
int retcode;
} dump;
static struct region const regs[] = {
#ifdef FX9860G
{ "ROM", 0x80000000, 0x807fffff, 8 },
@ -36,15 +29,15 @@ static struct region const regs[] = {
#endif
};
static void switch_dump(void)
static void switch_dump(int region, int segment, char *filename, int *retcode)
{
uint32_t start = regs[dump.region].start;
int size = regs[dump.region].end + 1 - start;
uint32_t start = regs[region].start;
int size = regs[region].end + 1 - start;
/* For segmented regions, use blocks of 1M */
if(regs[dump.region].segment_count > 1)
if(regs[region].segment_count > 1)
{
start += dump.segment << 20;
start += segment << 20;
size = 1 << 20;
}
@ -52,35 +45,34 @@ static void switch_dump(void)
size &= ~1;
uint16_t file[30] = { 0 };
for(int i = 0; i < 30; i++) file[i] = dump.filename[i];
for(int i = 0; i < 30; i++) file[i] = filename[i];
dump.retcode = 1;
*retcode = 1;
int x = BFile_Remove(file);
if(x < 0 && x != -1) { dump.retcode = x; return; }
if(x < 0 && x != -1) { *retcode = x; return; }
x = BFile_Create(file, BFile_File, &size);
if(x < 0) { dump.retcode = x; return; }
if(x < 0) { *retcode = x; return; }
int fd = BFile_Open(file, BFile_WriteOnly);
if(fd < 0) { dump.retcode = fd; return; }
if(fd < 0) { *retcode = fd; return; }
x = BFile_Write(fd, (void *)start, size);
if(x < 0) { dump.retcode = x; return; }
if(x < 0) { *retcode = x; return; }
BFile_Close(fd);
}
static int do_dump(int region, int segment)
{
/* Pass around parameters through the global variable */
dump.region = region;
dump.segment = segment;
sprintf(dump.filename, "\\\\fls0\\%s%02x.bin", regs[region].name,
segment);
char filename[30];
int retcode = 0;
gint_switch(switch_dump);
return dump.retcode;
sprintf(filename, "\\\\fls0\\%s%02x.bin", regs[region].name, segment);
gint_world_switch(GINT_CALL(switch_dump,region,segment,filename,&retcode));
return retcode;
}
/* gintctl_gint_dump(): Dump memory to filesystem */

View File

@ -1,276 +0,0 @@
#include <gint/gint.h>
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/drivers.h>
#include <gint/clock.h>
#include <gint/hardware.h>
#include <gint/mpu/tmu.h>
#include <gint/mpu/dma.h>
#include <gint/std/string.h>
#include <gintctl/gint.h>
#include <gintctl/util.h>
static int switches = 0;
static int menus = 0;
static void switch_function(void)
{
switches++;
}
//---
// Saved system context visualizer
//---
void *driver_ctx(char const *name)
{
extern gint_driver_t bdrv, edrv;
for(gint_driver_t *drv = &bdrv; drv < &edrv; drv++)
{
if(!strcmp(drv->name, name)) return drv->sys_ctx;
}
return NULL;
}
#ifdef FX9860G
static void ctx_tmu()
{
tmu_t *t = driver_ctx("TMU");
uint8_t *TSTR = (void *)t + 3 * sizeof(tmu_t) + 6 * sizeof(etmu_t);
for(int i = 0; i < 3; i++, t++)
{
row_print(2*i+1, 1, "TMU%d=%d CNT:%08x", i,
(*TSTR & (1 << i)) != 0, t->TCNT);
row_print(2*i+2, 1, "TCR:%04x COR:%08x", t->TCR.word, t->TCOR);
}
}
static void ctx_dd()
{
uint8_t *STRD = driver_ctx("T6K11");
row_print(1, 1, "STRD:%02x", *STRD);
row_print(2, 2, "RESET:%d", (*STRD & 0x08) != 0);
row_print(3, 2, "N/F:%d", (*STRD & 0x04) != 0);
row_print(4, 2, "X/Y:%d", (*STRD & 0x02) != 0);
row_print(5, 2, "U/D:%d", (*STRD & 0x01) != 0);
}
static void ctx_rtc()
{
uint8_t *ctx = driver_ctx("RTC");
if(!ctx) return;
uint8_t RCR1=ctx[0], RCR2=ctx[1];
row_print(1, 1, "RCR1:%02x", RCR1);
row_print(2, 1, "RCR2:%02x", RCR2);
}
static void show_etmu(int line, int id, etmu_t *t)
{
row_print(line, 1, "ETMU%d=%-3dCNT:%08x", id, t->TSTR, t->TCNT);
row_print(line+1, 1, "TCR:%02x COR:%08x", t->TCR.byte, t->TCOR);
}
static void ctx_etmu(int start)
{
etmu_t *t = driver_ctx("TMU") + 3 * sizeof(tmu_t);
int length = 3;
if(isSH3()) length=1, start=0;
t += start;
for(int i = 0; i < length; i++, t++)
{
show_etmu(2*i+1, i+start, t);
}
}
static void ctx_intc()
{
uint16_t *IPR = driver_ctx("INTC");
if(isSH3())
{
row_print(1,1, "A:%04x B:%04x C:%04x", IPR[0], IPR[1], IPR[2]);
row_print(2,1, "D:%04x E:%04x F:%04x", IPR[3], IPR[4], IPR[5]);
row_print(3,1, "G:%04x H:%04x", IPR[6], IPR[7]);
}
else
{
row_print(1,1, "A:%04x B:%04x C:%04x", IPR[0], IPR[1], IPR[2]);
row_print(2,1, "D:%04x E:%04x F:%04x", IPR[3], IPR[4], IPR[5]);
row_print(3,1, "G:%04x H:%04x I:%04x", IPR[6], IPR[7], IPR[8]);
row_print(4,1, "J:%04x K:%04x L:%04x", IPR[9],IPR[10],IPR[11]);
}
}
#endif /* FX9860G */
#ifdef FXCG50
static void ctx_tmu()
{
tmu_t *t = driver_ctx("TMU");
etmu_t *e = (void *)(t + 3);
uint8_t *TSTR = (void *)(e + 6);
int const x[] = { 6, 138, 270, 6, 138, 270, 6, 138, 270 };
int const y[] = { 24, 24, 24, 84, 84, 84, 144, 144, 144 };
tmu_print(x[0], y[0], "TMU0", t+0, *TSTR & 0x1);
tmu_print(x[1], y[1], "TMU1", t+1, *TSTR & 0x2);
tmu_print(x[2], y[2], "TMU2", t+2, *TSTR & 0x4);
etmu_print(x[3], y[3], "ETMU0", e+0);
etmu_print(x[4], y[4], "ETMU1", e+1);
etmu_print(x[5], y[5], "ETMU2", e+2);
etmu_print(x[6], y[6], "ETMU3", e+3);
etmu_print(x[7], y[7], "ETMU4", e+4);
etmu_print(x[8], y[8], "ETMU5", e+5);
}
static void ctx_dd()
{
uint16_t *win = driver_ctx("R61524");
uint16_t HSA = win[0], HEA = win[1], VSA = win[2], VEA = win[3];
row_print(1, 1, "Horizontal range: %d..%d", HSA, HEA);
row_print(2, 1, "Vertical range: %d..%d", VSA, VEA);
}
static void ctx_rtc()
{
uint8_t *ctx = driver_ctx("RTC");
if(!ctx) return;
uint8_t RCR1=ctx[0], RCR2=ctx[1];
row_print(1, 1, "RCR1:%02x", RCR1);
row_print(2, 1, "RCR2:%02x", RCR2);
}
static void ctx_dma()
{
sh7305_dma_channel_t *ch = driver_ctx("DMA0");
int *clock = (void *)(ch + 6);
uint16_t *OR = (void *)(clock + 1);
show_dma(6, 24, 0, ch+0);
show_dma(138, 24, 1, ch+1);
show_dma(270, 24, 2, ch+2);
show_dma(6, 104, 3, ch+3);
show_dma(138, 104, 4, ch+4);
show_dma(270, 104, 5, ch+5);
dprint(6, 184, C_BLACK, "DMAOR: %08X", *OR);
dprint(198, 184, C_BLACK, "Clock enabled: %s",(*clock ? "No" : "Yes"));
}
#endif /* FXCG50 */
static void system_contexts(void)
{
int key=0, tab=0;
while(key != KEY_EXIT)
{
dclear(C_WHITE);
#ifdef FX9860G
extern bopti_image_t img_opt_switch_ctx_sh3;
extern bopti_image_t img_opt_switch_ctx;
if(isSH3())
dimage(0, 56, &img_opt_switch_ctx_sh3);
else
dimage(0, 56, &img_opt_switch_ctx);
#endif
#ifdef FXCG50
row_title("System context visualizer");
fkey_button(1, "TMU");
fkey_button(2, "R61524");
fkey_button(3, "RTC");
fkey_button(4, "DMA");
#endif
if(tab == 0) ctx_tmu();
if(tab == 1) ctx_dd();
if(tab == 2) ctx_rtc();
#ifdef FX9860G
if(tab == 3) ctx_etmu(0);
if(tab == 4) ctx_etmu(3);
if(tab == 5) ctx_intc();
#endif
#ifdef FXCG50
if(tab == 3) ctx_dma();
#endif
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;
if(key == KEY_F6) tab = 5;
#ifdef FX9860G
if(key == KEY_F5 && isSH3()) tab = 4;
#endif
}
}
//---
// Interactive in-out switching
//---
/* Render VRAM for this screen, used when returning to menu */
void render(void)
{
dclear(C_WHITE);
#ifdef FX9860G
extern bopti_image_t img_opt_switch;
row_print(1, 1, "Switch to OS");
row_print(3, 1, "Switches done: %d", switches);
row_print(4, 1, "Menus done: %d", menus);
dimage(0, 56, &img_opt_switch);
#endif
#ifdef FXCG50
row_title("Hot switching between gint and OS");
row_print(2, 1, "Switches done: %d", switches);
row_print(3, 1, "Menus done: %d", menus);
fkey_button(1, "SWITCH");
fkey_button(2, "MENU");
fkey_action(6, "SYSTEM");
#endif
}
/* gintctl_gint_switch(): Test the gint switch-in-out procedures */
void gintctl_gint_switch(void)
{
int key = 0;
while(key != KEY_EXIT)
{
render();
dupdate();
key = getkey().key;
if(key == KEY_F1) gint_switch(switch_function);
/* Wait for F2 to be released before calling next getkey() */
if(key == KEY_F2)
{
/* Render next frame in advance. When we return from
the main menu, our VRAM will be displayed but
GetKeyWait() will not give control back until a key
is pressed. This will make it look like we render a
new frame right away. */
menus++;
render();
dupdate();
gint_osmenu();
while(keydown(KEY_F2)) waitevent(NULL);
}
if(key == KEY_F6) system_contexts();
}
}

View File

@ -3,6 +3,8 @@
#include <gint/mpu/usb.h>
#include <gint/usb.h>
#include <gint/usb-ff-bulk.h>
#include <gint/drivers.h>
#include <gint/drivers/states.h>
#include <gint/intc.h>
#include <gint/mpu/power.h>
#include <gint/mpu/cpg.h>
@ -18,17 +20,6 @@
#define USB SH7305_USB
/* Copy of the context structure from the driver (edgy style but heck) */
typedef struct
{
uint16_t SYSCFG, DVSTCTR, TESTMODE, REG_C2;
uint16_t CFIFOSEL, D0FIFOSEL, D1FIFOSEL;
uint16_t INTENB0, BRDYENB, NRDYENB, BEMPENB, SOFCFG;
uint16_t DCPCFG, DCPMAXP, DCPCTR;
uint16_t PIPECFG[9], PIPEBUF[9], PIPEMAXP[9], PIPEPERI[9];
uint16_t PIPEnCTR[9], PIPEnTRE[5], PIPEnTRN[5];
} ctx_t;
/* USB log buffer */
#define LOG_SIZE _(1023, 16383)
static char log_buffer[LOG_SIZE+1];
@ -155,25 +146,28 @@ static void draw_registers(GUNUSED int scroll)
static void draw_context(void)
{
extern void *driver_ctx(char const *name);
ctx_t *ctx = driver_ctx("USB");
GUNUSED int scroll = 0;
usb_state_t *s = NULL;
for(int i = 0; i < gint_driver_count(); i++) {
if(!strcmp(gint_drivers[i].name, "USB")) s = gint_world_os[i];
}
if(!s) return;
val( 0, "SYSCFG", ctx->SYSCFG);
val( 1, "DVSTCTR", ctx->DVSTCTR);
val( 2, "TESTMODE", ctx->TESTMODE);
val( 3, "REG_C2", ctx->REG_C2);
val( 4, "CFIFOSEL", ctx->CFIFOSEL);
val( 5, "D0FIFOSEL", ctx->D0FIFOSEL);
val( 6, "D1FIFOSEL", ctx->D1FIFOSEL);
val( 7, "INTENB0", ctx->INTENB0);
val( 8, "BRDYENB", ctx->BRDYENB);
val( 9, "NRDYENB", ctx->NRDYENB);
val(10, "BEMPENB", ctx->BEMPENB);
val(11, "SOFCFG", ctx->SOFCFG);
val(12, "DCPCFG", ctx->DCPCFG);
val(13, "DCPMAXP", ctx->DCPMAXP);
val(14, "DCPCTR", ctx->DCPCTR);
GUNUSED int scroll = 0;
val( 0, "SYSCFG", s->SYSCFG);
val( 1, "DVSTCTR", s->DVSTCTR);
val( 2, "TESTMODE", s->TESTMODE);
val( 3, "REG_C2", s->REG_C2);
val( 4, "CFIFOSEL", s->CFIFOSEL);
val( 5, "D0FIFOSEL", s->D0FIFOSEL);
val( 6, "D1FIFOSEL", s->D1FIFOSEL);
val( 7, "INTENB0", s->INTENB0);
val( 8, "BRDYENB", s->BRDYENB);
val( 9, "NRDYENB", s->NRDYENB);
val(10, "BEMPENB", s->BEMPENB);
val(11, "SOFCFG", s->SOFCFG);
val(12, "DCPCFG", s->DCPCFG);
val(13, "DCPMAXP", s->DCPMAXP);
val(14, "DCPCTR", s->DCPCTR);
// uint16_t PIPECFG[9], PIPEBUF[9], PIPEMAXP[9], PIPEPERI[9];
// uint16_t PIPEnCTR[9], PIPEnTRE[5], PIPEnTRN[5];
@ -305,7 +299,8 @@ void gintctl_gint_usb(void)
if(key == KEY_F3) tab = 2;
if(key == KEY_F4) tab = 3;
if(tab == 2 && key == KEY_F5) gint_switch(save_logger);
if(tab == 2 && key == KEY_F5)
gint_world_switch(GINT_CALL(save_logger));
if(key == KEY_F6)
{
@ -313,7 +308,7 @@ void gintctl_gint_usb(void)
else
{
usb_interface_t const *interfaces[] = { &usb_ff_bulk, NULL };
int rc = usb_open(interfaces, GINT_CB(open_callback));
int rc = usb_open(interfaces, GINT_CALL(open_callback));
open = (rc == 0);
}
}

View File

@ -27,29 +27,27 @@
struct menu menu_gint = {
_("gint tests", "gint features and driver tests"), .entries = {
{ "CPU and memory", gintctl_gint_cpumem, 0 },
{ "RAM discovery", gintctl_gint_ram, MENU_SH4_ONLY },
{ "CPU and memory", gintctl_gint_cpumem, 0 },
{ "RAM discovery", gintctl_gint_ram, MENU_SH4_ONLY },
#ifdef FXCG50
{ "DSP processors", gintctl_gint_dsp, 0 },
{ "DSP processors", gintctl_gint_dsp, 0 },
#endif
{ "SPU memory", gintctl_gint_spuram, MENU_SH4_ONLY },
{ "Memory dump", gintctl_gint_dump, 0 },
{ "Switching to OS", gintctl_gint_switch, 0 },
{ "TLB management", gintctl_gint_tlb, 0 },
{ "Memory allocation",gintctl_gint_kmalloc, 0 },
{ "Keyboard", gintctl_gint_keyboard, 0 },
{ "Timers", gintctl_gint_timer, 0 },
{ "Timer callbacks", gintctl_gint_timer_callbacks, 0 },
#ifdef FXCG50
{ "DMA control", gintctl_gint_dma, 0 },
#endif
{ "Real-time clock", gintctl_gint_rtc, 0 },
{ "USB communication",gintctl_gint_usb, MENU_SH4_ONLY },
{ "Image rendering", gintctl_gint_bopti, 0 },
{ "Text rendering", gintctl_gint_topti, 0 },
{ "SPU memory", gintctl_gint_spuram, MENU_SH4_ONLY },
{ "Memory dump", gintctl_gint_dump, 0 },
{ "Drivers and worlds", gintctl_gint_drivers, 0 },
{ "TLB management", gintctl_gint_tlb, 0 },
{ "Memory allocation", gintctl_gint_kmalloc, 0 },
{ "Keyboard", gintctl_gint_keyboard, 0 },
{ "Timers", gintctl_gint_timer, 0 },
{ "Timer callbacks", gintctl_gint_timer_callbacks, 0 },
{ "DMA control", gintctl_gint_dma, MENU_SH4_ONLY },
{ "Real-time clock", gintctl_gint_rtc, 0 },
{ "USB communication", gintctl_gint_usb, MENU_SH4_ONLY },
{ "Image rendering", gintctl_gint_bopti, 0 },
{ "Text rendering", gintctl_gint_topti, 0 },
#ifdef FX9860G
{ "Gray engine", gintctl_gint_gray, 0 },
{ "Gray rendering", gintctl_gint_grayrender, 0 },
{ "Gray engine", gintctl_gint_gray, 0 },
{ "Gray rendering", gintctl_gint_grayrender, 0 },
#endif
{ NULL, NULL, 0 },
}};
@ -61,9 +59,7 @@ struct menu menu_perf = {
{ "libprof basics", gintctl_perf_libprof, 0 },
{ "CPU and cache", gintctl_perf_cpucache, 0 },
{ "Interrupt stress", gintctl_perf_interrupts, 0 },
#ifdef FXCG50
{ "Memory access speed", gintctl_perf_memory, 0 },
#endif
{ "Rendering functions", gintctl_perf_render, 0 },
/* TODO: Comparison with MonochromeLib */

View File

@ -3,9 +3,11 @@
#include <gint/hardware.h>
#include <gint/dma.h>
#include <gint/std/string.h>
#include <gint/mmu.h>
#include <gintctl/perf.h>
#include <gintctl/util.h>
#include <gintctl/assets.h>
#include <libprof.h>
@ -104,17 +106,13 @@ static void test(struct results *r, void *address, uint32_t size, int rounds)
});
r->dma_memset_time = prof_exec({
#ifdef FXCG50
for(int i = 0; i < rounds; i++)
dma_memset(address, 0, size);
#endif
if(isSH4()) dma_memset(address, 0, size);
});
r->dma_memcpy_time = 2 * prof_exec({
#ifdef FXCG50
for(int i = 0; i < rounds; i++)
dma_memcpy(address + size / 2, address, size / 2);
#endif
if(isSH4()) dma_memcpy(address + size / 2, address, size / 2);
});
if(address == &xram_buffer)
@ -122,14 +120,14 @@ static void test(struct results *r, void *address, uint32_t size, int rounds)
/* Since the buffers are small, repeat 16 times */
r->dsp_xram_memset_time = prof_exec({
for(int i = 0; i < rounds; i++)
memory_dsp_xram_memset(address, size);
if(isSH4()) memory_dsp_xram_memset(address, size);
});
}
if(address == &yram_buffer)
{
r->dsp_yram_memset_time = prof_exec({
for(int i = 0; i < rounds; i++)
memory_dsp_yram_memset(address, size);
if(isSH4()) memory_dsp_yram_memset(address, size);
});
}
if(address == &xram_buffer)
@ -140,7 +138,7 @@ static void test(struct results *r, void *address, uint32_t size, int rounds)
/* Since the buffers are small, repeat 16 times */
r->dsp_xyram_memcpy_time = prof_exec({
for(int i = 0; i < rounds; i++)
memory_dsp_xyram_memcpy(y, x, size);
if(isSH4()) memory_dsp_xyram_memcpy(y, x, size);
});
}
if(address == &yram_buffer)
@ -150,7 +148,7 @@ static void test(struct results *r, void *address, uint32_t size, int rounds)
r->dsp_xyram_memcpy_time = prof_exec({
for(int i = 0; i < rounds; i++)
memory_dsp_xyram_memcpy(x, y, size);
if(isSH4()) memory_dsp_xyram_memcpy(x, y, size);
});
}
@ -171,25 +169,76 @@ static void test(struct results *r, void *address, uint32_t size, int rounds)
static void results_line(int row, uint32_t time, uint32_t speed)
{
dprint_opt(260, row_y(row), C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP,
int y = _(8+6*row, row_y(row));
dprint_opt(_(80,260), y, C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP,
"%d us", time);
dprint_opt(370, row_y(row), C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP,
"%3.3j MB/s", speed);
dprint_opt(_(125,370), y, C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP,
_("%3.1j MB/s", "%3.3j MB/s"), _(speed/100, speed));
}
/* gintctl_perf_memory(): Memory primitives and reading/writing speed */
void gintctl_perf_memory(void)
{
/* TODO: Memory performance on SH3 */
if(isSH3()) return;
int key = 0;
struct results r = { 0 };
/* Get the physical VRAM address */
void *vram_address = gint_vram;
#ifdef FX9860G
uint32_t virt_page = (uint32_t)vram_address & 0xfffff000;
uint32_t phys_page = 0x80000000 + mmu_translate(virt_page, NULL);
vram_address = (void *)phys_page + (vram_address - (void *)virt_page);
#endif
while(key != KEY_EXIT)
{
dclear(C_WHITE);
row_title("Memory access speed");
font_t const *old_font = dfont(_(&font_mini, dfont_default()));
#ifdef FX9860G
/* Due to less space, focus on the non-trivial methods */
dprint(1, 14, C_BLACK, "gint memcpy:");
dprint(1, 20, C_BLACK, "gint memset:");
if(isSH4()) {
dprint(1, 26, C_BLACK, "dma_memcpy:");
dprint(1, 32, C_BLACK, "dma_memset:");
if(r.address == &xram_buffer)
dprint(1, 38, C_BLACK, "DSP memset:");
if(r.address == &yram_buffer)
dprint(1, 38, C_BLACK, "DSP memset:");
if(r.address == &xram_buffer || r.address == &yram_buffer)
dprint(1, 44, C_BLACK, "DSP memcpy:");
}
if(!r.address) dprint(1, 8, C_BLACK, "No test yet");
else
{
dprint(1, 8, C_BLACK, "Area: %08X (%d B, %d round%s)",
(uint32_t)r.address, r.size, r.rounds, (r.rounds>1)?"s":"");
results_line(1, r.memcpy_time, r.memcpy_speed);
results_line(2, r.memset_time, r.memset_speed);
if(isSH4()) {
results_line(3, r.dma_memcpy_time, r.dma_memcpy_speed);
results_line(4, r.dma_memset_time, r.dma_memset_speed);
if(r.address == &xram_buffer)
results_line(5, r.dsp_xram_memset_time,
r.dsp_xram_memset_speed);
if(r.address == &yram_buffer)
results_line(5, r.dsp_yram_memset_time,
r.dsp_yram_memset_speed);
if(r.address==&xram_buffer || r.address==&yram_buffer)
results_line(6, r.dsp_xyram_memcpy_time,
r.dsp_xyram_memcpy_speed);
}
}
if(isSH3())
dimage(0, 56, &img_opt_perf_memory_sh3);
else
dimage(0, 56, &img_opt_perf_memory);
#endif
#ifdef FXCG50
row_print( 3, 1, "Naive C-loop u8 read:");
@ -208,10 +257,7 @@ void gintctl_perf_memory(void)
if(r.address == &xram_buffer || r.address == &yram_buffer)
row_print(12, 1, "DSP XRAM->YRAM memcpy():");
if(!r.address)
{
row_print(1, 1, "No test yet");
}
if(!r.address) row_print(1, 1, "No test yet");
else
{
row_print(1, 1, "Results for area %08x (%d bytes, %d "
@ -227,20 +273,14 @@ void gintctl_perf_memory(void)
results_line(10,r.dma_memset_time, r.dma_memset_speed);
if(r.address == &xram_buffer)
{
results_line(11, r.dsp_xram_memset_time,
r.dsp_xram_memset_speed);
}
if(r.address == &yram_buffer)
{
results_line(11, r.dsp_yram_memset_time,
r.dsp_yram_memset_speed);
}
if(r.address==&xram_buffer || r.address==&yram_buffer)
{
results_line(12, r.dsp_xyram_memcpy_time,
r.dsp_xyram_memcpy_speed);
}
}
fkey_button(1, "RAM");
@ -249,12 +289,15 @@ void gintctl_perf_memory(void)
fkey_button(4, "YRAM");
#endif
dfont(old_font);
dupdate();
key = getkey().key;
if(key == KEY_F1) test(&r, gint_vram, _(0x400,0x8000), 1);
if(key == KEY_F2) test(&r, &ilram_buffer, 0x800, 64);
if(key == KEY_F3) test(&r, &xram_buffer, 0x800, 64);
if(key == KEY_F4) test(&r, &yram_buffer, 0x800, 64);
if(key == KEY_F1) test(&r, vram_address, _(0x400,0x8000), _(32,1));
if(isSH4()) {
if(key == KEY_F2) test(&r, &ilram_buffer, 0x800, 64);
if(key == KEY_F3) test(&r, &xram_buffer, 0x800, 64);
if(key == KEY_F4) test(&r, &yram_buffer, 0x800, 64);
}
}
}

View File

@ -218,9 +218,7 @@ void fkey_menu(int position, char const *text)
// Screenshot saving
//---
static uint16_t const *path;
void switch_screen_mono(void)
void switch_screen_mono(uint16_t const *path)
{
int size = 1024;
@ -235,6 +233,5 @@ void switch_screen_mono(void)
/* screen_mono(): Take a screenshot of the mono VRAM */
void screen_mono(uint16_t const *filepath)
{
path = filepath;
gint_switch(switch_screen_mono);
gint_world_switch(GINT_CALL(switch_screen_mono, filepath));
}