mirror of
https://github.com/holub/mame
synced 2025-04-20 15:32:45 +03:00
ti99: Added the S0-triggered clock update to TMS9901.
This commit is contained in:
parent
9fbaa3862a
commit
d1b046cf34
@ -189,6 +189,7 @@ mainboard8_device::mainboard8_device(const machine_config &mconfig, const char *
|
||||
m_p3grom0(*owner, TI998_GLIB30_TAG),
|
||||
m_p3grom1(*owner, TI998_GLIB31_TAG),
|
||||
m_p3grom2(*owner, TI998_GLIB32_TAG),
|
||||
m_tms9901(*owner, TI998_TMS9901_TAG),
|
||||
m_sgrom_idle(true),
|
||||
m_tsgrom_idle(true),
|
||||
m_p8grom_idle(true),
|
||||
@ -383,6 +384,10 @@ void mainboard8_device::setaddress(offs_t offset, uint8_t busctrl)
|
||||
m_logical_address = offset;
|
||||
m_physical_address = 0;
|
||||
|
||||
// Trigger the 9901's clock if S0=1
|
||||
if ((offset & 0x0020) != 0)
|
||||
m_tms9901->update_clock();
|
||||
|
||||
// In TI's bit order, A14 is the second line from the right side (2^1)
|
||||
m_A14_set = ((m_logical_address & 2)!=0); // Needed for clock_in
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "bus/ti99/internal/ioport.h"
|
||||
#include "machine/ram.h"
|
||||
#include "machine/tmc0430.h"
|
||||
#include "machine/tms9901.h"
|
||||
#include "sound/sn76496.h"
|
||||
#include "sound/tms5220.h"
|
||||
#include "video/tms9928a.h"
|
||||
@ -685,6 +686,9 @@ private:
|
||||
required_device<tmc0430_device> m_p3grom1;
|
||||
required_device<tmc0430_device> m_p3grom2;
|
||||
|
||||
// Link to the 9901
|
||||
required_device<tms9901_device> m_tms9901;
|
||||
|
||||
// Idle flags for GROMs
|
||||
bool m_sgrom_idle = true;
|
||||
bool m_tsgrom_idle = true;
|
||||
|
@ -101,6 +101,7 @@ datamux_device::datamux_device(const machine_config &mconfig, const char *tag, d
|
||||
m_grom0(*owner, TI99_GROM0_TAG),
|
||||
m_grom1(*owner, TI99_GROM1_TAG),
|
||||
m_grom2(*owner, TI99_GROM2_TAG),
|
||||
m_tms9901(*owner, TI99_TMS9901_TAG),
|
||||
m_ready(*this),
|
||||
m_addr_buf(0),
|
||||
m_dbin(CLEAR_LINE),
|
||||
@ -436,6 +437,10 @@ void datamux_device::setaddress(offs_t offset, uint16_t busctrl)
|
||||
|
||||
LOGMASKED(LOG_ADDRESS, "Set address %04x\n", m_addr_buf);
|
||||
|
||||
// Trigger the TMS9901 clock when A10 is 1
|
||||
if ((m_addr_buf & 0x0020) != 0)
|
||||
m_tms9901->update_clock();
|
||||
|
||||
if ((m_addr_buf & 0xe000) == 0x0000)
|
||||
{
|
||||
return; // console ROM
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "sound/sn76496.h"
|
||||
#include "video/tms9928a.h"
|
||||
#include "machine/ram.h"
|
||||
#include "machine/tms9901.h"
|
||||
|
||||
#define TI99_DATAMUX_TAG "datamux_16_8"
|
||||
#define TI99_GROM0_TAG "console_grom_0"
|
||||
@ -32,6 +33,7 @@
|
||||
#define TI99_CONSOLEROM "console_rom"
|
||||
#define TI99_SOUNDCHIP_TAG "soundchip"
|
||||
#define TI99_VDP_TAG "vdp"
|
||||
#define TI99_TMS9901_TAG "tms9901"
|
||||
|
||||
namespace bus::ti99::internal {
|
||||
|
||||
@ -91,6 +93,9 @@ private:
|
||||
required_device<tmc0430_device> m_grom1;
|
||||
required_device<tmc0430_device> m_grom2;
|
||||
|
||||
// Link to 9901
|
||||
required_device<tms9901_device> m_tms9901;
|
||||
|
||||
// Common read routine
|
||||
void read_all(uint16_t addr, uint8_t *target);
|
||||
|
||||
|
@ -33,7 +33,8 @@ Reference: [1] TMS9901 Programmable Systems Interface Data Manual, July 1977
|
||||
Overview:
|
||||
TMS9901 is a support chip for TMS9900. It handles interrupts, provides
|
||||
several I/O pins, and a timer, which is a register which
|
||||
decrements regularly and can generate an interrupt when it reaches 0.
|
||||
decrements continuously and can be set to generate an interrupt when it
|
||||
reaches 0.
|
||||
|
||||
It communicates with the TMS9900 with the CRU bus, and with the rest of the
|
||||
world with a number of parallel I/O pins.
|
||||
@ -79,7 +80,8 @@ Interrupt inputs (group 1 and 2)
|
||||
The interrupt inputs (INT1*-INT15*) are sampled on each falling edge of
|
||||
the phi* clock. An interrupt mask is applied to mask away levels that
|
||||
shall not trigger an interrupt. The mask can be set using the SBO/SBZ
|
||||
commands (1=arm, 0=disarm) on each of the 15 bits.
|
||||
commands (1=arm, 0=disarm) on each of the 15 bits. A disarmed interrupt
|
||||
input can still be read like a normal input port via CRU access.
|
||||
|
||||
After each clock cycle, the TMS9901 latches the state of INT1*-INT15*
|
||||
(except those pins which are set as output pins).
|
||||
@ -98,8 +100,7 @@ Group 2 pins (shared I/O and INT*)
|
||||
and triggers an interrupt at level 7 when asserted.
|
||||
|
||||
In contrast, when writing to bit 31, P15 (same pin) is configured as an
|
||||
output, and the written value appears on the pin. When the port is set
|
||||
as output, the interrupt input on the shared pin is deactivated.
|
||||
output, and the written value appears on the pin.
|
||||
|
||||
According to [1], the interrupt mask should be set to 0 for those group 2
|
||||
pins that are used as input/output pins so that no unwanted interrupts are
|
||||
@ -108,16 +109,20 @@ Group 2 pins (shared I/O and INT*)
|
||||
Clock mode:
|
||||
The "clock mode" is entered by setting bit 0 to 1; setting to 0 enters
|
||||
"interrupt mode". The internal clock is a 14-bit decrementer that
|
||||
counts down by 1 every 64 clock ticks. On entering clock mode, the current
|
||||
value of the decrementer is copied to the clock read register and can be
|
||||
read by the CRU bits 1 to 14. Writing to these CRU bits modifies the
|
||||
respective bit of the clock register that serves as the start value. Every
|
||||
time a bit is written, the decrementer is loaded with the current clock
|
||||
register value.
|
||||
counts down by 1 every 64 clock ticks. On every update, the value is copied
|
||||
into the read register, but only in interrupt mode. In clock mode, the read
|
||||
register is locked so that it can be read without being changed.
|
||||
Whenever the counter reaches 0, it is reloaded from the clock register on
|
||||
the next update.
|
||||
Setting the clock register is possible via CRU addresses 1 to 14 in clock
|
||||
mode, with bit 1 being the LSB and bit 14 being the MSB. On each bit write
|
||||
operation, the current state of the clock register is copied into the counter.
|
||||
|
||||
|
||||
Interrupt
|
||||
^
|
||||
|
|
||||
[Clock register] -> [Decrementer] -> [Clock read register]
|
||||
[Clock register] -> [Decrementer] -> [Read register]
|
||||
^ |
|
||||
| v
|
||||
+--<--- CRU write CRU read---<---+
|
||||
@ -126,7 +131,7 @@ Clock mode:
|
||||
and "the clock is disabled by RST1* or by writing a zero value into the clock register".
|
||||
Tests show that when a 0 has been written, the chip still counts down from
|
||||
0x3FFF to 0. However, no interrupt is raised when reaching 0, so "enable"
|
||||
or "disable" most likely refer to the interrupt.
|
||||
or "disable" most likely refers to the interrupt.
|
||||
|
||||
When enabled, the clock raises an interrupt level 3 when reaching 0,
|
||||
overriding the input from the INT3* input. CRU bit 3 is the mask bit for
|
||||
@ -394,14 +399,6 @@ void tms9901_device::write_bit(int offset, bool data)
|
||||
// Write to control bit (CB)
|
||||
m_clock_mode = (data!=0);
|
||||
LOGMASKED(LOG_MODE, "Enter %s mode\n", m_clock_mode? "clock" : "interrupt");
|
||||
|
||||
if (m_clock_mode)
|
||||
{
|
||||
// we are switching to clock mode: latch the current value of
|
||||
// the decrementer register
|
||||
m_clock_read_register = m_decrementer_value;
|
||||
LOGMASKED(LOG_MODE, "Clock setting = %d\n", m_clock_read_register);
|
||||
}
|
||||
break;
|
||||
|
||||
case 15:
|
||||
@ -448,6 +445,26 @@ void tms9901_device::write_bit(int offset, bool data)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Update clock line. This is not a real connection to the 9901; it represents
|
||||
the effect of setting selection line S0 to 1. Since we use a separate
|
||||
I/O address space, and in the real machine, the same address lines as for
|
||||
memory access are used, and one of the address lines is connected to S0,
|
||||
we have settings of S0 even in situations when there is no I/O access but
|
||||
ordinary memory access.
|
||||
|
||||
Offering a method explicitly for S0 looks inconsistent with the way of
|
||||
addressing the bits in this chip (that is, we should then offer S1 to S4 as
|
||||
well).
|
||||
|
||||
Drivers may use this line for higher emulation precision concerning the
|
||||
clock.
|
||||
*/
|
||||
void tms9901_device::update_clock()
|
||||
{
|
||||
m_clock_read_register = m_decrementer_value;
|
||||
}
|
||||
|
||||
/*
|
||||
Timer callback
|
||||
Decrementer counts down the value set in clock mode; when it reaches 0,
|
||||
@ -467,6 +484,10 @@ void tms9901_device::timer_clock_in(line_state clk)
|
||||
if (clk == ASSERT_LINE)
|
||||
{
|
||||
m_decrementer_value = (m_decrementer_value - 1) & 0x3FFF;
|
||||
|
||||
if (!m_clock_mode)
|
||||
m_clock_read_register = m_decrementer_value;
|
||||
|
||||
LOGMASKED(LOG_CLOCK, "Clock = %04x\n", m_decrementer_value);
|
||||
if (m_decrementer_value==0)
|
||||
{
|
||||
@ -496,6 +517,9 @@ void tms9901_device::phi_line(int state)
|
||||
{
|
||||
timer_clock_in(ASSERT_LINE);
|
||||
|
||||
if (!m_clock_mode)
|
||||
m_clock_read_register = m_decrementer_value;
|
||||
|
||||
// We signal the interrupt in sync with the clock line
|
||||
signal_int();
|
||||
|
||||
|
@ -86,6 +86,8 @@ public:
|
||||
|
||||
void set_poll_int_lines(bool poll) { m_poll_lines = poll; }
|
||||
|
||||
void update_clock();
|
||||
|
||||
private:
|
||||
static constexpr device_timer_id DECREMENTER = 0;
|
||||
|
||||
|
@ -496,6 +496,10 @@ void geneve_state::setaddress_debug(bool debug, offs_t address, uint8_t busctrl)
|
||||
// See V9938 specs
|
||||
m_pal->csw_in(m_gatearray->csw_out());
|
||||
m_pal->csr_in(m_gatearray->csr_out());
|
||||
|
||||
// Trigger the 9901 clock when A10=1
|
||||
if ((address & 0x0020) != 0)
|
||||
m_tms9901->update_clock();
|
||||
}
|
||||
|
||||
// Going to the box
|
||||
|
@ -443,6 +443,10 @@ void ti99_4p_state::setaddress(offs_t address, uint16_t busctrl)
|
||||
m_decode = SGCPU_NONE;
|
||||
m_muxready = true;
|
||||
|
||||
// Trigger the TMS9901 clock when A10 is 1
|
||||
if ((m_addr_buf & 0x0020) != 0)
|
||||
m_tms9901->update_clock();
|
||||
|
||||
m_decode = decode_address(m_addr_buf);
|
||||
|
||||
if (m_decode == SGCPU_NONE)
|
||||
|
@ -56,7 +56,6 @@
|
||||
#include "speaker.h"
|
||||
|
||||
#define TI99_CONSOLEGROM "cons_grom"
|
||||
#define TI99_TMS9901_TAG "tms9901"
|
||||
#define TI99_SCREEN_TAG "screen"
|
||||
|
||||
// Debugging
|
||||
|
Loading…
Reference in New Issue
Block a user