PPS-4 refinements and modernization (nw)

- Split PPS-4 and PPS-4/2 device types; better explain and properly implement the difference
- Use callbacks for discrete input/output ports instead of fake memory addresses
- A17xx reads the address bus directly during I/O accesses
- Misc. chip documentation
This commit is contained in:
AJR 2017-01-06 22:11:19 -05:00
parent aabdd13259
commit f5bcff30f6
5 changed files with 248 additions and 105 deletions

View File

@ -5,14 +5,32 @@
*
* pps4.c
*
* Rockwell PPS-4 CPU
* Introduced in 1972, it ran at 256kHz. An improved version was released
* in 1975, but could only manage 200kHz. The chipset continued to be
* produced through the 1980s, but never found much acceptance. Chip
* numbers are 10660 (original), 11660, 12660.
* Rockwell Parallel Processing System (PPS-4) Microcomputer
*
* Introduced in 1972, the PPS-4 was a 4-bit PMOS CPU that ran at 256kHz.
* The improved PPS-4/2, released in 1975, doubled the width of discrete
* output and added an internal clock generator (intended for use with a
* 3.579545MHz NTSC XTAL), but the latter could only manage 200kHz. The
* chipset later evolved into the PPS-4/1 (MM76, MM78, etc.) series of
* MCUs which Rockwell continued to produce through the early 1980s.
*
* Part numbers are 10660 (original), 11660 (PPS-4/2), 12660.
*
* List of memory chips:
* 10432 RAM (256 x 4)
* 10932 RAM (512 x 4)
* A05XX ROM (1K x 8)
* A52XX ROM (2K x 8)
* A66XX ROM (4K x 8)
* A88XX ROM (8K x 8)
* A08XX ROM/RAM (704 x 8/72 x 4)
* A07XX ROM/RAM (1K x 8/116 x 4)
* A20XX ROM/RAM (1.5K x 8/128 x 4)
* A17XX ROM/RAM + I/O (2K x 8/128 x 4/16 x 1)
* A23XX ROM/RAM + I/O (1K x 8/128 x 4/16 x 1)
*
* List of support / peripheral chips:
* 10706 Clock generator
* 10706 4-phase clock generator
* 10738 Bus interface
* 11049 Interval timer
* 10686 General purpose I/O
@ -24,8 +42,10 @@
* 10815 keyboard/printer controller
* 10930 Serial data controller
* 15380 dot matrix printer controller
* 11696 Parallel input/output
*
* Note: External clock should be divided by 18 (not implemented).
* All of the above devices, except those providing 4-bit RAM, were also
* compatible with the failed PPS-8 series of 8-bit PMOS CPUs.
*
* Pinouts:
* 10660 11660
@ -55,6 +75,7 @@
* +--------------------+ +--------------------+
*
*****************************************************************************/
#include "emu.h"
#include "debugger.h"
#include "pps4.h"
@ -69,12 +90,26 @@
#endif
const device_type PPS4 = &device_creator<pps4_device>;
const device_type PPS4_2 = &device_creator<pps4_2_device>;
pps4_device::pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: cpu_device(mconfig, PPS4, "PPS4", tag, owner, clock, "pps4", __FILE__ )
pps4_device::pps4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, u32 clock, const char *shortname, const char *file)
: cpu_device(mconfig, type, name, tag, owner, clock, shortname, file)
, m_program_config("program", ENDIANNESS_LITTLE, 8, 12)
, m_data_config("data", ENDIANNESS_LITTLE, 8, 12) // 4bit RAM
, m_io_config("io", ENDIANNESS_LITTLE, 8, 8+1) // 4bit IO
, m_io_config("io", ENDIANNESS_LITTLE, 8, 8) // 4bit IO
, m_dia_cb(*this)
, m_dib_cb(*this)
, m_do_cb(*this)
{
}
pps4_device::pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pps4_device(mconfig, PPS4, "PPS-4", tag, owner, clock, "pps4", __FILE__)
{
}
pps4_2_device::pps4_2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: pps4_device(mconfig, PPS4_2, "PPS-4/2", tag, owner, clock, "pps4_2", __FILE__)
{
}
@ -82,9 +117,9 @@ pps4_device::pps4_device(const machine_config &mconfig, const char *tag, device_
* @brief pps4_device::M Return the memory at address B
* @return ROM/RAM(B)
*/
uint8_t pps4_device::M()
u8 pps4_device::M()
{
uint8_t ret = m_data->read_byte(m_B & ~m_SAG);
u8 ret = m_data->read_byte(m_B & ~m_SAG);
m_SAG = 0;
return ret;
}
@ -94,13 +129,13 @@ uint8_t pps4_device::M()
* @brief pps4_device::W Write to the memory address at B
* @return ROM/RAM(B)
*/
void pps4_device::W(uint8_t data)
void pps4_device::W(u8 data)
{
m_data->write_byte(m_B & ~m_SAG, data);
m_SAG = 0;
}
offs_t pps4_device::disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options)
offs_t pps4_device::disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options)
{
extern CPU_DISASSEMBLE( pps4 );
return CPU_DISASSEMBLE_NAME(pps4)(this, stream, pc, oprom, opram, options);
@ -113,9 +148,9 @@ offs_t pps4_device::disasm_disassemble(std::ostream &stream, offs_t pc, const ui
* program counter is incremented. The icount is decremented.
* @return m_I the next opcode
*/
inline uint8_t pps4_device::ROP()
inline u8 pps4_device::ROP()
{
const uint8_t op = m_direct->read_byte(m_P & 0xFFF);
const u8 op = m_direct->read_byte(m_P & 0xFFF);
m_Ip = m_I1; // save previous opcode
m_P = (m_P + 1) & 0xFFF;
m_icount -= 1;
@ -129,9 +164,9 @@ inline uint8_t pps4_device::ROP()
* icount is decremented.
* @return m_I2 the next argument
*/
inline uint8_t pps4_device::ARG()
inline u8 pps4_device::ARG()
{
const uint8_t arg = m_direct->read_byte(m_P & 0xFFF);
const u8 arg = m_direct->read_byte(m_P & 0xFFF);
m_P = (m_P + 1) & 0xFFF;
m_icount -= 1;
return arg;
@ -265,7 +300,7 @@ void pps4_device::iADCSK()
*/
void pps4_device::iADI()
{
const uint8_t imm = ~m_I1 & 15;
const u8 imm = ~m_I1 & 15;
m_A = m_A + imm;
m_Skip = (m_A >> 4) & 1;
m_A = m_A & 15;
@ -490,7 +525,7 @@ void pps4_device::iRF2()
*/
void pps4_device::iLD()
{
const uint16_t i3c = ~m_I1 & 7;
const u16 i3c = ~m_I1 & 7;
m_A = M();
m_B = m_B ^ (i3c << 4);
}
@ -513,8 +548,8 @@ void pps4_device::iLD()
*/
void pps4_device::iEX()
{
const uint16_t i3c = ~m_I1 & 7;
const uint8_t mem = M();
const u16 i3c = ~m_I1 & 7;
const u8 mem = M();
W(m_A);
m_A = mem;
m_B = m_B ^ (i3c << 4);
@ -542,9 +577,9 @@ void pps4_device::iEX()
*/
void pps4_device::iEXD()
{
const uint8_t i3c = ~m_I1 & 7;
const uint8_t mem = M();
uint8_t bl = m_B & 15;
const u8 i3c = ~m_I1 & 7;
const u8 mem = M();
u8 bl = m_B & 15;
W(m_A);
m_A = mem;
m_B = m_B ^ (i3c << 4);
@ -696,7 +731,7 @@ void pps4_device::iLBUA()
void pps4_device::iXABL()
{
// swap A and BL
uint8_t bl = m_B & 15;
u8 bl = m_B & 15;
m_B = (m_B & ~15) | m_A;
m_A = bl;
}
@ -717,7 +752,7 @@ void pps4_device::iXABL()
void pps4_device::iXBMX()
{
// swap X and BM
const uint8_t bm = (m_B >> 4) & 15;
const u8 bm = (m_B >> 4) & 15;
m_B = (m_B & ~(15 << 4)) | (m_X << 4);
m_X = bm;
}
@ -786,7 +821,7 @@ void pps4_device::iXS()
*/
void pps4_device::iCYS()
{
const uint16_t sa = (m_SA >> 4) | (m_A << 8);
const u16 sa = (m_SA >> 4) | (m_A << 8);
m_A = m_SA & 15;
m_SA = sa;
}
@ -893,7 +928,7 @@ void pps4_device::iLBL()
*/
void pps4_device::iINCB()
{
uint8_t bl = m_B & 15;
u8 bl = m_B & 15;
bl = (bl + 1) & 15;
if (0 == bl) {
LOG(("%s: skip BL=%x\n", __FUNCTION__, bl));
@ -919,7 +954,7 @@ void pps4_device::iINCB()
*/
void pps4_device::iDECB()
{
uint8_t bl = m_B & 15;
u8 bl = m_B & 15;
bl = (bl - 1) & 15;
if (15 == bl) {
LOG(("%s: skip BL=%x\n", __FUNCTION__, bl));
@ -945,7 +980,7 @@ void pps4_device::iDECB()
*/
void pps4_device::iT()
{
const uint16_t p = (m_P & ~63) | (m_I1 & 63);
const u16 p = (m_P & ~63) | (m_I1 & 63);
LOG(("%s: P=%03x I=%02x -> P=%03x\n", __FUNCTION__, m_P, m_I1, p));
m_P = p;
}
@ -1084,8 +1119,8 @@ void pps4_device::iSKZ()
*/
void pps4_device::iSKBI()
{
const uint8_t i4 = m_I1 & 15;
const uint8_t bl = m_B & 15;
const u8 i4 = m_I1 & 15;
const u8 bl = m_B & 15;
m_Skip = bl == i4 ? 1 : 0;
}
@ -1184,18 +1219,20 @@ void pps4_device::iRTNSK()
* the CPU and sets up the I/O enable signal. The second
* ROM word is then received by the I/O devices and decoded
* for address and command. The contents of the accumulator
* inverted are placed on the data lines for acceptance by
* the I/O. At the same time, input data received by the I/O
* device is transferred to the accumulator inverted.
* inverted are placed on the data lines [I/D:4-1] for
* acceptance by the I/O. At the same time, input data
* received by the I/O device [on I/D:8-5] is transferred
* to the accumulator inverted.
*
* FIXME: Is BL on the I/D:8-5 lines during the I/O cycle?
* The ROM, RAM, I/O chips A17xx suggest this, because they
* expect the value of BL to address one of the sixteen
* The RAM address register (B) is placed on the address bus
* during the I/O request cycle. The original RAM chip ignores
* this and leaves the data bus alone at this time, but the
* A17xx uses the value of BL to address one of the sixteen
* input/output lines.
*/
void pps4_device::iIOL()
{
uint8_t ac = ((m_B & 15) << 4) | (~m_A & 15);
u8 ac = (~m_A & 15);
m_I2 = ARG();
m_io->write_byte(m_I2, ac);
LOG(("%s: port:%02x <- %x\n", __FUNCTION__, m_I2, ac));
@ -1219,7 +1256,7 @@ void pps4_device::iIOL()
*/
void pps4_device::iDIA()
{
m_A = m_io->read_byte(PPS4_PORT_A) & 15;
m_A = m_dia_cb() & 15;
}
/**
@ -1237,7 +1274,13 @@ void pps4_device::iDIA()
*/
void pps4_device::iDIB()
{
m_A = m_io->read_byte(PPS4_PORT_B) & 15;
m_A = m_dib_cb() & 15;
}
void pps4_2_device::iDIB()
{
// PPS-4/2 can write zeros onto bidirectional DIO pins to mask open-drain inputs
m_A = m_dib_cb() & m_DIO;
}
/**
@ -1255,7 +1298,14 @@ void pps4_device::iDIB()
*/
void pps4_device::iDOA()
{
m_io->write_byte(PPS4_PORT_A, m_A);
m_do_cb(m_A);
}
void pps4_2_device::iDOA()
{
// DOA also transfers contents of X to DIO on PPS-4/2
m_DIO = m_X;
m_do_cb(m_A | (m_X << 4));
}
/**
@ -1551,6 +1601,16 @@ void pps4_device::device_start()
state_add( STATE_GENFLAGS, "GENFLAGS", m_C).formatstr("%3s").noshow();
m_icountptr = &m_icount;
m_dia_cb.resolve_safe(0);
m_dib_cb.resolve_safe(0);
m_do_cb.resolve_safe();
}
void pps4_2_device::device_start()
{
pps4_device::device_start();
save_item(NAME(m_DIO));
}
void pps4_device::state_string_export(const device_state_entry &entry, std::string &str) const
@ -1586,3 +1646,19 @@ void pps4_device::device_reset()
m_I2 = 0; // Most recent parameter I2(8:1)
m_Ip = 0; // Previous instruction I(8:1)
}
void pps4_2_device::device_reset()
{
pps4_device::device_reset();
m_DIO = 15; // DIO clamp
}
READ16_MEMBER(pps4_device::address_bus_r)
{
if (&space == m_io || &space == m_data)
return m_B;
else if (&space == m_program)
return m_P;
else
return 0;
}

View File

@ -19,26 +19,48 @@ enum
PPS4_SAG,
PPS4_I1,
PPS4_I2,
PPS4_Ip,
PPS4_PORT_A = 256,
PPS4_PORT_B = 257
PPS4_Ip
};
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_PPS4_DISCRETE_INPUT_A_CB(_devcb) \
devcb = &pps4_device::set_dia_cb(*device, DEVCB_##_devcb);
#define MCFG_PPS4_DISCRETE_INPUT_B_CB(_devcb) \
devcb = &pps4_device::set_dib_cb(*device, DEVCB_##_devcb);
#define MCFG_PPS4_DISCRETE_OUTPUT_CB(_devcb) \
devcb = &pps4_device::set_do_cb(*device, DEVCB_##_devcb);
//**************************************************************************
// DEVICE TYPE DEFINITIONS
//**************************************************************************
extern const device_type PPS4;
extern const device_type PPS4_2;
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
extern const device_type PPS4;
class pps4_device : public cpu_device
{
public:
// construction/destruction
pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
pps4_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
pps4_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, u32 clock, const char *shortname, const char *file);
public:
// static configuration helpers
template<class _Object> static devcb_base &set_dia_cb(device_t &device, _Object object) { return downcast<pps4_device &>(device).m_dia_cb.set_callback(object); }
template<class _Object> static devcb_base &set_dib_cb(device_t &device, _Object object) { return downcast<pps4_device &>(device).m_dib_cb.set_callback(object); }
template<class _Object> static devcb_base &set_do_cb(device_t &device, _Object object) { return downcast<pps4_device &>(device).m_do_cb.set_callback(object); }
DECLARE_READ16_MEMBER(address_bus_r);
protected:
// device-level overrides
@ -46,10 +68,10 @@ protected:
virtual void device_reset() override;
// device_execute_interface overrides
virtual uint32_t execute_min_cycles() const override { return 1; }
virtual uint32_t execute_max_cycles() const override { return 3; }
virtual uint32_t execute_input_lines() const override { return 0; }
virtual uint32_t execute_default_irq_vector() const override { return 0; }
virtual u32 execute_min_cycles() const override { return 1; }
virtual u32 execute_max_cycles() const override { return 3; }
virtual u32 execute_input_lines() const override { return 0; }
virtual u32 execute_default_irq_vector() const override { return 0; }
virtual void execute_run() override;
// device_memory_interface overrides
@ -62,47 +84,51 @@ protected:
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
// device_disasm_interface overrides
virtual uint32_t disasm_min_opcode_bytes() const override { return 1; }
virtual uint32_t disasm_max_opcode_bytes() const override { return 2; }
virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const uint8_t *oprom, const uint8_t *opram, uint32_t options) override;
virtual u32 disasm_min_opcode_bytes() const override { return 1; }
virtual u32 disasm_max_opcode_bytes() const override { return 2; }
virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) override;
private:
protected:
address_space_config m_program_config;
address_space_config m_data_config;
address_space_config m_io_config;
devcb_read8 m_dia_cb;
devcb_read8 m_dib_cb;
devcb_write8 m_do_cb;
address_space *m_program;
direct_read_data *m_direct;
address_space *m_data;
address_space *m_io;
int m_icount;
uint8_t m_A; //!< Accumulator A(4:1)
uint8_t m_X; //!< X register X(4:1)
uint16_t m_P; //!< program counter P(12:1)
uint16_t m_SA; //!< Shift register SA(12:1)
uint16_t m_SB; //!< Shift register SB(12:1)
uint8_t m_Skip; //!< Skip next instruction
uint16_t m_SAG; //!< Special address generation mask
uint16_t m_B; //!< B register B(12:1) (BL, BM and BH)
uint8_t m_C; //!< Carry flip-flop
uint8_t m_FF1; //!< Flip-flop 1
uint8_t m_FF2; //!< Flip-flop 2
uint8_t m_I1; //!< Most recent instruction I(8:1)
uint8_t m_I2; //!< Most recent parameter I2(8:1)
uint8_t m_Ip; //!< Previous instruction I(8:1)
u8 m_A; //!< Accumulator A(4:1)
u8 m_X; //!< X register X(4:1)
u16 m_P; //!< program counter P(12:1)
u16 m_SA; //!< Shift register SA(12:1)
u16 m_SB; //!< Shift register SB(12:1)
u8 m_Skip; //!< Skip next instruction
u16 m_SAG; //!< Special address generation mask
u16 m_B; //!< B register B(12:1) (BL, BM and BH)
u8 m_C; //!< Carry flip-flop
u8 m_FF1; //!< Flip-flop 1
u8 m_FF2; //!< Flip-flop 2
u8 m_I1; //!< Most recent instruction I(8:1)
u8 m_I2; //!< Most recent parameter I2(8:1)
u8 m_Ip; //!< Previous instruction I(8:1)
//! return memory at address B(12:1)
inline uint8_t M();
inline u8 M();
//! write to memory at address B(12:1)
inline void W(uint8_t data);
inline void W(u8 data);
//! return the next opcode (also in m_I)
inline uint8_t ROP();
inline u8 ROP();
//! return the next argument (also in m_I2)
inline uint8_t ARG();
inline u8 ARG();
void iAD(); //!< Add
void iADC(); //!< Add with carry-in
@ -151,11 +177,33 @@ private:
void iRTNSK(); //!< Return and skip
void iIOL(); //!< Input/Output long
void iDIA(); //!< Discrete input group A
void iDIB(); //!< Discrete input group B
void iDOA(); //!< Discrete output group A
virtual void iDIB(); //!< Discrete input group B
virtual void iDOA(); //!< Discrete output group A
void iSAG(); //!< Special address generation
void execute_one(); //!< execute one instruction
};
class pps4_2_device : public pps4_device
{
public:
// construction/destruction
pps4_2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// device_execute_interface overrides (NOTE: these assume internal XTAL divider is always used)
virtual u64 execute_clocks_to_cycles(u64 clocks) const override { return (clocks + 18 - 1) / 18; }
virtual u64 execute_cycles_to_clocks(u64 cycles) const override { return (cycles * 18); }
virtual void iDIB() override;
virtual void iDOA() override;
private:
u8 m_DIO; //!< DIO clamp
};
#endif // __PPS4_H__

View File

@ -11,6 +11,7 @@
There are two basic I/O instructions:
SES = Select Enable Status and SOS = Select Output Status
The lower 4 bits of the I/O address select one of 16 I/O lines.
Actually the lowest 6 bits are used, but bits 4 and 5 must be 0.
There are at most two A17XX per system, one for the lower
ROM and RAM portion and one for the higher.
@ -58,7 +59,8 @@ ra17xx_device::ra17xx_device(const machine_config &mconfig, const char *tag, dev
: device_t(mconfig, RA17XX, "Rockwell A17XX", tag, owner, clock, "ra17xx", __FILE__),
m_enable(false),
m_iord(*this),
m_iowr(*this)
m_iowr(*this),
m_cpu(*this, finder_base::DUMMY_TAG)
{
}
@ -97,26 +99,41 @@ void ra17xx_device::device_reset()
WRITE8_MEMBER( ra17xx_device::io_w )
{
assert(offset < 16);
m_bl = (data >> 4) & 15; // BL on the data bus most significant bits
if (offset & 1) {
m_bl = m_cpu->address_bus_r(space, 0) & 63;
if (offset & 1)
{
// SOS command
if (data & (1 << 3)) {
if (m_bl >= 16)
{
logerror("Attempt to write to nonexistent output %d\n");
}
else if (data & (1 << 3))
{
m_line[m_bl] = 1; // enable output
// if (m_enable)
m_iowr(m_bl, 1, 1);
} else {
}
else
{
m_line[m_bl] = 0; // disable output
// if (m_enable)
m_iowr(m_bl, 0, 1);
}
} else {
}
else
{
// SES command
if (data & (1 << 3)) {
if (data & (1 << 3))
{
// enable all outputs
m_enable = true;
for (int i = 0; i < 16; i++)
m_iowr(i, m_line[i], 1);
} else {
}
else
{
// disable all outputs
m_enable = false;
}
@ -127,5 +144,5 @@ WRITE8_MEMBER( ra17xx_device::io_w )
READ8_MEMBER( ra17xx_device::io_r )
{
assert(offset < 16);
return (m_iord(m_bl) & 1) ? 0x0f : 0x07;
return (m_bl >= 16 || (m_iord(m_bl) & 1)) ? 0x0f : 0x07;
}

View File

@ -16,6 +16,7 @@
#define __RA17XX_H__
#include "device.h"
#include "cpu/pps4/pps4.h"
/*************************************
*
@ -29,6 +30,10 @@
/* Set the write line handler */
#define MCFG_RA17XX_WRITE(_devcb) \
ra17xx_device::set_iowr(*device, DEVCB_##_devcb);
#define MCFG_RA17XX_CPU(_tag) \
ra17xx_device::set_cpu_tag(*device, "^" _tag);
class ra17xx_device : public device_t
{
public:
@ -40,6 +45,8 @@ public:
template<class _Object> static devcb_base &set_iord(device_t &device, _Object object) { return downcast<ra17xx_device &>(device).m_iord.set_callback(object); }
template<class _Object> static devcb_base &set_iowr(device_t &device, _Object object) { return downcast<ra17xx_device &>(device).m_iowr.set_callback(object); }
static void set_cpu_tag(device_t &device, const char *tag) { downcast<ra17xx_device &>(device).m_cpu.set_tag(tag); }
protected:
// device-level overrides
virtual void device_start() override;
@ -51,6 +58,7 @@ private:
bool m_enable; //!< true if outputs are enabled
devcb_read8 m_iord; //!< input line (read, offset = line, data = 0/1)
devcb_write8 m_iowr; //!< output line (write, offset = line, data = 0/1)
required_device<pps4_device> m_cpu;
};
extern const device_type RA17XX;

View File

@ -104,8 +104,7 @@ public:
DECLARE_READ8_MEMBER (gts1_io_r);
DECLARE_WRITE8_MEMBER(gts1_io_w);
DECLARE_READ8_MEMBER (gts1_pa_r);
DECLARE_WRITE8_MEMBER(gts1_pa_w);
DECLARE_WRITE8_MEMBER(gts1_pb_w);
DECLARE_WRITE8_MEMBER(gts1_do_w);
private:
virtual void machine_reset() override;
required_device<cpu_device> m_maincpu;
@ -134,8 +133,6 @@ static ADDRESS_MAP_START( gts1_io, AS_IO, 8, gts1_state )
AM_RANGE(0x0060, 0x006f) AM_DEVREADWRITE ( "u2", r10696_device, io_r, io_w ) // (U2) NVRAM io chip
AM_RANGE(0x00d0, 0x00df) AM_DEVREADWRITE ( "u6", r10788_device, io_r, io_w ) // (U6) display chip
AM_RANGE(0x0000, 0x00ff) AM_READ ( gts1_io_r ) AM_WRITE( gts1_io_w ) // catch undecoded I/O accesss
AM_RANGE(0x0100, 0x0100) AM_READ ( gts1_pa_r ) AM_WRITE( gts1_pa_w ) // CPU I/O port A (input/output)
AM_RANGE(0x0101, 0x0101) AM_WRITE( gts1_pb_w ) // CPU I/O port B (output only)
ADDRESS_MAP_END
static INPUT_PORTS_START( gts1_dips )
@ -669,27 +666,22 @@ READ8_MEMBER (gts1_state::gts1_pa_r)
return data;
}
WRITE8_MEMBER(gts1_state::gts1_pa_w)
WRITE8_MEMBER(gts1_state::gts1_do_w)
{
// write address lines 7-4
m_6351_addr = (m_6351_addr & 0x0f) | ((data & 0x0f) << 4);
LOG(("%s: ROM hi:%x addr:%02x\n", __FUNCTION__, data & 0x0f, m_6351_addr));
}
WRITE8_MEMBER(gts1_state::gts1_pb_w)
{
// write address lines 3-0
m_6351_addr = (m_6351_addr & 0xf0) | (data & 0x0f);
LOG(("%s: ROM lo:%x addr:%02x\n", __FUNCTION__, data & 0x0f, m_6351_addr));
// write address lines (DO1-4 to A0-3, DIO1-4 to A4-7)
m_6351_addr = (m_6351_addr & 0x300) | data;
LOG(("%s: ROM addr:%02x\n", __FUNCTION__, m_6351_addr));
}
static MACHINE_CONFIG_START( gts1, gts1_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", PPS4, XTAL_3_579545MHz / 18) // divided in the CPU
MCFG_CPU_ADD("maincpu", PPS4_2, XTAL_3_579545MHz) // divided by 18 in the CPU
MCFG_CPU_PROGRAM_MAP(gts1_map)
MCFG_CPU_DATA_MAP(gts1_data)
MCFG_CPU_IO_MAP(gts1_io)
MCFG_PPS4_DISCRETE_INPUT_A_CB(READ8(gts1_state, gts1_pa_r))
MCFG_PPS4_DISCRETE_OUTPUT_CB(WRITE8(gts1_state, gts1_do_w))
MCFG_NVRAM_ADD_0FILL("nvram")
@ -697,11 +689,13 @@ static MACHINE_CONFIG_START( gts1, gts1_state )
MCFG_DEVICE_ADD( "u5", RA17XX, 0 )
MCFG_RA17XX_READ ( READ8 (gts1_state,gts1_switches_r) )
MCFG_RA17XX_WRITE( WRITE8(gts1_state,gts1_switches_w) )
MCFG_RA17XX_CPU("maincpu")
/* A1752CF 2048 x 8 ROM (800-fff), 128 x 4 RAM (80-ff) and 16 I/O lines (40 ... 4f) */
MCFG_DEVICE_ADD( "u4", RA17XX, 0 )
MCFG_RA17XX_READ ( READ8 (gts1_state,gts1_solenoid_r) )
MCFG_RA17XX_WRITE( WRITE8(gts1_state,gts1_solenoid_w) )
MCFG_RA17XX_CPU("maincpu")
/* 10696 General Purpose Input/Output */
MCFG_DEVICE_ADD( "u2", R10696, 0 )