This commit is contained in:
Philip Smart
2022-06-25 17:14:05 +01:00
parent 91524ab724
commit cfd6e7d0a5
9 changed files with 363 additions and 301 deletions

View File

@@ -17,6 +17,8 @@
// v1.1 Nov 2021 - Further work on Video Controller and infrastructure.
// v1.2 Nov 2021 - Adding MZ2000 logic.
// v1.3 Dec 2021 - Adding MZ800 logic.
// v1.4 Jan 2022 - Adding floppy disk support.
// v1.5 Mar 2022 - Consolidation and bug rectification.
//
// Notes: See Makefile to enable/disable conditional components
//
@@ -80,8 +82,8 @@ extern "C" {
#define debugfx(a, ...) if(emuControl.debug) { printf("\033[1;32m%s: " a "\033[0m\n", __func__, ##__VA_ARGS__); }
// Version data.
#define EMUMZ_VERSION 1.45
#define EMUMZ_VERSION_DATE "26/01/2022"
#define EMUMZ_VERSION 1.50
#define EMUMZ_VERSION_DATE "16/03/2022"
//////////////////////////////////////////////////////////////
// Sharp MZ Series Emulation Service Methods //
@@ -1262,7 +1264,6 @@ void EMZNextDisplayType(enum ACTIONMODE mode)
// Move to the next valid entry, looping round as necessary.
do {
emuConfig.params[emuConfig.machineModel].displayType = (emuConfig.params[emuConfig.machineModel].displayType+1 >= NUMELEM(SHARPMZ_DISPLAY_TYPE[emuConfig.machineModel]) ? 0 : emuConfig.params[emuConfig.machineModel].displayType+1);
printf("%d\n", emuConfig.params[emuConfig.machineModel].displayType);
} while(SHARPMZ_DISPLAY_TYPE[emuConfig.machineModel][emuConfig.params[emuConfig.machineModel].displayType] == NULL);
}
return;
@@ -2061,7 +2062,6 @@ void EMZNextMonitorROM40(enum ACTIONMODE mode)
if(mode == ACTION_DEFAULT || mode == ACTION_TOGGLECHOICE)
{
emuConfig.params[emuConfig.machineModel].romMonitor40.romEnabled = (emuConfig.params[emuConfig.machineModel].romMonitor40.romEnabled == 1 ? 0 : 1);
printf("romEnabled=%d\n", emuConfig.params[emuConfig.machineModel].romMonitor40.romEnabled );
}
return;
}
@@ -5640,317 +5640,331 @@ void EMZservice(uint8_t interrupt)
// Has an interrupt been generated by the emulator support hardware?
if(interrupt)
{
// Read the reason code register.
// Take out a Lock on the Z80 bus - this is needed as a number of small operations are performed on the Z80/FPGA during an interrupt cycle and it adds overhead to wait for a Z80 request approval on each occasion.
//
result=readZ80Array(MZ_EMU_REG_INTR_ADDR, emuISRReason, MZ_EMU_INTR_MAX_REGISTERS, FPGA);
printf("IntrReg:"); for(uint16_t idx=0; idx < MZ_EMU_INTR_MAX_REGISTERS; idx++) { printf("%02x ", emuISRReason[idx]); } printf("\n");
if(!result)
if(lockZ80() == 0)
{
// Keyboard interrupt?
if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_KEYB)
// Read the reason code register.
//
result=readZ80Array(MZ_EMU_REG_INTR_ADDR, emuISRReason, MZ_EMU_INTR_MAX_REGISTERS, FPGA);
printf("IntrReg:"); for(uint16_t idx=0; idx < MZ_EMU_INTR_MAX_REGISTERS; idx++) { printf("%02x ", emuISRReason[idx]); } printf("\n");
if(!result)
{
// Read the key pressed.
result=readZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuInData[MZ_EMU_KEYB_CTRL_REG], MZ_EMU_KEYB_MAX_REGISTERS, FPGA);
printf("KeyReg:"); for(uint16_t idx=MZ_EMU_KEYB_CTRL_REG; idx < MZ_EMU_KEYB_CTRL_REG+MZ_EMU_KEYB_MAX_REGISTERS; idx++) { printf("%02x ", emuInData[idx]); } printf("\n");
if(!result)
// Keyboard interrupt?
if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_KEYB)
{
printf("Received key:%02x, %02x, %d, %d (%d,%d)\n", emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG], emuInData[MZ_EMU_KEYB_KEY_POS_REG], emuInData[MZ_EMU_KEYB_KEY_POS_LAST_REG], emuInData[MZ_EMU_KEYB_FIFO_WR_ADDR], emuInData[MZ_EMU_KEYB_FIFO_RD_ADDR]);
// Not interested in up key events or control events except for CTRL+BREAK, discard.
if(emuInData[MZ_EMU_KEYB_KEYC_REG] & KEY_DOWN_BIT)
// Read the key pressed.
result=readZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuInData[MZ_EMU_KEYB_CTRL_REG], MZ_EMU_KEYB_MAX_REGISTERS, FPGA);
printf("KeyReg:"); for(uint16_t idx=MZ_EMU_KEYB_CTRL_REG; idx < MZ_EMU_KEYB_CTRL_REG+MZ_EMU_KEYB_MAX_REGISTERS; idx++) { printf("%02x ", emuInData[idx]); } printf("\n");
if(!result)
{
// First time the menu key has been pressed, pop up the menu and redirect all key input to the I/O processor.
if(emuControl.activeMenu.menu[0] == MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE)
printf("Received key:%02x, %02x, %d, %d (%d,%d)\n", emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG], emuInData[MZ_EMU_KEYB_KEY_POS_REG], emuInData[MZ_EMU_KEYB_KEY_POS_LAST_REG], emuInData[MZ_EMU_KEYB_FIFO_WR_ADDR], emuInData[MZ_EMU_KEYB_FIFO_RD_ADDR]);
// Not interested in up key events or control events except for CTRL+BREAK, discard.
if(emuInData[MZ_EMU_KEYB_KEYC_REG] & KEY_DOWN_BIT)
{
// Recheck OSD parameters - the running machine may change resolution which in turn changes the OSD settings.
OSDUpdateScreenSize();
// Setup Menu Font according to available X pixels. Original screen formats only have 320 pixel width.
if((uint16_t)OSDGet(ACTIVE_MAX_X) < 512)
// First time the menu key has been pressed, pop up the menu and redirect all key input to the I/O processor.
if(emuControl.activeMenu.menu[0] == MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE)
{
EMZSetMenuFont(FONT_5X7);
// Recheck OSD parameters - the running machine may change resolution which in turn changes the OSD settings.
OSDUpdateScreenSize();
// Setup Menu Font according to available X pixels. Original screen formats only have 320 pixel width.
if((uint16_t)OSDGet(ACTIVE_MAX_X) < 512)
{
EMZSetMenuFont(FONT_5X7);
} else
{
EMZSetMenuFont(FONT_7X8);
}
// Disable keyboard scan being sent to emulation, enable interrupts on each key press.
emuOutData[MZ_EMU_KEYB_CTRL_REG] = MZ_EMU_KEYB_DISABLE_EMU | MZ_EMU_KEYB_ENABLE_INTR;
writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA);
emuControl.activeMenu.menuIdx = 0;
emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_MAIN;
// Draw the initial main menu.
EMZMainMenu();
OSDRefreshScreen();
// Enable the OSD.
emuOutData[0] = 0x40 | emuConfig.params[emuConfig.machineModel].displayOutput;
emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] | 0x40;
writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY2, emuOutData, 1, FPGA);
// Menu active and user has requested to return to emulation?
}
else if(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] != MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE)
{
// Enable keyboard scan being sent to emulation, disable interrupts on each key press.
emuOutData[MZ_EMU_KEYB_CTRL_REG] = 0;
writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA);
emuControl.activeMenu.menuIdx = 0;
emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_DISABLED;
// Release any allocated menu or file list memory as next invocation restarts at the main menu.
EMZReleaseDirMemory();
EMZReleaseMenuMemory();
// Disable the OSD cursor.
OSDClearCursorFlash();
// Disable the OSD, this is done by updating the local register copy as the final act is to upload the latest configuration, OSD mode included.
emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] & 0xbf;
//emuOutData[0] = 0x0;
//writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY3, emuOutData, 1, FPGA);
// Switch to the requested machine if changed, update the configuration in the FPGA.
//
if(emuConfig.machineChanged)
{
EMZRun();
} else
{
EMZSwitchToMachine(emuConfig.machineModel, 0);
}
// Direct key intercept, process according to state.
} else
{
EMZSetMenuFont(FONT_7X8);
}
// Disable keyboard scan being sent to emulation, enable interrupts on each key press.
emuOutData[MZ_EMU_KEYB_CTRL_REG] = MZ_EMU_KEYB_DISABLE_EMU | MZ_EMU_KEYB_ENABLE_INTR;
writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA);
emuControl.activeMenu.menuIdx = 0;
emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_MAIN;
// Draw the initial main menu.
EMZMainMenu();
OSDRefreshScreen();
// Enable the OSD.
emuOutData[0] = 0x40 | emuConfig.params[emuConfig.machineModel].displayOutput;
emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] | 0x40;
writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY2, emuOutData, 1, FPGA);
// Menu active and user has requested to return to emulation?
}
else if(emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] != MENU_DISABLED && emuInData[MZ_EMU_KEYB_KEYD_REG] == 0xFE)
{
// Enable keyboard scan being sent to emulation, disable interrupts on each key press.
emuOutData[MZ_EMU_KEYB_CTRL_REG] = 0;
writeZ80Array(MZ_EMU_REG_KEYB_ADDR+MZ_EMU_KEYB_CTRL_REG, &emuOutData[MZ_EMU_KEYB_CTRL_REG], 1, FPGA);
emuControl.activeMenu.menuIdx = 0;
emuControl.activeMenu.menu[emuControl.activeMenu.menuIdx] = MENU_DISABLED;
// Release any allocated menu or file list memory as next invocation restarts at the main menu.
EMZReleaseDirMemory();
EMZReleaseMenuMemory();
// Disable the OSD cursor.
OSDClearCursorFlash();
// Disable the OSD, this is done by updating the local register copy as the final act is to upload the latest configuration, OSD mode included.
emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] = emuConfig.emuRegisters[MZ_EMU_REG_DISPLAY2] & 0xbf;
//emuOutData[0] = 0x0;
//writeZ80Array(MZ_EMU_ADDR_REG_DISPLAY3, emuOutData, 1, FPGA);
// Switch to the requested machine if changed, update the configuration in the FPGA.
//
if(emuConfig.machineChanged)
{
EMZRun();
} else
{
EMZSwitchToMachine(emuConfig.machineModel, 0);
}
// Direct key intercept, process according to state.
} else
{
// Event driven key processing
switch(emuControl.activeDialog)
{
case DIALOG_FILELIST:
EMZProcessFileListKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
break;
case DIALOG_KEYENTRY:
EMZKeyInjectionEdit(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
break;
case DIALOG_MENU:
default:
EMZProcessMenuKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
//EMZProcessMenuKeyDebug(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
break;
// Event driven key processing
switch(emuControl.activeDialog)
{
case DIALOG_FILELIST:
EMZProcessFileListKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
break;
case DIALOG_KEYENTRY:
EMZKeyInjectionEdit(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
break;
case DIALOG_MENU:
default:
EMZProcessMenuKey(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
//EMZProcessMenuKeyDebug(emuInData[MZ_EMU_KEYB_KEYD_REG], emuInData[MZ_EMU_KEYB_KEYC_REG]);
break;
}
}
}
} else
{
printf("Key retrieval error.\n");
}
} else
{
printf("Key retrieval error.\n");
}
}
// CMT generated an interrupt?
if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_CMT)
// CMT generated an interrupt?
if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_CMT)
{
// Read the cmt status directly. This data can also be ready from the Master Control register of the emulator.
result=readZ80Array(MZ_EMU_CMT_REG_ADDR, emuInData, MZ_EMU_CMT_MAX_REGISTERS, FPGA);
// Update the local copy.
emuConfig.emuRegisters[MZ_EMU_REG_CMT3] = emuInData[MZ_EMU_CMT_STATUS_INTR_REG];
emuConfig.emuRegisters[MZ_EMU_REG_CMT2] = emuInData[MZ_EMU_CMT_STATUS2_INTR_REG];
// When debugging output register change as text message.
debugf("CMT/CMT2 (%02x,%02x,%s%s%s%s%s%s:%s%s%s%s%s).",
emuInData[MZ_EMU_CMT_STATUS_REG], emuInData[MZ_EMU_CMT_STATUS2_REG],
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_PLAY_READY ? "PLAY_READY," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_PLAYING ? "PLAYING," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_RECORD_READY ? "RECORD_READY,": "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_RECORDING ? "RECORDING," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_ACTIVE ? "ACTIVE," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_SENSE ? "SENSE," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_APSS ? "APSS," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_APSS ? emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_DIRECTION ? "FFWD," : "REW," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_EJECT ? "EJECT," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_PLAY ? "PLAY," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_STOP ? "STOP," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_AUTOREW ? "AUTOREW," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_AUTOPLAY ? "AUTOPLAY" : "");
debugf("CMT/CMT2i(%02x,%02x,%s%s%s%s%s%s:%s%s%s%s%s).",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG], emuInData[MZ_EMU_CMT_STATUS2_INTR_REG],
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_PLAY_READY ? "PLAY_READY," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_PLAYING ? "PLAYING," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_RECORD_READY ? "RECORD_READY,": "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_RECORDING ? "RECORDING," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_ACTIVE ? "ACTIVE," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_SENSE ? "SENSE," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_APSS ? "APSS," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_APSS ? emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_DIRECTION ? "FFWD," : "REW," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_EJECT ? "EJECT," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_PLAY ? "PLAY," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_STOP ? "STOP," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_AUTOREW ? "AUTOREW," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_AUTOPLAY ? "AUTOPLAY" : "");
// Process the tape queue according to signals received from the hardware.
EMZProcessTapeQueue(1);
}
// Floppy Disk Drive unit interrupt?
if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_FDD)
{
// Read the control data to allow a decision as to what is required.
result=readZ80Array(MZ_EMU_FDD_CTRL_ADDR, emuInData, MZ_EMU_FDD_MAX_REGISTERS, FPGA);
// Debug information to evaluate interrupt.
result=readZ80Array(MZ_EMU_FDC_CTRL_ADDR, &emuInData[MZ_EMU_FDD_MAX_REGISTERS], 32, FPGA); //MZ_EMU_FDC_MAX_REGISTERS, FPGA);
debugf("FDD: (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)",
emuInData[MZ_EMU_FDD_CTRL_REG],
emuInData[MZ_EMU_FDD_SECTOR_REG],
emuInData[MZ_EMU_FDD_TRACK_REG],
emuInData[MZ_EMU_FDD_CST_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_TRACK_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_SECTOR_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_DATA_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_LCMD_REG]);
debugf("FDD IOP: Drive No:%d, Head:%s, Request:%s, Command: %s, Sector:%d, Track:%d",
((emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_DISK_SELECT_NO) >> 5) & 0x03,
emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_SIDE ? "1" : "0",
emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_SERVICE_REQ ? "YES " : "NO",
(emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_REQ_MODE) == 0 ? "NOP" : (emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_REQ_MODE) == 1 ? "READ" : (emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_REQ_MODE) == 2 ? "WRITE" : "INFO",
emuInData[MZ_EMU_FDD_SECTOR_REG],
emuInData[MZ_EMU_FDD_TRACK_REG]);
debugf(" FDD Signals:(%s%s%s%s) Raw Drive Select:(%d)",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_BUSY ? "BUSY," : "",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_DRQ ? "DRQ," : "",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_DDEN ? "" : "DDEN,",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_MOTORON ? "" : "MOTOR",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_SELECT_NO);
cmdSvc = 0;
switch(emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_LCMD_REG] & 0xF0)
{
case FDC_CMD_RESTORE:
cmdStr = "RESTORE";
cmdType = 1;
break;
case FDC_CMD_SEEK:
cmdStr = "SEEK";
cmdType = 1;
break;
case FDC_CMD_STEP:
cmdStr = "STEP";
cmdType = 1;
break;
case FDC_CMD_STEP_TU:
cmdStr = "STEP TU";
cmdType = 1;
break;
case FDC_CMD_STEP_IN:
cmdStr = "STEPIN";
cmdType = 1;
break;
case FDC_CMD_STEPIN_TU:
cmdStr = "STEPIN TU";
cmdType = 1;
break;
case FDC_CMD_STEPOUT:
cmdStr = "STEPOUT";
cmdType = 1;
break;
case FDC_CMD_STEPOUT_TU:
cmdStr = "STEPOUT TU";
cmdType = 1;
break;
case FDC_CMD_READSEC:
cmdStr = "READSEC";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_READSEC_MULT:
cmdStr = "READSEC MULT";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_WRITESEC:
cmdStr = "WRITESEC";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_WRITESEC_MULT:
cmdStr = "WRITESEC MULT";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_READADDR:
cmdStr = "READADDR";
cmdSvc = 1;
cmdType = 3;
break;
case FDC_CMD_READTRACK:
cmdStr = "READTRACK";
cmdSvc = 1;
cmdType = 3;
break;
case FDC_CMD_WRITETRACK:
cmdStr = "WRITETRACK";
cmdSvc = 1;
cmdType = 3;
break;
case FDC_CMD_FORCEINT:
cmdStr = "FORCEINT";
cmdType = 4;
break;
}
debugf(" WD1793 Signals:(%s%s%s%s%s%s%s%s%s[%02x,%d])",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_NOTRDY ? "NOTRDY," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_PROTECTED ? "PROTECTED," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_HEADLOADED ? cmdType != 1 ? "RTYPE/WFAULT," : "HEADLOADED," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_SEEKERROR ? cmdType != 1 ? "RNF," : "SEEKERROR," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_CRCERROR ? "CRCERROR," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_TRACK0 ? cmdType != 1 ? "LOSTDATA," : "TRACK0," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_INDEX ? cmdType != 1 ? "DRQ," : "INDEX," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_BUSY ? "BUSY," : "",
cmdStr, emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_LCMD_REG], cmdType);
if(cmdType == 3)
debugf("READADDR:%02x,%02x,%02x,%02x,%02x,%02x", emuInData[MZ_EMU_FDD_MAX_REGISTERS+16], emuInData[MZ_EMU_FDD_MAX_REGISTERS+17],emuInData[MZ_EMU_FDD_MAX_REGISTERS+18],emuInData[MZ_EMU_FDD_MAX_REGISTERS+19],emuInData[MZ_EMU_FDD_MAX_REGISTERS+20],emuInData[MZ_EMU_FDD_MAX_REGISTERS+21]);
for(uint8_t tst=0; tst < 32; tst ++)
{
printf("%02x,", emuInData[MZ_EMU_FDD_MAX_REGISTERS+tst]);
}
// Clear the READY flag. This also clears the interrupt, basically an acknowledgement.
emuControl.fdd.ctrlReg &= ((~FDD_CTRL_READY) & 0x1f);
printf("CTRLREG ENTER:%02x\n", emuControl.fdd.ctrlReg );
writeZ80Array(MZ_EMU_FDD_CTRL_ADDR+MZ_EMU_FDD_CTRL_REG, &emuControl.fdd.ctrlReg, 1, FPGA);
// Process the request if it requires servicing.
enum FLOPPYERRORCODES floppyError = FLPYERR_NOERROR;
uint16_t thisSectorSize = 0;
uint16_t thisRotationalSpeed = 0;
if(cmdSvc) floppyError = (uint8_t)EMZProcessFDDRequest(emuInData[MZ_EMU_FDD_CTRL_REG], emuInData[MZ_EMU_FDD_TRACK_REG], emuInData[MZ_EMU_FDD_SECTOR_REG], emuInData[MZ_EMU_FDD_CST_REG], &thisSectorSize, &thisRotationalSpeed);
printf("Error Code:%d, Sector Size:%d, Rotational Speed:%d\n", floppyError, thisSectorSize, thisRotationalSpeed);
// Processing complete, set the READY flag along with current sector size, rotational speed and error code. 7:5 = error code, 4 = rotational speed, 3:1 = sector size code, 0 = Ready flag.
if(floppyError != FLPYERR_NOERROR)
{
emuControl.fdd.ctrlReg = (floppyError << 5 | FDD_CTRL_READY);
} else
{
emuControl.fdd.ctrlReg = thisRotationalSpeed == 360 ? 0x10 : 0x00 | ((uint8_t)((thisSectorSize&0xff00) >> 7) & 0x0E) | FDD_CTRL_READY;
}
printf("CTRLREG EXIT:%02x\n", emuControl.fdd.ctrlReg );
writeZ80Array(MZ_EMU_FDD_CTRL_ADDR+MZ_EMU_FDD_CTRL_REG, &emuControl.fdd.ctrlReg, 1, FPGA);
}
} else
{
// Read the cmt status directly. This data can also be ready from the Master Control register of the emulator.
result=readZ80Array(MZ_EMU_CMT_REG_ADDR, emuInData, MZ_EMU_CMT_MAX_REGISTERS, FPGA);
// Update the local copy.
emuConfig.emuRegisters[MZ_EMU_REG_CMT3] = emuInData[MZ_EMU_CMT_STATUS_INTR_REG];
emuConfig.emuRegisters[MZ_EMU_REG_CMT2] = emuInData[MZ_EMU_CMT_STATUS2_INTR_REG];
// When debugging output register change as text message.
debugf("CMT/CMT2 (%02x,%02x,%s%s%s%s%s%s:%s%s%s%s%s).",
emuInData[MZ_EMU_CMT_STATUS_REG], emuInData[MZ_EMU_CMT_STATUS2_REG],
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_PLAY_READY ? "PLAY_READY," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_PLAYING ? "PLAYING," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_RECORD_READY ? "RECORD_READY,": "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_RECORDING ? "RECORDING," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_ACTIVE ? "ACTIVE," : "",
emuInData[MZ_EMU_CMT_STATUS_REG] & MZ_EMU_CMT_SENSE ? "SENSE," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_APSS ? "APSS," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_APSS ? emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_DIRECTION ? "FFWD," : "REW," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_EJECT ? "EJECT," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_PLAY ? "PLAY," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_STOP ? "STOP," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_AUTOREW ? "AUTOREW," : "",
emuInData[MZ_EMU_CMT_STATUS2_REG] & MZ_EMU_CMT2_AUTOPLAY ? "AUTOPLAY" : "");
debugf("CMT/CMT2i(%02x,%02x,%s%s%s%s%s%s:%s%s%s%s%s).",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG], emuInData[MZ_EMU_CMT_STATUS2_INTR_REG],
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_PLAY_READY ? "PLAY_READY," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_PLAYING ? "PLAYING," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_RECORD_READY ? "RECORD_READY,": "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_RECORDING ? "RECORDING," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_ACTIVE ? "ACTIVE," : "",
emuInData[MZ_EMU_CMT_STATUS_INTR_REG] & MZ_EMU_CMT_SENSE ? "SENSE," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_APSS ? "APSS," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_APSS ? emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_DIRECTION ? "FFWD," : "REW," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_EJECT ? "EJECT," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_PLAY ? "PLAY," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_STOP ? "STOP," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_AUTOREW ? "AUTOREW," : "",
emuInData[MZ_EMU_CMT_STATUS2_INTR_REG] & MZ_EMU_CMT2_AUTOPLAY ? "AUTOPLAY" : "");
// Process the tape queue according to signals received from the hardware.
EMZProcessTapeQueue(1);
}
// Floppy Disk Drive unit interrupt?
if(emuISRReason[MZ_EMU_INTR_REG_ISR] & MZ_EMU_INTR_SRC_FDD)
{
// Read the control data to allow a decision as to what is required.
result=readZ80Array(MZ_EMU_FDD_CTRL_ADDR, emuInData, MZ_EMU_FDD_MAX_REGISTERS, FPGA);
// Debug information to evaluate interrupt.
result=readZ80Array(MZ_EMU_FDC_CTRL_ADDR, &emuInData[MZ_EMU_FDD_MAX_REGISTERS], 32, FPGA); //MZ_EMU_FDC_MAX_REGISTERS, FPGA);
debugf("FDD: (%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x)",
emuInData[MZ_EMU_FDD_CTRL_REG],
emuInData[MZ_EMU_FDD_SECTOR_REG],
emuInData[MZ_EMU_FDD_TRACK_REG],
emuInData[MZ_EMU_FDD_CST_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_TRACK_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_SECTOR_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_DATA_REG],
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_LCMD_REG]);
debugf("FDD IOP: Drive No:%d, Head:%s, Request:%s, Command: %s, Sector:%d, Track:%d",
((emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_DISK_SELECT_NO) >> 5) & 0x03,
emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_SIDE ? "1" : "0",
emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_SERVICE_REQ ? "YES " : "NO",
(emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_REQ_MODE) == 0 ? "NOP" : (emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_REQ_MODE) == 1 ? "READ" : (emuInData[MZ_EMU_FDD_CTRL_REG] & FDD_IOP_REQ_MODE) == 2 ? "WRITE" : "INFO",
emuInData[MZ_EMU_FDD_SECTOR_REG],
emuInData[MZ_EMU_FDD_TRACK_REG]);
debugf(" FDD Signals:(%s%s%s%s) Raw Drive Select:(%d)",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_BUSY ? "BUSY," : "",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_DRQ ? "DRQ," : "",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_DDEN ? "" : "DDEN,",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_MOTORON ? "" : "MOTOR",
emuInData[MZ_EMU_FDD_CST_REG] & FDD_DISK_SELECT_NO);
cmdSvc = 0;
switch(emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_LCMD_REG] & 0xF0)
{
case FDC_CMD_RESTORE:
cmdStr = "RESTORE";
cmdType = 1;
break;
case FDC_CMD_SEEK:
cmdStr = "SEEK";
cmdType = 1;
break;
case FDC_CMD_STEP:
cmdStr = "STEP";
cmdType = 1;
break;
case FDC_CMD_STEP_TU:
cmdStr = "STEP TU";
cmdType = 1;
break;
case FDC_CMD_STEP_IN:
cmdStr = "STEPIN";
cmdType = 1;
break;
case FDC_CMD_STEPIN_TU:
cmdStr = "STEPIN TU";
cmdType = 1;
break;
case FDC_CMD_STEPOUT:
cmdStr = "STEPOUT";
cmdType = 1;
break;
case FDC_CMD_STEPOUT_TU:
cmdStr = "STEPOUT TU";
cmdType = 1;
break;
case FDC_CMD_READSEC:
cmdStr = "READSEC";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_READSEC_MULT:
cmdStr = "READSEC MULT";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_WRITESEC:
cmdStr = "WRITESEC";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_WRITESEC_MULT:
cmdStr = "WRITESEC MULT";
cmdSvc = 1;
cmdType = 2;
break;
case FDC_CMD_READADDR:
cmdStr = "READADDR";
cmdSvc = 1;
cmdType = 3;
break;
case FDC_CMD_READTRACK:
cmdStr = "READTRACK";
cmdSvc = 1;
cmdType = 3;
break;
case FDC_CMD_WRITETRACK:
cmdStr = "WRITETRACK";
cmdSvc = 1;
cmdType = 3;
break;
case FDC_CMD_FORCEINT:
cmdStr = "FORCEINT";
cmdType = 4;
break;
}
debugf(" WD1793 Signals:(%s%s%s%s%s%s%s%s%s[%02x,%d])",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_NOTRDY ? "NOTRDY," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_PROTECTED ? "PROTECTED," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_HEADLOADED ? cmdType != 1 ? "RTYPE/WFAULT," : "HEADLOADED," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_SEEKERROR ? cmdType != 1 ? "RNF," : "SEEKERROR," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_CRCERROR ? "CRCERROR," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_TRACK0 ? cmdType != 1 ? "LOSTDATA," : "TRACK0," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_INDEX ? cmdType != 1 ? "DRQ," : "INDEX," : "",
emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_CTRL_REG] & FDC_STI_BUSY ? "BUSY," : "",
cmdStr, emuInData[MZ_EMU_FDD_MAX_REGISTERS+MZ_EMU_FDC_LCMD_REG], cmdType);
if(cmdType == 3)
debugf("READADDR:%02x,%02x,%02x,%02x,%02x,%02x", emuInData[MZ_EMU_FDD_MAX_REGISTERS+16], emuInData[MZ_EMU_FDD_MAX_REGISTERS+17],emuInData[MZ_EMU_FDD_MAX_REGISTERS+18],emuInData[MZ_EMU_FDD_MAX_REGISTERS+19],emuInData[MZ_EMU_FDD_MAX_REGISTERS+20],emuInData[MZ_EMU_FDD_MAX_REGISTERS+21]);
for(uint8_t tst=0; tst < 32; tst ++)
{
printf("%02x,", emuInData[MZ_EMU_FDD_MAX_REGISTERS+tst]);
}
// Clear the READY flag. This also clears the interrupt, basically an acknowledgement.
emuControl.fdd.ctrlReg &= ((~FDD_CTRL_READY) & 0x1f);
printf("CTRLREG ENTER:%02x\n", emuControl.fdd.ctrlReg );
writeZ80Array(MZ_EMU_FDD_CTRL_ADDR+MZ_EMU_FDD_CTRL_REG, &emuControl.fdd.ctrlReg, 1, FPGA);
// Process the request if it requires servicing.
enum FLOPPYERRORCODES floppyError = FLPYERR_NOERROR;
uint16_t thisSectorSize = 0;
uint16_t thisRotationalSpeed = 0;
if(cmdSvc) floppyError = (uint8_t)EMZProcessFDDRequest(emuInData[MZ_EMU_FDD_CTRL_REG], emuInData[MZ_EMU_FDD_TRACK_REG], emuInData[MZ_EMU_FDD_SECTOR_REG], emuInData[MZ_EMU_FDD_CST_REG], &thisSectorSize, &thisRotationalSpeed);
printf("Error Code:%d, Sector Size:%d, Rotational Speed:%d\n", floppyError, thisSectorSize, thisRotationalSpeed);
// Processing complete, set the READY flag along with current sector size, rotational speed and error code. 7:5 = error code, 4 = rotational speed, 3:1 = sector size code, 0 = Ready flag.
if(floppyError != FLPYERR_NOERROR)
{
emuControl.fdd.ctrlReg = (floppyError << 5 | FDD_CTRL_READY);
} else
{
emuControl.fdd.ctrlReg = thisRotationalSpeed == 360 ? 0x10 : 0x00 | ((uint8_t)((thisSectorSize&0xff00) >> 7) & 0x0E) | FDD_CTRL_READY;
}
printf("CTRLREG EXIT:%02x\n", emuControl.fdd.ctrlReg );
writeZ80Array(MZ_EMU_FDD_CTRL_ADDR+MZ_EMU_FDD_CTRL_REG, &emuControl.fdd.ctrlReg, 1, FPGA);
printf("Interrupt reason retrieval error.\n");
}
// Release the lock on the Z80 bus before exitting.
releaseLockZ80();
// Indicate processing time.
debugf("Int time:%ld", *ms - time);
} else
{
printf("Interrupt reason retrieval error.\n");
// Raise an error, couldnt service the interrupt because the Z80 bus couldnt be locked.
//
debugf("Failed to lock the Z80 bus, cannot service interrupt!");
}
// Indicate processing time.
debugf("Int time:%ld", *ms - time);
}
// Scheduling block, called periodically by the zOS scheduling.

