Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
827 lines
22 KiB
C
827 lines
22 KiB
C
// ____________________________
|
|
// ██▀▀█▀▀██▀▀▀▀▀▀▀█▀▀█ │ ▄▄▄ ▄▄
|
|
// ██ ▀ █▄ ▀██▄ ▀ ▄█ ▄▀▀ █ │ ▀█▄ ▄▀██ ▄█▄█ ██▀▄ ██ ▄███
|
|
// █ █ █ ▀▀ ▄█ █ █ ▀▄█ █▄ │ ▄▄█▀ ▀▄██ ██ █ ██▀ ▀█▄ ▀█▄▄
|
|
// ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀────────┘ ▀▀
|
|
// MSX-DOS sample
|
|
//─────────────────────────────────────────────────────────────────────────────
|
|
|
|
#include "msxgl.h"
|
|
#include "dos.h"
|
|
#include "dos_mapper.h"
|
|
#include "extbios.h"
|
|
#include "memory.h"
|
|
#include "string.h"
|
|
|
|
//=============================================================================
|
|
// DEFINES
|
|
//=============================================================================
|
|
|
|
// Library's logo
|
|
#define MSX_GL "\x01\x02\x03\x04\x05\x06"
|
|
|
|
#define TAB_X (128+16)
|
|
#define TAB_Y 32
|
|
|
|
#define PAGE_X 320
|
|
#define PAGE_Y 8
|
|
|
|
|
|
//=============================================================================
|
|
// READ-ONLY DATA
|
|
//=============================================================================
|
|
|
|
// Fonts
|
|
#include "font/font_mgl_sample6.h"
|
|
|
|
// Character animation
|
|
const u8 g_ChrAnim[] = { '|', '\\', '-', '/' };
|
|
|
|
//=============================================================================
|
|
// MEMORY DATA
|
|
//=============================================================================
|
|
|
|
// String buffer
|
|
c8 g_StrBuffer[128];
|
|
|
|
// String buffer
|
|
c8 g_SlotBuffer[4];
|
|
|
|
// File I/O buffer
|
|
u8 g_FileBuffer[4096]; // 32 lines of 4-bits data
|
|
|
|
// Log line
|
|
u8 g_LogLine = 120;
|
|
|
|
// Last segment
|
|
DOS_Segment g_LastSeg;
|
|
|
|
// Page 2 segment number
|
|
u8 g_Page2Seg;
|
|
|
|
// Frame counter
|
|
u8 g_Frame = 0;
|
|
|
|
// Previous KB row #0 value
|
|
u8 g_PrevRow0 = 0x00;
|
|
|
|
//=============================================================================
|
|
// FUNCTIONS
|
|
//=============================================================================
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Print Slot ID
|
|
void Print_DrawSlot(u8 slot)
|
|
{
|
|
Print_DrawInt(Sys_SlotGetPrimary(slot));
|
|
if (Sys_SlotIsExpended(slot))
|
|
{
|
|
Print_DrawChar('-');
|
|
Print_DrawInt(Sys_SlotGetSecondary(slot));
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Format slot ID
|
|
const c8* FormatSlot(u8 slot)
|
|
{
|
|
c8* str = g_SlotBuffer;
|
|
*str++ = '0' + Sys_SlotGetPrimary(slot);
|
|
if (Sys_SlotIsExpended(slot))
|
|
{
|
|
*str++ = '-';
|
|
*str++ = '0' + Sys_SlotGetSecondary(slot);
|
|
}
|
|
*str = 0;
|
|
return g_SlotBuffer;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display program header
|
|
void DisplayDOSHeader()
|
|
{
|
|
DOS_ClearScreen();
|
|
DOS_StringOutput("+--------------------------+\n\r$");
|
|
DOS_StringOutput("| MSXgl - MSX-DOS 2 SAMPLE |\n\r$");
|
|
DOS_StringOutput("+--------------------------+\n\r$");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display machine information
|
|
void DisplayInfo()
|
|
{
|
|
// Program header
|
|
DisplayDOSHeader();
|
|
|
|
// Display VDP version
|
|
u8 vdp = VDP_GetVersion();
|
|
switch (vdp)
|
|
{
|
|
case VDP_VERSION_TMS9918A: DOS_StringOutput("VDP: MSX1\n\r$"); break;
|
|
case VDP_VERSION_V9938: DOS_StringOutput("VDP: MSX2\n\r$"); break;
|
|
case VDP_VERSION_V9958: DOS_StringOutput("VDP: MSX2+\n\r$"); break;
|
|
default: DOS_StringOutput("VDP: Unknow\n\r$");
|
|
}
|
|
|
|
// // Display MSX-DOS version
|
|
DOS_Version ver;
|
|
u8 v = DOS_GetVersion(&ver);
|
|
String_Format(g_StrBuffer, "Version: %d (Kernel: %1x.%2x | System: %1x.%2x)\n\r$", v, ver.Kernel >> 8, ver.Kernel & 0x00FF, ver.System >> 8, ver.System & 0x00FF);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
|
|
// Display error explanation
|
|
DOS_StringOutput("Explain 'IBDOS': $");
|
|
DOS_Explain(DOS_ERR_IBDOS, g_StrBuffer);
|
|
c8* ptr = g_StrBuffer;
|
|
while (*ptr++) {}
|
|
*ptr = '$';
|
|
DOS_StringOutput(g_StrBuffer);
|
|
DOS_Return();
|
|
|
|
// Display default disk parameters
|
|
DOS_DiskParam param;
|
|
u8 err = DOS_GetDiskParam(DOS_DRIVE_DEFAULT, ¶m);
|
|
DOS_StringOutput("Default disk paramters:\n\r$");
|
|
String_Format(g_StrBuffer, "- Physical drive number: %c\n\r$", 'A' - 1 + param.DriveNum);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Sector size: %d\n\r$", param.SectorSize);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Sectors per cluster: %d\n\r$", param.ClusterSectors);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Number of reserved sectors: %d\n\r$", param.ReservedSectors);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Number of copies of the FAT: %d\n\r$", param.FATNum);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Number of root directory entries: %d\n\r$", param.RootNum);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Total number of logical sectors: %d\n\r$", param.LogicalSectors);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Media descriptor byte: %d\n\r$", param.Media);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Number of sectors per FAT: %d\n\r$", param.FATSectors);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- First root directory sector number: %d\n\r$", param.RootSector);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- First data sector number: %d\n\r$", param.DataSector);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Maximum cluster number: %d\n\r$", param.MaxClusters);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Dirty disk flag: %d\n\r$", param.DirtyFlag);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
String_Format(g_StrBuffer, "- Volume id.: %d\n\r$", param.VolumeID);
|
|
DOS_StringOutput(g_StrBuffer);
|
|
|
|
DOS_StringOutput("\n\rPRESS A KEY...$");
|
|
DOS_CharInput();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Wait for key press
|
|
void WaitKeyPress()
|
|
{
|
|
Print_DrawText("\nPRESS ANY KEY...");
|
|
DOS_CharInput();
|
|
}
|
|
|
|
#if (DOS_USE_VALIDATOR)
|
|
//-----------------------------------------------------------------------------
|
|
// Display last error
|
|
void DisplayLastError()
|
|
{
|
|
u8 err = DOS_GetLastError();
|
|
DOS_Explain(err, g_StrBuffer);
|
|
Print_DrawFormat("Error!\n%2x: %s\n", err, g_StrBuffer);
|
|
WaitKeyPress();
|
|
BIOS_Exit(0);
|
|
}
|
|
#endif
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display the page header
|
|
void DisplayHeader()
|
|
{
|
|
Print_Clear();
|
|
Print_SetPosition(0, 0);
|
|
Print_DrawText(MSX_GL " MSX-DOS 2 Sample");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display a file content
|
|
void DisplayFile()
|
|
{
|
|
// Initialize display system
|
|
VDP_SetMode(VDP_MODE_SCREEN5);
|
|
VDP_EnableSprite(FALSE);
|
|
VDP_SetColor(0x4);
|
|
|
|
u8 err;
|
|
|
|
// Start bitmap screen
|
|
Print_SetBitmapFont(g_Font_MGL_Sample6);
|
|
Print_SetColor(0xFF, 0x44);
|
|
DisplayHeader();
|
|
|
|
// Change current directory
|
|
Print_SetPosition(0, 16);
|
|
const DOS_Time* time = DOS_GetTime();
|
|
String_Format(g_StrBuffer, "\x07""Time... %02d/%02d/%02d %02d:%02d:%02d\n", time->Year, time->Month, time->Date, time->Hour, time->Minute, time->Second);
|
|
Print_DrawText(g_StrBuffer);
|
|
|
|
// Change current directory
|
|
String_Format(g_StrBuffer, "%02d%02d%02d%\0", time->Hour, time->Minute, time->Second);
|
|
Print_DrawFormat("\x07""Create %s directory... ", g_StrBuffer);
|
|
DOS_FCreate(g_StrBuffer, O_RDWR, ATTR_FOLDER);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err == DOS_ERR_NONE)
|
|
Print_DrawText("OK\n");
|
|
else if (err = DOS_ERR_DIRX)
|
|
Print_DrawText(" Warning\n Directory already exists\n");
|
|
else
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#else
|
|
Print_DrawText("OK\n");
|
|
#endif
|
|
|
|
Print_DrawFormat("\x07""Change current directory to %s... ", g_StrBuffer);
|
|
DOS_ChangeDirectory(g_StrBuffer);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
|
|
Print_DrawText("\x07""Get current directory... ");
|
|
DOS_GetDirectory(DOS_DRIVE_DEFAULT, g_FileBuffer);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
Print_DrawFormat(" Current directory: %s\n", g_FileBuffer);
|
|
|
|
Print_DrawText("\x07""Go back to parent (\"..\") directory ... ");
|
|
DOS_ChangeDirectory("..");
|
|
Print_DrawText("OK\n");
|
|
|
|
// Search
|
|
Print_DrawText("\x07""Searching for '*.sc5'... ");
|
|
DOS_FIB* fib = DOS_FindFirstEntry("*.SC5", 0);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
while (fib)
|
|
{
|
|
Print_DrawFormat(" Found: %s\n", fib->Filename);
|
|
fib = DOS_FindNextEntry();
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
#endif
|
|
}
|
|
|
|
WaitKeyPress();
|
|
|
|
// Start bitmap screen
|
|
Print_SetBitmapFont(g_Font_MGL_Sample6);
|
|
Print_SetColor(0xFF, 0x44);
|
|
DisplayHeader();
|
|
|
|
// Open
|
|
Print_SetPosition(0, 16);
|
|
Print_DrawText("\x07""Opening 'image01.sc5'... ");
|
|
u8 file = DOS_FOpen("IMAGE01.SC5", O_RDONLY);
|
|
#if (DOS_USE_VALIDATOR)
|
|
if (file == 0xFF)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawFormat("OK (%d)\n", file);
|
|
|
|
// Seek
|
|
Print_DrawText("\x07""Seeking 7 bytes (skip header)... ");
|
|
u32 seek = DOS_FSeek(file, 7, SEEK_SET);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
|
|
// Seek
|
|
Print_DrawText("\x07""Seeking 2 KB (16 lines)... ");
|
|
seek = DOS_FSeek(file, 2048, SEEK_CUR);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
|
|
// Read
|
|
Print_DrawText("\x07""Reading 4 KB (32 lines)... ");
|
|
u16 read = DOS_FRead(file, g_FileBuffer, 4096);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
VDP_WriteVRAM_128K(g_FileBuffer, 128 * g_PrintData.CursorY, 0, 4096);
|
|
|
|
// Close
|
|
g_PrintData.CursorY += 32;
|
|
Print_DrawText("\x07""Closing 'image01.sc5'... ");
|
|
err = DOS_FClose(file);
|
|
#if (DOS_USE_VALIDATOR)
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
|
|
// Create folder
|
|
Print_Return();
|
|
Print_DrawText("\x07""Creating 'tmp' directory... ");
|
|
file = DOS_FCreate("tmp", O_RDWR, ATTR_FOLDER);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err == DOS_ERR_NONE)
|
|
Print_DrawText("OK\n");
|
|
else if (err = DOS_ERR_DIRX)
|
|
Print_DrawText(" Warning\n Directory already exists\n");
|
|
else
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#else
|
|
Print_DrawText("OK\n");
|
|
#endif
|
|
|
|
// Create file
|
|
Print_DrawText("\x07""Creating 'tmp\\a.bin' file... ");
|
|
file = DOS_FCreate("tmp\\a.bin", O_RDWR, 0);
|
|
#if (DOS_USE_VALIDATOR)
|
|
if (file == 0xFF)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawFormat("OK (%d)\n", file);
|
|
|
|
// Write
|
|
Print_DrawText("\x07""Writing 4 KB (32 lines)... ");
|
|
u16 write = DOS_FWrite(file, g_FileBuffer, 4096);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
|
|
// Seek
|
|
Print_DrawText("\x07""Rewinding file... ");
|
|
seek = DOS_FSeek(file, 0, SEEK_SET);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
|
|
// Read
|
|
Print_DrawText("\x07""Reading 4 KB (32 lines)... ");
|
|
read = DOS_FRead(file, g_FileBuffer, 4096);
|
|
#if (DOS_USE_VALIDATOR)
|
|
err = DOS_GetLastError();
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
VDP_WriteVRAM_128K(g_FileBuffer, 128 * g_PrintData.CursorY, 0, 4096);
|
|
|
|
// Close
|
|
g_PrintData.CursorY += 32;
|
|
Print_DrawText("\x07""Closing 'tmp\\a.bin'... ");
|
|
err = DOS_FClose(file);
|
|
#if (DOS_USE_VALIDATOR)
|
|
if (err != DOS_ERR_NONE)
|
|
{
|
|
DisplayLastError();
|
|
return;
|
|
}
|
|
#endif
|
|
Print_DrawText("OK\n");
|
|
|
|
WaitKeyPress();
|
|
BIOS_Exit(0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Apply Memory Mapper
|
|
void ApplyExtBIOS()
|
|
{
|
|
// Mapper information
|
|
u16 TotalNumSeg = 0;
|
|
u16 TotalFreeSeg = 0;
|
|
u16 TotalSysSeg = 0;
|
|
u16 TotalUserSeg = 0;
|
|
|
|
VDP_CommandHMMV(TAB_X, TAB_Y, 512-TAB_X, 48, 0x44); // Clear
|
|
DOS_VarTable* tab = DOSMapper_GetVarTable();
|
|
u8 i = 0;
|
|
u16 x = TAB_X;
|
|
while (tab->Slot != 0)
|
|
{
|
|
Print_SetPosition(x, TAB_Y);
|
|
Print_DrawFormat("#%i", i);
|
|
|
|
Print_SetPosition(x, TAB_Y+8);
|
|
Print_DrawSlot(tab->Slot);
|
|
|
|
Print_SetPosition(x, TAB_Y+16);
|
|
Print_DrawInt(tab->NumSeg);
|
|
TotalNumSeg+= tab->NumSeg;
|
|
|
|
Print_SetPosition(x, TAB_Y+24);
|
|
Print_DrawInt(tab->FreeSeg);
|
|
TotalFreeSeg+= tab->FreeSeg;
|
|
|
|
Print_SetPosition(x, TAB_Y+32);
|
|
Print_DrawInt(tab->SysSeg);
|
|
TotalSysSeg+= tab->SysSeg;
|
|
|
|
Print_SetPosition(x, TAB_Y+40);
|
|
Print_DrawInt(tab->UserSeg);
|
|
TotalUserSeg+= tab->UserSeg;
|
|
|
|
x += 40;
|
|
i++;
|
|
tab++;
|
|
}
|
|
|
|
Print_SetPosition(x, TAB_Y);
|
|
Print_DrawText("Total");
|
|
|
|
Print_SetPosition(x, TAB_Y+16);
|
|
Print_DrawInt(TotalNumSeg);
|
|
if (TotalNumSeg < 64)
|
|
Print_DrawFormat(" (%iK)", TotalNumSeg * 16);
|
|
else if (TotalNumSeg % 64 == 0)
|
|
Print_DrawFormat(" (%iM)", TotalNumSeg / 64);
|
|
else
|
|
Print_DrawFormat(" (%iM+%iK)", TotalNumSeg / 64, (TotalNumSeg % 64) * 16);
|
|
|
|
Print_SetPosition(x, TAB_Y+24);
|
|
Print_DrawInt(TotalFreeSeg);
|
|
|
|
Print_SetPosition(x, TAB_Y+32);
|
|
Print_DrawInt(TotalSysSeg);
|
|
|
|
Print_SetPosition(x, TAB_Y+40);
|
|
Print_DrawInt(TotalUserSeg);
|
|
|
|
// Page information
|
|
VDP_CommandHMMV(PAGE_X, PAGE_Y+8, 512-PAGE_X, 8, 0x44); // Clear
|
|
x = PAGE_X;
|
|
for (u8 i = 0; i < 4; ++i)
|
|
{
|
|
Print_SetPosition(x, 16);
|
|
Print_DrawInt(DOSMapper_GetPage(i));
|
|
x += 6*5;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display Extended BIOS information
|
|
void DisplayExtBIOS()
|
|
{
|
|
// Initialize display system
|
|
VDP_SetMode(VDP_MODE_SCREEN7);
|
|
VDP_EnableSprite(FALSE);
|
|
VDP_SetColor(0x4);
|
|
|
|
// Start bitmap screen
|
|
Print_SetBitmapFont(g_Font_MGL_Sample6);
|
|
Print_SetColor(0xFF, 0x44);
|
|
Print_Clear();
|
|
Print_SetPosition(0, 0);
|
|
Print_DrawText(MSX_GL " MSX-DOS 2 Sample");
|
|
|
|
Print_SetPosition(PAGE_X, PAGE_Y);
|
|
Print_DrawText("P0 P1 P2 P3");
|
|
|
|
// Check Extended BIOS
|
|
Print_SetPosition(0, 16);
|
|
if (ExtBIOS_Check())
|
|
Print_DrawText("Extended BIOS: Detected\n");
|
|
else
|
|
Print_DrawText("Extended BIOS: Not detected\n");
|
|
|
|
// Memory mapper variables
|
|
Print_SetPosition(0, 24);
|
|
u8 a = DOSMapper_Init();
|
|
|
|
Print_DrawFormat("Jump table: %4xh\n", g_DOS_JumpTable);
|
|
Print_DrawText("Memory Mapper table:\n");
|
|
Print_DrawText("- Slot:\n");
|
|
Print_DrawText("- Segments number:\n");
|
|
Print_DrawText("- Free segments:\n");
|
|
Print_DrawText("- System segments:\n");
|
|
Print_DrawText("- User segments:\n\n");
|
|
Print_DrawText("ALLOC: [1] User Prim [2] User Not Prim [3] Sys Prim 1st\n");
|
|
Print_DrawText("FREE: [4] Last Seg MAPPER: [5] Inc Page 2 [6] Dec Page 2\n\n");
|
|
Print_DrawText("Log:\n");
|
|
|
|
g_Page2Seg = DOSMapper_GetPage2();
|
|
|
|
ApplyExtBIOS();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Log a message
|
|
void Log(const c8* str)
|
|
{
|
|
if (g_LogLine > 190)
|
|
{
|
|
VDP_CommandHMMV(0, 120, 512, 72, 0x44);
|
|
g_LogLine = 120;
|
|
}
|
|
|
|
Print_SetPosition(0, g_LogLine);
|
|
Print_DrawText(str);
|
|
g_LogLine += 8;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update Extended BIOS
|
|
void UpdateExtBIOS()
|
|
{
|
|
// Print sign-of-life
|
|
Print_SetPosition(512-8, 0);
|
|
Print_DrawChar(g_ChrAnim[g_Frame >> 2 & 0x03]);
|
|
|
|
u8 row0 = ~Keyboard_Read(0);
|
|
u8 keys = (row0 ^ g_PrevRow0) & row0;
|
|
g_PrevRow0 = row0;
|
|
|
|
// Allocate user segment from primary Memory mapper's slot
|
|
if (KEY_FLAG(KEY_1) & keys)
|
|
{
|
|
bool ok = DOSMapper_Alloc(DOS_ALLOC_USER, DOS_SEGSLOT_PRIM, &g_LastSeg);
|
|
String_Format(g_StrBuffer, "- %s: Allocate user segment from primary slot [slot:%s, seg:%d]", ok ? "Succed" : "Error", FormatSlot(g_LastSeg.Slot), g_LastSeg.Number);
|
|
Log(g_StrBuffer);
|
|
for (u8 i = 0; i < 4; ++i)
|
|
DOSMapper_WriteByte(g_LastSeg.Number, i, i);
|
|
ApplyExtBIOS();
|
|
}
|
|
|
|
// Allocate user segment from Memory mapper's slot other than primary one
|
|
if (KEY_FLAG(KEY_2) & keys)
|
|
{
|
|
bool ok = DOSMapper_Alloc(DOS_ALLOC_USER, g_DOS_VarTable->Slot | DOS_SEGSLOT_OTHER, &g_LastSeg);
|
|
String_Format(g_StrBuffer, "- %s: Allocate user segment from not-primary slot [slot:%s, seg:%d]", ok ? "Succed" : "Error", FormatSlot(g_LastSeg.Slot), g_LastSeg.Number);
|
|
Log(g_StrBuffer);
|
|
ApplyExtBIOS();
|
|
}
|
|
|
|
// Allocate system segment from primary Memory mapper's slot in priority
|
|
if (KEY_FLAG(KEY_3) & keys)
|
|
{
|
|
bool ok = DOSMapper_Alloc(DOS_ALLOC_SYS, g_DOS_VarTable->Slot | DOS_SEGSLOT_THISFIRST, &g_LastSeg);
|
|
String_Format(g_StrBuffer, "- %s: Allocate system segment from primary slot in priority [slot:%s, seg:%d]", ok ? "Succed" : "Error", FormatSlot(g_LastSeg.Slot), g_LastSeg.Number);
|
|
Log(g_StrBuffer);
|
|
ApplyExtBIOS();
|
|
}
|
|
|
|
// Free last allocated segment
|
|
if (KEY_FLAG(KEY_4) & keys)
|
|
{
|
|
if (g_LastSeg.Slot == SLOT_INVALID)
|
|
{
|
|
String_Format(g_StrBuffer, "- Error: Invalid last segment");
|
|
}
|
|
else
|
|
{
|
|
bool ok = DOSMapper_Free(g_LastSeg.Number, g_LastSeg.Slot);
|
|
String_Format(g_StrBuffer, "- %s: Free a segment [slot:%s, seg:%d]", ok ? "Succed" : "Error", FormatSlot(g_LastSeg.Slot), g_LastSeg.Number);
|
|
g_LastSeg.Slot = SLOT_INVALID;
|
|
}
|
|
Log(g_StrBuffer);
|
|
ApplyExtBIOS();
|
|
}
|
|
|
|
// Set page to next segment on the primary slot
|
|
if (KEY_FLAG(KEY_5) & keys)
|
|
{
|
|
DOSMapper_SetPage2(++g_Page2Seg);
|
|
u8 tab[8];
|
|
for (u8 i = 0; i < 8; ++i)
|
|
tab[i] = DOSMapper_ReadByte(g_Page2Seg, i);
|
|
String_Format(g_StrBuffer, "- Switch page 2 to segment %d. 8000h:[%2x %2x %2x %2x %2x %2x %2x %2x]", g_Page2Seg, tab[0], tab[1], tab[2], tab[3], tab[4], tab[5], tab[6], tab[7]);
|
|
Log(g_StrBuffer);
|
|
ApplyExtBIOS();
|
|
}
|
|
|
|
// Set page to previous segment on the primary slot
|
|
if (KEY_FLAG(KEY_6) & keys)
|
|
{
|
|
DOSMapper_SetPage2(--g_Page2Seg);
|
|
u8 tab[8];
|
|
for (u8 i = 0; i < 8; ++i)
|
|
tab[i] = DOSMapper_ReadByte(g_Page2Seg, i);
|
|
String_Format(g_StrBuffer, "- Switch page 2 to segment %d. 8000h:[%2x %2x %2x %2x %2x %2x %2x %2x]", g_Page2Seg, tab[0], tab[1], tab[2], tab[3], tab[4], tab[5], tab[6], tab[7]);
|
|
Log(g_StrBuffer);
|
|
ApplyExtBIOS();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Display standard input
|
|
void DisplayStdIn()
|
|
{
|
|
// Program header
|
|
DisplayDOSHeader();
|
|
|
|
DOS_StringOutput("\n\r$");
|
|
DOS_StringOutput("Press keys:\n\r$");
|
|
DOS_StringOutput("> $");
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Get a character from standard input
|
|
u8 DOS_StandardInput() __NAKED
|
|
{
|
|
__asm
|
|
push ix
|
|
ld e, #0xFF
|
|
ld c, #DOS_FUNC_DIRIO
|
|
call BDOS
|
|
pop ix
|
|
ret // Return value in A
|
|
__endasm;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Put a character to standard output
|
|
void DOS_StandardOutput(u8 chr)
|
|
{
|
|
chr; // A
|
|
__asm
|
|
push ix
|
|
ld e, a
|
|
ld c, #DOS_FUNC_DIRIO
|
|
call BDOS
|
|
pop ix
|
|
__endasm;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Update standard input
|
|
void UpdateStdIn()
|
|
{
|
|
u8 chr = DOS_StandardInput();
|
|
if (chr)
|
|
DOS_StandardOutput(chr);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Call driver and display result
|
|
void DisplayDriver()
|
|
{
|
|
// Program header
|
|
DisplayDOSHeader();
|
|
DOS_StringOutput("== START DRIVER AT 0xE000 ==\n\r$");
|
|
|
|
// Load driver to memory
|
|
DOS_StringOutput("Opening 'sample.drv'...\n\r$");
|
|
u8 file = DOS_FOpen("SAMPLE.DRV", O_RDONLY); // open
|
|
u32 size = DOS_FSeek(file, 0, SEEK_END); // get size
|
|
DOS_FSeek(file, 0, SEEK_SET); // rewind
|
|
DOS_FRead(file, (void*)0xE000, size); // load
|
|
DOS_FClose(file); // close
|
|
|
|
// Starting driver
|
|
DOS_StringOutput("Starting driver...\n\r$");
|
|
u8 val = CallDriver(0xE000, 12);
|
|
|
|
DOS_StringOutput("\n\rPRESS A KEY...$");
|
|
DOS_CharInput();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Program entry point
|
|
u8 main(u8 argc, const c8** argv)
|
|
{
|
|
c8 chr = 0;
|
|
if (argc > 0)
|
|
chr = argv[0][0];
|
|
|
|
DisplayMenu:
|
|
|
|
// Program header
|
|
DisplayDOSHeader();
|
|
|
|
DOS_StringOutput(" [1] System information\n\r$");
|
|
DOS_StringOutput(" [2] File handling (Screen 5)\n\r$");
|
|
DOS_StringOutput(" [3] Memory mapper (Screen 7)\n\r$");
|
|
DOS_StringOutput(" [4] Standard input\n\r$");
|
|
DOS_StringOutput(" [5] Load and execute driver\n\r$");
|
|
DOS_StringOutput(" [Q] Quit\n\r$");
|
|
|
|
callback cbUpdate = NULL;
|
|
if (chr == 0)
|
|
chr = DOS_CharInput();
|
|
switch (chr)
|
|
{
|
|
case '1':
|
|
DisplayInfo();
|
|
chr = 0;
|
|
goto DisplayMenu;
|
|
|
|
case '2':
|
|
DisplayFile();
|
|
return 1;
|
|
|
|
case '3':
|
|
DisplayExtBIOS();
|
|
cbUpdate = UpdateExtBIOS;
|
|
break;
|
|
|
|
case '4':
|
|
DisplayStdIn();
|
|
cbUpdate = UpdateStdIn;
|
|
break;
|
|
|
|
case '5':
|
|
DisplayDriver();
|
|
chr = 0;
|
|
goto DisplayMenu;
|
|
break;
|
|
|
|
case 'q':
|
|
case 'Q':
|
|
DOS_ClearScreen();
|
|
DOS_Exit(0);
|
|
|
|
default:
|
|
chr = 0;
|
|
goto DisplayMenu;
|
|
}
|
|
|
|
while (!Keyboard_IsKeyPressed(KEY_ESC))
|
|
{
|
|
// Naive V-Synch method
|
|
Halt();
|
|
|
|
// Update current page
|
|
if (cbUpdate)
|
|
cbUpdate();
|
|
|
|
// Increment frame counter
|
|
g_Frame++;
|
|
}
|
|
|
|
BIOS_Exit(0);
|
|
return 0; // Can be used only if you don't use VDP module
|
|
} |