add TLB management and timer callback tests

This commit is contained in:
Lephe 2020-06-17 14:36:18 +02:00
parent 09542e14a7
commit 33411e9822
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
11 changed files with 524 additions and 2 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
assets-fx/img/tlb_cells.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -17,12 +17,18 @@ void gintctl_gint_dump(void);
/* gintctl_gint_switch(): Test the gint switch-in-out procedures */
void gintctl_gint_switch(void);
/* gintctl_gint_tlb(): TLB miss handler and TLB management */
void gintctl_gint_tlb(void);
/* gintct_gint_keybaord: Real-time keyboard visualization */
void gintctl_gint_keyboard(void);
/* gintctl_gint_timer(): Show the timer status in real-time */
void gintctl_gint_timer(void);
/* gintctl_gint_timer_callbacks(): Stunts in the environment of callbacks */
void gintctl_gint_timer_callbacks(void);
/* gintctl_gint_bopti(): Test image rendering */
void gintctl_gint_bopti(void);

View File

@ -29,6 +29,9 @@ 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_print_color(): Formatted printing... with custom colors! */
void row_print_color(int row, int x, int fg, int bg, char const *format, ...);
/* row_highlight(): Invert a row's pixels to highlight it */
void row_highlight(int row);

View File

@ -0,0 +1,98 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/timer.h>
#include <gint/clock.h>
#include <gintctl/gint.h>
#include <gintctl/util.h>
static int callback_simple(volatile void *arg)
{
/* Perform a multiplication to check basic register saves */
int base = *(volatile int *)arg;
return base * 387 + 1;
}
static int callback_sleep(GUNUSED volatile void *arg)
{
sleep();
return 1;
}
static int callback_timer(GUNUSED volatile void *arg)
{
volatile int timeout = 0;
timer_setup(1, timer_delay(1, 10000), timer_default, timer_timeout,
&timeout);
timer_start(1);
timer_wait(1);
return 1;
}
/* gintctl_gint_timer_callbacks(): Stunts in the environment of callbacks */
void gintctl_gint_timer_callbacks(void)
{
int key = 0;
int base=0, done=0;
while(key != KEY_EXIT)
{
dclear(C_WHITE);
#ifdef FX9860G
row_title("Timer callbacks");
row_print(3, 1, "F1:Simple callback");
row_print(4, 1, "F2:Wait with sleep()");
row_print(5, 1, "F3:Start timer!");
extern bopti_image_t img_opt_gint_timer_callbacks;
dimage(0, 56, &img_opt_gint_timer_callbacks);
dprint(69, 56, C_BLACK, C_NONE, "Done:%d", done);
#endif
#ifdef FXCG50
row_title("Interrupt management in timer callbacks");
row_print(1, 1,
"SIMPLE runs a short callback that modifies CPU");
row_print(2, 1,
"registers.");
row_print(4, 1,
"SLEEP transitions to standby mode, forcing an");
row_print(5, 1,
"interrupt within the callback.");
row_print(7, 1,
"TIMER runs a callback that starts a timer (with its");
row_print(8, 1,
"own callback) and waits for the interrupt.");
row_print(10, 1, "Tests run: %d", done);
fkey_action(1, "SIMPLE");
fkey_action(2, "SLEEP");
fkey_action(3, "TIMER");
#endif
dupdate();
key = getkey().key;
int (*callback)(volatile void *arg) = NULL;
volatile void *arg = NULL;
if(key == KEY_F1) callback = callback_simple, arg = &base;
if(key == KEY_F2) callback = callback_sleep;
if(key == KEY_F3) callback = callback_timer;
if(callback)
{
timer_setup(0, timer_delay(0, 10000), timer_default,
callback, arg);
timer_start(0);
timer_wait(0);
done++;
}
}
}

401
src/gint/tlb.c Normal file
View File