View File

@@ -848,7 +848,7 @@ uint8_t reqZ80Bus(uint32_t timeout)
{
// Set BUSRQ low which sets the Z80 BUSRQ low.
pinLow(CTL_BUSRQ);
printf("Wait for low\n");
// Set BUSRQ low and wait for a BUSACK or for the timeout period. If no response in the timeout period then the tranZPUter board/CPLD has locked up.
// do {
// // Wait 1ms or until BUSACK goes low.
@@ -860,18 +860,16 @@ printf("Wait for low\n");
// pinHigh(CTL_BUSRQ);
// }
// }
while(((*ms - startTime) < timeout && pinGet(CTL_BUSACK)));
while(((*ms - startTime) < timeout && pinGet(CTL_BUSACK)));
// If we timed out, deassert BUSRQ and return error.
//
if((*ms - startTime) >= timeout)
{
printf("It is HIGH\n");
pinHigh(CTL_BUSRQ);
result = 1;
} else
{
printf("It is low\n");
// Setup the bus ready for transactions, default to read.
setupSignalsForZ80Access(READ);
@@ -943,6 +941,54 @@ uint8_t reqTranZPUterBus(uint32_t timeout, enum TARGETS target)
return(result);
}
// Method to request the Z80 bus and once obtained, hold it until later release. This is an external method to allow and prevent multiple
// bus request transactions and roll them up into one transaction.
//
uint8_t lockZ80(void)
{
// Locals.
//
uint8_t result = 0;
printf("LOCK Z80\n");
// Requst the Z80 Bus to tri-state the Z80.
if((result=reqZ80Bus(DEFAULT_BUSREQ_TIMEOUT)) == 0)
{
// Lock the bus, prevents it being released on method exit.
z80Control.holdZ80 = 1;
} else
{
printf("Failed to lock Z80 Bus\n");
}
return(result);
}
// Method to release an acquired lock on the Z80 bus.
//
uint8_t releaseLockZ80(void)
{
// Locals.
//
uint8_t result = 0;
printf("RELEASE LOCK Z80\n");
// Check to ensure a lock is in place.
if(z80Control.holdZ80 == 1)
{
// Indicate bus lock no longer required.
z80Control.holdZ80 = 0;
// Release the bus to complete.
//
releaseZ80();
} else
{
result = 1;
printf("Request to release lock and no lock active!\n");
}
return(result);
}
// Method to set all the pins to be able to perform a transaction on the Z80 bus.
//
void setupSignalsForZ80Access(enum BUS_DIRECTION dir)

View File

@@ -947,6 +947,8 @@ void resetZ80(uint8_t);
uint8_t reqZ80Bus(uint32_t);
uint8_t reqMainboardBus(uint32_t);
uint8_t reqTranZPUterBus(uint32_t, enum TARGETS);
uint8_t lockZ80(void);
uint8_t releaseLockZ80(void);
void setupSignalsForZ80Access(enum BUS_DIRECTION);
void releaseZ80(void);
void refreshZ80(void);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.