Merge latest TomB version as of 17 April

This commit is contained in:
Chips 2016-04-25 17:12:37 +00:00
parent d8ba1f9037
commit f6baa22248
29 changed files with 2007 additions and 247 deletions

View file

@ -29,6 +29,7 @@ static bool dialogResult = false;
static bool dialogFinished = false;
static bool fileSelected = false;
static gcn::Window *wndEditFilesysHardfile;
static gcn::Button* cmdOK;
static gcn::Button* cmdCancel;
@ -51,6 +52,23 @@ static gcn::Label *lblBlocksize;
static gcn::TextField *txtBlocksize;
static void check_rdb(const TCHAR *filename)
{
bool isrdb = hardfile_testrdb(filename);
if(isrdb)
{
txtSectors->setText("0");
txtSurfaces->setText("0");
txtReserved->setText("0");
txtBootPri->setText("0");
}
txtSectors->setEnabled(!isrdb);
txtSurfaces->setEnabled(!isrdb);
txtReserved->setEnabled(!isrdb);
txtBootPri->setEnabled(!isrdb);
}
class FilesysHardfileActionListener : public gcn::ActionListener
{
public:
@ -65,6 +83,7 @@ class FilesysHardfileActionListener : public gcn::ActionListener
{
txtPath->setText(tmp);
fileSelected = true;
check_rdb(tmp);
}
wndEditFilesysHardfile->requestModalFocus();
cmdPath->requestFocus();
@ -304,7 +323,7 @@ static void EditFilesysHardfileLoop(void)
bool EditFilesysHardfile(int unit_no)
{
struct mountedinfo mi;
struct uaedev_config_info *uci = &changed_prefs.mountconfig[unit_no];
struct uaedev_config_info *uci;
std::string strdevname, strroot;
char tmp[32];
@ -315,6 +334,7 @@ bool EditFilesysHardfile(int unit_no)
if(unit_no >= 0)
{
uci = &changed_prefs.mountconfig[unit_no];
get_filesys_unitconfig(&changed_prefs, unit_no, &mi);
strdevname.assign(uci->devname);
txtDevice->setText(strdevname);
@ -334,6 +354,8 @@ bool EditFilesysHardfile(int unit_no)
txtSectors->setText(tmp);
snprintf(tmp, 32, "%d", uci->blocksize);
txtBlocksize->setText(tmp);
check_rdb(strroot.c_str());
}
else
{

View file

@ -179,7 +179,10 @@ class ConfigsListActionListener : public gcn::ActionListener
strncpy(last_active_config, ConfigFilesList[selected_item]->Name, MAX_PATH);
DisableResume();
RefreshAllPanels();
uae_reset(1);
if(emulating)
uae_reset(1);
else
uae_reset(0);
gui_running = false;
}
else

View file

@ -34,12 +34,12 @@ static gcn::Button *cmdSaveForDisk;
static gcn::Button *cmdCreateDDDisk;
static gcn::Button *cmdCreateHDDisk;
static const char *diskfile_filter[] = { ".adf", ".adz", ".zip", ".gz", ".dms", ".rp9", "\0" };
static const char *diskfile_filter[] = { ".adf", ".adz", ".zip", ".gz", ".dms", "\0" };
static const char *drivespeedlist[] = { "100% (compatible)", "200%", "400%", "800%" };
static const int drivespeedvalues[] = { 100, 200, 400, 800 };
static void AdjustDropDownControls(void);
static bool bLoadConfigForDisk = true;
static bool bLoadConfigForDisk = false;
class DriveTypeListModel : public gcn::ListModel
@ -415,7 +415,6 @@ void InitPanelFloppy(const struct _ConfigCategory& category)
chkLoadConfig = new gcn::UaeCheckBox("Load config with same name as disk");
chkLoadConfig->setId("LoadDiskCfg");
chkLoadConfig->addActionListener(dfxCheckActionListener);
chkLoadConfig->setSelected(false);
}
}

View file

@ -34,8 +34,6 @@ extern gcn::Color gui_baseCol;
extern gcn::SDLInput* gui_input;
extern SDL_Surface* gui_screen;
extern void gui_force_rtarea_hdchange(void);
extern char currentDir[MAX_DPATH];
extern char last_loaded_config[MAX_DPATH];

View file

