New GROM implementation (TMC0430)

This commit is contained in:
Michael Zapf 2016-03-30 23:49:48 +02:00
parent ee6684ac85
commit ac3d3e5e41
2 changed files with 118 additions and 118 deletions

View File

@ -61,28 +61,28 @@
8 GROMs can be used to cover a whole 16-bit address space, but only
48 KiB of memory can be used. Each GROM has a burnt-in 3 bit identifier
which allows us to put 8 GROMs in parallel, each one answering only
when its area is currently selected.
when its area is currently selected.
The address that is loaded into the address register contains two parts:
The address that is loaded into the address register contains two parts:
[ I I I A A A A A A A A A A A A A ]
The I bits indicate which GROM to use. They are latched inside every GROM,
and when the address is read from the register, they are delivered as the
most significant three address bits.
The I bits indicate which GROM to use. They are latched inside every GROM,
and when the address is read from the register, they are delivered as the
most significant three address bits.
All GROMs are wired in parallel, and only the circuits whose ID matches the
prefix actually delivers the data to the outside. Apart from that, all
GROMs perform the same internal operations. This means that each one of
them holds the same address value and delivers it on request.
All GROMs are wired in parallel, and only the circuits whose ID matches the
prefix actually delivers the data to the outside. Apart from that, all
GROMs perform the same internal operations. This means that each one of
them holds the same address value and delivers it on request.
Timing. GROMs have a CPU-bound operation phase and a non-CPU-bound operation
phase. After being selected, the READY line is immediately lowered, and
it raises as soon as the data is ready for access. After that, a prefetch
is done to get the next data byte from the memory banks, advancing the
address counter. This prefetch is also done when loading the address.
Hence, reading the address register will always deliver a value increased
by one.
Timing. GROMs have a CPU-bound operation phase and a non-CPU-bound operation
phase. After being selected, the READY line is immediately lowered, and
it raises as soon as the data is ready for access. After that, a prefetch
is done to get the next data byte from the memory banks, advancing the
address counter. This prefetch is also done when loading the address.
Hence, reading the address register will always deliver a value increased
by one.
[1] Michael L. Bunyard: Hardware Manual for the Texas Instruments 99/4A Home Computer, section 2.5
@ -104,20 +104,20 @@
Constructor.
*/
tmc0430_device::tmc0430_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, TMC0430, "TMC0430 device (GROM)", tag, owner, clock, "grom", __FILE__),
m_gromready(*this),
m_current_clock_level(CLEAR_LINE),
m_current_ident(0),
m_phase(0),
m_address_mode(false),
m_read_mode(false),
m_selected(false),
m_address_lowbyte(false),
m_regionname(nullptr),
m_ident(0),
m_address(0),
m_buffer(0),
m_memptr(nullptr)
: device_t(mconfig, TMC0430, "TMC0430 device (GROM)", tag, owner, clock, "grom", __FILE__),
m_gromready(*this),
m_current_clock_level(CLEAR_LINE),
m_current_ident(0),
m_phase(0),
m_address_mode(false),
m_read_mode(false),
m_selected(false),
m_address_lowbyte(false),
m_regionname(nullptr),
m_ident(0),
m_address(0),
m_buffer(0),
m_memptr(nullptr)
{
}
@ -129,7 +129,7 @@ tmc0430_device::tmc0430_device(const machine_config &mconfig, const char *tag, d
// ========================================================================
/*
Direction. When ASSERTed, GROM is set to be read by CPU.
Direction. When ASSERTed, GROM is set to be read by CPU.
*/
WRITE_LINE_MEMBER( tmc0430_device::m_line )
{
@ -138,7 +138,7 @@ WRITE_LINE_MEMBER( tmc0430_device::m_line )
}
/*
Mode. When ASSERTed, the address counter will be accessed (read or write).
Mode. When ASSERTed, the address counter will be accessed (read or write).
*/
WRITE_LINE_MEMBER( tmc0430_device::mo_line )
{
@ -147,11 +147,11 @@ WRITE_LINE_MEMBER( tmc0430_device::mo_line )
}
/*
Select. When ASSERTed, the read/write operation is started.
Select. When ASSERTed, the read/write operation is started.
*/
WRITE_LINE_MEMBER( tmc0430_device::gsq_line )
{
if (state==ASSERT_LINE && !m_selected) // check for edge
if (state==ASSERT_LINE && !m_selected) // check for edge
{
if (TRACE_READY) logerror("GROM %d selected, pulling down READY\n", m_ident>>13);
m_gromready(CLEAR_LINE);
@ -161,20 +161,20 @@ WRITE_LINE_MEMBER( tmc0430_device::gsq_line )
}
/*
Combined select lines. Avoids separate calls to the chip.
Address:
0 -> MO=0, M=0
1 -> MO=0, M=1
2 -> MO=1, M=0
3 -> MO=1, M=1
Data: gsq line (ASSERT, CLEAR)
Combined select lines. Avoids separate calls to the chip.
Address:
0 -> MO=0, M=0
1 -> MO=0, M=1
2 -> MO=1, M=0
3 -> MO=1, M=1
Data: gsq line (ASSERT, CLEAR)
*/
WRITE8_MEMBER( tmc0430_device::set_lines )
{
m_read_mode = ((offset & GROM_M_LINE)!=0);
m_address_mode = ((offset & GROM_MO_LINE)!=0);
if (data!=CLEAR_LINE && !m_selected) // check for edge
if (data!=CLEAR_LINE && !m_selected) // check for edge
{
if (TRACE_READY) logerror("GROM %d selected, pulling down READY\n", m_ident>>13);
m_gromready(CLEAR_LINE);
@ -184,20 +184,20 @@ WRITE8_MEMBER( tmc0430_device::set_lines )
}
/*
Clock in.
Clock in.
Note about the GREADY line:
Inside the TI-99/4A console, the GREADY outputs of all GROMs are directly
connected in parallel and pulled up. This implies that the GROMs are
open-drain outputs pulling down. There are two options:
- Only the currently addressed GROM pulls down the line; all others keep
their output open.
- All GROMs act strictly in parallel. In the case that some circuits are
slightly out of sync, the GREADY line goes up when the last circuit releases
the line.
Note about the GREADY line:
Inside the TI-99/4A console, the GREADY outputs of all GROMs are directly
connected in parallel and pulled up. This implies that the GROMs are
open-drain outputs pulling down. There are two options:
- Only the currently addressed GROM pulls down the line; all others keep
their output open.
- All GROMs act strictly in parallel. In the case that some circuits are
slightly out of sync, the GREADY line goes up when the last circuit releases
the line.
For the emulation we may assume that all GROMs at the same clock line
raise their outputs synchronously.
For the emulation we may assume that all GROMs at the same clock line
raise their outputs synchronously.
*/
WRITE_LINE_MEMBER( tmc0430_device::gclock_in )
{
@ -266,8 +266,8 @@ WRITE_LINE_MEMBER( tmc0430_device::gclock_in )
}
/*
Read operation. For MO=Address, delivers the address register (and destroys its contents).
For MO=Data, delivers the byte inside the buffer and prefetches the next one.
Read operation. For MO=Address, delivers the address register (and destroys its contents).
For MO=Data, delivers the byte inside the buffer and prefetches the next one.
*/
READ8Z_MEMBER( tmc0430_device::readz )
{
@ -278,7 +278,7 @@ READ8Z_MEMBER( tmc0430_device::readz )
// Address reading is destructive
*value = (m_address & 0xff00)>>8;
UINT8 lsb = (m_address & 0x00ff);
m_address = (lsb << 8) | lsb; // see [1], section 2.5.3
m_address = (lsb << 8) | lsb; // see [1], section 2.5.3
if (TRACE_DETAIL) logerror("GROM %d return address %02x\n", m_ident>>13, *value);
}
else
@ -298,13 +298,13 @@ READ8Z_MEMBER( tmc0430_device::readz )
}
/*
Write operation. For MO=Address, shifts value in the address register
by 8 bits and copies the new value into the low byte. After every two
write operations, prefetches the byte from the new location. For MO=Data,
do nothing, because GRAMs were never seen in the wild.
Write operation. For MO=Address, shifts value in the address register
by 8 bits and copies the new value into the low byte. After every two
write operations, prefetches the byte from the new location. For MO=Data,
do nothing, because GRAMs were never seen in the wild.
This operation occurs in parallel to phase 4. The real GROM will pick up
the value from the data bus some phases later.
This operation occurs in parallel to phase 4. The real GROM will pick up
the value from the data bus some phases later.
*/
WRITE8_MEMBER( tmc0430_device::write )
{
@ -312,7 +312,7 @@ WRITE8_MEMBER( tmc0430_device::write )
if (m_address_mode)
{
m_address = ((m_address << 8) | data); // [1], section 2.5.7
m_address = ((m_address << 8) | data); // [1], section 2.5.7
m_current_ident = m_address & 0xe000;
if (TRACE_DETAIL) logerror("GROM %d new address %04x (%s)\n", m_ident>>13, m_address, m_address_lowbyte? "complete" : "incomplete");
// Toggle the lowbyte flag

View File

@ -77,17 +77,17 @@ private:
bool m_read_mode;
// Selected?
bool m_selected;
bool m_selected;
// Toggle for address loading
bool m_address_lowbyte;
bool m_address_lowbyte;
// Region name
const char* m_regionname;
// Offset in the region. We cannot rely on the ident because the GROMs
// in the cartridges begin with ident 3, but start at the beginning of their region.
int m_offset;
int m_offset;
// Identification of this GROM (0-7 <<13)
int m_ident;