HatariWii/src/vdi.c

974 lines
28 KiB
C

/*
Hatari - vdi.c
This file is distributed under the GNU General Public License, version 2
or at your option any later version. Read the file gpl.txt for details.
VDI (Virtual Device Interface) (Trap #2)
To get higher resolutions on the Desktop, we intercept the VDI/Line-A calls
and set elements in their structures to the higher width/height/cel/planes.
We need to intercept the initial Line-A call (which we force into the TOS on
boot-up) and also the init calls to the VDI.
*/
const char VDI_fileid[] = "Hatari vdi.c : " __DATE__ " " __TIME__;
#include "main.h"
#include "file.h"
#include "gemdos.h"
#include "m68000.h"
#include "options.h"
#include "screen.h"
#include "stMemory.h"
#include "vdi.h"
#include "video.h"
#include "configuration.h"
Uint32 VDI_OldPC; /* When call Trap#2, store off PC */
bool bVdiAesIntercept = false; /* Set to true to trace VDI & AES calls */
bool bUseVDIRes = false; /* Set to true (if want VDI), or false (ie for games) */
/* defaults */
int VDIRes = 0; /* 0,1 or 2 (low, medium, high) */
int VDIWidth = 640; /* 640x480, 800x600 or 1024x768 */
int VDIHeight = 480;
int VDIPlanes = 4;
static Uint32 LineABase; /* Line-A structure */
static Uint32 FontBase; /* Font base, used for 16-pixel high font */
/* Last VDI opcode & vectors */
static Uint16 VDIOpCode;
static Uint32 VDIControl;
static Uint32 VDIIntin;
static Uint32 VDIPtsin;
static Uint32 VDIIntout;
static Uint32 VDIPtsout;
#if ENABLE_TRACING
/* Last AES opcode & vectors */
static Uint32 AESControl;
static Uint32 AESGlobal;
static Uint32 AESIntin;
static Uint32 AESIntout;
static Uint32 AESAddrin;
static Uint32 AESAddrout;
static Uint16 AESOpCode;
#endif
/*-----------------------------------------------------------------------*/
/* Desktop TOS 1.04 and TOS 2.06 desktop configuration files */
static const Uint8 DesktopScript[504] =
{
0x23,0x61,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,0x23,0x62,0x30,0x30,0x30,0x30,
0x30,0x30,0x0D,0x0A,0x23,0x63,0x37,0x37,0x37,0x30,0x30,0x30,0x37,0x30,0x30,0x30,
0x36,0x30,0x30,0x30,0x37,0x30,0x30,0x35,0x35,0x32,0x30,0x30,0x35,0x30,0x35,0x35,
0x35,0x32,0x32,0x32,0x30,0x37,0x37,0x30,0x35,0x35,0x37,0x30,0x37,0x35,0x30,0x35,
0x35,0x35,0x30,0x37,0x37,0x30,0x33,0x31,0x31,0x31,0x31,0x30,0x33,0x0D,0x0A,0x23,
0x64,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0D,0x0A,
0x23,0x45,0x20,0x31,0x38,0x20,0x31,0x31,0x20,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,
0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x37,0x20,0x32,0x36,0x20,0x30,0x43,0x20,
0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,
0x32,0x20,0x30,0x42,0x20,0x32,0x36,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,
0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x41,0x20,0x30,0x46,0x20,
0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,
0x30,0x20,0x30,0x30,0x20,0x30,0x45,0x20,0x30,0x31,0x20,0x31,0x41,0x20,0x30,0x39,
0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x31,0x20,0x30,0x30,0x20,
0x30,0x30,0x20,0x46,0x46,0x20,0x43,0x20,0x48,0x41,0x52,0x44,0x20,0x44,0x49,0x53,
0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,0x30,0x20,
0x30,0x30,0x20,0x46,0x46,0x20,0x41,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,0x20,0x44,
0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,
0x31,0x20,0x30,0x30,0x20,0x46,0x46,0x20,0x42,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,
0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x54,0x20,0x30,0x30,
0x20,0x30,0x33,0x20,0x30,0x32,0x20,0x46,0x46,0x20,0x20,0x20,0x54,0x52,0x41,0x53,
0x48,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x46,0x20,0x46,0x46,0x20,0x30,0x34,0x20,
0x20,0x20,0x40,0x20,0x2A,0x2E,0x2A,0x40,0x20,0x0D,0x0A,0x23,0x44,0x20,0x46,0x46,
0x20,0x30,0x31,0x20,0x20,0x20,0x40,0x20,0x2A,0x2E,0x2A,0x40,0x20,0x0D,0x0A,0x23,
0x47,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x20,0x20,0x2A,0x2E,0x41,0x50,0x50,0x40,
0x20,0x40,0x20,0x0D,0x0A,0x23,0x47,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x20,0x20,
0x2A,0x2E,0x50,0x52,0x47,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x50,0x20,0x30,0x33,
0x20,0x46,0x46,0x20,0x20,0x20,0x2A,0x2E,0x54,0x54,0x50,0x40,0x20,0x40,0x20,0x0D,
0x0A,0x23,0x46,0x20,0x30,0x33,0x20,0x30,0x34,0x20,0x20,0x20,0x2A,0x2E,0x54,0x4F,
0x53,0x40,0x20,0x40,0x20,0x0D,0x0A,0x1A
};
static const Uint8 NewDeskScript[786] =
{
0x23,0x61,0x30,0x30,0x30,0x30,0x30,0x30,0x0D,0x0A,0x23,0x62,0x30,0x30,0x30,0x30,
0x30,0x30,0x0D,0x0A,0x23,0x63,0x37,0x37,0x37,0x30,0x30,0x30,0x37,0x30,0x30,0x30,
0x36,0x30,0x30,0x30,0x37,0x30,0x30,0x35,0x35,0x32,0x30,0x30,0x35,0x30,0x35,0x35,
0x35,0x32,0x32,0x32,0x30,0x37,0x37,0x30,0x35,0x35,0x37,0x30,0x37,0x35,0x30,0x35,
0x35,0x35,0x30,0x37,0x37,0x30,0x33,0x31,0x31,0x31,0x31,0x30,0x33,0x0D,0x0A,0x23,
0x64,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x0D,0x0A,
0x23,0x4B,0x20,0x34,0x46,0x20,0x35,0x33,0x20,0x34,0x43,0x20,0x30,0x30,0x20,0x34,
0x36,0x20,0x34,0x32,0x20,0x34,0x33,0x20,0x35,0x37,0x20,0x34,0x35,0x20,0x35,0x38,
0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,
0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,
0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x35,0x32,0x20,0x30,0x30,0x20,0x30,0x30,
0x20,0x34,0x44,0x20,0x35,0x36,0x20,0x35,0x30,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,
0x23,0x45,0x20,0x31,0x38,0x20,0x30,0x31,0x20,0x30,0x30,0x20,0x30,0x36,0x20,0x0D,
0x0A,0x23,0x51,0x20,0x34,0x31,0x20,0x34,0x30,0x20,0x34,0x33,0x20,0x34,0x30,0x20,
0x34,0x33,0x20,0x34,0x30,0x20,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,
0x20,0x30,0x30,0x20,0x30,0x37,0x20,0x32,0x36,0x20,0x30,0x43,0x20,0x30,0x30,0x20,
0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x32,0x20,0x30,
0x42,0x20,0x32,0x36,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,
0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x41,0x20,0x30,0x46,0x20,0x31,0x41,0x20,
0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,
0x30,0x20,0x30,0x45,0x20,0x30,0x31,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,
0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x34,0x20,
0x30,0x37,0x20,0x32,0x36,0x20,0x30,0x43,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,
0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x43,0x20,0x30,0x42,0x20,0x32,0x36,
0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,
0x30,0x30,0x20,0x30,0x38,0x20,0x30,0x46,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,
0x30,0x20,0x40,0x0D,0x0A,0x23,0x57,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x36,
0x20,0x30,0x31,0x20,0x31,0x41,0x20,0x30,0x39,0x20,0x30,0x30,0x20,0x40,0x0D,0x0A,
0x23,0x4E,0x20,0x46,0x46,0x20,0x30,0x34,0x20,0x30,0x30,0x30,0x20,0x40,0x20,0x2A,
0x2E,0x2A,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x44,0x20,0x46,0x46,0x20,0x30,0x31,
0x20,0x30,0x30,0x30,0x20,0x40,0x20,0x2A,0x2E,0x2A,0x40,0x20,0x40,0x20,0x0D,0x0A,
0x23,0x47,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x41,
0x50,0x50,0x40,0x20,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x47,0x20,0x30,0x33,0x20,
0x46,0x46,0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x50,0x52,0x47,0x40,0x20,0x40,0x20,
0x40,0x20,0x0D,0x0A,0x23,0x59,0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x30,0x30,0x30,
0x20,0x2A,0x2E,0x47,0x54,0x50,0x40,0x20,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x50,
0x20,0x30,0x33,0x20,0x46,0x46,0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x54,0x54,0x50,
0x40,0x20,0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x46,0x20,0x30,0x33,0x20,0x30,0x34,
0x20,0x30,0x30,0x30,0x20,0x2A,0x2E,0x54,0x4F,0x53,0x40,0x20,0x40,0x20,0x40,0x20,
0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,0x31,0x20,0x30,0x30,0x20,0x46,0x46,
0x20,0x43,0x20,0x48,0x41,0x52,0x44,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,0x40,0x20,
0x0D,0x0A,0x23,0x4D,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x30,0x30,0x20,0x46,0x46,
0x20,0x41,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,0x20,0x44,0x49,0x53,0x4B,0x40,0x20,
0x40,0x20,0x0D,0x0A,0x23,0x4D,0x20,0x30,0x31,0x20,0x30,0x30,0x20,0x30,0x30,0x20,
0x46,0x46,0x20,0x42,0x20,0x46,0x4C,0x4F,0x50,0x50,0x59,0x20,0x44,0x49,0x53,0x4B,
0x40,0x20,0x40,0x20,0x0D,0x0A,0x23,0x54,0x20,0x30,0x30,0x20,0x30,0x33,0x20,0x30,
0x32,0x20,0x46,0x46,0x20,0x20,0x20,0x54,0x52,0x41,0x53,0x48,0x40,0x20,0x40,0x20,
0x0D,0x0A
};
static void VDI_FixDesktopInf(void);
/*-----------------------------------------------------------------------*/
/**
* Called to reset VDI variables on reset.
*/
void VDI_Reset(void)
{
/* no VDI calls in progress */
VDI_OldPC = 0;
}
/*-----------------------------------------------------------------------*/
/**
* Limit width and height to VDI screen size in bytes, retaining their ratio.
* Return true if limiting was done.
*/
static bool VDI_ByteLimit(int *width, int *height, int planes)
{
double ratio;
int size;
size = (*width)*(*height)*planes/8;
if (size <= MAX_VDI_BYTES)
return false;
ratio = sqrt(MAX_VDI_BYTES) / sqrt(size);
*width = (*width) * ratio;
*height = (*height) * ratio;
if (*width < MIN_VDI_WIDTH || *height < MIN_VDI_HEIGHT)
{
*width = MIN_VDI_WIDTH;
*height = MIN_VDI_HEIGHT;
fputs("Bad VDI screen ratio / too small size -> use smallest valid size.\n", stderr);
}
return true;
}
/*-----------------------------------------------------------------------*/
/**
* Set Width/Height/BitDepth according to passed GEMCOLOR_2/4/16.
* Align size when necessary.
*/
void VDI_SetResolution(int GEMColor, int WidthRequest, int HeightRequest)
{
int w = WidthRequest;
int h = HeightRequest;
/* Color depth */
switch (GEMColor)
{
case GEMCOLOR_2:
VDIRes = 2;
VDIPlanes = 1;
break;
case GEMCOLOR_4:
VDIRes = 1;
VDIPlanes = 2;
break;
case GEMCOLOR_16:
VDIRes = 0;
VDIPlanes = 4;
break;
}
/* screen size in bytes needs to be below limit */
VDI_ByteLimit(&w, &h, VDIPlanes);
/* width needs to be aligned to 16 bytes */
VDIWidth = Opt_ValueAlignMinMax(w, 128/VDIPlanes, MIN_VDI_WIDTH, MAX_VDI_WIDTH);
/* height needs to be multiple of cell height (either 8 or 16) */
VDIHeight = Opt_ValueAlignMinMax(h, 16, MIN_VDI_HEIGHT, MAX_VDI_HEIGHT);
printf("VDI screen: request = %dx%d@%d, result = %dx%d@%d\n",
WidthRequest, HeightRequest, VDIPlanes, VDIWidth, VDIHeight, VDIPlanes);
/* Write resolution to re-boot takes effect with correct bit-depth */
VDI_FixDesktopInf();
}
#if ENABLE_TRACING
/*-----------------------------------------------------------------------*/
/* AES opcodes which have string args */
static const struct {
int code; /* AES opcode */
int count; /* number of char * args _first_ in addrin[] */
} AESStrings[] = {
{ 0x0D, 1 }, /* appl_find() */
{ 0x12, 1 }, /* appl_search() */
{ 0x23, 1 }, /* menu_register() */
{ 0x34, 1 }, /* form_alert() */
{ 0x51, 1 }, /* scrp_write() */
{ 0x5A, 2 }, /* fsel_input() */
{ 0x5B, 3 }, /* fsel_exinput() */
{ 0x6E, 1 }, /* rsrc_load() */
{ 0x7C, 1 } /* shell_find() */
};
/* AES opcode -> function name mapping */
static const char* AESName_10[] = {
"appl_init", /* (0x0A) */
"appl_read", /* (0x0B) */
"appl_write", /* (0x0C) */
"appl_find", /* (0x0D) */
"appl_tplay", /* (0x0E) */
"appl_trecord", /* (0x0F) */
NULL, /* (0x10) */
NULL, /* (0x11) */
"appl_search", /* (0x12) */
"appl_exit", /* (0x13) */
"evnt_keybd", /* (0x14) */
"evnt_button", /* (0x15) */
"evnt_mesag", /* (0x16) */
"evnt_mesag", /* (0x17) */
"evnt_timer", /* (0x18) */
"evnt_multi", /* (0x19) */
"evnt_dclick", /* (0x1A) */
NULL, /* (0x1b) */
NULL, /* (0x1c) */
NULL, /* (0x1d) */
"menu_bar", /* (0x1E) */
"menu_icheck", /* (0x1F) */
"menu_ienable", /* (0x20) */
"menu_tnormal", /* (0x21) */
"menu_text", /* (0x22) */
"menu_register", /* (0x23) */
"menu_popup", /* (0x24) */
"menu_attach", /* (0x25) */
"menu_istart", /* (0x26) */
"menu_settings", /* (0x27) */
"objc_add", /* (0x28) */
"objc_delete", /* (0x29) */
"objc_draw", /* (0x2A) */
"objc_find", /* (0x2B) */
"objc_offset", /* (0x2C) */
"objc_order", /* (0x2D) */
"objc_edit", /* (0x2E) */
"objc_change", /* (0x2F) */
"objc_sysvar", /* (0x30) */
NULL, /* (0x31) */
"form_do", /* (0x32) */
"form_dial", /* (0x33) */
"form_alert", /* (0x34) */
"form_error", /* (0x35) */
"form_center", /* (0x36) */
"form_keybd", /* (0x37) */
"form_button", /* (0x38) */
NULL, /* (0x39) */
NULL, /* (0x3a) */
NULL, /* (0x3b) */
NULL, /* (0x3c) */
NULL, /* (0x3d) */
NULL, /* (0x3e) */
NULL, /* (0x3f) */
NULL, /* (0x40) */
NULL, /* (0x41) */
NULL, /* (0x42) */
NULL, /* (0x43) */
NULL, /* (0x44) */
NULL, /* (0x45) */
"graf_rubberbox", /* (0x46) */
"graf_dragbox", /* (0x47) */
"graf_movebox", /* (0x48) */
"graf_growbox", /* (0x49) */
"graf_shrinkbox", /* (0x4A) */
"graf_watchbox", /* (0x4B) */
"graf_slidebox", /* (0x4C) */
"graf_handle", /* (0x4D) */
"graf_mouse", /* (0x4E) */
"graf_mkstate", /* (0x4F) */
"scrp_read", /* (0x50) */
"scrp_write", /* (0x51) */
NULL, /* (0x52) */
NULL, /* (0x53) */
NULL, /* (0x54) */
NULL, /* (0x55) */
NULL, /* (0x56) */
NULL, /* (0x57) */
NULL, /* (0x58) */
NULL, /* (0x59) */
"fsel_input", /* (0x5A) */
"fsel_exinput", /* (0x5B) */
NULL, /* (0x5c) */
NULL, /* (0x5d) */
NULL, /* (0x5e) */
NULL, /* (0x5f) */
NULL, /* (0x60) */
NULL, /* (0x61) */
NULL, /* (0x62) */
NULL, /* (0x63) */
"wind_create", /* (0x64) */
"wind_open", /* (0x65) */
"wind_close", /* (0x66) */
"wind_delete", /* (0x67) */
"wind_get", /* (0x68) */
"wind_set", /* (0x69) */
"wind_find", /* (0x6A) */
"wind_update", /* (0x6B) */
"wind_calc", /* (0x6C) */
"wind_new", /* (0x6D) */
"rsrc_load", /* (0x6E) */
"rsrc_free", /* (0x6F) */
"rsrc_gaddr", /* (0x70) */
"rsrc_saddr", /* (0x71) */
"rsrc_obfix", /* (0x72) */
"rsrc_rcfix", /* (0x73) */
NULL, /* (0x74) */
NULL, /* (0x75) */
NULL, /* (0x76) */
NULL, /* (0x77) */
"shel_read", /* (0x78) */
"shel_write", /* (0x79) */
"shel_get", /* (0x7A) */
"shel_put", /* (0x7B) */
"shel_find", /* (0x7C) */
"shel_envrn", /* (0x7D) */
NULL, /* (0x7e) */
NULL, /* (0x7f) */
NULL, /* (0x80) */
NULL, /* (0x81) */
"appl_getinfo" /* (0x82) */
};
/**
* Map AES call opcode to an AES function name
*/
static const char* AES_Opcode2Name(Uint16 opcode)
{
int code = opcode - 10;
if (code >= 0 && code < ARRAYSIZE(AESName_10) && AESName_10[code])
return AESName_10[code];
else
return "???";
}
/**
* Output AES call info, including some of args
*/
static void AES_OpcodeInfo(FILE *fp, Uint16 opcode)
{
int code = opcode - 10;
fprintf(fp, "AES call %3hd ", opcode);
if (code >= 0 && code < ARRAYSIZE(AESName_10) && AESName_10[code])
{
bool first = true;
int i, items;
fprintf(fp, "%s(", AESName_10[code]);
items = 0;
/* there are so few of these that linear search is fine */
for (i = 0; i < ARRAYSIZE(AESStrings); i++)
{
/* something that can be shown? */
if (AESStrings[i].code == opcode)
{
items = AESStrings[i].count;
break;
}
}
/* addrin array size in longs enough for items? */
if (items > 0 && items <= STMemory_ReadWord(AESControl+SIZE_WORD*3))
{
const char *str;
fputs("addrin: ", fp);
for (i = 0; i < items; i++)
{
if (first)
first = false;
else
fputs(", ", fp);
str = (const char *)STMemory_STAddrToPointer(STMemory_ReadLong(AESAddrin+SIZE_LONG*i));
fprintf(fp, "\"%s\"", str);
}
}
/* intin array size in words */
items = STMemory_ReadWord(AESControl+SIZE_WORD*1);
if (items > 0)
{
if (!first)
{
fputs(", ", fp);
first = true;
}
fputs("intin: ", fp);
for (i = 0; i < items; i++)
{
if (first)
first = false;
else
fputs(",", fp);
fprintf(fp, "0x%x", STMemory_ReadWord(AESIntin+SIZE_WORD*i));
}
}
fputs(")\n", fp);
}
else
fputs("???\n", fp);
fflush(fp);
}
/**
* If opcodes argument is set, show AES opcode/function name table,
* otherwise AES vectors information.
*/
void AES_Info(FILE *fp, Uint32 bShowOpcodes)
{
Uint16 opcode;
if (bShowOpcodes)
{
for (opcode = 10; opcode < 0x86; opcode++)
{
fprintf(fp, "%02x %-16s", opcode, AES_Opcode2Name(opcode));
if ((opcode-9) % 4 == 0) fputs("\n", fp);
}
return;
}
if (!bVdiAesIntercept)
{
fputs("VDI/AES interception isn't enabled!\n", fp);
return;
}
if (!AESControl)
{
fputs("No traced AES calls!\n", fp);
return;
}
opcode = STMemory_ReadWord(AESControl);
if (opcode != AESOpCode)
{
fputs("AES parameter block contents changed since last call!\n", fp);
return;
}
fputs("Latest AES Parameter block:\n", fp);
fprintf(fp, "- Opcode: %3hd (%s)\n",
opcode, AES_Opcode2Name(opcode));
fprintf(fp, "- Control: %#8x\n", AESControl);
fprintf(fp, "- Global: %#8x, %d bytes\n",
AESGlobal, 2+2+2+4+4+4+4+4+4);
fprintf(fp, "- Intin: %#8x, %d words\n",
AESIntin, STMemory_ReadWord(AESControl+2*1));
fprintf(fp, "- Intout: %#8x, %d words\n",
AESIntout, STMemory_ReadWord(AESControl+2*2));
fprintf(fp, "- Addrin: %#8x, %d longs\n",
AESAddrin, STMemory_ReadWord(AESControl+2*3));
fprintf(fp, "- Addrout: %#8x, %d longs\n",
AESAddrout, STMemory_ReadWord(AESControl+2*4));
}
/*-----------------------------------------------------------------------*/
/**
* Map VDI call opcode/sub-opcode to a VDI function name
*/
static const char* VDI_Opcode2Name(Uint16 opcode, Uint16 subcode)
{
static const char* names_0[] = {
"???",
"v_opnwk",
"v_clswk",
"v_clrwk",
"v_updwk",
"", /* 5: lots of sub opcodes */
"v_pline",
"v_pmarker",
"v_gtext",
"v_fillarea", /* sub-opcode 13: v_bez_fill with GDOS */
"v_cellarray",
"", /* 11: lots of sub opcodes */
"vst_height",
"vst_rotation",
"vs_color",
"vsl_type",
"vsl_width",
"vsl_color",
"vsm_type",
"vsm_height",
"vsm_color",
"vst_font",
"vst_color",
"vsf_interior",
"vsf_style",
"vsf_color",
"vq_color",
"vq_cellarray",
"vrq/sm_locator",
"vrq/sm_valuator",
"vrq/sm_choice",
"vrq/sm_string",
"vswr_mode",
"vsin_mode",
"???", /* 34 */
"vql_attributes",
"vqm_attributes",
"vqf_attributes",
"vqt_attributes",
"vst_alignment"
};
static const char* names_100[] = {
"v_opnvwk",
"v_clsvwk",
"vq_extnd",
"v_contourfill",
"vsf_perimeter",
"v_get_pixel",
"vst_effects",
"vst_point",
"vsl_ends",
"vro_cpyfm",
"vr_trnfm",
"vsc_form",
"vsf_udpat",
"vsl_udsty",
"vr_recfl",
"vqin_mode",
"vqt_extent",
"vqt_width",
"vex_timv",
"vst_load_fonts",
"vst_unload_fonts",
"vrt_cpyfm",
"v_show_c",
"v_hide_c",
"vq_mouse",
"vex_butv",
"vex_motv",
"vex_curv",
"vq_key_s",
"vs_clip",
"vqt_name",
"vqt_fontinfo"
/* 131-233: no known opcodes
* 234-255: (Speedo) GDOS opcodes
*/
};
static const char* names_opcode5[] = {
"<no subcode>",
"vq_chcells",
"v_exit_cur",
"v_enter_cur",
"v_curup",
"v_curdown",
"v_curright",
"v_curleft",
"v_curhome",
"v_eeos",
"v_eeol",
"vs_curaddress",
"v_curtext",
"v_rvon",
"v_rvoff",
"vq_curaddress",
"vq_tabstatus",
"v_hardcopy",
"v_dspcur",
"v_rmcur",
"v_form_adv",
"v_output_window",
"v_clear_disp_list",
"v_bit_image",
"vq_scan",
"v_alpha_text"
};
static const char* names_opcode5_98[] = {
"v_meta_extents",
"v_write_meta",
"vm_filename",
"???",
"v_fontinit"
};
static const char* names_opcode11[] = {
"<no subcode>",
"v_bar",
"v_arc",
"v_pieslice",
"v_circle",
"v_ellipse",
"v_ellarc",
"v_ellpie",
"v_rbox",
"v_rfbox",
"v_justified"
};
if (opcode == 5)
{
if (subcode < ARRAYSIZE(names_opcode5)) {
return names_opcode5[subcode];
}
if (subcode >= 98) {
subcode -= 98;
if (subcode < ARRAYSIZE(names_opcode5_98)) {
return names_opcode5_98[subcode];
}
}
}
else if (opcode == 11)
{
if (subcode < ARRAYSIZE(names_opcode11)) {
return names_opcode11[subcode];
}
}
else if (opcode < ARRAYSIZE(names_0))
{
return names_0[opcode];
}
else if (opcode >= 100)
{
opcode -= 100;
if (opcode < ARRAYSIZE(names_100))
{
return names_100[opcode];
}
}
return "GDOS?";
}
/**
* If opcodes argument is set, show VDI opcode/function name table,
* otherwise VDI vectors information.
*/
void VDI_Info(FILE *fp, Uint32 bShowOpcodes)
{
Uint16 opcode, subcode;
if (bShowOpcodes)
{
Uint16 opcode;
for (opcode = 0; opcode < 0x84; )
{
if (opcode == 0x28)
{
fputs("--- GDOS calls? ---\n", fp);
opcode = 0x64;
}
fprintf(fp, "%02x %-16s",
opcode, VDI_Opcode2Name(opcode, 0));
if (++opcode % 4 == 0) fputs("\n", fp);
}
return;
}
if (!bVdiAesIntercept)
{
fputs("VDI/AES interception isn't enabled!\n", fp);
return;
}
if (!VDIControl)
{
fputs("No traced VDI calls!\n", fp);
return;
}
opcode = STMemory_ReadWord(VDIControl);
if (opcode != VDIOpCode)
{
fputs("VDI parameter block contents changed since last call!\n", fp);
return;
}
fputs("Latest VDI Parameter block:\n", fp);
subcode = STMemory_ReadWord(VDIControl+2*5);
fprintf(fp, "- Opcode/Subcode: %hd/%hd (%s)\n",
opcode, subcode, VDI_Opcode2Name(opcode, subcode));
fprintf(fp, "- Device handle: %d\n",
STMemory_ReadWord(VDIControl+2*6));
fprintf(fp, "- Control: %#8x\n", VDIControl);
fprintf(fp, "- Ptsin: %#8x, %d co-ordinate word pairs\n",
VDIPtsin, STMemory_ReadWord(VDIControl+2*1));
fprintf(fp, "- Ptsout: %#8x, %d co-ordinate word pairs\n",
VDIPtsout, STMemory_ReadWord(VDIControl+2*2));
fprintf(fp, "- Intin: %#8x, %d words\n",
VDIIntin, STMemory_ReadWord(VDIControl+2*3));
fprintf(fp, "- Intout: %#8x, %d words\n",
VDIIntout, STMemory_ReadWord(VDIControl+2*4));
}
#else /* !ENABLE_TRACING */
void AES_Info(FILE *fp, Uint32 bShowOpcodes)
{
fputs("Hatari isn't configured with ENABLE_TRACING\n", fp);
}
void VDI_Info(FILE *fp, Uint32 bShowOpcodes)
{
fputs("Hatari isn't configured with ENABLE_TRACING\n", fp);
}
#endif /* !ENABLE_TRACING */
/*-----------------------------------------------------------------------*/
/**
* Return true for only VDI opcodes that need to be handled at Trap exit.
*/
static inline bool VDI_isWorkstationOpen(Uint16 opcode)
{
if (opcode == 1 || opcode == 100)
return true;
else
return false;
}
/**
* Check whether this is VDI/AES call and see if we need to re-direct
* it to our own routines. Return true if VDI_Complete() function
* needs to be called on OS call exit, otherwise return false.
*
* We enter here with Trap #2, so D0 tells which OS call it is (VDI/AES)
* and D1 is pointer to VDI/AES vectors, i.e. Control, Intin, Ptsin etc...
*/
bool VDI_AES_Entry(void)
{
Uint16 call = Regs[REG_D0];
Uint32 TablePtr = Regs[REG_D1];
#if ENABLE_TRACING
/* AES call? */
if (call == 0xC8)
{
if ( !STMemory_CheckAreaType ( TablePtr, 24, ABFLAG_RAM ) )
{
Log_Printf(LOG_WARN, "AES call failed due to invalid parameter block address 0x%x+%i\n", TablePtr, 24);
return false;
}
/* store values for debugger "info aes" command */
AESControl = STMemory_ReadLong(TablePtr);
AESGlobal = STMemory_ReadLong(TablePtr+4);
AESIntin = STMemory_ReadLong(TablePtr+8);
AESIntout = STMemory_ReadLong(TablePtr+12);
AESAddrin = STMemory_ReadLong(TablePtr+16);
AESAddrout = STMemory_ReadLong(TablePtr+20);
AESOpCode = STMemory_ReadWord(AESControl);
if (LOG_TRACE_LEVEL(TRACE_OS_AES))
{
AES_OpcodeInfo(TraceFile, AESOpCode);
}
/* using same special opcode trick doesn't work for
* both VDI & AES as AES functions can be called
* recursively and VDI calls happen inside AES calls.
*/
return false;
}
#endif
/* VDI call? */
if (call == 0x73)
{
if ( !STMemory_CheckAreaType ( TablePtr, 20, ABFLAG_RAM ) )
{
Log_Printf(LOG_WARN, "VDI call failed due to invalid parameter block address 0x%x+%i\n", TablePtr, 20);
return false;
}
/* store values for extended VDI resolution handling
* and debugger "info vdi" command
*/
VDIControl = STMemory_ReadLong(TablePtr);
VDIIntin = STMemory_ReadLong(TablePtr+4);
VDIPtsin = STMemory_ReadLong(TablePtr+8);
VDIIntout = STMemory_ReadLong(TablePtr+12);
VDIPtsout = STMemory_ReadLong(TablePtr+16);
VDIOpCode = STMemory_ReadWord(VDIControl);
#if ENABLE_TRACING
{
Uint16 subcode = STMemory_ReadWord(VDIControl+2*5);
LOG_TRACE(TRACE_OS_VDI, "VDI call %3hd/%3hd (%s)\n",
VDIOpCode, subcode,
VDI_Opcode2Name(VDIOpCode, subcode));
}
#endif
/* Only workstation open needs to be handled at trap return */
return bUseVDIRes && VDI_isWorkstationOpen(VDIOpCode);
}
LOG_TRACE((TRACE_OS_VDI|TRACE_OS_AES), "Trap #2 with D0 = 0x%hX\n", call);
return false;
}
/*-----------------------------------------------------------------------*/
/**
* Modify Line-A structure for our VDI resolutions
*/
void VDI_LineA(Uint32 linea, Uint32 fontbase)
{
LineABase = linea;
FontBase = fontbase;
if (bUseVDIRes)
{
int cel_ht = STMemory_ReadWord(linea-46); /* v_cel_ht */
if (cel_ht <= 0)
{
Log_Printf(LOG_WARN, "VDI Line-A init failed due to bad cell height!\n");
return;
}
STMemory_WriteWord(linea-44, (VDIWidth/8)-1); /* v_cel_mx (cols-1) */
STMemory_WriteWord(linea-42, (VDIHeight/cel_ht)-1); /* v_cel_my (rows-1) */
STMemory_WriteWord(linea-40, cel_ht*((VDIWidth*VDIPlanes)/8)); /* v_cel_wr */
STMemory_WriteWord(linea-12, VDIWidth); /* v_rez_hz */
STMemory_WriteWord(linea-4, VDIHeight); /* v_rez_vt */
STMemory_WriteWord(linea-2, (VDIWidth*VDIPlanes)/8); /* bytes_lin */
STMemory_WriteWord(linea+0, VDIPlanes); /* planes */
STMemory_WriteWord(linea+2, (VDIWidth*VDIPlanes)/8); /* width */
}
}
/*-----------------------------------------------------------------------*/
/**
* This is called on completion of a VDI Trap workstation open,
* to modify the return structure for extended resolutions.
*/
void VDI_Complete(void)
{
/* right opcode? */
assert(VDI_isWorkstationOpen(VDIOpCode));
/* not changed between entry and completion? */
assert(VDIOpCode == STMemory_ReadWord(VDIControl));
STMemory_WriteWord(VDIIntout, VDIWidth-1); /* IntOut[0] Width-1 */
STMemory_WriteWord(VDIIntout+1*2, VDIHeight-1); /* IntOut[1] Height-1 */
STMemory_WriteWord(VDIIntout+13*2, 1 << VDIPlanes); /* IntOut[13] #colors */
STMemory_WriteWord(VDIIntout+39*2, 512); /* IntOut[39] #available colors */
STMemory_WriteWord(LineABase-0x15a*2, VDIWidth-1); /* WKXRez */
STMemory_WriteWord(LineABase-0x159*2, VDIHeight-1); /* WKYRez */
VDI_LineA(LineABase, FontBase); /* And modify Line-A structure accordingly */
}
/*-----------------------------------------------------------------------*/
/**
* Save desktop configuration file for VDI, eg desktop.inf(TOS 1.04) or newdesk.inf(TOS 2.06)
*/
static void VDI_SaveDesktopInf(char *pszFileName, const Uint8 *Script, long ScriptSize)
{
/* Just save file */
File_Save(pszFileName, Script, ScriptSize, false);
}
/*-----------------------------------------------------------------------*/
/**
* Modify exisiting ST desktop configuration files to set resolution(keep user settings)
*/
static void VDI_ModifyDesktopInf(char *pszFileName)
{
long InfSize;
Uint8 *pInfData;
int i;
/* Load our '.inf' file */
pInfData = File_Read(pszFileName, &InfSize, NULL);
if (pInfData)
{
/* Scan file for '#E' */
i = 0;
while (i < (InfSize-8))
{
if ((pInfData[i]=='#') && (pInfData[i+1]=='E'))
{
/* Modify resolution */
pInfData[i+7] = '1'+VDIRes;
break;
}
i++;
}
/* And save */
File_Save(pszFileName, pInfData, InfSize, false);
/* Free */
free(pInfData);
}
}
/*-----------------------------------------------------------------------*/
/**
* Modify (or create) ST desktop configuration files so VDI boots up in
* correct color depth
*/
static void VDI_FixDesktopInf(void)
{
char *szDesktopFileName, *szNewDeskFileName;
/* Modifying DESKTOP.INF only makes sense when we emulate the GEMDOS
* hard disk 'C:' (i.e. the HD we boot from) - if not, simply return */
if (!GemDOS_IsDriveEmulated(2))
{
return;
}
szDesktopFileName = malloc(2 * FILENAME_MAX);
if (!szDesktopFileName)
{
perror("VDI_FixDesktopInf");
return;
}
szNewDeskFileName = szDesktopFileName + FILENAME_MAX;
/* Create filenames for hard-drive */
GemDOS_CreateHardDriveFileName(2, "\\DESKTOP.INF", szDesktopFileName, FILENAME_MAX);
GemDOS_CreateHardDriveFileName(2, "\\NEWDESK.INF", szNewDeskFileName, FILENAME_MAX);
/* First, check if files exist(ie modify or replace) */
if (!File_Exists(szDesktopFileName))
VDI_SaveDesktopInf(szDesktopFileName,DesktopScript,sizeof(DesktopScript));
VDI_ModifyDesktopInf(szDesktopFileName);
if (!File_Exists(szNewDeskFileName))
VDI_SaveDesktopInf(szNewDeskFileName,NewDeskScript,sizeof(NewDeskScript));
VDI_ModifyDesktopInf(szNewDeskFileName);
free(szDesktopFileName);
}