Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
340 lines
9.2 KiB
C
340 lines
9.2 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// ROM mapper sample
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
#include "msxgl.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
// Library's logo
|
|
#define MSX_GL "\x01\x02\x03\x04\x05\x06"
|
|
|
|
#if (ROM_MAPPER == ROM_NEO8)
|
|
#define SET_SEGMENT(s) SET_BANK_SEGMENT(4, s)
|
|
#define SET_SEGMENT_LOW(s) SET_BANK_SEGMENT_LOW(4, s)
|
|
#define SET_SEGMENT_HIGH(s) SET_BANK_SEGMENT_HIGH(4, s)
|
|
#define GET_SEGMENT() GET_BANK_SEGMENT(4)
|
|
#define BANK_NUM 6
|
|
#define BANK_SIZE 0x2000
|
|
#define TEST_BANK 4
|
|
#define TEST_ADDR 0x8000
|
|
#elif (ROM_MAPPER == ROM_NEO16)
|
|
#define SET_SEGMENT(s) SET_BANK_SEGMENT(2, s)
|
|
#define SET_SEGMENT_LOW(s) SET_BANK_SEGMENT_LOW(2, s)
|
|
#define SET_SEGMENT_HIGH(s) SET_BANK_SEGMENT_HIGH(2, s)
|
|
#define GET_SEGMENT() GET_BANK_SEGMENT(2)
|
|
#define BANK_NUM 3
|
|
#define BANK_SIZE 0x4000
|
|
#define TEST_BANK 2
|
|
#define TEST_ADDR 0x8000
|
|
#else
|
|
#error Error: Invalide ROM mapper type (ROM_MAPPER)
|
|
#endif
|
|
|
|
#define MIRROR_MASK 0b0000011111111110
|
|
|
|
struct SignEntry
|
|
{
|
|
u16 Segment;
|
|
const c8* Sign;
|
|
};
|
|
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// Fonts
|
|
#include "font/font_mgl_sample6.h"
|
|
|
|
// Animation characters
|
|
const u8 g_ChrAnim[] = { '|', '\\', '-', '/' };
|
|
|
|
// Sample data
|
|
__at(0x00030000) const c8 g_S003Data[] = "S003";
|
|
__at(0x00110000) const c8 g_S011Data[] = "S011";
|
|
__at(0x01110000) const c8 g_S111Data[] = "S111";
|
|
__at(0x01120000) const c8 g_S000Data[] = "S112";
|
|
__at(0x00FF0000) const c8 g_S0FFData[] = "S0FF";
|
|
__at(0x01000000) const c8 g_S100Data[] = "S100";
|
|
__at(0x01230000) const c8 g_S123Data[] = "S123";
|
|
__at(0x01FF0000) const c8 g_S1FFData[] = "S1FF";
|
|
|
|
const struct SignEntry g_Signs[] =
|
|
{
|
|
{ 0x0003, "S003" },
|
|
{ 0x0011, "S011" },
|
|
{ 0x0111, "S111" },
|
|
{ 0x0112, "S112" },
|
|
{ 0x00FF, "S0FF" },
|
|
{ 0x0100, "S100" },
|
|
{ 0x0123, "S123" },
|
|
{ 0x01FF, "S1FF" },
|
|
};
|
|
|
|
const u16 g_SwitchAddr[BANK_NUM] =
|
|
{
|
|
#if (ROM_MAPPER == ROM_NEO8)
|
|
0x5000,
|
|
0x5800,
|
|
0x6000,
|
|
0x6800,
|
|
0x7000,
|
|
0x7800,
|
|
#elif (ROM_MAPPER == ROM_NEO16)
|
|
0x5000,
|
|
0x6000,
|
|
0x7000,
|
|
#endif
|
|
};
|
|
|
|
|
|
//=============================================================================
|
|
// FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
bool CheckSign(const u8* addr, const u8* sign)
|
|
{
|
|
loop (i, 4)
|
|
if (*addr++ != *sign++)
|
|
return FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
void Print_Slot(u8 slot)
|
|
{
|
|
Print_DrawInt(Sys_SlotGetPrimary(slot));
|
|
if (Sys_SlotIsExpended(slot))
|
|
{
|
|
Print_DrawChar('-');
|
|
Print_DrawInt(Sys_SlotGetSecondary(slot));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
const c8* GetTargetType(u8 target)
|
|
{
|
|
switch (target)
|
|
{
|
|
case TYPE_BIN: return "BASIC";
|
|
case TYPE_ROM: return "ROM";
|
|
case TYPE_DOS: return "DOS";
|
|
};
|
|
return "Unknow";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
const c8* GetROMMapper(u8 mapper)
|
|
{
|
|
switch (mapper)
|
|
{
|
|
case ROM_PLAIN: return "Plain";
|
|
case ROM_ASCII8: return "ASCII-8";
|
|
case ROM_ASCII16: return "ASCII-16";
|
|
case ROM_KONAMI: return "Konami";
|
|
case ROM_KONAMI_SCC: return "Konami SCC";
|
|
case ROM_NEO8: return "NEO-8";
|
|
case ROM_NEO16: return "NEO-16";
|
|
case ROM_YAMANOOTO: return "YAMANOOTO";
|
|
case ROM_ASCII16X: return "ASCII16-X";
|
|
};
|
|
return "Unknow";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
const c8* GetROMSize(u8 size)
|
|
{
|
|
switch (size)
|
|
{
|
|
case ROM_8K: return "8 KB";
|
|
case ROM_16K: return "16 KB";
|
|
case ROM_24K: return "24 KB";
|
|
case ROM_32K: return "32 KB";
|
|
case ROM_48K: return "48 KB";
|
|
case ROM_64K: return "64 KB";
|
|
};
|
|
return "Unknow";
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display from address
|
|
void DisplayMemory(u16 addr)
|
|
{
|
|
const u8* ptr = (const u8*)addr;
|
|
loop (i, 28)
|
|
Print_DrawChar(*ptr++);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Interrupt handler
|
|
void VDP_InterruptHandler()
|
|
{
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Program entry point
|
|
void main()
|
|
{
|
|
VDP_SetMode(VDP_MODE_SCREEN0); // Initialize screen mode 0 (text)
|
|
VDP_ClearVRAM();
|
|
|
|
#if (ROM_MAPPER == ROM_NEO8)
|
|
SET_BANK_SEGMENT(0, 4); // Bank 0 (0000-1FFF) = Segment 4
|
|
SET_BANK_SEGMENT(1, 5); // Bank 1 (2000-3FFF) = Segment 5
|
|
SET_BANK_SEGMENT(2, 0); // Bank 2 (4000-5FFF) = Segment 0
|
|
SET_BANK_SEGMENT(3, 1); // Bank 3 (6000-7FFF) = Segment 1
|
|
SET_BANK_SEGMENT(4, 2); // Bank 4 (8000-9FFF) = Segment 2
|
|
SET_BANK_SEGMENT(5, 3); // Bank 5 (A000-BFFF) = Segment 3
|
|
#elif (ROM_MAPPER == ROM_NEO16)
|
|
SET_BANK_SEGMENT(0, 2); // Bank 0 (0000-3FFF) = Segment 2
|
|
SET_BANK_SEGMENT(1, 0); // Bank 1 (4000-7FFF) = Segment 0
|
|
SET_BANK_SEGMENT(2, 1); // Bank 2 (8000-BFFF) = Segment 1
|
|
#endif
|
|
|
|
// Title
|
|
Print_SetTextFont(g_Font_MGL_Sample6, 1); // Initialize font
|
|
Print_DrawText(MSX_GL " NEO MAPPER SAMPLE"); // Display title
|
|
Print_DrawLineH(0, 1, 40);
|
|
|
|
// Information
|
|
Print_SetPosition(0, 2);
|
|
Print_DrawFormat("%s\n\n", TARGET_NAME);
|
|
Print_DrawFormat("Type: %s\n", GetTargetType(TARGET_TYPE));
|
|
Print_DrawFormat("Mapper: %s\n", GetROMMapper(ROM_MAPPER));
|
|
if (ROM_SIZE > 1024)
|
|
Print_DrawFormat("Size: %iMB\n", ROM_SIZE / 1024);
|
|
else
|
|
Print_DrawFormat("Size: %iKB\n", ROM_SIZE);
|
|
Print_DrawFormat("Seg num: %i\n", ROM_SEGMENTS);
|
|
// Slot selection
|
|
loop (i, 4)
|
|
{
|
|
u8 slotId = Sys_GetPageSlot(i);
|
|
Print_SetPosition(20, 4+i);
|
|
Print_DrawFormat("Page[%i]: ", i);
|
|
Print_Slot(slotId);
|
|
}
|
|
Print_DrawLineH(0, 8, 40);
|
|
|
|
Print_SetPosition(0, 8);
|
|
Print_DrawText("\nBank test:");
|
|
loop (b, BANK_NUM)
|
|
{
|
|
u16 s = 0;
|
|
switch (b)
|
|
{
|
|
case 0:
|
|
s = GET_BANK_SEGMENT(0);
|
|
break;
|
|
case 1:
|
|
s = GET_BANK_SEGMENT(1);
|
|
break;
|
|
case 2:
|
|
s = GET_BANK_SEGMENT(2);
|
|
break;
|
|
#if (ROM_MAPPER == ROM_NEO8)
|
|
case 3:
|
|
s = GET_BANK_SEGMENT(3);
|
|
break;
|
|
case 4:
|
|
s = GET_BANK_SEGMENT(4);
|
|
break;
|
|
case 5:
|
|
s = GET_BANK_SEGMENT(5);
|
|
break;
|
|
#endif
|
|
}
|
|
Print_DrawFormat("\n\x7""[%i]->%03i: ", b, s);
|
|
DisplayMemory(BANK_SIZE * b);
|
|
}
|
|
|
|
Print_DrawText("\n\nAccess test:");
|
|
Print_DrawText("\n\x7SET_BANK_SEGMENT() ");
|
|
SET_SEGMENT(0);
|
|
loop (i, numberof(g_Signs))
|
|
{
|
|
const struct SignEntry* e = &g_Signs[i];
|
|
SET_SEGMENT(e->Segment); // Set segment in bank
|
|
Print_DrawText(CheckSign((const u8*)TEST_ADDR, e->Sign) ? "\xC " : "\xB ");
|
|
}
|
|
|
|
Print_DrawText("\n\x7""16b access ");
|
|
SET_SEGMENT(0);
|
|
loop (i, numberof(g_Signs))
|
|
{
|
|
const struct SignEntry* e = &g_Signs[i];
|
|
Poke16(g_SwitchAddr[TEST_BANK], e->Segment); // Set segment in bank
|
|
Print_DrawText(CheckSign((const u8*)TEST_ADDR, e->Sign) ? "\xC " : "\xB ");
|
|
}
|
|
|
|
Print_DrawText("\n\x7""16b access + mask ");
|
|
SET_SEGMENT(0);
|
|
loop (i, numberof(g_Signs))
|
|
{
|
|
const struct SignEntry* e = &g_Signs[i];
|
|
u16 addr = g_SwitchAddr[TEST_BANK] | MIRROR_MASK;
|
|
Poke16(addr, e->Segment); // Set segment in bank
|
|
Print_DrawText(CheckSign((const u8*)TEST_ADDR, e->Sign) ? "\xC " : "\xB ");
|
|
}
|
|
|
|
Print_DrawText("\n\x7""8b access ");
|
|
SET_SEGMENT(0);
|
|
loop (i, numberof(g_Signs))
|
|
{
|
|
const struct SignEntry* e = &g_Signs[i];
|
|
u16 addr = g_SwitchAddr[TEST_BANK];
|
|
switch (i)
|
|
{
|
|
case 0: // 0x0003
|
|
SET_SEGMENT_LOW(0x03);
|
|
break;
|
|
case 1: // 0x0011
|
|
SET_SEGMENT_LOW(0x11);
|
|
break;
|
|
case 2: // 0x0111
|
|
SET_SEGMENT_HIGH(0x01);
|
|
break;
|
|
case 3: // 0x0112
|
|
SET_SEGMENT_LOW(0x12);
|
|
break;
|
|
case 4: // 0x00FF
|
|
SET_SEGMENT_HIGH(0x00);
|
|
SET_SEGMENT_LOW(0xFF);
|
|
break;
|
|
case 5: // 0x0100
|
|
SET_SEGMENT_HIGH(0x01);
|
|
SET_SEGMENT_LOW(0x00);
|
|
break;
|
|
case 6: // 0x0123
|
|
SET_SEGMENT_LOW(0x23);
|
|
break;
|
|
case 7: // 0x01FF
|
|
SET_SEGMENT_LOW(0xFF);
|
|
break;
|
|
}
|
|
Print_DrawText(CheckSign((const u8*)TEST_ADDR, e->Sign) ? "\xC " : "\xB ");
|
|
}
|
|
|
|
|
|
u8 count = 0;
|
|
while (!Keyboard_IsKeyPressed(KEY_ESC))
|
|
{
|
|
Halt();
|
|
|
|
Print_SetPosition(39, 0);
|
|
Print_DrawChar(g_ChrAnim[count++ & 0x03]);
|
|
}
|
|
} |