mirror of
https://github.com/holub/mame
synced 2025-04-26 10:13:37 +03:00
ti99_8: OSO implementation completed; pending tests (nw)
This commit is contained in:
parent
8593fdceab
commit
46958737cf
@ -2243,6 +2243,15 @@ enum
|
|||||||
CR7 = 0x01
|
CR7 = 0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Line */
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
LINE_HSK = 0x10,
|
||||||
|
LINE_BAV = 0x04,
|
||||||
|
LINE_BIT32 = 0xc0,
|
||||||
|
LINE_BIT10 = 0x03
|
||||||
|
};
|
||||||
|
|
||||||
oso_device::oso_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
oso_device::oso_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
||||||
bus::hexbus::hexbus_chained_device(mconfig, TI99_OSO, tag, owner, clock),
|
bus::hexbus::hexbus_chained_device(mconfig, TI99_OSO, tag, owner, clock),
|
||||||
m_int(*this),
|
m_int(*this),
|
||||||
@ -2250,17 +2259,16 @@ oso_device::oso_device(const machine_config &mconfig, const char *tag, device_t
|
|||||||
m_status(0xff),
|
m_status(0xff),
|
||||||
m_control(0),
|
m_control(0),
|
||||||
m_xmit(0), m_lasthxvalue(0x01),
|
m_xmit(0), m_lasthxvalue(0x01),
|
||||||
m_clkcount(0),
|
m_bav(false), m_sbav(false), m_sbavold(true), m_bavhold(false),
|
||||||
m_sbav(false), m_sbavold(true),
|
m_hsk(false), m_shsk(false), m_shskold(true), m_hskhold(false),
|
||||||
m_bav(false), m_bavhold(false),
|
|
||||||
m_shsk(false), m_shskold(true),
|
|
||||||
m_hsk(false), m_hskhold(false),
|
|
||||||
m_wq1(false), m_wq1old(true), m_wq2(false), m_wq2old(true),
|
m_wq1(false), m_wq1old(true), m_wq2(false), m_wq2old(true),
|
||||||
m_wnp(false),
|
m_wnp(false), m_wbusyold(false), m_sendbyte(false),
|
||||||
m_wbusy(false), m_wbusyold(false),
|
m_wrset(false), m_counting(false), m_clkcount(0),
|
||||||
m_sendbyte(false),
|
m_rq1(false), m_rq2(false), m_rq2old(true),
|
||||||
m_wrst(false), m_counting(false),
|
m_rnib(false), m_rnibcold(false),
|
||||||
m_rq2(false), m_rq2old(true)
|
m_rdset(false), m_rdsetold(true),
|
||||||
|
m_msns(false), m_lsns(false),
|
||||||
|
m_rdend(false), m_byteavailable(false)
|
||||||
{
|
{
|
||||||
(void)m_shskold;
|
(void)m_shskold;
|
||||||
m_hexbus_inbound = nullptr;
|
m_hexbus_inbound = nullptr;
|
||||||
@ -2277,6 +2285,8 @@ READ8_MEMBER( oso_device::read )
|
|||||||
// read 5FF8: read data register
|
// read 5FF8: read data register
|
||||||
if (TRACE_OSO) logerror("Read data register = %02x\n", value);
|
if (TRACE_OSO) logerror("Read data register = %02x\n", value);
|
||||||
value = m_data;
|
value = m_data;
|
||||||
|
// Release the handshake
|
||||||
|
m_byteavailable = false;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
// read 5FFA: read status register
|
// read 5FFA: read status register
|
||||||
@ -2314,9 +2324,8 @@ WRITE8_MEMBER( oso_device::write )
|
|||||||
m_sendbyte = true;
|
m_sendbyte = true;
|
||||||
if (!m_wq1)
|
if (!m_wq1)
|
||||||
{
|
{
|
||||||
m_wbusy = true;
|
|
||||||
m_wbusyold = true;
|
m_wbusyold = true;
|
||||||
set_status(WBUSY, m_wbusy);
|
set_status(WBUSY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_xmit = data;
|
m_xmit = data;
|
||||||
@ -2327,12 +2336,16 @@ WRITE8_MEMBER( oso_device::write )
|
|||||||
data, (data & WIEN)? 1:0, (data & RIEN)? 1:0, (data&BAVIAEN)? 1:0, (data&BAVAIEN)? 1:0,
|
data, (data & WIEN)? 1:0, (data & RIEN)? 1:0, (data&BAVIAEN)? 1:0, (data&BAVAIEN)? 1:0,
|
||||||
(data & BAVC)? 1:0, (data & WEN)? 1:0, (data & REN)? 1:0);
|
(data & BAVC)? 1:0, (data & WEN)? 1:0, (data & REN)? 1:0);
|
||||||
m_control = data;
|
m_control = data;
|
||||||
|
|
||||||
|
// Reset some flipflops in the write/read timing section
|
||||||
if (!control_bit(WEN))
|
if (!control_bit(WEN))
|
||||||
{
|
{
|
||||||
// Reset some flipflops in the write timing section
|
m_wq1 = m_wq2 = m_wrset = false;
|
||||||
m_wq1 = m_wq2 = m_wrst = false;
|
}
|
||||||
|
if (!control_bit(REN))
|
||||||
|
{
|
||||||
|
m_rq1 = m_rq2 = m_rdset = false;
|
||||||
}
|
}
|
||||||
m_bav = control_bit(BAVC);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// write 5FFC, 5FFE: undefined
|
// write 5FFC, 5FFE: undefined
|
||||||
@ -2344,12 +2357,22 @@ WRITE8_MEMBER( oso_device::write )
|
|||||||
void oso_device::clear_int_status()
|
void oso_device::clear_int_status()
|
||||||
{
|
{
|
||||||
m_status &= ~(HSKWT | HSKRD | BAVIAS | BAVAIS);
|
m_status &= ~(HSKWT | HSKRD | BAVIAS | BAVAIS);
|
||||||
|
m_rdend = false;
|
||||||
m_int(CLEAR_LINE);
|
m_int(CLEAR_LINE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void oso_device::hexbus_value_changed(uint8_t data)
|
void oso_device::hexbus_value_changed(uint8_t data)
|
||||||
{
|
{
|
||||||
if (TRACE_OSO) logerror("Hexbus value changed to %02x\n", data);
|
if (TRACE_OSO) logerror("Hexbus value changed to %02x\n", data);
|
||||||
|
|
||||||
|
m_bav = ((data & LINE_BAV)==0) | control_bit(BAVC);
|
||||||
|
|
||||||
|
m_hsk = (data & LINE_HSK)==0;
|
||||||
|
int nibble = ((data & LINE_BIT32)>>4) | (data & LINE_BIT10);
|
||||||
|
if (m_msns)
|
||||||
|
m_data = (m_data & 0x0f) | (nibble<<4);
|
||||||
|
if (m_lsns)
|
||||||
|
m_data = (m_data & 0xf0) | nibble;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2363,13 +2386,21 @@ WRITE_LINE_MEMBER( oso_device::clock_in )
|
|||||||
// When BAV/HSK is 0/1 for two rising edges of Phi3*, SBAV/SHSK goes to
|
// When BAV/HSK is 0/1 for two rising edges of Phi3*, SBAV/SHSK goes to
|
||||||
// 0/1 at the following falling edge of Phi3*.
|
// 0/1 at the following falling edge of Phi3*.
|
||||||
// Page 5
|
// Page 5
|
||||||
m_sbav = m_bavhold && m_bav;
|
m_sbav = m_bavhold && m_bav; // could mean "stable BAV"
|
||||||
m_bavhold = m_bav;
|
m_bavhold = m_bav;
|
||||||
m_shsk = m_hskhold && m_hsk;
|
m_shsk = m_hskhold && m_hsk;
|
||||||
m_hskhold = m_hsk;
|
m_hskhold = m_hsk;
|
||||||
set_status(SHSK, m_shsk);
|
set_status(SHSK, m_shsk);
|
||||||
set_status(SBAV, m_sbav);
|
set_status(SBAV, m_sbav);
|
||||||
|
|
||||||
|
// Raising edge of SBAV*
|
||||||
|
if (m_sbav == true && m_sbavold == false)
|
||||||
|
set_status(BAVIAS, true);
|
||||||
|
// Falling edge of SBAV*
|
||||||
|
if (m_sbav == false && m_sbavold == true)
|
||||||
|
set_status(BAVAIS, true);
|
||||||
|
m_sbavold = m_sbav;
|
||||||
|
|
||||||
// Implement the write timing logic
|
// Implement the write timing logic
|
||||||
// This subcircuit in the OSO chip autonomously runs the Hexbus
|
// This subcircuit in the OSO chip autonomously runs the Hexbus
|
||||||
// protocol. After loading a byte into the transmit register, it sends
|
// protocol. After loading a byte into the transmit register, it sends
|
||||||
@ -2382,11 +2413,11 @@ WRITE_LINE_MEMBER( oso_device::clock_in )
|
|||||||
|
|
||||||
if (control_bit(WEN)) // Nothing happens without WEN
|
if (control_bit(WEN)) // Nothing happens without WEN
|
||||||
{
|
{
|
||||||
if (TRACE_OSO) if (!m_wrst && m_sendbyte) logerror("Starting write process\n");
|
if (TRACE_OSO) if (!m_wrset && m_sendbyte) logerror("Starting write process\n");
|
||||||
// Page 3: Write timing
|
// Page 3: Write timing
|
||||||
// Note: First pass counts to 30, second to 31
|
// Note: First pass counts to 30, second to 31
|
||||||
bool cnt30 = ((m_clkcount & 0x1e) == 30);
|
bool cnt30 = ((m_clkcount & 0x1e) == 30);
|
||||||
bool cont = (m_wrst && !m_wq2 && !m_wq1) || (cnt30 && m_wq2 && !m_wq1)
|
bool cont = (m_wrset && !m_wq2 && !m_wq1) || (cnt30 && m_wq2 && !m_wq1)
|
||||||
|| (cnt30 && !m_wq2 && m_wq1) || (m_shsk && m_wq2 && m_wq1);
|
|| (cnt30 && !m_wq2 && m_wq1) || (m_shsk && m_wq2 && m_wq1);
|
||||||
|
|
||||||
bool jwq1 = cont && m_wq2;
|
bool jwq1 = cont && m_wq2;
|
||||||
@ -2401,37 +2432,17 @@ WRITE_LINE_MEMBER( oso_device::clock_in )
|
|||||||
if (m_wq1 == true)
|
if (m_wq1 == true)
|
||||||
m_sendbyte = false;
|
m_sendbyte = false;
|
||||||
|
|
||||||
|
// logerror("sendbyte=%d, wq1=%d, wq2=%d, jwq1=%d, kwq1=%d, jwq2=%d, kwq2=%d, shsk=%d\n", m_sendbyte, m_wq1, m_wq2, jwq1, kwq1, jwq2, kwq2, m_shsk);
|
||||||
// WBUSY is asserted on byte load, during phase 1, and phase 2.
|
// WBUSY is asserted on byte load, during phase 1, and phase 2.
|
||||||
m_wbusy = m_sendbyte || m_wq1 || m_wq2;
|
bool wbusy = m_sendbyte || m_wq1 || m_wq2;
|
||||||
|
|
||||||
// Set status bits and raise interrupt (p. 4)
|
// Set status bits and raise interrupt (p. 4)
|
||||||
set_status(WBUSY, m_wbusy);
|
set_status(WBUSY, wbusy);
|
||||||
if (m_wbusy != m_wbusyold)
|
|
||||||
{
|
|
||||||
// Raising edge of wbusy*
|
|
||||||
if (!m_wbusy) set_status(HSKWT, !m_wbusy);
|
|
||||||
m_wbusyold = m_wbusy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_rq2 != m_rq2old)
|
// Raising edge of wbusy*
|
||||||
{
|
if (m_wbusyold == true && wbusy == false)
|
||||||
// Raising edge of RQ2*
|
set_status(HSKWT, true);
|
||||||
if (!m_rq2)
|
m_wbusyold = wbusy;
|
||||||
{
|
|
||||||
set_status(HSKRD, m_rq2);
|
|
||||||
}
|
|
||||||
m_wbusyold = m_wbusy;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_sbav != m_sbavold)
|
|
||||||
{
|
|
||||||
// Raising edge of SBAV -> BAVIA
|
|
||||||
// Falling edge of SBAV -> BAVAI
|
|
||||||
if (m_sbav)
|
|
||||||
set_status(BAVIAS, m_sbav);
|
|
||||||
else
|
|
||||||
set_status(BAVAIS, !m_sbav);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Operate flipflops
|
// Operate flipflops
|
||||||
// Write phases
|
// Write phases
|
||||||
@ -2462,26 +2473,80 @@ WRITE_LINE_MEMBER( oso_device::clock_in )
|
|||||||
}
|
}
|
||||||
m_wq1old = m_wq1;
|
m_wq1old = m_wq1;
|
||||||
|
|
||||||
// Set HSK
|
|
||||||
m_hsk = !m_wq1 && m_wq2;
|
|
||||||
|
|
||||||
// Reset WNP if phases are done
|
// Reset WNP if phases are done
|
||||||
if (!m_wq2 && !m_wq1)
|
if (!m_wq2 && !m_wq1)
|
||||||
{
|
{
|
||||||
m_wnp = false;
|
m_wnp = false;
|
||||||
}
|
}
|
||||||
update_hexbus();
|
}
|
||||||
|
|
||||||
|
// This is the reading behavior. In this case, the master (this
|
||||||
|
// component) pulls down BAV*, then the slave sets the data lines
|
||||||
|
// with the back nibble, pulls down HSK*, then releases HSK*,
|
||||||
|
// puts the front nibble on the data lines, pulls down HSK* again,
|
||||||
|
// releases it, and this continues until the master releases BAV*
|
||||||
|
|
||||||
|
if (control_bit(REN))
|
||||||
|
{
|
||||||
|
bool rbusy = m_rq1 || m_rq2;
|
||||||
|
set_status(RBUSY, rbusy);
|
||||||
|
|
||||||
|
// Flipflop resets
|
||||||
|
if (!rbusy) m_rnib = false;
|
||||||
|
if (m_rq2) m_rdset = false;
|
||||||
|
|
||||||
|
bool rdsetin = !control_bit(WBUSY) && m_sbav && m_shsk;
|
||||||
|
bool next = (m_rdset && !m_rq2) || (m_shsk && m_rq2);
|
||||||
|
bool drq1 = (next && m_rq2) || (m_rq2 && m_rq1 && !m_rnib);
|
||||||
|
bool jrq2 = next && !m_rq1;
|
||||||
|
bool krq2 = m_rq1 && !m_rnib;
|
||||||
|
m_msns = m_rnib && !m_rq1 && m_rq2;
|
||||||
|
m_lsns = !m_rnib && !m_rq1 && m_rq2;
|
||||||
|
bool rnibc = m_rq1;
|
||||||
|
|
||||||
|
// Next state
|
||||||
|
if (!m_rdsetold && rdsetin) m_rdset = true; // raising edge
|
||||||
|
m_rdsetold = rdsetin;
|
||||||
|
m_rq1 = drq1;
|
||||||
|
|
||||||
|
if (jrq2)
|
||||||
|
{
|
||||||
|
if (!krq2) m_rq2 = !m_rq2;
|
||||||
|
else m_rq2 = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (!krq2) m_rq2 = false;
|
||||||
|
|
||||||
|
if (m_rnibcold == false && rnibc == true) m_rnib = !m_rnib; // raising edge
|
||||||
|
m_rnibcold = rnibc;
|
||||||
|
|
||||||
|
// Raising edge of RQ2*
|
||||||
|
if (m_rq2old == true && m_rq2 == false)
|
||||||
|
{
|
||||||
|
set_status(HSKRD, true);
|
||||||
|
m_rdend = true;
|
||||||
|
}
|
||||||
|
m_rq2old = m_rq2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_wq1 = m_wq2 = m_wrst = m_counting = false;
|
m_byteavailable = false;
|
||||||
m_clkcount = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handshake control
|
||||||
|
// Set HSK (Page 6, RHSUS*)
|
||||||
|
bool hskwrite = !m_wq1 && m_wq2;
|
||||||
|
if (m_rdend) m_byteavailable = true;
|
||||||
|
|
||||||
|
// We can simplify this to a single flag because the CPU read operation
|
||||||
|
// is atomic here (starts and immediately terminates)
|
||||||
|
m_hsk = hskwrite || m_byteavailable;
|
||||||
|
update_hexbus();
|
||||||
}
|
}
|
||||||
// Actions that occur for Phi3=0
|
// Actions that occur for Phi3=0
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_wrst = m_sendbyte;
|
m_wrset = m_sendbyte;
|
||||||
// Only count when one phase is active
|
// Only count when one phase is active
|
||||||
m_counting = !(m_wq1==m_wq2);
|
m_counting = !(m_wq1==m_wq2);
|
||||||
|
|
||||||
@ -2491,6 +2556,17 @@ WRITE_LINE_MEMBER( oso_device::clock_in )
|
|||||||
m_clkcount = 0; // Reset when not counting
|
m_clkcount = 0; // Reset when not counting
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flipflop resets (not related to clock)
|
||||||
|
if (!control_bit(WEN))
|
||||||
|
{
|
||||||
|
m_wq1 = m_wq2 = m_wrset = m_counting = false;
|
||||||
|
m_clkcount = 0;
|
||||||
|
}
|
||||||
|
if (!control_bit(REN))
|
||||||
|
{
|
||||||
|
m_rq1 = m_rq2 = m_rdset = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Show some lines in log
|
// Show some lines in log
|
||||||
if (TRACE_OSO) {
|
if (TRACE_OSO) {
|
||||||
if (m_sbav != m_sbavold) {
|
if (m_sbav != m_sbavold) {
|
||||||
@ -2517,7 +2593,7 @@ void oso_device::update_hexbus()
|
|||||||
|
|
||||||
value = ((m_xmit & 0x0c)<<4) | (m_xmit & 0x03);
|
value = ((m_xmit & 0x0c)<<4) | (m_xmit & 0x03);
|
||||||
if (!m_hsk) value |= 0x10;
|
if (!m_hsk) value |= 0x10;
|
||||||
if (!m_bav) value |= 0x04;
|
if (!control_bit(BAVC)) value |= 0x04;
|
||||||
if (value != m_lasthxvalue)
|
if (value != m_lasthxvalue)
|
||||||
{
|
{
|
||||||
if (TRACE_OSO) logerror("Set hexbus = %02x (BAV*=%d, HSK*=%d, data=%01x)\n", value, (value & 0x04)? 1:0, (value & 0x10)? 1:0, ((value>>4)&0x0c) | (value&0x03));
|
if (TRACE_OSO) logerror("Set hexbus = %02x (BAV*=%d, HSK*=%d, data=%01x)\n", value, (value & 0x04)? 1:0, (value & 0x10)? 1:0, ((value>>4)&0x0c) | (value&0x03));
|
||||||
|
@ -446,41 +446,52 @@ private:
|
|||||||
void set_status(int bit, bool set) { m_status = (set)? (m_status | bit) : (m_status & ~bit); }
|
void set_status(int bit, bool set) { m_status = (set)? (m_status | bit) : (m_status & ~bit); }
|
||||||
void update_hexbus();
|
void update_hexbus();
|
||||||
|
|
||||||
|
// Registers
|
||||||
uint8_t m_data;
|
uint8_t m_data;
|
||||||
uint8_t m_status;
|
uint8_t m_status;
|
||||||
uint8_t m_control;
|
uint8_t m_control;
|
||||||
uint8_t m_xmit;
|
uint8_t m_xmit;
|
||||||
|
|
||||||
|
// Last hexbus value; when the new value is different, send it via the hexbus
|
||||||
uint8_t m_lasthxvalue;
|
uint8_t m_lasthxvalue;
|
||||||
|
|
||||||
int m_clkcount;
|
bool m_bav; // Bus available; when true, a communication is about to happen
|
||||||
|
bool m_sbav; // Stable BAV; the BAV signal is true for two clock cycles
|
||||||
|
bool m_sbavold; // Old SBAV state
|
||||||
|
bool m_bavhold; // For computing the SBAV signal
|
||||||
|
|
||||||
bool m_sbav;
|
bool m_hsk; // Handshake line; when true, a bus member needs more time to process the message
|
||||||
bool m_sbavold;
|
bool m_shsk; // Stable HSK
|
||||||
bool m_bav;
|
bool m_shskold; // see above
|
||||||
bool m_bavhold;
|
bool m_hskhold; // see above
|
||||||
|
|
||||||
bool m_shsk;
|
// Page 3 in OSO schematics: Write timing
|
||||||
bool m_shskold;
|
bool m_wq1; // Flipflop 1
|
||||||
bool m_hsk;
|
bool m_wq1old; // Previous state
|
||||||
bool m_hskhold;
|
bool m_wq2; // Flipflop 2
|
||||||
|
bool m_wq2old; // Previous state
|
||||||
|
bool m_wnp; // Write nibble selection; true means upper 4 bits
|
||||||
|
bool m_wbusyold; // Old state of the WBUSY line
|
||||||
|
bool m_sendbyte; // Byte has been loaded into the XMIT register
|
||||||
|
bool m_wrset; // Start sending
|
||||||
|
bool m_counting; // Counter running
|
||||||
|
int m_clkcount; // Counter for 30 cycles
|
||||||
|
|
||||||
// Page 3 in OSO schematics
|
// Page 4 in OSO schematics: Read timing
|
||||||
bool m_wq1;
|
bool m_rq1; // Flipflop 1
|
||||||
bool m_wq1old;
|
bool m_rq2; // Flipflop 2
|
||||||
bool m_wq2;
|
bool m_rq2old; // Previous state
|
||||||
bool m_wq2old;
|
bool m_rnib; // Read nibble, true means upper 4 bits
|
||||||
bool m_wnp;
|
bool m_rnibcold; // Needed to detect the raising edge
|
||||||
bool m_wbusy;
|
bool m_rdset; // Start reading
|
||||||
bool m_wbusyold;
|
bool m_rdsetold; // Old state
|
||||||
bool m_sendbyte;
|
bool m_msns; // Upper 4 bits
|
||||||
|
bool m_lsns; // Lower 4 bits
|
||||||
|
|
||||||
bool m_wrst;
|
bool m_rdend; // Read completed
|
||||||
|
|
||||||
bool m_counting;
|
// Page 6
|
||||||
|
bool m_byteavailable; // Needed to assert the HSK line until the CPU has read the byte
|
||||||
bool m_rq2;
|
|
||||||
bool m_rq2old;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class mainboard8_device : public device_t
|
class mainboard8_device : public device_t
|
||||||
|
Loading…
Reference in New Issue
Block a user