mirror of
https://github.com/holub/mame
synced 2025-05-31 18:11:50 +03:00
(MESS) ti99: Work in progress on new HFDC / HDC9234. (nw)
This commit is contained in:
parent
ea9fd2f6c2
commit
b4bc7ee1c6
@ -352,16 +352,26 @@ WRITE8_MEMBER(myarc_hfdc_device::cruwrite)
|
|||||||
m_ram_page[(bit-4)/5] |= 1 << ((bit-9)%5);
|
m_ram_page[(bit-4)/5] |= 1 << ((bit-9)%5);
|
||||||
else
|
else
|
||||||
m_ram_page[(bit-4)/5] &= ~(1 << ((bit-9)%5));
|
m_ram_page[(bit-4)/5] &= ~(1 << ((bit-9)%5));
|
||||||
|
|
||||||
|
if (TRACE_CRU)
|
||||||
|
{
|
||||||
|
if (bit==0x0d) logerror("%s: RAM page @5400 = %d\n", tag(), m_ram_page[1]);
|
||||||
|
if (bit==0x12) logerror("%s: RAM page @5800 = %d\n", tag(), m_ram_page[2]);
|
||||||
|
if (bit==0x17) logerror("%s: RAM page @5C00 = %d\n", tag(), m_ram_page[3]);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (bit)
|
switch (bit)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
m_selected = (data!=0);
|
{
|
||||||
if (TRACE_CRU) logerror("%s: selected = %d\n", tag(), m_selected);
|
bool turnOn = (data!=0);
|
||||||
break;
|
// Avoid too many meaningless log outputs
|
||||||
|
if (TRACE_CRU) if (m_selected != turnOn) logerror("%s: card %s\n", tag(), turnOn? "selected" : "unselected");
|
||||||
|
m_selected = turnOn;
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 1:
|
case 1:
|
||||||
if (TRACE_CRU) if (data==0) logerror("%s: trigger HDC reset\n", tag());
|
if (TRACE_CRU) if (data==0) logerror("%s: trigger HDC reset\n", tag());
|
||||||
m_hdc9234->reset((data == 0)? ASSERT_LINE : CLEAR_LINE);
|
m_hdc9234->reset((data == 0)? ASSERT_LINE : CLEAR_LINE);
|
||||||
@ -382,11 +392,13 @@ WRITE8_MEMBER(myarc_hfdc_device::cruwrite)
|
|||||||
case 3:
|
case 3:
|
||||||
m_CD = (data != 0)? (m_CD | 2) : (m_CD & 0xfd);
|
m_CD = (data != 0)? (m_CD | 2) : (m_CD & 0xfd);
|
||||||
m_rom_page = (data != 0)? (m_rom_page | 2) : (m_rom_page & 0xfd);
|
m_rom_page = (data != 0)? (m_rom_page | 2) : (m_rom_page & 0xfd);
|
||||||
|
if (TRACE_CRU) logerror("%s: ROM page = %d, CD = %d\n", tag(), m_rom_page, m_CD);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
m_see_switches = (data != 0);
|
m_see_switches = (data != 0);
|
||||||
m_rom_page = (data != 0)? (m_rom_page | 1) : (m_rom_page & 0xfe);
|
m_rom_page = (data != 0)? (m_rom_page | 1) : (m_rom_page & 0xfe);
|
||||||
|
if (TRACE_CRU) logerror("%s: ROM page = %d, see_switches = %d\n", tag(), m_rom_page, m_see_switches);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -411,6 +423,7 @@ void myarc_hfdc_device::floppy_index_callback(floppy_image_device *floppy, int s
|
|||||||
logerror("%s: Index callback level=%d\n", tag(), state);
|
logerror("%s: Index callback level=%d\n", tag(), state);
|
||||||
// m_status_latch = (state==ASSERT_LINE)? (m_status_latch | HDC_DS_INDEX) : (m_status_latch & ~HDC_DS_INDEX);
|
// m_status_latch = (state==ASSERT_LINE)? (m_status_latch | HDC_DS_INDEX) : (m_status_latch & ~HDC_DS_INDEX);
|
||||||
set_bits(m_status_latch, HDC_DS_INDEX, (state==ASSERT_LINE));
|
set_bits(m_status_latch, HDC_DS_INDEX, (state==ASSERT_LINE));
|
||||||
|
signal_drive_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
void myarc_hfdc_device::set_bits(UINT8& byte, int mask, bool set)
|
void myarc_hfdc_device::set_bits(UINT8& byte, int mask, bool set)
|
||||||
@ -435,24 +448,37 @@ int myarc_hfdc_device::slog2(int value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read the selected latch via the auxbus. This is always the status register.
|
Notify the controller about the status change
|
||||||
*/
|
*/
|
||||||
READ8_MEMBER( myarc_hfdc_device::auxbus_in )
|
void myarc_hfdc_device::signal_drive_status()
|
||||||
{
|
{
|
||||||
//UINT8 reply = 0;
|
UINT8 reply = 0;
|
||||||
//int index = 0;
|
//int index = 0;
|
||||||
|
|
||||||
if ((m_output1_latch & 0xf0)==0)
|
// Status byte as defined by HDC9234
|
||||||
{
|
// +------+------+------+------+------+------+------+------+
|
||||||
logerror("%s: no drive selected, returning 0\n", tag());
|
// | ECC |Index | SeekC| Tr00 | User | WrPrt| Ready|Fault |
|
||||||
// No HD and no floppy
|
// +------+------+------+------+------+------+------+------+
|
||||||
return 0; /* is that the correct default value? */
|
//
|
||||||
}
|
// Set by HFDC
|
||||||
|
// 74LS240 is used for driving the lines; it also inverts the inputs
|
||||||
|
// If no hard drive or floppy is connected, all lines are 0
|
||||||
|
// +------+------+------+------+------+------+------+------+
|
||||||
|
// | 0 | Index| SeekC| Tr00 | 0 | WrPrt| Ready|Fault |
|
||||||
|
// +------+------+------+------+------+------+------+------+
|
||||||
|
//
|
||||||
|
// Ready = WDS.ready | DSK
|
||||||
|
// SeekComplete = WDS.seekComplete | DSK
|
||||||
|
|
||||||
return m_status_latch;
|
// If DSK is selected, set Ready and SeekComplete to 1
|
||||||
|
// If WDS is selected but not connected, Ready and SeekComplete are 1
|
||||||
|
if ((m_output1_latch & 0x10)!=0) reply |= 0x22;
|
||||||
|
|
||||||
|
reply |= m_status_latch;
|
||||||
|
|
||||||
|
m_hdc9234->auxbus_in(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
When the HDC outputs a byte via its AB (auxiliary bus), we need to latch it.
|
When the HDC outputs a byte via its AB (auxiliary bus), we need to latch it.
|
||||||
The target of the transfer is determined by two control lines (S1,S0).
|
The target of the transfer is determined by two control lines (S1,S0).
|
||||||
@ -463,7 +489,7 @@ READ8_MEMBER( myarc_hfdc_device::auxbus_in )
|
|||||||
*/
|
*/
|
||||||
WRITE8_MEMBER( myarc_hfdc_device::auxbus_out )
|
WRITE8_MEMBER( myarc_hfdc_device::auxbus_out )
|
||||||
{
|
{
|
||||||
//int index;
|
int index;
|
||||||
switch (offset)
|
switch (offset)
|
||||||
{
|
{
|
||||||
case HDC_INPUT_STATUS:
|
case HDC_INPUT_STATUS:
|
||||||
@ -496,18 +522,49 @@ WRITE8_MEMBER( myarc_hfdc_device::auxbus_out )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// HD selected
|
// HD selected
|
||||||
// index = slog2((data>>4) & 0x0f);
|
index = slog2((data>>4) & 0x0f);
|
||||||
// if (index>=0) m_hdc9234->connect_hard_drive(m_harddisk_unit[index-1]);
|
if (index == -1)
|
||||||
set_bits(m_status_latch, HDC_DS_READY, false);
|
{
|
||||||
|
logerror("%s: Unselect all drives\n", tag());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logerror("%s: Select hard disk WDS%d\n", tag(), index);
|
||||||
|
// if (index>=0) m_hdc9234->connect_hard_drive(m_harddisk_unit[index-1]);
|
||||||
|
}
|
||||||
|
if (m_current_harddisk==NULL)
|
||||||
|
{
|
||||||
|
set_bits(m_status_latch, HDC_DS_READY | HDC_DS_SKCOM, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HDC_OUTPUT_2:
|
case HDC_OUTPUT_2:
|
||||||
// value is output2
|
// value is output2
|
||||||
|
// DS3* = /WDS3
|
||||||
|
// WCur = Reduced Write Current
|
||||||
|
// Dir = Step direction
|
||||||
|
// Step = Step pulse
|
||||||
|
// Head = Selected head number (floppy: 0000 or 0001)
|
||||||
|
// +------+------+------+------+------+------+------+------+
|
||||||
|
// | DS3* | WCur | Dir | Step | Head |
|
||||||
|
// +------+------+------+------+------+------+------+------+
|
||||||
logerror("%s: Setting OUTPUT2 latch to %02x\n", tag(), data);
|
logerror("%s: Setting OUTPUT2 latch to %02x\n", tag(), data);
|
||||||
m_output2_latch = data;
|
m_output2_latch = data;
|
||||||
|
|
||||||
|
// Output the step pulse to the selected floppy drive
|
||||||
|
if (m_current_floppy != NULL)
|
||||||
|
{
|
||||||
|
m_current_floppy->dir_w((data & 0x20)==0);
|
||||||
|
m_current_floppy->stp_w(0);
|
||||||
|
m_current_floppy->stp_w(1);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We are pushing the drive status after every output
|
||||||
|
signal_drive_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum
|
enum
|
||||||
@ -523,7 +580,7 @@ void myarc_hfdc_device::connect_floppy_unit(int index)
|
|||||||
{
|
{
|
||||||
if (m_floppy_unit[index] != m_current_floppy)
|
if (m_floppy_unit[index] != m_current_floppy)
|
||||||
{
|
{
|
||||||
logerror("%s: Connect floppy drive %d\n", tag(), index);
|
logerror("%s: Select floppy drive DSK%d\n", tag(), index);
|
||||||
if (m_current_floppy != NULL)
|
if (m_current_floppy != NULL)
|
||||||
{
|
{
|
||||||
// Disconnect old drive from index line
|
// Disconnect old drive from index line
|
||||||
@ -539,33 +596,27 @@ void myarc_hfdc_device::connect_floppy_unit(int index)
|
|||||||
}
|
}
|
||||||
m_hdc9234->connect_floppy_drive(m_floppy_unit[index]);
|
m_hdc9234->connect_floppy_drive(m_floppy_unit[index]);
|
||||||
}
|
}
|
||||||
set_ready(HFDC_FLOPPY, true);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
logerror("%s: Disconnect all floppy drives\n", tag());
|
logerror("%s: Unselect all floppy drives\n", tag());
|
||||||
// Disconnect current floppy
|
// Disconnect current floppy
|
||||||
if (m_current_floppy != NULL)
|
if (m_current_floppy != NULL)
|
||||||
{
|
{
|
||||||
m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
|
m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
|
||||||
m_current_floppy = NULL;
|
m_current_floppy = NULL;
|
||||||
}
|
}
|
||||||
set_ready(HFDC_FLOPPY, false);
|
|
||||||
}
|
}
|
||||||
|
signal_drive_status();
|
||||||
}
|
}
|
||||||
|
|
||||||
void myarc_hfdc_device::connect_harddisk_unit(int index)
|
void myarc_hfdc_device::connect_harddisk_unit(int index)
|
||||||
{
|
{
|
||||||
set_ready(HFDC_HARDDISK, false);
|
// if (index < 0)
|
||||||
}
|
// {
|
||||||
|
m_current_harddisk = NULL;
|
||||||
/*
|
// }
|
||||||
Joins the ready lines from the floppy drives and the hard drives
|
signal_drive_status();
|
||||||
*/
|
|
||||||
void myarc_hfdc_device::set_ready(int dev, bool ready)
|
|
||||||
{
|
|
||||||
m_readyflags = ready? (m_readyflags | dev) : (m_readyflags & ~dev);
|
|
||||||
set_bits(m_status_latch, HDC_DS_READY, (m_readyflags != 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -638,6 +689,7 @@ void myarc_hfdc_device::device_start()
|
|||||||
m_buffer_ram = memregion(BUFFER)->base();
|
m_buffer_ram = memregion(BUFFER)->base();
|
||||||
m_motor_on_timer = timer_alloc(MOTOR_TIMER);
|
m_motor_on_timer = timer_alloc(MOTOR_TIMER);
|
||||||
// The HFDC does not use READY; it has on-board RAM for DMA
|
// The HFDC does not use READY; it has on-board RAM for DMA
|
||||||
|
m_current_floppy = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void myarc_hfdc_device::device_reset()
|
void myarc_hfdc_device::device_reset()
|
||||||
@ -665,6 +717,9 @@ void myarc_hfdc_device::device_reset()
|
|||||||
for (int i=1; i < 4; i++) m_ram_page[i] = 0;
|
for (int i=1; i < 4; i++) m_ram_page[i] = 0;
|
||||||
|
|
||||||
m_output1_latch = m_output2_latch = 0;
|
m_output1_latch = m_output2_latch = 0;
|
||||||
|
|
||||||
|
m_status_latch = 0x00;
|
||||||
|
|
||||||
m_dip = m_irq = CLEAR_LINE;
|
m_dip = m_irq = CLEAR_LINE;
|
||||||
m_see_switches = false;
|
m_see_switches = false;
|
||||||
m_CD = 0;
|
m_CD = 0;
|
||||||
@ -742,7 +797,6 @@ MACHINE_CONFIG_FRAGMENT( ti99_hfdc )
|
|||||||
MCFG_HDC9234_INTRQ_CALLBACK(WRITELINE(myarc_hfdc_device, intrq_w))
|
MCFG_HDC9234_INTRQ_CALLBACK(WRITELINE(myarc_hfdc_device, intrq_w))
|
||||||
MCFG_HDC9234_DIP_CALLBACK(WRITELINE(myarc_hfdc_device, dip_w))
|
MCFG_HDC9234_DIP_CALLBACK(WRITELINE(myarc_hfdc_device, dip_w))
|
||||||
MCFG_HDC9234_AUXBUS_OUT_CALLBACK(WRITE8(myarc_hfdc_device, auxbus_out))
|
MCFG_HDC9234_AUXBUS_OUT_CALLBACK(WRITE8(myarc_hfdc_device, auxbus_out))
|
||||||
MCFG_HDC9234_AUXBUS_IN_CALLBACK(READ8(myarc_hfdc_device, auxbus_in))
|
|
||||||
MCFG_HDC9234_DMA_IN_CALLBACK(READ8(myarc_hfdc_device, read_buffer))
|
MCFG_HDC9234_DMA_IN_CALLBACK(READ8(myarc_hfdc_device, read_buffer))
|
||||||
MCFG_HDC9234_DMA_OUT_CALLBACK(WRITE8(myarc_hfdc_device, write_buffer))
|
MCFG_HDC9234_DMA_OUT_CALLBACK(WRITE8(myarc_hfdc_device, write_buffer))
|
||||||
|
|
||||||
|
@ -43,7 +43,6 @@ public:
|
|||||||
DECLARE_WRITE_LINE_MEMBER( intrq_w );
|
DECLARE_WRITE_LINE_MEMBER( intrq_w );
|
||||||
DECLARE_WRITE_LINE_MEMBER( dip_w );
|
DECLARE_WRITE_LINE_MEMBER( dip_w );
|
||||||
DECLARE_WRITE8_MEMBER( auxbus_out );
|
DECLARE_WRITE8_MEMBER( auxbus_out );
|
||||||
DECLARE_READ8_MEMBER( auxbus_in );
|
|
||||||
DECLARE_READ8_MEMBER( read_buffer );
|
DECLARE_READ8_MEMBER( read_buffer );
|
||||||
DECLARE_WRITE8_MEMBER( write_buffer );
|
DECLARE_WRITE8_MEMBER( write_buffer );
|
||||||
|
|
||||||
@ -71,6 +70,9 @@ private:
|
|||||||
// Connect or disconnect harddisk drives
|
// Connect or disconnect harddisk drives
|
||||||
void connect_harddisk_unit(int index);
|
void connect_harddisk_unit(int index);
|
||||||
|
|
||||||
|
// Pushes the drive status to the HDC
|
||||||
|
void signal_drive_status();
|
||||||
|
|
||||||
// Motor monoflop (4.23 sec)
|
// Motor monoflop (4.23 sec)
|
||||||
emu_timer* m_motor_on_timer;
|
emu_timer* m_motor_on_timer;
|
||||||
|
|
||||||
@ -86,6 +88,9 @@ private:
|
|||||||
// Currently selected floppy drive
|
// Currently selected floppy drive
|
||||||
floppy_image_device* m_current_floppy;
|
floppy_image_device* m_current_floppy;
|
||||||
|
|
||||||
|
// Currently selected hard drive
|
||||||
|
void* m_current_harddisk;
|
||||||
|
|
||||||
// True: Access to DIP switch settings, false: access to line states
|
// True: Access to DIP switch settings, false: access to line states
|
||||||
bool m_see_switches;
|
bool m_see_switches;
|
||||||
|
|
||||||
|
@ -27,6 +27,28 @@
|
|||||||
/*
|
/*
|
||||||
Register names of the HDC. The left part is the set of write registers,
|
Register names of the HDC. The left part is the set of write registers,
|
||||||
while the right part are the read registers.
|
while the right part are the read registers.
|
||||||
|
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
DHEAD: | 0 | Sector size | 0 | Desired head (OUTPUT2) | AT mode
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
| 0 | Desired cylinder | Desired head (OUTPUT2) | SMC mode
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
RETRY: | Retry count | Progr. output (OUTPUT1) |
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
MODE: | HD | use CRC/ECC | FM | 0 | step rate |
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
INTCOMM:| 1 | 0 | Done | DelD | User | WrPrt| Ready|Wfault|
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
DDELAY: | 0 | 0 | Sector size | 0 | 0 | Zone | AT mode
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
| Data to be written on disk | writing
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
| Head load timer count | drselect
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -51,17 +73,32 @@ enum
|
|||||||
*/
|
*/
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
ST_INTPEND = 0x80 , // interrupt pending
|
ST_INTPEND = 0x80, // interrupt pending
|
||||||
ST_DMAREQ = 0x40 , // DMA request
|
ST_DMAREQ = 0x40, // DMA request
|
||||||
ST_DONE = 0x20 , // command done
|
ST_DONE = 0x20, // command done
|
||||||
ST_TERMCOD = 0x18 , // termination code (see below)
|
ST_TERMCOD = 0x18, // termination code (see below)
|
||||||
TC_SUCCESS = 0x00 , // Successful completion
|
TC_SUCCESS = 0x00, // Successful completion
|
||||||
TC_RDIDERR = 0x08 , // Error in READ-ID sequence
|
TC_RDIDERR = 0x08, // Error in READ-ID sequence
|
||||||
TC_SEEKERR = 0x10 , // Error in SEEK sequence
|
TC_SEEKERR = 0x10, // Error in SEEK sequence
|
||||||
TC_DATAERR = 0x18 , // Error in DATA-TRANSFER seq.
|
TC_DATAERR = 0x18, // Error in DATA-TRANSFER seq.
|
||||||
ST_RDYCHNG = 0x04 , // ready change
|
ST_RDYCHNG = 0x04, // ready change
|
||||||
ST_OVRUN = 0x02 , // overrun/underrun
|
ST_OVRUN = 0x02, // overrun/underrun
|
||||||
ST_BADSECT = 0x01 // bad sector
|
ST_BADSECT = 0x01 // bad sector
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
Definition of bits in the Termination-Conditions register
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
TC_CRCPRE = 0x80, // CRC register preset, must be 1
|
||||||
|
TC_UNUSED = 0x40, // bit 6 is not used and must be 0
|
||||||
|
TC_INTDONE = 0x20, // interrupt on command completion
|
||||||
|
TC_TDELDAT = 0x10, // terminate on deleted data mark detection
|
||||||
|
TC_TDUSER = 0x08, // user-defined condition
|
||||||
|
TC_TWPROT = 0x04, // terminate on write protection
|
||||||
|
TC_INTRDCH = 0x02, // interrupt on ready change
|
||||||
|
TC_TWRFLT = 0x01 // interrupt on write fault
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -117,7 +154,6 @@ hdc9234_device::hdc9234_device(const machine_config &mconfig, const char *tag, d
|
|||||||
m_out_intrq(*this),
|
m_out_intrq(*this),
|
||||||
m_out_dip(*this),
|
m_out_dip(*this),
|
||||||
m_out_auxbus(*this),
|
m_out_auxbus(*this),
|
||||||
m_in_auxbus(*this),
|
|
||||||
m_in_dma(*this),
|
m_in_dma(*this),
|
||||||
m_out_dma(*this)
|
m_out_dma(*this)
|
||||||
{
|
{
|
||||||
@ -189,19 +225,18 @@ void hdc9234_device::process_command(UINT8 opcode)
|
|||||||
// done when no drive is in use
|
// done when no drive is in use
|
||||||
if (TRACE_ACT) logerror("%s: drdeselect command\n", tag());
|
if (TRACE_ACT) logerror("%s: drdeselect command\n", tag());
|
||||||
set_bits(m_output1, OUT1_DRVSEL3|OUT1_DRVSEL2|OUT1_DRVSEL1|OUT1_DRVSEL0, false);
|
set_bits(m_output1, OUT1_DRVSEL3|OUT1_DRVSEL2|OUT1_DRVSEL1|OUT1_DRVSEL0, false);
|
||||||
set_bits(m_output2, OUT2_DRVSEL3I, true); // inverted level
|
sync_latches_out();
|
||||||
}
|
}
|
||||||
else if (opcode >= 0x20 && opcode <= 0x3f)
|
else if (opcode >= 0x20 && opcode <= 0x3f)
|
||||||
{
|
{
|
||||||
// DRIVE SELECT
|
// DRIVE SELECT
|
||||||
if (TRACE_ACT) logerror("%s: drselect command %02x\n", tag(), opcode);
|
|
||||||
drive_select(opcode&0x1f);
|
drive_select(opcode&0x1f);
|
||||||
}
|
}
|
||||||
else if (opcode >= 0x40 && opcode <= 0x4f)
|
else if (opcode >= 0x40 && opcode <= 0x4f)
|
||||||
{
|
{
|
||||||
// SETREGPTR
|
// SETREGPTR
|
||||||
if (TRACE_ACT) logerror("%s: setregptr command %02x\n", tag(), opcode);
|
|
||||||
m_register_pointer = opcode & 0xf;
|
m_register_pointer = opcode & 0xf;
|
||||||
|
if (TRACE_ACT) logerror("%s: setregptr command; start reg=%d\n", tag(), m_register_pointer);
|
||||||
// Spec does not say anything about the effect of setting an
|
// Spec does not say anything about the effect of setting an
|
||||||
// invalid value (only "care should be taken")
|
// invalid value (only "care should be taken")
|
||||||
if (m_register_pointer > 10)
|
if (m_register_pointer > 10)
|
||||||
@ -210,6 +245,39 @@ void hdc9234_device::process_command(UINT8 opcode)
|
|||||||
m_register_pointer = 10;
|
m_register_pointer = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
set_command_done();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Assert Command Done status bit, triggering interrupts as needed
|
||||||
|
*/
|
||||||
|
void hdc9234_device::set_command_done(int flags)
|
||||||
|
{
|
||||||
|
set_bits(m_register_r[INT_STATUS], ST_DONE, true);
|
||||||
|
|
||||||
|
if (flags != -1)
|
||||||
|
{
|
||||||
|
set_bits(m_register_r[INT_STATUS], ST_TERMCOD, false); // clear the previously set flags
|
||||||
|
m_register_r[INT_STATUS] |= flags;
|
||||||
|
if (TRACE_ACT) logerror("%s: command %02x done, flags=%02x\n", tag(), m_command, flags);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (TRACE_ACT) logerror("%s: command %02x done\n", tag(), m_command);
|
||||||
|
}
|
||||||
|
|
||||||
|
// [1], p. 6
|
||||||
|
if (m_register_w[INT_COMM_TERM] & TC_INTDONE)
|
||||||
|
set_interrupt(ASSERT_LINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Preserve previously set termination code
|
||||||
|
*/
|
||||||
|
void hdc9234_device::set_command_done()
|
||||||
|
{
|
||||||
|
set_command_done(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hdc9234_device::drive_select(int driveparm)
|
void hdc9234_device::drive_select(int driveparm)
|
||||||
@ -222,13 +290,17 @@ void hdc9234_device::drive_select(int driveparm)
|
|||||||
// +-----+-----+-----+-----+-----+-----+-----+-----+
|
// +-----+-----+-----+-----+-----+-----+-----+-----+
|
||||||
//
|
//
|
||||||
// [1] p.5: lower 4 bits of retry count register is put on OUTPUT1
|
// [1] p.5: lower 4 bits of retry count register is put on OUTPUT1
|
||||||
|
|
||||||
m_output1 = (0x10 << (driveparm & 0x03)) | (m_register_w[RETRY_COUNT]&0x0f);
|
m_output1 = (0x10 << (driveparm & 0x03)) | (m_register_w[RETRY_COUNT]&0x0f);
|
||||||
|
// Bit 7 of OUTPUT2 is complement of Bit 7 of OUTPUT1
|
||||||
|
|
||||||
// The drive type is used to configure DMA burst mode ([1], p.12)
|
// The drive type is used to configure DMA burst mode ([1], p.12)
|
||||||
// and to select the timing parameters
|
// and to select the timing parameters
|
||||||
m_selected_drive_type = (driveparm>>2) & 0x03;
|
m_selected_drive_type = (driveparm>>2) & 0x03;
|
||||||
m_head_load_delay_enable = (driveparm>>4)&0x01;
|
m_head_load_delay_enable = (driveparm>>4)&0x01;
|
||||||
|
|
||||||
|
if (TRACE_ACT) logerror("%s: drive select command: head load delay=%d, type=%d, drive=%d\n", tag(), m_head_load_delay_enable, m_selected_drive_type, driveparm&3);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// We need to store the type of the drive for the poll_drives command
|
// We need to store the type of the drive for the poll_drives command
|
||||||
// to be able to correctly select the device (floppy or hard disk).
|
// to be able to correctly select the device (floppy or hard disk).
|
||||||
@ -244,7 +316,6 @@ void hdc9234_device::drive_select(int driveparm)
|
|||||||
m_register_r[CHIP_STATUS] = (m_register_r[CHIP_STATUS] & 0xfc) | (driveparm & 0x03);
|
m_register_r[CHIP_STATUS] = (m_register_r[CHIP_STATUS] & 0xfc) | (driveparm & 0x03);
|
||||||
|
|
||||||
sync_latches_out();
|
sync_latches_out();
|
||||||
sync_status_in();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -256,37 +327,6 @@ void hdc9234_device::connect_floppy_drive(floppy_image_device* floppy)
|
|||||||
m_floppy = floppy;
|
m_floppy = floppy;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
Get the state from outside and latch it in the register.
|
|
||||||
There should be a bus driver on the PCB which provides the signals from
|
|
||||||
both the hard and floppy drives during S0=S1=0 and STB*=0 times via the
|
|
||||||
auxiliary bus.
|
|
||||||
*/
|
|
||||||
void hdc9234_device::sync_status_in()
|
|
||||||
{
|
|
||||||
UINT8 prev = m_register_r[DRIVE_STATUS];
|
|
||||||
m_register_r[DRIVE_STATUS] = m_in_auxbus(0);
|
|
||||||
|
|
||||||
// Raise interrupt if ready changes.
|
|
||||||
if (((m_register_r[DRIVE_STATUS] & HDC_DS_READY) != (prev & HDC_DS_READY))
|
|
||||||
& (m_register_r[INT_STATUS] & ST_RDYCHNG))
|
|
||||||
{
|
|
||||||
set_interrupt(ASSERT_LINE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
Push the output registers over the auxiliary bus. It is expected that
|
|
||||||
the PCB contains latches to store the values.
|
|
||||||
TODO: Timing (the spec is not clear at that point)
|
|
||||||
*/
|
|
||||||
void hdc9234_device::sync_latches_out()
|
|
||||||
{
|
|
||||||
m_output1 = (m_output1 & 0xf0) | (m_register_w[RETRY_COUNT]&0x0f);
|
|
||||||
m_out_auxbus((offs_t)HDC_OUTPUT_1, m_output1);
|
|
||||||
m_out_auxbus((offs_t)HDC_OUTPUT_2, m_output2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read a byte of data from the controller
|
Read a byte of data from the controller
|
||||||
The address (offset) encodes the C/D* line (command and /data)
|
The address (offset) encodes the C/D* line (command and /data)
|
||||||
@ -350,6 +390,100 @@ WRITE8_MEMBER( hdc9234_device::write )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Auxiliary bus operation.
|
||||||
|
|
||||||
|
The auxbus of the HDC9234 is used to poll the drive status of the cur-
|
||||||
|
rently selected drive, to transmit DMA address bytes, to output the
|
||||||
|
OUTPUT1 register, and to output the OUTPUT2 register.
|
||||||
|
|
||||||
|
The specification is not really precise on the times when this bus is
|
||||||
|
used, but at least we can rely on this information:
|
||||||
|
|
||||||
|
- Whenever there is no output of data, the bus is sampled. ([1], p.8,
|
||||||
|
Drive status register). Data is sampled at the rising edge of STB*.
|
||||||
|
As the minimum STB* pulse is 800ns with min 100ns S0/S1 settling time
|
||||||
|
and min 100ns hold time we can say that the bus is polled at a maximum
|
||||||
|
rate of 1 MHz.
|
||||||
|
|
||||||
|
- Data for the DMA address is output only when the address is initially
|
||||||
|
set; also when the address must be set again on error ([1], p.5,
|
||||||
|
DMA registers). The external memory system has to take care of the
|
||||||
|
addressing for subsequent bytes. The address will be increased by the
|
||||||
|
length of a sector during multiple sector read/write operations.
|
||||||
|
|
||||||
|
We may assume that the OUTPUT1 and OUTPUT2 operations only occur on
|
||||||
|
changes to the registers in the controller. The values showing up on the
|
||||||
|
auxiliary bus must be latched anyway.
|
||||||
|
|
||||||
|
For the sampling of drive status values, the emulation would have to
|
||||||
|
invoke a callback to the hosting board at a rate of about 1 MHz. Since
|
||||||
|
the devices like floppy or hard disks are pushing their status changes,
|
||||||
|
it makes much more sense to allow for an incoming call to the controller
|
||||||
|
instead of a polling. This also allows to raise interrupts as soon
|
||||||
|
as the drive status changes. The difference to the real controller
|
||||||
|
would be less than 3 microseconds (in the worst case when the auxbus is
|
||||||
|
currently outputting data as the drive status change occurs).
|
||||||
|
|
||||||
|
Drive status read
|
||||||
|
S0 = 0, S1 = 0
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
| ECC |Index | SeekC| Tr00 | User | WrPrt| Ready|Fault |
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
|
||||||
|
|
||||||
|
OUTPUT1 register contents
|
||||||
|
S0 = 0, S1 = 1
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
| Drv3 | Drv2 | Drv1 | Drv0 | PO3 | PO2 | PO1 | PO0 |
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
|
||||||
|
DrvX = select Drive X (only one bit allowed)
|
||||||
|
POX = Programmable output X (contents from low 4 bits of register RETRY_COUNT)
|
||||||
|
|
||||||
|
|
||||||
|
OUTPUT2 register contents
|
||||||
|
S0 = 1, S1 = 1
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
| Drv3*| WCur | Dir | Step | Head |
|
||||||
|
+------+------+------+------+------+------+------+------+
|
||||||
|
|
||||||
|
Drv3* = inverted Drv3 signal of OUTPUT1
|
||||||
|
WCur = Reduced write current
|
||||||
|
Dir = Step direction (0 = towards track 0)
|
||||||
|
Step = Step pulse
|
||||||
|
Head = desired head
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
Read the drive status over the auxbus
|
||||||
|
(as said, let the controller board push the values into the controller)
|
||||||
|
*/
|
||||||
|
void hdc9234_device::auxbus_in(UINT8 data)
|
||||||
|
{
|
||||||
|
if (TRACE_ACT) logerror("%s: Got value %02x via auxbus\n", tag(), data);
|
||||||
|
UINT8 prev = m_register_r[DRIVE_STATUS];
|
||||||
|
m_register_r[DRIVE_STATUS] = data;
|
||||||
|
|
||||||
|
// Raise interrupt if ready changes.
|
||||||
|
if (((m_register_r[DRIVE_STATUS] & HDC_DS_READY) != (prev & HDC_DS_READY))
|
||||||
|
& (m_register_r[INT_STATUS] & ST_RDYCHNG))
|
||||||
|
{
|
||||||
|
set_interrupt(ASSERT_LINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Push the output registers over the auxiliary bus. It is expected that
|
||||||
|
the PCB contains latches to store the values.
|
||||||
|
*/
|
||||||
|
void hdc9234_device::sync_latches_out()
|
||||||
|
{
|
||||||
|
m_out_auxbus((offs_t)HDC_OUTPUT_1, m_output1);
|
||||||
|
set_bits(m_output2, OUT2_DRVSEL3I, (m_output1 & 0x80)==0);
|
||||||
|
m_out_auxbus((offs_t)HDC_OUTPUT_2, m_output2);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reset the controller. Negative logic, but we use ASSERT_LINE.
|
Reset the controller. Negative logic, but we use ASSERT_LINE.
|
||||||
*/
|
*/
|
||||||
@ -368,7 +502,6 @@ void hdc9234_device::device_start()
|
|||||||
m_out_intrq.resolve_safe();
|
m_out_intrq.resolve_safe();
|
||||||
m_out_dip.resolve_safe();
|
m_out_dip.resolve_safe();
|
||||||
m_out_auxbus.resolve_safe();
|
m_out_auxbus.resolve_safe();
|
||||||
m_in_auxbus.resolve_safe(0);
|
|
||||||
m_out_dma.resolve_safe();
|
m_out_dma.resolve_safe();
|
||||||
m_in_dma.resolve_safe(0);
|
m_in_dma.resolve_safe(0);
|
||||||
|
|
||||||
@ -381,6 +514,14 @@ void hdc9234_device::device_reset()
|
|||||||
m_selected_drive_type = 0;
|
m_selected_drive_type = 0;
|
||||||
m_head_load_delay_enable = false;
|
m_head_load_delay_enable = false;
|
||||||
m_register_pointer = 0;
|
m_register_pointer = 0;
|
||||||
|
m_output1 = 0;
|
||||||
|
m_output2 = 0x80;
|
||||||
|
|
||||||
|
set_interrupt(CLEAR_LINE);
|
||||||
|
m_out_dip(CLEAR_LINE);
|
||||||
|
|
||||||
|
for (int i=0; i<=11; i++)
|
||||||
|
m_register_r[i] = m_register_w[i] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const device_type HDC9234 = &device_creator<hdc9234_device>;
|
const device_type HDC9234 = &device_creator<hdc9234_device>;
|
||||||
|
@ -55,10 +55,6 @@ enum
|
|||||||
#define MCFG_HDC9234_AUXBUS_OUT_CALLBACK(_write) \
|
#define MCFG_HDC9234_AUXBUS_OUT_CALLBACK(_write) \
|
||||||
devcb = &hdc9234_device::set_auxbus_wr_callback(*device, DEVCB_##_write);
|
devcb = &hdc9234_device::set_auxbus_wr_callback(*device, DEVCB_##_write);
|
||||||
|
|
||||||
/* Auxiliary Bus. This is only used for S0=S1=0. */
|
|
||||||
#define MCFG_HDC9234_AUXBUS_IN_CALLBACK(_read) \
|
|
||||||
devcb = &hdc9234_device::set_auxbus_rd_callback(*device, DEVCB_##_read);
|
|
||||||
|
|
||||||
/* Callback to read the contents of the external RAM via the data bus.
|
/* Callback to read the contents of the external RAM via the data bus.
|
||||||
Note that the address must be set and automatically increased
|
Note that the address must be set and automatically increased
|
||||||
by external circuitry. */
|
by external circuitry. */
|
||||||
@ -87,10 +83,14 @@ public:
|
|||||||
template<class _Object> static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_intrq.set_callback(object); }
|
template<class _Object> static devcb_base &set_intrq_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_intrq.set_callback(object); }
|
||||||
template<class _Object> static devcb_base &set_dip_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_dip.set_callback(object); }
|
template<class _Object> static devcb_base &set_dip_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_dip.set_callback(object); }
|
||||||
template<class _Object> static devcb_base &set_auxbus_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_auxbus.set_callback(object); }
|
template<class _Object> static devcb_base &set_auxbus_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_auxbus.set_callback(object); }
|
||||||
template<class _Object> static devcb_base &set_auxbus_rd_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_in_auxbus.set_callback(object); }
|
|
||||||
template<class _Object> static devcb_base &set_dma_rd_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_in_dma.set_callback(object); }
|
template<class _Object> static devcb_base &set_dma_rd_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_in_dma.set_callback(object); }
|
||||||
template<class _Object> static devcb_base &set_dma_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_dma.set_callback(object); }
|
template<class _Object> static devcb_base &set_dma_wr_callback(device_t &device, _Object object) { return downcast<hdc9234_device &>(device).m_out_dma.set_callback(object); }
|
||||||
|
|
||||||
|
// auxbus_in is intended to read events from the drives
|
||||||
|
// In the real chip the status is polled; to avoid unnecessary load
|
||||||
|
// we implement it as a push call
|
||||||
|
void auxbus_in( UINT8 data );
|
||||||
|
|
||||||
// Used to reconfigure the drive connections. Floppy drive selection is done
|
// Used to reconfigure the drive connections. Floppy drive selection is done
|
||||||
// using the user-programmable outputs. Hence, the connection
|
// using the user-programmable outputs. Hence, the connection
|
||||||
// is changed outside of the controller, and by this way we let it know.
|
// is changed outside of the controller, and by this way we let it know.
|
||||||
@ -104,7 +104,6 @@ private:
|
|||||||
devcb_write_line m_out_intrq; // INT line
|
devcb_write_line m_out_intrq; // INT line
|
||||||
devcb_write_line m_out_dip; // DMA in progress line
|
devcb_write_line m_out_dip; // DMA in progress line
|
||||||
devcb_write8 m_out_auxbus; // AB0-7 lines (using S0,S1 as address)
|
devcb_write8 m_out_auxbus; // AB0-7 lines (using S0,S1 as address)
|
||||||
devcb_read8 m_in_auxbus; // AB0-7 lines (S0=S1=0)
|
|
||||||
devcb_read8 m_in_dma; // DMA read access to the cache buffer
|
devcb_read8 m_in_dma; // DMA read access to the cache buffer
|
||||||
devcb_write8 m_out_dma; // DMA write access to the cache buffer
|
devcb_write8 m_out_dma; // DMA write access to the cache buffer
|
||||||
|
|
||||||
@ -118,6 +117,10 @@ private:
|
|||||||
// Command processing
|
// Command processing
|
||||||
void process_command(UINT8 opcode);
|
void process_command(UINT8 opcode);
|
||||||
|
|
||||||
|
// Command is done
|
||||||
|
void set_command_done(int flags);
|
||||||
|
void set_command_done();
|
||||||
|
|
||||||
// Recent command.
|
// Recent command.
|
||||||
UINT8 m_command;
|
UINT8 m_command;
|
||||||
|
|
||||||
@ -133,9 +136,6 @@ private:
|
|||||||
// internal register OUTPUT2
|
// internal register OUTPUT2
|
||||||
UINT8 m_output2;
|
UINT8 m_output2;
|
||||||
|
|
||||||
// Sample the values of the incoming status bits
|
|
||||||
void sync_status_in();
|
|
||||||
|
|
||||||
// Write the output registers to the latches
|
// Write the output registers to the latches
|
||||||
void sync_latches_out();
|
void sync_latches_out();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user