(MESS) ti99: Fixing the TI floppy controller; still issues. (nw)

This commit is contained in:
Michael Zapf 2013-12-11 23:49:42 +00:00
parent 175ef51ec4
commit 55c1991174
2 changed files with 134 additions and 90 deletions

View File

@ -15,14 +15,33 @@
#include "emu.h"
#include "peribox.h"
#include "ti_fdc.h"
#include "machine/wd17xx.h"
#include "formats/ti99_dsk.h"
#define LOG logerror
#define VERBOSE 1
// ----------------------------------
// Flags for debugging
#define fdc_IRQ 1
#define fdc_DRQ 2
// Show read and write accesses
#define TRACE_RW 0
// Show CRU bit accesses
#define TRACE_CRU 0
// Show ready line activity
#define TRACE_READY 0
// Show detailed signal activity
#define TRACE_SIGNALS 0
// Show sector data
#define TRACE_DATA 0
// Show address bus operations
#define TRACE_ADDRESS 0
// Show address bus operations
#define TRACE_MOTOR 0
// ----------------------------------
#define TI_FDC_TAG "ti_dssd_controller"
@ -39,9 +58,8 @@ const wd17xx_interface ti_wd17xx_interface =
};
ti_fdc_device::ti_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: ti_expansion_card_device(mconfig, TI99_FDC, "TI-99 Standard DSSD Floppy Controller", tag, owner, clock, "ti99_fdc", __FILE__)
{
}
: ti_expansion_card_device(mconfig, TI99_FDC, "TI-99 Standard DSSD Floppy Controller", tag, owner, clock, "ti99_fdc", __FILE__),
m_fd1771(*this, FDC_TAG) { }
/*
callback called at the end of DVENA pulse
@ -49,48 +67,85 @@ ti_fdc_device::ti_fdc_device(const machine_config &mconfig, const char *tag, dev
void ti_fdc_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
m_DVENA = CLEAR_LINE;
handle_hold();
if (TRACE_MOTOR) logerror("tifdc: Motor off\n");
set_ready_line();
}
/*
Operate the wait state logic.
*/
void ti_fdc_device::set_ready_line()
{
// This is the wait state logic
if (TRACE_SIGNALS) logerror("tifdc: address=%04x, DRQ=%d, INTRQ=%d, MOTOR=%d\n", m_address & 0xffff, m_DRQ, m_IRQ, m_DVENA);
line_state nready = (m_WDsel && // Are we accessing 5ffx?
m_WAITena && // and the wait state generation is active (SBO 2)
(m_DRQ==CLEAR_LINE) && // and we are waiting for a byte
(m_IRQ==CLEAR_LINE) && // and there is no interrupt yet
(m_DVENA==ASSERT_LINE) // and the motor is turning?
)? ASSERT_LINE : CLEAR_LINE; // In that case, clear READY and thus trigger wait states
if (TRACE_READY) if (nready==ASSERT_LINE) logerror("tifdc: READY line = %d\n", (nready==CLEAR_LINE)? 1:0);
m_slot->set_ready((nready==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE);
}
SETADDRESS_DBIN_MEMBER( ti_fdc_device::setaddress_dbin )
{
// Selection login in the PAL and some circuits on the board
// Is the card being selected?
m_address = offset;
m_inDsrArea = ((m_address & m_select_mask)==m_select_value);
if (!m_inDsrArea) return;
if (TRACE_ADDRESS) logerror("tifdc: set address = %04x\n", offset & 0xffff);
// Is the WD chip on the card being selected?
m_WDsel = m_inDsrArea && ((m_address & 0x1ff0)==0x1ff0);
// Clear or assert the outgoing READY line
set_ready_line();
}
READ8Z_MEMBER(ti_fdc_device::readz)
{
if (m_selected)
if (m_inDsrArea && m_selected)
{
if ((offset & m_select_mask)==m_select_value)
{
// only use the even addresses from 1ff0 to 1ff6.
// Note that data is inverted.
// 0101 1111 1111 0xx0
UINT8 reply = 0;
// only use the even addresses from 1ff0 to 1ff6.
// Note that data is inverted.
// 0101 1111 1111 0xx0
UINT8 reply = 0;
if ((offset & 0x1ff9)==0x1ff0)
if (m_WDsel && ((m_address & 1)==0))
{
if (!space.debugger_access()) reply = wd17xx_r(m_fd1771, space, (offset >> 1)&0x03);
if (TRACE_DATA)
{
if (!space.debugger_access()) reply = wd17xx_r(m_controller, space, (offset >> 1)&0x03);
if ((m_address & 0xffff)==0x5ff6) logerror("%02x ", ~reply & 0xff);
else logerror("\n%04x: %02x", m_address&0xffff, ~reply & 0xff);
}
else
{
reply = m_dsrrom[offset & 0x1fff];
}
*value = reply;
if (VERBOSE>5) LOG("ti_fdc: %04x -> %02x\n", offset & 0xffff, *value);
}
else
{
reply = m_dsrrom[m_address & 0x1fff];
}
*value = reply;
if (TRACE_RW) logerror("ti_fdc: %04x -> %02x\n", offset & 0xffff, *value);
}
}
WRITE8_MEMBER(ti_fdc_device::write)
{
if (m_selected)
if (m_inDsrArea && m_selected)
{
if ((offset & m_select_mask)==m_select_value)
if (TRACE_RW) logerror("ti_fdc: %04x <- %02x\n", offset & 0xffff, ~data & 0xff);
// only use the even addresses from 1ff8 to 1ffe.
// Note that data is inverted.
// 0101 1111 1111 1xx0
if (m_WDsel && ((m_address & 9)==8))
{
if (VERBOSE>5) LOG("ti_fdc: %04x <- %02x\n", offset & 0xffff, data);
// only use the even addresses from 1ff8 to 1ffe.
// Note that data is inverted.
// 0101 1111 1111 1xx0
if ((offset & 0x1ff9)==0x1ff8)
{
if (!space.debugger_access()) wd17xx_w(m_controller, space, (offset >> 1)&0x03, data);
}
if (!space.debugger_access()) wd17xx_w(m_fd1771, space, (offset >> 1)&0x03, data);
}
}
}
@ -121,6 +176,7 @@ READ8Z_MEMBER(ti_fdc_device::crureadz)
if (m_SIDSEL) reply |= 0x80;
}
*value = reply;
if (TRACE_CRU) logerror("tifdc: Read CRU = %02x\n", *value);
}
}
@ -136,17 +192,19 @@ WRITE8_MEMBER(ti_fdc_device::cruwrite)
case 0:
/* (De)select the card. Indicated by a LED on the board. */
m_selected = (data!=0);
if (VERBOSE>4) LOG("ti_fdc: Map DSR = %d\n", m_selected);
if (TRACE_CRU) logerror("tifdc: Map DSR (bit 0) = %d\n", m_selected);
break;
case 1:
/* Activate motor */
if (data && !m_strobe_motor)
if (data==1 && m_lastval==0)
{ /* on rising edge, set motor_running for 4.23s */
if (TRACE_CRU) logerror("tifdc: trigger motor (bit 1)\n");
m_DVENA = ASSERT_LINE;
handle_hold();
if (TRACE_MOTOR) logerror("tifdc: motor on\n");
set_ready_line();
m_motor_on_timer->adjust(attotime::from_msec(4230));
}
m_strobe_motor = (data!=0);
m_lastval = data;
break;
case 2:
@ -155,13 +213,13 @@ WRITE8_MEMBER(ti_fdc_device::cruwrite)
// 1: TMS9900 is stopped until IRQ or DRQ are set
// OR the motor stops rotating - rotates for 4.23s after write
// to CRU bit 1
// This is not emulated and could cause the TI99 to lock up
m_hold = (data != 0);
handle_hold();
m_WAITena = (data != 0);
if (TRACE_CRU) logerror("tifdc: arm wait state logic (bit 2) = %d\n", data);
break;
case 3:
/* Load disk heads (HLT pin) (bit 3). Not implemented. */
if (TRACE_CRU) logerror("tifdc: set head load (bit 3) = %d\n", data);
break;
case 4:
@ -169,17 +227,17 @@ WRITE8_MEMBER(ti_fdc_device::cruwrite)
case 6:
/* Select drive X (bits 4-6) */
drive = bit-4; /* drive # (0-2) */
if (TRACE_CRU) logerror("tifdc: set drive (bit %d) = %d\n", bit, data);
drivebit = 1<<drive;
if (data)
if (data != 0)
{
if ((m_DSEL & drivebit)!=0) /* select drive */
if ((m_DSEL & drivebit) == 0) /* select drive */
{
if (m_DSEL != 0)
LOG("ti_fdc: Multiple drives selected, %02x\n", m_DSEL);
logerror("tifdc: Multiple drives selected, %02x\n", m_DSEL);
m_DSEL |= drivebit;
wd17xx_set_drive(m_controller, drive);
/*wd17xx_set_side(DSKside);*/
wd17xx_set_drive(m_fd1771, drive);
}
}
else
@ -189,34 +247,13 @@ WRITE8_MEMBER(ti_fdc_device::cruwrite)
case 7:
/* Select side of disk (bit 7) */
m_SIDSEL = data;
wd17xx_set_side(m_controller, data);
if (TRACE_CRU) logerror("tifdc: set side (bit 7) = %d\n", data);
wd17xx_set_side(m_fd1771, data);
break;
}
}
}
/*
Call this when the state of DSKhold or DRQ/IRQ or DVENA change
Emulation is faulty because the CPU is actually stopped in the midst of
instruction, at the end of the memory access
TODO: This has to be replaced by the proper READY handling that is already
prepared here. (Requires READY handling by the CPU.)
*/
void ti_fdc_device::handle_hold()
{
line_state state;
if (m_hold && !m_DRQ && !m_IRQ && (m_DVENA==ASSERT_LINE))
state = ASSERT_LINE;
else
state = CLEAR_LINE;
m_slot->set_ready((state==CLEAR_LINE)? ASSERT_LINE : CLEAR_LINE);
// machine().device("maincpu")->execute().set_input_line(INPUT_LINE_HALT, state);
}
/*
Resets the drive geometry. This is required because the heuristic of
the default implementation sets the drive geometry to the geometry
@ -243,40 +280,37 @@ void ti_fdc_device::set_all_geometries(floppy_type_t type)
*/
WRITE_LINE_MEMBER( ti_fdc_device::intrq_w )
{
if (VERBOSE>8) LOG("ti_fdc: set irq = %02x\n", state);
m_IRQ = (state==ASSERT_LINE);
if (TRACE_SIGNALS) logerror("ti_fdc: set irq = %d\n", state);
m_IRQ = (line_state)state;
// Note that INTB is actually not used in the TI-99 family. But the
// controller asserts the line nevertheless, probably intended for
// use in another planned TI system
m_slot->set_intb(state);
handle_hold();
set_ready_line();
}
WRITE_LINE_MEMBER( ti_fdc_device::drq_w )
{
if (VERBOSE>8) LOG("ti_fdc: set drq = %02x\n", state);
m_DRQ = (state == ASSERT_LINE);
handle_hold();
if (TRACE_SIGNALS) logerror("ti_fdc: set drq = %d\n", state);
m_DRQ = (line_state)state;
set_ready_line();
}
void ti_fdc_device::device_start(void)
{
if (VERBOSE>5) LOG("ti_fdc: TI FDC start\n");
logerror("ti_fdc: TI FDC start\n");
m_dsrrom = memregion(DSRROM)->base();
m_motor_on_timer = timer_alloc(MOTOR_TIMER);
m_controller = subdevice(FDC_TAG);
m_cru_base = 0x1100;
}
void ti_fdc_device::device_reset(void)
{
if (VERBOSE>5) LOG("ti_fdc: TI FDC reset\n");
logerror("ti_fdc: TI FDC reset\n");
m_DSEL = 0;
m_SIDSEL = 0;
m_DVENA = CLEAR_LINE;
m_strobe_motor = false;
m_lastval = 0;
if (m_genmod)
{
m_select_mask = 0x1fe000;
@ -287,9 +321,9 @@ void ti_fdc_device::device_reset(void)
m_select_mask = 0x7e000;
m_select_value = 0x74000;
}
m_DRQ = false;
m_IRQ = false;
m_hold = false;
m_DRQ = CLEAR_LINE;
m_IRQ = CLEAR_LINE;
m_WAITena = false;
m_selected = false;
ti99_set_80_track_drives(FALSE);

View File

@ -16,6 +16,7 @@
#define __TIFDC__
#include "ti99defs.h"
#include "machine/wd17xx.h"
#include "imagedev/flopdrv.h"
extern const device_type TI99_FDC;
@ -26,6 +27,7 @@ public:
ti_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
DECLARE_READ8Z_MEMBER(readz);
DECLARE_WRITE8_MEMBER(write);
DECLARE_SETADDRESS_DBIN_MEMBER(setaddress_dbin);
DECLARE_WRITE_LINE_MEMBER( intrq_w );
DECLARE_WRITE_LINE_MEMBER( drq_w );
@ -41,22 +43,30 @@ protected:
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
private:
void handle_hold(void);
void set_ready_line();
void set_all_geometries(floppy_type_t type);
void set_geometry(device_t *drive, floppy_type_t type);
// Recent address
int m_address;
// Holds the status of the DRQ and IRQ lines.
bool m_DRQ, m_IRQ;
line_state m_DRQ, m_IRQ;
// When TRUE, keeps DVENA high.
bool m_strobe_motor;
// Needed for triggering the motor monoflop
UINT8 m_lastval;
// Signal DVENA. When TRUE, makes some drive turning.
line_state m_DVENA;
// When TRUE the CPU is halted while DRQ/IRQ are true.
bool m_hold;
bool m_WAITena;
// WD chip selected
bool m_WDsel;
// Set when address is in card area
bool m_inDsrArea;
// Indicates which drive has been selected. Values are 0, 1, 2, and 4.
// 000 = no drive
@ -72,7 +82,7 @@ private:
emu_timer* m_motor_on_timer;
// Link to the FDC1771 controller on the board.
device_t* m_controller;
required_device<fd1771_device> m_fd1771;
// DSR ROM
UINT8* m_dsrrom;