@ -0,0 +1,401 @@
#include <gint/display.h>
#include <gint/keyboard.h>
#include <gint/timer.h>
#include <gint/mmu.h>
#include <gintctl/gint.h>
#include <gintctl/util.h>
#define PAGE_USED 0x01
#define PAGE_MAPPED 0x02
#define C_ C_BLACK, C_NONE
#define TLB_VIEW_MAX (64 - TLB_VIEW)
#ifdef FXCG50
#define PAGE_COUNT 0x200
#define SQUARE_WIDTH 8
#define SQUARE_HEIGHT 8
#define LINE_SIZE 32
#define TLB_VIEW 12
static void draw_rom_cell(int x, int y, int status)
{
uint16_t colors[4] = {
C_RGB(24,24,24), /* Unused and unmapped */
C_WHITE, /* Used, but currently unmapped */
C_RGB(31,24,0), /* Unused but still mapped?! */
C_RGB(0,31,0), /* Used and currently mapped */
};
uint16_t border =
status == -1 ? C_RGB(0,0,31) :
status == -2 ? C_RGB(31,0,0) :
C_BLACK;
if(status >= 0 && status < 4)
drect(x, y, x+SQUARE_WIDTH, y+SQUARE_HEIGHT, colors[status]);
dline(x, y, x+SQUARE_WIDTH, y, border);
dline(x, y, x, y+SQUARE_HEIGHT, border);
dline(x+SQUARE_WIDTH, y, x+SQUARE_WIDTH, y+SQUARE_HEIGHT, border);
dline(x, y+SQUARE_HEIGHT, x+SQUARE_WIDTH, y+SQUARE_HEIGHT, border);
}
#endif
#ifdef FX9860G
#define PAGE_COUNT 0x80
#define SQUARE_WIDTH 4
#define SQUARE_HEIGHT 4
#define LINE_SIZE 16
#define TLB_VIEW 8
static void draw_rom_cell(int x, int y, int status)
{
extern bopti_image_t img_tlb_cells;
dsubimage(x, y, &img_tlb_cells, (status+2)*(SQUARE_WIDTH+2), 0,
SQUARE_WIDTH+1, SQUARE_HEIGHT+1, DIMAGE_NONE);
}
#endif
static int rom_cell_x(int page_number)
{
int x = (page_number % LINE_SIZE) * SQUARE_WIDTH;
x += 3 * ((page_number % LINE_SIZE) >> 3);
return x;
}
static int rom_cell_y(int page_number)
{
return (page_number / LINE_SIZE) * SQUARE_HEIGHT;
}
#ifdef FX9860G
void triangle_up(int y)
{
int x=118;
dpixel(x+2, y, C_BLACK);
dline(x+1, y+1, x+3, y+1, C_BLACK);
dline(x, y+2, x+4, y+2, C_BLACK);
}
void triangle_down(int y)
{
int x=118;
dline(x, y, x+4, y, C_BLACK);
dline(x+1, y+1, x+3, y+1, C_BLACK);
dpixel(x+2, y+2, C_BLACK);
}
#endif
#ifdef FXCG50
void triangle_up(int y)
{
int x=370;
dpixel(x+3, y, C_BLACK);
dline(x+2, y+1, x+4, y+1, C_BLACK);
dline(x+1, y+2, x+5, y+2, C_BLACK);
dline(x, y+3, x+6, y+3, C_BLACK);
dline(x, y+4, x+6, y+4, C_BLACK);
}
void triangle_down(int y)
{
int x=370;
dline(x, y, x+6, y, C_BLACK);
dline(x, y+1, x+6, y+1, C_BLACK);
dline(x+1, y+2, x+5, y+2, C_BLACK);
dline(x+2, y+3, x+4, y+3, C_BLACK);
dpixel(x+3, y+4, C_BLACK);
}
#endif
static void explore_pages(uint8_t *pages, uint32_t *next_miss)
{
extern uint32_t srom;
for(uint p = 0; p < PAGE_COUNT; p++)
{
pages[p] = ((p << 12) < (uint32_t)&srom) ? PAGE_USED : 0;
}
for(uint E = 0; E < 64; E++)
{
utlb_addr_t addr = *utlb_addr(E);
utlb_data_t data = *utlb_data(E);
uint32_t src = addr.VPN << 10;
int valid = (addr.V != 0) && (data.V != 0);
int size = (data.SZ1 << 1) | data.SZ2;
if(!valid || size != 1) continue;
int p = (src - 0x00300000) >> 12;
pages[p] |= PAGE_MAPPED;
}
*next_miss = 0xffffffff;
for(uint p = 0; p < PAGE_COUNT; p++)
{
if((pages[p] & PAGE_USED) && !(pages[p] & PAGE_MAPPED))
{
*next_miss = 0x00300000 + (p << 12);
break;
}
}
}
#ifdef FXCG50
void show_utlb(int row, int E)
{
if(E == -1)
{
row_print(row, 2, "ID");
row_print(row, 5, "Virtual");
row_print(row, 14, "Physical");
row_print(row, 23, "Size");
row_print(row, 28, "Mode");
row_print(row, 34, "SH");
row_print(row, 37, "WT");
row_print(row, 40, "C");
row_print(row, 42, "D");
row_print(row, 44, "V");
return;
}
utlb_addr_t addr = *utlb_addr(E);
utlb_data_t data = *utlb_data(E);
uint32_t src = addr.VPN << 10;
uint32_t dst = data.PPN << 10;
int valid = (addr.V != 0) && (data.V != 0);
int size = (data.SZ1 << 1) | data.SZ2;
char const *size_str[] = { "1k", "4k", "64k", "1M" };
char const *access_str[] = { "K:r", "K:rw", "U:r", "U:rw" };
uint16_t fg = valid ? C_BLACK : C_RGB(24,24,24);
#define fg_ fg, C_NONE
row_print_color(row, 2, fg_, "%d", E);
row_print_color(row, 5, fg_, "%08X", src);
row_print_color(row, 14, fg_, "%08X", dst);
row_print_color(row, 23, fg_, "%s", size_str[size]);
row_print_color(row, 28, fg_, "%s", access_str[data.PR]);
row_print_color(row, 34, fg_, "%s", (data.SH ? "SH" : "-"));
row_print_color(row, 37, fg_, "%s", (data.WT ? "WT" : "CB"));
row_print_color(row, 40, fg_, "%s", (data.C ? "C" : "-"));
row_print_color(row, 42, fg_, "%s", (addr.D || data.D ? "D" : "-"));
row_print_color(row, 44, fg_, "%s", (addr.V && data.V ? "V" : "-"));
}
#endif
#ifdef FX9860G
void show_utlb(int row, int E)
{
extern font_t font_hexa;
font_t const *old_font = dfont(&font_hexa);
int y = (row - 1) * 6;
if(E == -1)
{
dprint( 1, y, C_, "ID");
dprint(12, y, C_, "Virtual");
dprint(47, y, C_, "Physical");
dprint(82, y, C_, "Len");
dprint(98, y, C_, "Mode");
dfont(old_font);
return;
}
utlb_addr_t addr = *utlb_addr(E);
utlb_data_t data = *utlb_data(E);
uint32_t src = addr.VPN << 10;
uint32_t dst = data.PPN << 10;
int valid = (addr.V != 0) && (data.V != 0);
int size = (data.SZ1 << 1) | data.SZ2;
char const *size_str[] = { "1k", "4k", "64k", "1M" };
char const *access_str[] = { "K:r", "K:rw", "U:r", "U:rw" };
dprint( 1, y, C_, "%d", E);
if(valid)
{
dprint(12, y, C_, "%08X", src);
dprint(47, y, C_, "%08X", dst);
dprint(82, y, C_, "%s", size_str[size]);
dprint(98, y, C_, "%s", access_str[data.PR]);
}
dfont(old_font);
}
#endif
static void draw(int tab, uint8_t *pages, uint32_t next_miss, int tlb_scroll)
{
extern uint32_t srom;
uint32_t rom_size = (uint32_t)&srom;
int rom_pages = (rom_size + (1 << 12)-1) >> 12;
#ifdef FX9860G
if(tab != 2)
#endif
row_title(_("TLB management", "TLB miss handler and TLB management"));
if(tab == 0)
{
row_print(_(2,1), 1, _("srom=%x (%d pages)",
"Size of ROM sections: %08X (%d pages of 4k)"),
rom_size, rom_pages);
for(uint p=0, y=_(19,36); p < PAGE_COUNT; p += 2*LINE_SIZE)
{
dprint(_(4,18), y, C_, _("%06x","%08X"),
0x00300000 + (p << 12));
y += 2*SQUARE_HEIGHT;
}
for(uint p = 0; p < PAGE_COUNT; p++)
{
draw_rom_cell(_(44,88) + rom_cell_x(p),
_(20,36) + rom_cell_y(p), pages[p]);
}
#ifdef FXCG50
if(next_miss != 0xffffffff)
{
uint p = (next_miss - 0x00300000) >> 12;
draw_rom_cell(88+rom_cell_x(p), 36+rom_cell_y(p), -1);
row_print(12, 1, "Next page to load: %08X", next_miss);
}
else
{
row_print(12, 1, "No page left to load!");
}
row_print(13, 1, "See INFO tab for details.");
#endif
}
else if(tab == 1)
{
row_print(_(2,1), 1, "Legend:");
draw_rom_cell(_(8,18), _(17,36), 0);
draw_rom_cell(_(64,200), _(17,36), 1);
draw_rom_cell(_(8,18), _(25,50), 2);
draw_rom_cell(_(64,200), _(25,50), 3);
dprint(_(16,30), _(16,36), C_,
_("Unused", "Unused in add-in"));
dprint(_(72,212), _(16,36), C_,
_("Unmapped", "Currently unmapped"));
dprint(_(16,30), _(24,50), C_,
_("Mapped?", "Strangely mapped?!"));
dprint(_(72,212), _(24,50), C_,
_("Mapped", "Currently mapped"));
#ifdef FXCG50
draw_rom_cell(18, 64, -1);
dprint(30, 64, C_, "Next page to load");
row_print(6, 1,
"The MISS key will load an unmapped page to TLB by");
row_print(7, 1,
"performing a TLB miss, which calls %%003 on fx9860g");
row_print(8, 1,
"and %%00c on fxcg50. The TIMER key performs a TLB");
row_print(9, 1,
"miss from a timer callback.");
row_print(11, 1,
"Sometimes the page might be loaded by code or");
row_print(12, 1,
"data before the intended TLB miss occurs.");
#endif
#ifdef FX9860G
if(next_miss != 0xffffffff)
row_print(5, 1, "Next load: %x", next_miss);
else
row_print(5, 1, "No page left to load!");
row_print(6, 1, "MISS: TLB miss");
row_print(7, 1, "TIMER: From timer");
#endif
}
else if(tab == 2)
{
show_utlb(1, -1);
for(int i = 0; i < TLB_VIEW; i++)
show_utlb(i+2, tlb_scroll+i);
if(tlb_scroll > 0) triangle_up(_(7,38));
if(tlb_scroll < TLB_VIEW_MAX) triangle_down(_(49,192));
}
#ifdef FX9860G
extern bopti_image_t img_opt_gint_tlb;
dimage(0, 56, &img_opt_gint_tlb);
#endif
#ifdef FXCG50
fkey_menu(1, "ROM");
fkey_menu(2, "INFO");
fkey_menu(3, "TLB");
fkey_action(5, "MISS");
fkey_action(6, "TIMER");
#endif
}
static int generate_tlb_miss(volatile void *arg)
{
uint8_t volatile *next_miss = arg;
GUNUSED uint8_t volatile x = *next_miss;
return 1;
}
/* gintctl_gint_tlb(): TLB miss handler and TLB management */
void gintctl_gint_tlb(void)
{
key_event_t ev;
int key=0, tab=0;
uint8_t pages[PAGE_COUNT];
uint32_t next_miss = 0xffffffff;
int tlb_scroll = 0;
while(key != KEY_EXIT)
{
dclear(C_WHITE);
if(tab == 0 || tab == 1)
explore_pages(pages, &next_miss);
draw(tab, pages, next_miss, tlb_scroll);
dupdate();
key = (ev = getkey()).key;
if(key == KEY_F1) tab = 0;
if(key == KEY_F2) tab = 1;
if(key == KEY_F3) tab = 2;
if(tab == 2 && key == KEY_UP)
{
if(ev.shift) tlb_scroll = 0;
else if(tlb_scroll > 0) tlb_scroll--;
}
if(tab == 2 && key == KEY_DOWN)
{
if(ev.shift) tlb_scroll = TLB_VIEW_MAX;
else if (tlb_scroll < TLB_VIEW_MAX) tlb_scroll++;
}
if(key == KEY_F5 && next_miss != 0xffffffff)
{
GUNUSED uint8_t volatile x;
x = *(uint8_t volatile *)next_miss;
}
if(key == KEY_F6 && next_miss != 0xffffffff)
{
timer_setup(1, timer_delay(1, 10000), timer_default,
generate_tlb_miss, (volatile void *)next_miss);
timer_start(1);
timer_wait(1);
}
}
}

