Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Robbbert committed Jun 22, 2024
2 parents 1b3ae39 + 0e459c1 commit 55d663f
Show file tree
Hide file tree
Showing 12 changed files with 1,046 additions and 215 deletions.
128 changes: 20 additions & 108 deletions src/devices/cpu/z80/z80.cpp
Original file line number Diff line number Diff line change
@@ -1,113 +1,25 @@
// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller
/*****************************************************************************
*
* z80.cpp
* Portable Z80 emulator V3.9
*
* TODO:
* - Interrupt mode 0 should be able to execute arbitrary opcodes
* - If LD A,I or LD A,R is interrupted, P/V flag gets reset, even if IFF2
* was set before this instruction (implemented, but not enabled: we need
* document Z80 types first, see below)
* - Ideally, the tiny differences between Z80 types should be supported,
* currently known differences:
* - LD A,I/R P/V flag reset glitch is fixed on CMOS Z80
* - OUT (C),0 outputs 0 on NMOS Z80, $FF on CMOS Z80
* - SCF/CCF X/Y flags is ((flags | A) & 0x28) on SGS/SHARP/ZiLOG NMOS Z80,
* (flags & A & 0x28).
* However, recent findings say that SCF/CCF X/Y results depend on whether
* or not the previous instruction touched the flag register.
* This Z80 emulator assumes a ZiLOG NMOS model.
*
* Changes in 0.243:
* Foundation for M cycles emulation. Currently we preserve cc_* tables with total timings.
* execute_run() behavior (simplified) ...
* Changes in 3.9:
* - Fixed cycle counts for LD IYL/IXL/IYH/IXH,n [Marshmellow]
* - Fixed X/Y flags in CCF/SCF/BIT, ZEXALL is happy now [hap]
* - Simplified DAA, renamed MEMPTR (3.8) to WZ, added TODO [hap]
* - Fixed IM2 interrupt cycles [eke]
* Changes in 3.8 [Miodrag Milanovic]:
* - Added MEMPTR register (according to informations provided
* by Vladimir Kladov
* - BIT n,(HL) now return valid values due to use of MEMPTR
* - Fixed BIT 6,(XY+o) undocumented instructions
* Changes in 3.7 [Aaron Giles]:
* - Changed NMI handling. NMIs are now latched in set_irq_state
* but are not taken there. Instead they are taken at the start of the
* execute loop.
* - Changed IRQ handling. IRQ state is set in set_irq_state but not taken
* except during the inner execute loop.
* - Removed x86 assembly hacks and obsolete timing loop catchers.
* Changes in 3.6:
* - Got rid of the code that would inexactly emulate a Z80, i.e. removed
* all the #if Z80_EXACT #else branches.
* - Removed leading underscores from local register name shortcuts as
* this violates the C99 standard.
* - Renamed the registers inside the Z80 context to lower case to avoid
* ambiguities (shortcuts would have had the same names as the fields
* of the structure).
* Changes in 3.5:
* - Implemented OTIR, INIR, etc. without look-up table for PF flag.
* [Ramsoft, Sean Young]
* Changes in 3.4:
* - Removed Z80-MSX specific code as it's not needed any more.
* - Implemented DAA without look-up table [Ramsoft, Sean Young]
* Changes in 3.3:
* - Fixed undocumented flags XF & YF in the non-asm versions of CP,
* and all the 16 bit arithmetic instructions. [Sean Young]
* Changes in 3.2:
* - Fixed undocumented flags XF & YF of RRCA, and CF and HF of
* INI/IND/OUTI/OUTD/INIR/INDR/OTIR/OTDR [Sean Young]
* Changes in 3.1:
* - removed the REPEAT_AT_ONCE execution of LDIR/CPIR etc. opcodes
* for readabilities sake and because the implementation was buggy
* (and i was not able to find the difference)
* Changes in 3.0:
* - 'finished' switch to dynamically overrideable cycle count tables
* Changes in 2.9:
* - added methods to access and override the cycle count tables
* - fixed handling and timing of multiple DD/FD prefixed opcodes
* Changes in 2.8:
* - OUTI/OUTD/OTIR/OTDR also pre-decrement the B register now.
* This was wrong because of a bug fix on the wrong side
* (astrocade sound driver).
* Changes in 2.7:
* - removed z80_vm specific code, it's not needed (and never was).
* Changes in 2.6:
* - BUSY_LOOP_HACKS needed to call change_pc() earlier, before
* checking the opcodes at the new address, because otherwise they
* might access the old (wrong or even nullptr) banked memory region.
* Thanks to Sean Young for finding this nasty bug.
* Changes in 2.5:
* - Burning cycles always adjusts the ICount by a multiple of 4.
* - In REPEAT_AT_ONCE cases the r register wasn't incremented twice
* per repetition as it should have been. Those repeated opcodes
* could also underflow the ICount.
* - Simplified TIME_LOOP_HACKS for BC and added two more for DE + HL
* timing loops. i think those hacks weren't endian safe before too.
* Changes in 2.4:
* - z80_reset zaps the entire context, sets IX and IY to 0xffff(!) and
* sets the Z flag. With these changes the Tehkan World Cup driver
* _seems_ to work again.
* Changes in 2.3:
* - External termination of the execution loop calls z80_burn() and
* z80_vm_burn() to burn an amount of cycles (r adjustment)
* - Shortcuts which burn CPU cycles (BUSY_LOOP_HACKS and TIME_LOOP_HACKS)
* now also adjust the r register depending on the skipped opcodes.
* Changes in 2.2:
* - Fixed bugs in CPL, SCF and CCF instructions flag handling.
* - Changed variable ea and arg16() function to u32; this
* produces slightly more efficient code.
* - The DD/FD XY CB opcodes where XY is 40-7F and Y is not 6/E
* are changed to calls to the X6/XE opcodes to reduce object size.
* They're hardly ever used so this should not yield a speed penalty.
* New in 2.0:
* - Optional more exact Z80 emulation (#define Z80_EXACT 1) according
* to a detailed description by Sean Young which can be found at:
* http://www.msxnet.org/tech/z80-documented.pdf
*****************************************************************************/
ZiLOG Z80 emulator
TODO:
- Interrupt mode 0 should be able to execute arbitrary opcodes
- If LD A,I or LD A,R is interrupted, P/V flag gets reset, even if IFF2
was set before this instruction (implemented, but not enabled: we need
document Z80 types first, see below)
- Ideally, the tiny differences between Z80 types should be supported,
currently known differences:
- LD A,I/R P/V flag reset glitch is fixed on CMOS Z80
- OUT (C),0 outputs 0 on NMOS Z80, $FF on CMOS Z80
- SCF/CCF X/Y flags is ((flags | A) & 0x28) on SGS/SHARP/ZiLOG NMOS Z80,
(flags & A & 0x28).
However, recent findings say that SCF/CCF X/Y results depend on whether
or not the previous instruction touched the flag register.
This Z80 emulator assumes a ZiLOG NMOS model.
*****************************************************************************/

