mirror of
https://github.com/holub/mame
synced 2025-05-23 14:19:01 +03:00
mess sync (nw)
This commit is contained in:
parent
2e80c5ff0e
commit
c8822a8937
2
.gitattributes
vendored
2
.gitattributes
vendored
@ -810,8 +810,6 @@ src/emu/machine/adc1213x.c svneol=native#text/plain
|
||||
src/emu/machine/adc1213x.h svneol=native#text/plain
|
||||
src/emu/machine/am53cf96.c svneol=native#text/plain
|
||||
src/emu/machine/am53cf96.h svneol=native#text/plain
|
||||
src/emu/machine/am8530h.c svneol=native#text/plain
|
||||
src/emu/machine/am8530h.h svneol=native#text/plain
|
||||
src/emu/machine/amigafdc.c svneol=native#text/plain
|
||||
src/emu/machine/amigafdc.h svneol=native#text/plain
|
||||
src/emu/machine/at28c16.c svneol=native#text/plain
|
||||
|
@ -1823,12 +1823,60 @@ static void do_frestore_null(m68ki_cpu_core *m68k)
|
||||
m68k->fpu_just_reset = 1;
|
||||
}
|
||||
|
||||
static void m68040_do_fsave(m68ki_cpu_core *m68k, UINT32 addr, int reg, int inc)
|
||||
{
|
||||
if (m68k->fpu_just_reset)
|
||||
{
|
||||
m68ki_write_32(m68k, addr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we normally generate an IDLE frame
|
||||
if(reg != -1)
|
||||
REG_A(m68k)[reg] += inc ? 6*4 : -6*4;
|
||||
perform_fsave(m68k, addr, inc);
|
||||
}
|
||||
}
|
||||
|
||||
static void m68040_do_frestore(m68ki_cpu_core *m68k, UINT32 addr, int reg)
|
||||
{
|
||||
UINT32 temp = m68ki_read_32(m68k, addr);
|
||||
|
||||
// check for NULL frame
|
||||
if (temp & 0xff000000)
|
||||
{
|
||||
// we don't handle non-NULL frames
|
||||
m68k->fpu_just_reset = 0;
|
||||
|
||||
if (reg != -1)
|
||||
{
|
||||
// how about an IDLE frame?
|
||||
if ((temp & 0x00ff0000) == 0x00180000)
|
||||
{
|
||||
REG_A(m68k)[reg] += 6*4;
|
||||
} // check UNIMP
|
||||
else if ((temp & 0x00ff0000) == 0x00380000)
|
||||
{
|
||||
REG_A(m68k)[reg] += 14*4;
|
||||
} // check BUSY
|
||||
else if ((temp & 0x00ff0000) == 0x00b40000)
|
||||
{
|
||||
REG_A(m68k)[reg] += 45*4;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do_frestore_null(m68k);
|
||||
}
|
||||
}
|
||||
|
||||
void m68040_fpu_op1(m68ki_cpu_core *m68k)
|
||||
{
|
||||
int ea = m68k->ir & 0x3f;
|
||||
int mode = (ea >> 3) & 0x7;
|
||||
int reg = (ea & 0x7);
|
||||
UINT32 addr, temp;
|
||||
UINT32 addr;
|
||||
|
||||
switch ((m68k->ir >> 6) & 0x3)
|
||||
{
|
||||
@ -1838,50 +1886,47 @@ void m68040_fpu_op1(m68ki_cpu_core *m68k)
|
||||
{
|
||||
case 2: // (An)
|
||||
addr = REG_A(m68k)[reg];
|
||||
|
||||
if (m68k->fpu_just_reset)
|
||||
{
|
||||
m68ki_write_32(m68k, addr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we normally generate an IDLE frame
|
||||
perform_fsave(m68k, addr, 1);
|
||||
}
|
||||
m68040_do_fsave(m68k, addr, -1, 1);
|
||||
break;
|
||||
|
||||
case 3: // (An)+
|
||||
addr = EA_AY_PI_32(m68k);
|
||||
addr = EA_AY_PI_32(m68k);
|
||||
m68040_do_fsave(m68k, addr, reg, 1);
|
||||
break;
|
||||
|
||||
if (m68k->fpu_just_reset)
|
||||
{
|
||||
m68ki_write_32(m68k, addr, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we normally generate an IDLE frame
|
||||
REG_A(m68k)[reg] += 6*4;
|
||||
perform_fsave(m68k, addr, 1);
|
||||
}
|
||||
break;
|
||||
case 4: // -(An)
|
||||
addr = EA_AY_PD_32(m68k);
|
||||
m68040_do_fsave(m68k, addr, reg, 0);
|
||||
break;
|
||||
|
||||
case 4: // -(An)
|
||||
addr = EA_AY_PD_32(m68k);
|
||||
case 5: // (D16, An)
|
||||
addr = EA_AY_DI_16(m68k);
|
||||
m68040_do_fsave(m68k, addr, -1, 0);
|
||||
break;
|
||||
|
||||
if (m68k->fpu_just_reset)
|
||||
case 7: //
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (abs32)
|
||||
{
|
||||
m68ki_write_32(m68k, addr, 0);
|
||||
addr = EA_AL_32(m68k);
|
||||
m68040_do_fsave(m68k, addr, -1, 1);
|
||||
break;
|
||||
}
|
||||
else
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
// we normally generate an IDLE frame
|
||||
REG_A(m68k)[reg] -= 6*4;
|
||||
perform_fsave(m68k, addr, 0);
|
||||
addr = EA_PCDI_16(m68k);
|
||||
m68040_do_fsave(m68k, addr, -1, 1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k));
|
||||
}
|
||||
|
||||
default:
|
||||
fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k));
|
||||
break;
|
||||
|
||||
default:
|
||||
fatalerror("M68kFPU: FSAVE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1891,95 +1936,44 @@ void m68040_fpu_op1(m68ki_cpu_core *m68k)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 2: // (An)
|
||||
addr = REG_A(m68k)[reg];
|
||||
temp = m68ki_read_32(m68k, addr);
|
||||
case 2: // (An)
|
||||
addr = REG_A(m68k)[reg];
|
||||
m68040_do_frestore(m68k, addr, -1);
|
||||
break;
|
||||
|
||||
// check for NULL frame
|
||||
if (temp & 0xff000000)
|
||||
case 3: // (An)+
|
||||
addr = EA_AY_PI_32(m68k);
|
||||
m68040_do_frestore(m68k, addr, reg);
|
||||
break;
|
||||
|
||||
case 5: // (D16, An)
|
||||
addr = EA_AY_DI_16(m68k);
|
||||
m68040_do_frestore(m68k, addr, -1);
|
||||
break;
|
||||
|
||||
case 7: //
|
||||
switch (reg)
|
||||
{
|
||||
case 1: // (abs32)
|
||||
{
|
||||
// we don't handle non-NULL frames and there's no pre/post inc/dec to do here
|
||||
m68k->fpu_just_reset = 0;
|
||||
addr = EA_AL_32(m68k);
|
||||
m68040_do_frestore(m68k, addr, -1);
|
||||
break;
|
||||
}
|
||||
else
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
do_frestore_null(m68k);
|
||||
addr = EA_PCDI_16(m68k);
|
||||
m68040_do_frestore(m68k, addr, -1);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k));
|
||||
}
|
||||
|
||||
case 3: // (An)+
|
||||
addr = EA_AY_PI_32(m68k);
|
||||
temp = m68ki_read_32(m68k, addr);
|
||||
break;
|
||||
|
||||
// check for NULL frame
|
||||
if (temp & 0xff000000)
|
||||
{
|
||||
m68k->fpu_just_reset = 0;
|
||||
|
||||
// how about an IDLE frame?
|
||||
if ((temp & 0x00ff0000) == 0x00180000)
|
||||
{
|
||||
REG_A(m68k)[reg] += 6*4;
|
||||
} // check UNIMP
|
||||
else if ((temp & 0x00ff0000) == 0x00380000)
|
||||
{
|
||||
REG_A(m68k)[reg] += 14*4;
|
||||
} // check BUSY
|
||||
else if ((temp & 0x00ff0000) == 0x00b40000)
|
||||
{
|
||||
REG_A(m68k)[reg] += 45*4;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
do_frestore_null(m68k);
|
||||
}
|
||||
break;
|
||||
|
||||
case 5: // (D16, An)
|
||||
addr = EA_AY_DI_16(m68k);
|
||||
temp = m68ki_read_32(m68k, addr);
|
||||
|
||||
// check for NULL frame
|
||||
if (temp & 0xff000000)
|
||||
{
|
||||
// we don't handle non-NULL frames and there's no pre/post inc/dec to do here
|
||||
m68k->fpu_just_reset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_frestore_null(m68k);
|
||||
}
|
||||
break;
|
||||
|
||||
case 7: //
|
||||
switch (reg)
|
||||
{
|
||||
case 2: // (d16, PC)
|
||||
{
|
||||
addr = EA_PCDI_16(m68k);;
|
||||
temp = m68ki_read_32(m68k, addr);
|
||||
|
||||
// check for NULL frame
|
||||
if (temp & 0xff000000)
|
||||
{
|
||||
// we don't handle non-NULL frames and there's no pre/post inc/dec to do here
|
||||
m68k->fpu_just_reset = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_frestore_null(m68k);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k));
|
||||
default:
|
||||
fatalerror("M68kFPU: FRESTORE unhandled mode %d reg %d at %x\n", mode, reg, REG_PC(m68k));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -761,5 +761,8 @@ public:
|
||||
delegate &operator=(const basetype &src) { *static_cast<basetype *>(this) = src; return *this; }
|
||||
};
|
||||
|
||||
// Some useful delegates
|
||||
|
||||
typedef delegate<void (bool state)> line_cb_t;
|
||||
|
||||
#endif /* __DELEGATE_H__ */
|
||||
|
@ -165,7 +165,6 @@ EMUMACHINEOBJS = \
|
||||
$(EMUMACHINE)/adc1038.o \
|
||||
$(EMUMACHINE)/adc1213x.o \
|
||||
$(EMUMACHINE)/am53cf96.o \
|
||||
$(EMUMACHINE)/am8530h.o \
|
||||
$(EMUMACHINE)/amigafdc.o \
|
||||
$(EMUMACHINE)/at28c16.o \
|
||||
$(EMUMACHINE)/cdp1852.o \
|
||||
|
@ -1,57 +0,0 @@
|
||||
#include "am8530h.h"
|
||||
|
||||
const device_type AM8530H = &device_creator<am8530h_device>;
|
||||
|
||||
am8530h_device::am8530h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, AM8530H, "AM8530H", tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
void am8530h_device::set_int_change_cb(int_cb_t _int_change_cb)
|
||||
{
|
||||
int_change_cb = _int_change_cb;
|
||||
}
|
||||
|
||||
|
||||
void am8530h_device::device_start()
|
||||
{
|
||||
}
|
||||
|
||||
READ8_MEMBER( am8530h_device::ca_r )
|
||||
{
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
READ8_MEMBER( am8530h_device::cb_r )
|
||||
{
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
READ8_MEMBER( am8530h_device::da_r )
|
||||
{
|
||||
return 0x40;
|
||||
}
|
||||
|
||||
READ8_MEMBER( am8530h_device::db_r )
|
||||
{
|
||||
return 0x40;
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( am8530h_device::ca_w )
|
||||
{
|
||||
fprintf(stderr, "ca_w %x, %02x\n", offset, data);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( am8530h_device::cb_w )
|
||||
{
|
||||
fprintf(stderr, "cb_w %x, %02x\n", offset, data);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( am8530h_device::da_w )
|
||||
{
|
||||
fprintf(stderr, "da_w %x, %02x\n", offset, data);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( am8530h_device::db_w )
|
||||
{
|
||||
fprintf(stderr, "db_w %x, %02x\n", offset, data);
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
#ifndef __AM8530H_H__
|
||||
#define __AM8530H_H__
|
||||
|
||||
#include "emu.h"
|
||||
|
||||
#define MCFG_AM8530H_ADD(_tag, _int_change_cb) \
|
||||
MCFG_DEVICE_ADD(_tag, AM8530H, 0) \
|
||||
downcast<am8530h_device *>(device)->set_int_change_cb(_int_change_cb);
|
||||
|
||||
class am8530h_device : public device_t {
|
||||
public:
|
||||
typedef delegate<void ()> int_cb_t;
|
||||
|
||||
am8530h_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
void set_int_change_cb(int_cb_t int_change_cb);
|
||||
|
||||
DECLARE_READ8_MEMBER(ca_r);
|
||||
DECLARE_READ8_MEMBER(cb_r);
|
||||
DECLARE_READ8_MEMBER(da_r);
|
||||
DECLARE_READ8_MEMBER(db_r);
|
||||
|
||||
DECLARE_WRITE8_MEMBER(ca_w);
|
||||
DECLARE_WRITE8_MEMBER(cb_w);
|
||||
DECLARE_WRITE8_MEMBER(da_w);
|
||||
DECLARE_WRITE8_MEMBER(db_w);
|
||||
|
||||
void data_a_w(UINT8 val);
|
||||
void data_b_w(UINT8 val);
|
||||
|
||||
void int_ack();
|
||||
bool int_level_get();
|
||||
|
||||
protected:
|
||||
virtual void device_start();
|
||||
|
||||
private:
|
||||
int_cb_t int_change_cb;
|
||||
};
|
||||
|
||||
extern const device_type AM8530H;
|
||||
|
||||
#endif
|
@ -131,7 +131,8 @@ inline void mccs1850_device::check_interrupt()
|
||||
m_ram[REGISTER_STATUS] &= ~STATUS_IT;
|
||||
}
|
||||
|
||||
m_out_int_func(interrupt ? ASSERT_LINE : CLEAR_LINE);
|
||||
if(!int_cb.isnull())
|
||||
int_cb(interrupt);
|
||||
}
|
||||
|
||||
|
||||
@ -139,11 +140,12 @@ inline void mccs1850_device::check_interrupt()
|
||||
// set_pse_line -
|
||||
//-------------------------------------------------
|
||||
|
||||
inline void mccs1850_device::set_pse_line(int state)
|
||||
inline void mccs1850_device::set_pse_line(bool state)
|
||||
{
|
||||
m_pse = state;
|
||||
|
||||
m_out_pse_func(m_pse);
|
||||
if(!pse_cb.isnull())
|
||||
pse_cb(m_pse);
|
||||
}
|
||||
|
||||
|
||||
@ -156,6 +158,7 @@ inline UINT8 mccs1850_device::read_register(offs_t offset)
|
||||
switch (offset)
|
||||
{
|
||||
case REGISTER_COUNTER_LATCH:
|
||||
case REGISTER_COUNTER_LATCH+3: // Required by the NeXT power on test
|
||||
// load counter value into latch
|
||||
m_ram[REGISTER_COUNTER_LATCH] = m_counter >> 24;
|
||||
m_ram[REGISTER_COUNTER_LATCH + 1] = m_counter >> 16;
|
||||
@ -195,7 +198,7 @@ inline void mccs1850_device::write_register(offs_t offset, UINT8 data)
|
||||
if (data & CONTROL_PD)
|
||||
{
|
||||
if (LOG) logerror("MCCS1850 '%s' Power Down\n", tag());
|
||||
set_pse_line(0);
|
||||
set_pse_line(false);
|
||||
}
|
||||
|
||||
if (data & CONTROL_AR)
|
||||
@ -262,7 +265,7 @@ inline void mccs1850_device::advance_seconds()
|
||||
else
|
||||
{
|
||||
// wake up
|
||||
set_pse_line(1);
|
||||
set_pse_line(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -291,27 +294,11 @@ mccs1850_device::mccs1850_device(const machine_config &mconfig, const char *tag,
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_config_complete - perform any
|
||||
// operations now that the configuration is
|
||||
// complete
|
||||
//-------------------------------------------------
|
||||
|
||||
void mccs1850_device::device_config_complete()
|
||||
void mccs1850_device::set_cb(cb_t _int_cb, cb_t _pse_cb, cb_t _nuc_cb)
|
||||
{
|
||||
// inherit a copy of the static data
|
||||
const mccs1850_interface *intf = reinterpret_cast<const mccs1850_interface *>(static_config());
|
||||
if (intf != NULL)
|
||||
*static_cast<mccs1850_interface *>(this) = *intf;
|
||||
|
||||
// or initialize to defaults if none provided
|
||||
else
|
||||
{
|
||||
memset(&m_out_int_cb, 0, sizeof(m_out_int_cb));
|
||||
memset(&m_out_pse_cb, 0, sizeof(m_out_pse_cb));
|
||||
memset(&m_out_nuc_cb, 0, sizeof(m_out_nuc_cb));
|
||||
}
|
||||
int_cb = _int_cb;
|
||||
pse_cb = _pse_cb;
|
||||
nuc_cb = _nuc_cb;
|
||||
}
|
||||
|
||||
|
||||
@ -321,11 +308,6 @@ void mccs1850_device::device_config_complete()
|
||||
|
||||
void mccs1850_device::device_start()
|
||||
{
|
||||
// resolve callbacks
|
||||
m_out_int_func.resolve(m_out_int_cb, *this);
|
||||
m_out_pse_func.resolve(m_out_pse_cb, *this);
|
||||
m_out_nuc_func.resolve(m_out_nuc_cb, *this);
|
||||
|
||||
// allocate timers
|
||||
m_clock_timer = timer_alloc(TIMER_CLOCK);
|
||||
m_clock_timer->adjust(attotime::from_hz(clock() / 32768), 0, attotime::from_hz(clock() / 32768));
|
||||
@ -456,7 +438,7 @@ WRITE_LINE_MEMBER( mccs1850_device::sck_w )
|
||||
|
||||
if (m_bits == 8)
|
||||
{
|
||||
if (LOG) logerror("MCCS1850 '%s' %s Address %u\n", tag(), BIT(m_address, 7) ? "Write" : "Read", m_address & 0x7f);
|
||||
if (LOG) logerror("MCCS1850 '%s' %s Address %02x\n", tag(), BIT(m_address, 7) ? "Write" : "Read", m_address & 0x7f);
|
||||
|
||||
m_bits = 0;
|
||||
m_state = STATE_DATA;
|
||||
@ -559,7 +541,7 @@ WRITE_LINE_MEMBER( mccs1850_device::pwrsw_w )
|
||||
check_interrupt();
|
||||
}
|
||||
|
||||
set_pse_line(1);
|
||||
set_pse_line(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,41 +31,27 @@
|
||||
// INTERFACE CONFIGURATION MACROS
|
||||
//**************************************************************************
|
||||
|
||||
#define MCFG_MCCS1850_ADD(_tag, _clock, _config) \
|
||||
#define MCFG_MCCS1850_ADD(_tag, _clock, _int_cb, _pse_cb, _nuc_cb) \
|
||||
MCFG_DEVICE_ADD(_tag, MCCS1850, _clock) \
|
||||
MCFG_DEVICE_CONFIG(_config)
|
||||
|
||||
|
||||
#define MCCS1850_INTERFACE(name) \
|
||||
const mccs1850_interface (name) =
|
||||
|
||||
downcast<mccs1850_device *>(device)->set_cb(_int_cb, _pse_cb, _nuc_cb);
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> mccs1850_interface
|
||||
|
||||
struct mccs1850_interface
|
||||
{
|
||||
devcb_write_line m_out_int_cb;
|
||||
devcb_write_line m_out_pse_cb;
|
||||
devcb_write_line m_out_nuc_cb;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ======================> mccs1850_device
|
||||
|
||||
class mccs1850_device : public device_t,
|
||||
public device_rtc_interface,
|
||||
public device_nvram_interface,
|
||||
public mccs1850_interface
|
||||
public device_nvram_interface
|
||||
{
|
||||
public:
|
||||
typedef delegate<void (bool state)> cb_t;
|
||||
|
||||
// construction/destruction
|
||||
mccs1850_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
void set_cb(cb_t int_cb, cb_t pse_cb, cb_t nuc_cb);
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER( ce_w );
|
||||
DECLARE_WRITE_LINE_MEMBER( sck_w );
|
||||
@ -77,7 +63,6 @@ public:
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_config_complete();
|
||||
virtual void device_start();
|
||||
virtual void device_reset();
|
||||
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
|
||||
@ -93,16 +78,14 @@ protected:
|
||||
|
||||
private:
|
||||
inline void check_interrupt();
|
||||
inline void set_pse_line(int state);
|
||||
inline void set_pse_line(bool state);
|
||||
inline UINT8 read_register(offs_t offset);
|
||||
inline void write_register(offs_t offset, UINT8 data);
|
||||
inline void advance_seconds();
|
||||
|
||||
static const device_timer_id TIMER_CLOCK = 0;
|
||||
|
||||
devcb_resolved_write_line m_out_int_func;
|
||||
devcb_resolved_write_line m_out_pse_func;
|
||||
devcb_resolved_write_line m_out_nuc_func;
|
||||
cb_t int_cb, pse_cb, nuc_cb;
|
||||
|
||||
UINT8 m_ram[0x80]; // RAM
|
||||
|
||||
|
@ -213,34 +213,71 @@ UINT64 floppy_image_size(floppy_image_legacy *floppy);
|
||||
/* misc */
|
||||
const char *floppy_error(floperr_t err);
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
/// New implementation
|
||||
// New implementation
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
class floppy_image;
|
||||
|
||||
//! Class representing a floppy image format.
|
||||
class floppy_image_format_t
|
||||
{
|
||||
public:
|
||||
floppy_image_format_t();
|
||||
virtual ~floppy_image_format_t();
|
||||
|
||||
|
||||
/*! @brief Identify an image.
|
||||
The identify function tests if the image is valid
|
||||
for this particular format.
|
||||
@param io buffer containing the image data.
|
||||
@param form_factor Physical form factor of disk, from the enum
|
||||
in floppy_image
|
||||
@return 1 if image valid, 0 otherwise.
|
||||
*/
|
||||
virtual int identify(io_generic *io, UINT32 form_factor) = 0;
|
||||
virtual bool load(io_generic *io, UINT32 form_factor, floppy_image *image) = 0;
|
||||
|
||||
/*! @brief Load an image.
|
||||
The load function opens an image file and converts it to the
|
||||
internal MESS floppy representation.
|
||||
@param io source buffer containing the image data.
|
||||
@param form_factor Physical form factor of disk, from the enum
|
||||
in floppy_image
|
||||
@param image output buffer for data in MESS internal format.
|
||||
@return true on success, false otherwise.
|
||||
*/
|
||||
virtual bool load(io_generic *io, UINT32 form_factor, floppy_image *image) = 0;
|
||||
|
||||
/*! @brief Save an image.
|
||||
The save function writes back an image from the MESS internal
|
||||
floppy representation to the appropriate format on disk.
|
||||
@param io output buffer for the data in the on-disk format.
|
||||
@param image source buffer containing data in MESS internal format.
|
||||
@return true on success, false otherwise.
|
||||
*/
|
||||
virtual bool save(io_generic *io, floppy_image *image);
|
||||
|
||||
//! @returns string containing name of format.
|
||||
virtual const char *name() const = 0;
|
||||
//! @returns string containing description of format.
|
||||
virtual const char *description() const = 0;
|
||||
//! @returns string containing comma-separated list of file
|
||||
//! extensions the format may use.
|
||||
virtual const char *extensions() const = 0;
|
||||
//! @returns true if format supports saving.
|
||||
virtual bool supports_save() const = 0;
|
||||
|
||||
//! Used if a linked list of formats is needed
|
||||
floppy_image_format_t *next;
|
||||
//! This appends a format to the linked list of formats, needed for floppy_image_device().
|
||||
void append(floppy_image_format_t *_next);
|
||||
|
||||
//! This checks if the file has the proper extension for this format.
|
||||
//! @param file_name
|
||||
//! @returns true if file matches the extension.
|
||||
bool extension_matches(const char *file_name) const;
|
||||
|
||||
|
||||
protected:
|
||||
// Input for convert_to_edge
|
||||
//! Input for convert_to_edge
|
||||
enum {
|
||||
MG_SHIFT = 28,
|
||||
|
||||
@ -251,85 +288,105 @@ protected:
|
||||
|
||||
// **** Reader helpers ****
|
||||
|
||||
// Struct designed for easy track data description
|
||||
// Optional, you can always do things by hand, but useful nevertheless
|
||||
// A vector of these structures describes one track.
|
||||
|
||||
//! Struct designed for easy track data description. Contains an opcode and two params.
|
||||
|
||||
//! Optional, you can always do things by hand, but useful nevertheless.
|
||||
//! A vector of these structures describes one track.
|
||||
|
||||
struct desc_e {
|
||||
int type, p1, p2;
|
||||
int type, //!< An opcode
|
||||
p1, //!< first param
|
||||
p2; //!< second param
|
||||
};
|
||||
|
||||
|
||||
//! Opcodes of the format description language used by generate_track()
|
||||
enum {
|
||||
END, // End of description
|
||||
MFM, // One byte in p1 to be mfm-encoded, msb first, repeated p2 times
|
||||
MFMBITS, // A value of p2 bits in p1 to be mfm-encoded, msb first
|
||||
RAW, // One 16 bits word in p1 to be written raw, msb first, repeated p2 times
|
||||
RAWBITS, // A value of p2 bits in p1 to be copied as-is, msb first
|
||||
TRACK_ID, // Track id byte, mfm-encoded
|
||||
TRACK_ID_GCR6, // Track id low 6 bits, gcr6-encoded
|
||||
HEAD_ID, // Head id byte, mfm-encoded
|
||||
TRACK_HEAD_ID_GCR6, // Track id 7th bit + head, gc6-encoded
|
||||
SECTOR_ID, // Sector id byte, mfm-encoded
|
||||
SECTOR_ID_GCR6, // Sector id byte, gcr6-encoded
|
||||
SIZE_ID, // Sector size code on one byte [log2(size/128)], mfm-encoded
|
||||
SECTOR_INFO_GCR6, // Sector info byte, gcr6-encoded
|
||||
OFFSET_ID_O, // Offset (track*2+head) byte, odd bits, mfm-encoded
|
||||
OFFSET_ID_E, // Offset (track*2+head) byte, even bits, mfm-encoded
|
||||
SECTOR_ID_O, // Sector id byte, odd bits, mfm-encoded
|
||||
SECTOR_ID_E, // Sector id byte, even bits, mfm-encoded
|
||||
REMAIN_O, // Remaining sector count, odd bits, mfm-encoded, total sector count in p1
|
||||
REMAIN_E, // Remaining sector count, even bits, mfm-encoded, total sector count in p1
|
||||
END, //!< End of description
|
||||
MFM, //!< One byte in p1 to be mfm-encoded, msb first, repeated p2 times
|
||||
MFMBITS, //!< A value of p2 bits in p1 to be mfm-encoded, msb first
|
||||
RAW, //!< One 16 bits word in p1 to be written raw, msb first, repeated p2 times
|
||||
RAWBITS, //!< A value of p2 bits in p1 to be copied as-is, msb first
|
||||
TRACK_ID, //!< Track id byte, mfm-encoded
|
||||
TRACK_ID_GCR6, //!< Track id low 6 bits, gcr6-encoded
|
||||
HEAD_ID, //!< Head id byte, mfm-encoded
|
||||
TRACK_HEAD_ID_GCR6, //!< Track id 7th bit + head, gc6-encoded
|
||||
SECTOR_ID, //!< Sector id byte, mfm-encoded
|
||||
SECTOR_ID_GCR6, //!< Sector id byte, gcr6-encoded
|
||||
SIZE_ID, //!< Sector size code on one byte [log2(size/128)], mfm-encoded
|
||||
SECTOR_INFO_GCR6, //!< Sector info byte, gcr6-encoded
|
||||
OFFSET_ID_O, //!< Offset (track*2+head) byte, odd bits, mfm-encoded
|
||||
OFFSET_ID_E, //!< Offset (track*2+head) byte, even bits, mfm-encoded
|
||||
SECTOR_ID_O, //!< Sector id byte, odd bits, mfm-encoded
|
||||
SECTOR_ID_E, //!< Sector id byte, even bits, mfm-encoded
|
||||
REMAIN_O, //!< Remaining sector count, odd bits, mfm-encoded, total sector count in p1
|
||||
REMAIN_E, //!< Remaining sector count, even bits, mfm-encoded, total sector count in p1
|
||||
|
||||
SECTOR_DATA, // Sector data to mfm-encode, which in p1, -1 for the current one per the sector id
|
||||
SECTOR_DATA_O, // Sector data to mfm-encode, odd bits only, which in p1, -1 for the current one per the sector id
|
||||
SECTOR_DATA_E, // Sector data to mfm-encode, even bits only, which in p1, -1 for the current one per the sector id
|
||||
SECTOR_DATA_MAC, // Transformed sector data + checksum, mac style, id in p1, -1 for the current one per the sector id
|
||||
SECTOR_DATA, //!< Sector data to mfm-encode, which in p1, -1 for the current one per the sector id
|
||||
SECTOR_DATA_O, //!< Sector data to mfm-encode, odd bits only, which in p1, -1 for the current one per the sector id
|
||||
SECTOR_DATA_E, //!< Sector data to mfm-encode, even bits only, which in p1, -1 for the current one per the sector id
|
||||
SECTOR_DATA_MAC, //!< Transformed sector data + checksum, mac style, id in p1, -1 for the current one per the sector id
|
||||
|
||||
CRC_CCITT_START, // Start a CCITT CRC calculation, with the usual x^16 + x^12 + x^5 + 1 (11021) polynomial, p1 = crc id
|
||||
CRC_AMIGA_START, // Start an amiga checksum calculation, p1 = crc id
|
||||
CRC_MACHEAD_START, // Start of the mac gcr6 sector header checksum calculation (xor of pre-encode 6-bits values, gcr6-encoded)
|
||||
CRC_END, // End the checksum, p1 = crc id
|
||||
CRC, // Write a checksum in the apporpriate format, p1 = crc id
|
||||
CRC_CCITT_START, //!< Start a CCITT CRC calculation, with the usual x^16 + x^12 + x^5 + 1 (11021) polynomial, p1 = crc id
|
||||
CRC_AMIGA_START, //!< Start an amiga checksum calculation, p1 = crc id
|
||||
CRC_MACHEAD_START, //!< Start of the mac gcr6 sector header checksum calculation (xor of pre-encode 6-bits values, gcr6-encoded)
|
||||
CRC_END, //!< End the checksum, p1 = crc id
|
||||
CRC, //!< Write a checksum in the apporpriate format, p1 = crc id
|
||||
|
||||
SECTOR_LOOP_START, // Start of the per-sector loop, sector number goes from p1 to p2 inclusive
|
||||
SECTOR_LOOP_END, // End of the per-sector loop
|
||||
SECTOR_INTERLEAVE_SKEW, // Defines interleave and skew for sector counting
|
||||
SECTOR_LOOP_START, //!< Start of the per-sector loop, sector number goes from p1 to p2 inclusive
|
||||
SECTOR_LOOP_END, //!< End of the per-sector loop
|
||||
SECTOR_INTERLEAVE_SKEW, //!< Defines interleave and skew for sector counting
|
||||
};
|
||||
|
||||
// Sector data description
|
||||
//! Sector data description
|
||||
struct desc_s {
|
||||
int size; // Sector size, int bytes
|
||||
const UINT8 *data; // Sector data
|
||||
UINT8 sector_id; // Sector ID
|
||||
UINT8 sector_info; // Sector free byte
|
||||
int size; //!< Sector size, int bytes
|
||||
const UINT8 *data; //!< Sector data
|
||||
UINT8 sector_id; //!< Sector ID
|
||||
UINT8 sector_info; //!< Sector free byte
|
||||
};
|
||||
|
||||
|
||||
// Generate one track according to the description vector
|
||||
// "sect" is a vector indexed by sector id
|
||||
// "track_size" is in _cells_, i.e. 100000 for a usual 2us-per-cell track at 300rpm
|
||||
|
||||
/*! @brief Generate one track according to the description vector.
|
||||
@param desc track data description
|
||||
@param track
|
||||
@param head
|
||||
@param sect a vector indexed by sector id.
|
||||
@param sect_count number of sectors.
|
||||
@param track_size in _cells_, i.e. 100000 for a usual 2us-per-cell track at 300rpm.
|
||||
@param image
|
||||
*/
|
||||
void generate_track(const desc_e *desc, int track, int head, const desc_s *sect, int sect_count, int track_size, floppy_image *image);
|
||||
|
||||
// Generate a track from cell binary values, MSB-first, size in cells and not bytes
|
||||
/*! @brief Generate a track from cell binary values, MSB-first.
|
||||
@param track
|
||||
@param head
|
||||
@param trackbuf track input buffer.
|
||||
@param track_size in cells, not bytes.
|
||||
@param image
|
||||
*/
|
||||
void generate_track_from_bitstream(int track, int head, const UINT8 *trackbuf, int track_size, floppy_image *image);
|
||||
|
||||
// Generate a track from cell level values (0/1/W/D/N)
|
||||
//
|
||||
// Splice pos is the position of the track splice. For normal
|
||||
// formats, use -1. For protected formats, you're supposed to
|
||||
// know. trackbuf may be modified at that position or after.
|
||||
//
|
||||
// Note that this function needs to be able to split cells in two,
|
||||
// so no time value should be less than 2, and even values are a
|
||||
// good idea.
|
||||
|
||||
//! @brief Generate a track from cell level values (0/1/W/D/N).
|
||||
|
||||
/*! Note that this function needs to be able to split cells in two,
|
||||
so no time value should be less than 2, and even values are a
|
||||
good idea.
|
||||
*/
|
||||
/*! @param track
|
||||
@param head
|
||||
@param trackbuf track input buffer.
|
||||
@param track_size in cells, not bytes.
|
||||
@param splice_pos is the position of the track splice. For normal
|
||||
formats, use -1. For protected formats, you're supposed to
|
||||
know. trackbuf may be modified at that position or after.
|
||||
@param image
|
||||
*/
|
||||
void generate_track_from_levels(int track, int head, UINT32 *trackbuf, int track_size, int splice_pos, floppy_image *image);
|
||||
|
||||
// Normalize the times in a cell buffer to sum up to 200000000
|
||||
//! Normalize the times in a cell buffer to sum up to 200000000
|
||||
void normalize_times(UINT32 *buffer, int bitlen);
|
||||
|
||||
// Some conversion tables
|
||||
// Some conversion tables for gcr6
|
||||
static const UINT8 gcr6fw_tb[0x40], gcr6bw_tb[0x100];
|
||||
|
||||
// Some useful descriptions shared by multiple formats
|
||||
@ -343,7 +400,7 @@ protected:
|
||||
|
||||
// Fastcopy Pro optimized formats, with fake sector header for
|
||||
// faster verify and skew/interleave where appropriate
|
||||
static const desc_e atari_st_fcp_9[];
|
||||
static const desc_e atari_st_fcp_9[];
|
||||
static const desc_e *const atari_st_fcp_10[10];
|
||||
static const desc_e atari_st_fcp_11[];
|
||||
|
||||
@ -363,83 +420,108 @@ protected:
|
||||
|
||||
// **** Writer helpers ****
|
||||
|
||||
// Rebuild a cell bitstream for a track. Takes the cell standard
|
||||
// angular size as a parameter, gives out a msb-first bitstream.
|
||||
// Beware that fuzzy bits will always give out the same value.
|
||||
//
|
||||
// Output buffer size should be 34% more than the nominal number
|
||||
// of cells (the dpll tolerates a cell size down to 75% of the
|
||||
// nominal one, with gives a cell count of 1/0.75=1.333... times
|
||||
// the nominal one).
|
||||
//
|
||||
// Output size is given in bits (cells).
|
||||
//
|
||||
// Computing the standard angular size of a cell is
|
||||
// simple. Noting:
|
||||
// d = standard cell duration in microseconds
|
||||
// r = motor rotational speed in rpm
|
||||
// then:
|
||||
// a = r * d * 10 / 3
|
||||
//
|
||||
// Some values:
|
||||
// Type Cell RPM Size
|
||||
/*! @brief Rebuild a cell bitstream for a track.
|
||||
Takes the cell standard
|
||||
angular size as a parameter, gives out a msb-first bitstream.
|
||||
|
||||
// C1541 tr 1-17 3.25 300 3250
|
||||
// C1541 tr 18-24 3.50 300 3500
|
||||
// C1541 tr 25-30 3.75 300 3750
|
||||
// C1541 tr 31+ 4.00 300 4000
|
||||
// 5.25" SD 4 300 4000
|
||||
// 5.25" DD 2 300 2000
|
||||
// 5.25" HD 1 360 1200
|
||||
// 3.5" SD 4 300 4000
|
||||
// 3.5" DD 2 300 2000
|
||||
// 3.5" HD 1 300 1000
|
||||
// 3.5" ED 0.5 300 500
|
||||
Beware that fuzzy bits will always give out the same value.
|
||||
@param track
|
||||
@param head
|
||||
@param cell_size
|
||||
@param trackbuf Output buffer size should be 34% more than the nominal number
|
||||
of cells (the dpll tolerates a cell size down to 75% of the
|
||||
nominal one, with gives a cell count of 1/0.75=1.333... times
|
||||
the nominal one).
|
||||
@param track_size Output size is given in bits (cells).
|
||||
@param image
|
||||
*/
|
||||
/*! @verbatim
|
||||
Computing the standard angular size of a cell is
|
||||
simple. Noting:
|
||||
d = standard cell duration in microseconds
|
||||
r = motor rotational speed in rpm
|
||||
then:
|
||||
a = r * d * 10 / 3.
|
||||
Some values:
|
||||
Type Cell RPM Size
|
||||
|
||||
C1541 tr 1-17 3.25 300 3250
|
||||
C1541 tr 18-24 3.50 300 3500
|
||||
C1541 tr 25-30 3.75 300 3750
|
||||
C1541 tr 31+ 4.00 300 4000
|
||||
5.25" SD 4 300 4000
|
||||
5.25" DD 2 300 2000
|
||||
5.25" HD 1 360 1200
|
||||
3.5" SD 4 300 4000
|
||||
3.5" DD 2 300 2000
|
||||
3.5" HD 1 300 1000
|
||||
3.5" ED 0.5 300 500
|
||||
@endverbatim
|
||||
*/
|
||||
|
||||
void generate_bitstream_from_track(int track, int head, int cell_size, UINT8 *trackbuf, int &track_size, floppy_image *image);
|
||||
|
||||
|
||||
//! Defines a standard sector for extracting.
|
||||
struct desc_xs {
|
||||
int track, head, size;
|
||||
const UINT8 *data;
|
||||
int track, //!< Track for this sector
|
||||
head, //!< Head for this sector
|
||||
size; //!< Size of this sector
|
||||
const UINT8 *data; //!< Data within this sector
|
||||
};
|
||||
|
||||
// Extract standard sectors from a regenerated bitstream
|
||||
// sectors must point to an array of 256 desc_xs
|
||||
// An existing sector is reconizable by having ->data non-null
|
||||
// Sector data is written in sectdata up to sectdata_size bytes
|
||||
//! @brief Extract standard sectors from a regenerated bitstream.
|
||||
//! Sectors must point to an array of 256 desc_xs.
|
||||
|
||||
// The ones implemented here are the ones used by multiple
|
||||
// systems.
|
||||
//! An existing sector is recognizable by having ->data non-null.
|
||||
//! Sector data is written in sectdata up to sectdata_size bytes.
|
||||
|
||||
// PC-type sectors with MFM encoding, sector size can go from 128 bytes to 16K
|
||||
//! The ones implemented here are the ones used by multiple
|
||||
//! systems.
|
||||
|
||||
//! PC-type sectors with MFM encoding, sector size can go from 128 bytes to 16K.
|
||||
void extract_sectors_from_bitstream_mfm_pc(const UINT8 *bitstream, int track_size, desc_xs *sectors, UINT8 *sectdata, int sectdata_size);
|
||||
|
||||
|
||||
// Get a geometry (including sectors) from an image
|
||||
// PC-type sectors with MFM encoding
|
||||
//! @brief Get a geometry (including sectors) from an image.
|
||||
|
||||
//! PC-type sectors with MFM encoding
|
||||
void get_geometry_mfm_pc(floppy_image *image, int cell_size, int &track_count, int &head_count, int §or_count);
|
||||
|
||||
|
||||
// Regenerate the data for a full track
|
||||
// PC-type sectors with MFM encoding and fixed-size
|
||||
//! Regenerate the data for a full track.
|
||||
//! PC-type sectors with MFM encoding and fixed-size.
|
||||
void get_track_data_mfm_pc(int track, int head, floppy_image *image, int cell_size, int sector_size, int sector_count, UINT8 *sectdata);
|
||||
|
||||
//! Look up a bit in a level-type stream.
|
||||
bool bit_r(const UINT32 *buffer, int offset);
|
||||
//! Look up multiple bits
|
||||
UINT32 bitn_r(const UINT32 *buffer, int offset, int count);
|
||||
//! Write a bit with a given size.
|
||||
void bit_w(UINT32 *buffer, int offset, bool val, UINT32 size = 1000);
|
||||
//! Calculate a CCITT-type CRC.
|
||||
UINT16 calc_crc_ccitt(const UINT32 *buffer, int start, int end);
|
||||
//! Write a series of (raw) bits and increment the offset.
|
||||
void raw_w(UINT32 *buffer, int &offset, int n, UINT32 val, UINT32 size = 1000);
|
||||
//! MFM-encode and write a series of bits
|
||||
void mfm_w(UINT32 *buffer, int &offset, int n, UINT32 val, UINT32 size = 1000);
|
||||
//! MFM-encode every two bits and write
|
||||
void mfm_half_w(UINT32 *buffer, int &offset, int start_bit, UINT32 val, UINT32 size = 1000);
|
||||
//! GCR6 encode (Apple II 16-sector and Mac-style GCR)
|
||||
UINT32 gcr6_encode(UINT8 va, UINT8 vb, UINT8 vc);
|
||||
//! GCR6 decode
|
||||
void gcr6_decode(UINT8 e0, UINT8 e1, UINT8 e2, UINT8 e3, UINT8 &va, UINT8 &vb, UINT8 &vc);
|
||||
|
||||
private:
|
||||
enum { CRC_NONE, CRC_AMIGA, CRC_CCITT, CRC_MACHEAD };
|
||||
enum { MAX_CRC_COUNT = 64 };
|
||||
|
||||
//! Holds data used internally for generating CRCs.
|
||||
struct gen_crc_info {
|
||||
int type, start, end, write;
|
||||
bool fixup_mfm_clock;
|
||||
int type, //!< Type of CRC
|
||||
start, //!< Start position
|
||||
end, //!< End position
|
||||
write; //!< where to write the CRC
|
||||
bool fixup_mfm_clock; //!< would the MFM clock bit after the CRC need to be fixed?
|
||||
};
|
||||
|
||||
bool type_no_data(int type) const;
|
||||
@ -459,7 +541,7 @@ private:
|
||||
int calc_sector_index(int num, int interleave, int skew, int total_sectors, int track_head);
|
||||
};
|
||||
|
||||
// a device_type is simply a pointer to its alloc function
|
||||
// a dce_type is simply a pointer to its alloc function
|
||||
typedef floppy_image_format_t *(*floppy_format_type)();
|
||||
|
||||
// this template function creates a stub which constructs a image format
|
||||
@ -471,85 +553,132 @@ floppy_image_format_t *floppy_image_format_creator()
|
||||
|
||||
// ======================> floppy_image
|
||||
|
||||
// class representing floppy image
|
||||
//! Class representing floppy image
|
||||
|
||||
//! Internal format is close but not identical to the mfi format.
|
||||
//!
|
||||
//!
|
||||
//! Track data consists of a series of 32-bits lsb-first values
|
||||
//! representing magnetic cells. Bits 0-27 indicate the absolute
|
||||
//! position of the start of the cell (not the size), and bits
|
||||
//! 28-31 the type. Type can be:
|
||||
//! - 0, MG_A -> Magnetic orientation A
|
||||
//! - 1, MG_B -> Magnetic orientation B
|
||||
//! - 2, MG_N -> Non-magnetized zone (neutral)
|
||||
//! - 3, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing
|
||||
//!
|
||||
//! The position is in angular units of 1/200,000,000th of a turn.
|
||||
//! The last cell implicit end position is of course 200,000,000.
|
||||
//!
|
||||
//! Unformatted tracks are encoded as zero-size.
|
||||
//!
|
||||
//! The "track splice" information indicates where to start writing
|
||||
//! if you try to rewrite a physical disk with the data. Some
|
||||
//! preservation formats encode that information, it is guessed for
|
||||
//! others. The write track function of fdcs should set it. The
|
||||
//! representation is the angular position relative to the index.
|
||||
//!
|
||||
//! The media type is divided in two parts. The first half
|
||||
//! indicates the physical form factor, i.e. all medias with that
|
||||
//! form factor can be physically inserted in a reader that handles
|
||||
//! it. The second half indicates the variants which are usually
|
||||
//! detectable by the reader, such as density and number of sides.
|
||||
|
||||
|
||||
class floppy_image
|
||||
{
|
||||
public:
|
||||
// Internal format is close but not identical to the mfi format.
|
||||
//
|
||||
//
|
||||
// Track data consists of a series of 32-bits lsb-first values
|
||||
// representing magnetic cells. Bits 0-27 indicate the absolute
|
||||
// position of the start of the cell (not the size), and bits
|
||||
// 28-31 the type. Type can be:
|
||||
// - 0, MG_A -> Magnetic orientation A
|
||||
// - 1, MG_B -> Magnetic orientation B
|
||||
// - 2, MG_N -> Non-magnetized zone (neutral)
|
||||
// - 3, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing
|
||||
//
|
||||
// The position is in angular units of 1/200,000,000th of a turn.
|
||||
// The last cell implicit end position is of course 200,000,000.
|
||||
//
|
||||
// Unformatted tracks are encoded as zero-size.
|
||||
//
|
||||
// The "track splice" information indicates where to start writing
|
||||
// if you try to rewrite a physical disk with the data. Some
|
||||
// preservation formats encode that information, it is guessed for
|
||||
// others. The write track function of fdcs should set it. The
|
||||
// representation is the angular position relative to the index.
|
||||
//
|
||||
// The media type is divided in two parts. The first half
|
||||
// indicate the physical form factor, i.e. all medias with that
|
||||
// form factor can be physically inserted in a reader that handles
|
||||
// it. The second half indicates the variants which are usually
|
||||
// detectable by the reader, such as density and number of sides.
|
||||
|
||||
//! Floppy format data
|
||||
enum {
|
||||
TIME_MASK = 0x0fffffff,
|
||||
MG_MASK = 0xf0000000,
|
||||
MG_SHIFT = 28,
|
||||
|
||||
MG_A = (0 << MG_SHIFT),
|
||||
MG_B = (1 << MG_SHIFT),
|
||||
MG_N = (2 << MG_SHIFT),
|
||||
MG_D = (3 << MG_SHIFT)
|
||||
MG_SHIFT = 28, //!< Bitshift constant for magnetic orientation data
|
||||
MG_A = (0 << MG_SHIFT), //!< - 0, MG_A -> Magnetic orientation A
|
||||
MG_B = (1 << MG_SHIFT), //!< - 1, MG_B -> Magnetic orientation B
|
||||
MG_N = (2 << MG_SHIFT), //!< - 2, MG_N -> Non-magnetized zone (neutral)
|
||||
MG_D = (3 << MG_SHIFT) //!< - 3, MG_D -> Damaged zone, reads as neutral but cannot be changed by writing
|
||||
};
|
||||
|
||||
// Form factors
|
||||
|
||||
//! Form factors
|
||||
enum {
|
||||
FF_UNKNOWN = 0x00000000, // Unknown, useful when converting
|
||||
FF_35 = 0x20203533, // "35 "
|
||||
FF_525 = 0x20353235, // "525 "
|
||||
FF_UNKNOWN = 0x00000000, //!< Unknown, useful when converting
|
||||
FF_35 = 0x20203533, //!< "35 " 3.5 inch disk
|
||||
FF_525 = 0x20353235, //!< "525 " 5.25 inch disk
|
||||
};
|
||||
|
||||
// Variants
|
||||
//! Variants
|
||||
enum {
|
||||
SSSD = 0x44535353, // "SSSD",
|
||||
SSDD = 0x44445353, // "DSSD",
|
||||
DSDD = 0x44445344, // "DSDD",
|
||||
DSHD = 0x44485344, // "DSHD",
|
||||
DSED = 0x44455344, // "DSED",
|
||||
SSSD = 0x44535353, //!< "SSSD", Single-sided single-density
|
||||
SSDD = 0x44445353, //!< "DSSD", Double-sided single-density
|
||||
DSDD = 0x44445344, //!< "DSDD", Double-sided double-density (720K)
|
||||
DSHD = 0x44485344, //!< "DSHD", Double-sided high-density (1440K)
|
||||
DSED = 0x44455344, //!< "DSED", Double-sided extra-density (2880K)
|
||||
};
|
||||
|
||||
// construction/destruction
|
||||
// construction/destruction
|
||||
|
||||
|
||||
//! floppy_image constructor
|
||||
/*!
|
||||
@param _tracks number of tracks.
|
||||
@param _heads number of heads.
|
||||
@param _form_factor form factor of drive (from enum)
|
||||
*/
|
||||
floppy_image(int tracks, int heads, UINT32 form_factor);
|
||||
virtual ~floppy_image();
|
||||
|
||||
|
||||
//! @return the form factor.
|
||||
UINT32 get_form_factor() { return form_factor; }
|
||||
//! @return the variant.
|
||||
UINT32 get_variant() { return variant; }
|
||||
void set_variant(UINT32 v) { variant = v; }
|
||||
//! @param v the variant.
|
||||
void set_variant(UINT32 v) { variant = v; }
|
||||
|
||||
/*!
|
||||
@param track
|
||||
@param head
|
||||
@param size size of this track
|
||||
*/
|
||||
void set_track_size(int track, int head, UINT32 size) { track_size[track][head] = size; ensure_alloc(track, head); }
|
||||
|
||||
/*!
|
||||
@param track track number
|
||||
@param head head number
|
||||
@return a pointer to the data buffer for this track and head
|
||||
*/
|
||||
UINT32 *get_buffer(int track, int head) { return cell_data[track][head]; }
|
||||
//! @return the track size
|
||||
//! @param track
|
||||
//! @param head
|
||||
UINT32 get_track_size(int track, int head) { return track_size[track][head]; }
|
||||
void set_write_splice_position(int track, int head, UINT32 pos) { write_splice[track][head] = pos; }
|
||||
UINT32 get_write_splice_position(int track, int head) const { return write_splice[track][head]; }
|
||||
void get_maximal_geometry(int &tracks, int &heads);
|
||||
void get_actual_geometry(int &tracks, int &heads);
|
||||
|
||||
//! Sets the write splice position.
|
||||
//! The "track splice" information indicates where to start writing
|
||||
//! if you try to rewrite a physical disk with the data. Some
|
||||
//! preservation formats encode that information, it is guessed for
|
||||
//! others. The write track function of fdcs should set it. The
|
||||
//! representation is the angular position relative to the index.
|
||||
|
||||
/*! @param track
|
||||
@param head
|
||||
@param pos the position
|
||||
*/
|
||||
void set_write_splice_position(int track, int head, UINT32 pos) { write_splice[track][head] = pos; }
|
||||
//! @return the current write splice position.
|
||||
UINT32 get_write_splice_position(int track, int head) const { return write_splice[track][head]; }
|
||||
//! @return the maximal geometry supported by thie format.
|
||||
void get_maximal_geometry(int &tracks, int &heads);
|
||||
//! @return the current geometry of the loaded image.
|
||||
void get_actual_geometry(int &tracks, int &heads);
|
||||
//! Returns the variant name for the particular disk form factor/variant
|
||||
//! @param form_factor
|
||||
//! @param variant
|
||||
//! @param returns a string containing the variant name.
|
||||
static const char *get_variant_name(UINT32 form_factor, UINT32 variant);
|
||||
|
||||
private:
|
||||
|
||||
enum {
|
||||
MAX_FLOPPY_HEADS = 2,
|
||||
MAX_FLOPPY_TRACKS = 84
|
||||
|
Loading…
Reference in New Issue
Block a user