View File

@ -39,8 +39,10 @@ struct menu menu_gint = {
{ "RAM discovery", gintctl_gint_ram },
{ "Memory dump", gintctl_gint_dump },
{ "Switching to OS", gintctl_gint_switch },
{ "TLB management", gintctl_gint_tlb },
{ "Keyboard", gintctl_gint_keyboard },
{ "Timers", gintctl_gint_timer },
{ "Timer callbacks", gintctl_gint_timer_callbacks },
#ifdef FXCG50
{ "DMA Control", gintctl_gint_dma },
#endif

View File

@ -9,7 +9,7 @@
/* Code of exception that occurs during a memory access */
static uint32_t exception = 0;
/* Exception-catching function */
static int catch_exc(uint32_t code)
GMAPPED static int catch_exc(uint32_t code)
{
if(code == 0x040 || code == 0x0e0)
{
@ -25,7 +25,7 @@ int line(uint8_t *mem, char *header, char *bytes, char *ascii, int n)
/* First do a naive access to the first byte, and record possible
exceptions - TLB miss read and CPU read error.
I use a volatile asm statement so that the read can't be optimized
away by the compiler. */
away or moved by the compiler. */
exception = 0;
gint_exc_catch(catch_exc);
uint8_t z;

View File

@ -62,6 +62,18 @@ void row_print(int row, int x, char const *format, ...)
str, C_BLACK, C_NONE);
}
/* row_print_color(): Formatted printing... with custom colors! */
void row_print_color(int row, int x, int fg, int bg, char const *format, ...)
{
if(row < _(0,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, fg, bg);
}
/* row_highlight(): Invert a row's pixels to highlight it */
void row_highlight(int row)
{