#include "emu.h"
#include "z80.h"
Expand Down Expand Up @@ -615,7 +527,7 @@ void z80_device::device_start()
// sbc with carry set
val = oldval - newval - 1;
*psbc = NF | ((newval) ? ((newval & 0x80) ? SF : 0) : ZF);
*psbc |= (newval & (YF | XF)); /* undocumented flag bits 5+3 */
*psbc |= (newval & (YF | XF)); // undocumented flag bits 5+3
if( (newval & 0x0f) >= (oldval & 0x0f) ) *psbc |= HF;
if( newval >= oldval ) *psbc |= CF;
if( (val^oldval) & (oldval^newval) & 0x80 ) *psbc |= VF;
Expand Down
104 changes: 70 additions & 34 deletions src/devices/machine/atastorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@

#include "multibyte.h"

//#define VERBOSE (LOG_GENERAL)
//#define LOG_OUTPUT_FUNC osd_printf_debug
#include "logmacro.h"


/***************************************************************************
DEBUGGING
***************************************************************************/

#define VERBOSE 0
#define PRINTF_IDE_COMMANDS 0
#define PRINTF_IDE_PASSWORD 0

#define LOGPRINT(x) do { if (VERBOSE) logerror x; if (PRINTF_IDE_COMMANDS) osd_printf_debug x; } while (0)

