mirror of
https://github.com/holub/mame
synced 2025-05-30 09:33:05 +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);
|
||||
else
|
||||
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;
|
||||
}
|
||||
|
||||
switch (bit)
|
||||
{
|
||||
case 0:
|
||||
m_selected = (data!=0);
|
||||
if (TRACE_CRU) logerror("%s: selected = %d\n", tag(), m_selected);
|
||||
break;
|
||||
|
||||
{
|
||||
bool turnOn = (data!=0);
|
||||
// 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:
|
||||
if (TRACE_CRU) if (data==0) logerror("%s: trigger HDC reset\n", tag());
|
||||
m_hdc9234->reset((data == 0)? ASSERT_LINE : CLEAR_LINE);
|
||||
@ -382,11 +392,13 @@ WRITE8_MEMBER(myarc_hfdc_device::cruwrite)
|
||||
case 3:
|
||||
m_CD = (data != 0)? (m_CD | 2) : (m_CD & 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;
|
||||
|
||||
case 4:
|
||||
m_see_switches = (data != 0);
|
||||
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;
|
||||
|
||||
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);
|
||||
// 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));
|
||||
signal_drive_status();
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if ((m_output1_latch & 0xf0)==0)
|
||||
{
|
||||
logerror("%s: no drive selected, returning 0\n", tag());
|
||||
// No HD and no floppy
|
||||
return 0; /* is that the correct default value? */
|
||||
}
|
||||
// Status byte as defined by HDC9234
|
||||
// +------+------+------+------+------+------+------+------+
|
||||
// | ECC |Index | SeekC| Tr00 | User | WrPrt| Ready|Fault |
|
||||
// +------+------+------+------+------+------+------+------+
|
||||
//
|
||||
// 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.
|
||||
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 )
|
||||
{
|
||||
//int index;
|
||||
int index;
|
||||
switch (offset)
|
||||
{
|
||||
case HDC_INPUT_STATUS:
|
||||
@ -496,18 +522,49 @@ WRITE8_MEMBER( myarc_hfdc_device::auxbus_out )
|
||||
else
|
||||
{
|
||||
// HD selected
|
||||
// index = slog2((data>>4) & 0x0f);
|
||||
// if (index>=0) m_hdc9234->connect_hard_drive(m_harddisk_unit[index-1]);
|
||||
set_bits(m_status_latch, HDC_DS_READY, false);
|
||||
index = slog2((data>>4) & 0x0f);
|
||||
if (index == -1)
|
||||
{
|
||||
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;
|
||||
|
||||
case HDC_OUTPUT_2:
|
||||
// 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);
|
||||
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;
|
||||
}
|
||||
|
||||
// We are pushing the drive status after every output
|
||||
signal_drive_status();
|
||||
}
|
||||
|
||||
enum
|
||||
@ -523,7 +580,7 @@ void myarc_hfdc_device::connect_floppy_unit(int index)
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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]);
|
||||
}
|
||||
set_ready(HFDC_FLOPPY, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
logerror("%s: Disconnect all floppy drives\n", tag());
|
||||
logerror("%s: Unselect all floppy drives\n", tag());
|
||||
// Disconnect current floppy
|
||||
if (m_current_floppy != NULL)
|
||||
{
|
||||
m_current_floppy->setup_index_pulse_cb(floppy_image_device::index_pulse_cb());
|
||||
m_current_floppy = NULL;
|
||||
}
|
||||
set_ready(HFDC_FLOPPY, false);
|
||||
}
|
||||
signal_drive_status();
|
||||
}
|
||||
|
||||
void myarc_hfdc_device::connect_harddisk_unit(int index)
|
||||
{
|
||||
set_ready(HFDC_HARDDISK, false);
|
||||
}
|
||||
|
||||
/*
|
||||
Joins the ready lines from the floppy drives and the hard drives
|
||||
*/
|
||||
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));
|
||||
// if (index < 0)
|
||||
// {
|
||||
m_current_harddisk = NULL;
|
||||
// }
|
||||
signal_drive_status();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -638,6 +689,7 @@ void myarc_hfdc_device::device_start()
|
||||
m_buffer_ram = memregion(BUFFER)->base();
|
||||
m_motor_on_timer = timer_alloc(MOTOR_TIMER);
|
||||
// The HFDC does not use READY; it has on-board RAM for DMA
|
||||
m_current_floppy = NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
m_output1_latch = m_output2_latch = 0;
|
||||
|
||||
m_status_latch = 0x00;
|
||||
|
||||
m_dip = m_irq = CLEAR_LINE;
|
||||
m_see_switches = false;
|
||||
m_CD = 0;
|
||||
@ -742,7 +797,6 @@ MACHINE_CONFIG_FRAGMENT( ti99_hfdc )
|
||||
MCFG_HDC9234_INTRQ_CALLBACK(WRITELINE(myarc_hfdc_device, intrq_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_IN_CALLBACK(READ8(myarc_hfdc_device, auxbus_in))
|
||||
MCFG_HDC9234_DMA_IN_CALLBACK(READ8(myarc_hfdc_device, read_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( dip_w );
|
||||
DECLARE_WRITE8_MEMBER( auxbus_out );
|
||||
DECLARE_READ8_MEMBER( auxbus_in );
|
||||
DECLARE_READ8_MEMBER( read_buffer );
|
||||
DECLARE_WRITE8_MEMBER( write_buffer );
|
||||
|
||||
@ -71,6 +70,9 @@ private:
|
||||
// Connect or disconnect harddisk drives
|
||||
void connect_harddisk_unit(int index);
|
||||
|
||||
// Pushes the drive status to the HDC
|
||||
void signal_drive_status();
|
||||
|
||||
// Motor monoflop (4.23 sec)
|
||||
emu_timer* m_motor_on_timer;
|
||||
|
||||
@ -86,6 +88,9 @@ private:
|
||||
// Currently selected floppy drive
|
||||
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
|
||||
bool m_see_switches;
|
||||
|
||||
|
@ -27,6 +27,28 @@
|
||||
/*
|
||||
Register names of the HDC. The left part is the set of write 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
|
||||
{
|
||||
@ -51,17 +73,32 @@ enum
|
||||
*/
|
||||
enum
|
||||
{
|
||||
ST_INTPEND = 0x80 , // interrupt pending
|
||||
ST_DMAREQ = 0x40 , // DMA request
|
||||
ST_DONE = 0x20 , // command done
|
||||
ST_TERMCOD = 0x18 , // termination code (see below)
|
||||
TC_SUCCESS = 0x00 , // Successful completion
|
||||
TC_RDIDERR = 0x08 , // Error in READ-ID sequence
|
||||
TC_SEEKERR = 0x10 , // Error in SEEK sequence
|
||||
TC_DATAERR = 0x18 , // Error in DATA-TRANSFER seq.
|
||||
ST_RDYCHNG = 0x04 , // ready change
|
||||
ST_OVRUN = 0x02 , // overrun/underrun
|
||||
ST_BADSECT = 0x01 // bad sector
|
||||
ST_INTPEND = 0x80, // interrupt pending
|
||||
ST_DMAREQ = 0x40, // DMA request
|
||||
ST_DONE = 0x20, // command done
|
||||
ST_TERMCOD = 0x18, // termination code (see below)
|
||||
TC_SUCCESS = 0x00, // Successful completion
|
||||
TC_RDIDERR = 0x08, // Error in READ-ID sequence
|
||||
TC_SEEKERR = 0x10, // Error in SEEK sequence
|
||||
TC_DATAERR = 0x18, // Error in DATA-TRANSFER seq.
|
||||
ST_RDYCHNG = 0x04, // ready change
|
||||
ST_OVRUN = 0x02, // overrun/underrun
|
||||
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_dip(*this),
|
||||
m_out_auxbus(*this),
|
||||
m_in_auxbus(*this),
|
||||
m_in_dma(*this),
|
||||
m_out_dma(*this)
|
||||
{
|
||||
@ -189,19 +225,18 @@ void hdc9234_device::process_command(UINT8 opcode)
|
||||
// done when no drive is in use
|
||||
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_output2, OUT2_DRVSEL3I, true); // inverted level
|
||||
sync_latches_out();
|
||||
}
|
||||
else if (opcode >= 0x20 && opcode <= 0x3f)
|
||||
{
|
||||
// DRIVE SELECT
|
||||
if (TRACE_ACT) logerror("%s: drselect command %02x\n", tag(), opcode);
|
||||
drive_select(opcode&0x1f);
|
||||
}
|
||||
else if (opcode >= 0x40 && opcode <= 0x4f)
|
||||
{
|
||||
// SETREGPTR
|
||||
if (TRACE_ACT) logerror("%s: setregptr command %02x\n", tag(), opcode);
|
||||
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
|
||||
// invalid value (only "care should be taken")
|
||||
if (m_register_pointer > 10)
|
||||
@ -210,6 +245,39 @@ void hdc9234_device::process_command(UINT8 opcode)
|
||||
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)
|
||||
@ -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
|
||||
|
||||
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)
|
||||
// and to select the timing parameters
|
||||
m_selected_drive_type = (driveparm>>2) & 0x03;
|
||||
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
|
||||
// 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);
|
||||
|
||||
sync_latches_out();
|
||||
sync_status_in();
|
||||
}
|
||||
|
||||
/*
|
||||
@ -256,37 +327,6 @@ void hdc9234_device::connect_floppy_drive(floppy_image_device* 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
|
||||
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.
|
||||
*/
|
||||
@ -368,7 +502,6 @@ void hdc9234_device::device_start()
|
||||
m_out_intrq.resolve_safe();
|
||||
m_out_dip.resolve_safe();
|
||||
m_out_auxbus.resolve_safe();
|
||||
m_in_auxbus.resolve_safe(0);
|
||||
m_out_dma.resolve_safe();
|
||||
m_in_dma.resolve_safe(0);
|
||||
|
||||
@ -381,6 +514,14 @@ void hdc9234_device::device_reset()
|
||||
m_selected_drive_type = 0;
|
||||
m_head_load_delay_enable = false;
|
||||
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>;
|
||||
|
@ -55,10 +55,6 @@ enum
|
||||
#define MCFG_HDC9234_AUXBUS_OUT_CALLBACK(_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.
|
||||
Note that the address must be set and automatically increased
|
||||
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_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_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_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
|
||||
// using the user-programmable outputs. Hence, the connection
|
||||
// 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_dip; // DMA in progress line
|
||||
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_write8 m_out_dma; // DMA write access to the cache buffer
|
||||
|
||||
@ -118,6 +117,10 @@ private:
|
||||
// Command processing
|
||||
void process_command(UINT8 opcode);
|
||||
|
||||
// Command is done
|
||||
void set_command_done(int flags);
|
||||
void set_command_done();
|
||||
|
||||
// Recent command.
|
||||
UINT8 m_command;
|
||||
|
||||
@ -133,9 +136,6 @@ private:
|
||||
// internal register OUTPUT2
|
||||
UINT8 m_output2;
|
||||
|
||||
// Sample the values of the incoming status bits
|
||||
void sync_status_in();
|
||||
|
||||
// Write the output registers to the latches
|
||||
void sync_latches_out();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user