mirror of https://github.com/JorjBauer/aiie.git
bios support for HD files; Teensy 32-MB HD image support
This commit is contained in:
parent
0fecbd3956
commit
8aafabc61e
|
@ -26,17 +26,20 @@ As with many emulators, you have to go get the ROMs yourself. I've got
|
||||||
the ROMs that I dumped out of my Apple //e. You can probably get yours
|
the ROMs that I dumped out of my Apple //e. You can probably get yours
|
||||||
a lot easier.
|
a lot easier.
|
||||||
|
|
||||||
There are three files that you'll need:
|
There are four files that you'll need:
|
||||||
|
|
||||||
* apple2e.rom -- a 32k dump of the entire Apple //e ROM
|
* apple2e.rom -- a 32k dump of the entire Apple //e ROM
|
||||||
* disk.rom -- a 256 byte dump of the DiskII controller ROM (16-sector P5)
|
* disk.rom -- a 256 byte dump of the DiskII controller ROM (16-sector P5)
|
||||||
* parallel.rom -- a 256 byte dump of the Apple Parallel Card
|
* parallel.rom -- a 256 byte dump of the Apple Parallel Card
|
||||||
|
* HDDRVR.BIN -- a 256 byte hard drive driver from AppleWin
|
||||||
|
(https://github.com/AppleWin/AppleWin/blob/master/firmware/HDD/HDDRVR.BIN)
|
||||||
|
|
||||||
The MD5 sums of those files are:
|
The MD5 sums of those files are:
|
||||||
|
|
||||||
* 003a780b461c96ae3e72861ed0f4d3d9 apple2e.rom
|
* 003a780b461c96ae3e72861ed0f4d3d9 apple2e.rom
|
||||||
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom
|
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom
|
||||||
* 5902996f16dc78fc013f6e1db14805b3 parallel.rom
|
* 5902996f16dc78fc013f6e1db14805b3 parallel.rom
|
||||||
|
* e91f379957d87aa0af0c7255f6ee6ba0 HDDRVR.BIN
|
||||||
|
|
||||||
From those, the appropriate headers will be automatically generated by
|
From those, the appropriate headers will be automatically generated by
|
||||||
"make roms" (or any other target that relies on the ROMs).
|
"make roms" (or any other target that relies on the ROMs).
|
||||||
|
|
|
@ -101,6 +101,11 @@ void AppleVM::insertDisk(uint8_t drivenum, const char *filename, bool drawIt)
|
||||||
disk6->insertDisk(drivenum, filename, drawIt);
|
disk6->insertDisk(drivenum, filename, drawIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *AppleVM::HDName(uint8_t drivenum)
|
||||||
|
{
|
||||||
|
return hd32->diskName(drivenum);
|
||||||
|
}
|
||||||
|
|
||||||
void AppleVM::ejectHD(uint8_t drivenum)
|
void AppleVM::ejectHD(uint8_t drivenum)
|
||||||
{
|
{
|
||||||
hd32->ejectDisk(drivenum);
|
hd32->ejectDisk(drivenum);
|
||||||
|
|
|
@ -30,6 +30,7 @@ class AppleVM : public VM {
|
||||||
void ejectDisk(uint8_t drivenum);
|
void ejectDisk(uint8_t drivenum);
|
||||||
void insertDisk(uint8_t drivenum, const char *filename, bool drawIt = true);
|
void insertDisk(uint8_t drivenum, const char *filename, bool drawIt = true);
|
||||||
|
|
||||||
|
const char *HDName(uint8_t drivenum);
|
||||||
void ejectHD(uint8_t drivenum);
|
void ejectHD(uint8_t drivenum);
|
||||||
void insertHD(uint8_t drivenum, const char *filename);
|
void insertHD(uint8_t drivenum, const char *filename);
|
||||||
|
|
||||||
|
|
|
@ -238,7 +238,7 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: fixed test disk...
|
// FIXME: fixed test disk...
|
||||||
((AppleVM *)g_vm)->insertHD(0, "hd32.img");
|
// ((AppleVM *)g_vm)->insertHD(0, "hd32.img");
|
||||||
|
|
||||||
nonblock(NB_ENABLE);
|
nonblock(NB_ENABLE);
|
||||||
|
|
||||||
|
|
|
@ -12,16 +12,18 @@
|
||||||
enum {
|
enum {
|
||||||
ACT_EXIT = 0,
|
ACT_EXIT = 0,
|
||||||
ACT_RESET = 1,
|
ACT_RESET = 1,
|
||||||
ACT_REBOOT = 2,
|
ACT_COLDBOOT = 2,
|
||||||
ACT_MONITOR = 3,
|
ACT_MONITOR = 3,
|
||||||
ACT_DISPLAYTYPE = 4,
|
ACT_DISPLAYTYPE = 4,
|
||||||
ACT_DEBUG = 5,
|
ACT_DEBUG = 5,
|
||||||
ACT_DISK1 = 6,
|
ACT_DISK1 = 6,
|
||||||
ACT_DISK2 = 7,
|
ACT_DISK2 = 7,
|
||||||
ACT_VOLPLUS = 8,
|
ACT_HD1 = 8,
|
||||||
ACT_VOLMINUS = 9,
|
ACT_HD2 = 9,
|
||||||
|
ACT_VOLPLUS = 10,
|
||||||
|
ACT_VOLMINUS = 11,
|
||||||
|
|
||||||
NUM_ACTIONS = 10
|
NUM_ACTIONS = 12
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *titles[NUM_ACTIONS] = { "Resume",
|
const char *titles[NUM_ACTIONS] = { "Resume",
|
||||||
|
@ -32,6 +34,8 @@ const char *titles[NUM_ACTIONS] = { "Resume",
|
||||||
"Debug: %s",
|
"Debug: %s",
|
||||||
"%s Disk 1",
|
"%s Disk 1",
|
||||||
"%s Disk 2",
|
"%s Disk 2",
|
||||||
|
"%s HD 1",
|
||||||
|
"%s HD 2",
|
||||||
"Volume +",
|
"Volume +",
|
||||||
"Volume -"
|
"Volume -"
|
||||||
};
|
};
|
||||||
|
@ -86,7 +90,7 @@ bool BIOS::runUntilDone()
|
||||||
switch (prevAction = GetAction(prevAction)) {
|
switch (prevAction = GetAction(prevAction)) {
|
||||||
case ACT_EXIT:
|
case ACT_EXIT:
|
||||||
goto done;
|
goto done;
|
||||||
case ACT_REBOOT:
|
case ACT_COLDBOOT:
|
||||||
ColdReboot();
|
ColdReboot();
|
||||||
goto done;
|
goto done;
|
||||||
case ACT_RESET:
|
case ACT_RESET:
|
||||||
|
@ -124,6 +128,26 @@ bool BIOS::runUntilDone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ACT_HD1:
|
||||||
|
if (((AppleVM *)g_vm)->HDName(0)[0] != '\0') {
|
||||||
|
((AppleVM *)g_vm)->ejectHD(0);
|
||||||
|
} else {
|
||||||
|
if (SelectDiskImage()) {
|
||||||
|
((AppleVM *)g_vm)->insertHD(0, staticPathConcat(rootPath, fileDirectory[selectedFile]));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACT_HD2:
|
||||||
|
if (((AppleVM *)g_vm)->HDName(1)[0] != '\0') {
|
||||||
|
((AppleVM *)g_vm)->ejectHD(1);
|
||||||
|
} else {
|
||||||
|
if (SelectDiskImage()) {
|
||||||
|
((AppleVM *)g_vm)->insertHD(1, staticPathConcat(rootPath, fileDirectory[selectedFile]));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case ACT_VOLPLUS:
|
case ACT_VOLPLUS:
|
||||||
g_volume ++;
|
g_volume ++;
|
||||||
if (g_volume > 15) {
|
if (g_volume > 15) {
|
||||||
|
@ -204,12 +228,14 @@ bool BIOS::isActionActive(int8_t action)
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case ACT_EXIT:
|
case ACT_EXIT:
|
||||||
case ACT_RESET:
|
case ACT_RESET:
|
||||||
case ACT_REBOOT:
|
case ACT_COLDBOOT:
|
||||||
case ACT_MONITOR:
|
case ACT_MONITOR:
|
||||||
case ACT_DISPLAYTYPE:
|
case ACT_DISPLAYTYPE:
|
||||||
case ACT_DEBUG:
|
case ACT_DEBUG:
|
||||||
case ACT_DISK1:
|
case ACT_DISK1:
|
||||||
case ACT_DISK2:
|
case ACT_DISK2:
|
||||||
|
case ACT_HD1:
|
||||||
|
case ACT_HD2:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case ACT_VOLPLUS:
|
case ACT_VOLPLUS:
|
||||||
|
@ -225,11 +251,13 @@ bool BIOS::isActionActive(int8_t action)
|
||||||
void BIOS::DrawMainMenu(int8_t selection)
|
void BIOS::DrawMainMenu(int8_t selection)
|
||||||
{
|
{
|
||||||
((TeensyDisplay *)g_display)->clrScr();
|
((TeensyDisplay *)g_display)->clrScr();
|
||||||
g_display->drawString(M_NORMAL, 0, 12, "BIOS Configuration");
|
g_display->drawString(M_NORMAL, 0, 0, "BIOS Configuration");
|
||||||
for (int i=0; i<NUM_ACTIONS; i++) {
|
for (int i=0; i<NUM_ACTIONS; i++) {
|
||||||
char buf[25];
|
char buf[25];
|
||||||
if (i == ACT_DISK1 || i == ACT_DISK2) {
|
if (i == ACT_DISK1 || i == ACT_DISK2) {
|
||||||
sprintf(buf, titles[i], ((AppleVM *)g_vm)->DiskName(i - ACT_DISK1)[0] ? "Eject" : "Insert");
|
sprintf(buf, titles[i], ((AppleVM *)g_vm)->DiskName(i - ACT_DISK1)[0] ? "Eject" : "Insert");
|
||||||
|
} else if (i == ACT_HD1 || i == ACT_HD2) {
|
||||||
|
sprintf(buf, titles[i], ((AppleVM *)g_vm)->HDName(i - ACT_HD1)[0] ? "Eject" : "Insert");
|
||||||
} else if (i == ACT_DISPLAYTYPE) {
|
} else if (i == ACT_DISPLAYTYPE) {
|
||||||
switch (g_displayType) {
|
switch (g_displayType) {
|
||||||
case m_blackAndWhite:
|
case m_blackAndWhite:
|
||||||
|
@ -277,9 +305,9 @@ void BIOS::DrawMainMenu(int8_t selection)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isActionActive(i)) {
|
if (isActionActive(i)) {
|
||||||
g_display->drawString(selection == i ? M_SELECTED : M_NORMAL, 10, 50 + 14 * i, buf);
|
g_display->drawString(selection == i ? M_SELECTED : M_NORMAL, 10, 20 + 14 * i, buf);
|
||||||
} else {
|
} else {
|
||||||
g_display->drawString(selection == i ? M_SELECTDISABLED : M_DISABLED, 10, 50 + 14 * i, buf);
|
g_display->drawString(selection == i ? M_SELECTDISABLED : M_DISABLED, 10, 20 + 14 * i, buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,8 +430,7 @@ uint8_t BIOS::GatherFilenames(uint8_t pageOffset)
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
char fn[BIOS_MAXPATH];
|
char fn[BIOS_MAXPATH];
|
||||||
// FIXME: add po, nib
|
int8_t idx = g_filemanager->readDir(rootPath, "dsk,.po,nib,img", fn, startNum + count, BIOS_MAXPATH);
|
||||||
int8_t idx = g_filemanager->readDir(rootPath, "dsk", fn, startNum + count, BIOS_MAXPATH);
|
|
||||||
|
|
||||||
if (idx == -1) {
|
if (idx == -1) {
|
||||||
return count;
|
return count;
|
||||||
|
|
|
@ -10,6 +10,9 @@ DIR dir;
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
FIL fil;
|
FIL fil;
|
||||||
|
|
||||||
|
int8_t rawFd = -1;
|
||||||
|
FIL rawFil;
|
||||||
|
|
||||||
static TCHAR *char2tchar( const char *charString, int nn, TCHAR *output)
|
static TCHAR *char2tchar( const char *charString, int nn, TCHAR *output)
|
||||||
{
|
{
|
||||||
int ii;
|
int ii;
|
||||||
|
@ -42,6 +45,12 @@ TeensyFileManager::~TeensyFileManager()
|
||||||
|
|
||||||
int8_t TeensyFileManager::openFile(const char *name)
|
int8_t TeensyFileManager::openFile(const char *name)
|
||||||
{
|
{
|
||||||
|
// invalidate the raw file cache
|
||||||
|
if (rawFd != -1) {
|
||||||
|
f_close(&rawFil);
|
||||||
|
rawFd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// See if there's a hole to re-use...
|
// See if there's a hole to re-use...
|
||||||
for (int i=0; i<numCached; i++) {
|
for (int i=0; i<numCached; i++) {
|
||||||
if (cachedNames[i][0] == '\0') {
|
if (cachedNames[i][0] == '\0') {
|
||||||
|
@ -68,6 +77,12 @@ int8_t TeensyFileManager::openFile(const char *name)
|
||||||
|
|
||||||
void TeensyFileManager::closeFile(int8_t fd)
|
void TeensyFileManager::closeFile(int8_t fd)
|
||||||
{
|
{
|
||||||
|
// invalidate the raw file cache
|
||||||
|
if (rawFd != -1) {
|
||||||
|
f_close(&rawFil);
|
||||||
|
rawFd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// invalid fd provided?
|
// invalid fd provided?
|
||||||
if (fd < 0 || fd >= numCached)
|
if (fd < 0 || fd >= numCached)
|
||||||
return;
|
return;
|
||||||
|
@ -136,7 +151,7 @@ int8_t TeensyFileManager::readDir(const char *where, const char *suffix, char *o
|
||||||
}
|
}
|
||||||
p = strstr(p, ",")+1;
|
p = strstr(p, ",")+1;
|
||||||
}
|
}
|
||||||
if (matchesAny)
|
if (!matchesAny)
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// one suffix to check
|
// one suffix to check
|
||||||
|
@ -273,6 +288,36 @@ bool TeensyFileManager::writeTrack(int8_t fd, uint8_t *fromWhere, bool isNib)
|
||||||
return (v == (isNib ? 0x1a00 : (256*16)));
|
return (v == (isNib ? 0x1a00 : (256*16)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TeensyFileManager::_prepCache(int8_t fd)
|
||||||
|
{
|
||||||
|
FRESULT rc;
|
||||||
|
|
||||||
|
if (rawFd == -1 ||
|
||||||
|
rawFd != fd) {
|
||||||
|
|
||||||
|
// Not our cached file, or we have no cached file
|
||||||
|
if (rawFd != -1) {
|
||||||
|
// Close the old one if we had one
|
||||||
|
Serial.println("closing old HD cache");
|
||||||
|
f_close(&rawFil);
|
||||||
|
rawFd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the new one
|
||||||
|
TCHAR buf[MAXPATH];
|
||||||
|
char2tchar(cachedNames[fd], MAXPATH, buf);
|
||||||
|
rc = f_open(&rawFil, (TCHAR*) buf, FA_READ|FA_WRITE);
|
||||||
|
if (rc) {
|
||||||
|
Serial.println("readByteAt: failed to open");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Serial.println("new cache file open");
|
||||||
|
rawFd = fd; // cache is live
|
||||||
|
}
|
||||||
|
|
||||||
|
return (!rc);
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t TeensyFileManager::readByteAt(int8_t fd, uint32_t pos)
|
uint8_t TeensyFileManager::readByteAt(int8_t fd, uint32_t pos)
|
||||||
{
|
{
|
||||||
// open, seek, read, close.
|
// open, seek, read, close.
|
||||||
|
@ -282,26 +327,21 @@ uint8_t TeensyFileManager::readByteAt(int8_t fd, uint32_t pos)
|
||||||
if (cachedNames[fd][0] == 0)
|
if (cachedNames[fd][0] == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// open, seek, read, close.
|
FRESULT rc;
|
||||||
TCHAR buf[MAXPATH];
|
|
||||||
char2tchar(cachedNames[fd], MAXPATH, buf);
|
|
||||||
FRESULT rc = f_open(&fil, (TCHAR*) buf, FA_READ);
|
|
||||||
if (rc) {
|
|
||||||
Serial.println("readByteAt: failed to open");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = f_lseek(&fil, pos);
|
_prepCache(fd);
|
||||||
|
|
||||||
|
rc = f_lseek(&rawFil, pos);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
Serial.println("readByteAt: seek failed");
|
Serial.println("readByteAt: seek failed");
|
||||||
f_close(&fil);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
UINT v;
|
UINT v;
|
||||||
f_read(&fil, &b, 1, &v);
|
f_read(&rawFil, &b, 1, &v);
|
||||||
f_close(&fil);
|
|
||||||
return (v == 1);
|
// FIXME: check v == 1 & handle error
|
||||||
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TeensyFileManager::writeByteAt(int8_t fd, uint8_t v, uint32_t pos)
|
bool TeensyFileManager::writeByteAt(int8_t fd, uint8_t v, uint32_t pos)
|
||||||
|
@ -313,14 +353,14 @@ bool TeensyFileManager::writeByteAt(int8_t fd, uint8_t v, uint32_t pos)
|
||||||
if (cachedNames[fd][0] == 0)
|
if (cachedNames[fd][0] == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// open, seek, write, close.
|
FRESULT rc;
|
||||||
TCHAR buf[MAXPATH];
|
|
||||||
char2tchar(cachedNames[fd], MAXPATH, buf);
|
_prepCache(fd);
|
||||||
FRESULT rc = f_open(&fil, (TCHAR*) buf, FA_WRITE);
|
|
||||||
rc = f_lseek(&fil, pos);
|
rc = f_lseek(&rawFil, pos);
|
||||||
UINT ret;
|
UINT ret;
|
||||||
f_write(&fil, &v, 1, &ret);
|
f_write(&rawFil, &v, 1, &ret);
|
||||||
f_close(&fil);
|
|
||||||
return (ret == 1);
|
return (ret == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,9 @@ class TeensyFileManager : public FileManager {
|
||||||
|
|
||||||
virtual uint8_t readByteAt(int8_t fd, uint32_t pos);
|
virtual uint8_t readByteAt(int8_t fd, uint32_t pos);
|
||||||
virtual bool writeByteAt(int8_t fd, uint8_t v, uint32_t pos);
|
virtual bool writeByteAt(int8_t fd, uint8_t v, uint32_t pos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _prepCache(int8_t fd);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int8_t numCached;
|
int8_t numCached;
|
||||||
|
|
Loading…
Reference in New Issue