@ -0,0 +1,361 @@
#include "sysconfig.h"
#include "sysdeps.h"
#include "td-sdl/thread.h"
#include "options.h"
#include "filesys.h"
#include "zfile.h"
struct hardfilehandle
{
int zfile;
struct zfile *zf;
FILE *f;
};
struct uae_driveinfo {
TCHAR vendor_id[128];
TCHAR product_id[128];
TCHAR product_rev[128];
TCHAR product_serial[128];
TCHAR device_name[2048];
TCHAR device_path[2048];
uae_u64 size;
uae_u64 offset;
int bytespersector;
int removablemedia;
int nomedia;
int dangerous;
int readonly;
};
#define HDF_HANDLE_FILE 1
#define HDF_HANDLE_ZFILE 2
#define CACHE_SIZE 16384
#define CACHE_FLUSH_TIME 5
static TCHAR *hdz[] = { _T("hdz"), _T("zip"), NULL };
int hdf_open_target (struct hardfiledata *hfd, const TCHAR *pname)
{
FILE *f = 0;
int i;
TCHAR *name = my_strdup (pname);
TCHAR *ext;
int zmode = 0;
hfd->flags = 0;
hfd->drive_empty = 0;
hdf_close (hfd);
hfd->cache = (uae_u8*)malloc (CACHE_SIZE);
hfd->cache_valid = 0;
hfd->virtual_size = 0;
hfd->virtual_rdb = NULL;
if (!hfd->cache) {
write_log (_T("malloc(%d) failed in hdf_open_target\n"), CACHE_SIZE);
goto end;
}
hfd->handle = xcalloc (struct hardfilehandle, 1);
hfd->handle->f = 0;
write_log (_T("hfd attempting to open: '%s'\n"), name);
ext = _tcsrchr (name, '.');
if (ext != NULL) {
ext++;
for (i = 0; hdz[i]; i++) {
if (!_tcsicmp (ext, hdz[i]))
zmode = 1;
}
}
f = fopen(name, (hfd->readonly ? "rb" : "r+b"));
hfd->handle->f = f;
i = _tcslen (name) - 1;
while (i >= 0) {
if ((i > 0 && (name[i - 1] == '/' || name[i - 1] == '\\')) || i == 0) {
_tcscpy (hfd->vendor_id, _T("UAE"));
_tcsncpy (hfd->product_id, name + i, 15);
_tcscpy (hfd->product_rev, _T("0.3"));
break;
}
i--;
}
if (f != NULL) {
uae_s64 pos = ftell(f);
fseek(f, 0, SEEK_END);
uae_s64 size = ftell(f);
fseek(f, pos, SEEK_SET);
size &= ~(hfd->blocksize - 1);
hfd->physsize = hfd->virtsize = size;
if (hfd->physsize < hfd->blocksize || hfd->physsize == 0) {
write_log (_T("HDF '%s' is too small\n"), name);
goto end;
}
hfd->handle_valid = HDF_HANDLE_FILE;
if (hfd->physsize < 64 * 1024 * 1024 && zmode) {
write_log (_T("HDF '%s' re-opened in zfile-mode\n"), name);
fclose (f);
hfd->handle->f = 0;
hfd->handle->zf = zfile_fopen (name, _T("rb"), ZFD_NORMAL);
hfd->handle->zfile = 1;
if (!hfd->handle->zf)
goto end;
zfile_fseek (hfd->handle->zf, 0, SEEK_END);
hfd->physsize = hfd->virtsize = zfile_ftell (hfd->handle->zf);
zfile_fseek (hfd->handle->zf, 0, SEEK_SET);
hfd->handle_valid = HDF_HANDLE_ZFILE;
}
} else {
write_log (_T("HDF '%s' failed to open.\n"), name);
}
if (hfd->handle_valid || hfd->drive_empty) {
write_log (_T("HDF '%s' %p opened, size=%dK mode=%d empty=%d\n"),
name, hfd, hfd->physsize / 1024, hfd->handle_valid, hfd->drive_empty);
return 1;
}
end:
hdf_close (hfd);
xfree (name);
return 0;
}
static void freehandle (struct hardfilehandle *h)
{
if (!h)
return;
if (!h->zfile && h->f != 0)
fclose (h->f);
if (h->zfile && h->zf)
zfile_fclose (h->zf);
h->zf = NULL;
h->f = 0;
h->zfile = 0;
}
void hdf_close_target (struct hardfiledata *hfd)
{
freehandle (hfd->handle);
xfree (hfd->handle);
xfree (hfd->emptyname);
hfd->emptyname = NULL;
hfd->handle = NULL;
hfd->handle_valid = 0;
if (hfd->cache)
free (hfd->cache);
xfree(hfd->virtual_rdb);
hfd->virtual_rdb = 0;
hfd->virtual_size = 0;
hfd->cache = 0;
hfd->cache_valid = 0;
hfd->drive_empty = 0;
hfd->dangerous = 0;
}
static int hdf_seek (struct hardfiledata *hfd, uae_u64 offset)
{
int ret;
if (hfd->handle_valid == 0) {
gui_message (_T("hd: hdf handle is not valid. bug."));
abort();
}
if (offset >= hfd->physsize - hfd->virtual_size) {
gui_message (_T("hd: tried to seek out of bounds! (%I64X >= %I64X)\n"), offset, hfd->physsize);
abort ();
}
offset += hfd->offset;
if (offset & (hfd->blocksize - 1)) {
gui_message (_T("hd: poscheck failed, offset=%I64X not aligned to blocksize=%d! (%I64X & %04X = %04X)\n"),
offset, hfd->blocksize, offset, hfd->blocksize, offset & (hfd->blocksize - 1));
abort ();
}
if (hfd->handle_valid == HDF_HANDLE_FILE) {
ret = fseek (hfd->handle->f, offset, SEEK_SET);
if (ret != 0)
return -1;
} else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
zfile_fseek (hfd->handle->zf, (long)offset, SEEK_SET);
}
return 0;
}
static void poscheck (struct hardfiledata *hfd, int len)
{
uae_u64 pos;
if (hfd->handle_valid == HDF_HANDLE_FILE) {
pos = ftell (hfd->handle->f);
if (pos == -1) {
gui_message (_T("hd: poscheck failed. seek failure"));
abort ();
}
} else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
pos = zfile_ftell (hfd->handle->zf);
}
if (len < 0) {
gui_message (_T("hd: poscheck failed, negative length! (%d)"), len);
abort ();
}
if (pos < hfd->offset) {
gui_message (_T("hd: poscheck failed, offset out of bounds! (%I64d < %I64d)"), pos, hfd->offset);
abort ();
}
if (pos >= hfd->offset + hfd->physsize - hfd->virtual_size || pos >= hfd->offset + hfd->physsize + len - hfd->virtual_size) {
gui_message (_T("hd: poscheck failed, offset out of bounds! (%I64d >= %I64d, LEN=%d)"), pos, hfd->offset + hfd->physsize, len);
abort ();
}
if (pos & (hfd->blocksize - 1)) {
gui_message (_T("hd: poscheck failed, offset not aligned to blocksize! (%I64X & %04X = %04X\n"), pos, hfd->blocksize, pos & hfd->blocksize);
abort ();
}
}
static int isincache (struct hardfiledata *hfd, uae_u64 offset, int len)
{
if (!hfd->cache_valid)
return -1;
if (offset >= hfd->cache_offset && offset + len <= hfd->cache_offset + CACHE_SIZE)
return (int)(offset - hfd->cache_offset);
return -1;
}
static int hdf_read_2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
int outlen = 0;
int coffset;
if (offset == 0)
hfd->cache_valid = 0;
coffset = isincache (hfd, offset, len);
if (coffset >= 0) {
memcpy (buffer, hfd->cache + coffset, len);
return len;
}
hfd->cache_offset = offset;
if (offset + CACHE_SIZE > hfd->offset + (hfd->physsize - hfd->virtual_size))
hfd->cache_offset = hfd->offset + (hfd->physsize - hfd->virtual_size) - CACHE_SIZE;
hdf_seek (hfd, hfd->cache_offset);
poscheck (hfd, CACHE_SIZE);
if (hfd->handle_valid == HDF_HANDLE_FILE)
outlen = fread(hfd->cache, 1, CACHE_SIZE, hfd->handle->f);
else if (hfd->handle_valid == HDF_HANDLE_ZFILE)
outlen = zfile_fread (hfd->cache, 1, CACHE_SIZE, hfd->handle->zf);
hfd->cache_valid = 0;
if (outlen != CACHE_SIZE)
return 0;
hfd->cache_valid = 1;
coffset = isincache (hfd, offset, len);
if (coffset >= 0) {
memcpy (buffer, hfd->cache + coffset, len);
return len;
}
write_log (_T("hdf_read: cache bug! offset=%I64d len=%d\n"), offset, len);
hfd->cache_valid = 0;
return 0;
}
int hdf_read_target (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
int got = 0;
uae_u8 *p = (uae_u8*)buffer;
if (hfd->drive_empty)
return 0;
if (offset < hfd->virtual_size) {
uae_u64 len2 = offset + len <= hfd->virtual_size ? len : hfd->virtual_size - offset;
if (!hfd->virtual_rdb)
return 0;
memcpy (buffer, hfd->virtual_rdb + offset, len2);
return len2;
}
offset -= hfd->virtual_size;
while (len > 0) {
int maxlen;
int ret;
if (hfd->physsize < CACHE_SIZE) {
hfd->cache_valid = 0;
hdf_seek (hfd, offset);
poscheck (hfd, len);
if (hfd->handle_valid == HDF_HANDLE_FILE) {
ret = fread (hfd->cache, 1, len, hfd->handle->f);
memcpy (buffer, hfd->cache, ret);
} else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
ret = zfile_fread (buffer, 1, len, hfd->handle->zf);
}
maxlen = len;
} else {
maxlen = len > CACHE_SIZE ? CACHE_SIZE : len;
ret = hdf_read_2 (hfd, p, offset, maxlen);
}
got += ret;
if (ret != maxlen)
return got;
offset += maxlen;
p += maxlen;
len -= maxlen;
}
return got;
}
static int hdf_write_2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
int outlen = 0;
if (hfd->readonly)
return 0;
if (hfd->dangerous)
return 0;
hfd->cache_valid = 0;
hdf_seek (hfd, offset);
poscheck (hfd, len);
memcpy (hfd->cache, buffer, len);
if (hfd->handle_valid == HDF_HANDLE_FILE) {
TCHAR *name = hfd->emptyname == NULL ? (char *) _T("<unknown>") : hfd->emptyname;
outlen = fwrite (hfd->cache, 1, len, hfd->handle->f);
if (offset == 0) {
int outlen2;
uae_u8 *tmp;
int tmplen = 512;
tmp = (uae_u8*)malloc (tmplen);
if (tmp) {
memset (tmp, 0xa1, tmplen);
hdf_seek (hfd, offset);
outlen2 = fread (tmp, 1, tmplen, hfd->handle->f);
if (memcmp (hfd->cache, tmp, tmplen) != 0 || outlen != len)
gui_message (_T("\"%s\"\n\nblock zero write failed!"), name);
free (tmp);
}
}
} else if (hfd->handle_valid == HDF_HANDLE_ZFILE) {
outlen = zfile_fwrite (hfd->cache, 1, len, hfd->handle->zf);
}
return outlen;
}
int hdf_write_target (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
{
int got = 0;
uae_u8 *p = (uae_u8*)buffer;
if (hfd->drive_empty)
return 0;
if (offset < hfd->virtual_size)
return len;
offset -= hfd->virtual_size;
while (len > 0) {
int maxlen = len > CACHE_SIZE ? CACHE_SIZE : len;
int ret = hdf_write_2 (hfd, p, offset, maxlen);
if (ret < 0)
return ret;
got += ret;
if (ret != maxlen)
return got;
offset += maxlen;
p += maxlen;
len -= maxlen;
}
return got;
}

View file

@ -29,10 +29,10 @@
@
@----------------------------------------------------------------
copy_screen_8bit:
stmdb sp!, {r4-r7, lr}
stmdb sp!, {r4-r6, lr}
copy_screen_8bit_loop:
pld [r1, #192]
mov r7, #64
mov lr, #64
copy_screen_8bit_loop_2:
ldr r4, [r1], #4
and r5, r4, #255
@ -46,12 +46,12 @@ copy_screen_8bit_loop_2:
ubfx r5, r4, #24, #8
strh r6, [r0], #2
ldr r6, [r3, r5, lsl #2]
subs r7, r7, #4
subs lr, lr, #4
strh r6, [r0], #2
bgt copy_screen_8bit_loop_2
subs r2, r2, #64
bgt copy_screen_8bit_loop
ldmia sp!, {r4-r7, pc}
ldmia sp!, {r4-r6, pc}
@----------------------------------------------------------------
@ -126,48 +126,48 @@ copy_screen_32bit_to_16bit_neon:
@
@----------------------------------------------------------------
ARM_doline_n1:
stmdb sp!, {r4-r9, lr}
stmdb sp!, {r5-r9, lr}
mov r3, #1600
mul r2, r2, r3
ldr r3, =line_data
add r3, r3, r2 @ real_bplpt[0]
ldr r4, =Lookup_doline_n1
ldr lr, =Lookup_doline_n1
ARM_doline_n1_loop:
ldr r2, [r3], #4
ubfx r5, r2, #28, #4
ldr r6, [r4, r5, lsl #2]
ldr r6, [lr, r5, lsl #2]
ubfx r5, r2, #24, #4
ldr r7, [r4, r5, lsl #2]
ldr r7, [lr, r5, lsl #2]
ubfx r5, r2, #20, #4
ldr r8, [r4, r5, lsl #2]
ldr r8, [lr, r5, lsl #2]
ubfx r5, r2, #16, #4
ldr r9, [r4, r5, lsl #2]
ldr r9, [lr, r5, lsl #2]
stmia r0!, {r6-r9}
ubfx r5, r2, #12, #4
ldr r6, [r4, r5, lsl #2]
ldr r6, [lr, r5, lsl #2]
ubfx r5, r2, #8, #4
ldr r7, [r4, r5, lsl #2]
ldr r7, [lr, r5, lsl #2]
ubfx r5, r2, #4, #4
ldr r8, [r4, r5, lsl #2]
ldr r8, [lr, r5, lsl #2]
ubfx r5, r2, #0, #4
ldr r9, [r4, r5, lsl #2]
ldr r9, [lr, r5, lsl #2]
stmia r0!, {r6-r9}
subs r1, r1, #1
bgt ARM_doline_n1_loop
ldmia sp!, {r4-r9, pc}
ldmia sp!, {r5-r9, pc}
.align 8
@ -261,17 +261,17 @@ NEON_doline_n2_exit:
@
@----------------------------------------------------------------
NEON_doline_n3:
stmdb sp!, {r4, lr}
stmdb sp!, {lr}
mov r3, #1600
mul r2, r2, r3
ldr r3, =line_data
add r2, r3, r2 @ real_bplpt[0]
add r3, r2, #200
add r4, r3, #200
add lr, r3, #200
@ Load data as early as possible
vldmia r4!, {d0}
vldmia lr!, {d0}
@ Load masks to registers
vmov.u8 d18, #0x55
@ -280,7 +280,7 @@ NEON_doline_n3:
NEON_doline_n3_loop:
@ Load from real_bplpt (now loaded earlier)
@ vld1.8 d0, [r4]!
@ vld1.8 d0, [lr]!
@ vld1.8 d4, [r2]!
@ vld1.8 d6, [r3]!
@ -340,12 +340,12 @@ NEON_doline_n3_loop:
vst1.8 {d0, d1, d2, d3}, [r0]!
cmp r1, #1 @ Exit from here if odd number of words
ldmeqia sp!, {r4, pc}
ldmeqia sp!, {pc}
subs r1, r1, #2 @ We handle 2 words (64 bit) per loop: wordcount -= 2
@ Load next data (if needed) as early as possible
vldmiagt r4!, {d0}
vldmiagt lr!, {d0}
vzip.8 d7, d5
vzip.8 d6, d4
@ -357,7 +357,7 @@ NEON_doline_n3_loop:
bgt NEON_doline_n3_loop
NEON_doline_n3_exit:
ldmia sp!, {r4, pc}
ldmia sp!, {pc}
.align 8
@ -373,7 +373,7 @@ NEON_doline_n3_exit:
@
@----------------------------------------------------------------
NEON_doline_n4:
stmdb sp!, {r4-r5, lr}
stmdb sp!, {r4, lr}
mov r3, #1600
mul r2, r2, r3
@ -381,11 +381,11 @@ NEON_doline_n4:
add r2, r3, r2 @ real_bplpt[0]
add r3, r2, #200
add r4, r3, #200
add r5, r4, #200
add lr, r4, #200
@ Load data as early as possible
vldmia r4!, {d0}
vldmia r5!, {d2}
vldmia lr!, {d2}
@ Load masks to registers
vmov.u8 d18, #0x55
@ -395,7 +395,7 @@ NEON_doline_n4:
NEON_doline_n4_loop:
@ Load from real_bplpt (now loaded earlier)
@ vld1.8 d0, [r4]!
@ vld1.8 d2, [r5]!
@ vld1.8 d2, [lr]!
@ vld1.8 d4, [r2]!
@ vld1.8 d6, [r3]!
@ -457,7 +457,7 @@ NEON_doline_n4_loop:
vst1.8 {d0, d1, d2, d3}, [r0]!
cmp r1, #1 @ Exit from here if odd number of words
ldmeqia sp!, {r4-r5, pc}
ldmeqia sp!, {r4, pc}
subs r1, r1, #2 @ We handle 2 words (64 bit) per loop: wordcount -= 2
@ -467,7 +467,7 @@ NEON_doline_n4_loop:
vzip.8 d7, d5
vzip.8 d6, d4
vldmiagt r5!, {d2}
vldmiagt lr!, {d2}
vzip.32 d7, d6
vzip.32 d5, d4
@ -477,7 +477,7 @@ NEON_doline_n4_loop:
bgt NEON_doline_n4_loop
NEON_doline_n4_exit:
ldmia sp!, {r4-r5, pc}
ldmia sp!, {r4, pc}
.align 8
@ -493,7 +493,7 @@ NEON_doline_n4_exit:
@
@----------------------------------------------------------------
NEON_doline_n6:
stmdb sp!, {r4-r7, lr}
stmdb sp!, {r4-r6, lr}
mov r3, #1600
mul r2, r2, r3
@ -503,7 +503,7 @@ NEON_doline_n6:
add r4, r3, #200
add r5, r4, #200
add r6, r5, #200
add r7, r6, #200
add lr, r6, #200
@ Load masks to registers
vmov.u8 d18, #0x55
@ -513,7 +513,7 @@ NEON_doline_n6:
NEON_doline_n6_loop:
@ Load data as early as possible
vldmia r6!, {d5}
vldmia r7!, {d7}
vldmia lr!, {d7}
@ Load data as early as possible
vldmia r4!, {d0}
@ -592,7 +592,7 @@ NEON_doline_n6_loop:
vst1.8 {d0, d1, d2, d3}, [r0]!
cmp r1, #1 @ Exit from here if odd number of words
ldmeqia sp!, {r4-r7, pc}
ldmeqia sp!, {r4-r6, pc}
subs r1, r1, #2 @ We handle 2 words (64 bit) per loop: wordcount -= 2
@ -606,7 +606,7 @@ NEON_doline_n6_loop:
bgt NEON_doline_n6_loop
NEON_doline_n6_exit:
ldmia sp!, {r4-r7, pc}
ldmia sp!, {r4-r6, pc}
.align 8
@ -622,7 +622,7 @@ NEON_doline_n6_exit:
@
@----------------------------------------------------------------
NEON_doline_n8:
stmdb sp!, {r4-r9, lr}
stmdb sp!, {r4-r8, lr}
mov r3, #1600
mul r2, r2, r3
@ -634,11 +634,11 @@ NEON_doline_n8:
add r6, r5, #200
add r7, r6, #200
add r8, r7, #200
add r9, r8, #200
add lr, r8, #200
@ Load data as early as possible
vldmia r8!, {d1}
vldmia r9!, {d3}
vldmia lr!, {d3}
@ Load masks to registers
vmov.u8 d18, #0x55
@ -734,7 +734,7 @@ NEON_doline_n8_loop:
vst1.8 {d0, d1, d2, d3}, [r0]!
cmp r1, #1 @ Exit from here if odd number of words
ldmeqia sp!, {r4-r9, pc}
ldmeqia sp!, {r4-r8, pc}
subs r1, r1, #2 @ We handle 2 words (64 bit) per loop: wordcount -= 2
@ -745,7 +745,7 @@ NEON_doline_n8_loop:
vzip.8 d6, d4
@ Load data as early as possible
vldmiagt r9!, {d3}
vldmiagt lr!, {d3}
vzip.32 d7, d6
vzip.32 d5, d4
@ -755,7 +755,7 @@ NEON_doline_n8_loop:
bgt NEON_doline_n8_loop
NEON_doline_n8_exit:
ldmia sp!, {r4-r9, pc}
ldmia sp!, {r4-r8, pc}
.data

View file

@ -41,6 +41,7 @@
#include "rommgr.h"
#include <SDL.h>
#include "gp2x.h"
#include "pandora_rp9.h"
/*
#define DBG_MAX_THREADS 128
@ -122,6 +123,7 @@ int sleep_resolution = 1000 / 1;
static char config_path[MAX_DPATH];
static char rom_path[MAX_DPATH];
static char rp9_path[MAX_DPATH];
char last_loaded_config[MAX_DPATH] = { '\0' };
static bool slow_mouse = false;
@ -306,7 +308,7 @@ void target_default_options (struct uae_prefs *p, int type)
p->pandora_cpu_speed = 600;
p->pandora_joyConf = 0;
p->pandora_joyPort = 0;
p->pandora_joyPort = 2;
p->pandora_tapDelay = 10;
p->pandora_customControls = 0;
@ -426,6 +428,12 @@ void set_rompath(char *newpath)
}
void fetch_rp9path (char *out, int size)
{
strncpy(out, rp9_path, size);
}
void fetch_savestatepath(char *out, int size)
{
strncpy(out, start_path_data, size);
@ -447,19 +455,33 @@ int target_cfgfile_load (struct uae_prefs *p, const char *filename, int type, in
discard_prefs(p, type);
char *ptr = strstr(filename, ".uae");
char *ptr = strstr(filename, ".rp9");
if(ptr > 0)
{
int type = CONFIG_TYPE_HARDWARE | CONFIG_TYPE_HOST;
result = cfgfile_load(p, filename, &type, 0, 1);
}
if(result)
{
set_joyConf(p);
extractFileName(filename, last_loaded_config);
// Load rp9 config
result = rp9_parse_file(p, filename);
if(result)
{
set_joyConf(p);
extractFileName(filename, last_loaded_config);
}
}
else
result = loadconfig_old(p, filename);
{
ptr = strstr(filename, ".uae");
if(ptr > 0)
{
int type = CONFIG_TYPE_HARDWARE | CONFIG_TYPE_HOST;
result = cfgfile_load(p, filename, &type, 0, 1);
}
if(result)
{
set_joyConf(p);
extractFileName(filename, last_loaded_config);
}
else
result = loadconfig_old(p, filename);
}
if(result)
{
@ -645,6 +667,7 @@ void loadAdfDir(void)
strcpy(currentDir, start_path_data);
snprintf(config_path, MAX_DPATH, "%s/conf/", start_path_data);
snprintf(rom_path, MAX_DPATH, "%s/kickstarts/", start_path_data);
snprintf(rp9_path, MAX_DPATH, "%s/rp9/", start_path_data);
snprintf(path, MAX_DPATH, "%s/conf/adfdir.conf", start_path_data);
FILE *f1=fopen(path,"rt");
@ -681,7 +704,12 @@ void loadAdfDir(void)
{
fscanf(f1, "Diskfile=");
get_string(f1, disk, sizeof(disk));
lstMRUDiskList.push_back(disk);
FILE *f = fopen(disk, "rb");
if(f != NULL)
{
fclose(f);
lstMRUDiskList.push_back(disk);
}
}
}
fclose(f1);
@ -776,8 +804,8 @@ int main (int argc, char *argv[])
// Get startup path
getcwd(start_path_data, MAX_DPATH);
loadAdfDir();
rp9_init();
snprintf(savestate_fname, MAX_PATH, "%s/saves/default.ads", start_path_data);
logging_init ();
@ -802,9 +830,11 @@ int main (int argc, char *argv[])
real_main (argc, argv);
ClearAvailableROMList();
romlist_clear();
free_keyring();
free_AmigaMem();
lstMRUDiskList.clear();
rp9_cleanup();
logging_cleanup();

View file

@ -129,6 +129,7 @@ static void addrom(struct romdata *rd, char *path)
strncpy(tmp->Path, path, MAX_PATH);
tmp->ROMType = rd->type;
lstAvailableROMs.push_back(tmp);
romlist_add(path, rd);
}
struct romscandata {
@ -256,6 +257,8 @@ void RescanROMs(void)
std::vector<std::string> files;
char path[MAX_DPATH];
romlist_clear();
ClearAvailableROMList();
fetch_rompath(path, MAX_DPATH);
@ -295,11 +298,28 @@ void ReadConfigFileList(void)
{
char path[MAX_PATH];
std::vector<std::string> files;
const char *filter_rp9[] = { ".rp9", "\0" };
const char *filter_uae[] = { ".uae", "\0" };
const char *filter_conf[] = { ".conf", "\0" };
ClearConfigFileList();
// Read rp9 files
fetch_rp9path(path, MAX_PATH);
ReadDirectory(path, NULL, &files);
FilterFiles(&files, filter_rp9);
for (int i=0; i<files.size(); ++i)
{
ConfigFileInfo *tmp = new ConfigFileInfo();
strncpy(tmp->FullPath, path, MAX_DPATH);
strcat(tmp->FullPath, files[i].c_str());
strncpy(tmp->Name, files[i].c_str(), MAX_DPATH);
removeFileExtension(tmp->Name);
strcpy(tmp->Description, _T("rp9"));
ConfigFilesList.push_back(tmp);
}
// Read standard config files
fetch_configurationpath(path, MAX_PATH);
ReadDirectory(path, NULL, &files);
FilterFiles(&files, filter_uae);
@ -1481,3 +1501,27 @@ int tweakbootpri (int bp, int ab, int dnm)
bp = -127;
return bp;
}
bool hardfile_testrdb (const TCHAR *filename)
{
bool isrdb = false;
struct zfile *f = zfile_fopen (filename, _T("rb"), ZFD_NORMAL);
uae_u8 tmp[8];
int i;
if (!f)
return false;
for (i = 0; i < 16; i++) {
zfile_fseek (f, i * 512, SEEK_SET);
memset (tmp, 0, sizeof tmp);
zfile_fread (tmp, 1, sizeof tmp, f);
if (!memcmp (tmp, "RDSK\0\0\0", 7) || !memcmp (tmp, "DRKS\0\0", 6) || (tmp[0] == 0x53 && tmp[1] == 0x10 && tmp[2] == 0x9b && tmp[3] == 0x13 && tmp[4] == 0 && tmp[5] == 0)) {
// RDSK or ADIDE "encoded" RDSK
isrdb = true;
break;
}
}
zfile_fclose (f);
return isrdb;
}

View file

@ -0,0 +1,566 @@
#include "sysconfig.h"
#include "sysdeps.h"
#include "config.h"
#include "autoconf.h"
#include "uae.h"
#include "options.h"
#include "gui.h"
#include "disk.h"
#include "memory.h"
#include "newcpu.h"
#include "custom.h"
#include "filesys.h"
#include "zfile.h"
#include "archivers/zip/unzip.h"
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <vector>
#define RP9_MANIFEST _T("rp9-manifest.xml")
#define MAX_MANIFEST_ENTRY 256
static char rp9tmp_path[MAX_DPATH];
static std::vector<std::string> lstTmpRP9Files;
static int add_HDF_DHnum = 0;
static bool clip_no_hires = false;
void rp9_init(void)
{
fetch_rp9path(rp9tmp_path, MAX_DPATH);
strncat(rp9tmp_path, _T("tmp/"), MAX_DPATH);
lstTmpRP9Files.clear();
LIBXML_TEST_VERSION
}
static void del_tmpFiles(void)
{
int i;
for(i=0; i<lstTmpRP9Files.size(); ++i)
remove(lstTmpRP9Files[i].c_str());
lstTmpRP9Files.clear();
}
void rp9_cleanup(void)
{
del_tmpFiles();
xmlCleanupParser();
xmlMemoryDump();
}
static xmlNode *get_node(xmlNode *node, const char *name)
{
for(xmlNode *curr_node = node; curr_node; curr_node = curr_node->next) {
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, name) == 0)
return curr_node->children;
}
return NULL;
}
static bool get_value(xmlNode *node, const char *key, char *value, int max_size)
{
bool bResult = false;
for(xmlNode *curr_node = node; curr_node; curr_node = curr_node->next) {
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, key) == 0) {
xmlChar *content = xmlNodeGetContent(curr_node);
if(content != NULL) {
strncpy(value, (char *)content, max_size);
xmlFree(content);
bResult = true;
}
break;
}
}
return bResult;
}
static void set_default_system(struct uae_prefs *p, const char *system, int rom)
{
default_prefs(p, 0);
del_tmpFiles();
if(strcmp(system, "a-500") == 0)
bip_a500(p, rom);
else if(strcmp(system, "a-500plus") == 0)
bip_a500plus(p, rom);
else if(strcmp(system, "a-1200") == 0)
bip_a1200(p, rom);
else if(strcmp(system, "a-2000") == 0)
bip_a2000(p, rom);
else if(strcmp(system, "a-4000") == 0)
bip_a4000(p, rom);
}
static void parse_compatibility(struct uae_prefs *p, xmlNode *node)
{
for(xmlNode *curr_node = node; curr_node; curr_node = curr_node->next) {
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, _T("compatibility")) == 0) {
xmlChar *content = xmlNodeGetContent(curr_node);
if(content != NULL) {
if(strcmp((const char *) content, "flexible-blitter-immediate") == 0)
p->immediate_blits = 1;
else if(strcmp((const char *) content, "turbo-floppy") == 0)
p->floppy_speed = 400;
else if(strcmp((const char *) content, "flexible-sprite-collisions-spritesplayfield") == 0)
p->collision_level = 2;
else if(strcmp((const char *) content, "flexible-sprite-collisions-spritesonly") == 0)
p->collision_level = 1;
else if(strcmp((const char *) content, "flexible-sound") == 0)
p->produce_sound = 2;
else if(strcmp((const char *) content, "flexible-maxhorizontal-nohires") == 0)
clip_no_hires = true;
else if(strcmp((const char *) content, "jit") == 0)
{
p->cachesize = 8192;
p->address_space_24 = 0;
}
else if(strcmp((const char *) content, "flexible-cpu-cycles") == 0)
p->cpu_compatible = 0;
else if(strcmp((const char *) content, "flexible-maxhorizontal-nosuperhires") == 0)
; /* nothing to change */
else if(strcmp((const char *) content, "flexible-maxvertical-nointerlace") == 0)
; /* nothing to change */
else
printf("rp9: unknown compatibility: %s\n", content);
xmlFree(content);
}
}
}
}
static void parse_ram(struct uae_prefs *p, xmlNode *node)
{
for(xmlNode *curr_node = node; curr_node; curr_node = curr_node->next) {
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, _T("ram")) == 0) {
xmlChar *content = xmlNodeGetContent(curr_node);
if(content != NULL) {
xmlChar *attr = xmlGetProp(curr_node, (const xmlChar *) _T("type"));
if(attr != NULL)
{
int size = atoi((const char *)content);
if(strcmp((const char *) attr, "fast") == 0)
p->fastmem_size = size;
else if(strcmp((const char *) attr, "z3") == 0)
p->z3fastmem_size = size;
else if(strcmp((const char *) attr, "chip") == 0)
p->chipmem_size = size;
xmlFree(attr);
}
xmlFree(content);
}
}
}
}
static void parse_clip(struct uae_prefs *p, xmlNode *node)
{
int left = 0, top = 0, width = 320, height = 240;
for(xmlNode *curr_node = node; curr_node; curr_node = curr_node->next)
{
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, _T("clip")) == 0)
{
xmlChar *attr = xmlGetProp(curr_node, (const xmlChar *) _T("left"));
if(attr != NULL)
{
left = atoi((const char *)attr);
xmlFree(attr);
}
attr = xmlGetProp(curr_node, (const xmlChar *) _T("top"));
if(attr != NULL)
{
top = atoi((const char *)attr) / 2;
p->pandora_vertical_offset = top - 41; // VBLANK_ENDLINE_PAL + OFFSET_Y_ADJUST
xmlFree(attr);
}
attr = xmlGetProp(curr_node, (const xmlChar *) _T("width"));
if(attr != NULL)
{
width = atoi((const char *)attr);
if(p->chipset_mask & CSMASK_AGA && clip_no_hires == false)
width = width / 2; // Use Hires in AGA mode
else
width = width / 4; // Use Lores in OCS/ECS
if(width <= 320)
p->gfx_size.width = 320;
else if(width <= 352)
p->gfx_size.width = 352;
else if(width <= 384)
p->gfx_size.width = 384;
else if(width <= 640)
p->gfx_size.width = 640;
else if(width <= 704)
p->gfx_size.width = 704;
else
p->gfx_size.width = 768;
xmlFree(attr);
}
attr = xmlGetProp(curr_node, (const xmlChar *) _T("height"));
if(attr != NULL)
{
height = atoi((const char *)attr) / 2;
if(height <= 200)
p->gfx_size.height = 200;
else if(height <= 216)
p->gfx_size.height = 216;
else if(height <= 240)
p->gfx_size.height = 240;
else if(height <= 256)
p->gfx_size.height = 256;
else if(height <= 262)
p->gfx_size.height = 262;
else
p->gfx_size.height = 270;
xmlFree(attr);
}
break;
}
}
}
static void parse_peripheral(struct uae_prefs *p, xmlNode *node)
{
for(xmlNode *curr_node = node; curr_node; curr_node = curr_node->next)
{
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, _T("peripheral")) == 0)
{
xmlChar *content = xmlNodeGetContent(curr_node);
if(content != NULL)
{
if(strcmp((const char *)content, "floppy") == 0)
{
int type = DRV_35_DD;
int unit = -1;
xmlChar *attr = xmlGetProp(curr_node, (const xmlChar *) _T("type"));
if(attr != NULL)
{
if(strcmp((const char *) attr, "dd") == 0)
type = DRV_35_DD;
else
type = DRV_35_HD;
xmlFree(attr);
}
attr = xmlGetProp(curr_node, (const xmlChar *) _T("unit"));
if(attr != NULL)
{
unit = atoi((const char *) attr);
xmlFree(attr);
}
if(unit >= 0)
{
if(unit + 1 > p->nr_floppies)
p->nr_floppies = unit + 1;
p->floppyslots[unit].dfxtype = type;
}
}
else if(strcmp((const char *)content, "a-501") == 0)
p->bogomem_size = 0x00080000;
else if(strcmp((const char *)content, "cpu") == 0)
{
xmlChar *attr = xmlGetProp(curr_node, (const xmlChar *) _T("type"));
if(attr != NULL)
{
p->cpu_model = atoi((const char *) attr);
if(p->cpu_model > 68020)
p->address_space_24 = 0;
xmlFree(attr);
}
attr = xmlGetProp(curr_node, (const xmlChar *) _T("speed"));
if(attr != NULL)
{
if(strcmp((const char *) attr, "max") == 0)
p->m68k_speed = -1;
xmlFree(attr);
}
}
else if(strcmp((const char *)content, "jit") == 0)
{
xmlChar *attr = xmlGetProp(curr_node, (const xmlChar *) _T("memory"));
if(attr != NULL)
{
p->cachesize = atoi((const char *) attr) / 1024;
xmlFree(attr);
}
}
xmlFree(content);
}
}
}
}
static void parse_boot(struct uae_prefs *p, xmlNode *node)
{
for(xmlNode *curr_node = node; curr_node; curr_node = curr_node->next)
{
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, _T("boot")) == 0)
{
xmlChar *attr = xmlGetProp(curr_node, (const xmlChar *) _T("type"));
if(attr != NULL)
{
if(strcmp((const char *) attr, "hdf") == 0)
{
// Build-in hdf required
xmlChar *content = xmlNodeGetContent(curr_node);
if(content != NULL)
{
char target_file[MAX_DPATH];
fetch_rp9path(target_file, MAX_DPATH);
strncat(target_file, "workbench-", MAX_DPATH);
strncat(target_file, (const char *)content, MAX_DPATH);
strncat(target_file, ".hdf", MAX_DPATH);
FILE *f = fopen(target_file, "rb");
if(f != NULL)
{
char dhx[8];
struct uaedev_config_info *uci;
int readonly = 0;
fclose(f);
xmlChar *ro = xmlGetProp(curr_node, (const xmlChar *) _T("readonly"));
if(ro != NULL)
{
if(strcmp((const char *) ro, "true") == 0)
readonly = 1;
xmlFree(ro);
}
sprintf(dhx, "DH%d", add_HDF_DHnum);
++add_HDF_DHnum;
if(hardfile_testrdb (target_file))
uci = add_filesys_config(p, -1, dhx, 0, target_file, readonly, 0, 0, 0, 512, 127, 0, 0, 0);
else
uci = add_filesys_config(p, -1, dhx, 0, target_file, readonly, 32, 1, 2, 512, 127, 0, 0, 0);
if (uci)
hardfile_do_disk_change (uci, 1);
gui_force_rtarea_hdchange();
}
xmlFree(content);
}
}
xmlFree(attr);
}
}
}
}
static void extract_media(struct uae_prefs *p, unzFile uz, xmlNode *node)
{
xmlNode *tmp = get_node(node, "media");
if(tmp != NULL)
{
for(xmlNode *curr_node = tmp; curr_node; curr_node = curr_node->next)
{
int mediatype = -1;
if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, _T("floppy")) == 0)
mediatype = 0;
else if (curr_node->type == XML_ELEMENT_NODE && strcmp((const char *)curr_node->name, _T("harddrive")) == 0)
mediatype = 1;
if(mediatype >= 0)
{
xmlChar *content = xmlNodeGetContent(curr_node);
if(content != NULL)
{
int priority = 0;
xmlChar *attr = xmlGetProp(curr_node, (const xmlChar *) _T("priority"));
if(attr != NULL)
{
priority = atoi((const char *)attr);
xmlFree(attr);
}
if (unzLocateFile (uz, (char *)content, 1) == UNZ_OK)
{
unz_file_info file_info;
if (unzGetCurrentFileInfo (uz, &file_info, NULL, 0, NULL, 0, NULL, 0) == UNZ_OK)
{
void *buffer = malloc(file_info.uncompressed_size);
if(buffer != NULL)
{
if (unzOpenCurrentFile (uz) == UNZ_OK)
{
int readsize = unzReadCurrentFile(uz, buffer, file_info.uncompressed_size);
unzCloseCurrentFile(uz);
if(readsize == file_info.uncompressed_size)
{
char target_file[MAX_DPATH];
snprintf(target_file, MAX_DPATH, "%s%s", rp9tmp_path, content);
FILE *f = fopen(target_file, "wb");
if(f != NULL)
{
fwrite(buffer, 1, readsize, f);
fclose(f);
if(mediatype == 0)
{
// Add floppy
if(priority < 2)
{
strncpy(p->floppyslots[0].df, target_file, sizeof(p->floppyslots[0].df));
disk_insert(0, p->floppyslots[0].df);
}
else if(priority == 2 && p->nr_floppies > 1)
{
strncpy(p->floppyslots[1].df, target_file, sizeof(p->floppyslots[1].df));
disk_insert(1, p->floppyslots[1].df);
}
else if(priority == 3 && p->nr_floppies > 2)
{
strncpy(p->floppyslots[2].df, target_file, sizeof(p->floppyslots[2].df));
disk_insert(2, p->floppyslots[2].df);
}
else if(priority == 4 && p->nr_floppies > 3)
{
strncpy(p->floppyslots[3].df, target_file, sizeof(p->floppyslots[3].df));
disk_insert(3, p->floppyslots[3].df);
}
AddFileToDiskList(target_file, 1);
}
else
{
// Add hardfile
struct uaedev_config_info *uci;
char dhx[8];
sprintf(dhx, "DH%d", add_HDF_DHnum);
++add_HDF_DHnum;
if(hardfile_testrdb (target_file))
uci = add_filesys_config(p, -1, dhx, 0, target_file, 0, 0, 0, 0, 512, 0, 0, 0, 0);
else
uci = add_filesys_config(p, -1, dhx, 0, target_file, 0, 32, 1, 2, 512, 0, 0, 0, 0);
if (uci)
hardfile_do_disk_change (uci, 1);
gui_force_rtarea_hdchange();
}
lstTmpRP9Files.push_back(target_file);
}
}
}
free(buffer);
}
}
}
xmlFree(content);
}
}
}
}
}
static bool parse_manifest(struct uae_prefs *p, unzFile uz, const char *manifest)
{
bool bResult = false;
char buffer[MAX_MANIFEST_ENTRY];
xmlDocPtr doc = xmlReadMemory(manifest, strlen(manifest), NULL, NULL, 0);;
if(doc != NULL)
{
xmlNode *root_element = xmlDocGetRootElement(doc);
xmlNode *rp9 = get_node(root_element, "rp9");
if(rp9 != NULL)
{
xmlNode *app = get_node(rp9, "application");
if(app != NULL)
{
int rom = -1;
xmlNode *tmp = get_node(app, "description");
if(tmp != NULL && get_value(tmp, "systemrom", buffer, MAX_MANIFEST_ENTRY))
rom = atoi(buffer);
tmp = get_node(app, "configuration");
if(tmp != NULL && get_value(tmp, "system", buffer, MAX_MANIFEST_ENTRY))
{
set_default_system(p, buffer, rom);
parse_compatibility(p, tmp);
parse_ram(p, tmp);
parse_clip(p, tmp);
parse_peripheral(p, tmp);
parse_boot(p, tmp);
extract_media(p, uz, app);
bResult = true;
}
}
}
xmlFreeDoc(doc);
}
return bResult;
}
bool rp9_parse_file(struct uae_prefs *p, const char *filename)
{
bool bResult = false;
struct zfile *zf;
unzFile uz;
unz_file_info file_info;
char *manifest;
add_HDF_DHnum = 0;
clip_no_hires = false;
zf = zfile_fopen(filename, _T("rb"));
if(zf != NULL)
{
uz = unzOpen(zf);
if (uz != NULL)
{
if (unzLocateFile (uz, RP9_MANIFEST, 1) == UNZ_OK)
{
if (unzGetCurrentFileInfo (uz, &file_info, NULL, 0, NULL, 0, NULL, 0) == UNZ_OK)
{
manifest = (char *)malloc(file_info.uncompressed_size + 1);
if(manifest != NULL)
{
if (unzOpenCurrentFile (uz) == UNZ_OK)
{
int readsize = unzReadCurrentFile(uz, manifest, file_info.uncompressed_size);
unzCloseCurrentFile(uz);
if(readsize == file_info.uncompressed_size)
{
manifest[readsize] = '\0';
bResult = parse_manifest(p, uz, manifest);
if(bResult)
{
// Fixup some prefs...
if(p->m68k_speed >= 0)
p->cachesize = 0; // Use JIT only if max. speed selected
p->input_joymouse_multiplier = 5; // Most games need slower mouse movement...
}
}
}
free(manifest);
}
}
}
unzClose (uz);
}
zfile_fclose(zf);
}
return bResult;
}

View file

@ -0,0 +1,3 @@
void rp9_init(void);
void rp9_cleanup(void);
bool rp9_parse_file(struct uae_prefs *p, const char *filename);

View file

@ -3270,7 +3270,7 @@ static uaecptr uaegfx_card_install (TrapContext *ctx, uae_u32 extrasize)
uaecptr exec = get_long (4);
if (uaegfx_old || !gfxmem_start)
return NULL;
return 0;
uaegfx_resid = ds (_T("UAE Graphics Card 3.3"));
uaegfx_vblankname = ds (_T("UAE Graphics Card VBLANK"));

View file

@ -34,3 +34,5 @@ void keyboard_init(void);
void reinit_amiga(void);
int count_HDs(struct uae_prefs *p);
extern void gui_force_rtarea_hdchange(void);
extern bool hardfile_testrdb (const TCHAR *filename);