#define TIME_PER_SECTOR_WRITE (attotime::from_usec(100))
#define TIME_PER_ROTATION (attotime::from_hz(5400/60))
#define TIME_BETWEEN_SECTORS (attotime::from_nsec(400))
Expand Down Expand Up @@ -534,19 +535,17 @@ void ata_mass_storage_device_base::process_buffer()
{
if (m_user_password_enable && memcmp(&m_buffer[0], m_user_password, 2 + 32) == 0)
{
LOGPRINT(("IDE Unlocked user password\n"));
LOG("IDE Unlocked user password\n");
m_user_password_enable = 0;
}
if (m_master_password_enable && memcmp(&m_buffer[0], m_master_password, 2 + 32) == 0)
{
LOGPRINT(("IDE Unlocked master password\n"));
LOG("IDE Unlocked master password\n");
m_master_password_enable = 0;
}
if (PRINTF_IDE_PASSWORD)
{
int i;

for (i = 0; i < 34; i += 2)
for (int i = 0; i < 34; i += 2)
{
if (i % 8 == 2)
osd_printf_debug("\n");
Expand All @@ -562,7 +561,7 @@ void ata_mass_storage_device_base::process_buffer()
}
else if (m_command == IDE_COMMAND_SECURITY_DISABLE_PASSWORD)
{
LOGPRINT(("IDE Done unimplemented SECURITY_DISABLE_PASSWORD command\n"));
LOG("IDE Done unimplemented SECURITY_DISABLE_PASSWORD command\n");
}
else if (m_command == IDE_COMMAND_WRITE_BUFFER)
{
Expand Down Expand Up @@ -666,8 +665,12 @@ void ata_mass_storage_device_base::process_command()
{
case IDE_COMMAND_READ_SECTORS:
case IDE_COMMAND_READ_SECTORS_NORETRY:
LOGPRINT(("IDE Read multiple: C=%u H=%d S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
LOG("IDE Read multiple: C=%u H=%d S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low,
m_device_head & IDE_DEVICE_HEAD_HS,
m_sector_number,
lba_address(),
m_sector_count);

m_sectors_until_int = 1;

Expand All @@ -676,7 +679,7 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_READ_BUFFER:
LOGPRINT(("IDE Read Buffer\n"));
LOG("IDE Read Buffer\n");

m_sectors_until_int = 1;
m_buffer_offset = 0;
Expand All @@ -686,8 +689,12 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_READ_MULTIPLE:
LOGPRINT(("IDE Read multiple block: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
LOG("IDE Read multiple block: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low,
m_device_head & IDE_DEVICE_HEAD_HS,
m_sector_number,
lba_address(),
m_sector_count);

m_sectors_until_int = 1;

Expand All @@ -697,8 +704,12 @@ void ata_mass_storage_device_base::process_command()

case IDE_COMMAND_VERIFY_SECTORS:
case IDE_COMMAND_VERIFY_SECTORS_NORETRY:
LOGPRINT(("IDE Read verify multiple with/without retries: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
LOG("IDE Read verify multiple with/without retries: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low,
m_device_head & IDE_DEVICE_HEAD_HS,
m_sector_number,
lba_address(),
m_sector_count);

/* reset the buffer */
m_sectors_until_int = m_sector_count;
Expand All @@ -708,8 +719,12 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_READ_DMA:
LOGPRINT(("IDE Read multiple DMA: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
LOG("IDE Read multiple DMA: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low,
m_device_head & IDE_DEVICE_HEAD_HS,
m_sector_number,
lba_address(),
m_sector_count);

/* reset the buffer */
m_sectors_until_int = m_sector_count;
Expand All @@ -720,8 +735,12 @@ void ata_mass_storage_device_base::process_command()

case IDE_COMMAND_WRITE_SECTORS:
case IDE_COMMAND_WRITE_SECTORS_NORETRY:
LOGPRINT(("IDE Write multiple: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
LOG("IDE Write multiple: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low,
m_device_head & IDE_DEVICE_HEAD_HS,
m_sector_number,
lba_address(),
m_sector_count);

/* reset the buffer */
m_sectors_until_int = 1;
Expand All @@ -731,7 +750,7 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_WRITE_BUFFER:
LOGPRINT(("IDE Write Buffer\n"));
LOG("IDE Write Buffer\n");

/* reset the buffer */
m_sectors_until_int = 1;
Expand All @@ -742,8 +761,12 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_WRITE_MULTIPLE:
LOGPRINT(("IDE Write multiple block: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
LOG("IDE Write multiple block: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low,
m_device_head & IDE_DEVICE_HEAD_HS,
m_sector_number,
lba_address(),
m_sector_count);

/* reset the buffer */
m_sectors_until_int = m_block_count;
Expand All @@ -753,8 +776,12 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_WRITE_DMA:
LOGPRINT(("IDE Write multiple DMA: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low, m_device_head & IDE_DEVICE_HEAD_HS, m_sector_number, lba_address(), m_sector_count));
LOG("IDE Write multiple DMA: C=%u H=%u S=%u LBA=%u count=%u\n",
(m_cylinder_high << 8) | m_cylinder_low,
m_device_head & IDE_DEVICE_HEAD_HS,
m_sector_number,
lba_address(),
m_sector_count);

/* reset the buffer */
m_sectors_until_int = m_sector_count;
Expand All @@ -767,7 +794,7 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_SECURITY_UNLOCK:
LOGPRINT(("IDE Security Unlock\n"));
LOG("IDE Security Unlock\n");

/* mark the buffer ready */
m_status |= IDE_STATUS_DRQ;
Expand All @@ -776,7 +803,7 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_SECURITY_DISABLE_PASSWORD:
LOGPRINT(("IDE Unimplemented SECURITY DISABLE PASSWORD command\n"));
LOG("IDE Unimplemented SECURITY DISABLE PASSWORD command\n");

/* mark the buffer ready */
m_status |= IDE_STATUS_DRQ;
Expand All @@ -785,7 +812,7 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_IDENTIFY_DEVICE:
LOGPRINT(("IDE Identify device\n"));
LOG("IDE Identify device\n");

start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
break;
Expand All @@ -800,20 +827,26 @@ void ata_mass_storage_device_base::process_command()
break;

case IDE_COMMAND_SET_CONFIG:
LOGPRINT(("IDE Set configuration (%u heads, %u sectors)\n", (m_device_head & IDE_DEVICE_HEAD_HS) + 1, m_sector_count));
LOG("IDE Set configuration (%u heads, %u sectors)\n",
(m_device_head & IDE_DEVICE_HEAD_HS) + 1,
m_sector_count);

start_busy(MINIMUM_COMMAND_TIME, PARAM_COMMAND);
break;

case IDE_COMMAND_SET_MAX:
LOGPRINT(("IDE Set max (%02X %02X %02X %02X %02X)\n", m_feature, m_sector_count & 0xff, m_sector_number, m_cylinder_low, m_cylinder_high));
LOG("IDE Set max (%02X %02X %02X %02X %02X)\n",
m_feature,
m_sector_count & 0xff,
m_sector_number,
m_cylinder_low, m_cylinder_high);

/* signal an interrupt */
set_irq(ASSERT_LINE);
break;

case IDE_COMMAND_SET_BLOCK_COUNT:
LOGPRINT(("IDE Set block count (%u)\n", m_sector_count));
LOG("IDE Set block count (%u)\n", m_sector_count);

m_block_count = m_sector_count;

Expand Down Expand Up @@ -872,8 +905,11 @@ void ide_hdd_device_base::device_reset()
m_num_cylinders = hdinfo.cylinders;
m_num_sectors = hdinfo.sectors;
m_num_heads = hdinfo.heads;
if (PRINTF_IDE_COMMANDS) osd_printf_debug("CHS: %u %u %u\n", m_num_cylinders, m_num_heads, m_num_sectors);
osd_printf_debug("CHS: %u %u %u\n", m_num_cylinders, m_num_heads, m_num_sectors);
osd_printf_verbose("%s: Mounted disk image CHS: %u %u %u\n",
tag(),
m_num_cylinders,
m_num_heads,
m_num_sectors);
}

// build the features page
Expand Down
Loading

0 comments on commit 55d663f

Please sign in to comment.