mirror of
https://github.com/holub/mame
synced 2025-07-06 18:39:28 +03:00
New GROM implementation (TMC0430)
This commit is contained in:
parent
ee6684ac85
commit
ac3d3e5e41
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user