Merge pull request #1938 from ajrhacker/pps4_2

PPS-4 refinements and modernization (nw)
This commit is contained in:
Dirk Best 2017-01-07 12:37:23 +01:00 committed by GitHub
commit 02108b60e8
5 changed files with 248 additions and 105 deletions

View File

@ -5,14 +5,32 @@
* *
* pps4.c * pps4.c
* *
* Rockwell PPS-4 CPU * Rockwell Parallel Processing System (PPS-4) Microcomputer
* Introduced in 1972, it ran at 256kHz. An improved version was released *
* in 1975, but could only manage 200kHz. The chipset continued to be * Introduced in 1972, the PPS-4 was a 4-bit PMOS CPU that ran at 256kHz.
* produced through the 1980s, but never found much acceptance. Chip * The improved PPS-4/2, released in 1975, doubled the width of discrete
* numbers are 10660 (original), 11660, 12660. * 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: * List of support / peripheral chips:
* 10706 Clock generator * 10706 4-phase clock generator
* 10738 Bus interface * 10738 Bus interface
* 11049 Interval timer * 11049 Interval timer
* 10686 General purpose I/O * 10686 General purpose I/O
@ -24,8 +42,10 @@
* 10815 keyboard/printer controller * 10815 keyboard/printer controller
* 10930 Serial data controller * 10930 Serial data controller
* 15380 dot matrix printer 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: * Pinouts:
* 10660 11660 * 10660 11660
@ -55,6 +75,7 @@
* +--------------------+ +--------------------+ * +--------------------+ +--------------------+
* *
*****************************************************************************/ *****************************************************************************/
#include "emu.h" #include "emu.h"
#include "debugger.h" #include "debugger.h"
#include "pps4.h" #include "pps4.h"
@ -69,12 +90,26 @@
#endif #endif
const device_type PPS4 = &device_creator<pps4_device>; 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) 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, PPS4, "PPS4", tag, owner, clock, "pps4", __FILE__ ) : cpu_device(mconfig, type, name, tag, owner, clock, shortname, file)
, m_program_config("program", ENDIANNESS_LITTLE, 8, 12) , m_program_config("program", ENDIANNESS_LITTLE, 8, 12)
, m_data_config("data", ENDIANNESS_LITTLE, 8, 12) // 4bit RAM , 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 * @brief pps4_device::M Return the memory at address B
* @return ROM/RAM(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; m_SAG = 0;
return ret; return ret;
} }
@ -94,13 +129,13 @@ uint8_t pps4_device::M()
* @brief pps4_device::W Write to the memory address at B * @brief pps4_device::W Write to the memory address at B
* @return ROM/RAM(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_data->write_byte(m_B & ~m_SAG, data);
m_SAG = 0; 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 ); extern CPU_DISASSEMBLE( pps4 );
return CPU_DISASSEMBLE_NAME(pps4)(this, stream, pc, oprom, opram, options); 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. * program counter is incremented. The icount is decremented.
* @return m_I the next opcode * @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_Ip = m_I1; // save previous opcode
m_P = (m_P + 1) & 0xFFF; m_P = (m_P + 1) & 0xFFF;
m_icount -= 1; m_icount -= 1;
@ -129,9 +164,9 @@ inline uint8_t pps4_device::ROP()
* icount is decremented. * icount is decremented.
* @return m_I2 the next argument * @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_P = (m_P + 1) & 0xFFF;
m_icount -= 1; m_icount -= 1;
return arg; return arg;
@ -265,7 +300,7 @@ void pps4_device::iADCSK()
*/ */
void pps4_device::iADI() void pps4_device::iADI()
{ {
const uint8_t imm = ~m_I1 & 15; const u8 imm = ~m_I1 & 15;
m_A = m_A + imm; m_A = m_A + imm;
m_Skip = (m_A >> 4) & 1; m_Skip = (m_A >> 4) & 1;
m_A = m_A & 15; m_A = m_A & 15;
@ -490,7 +525,7 @@ void pps4_device::iRF2()
*/ */
void pps4_device::iLD() void pps4_device::iLD()
{ {
const uint16_t i3c = ~m_I1 & 7; const u16 i3c = ~m_I1 & 7;
m_A = M(); m_A = M();
m_B = m_B ^ (i3c << 4); m_B = m_B ^ (i3c << 4);
} }
@ -513,8 +548,8 @@ void pps4_device::iLD()
*/ */
void pps4_device::iEX() void pps4_device::iEX()
{ {
const uint16_t i3c = ~m_I1 & 7; const u16 i3c = ~m_I1 & 7;
const uint8_t mem = M(); const u8 mem = M();
W(m_A); W(m_A);
m_A = mem; m_A = mem;
m_B = m_B ^ (i3c << 4); m_B = m_B ^ (i3c << 4);
@ -542,9 +577,9 @@ void pps4_device::iEX()
*/ */
void pps4_device::iEXD() void pps4_device::iEXD()
{ {
const uint8_t i3c = ~m_I1 & 7; const u8 i3c = ~m_I1 & 7;
const uint8_t mem = M(); const u8 mem = M();
uint8_t bl = m_B & 15; u8 bl = m_B & 15;
W(m_A); W(m_A);
m_A = mem; m_A = mem;
m_B = m_B ^ (i3c << 4); m_B = m_B ^ (i3c << 4);
@ -696,7 +731,7 @@ void pps4_device::iLBUA()
void pps4_device::iXABL() void pps4_device::iXABL()
{ {
// swap A and BL // swap A and BL
uint8_t bl = m_B & 15; u8 bl = m_B & 15;
m_B = (m_B & ~15) | m_A; m_B = (m_B & ~15) | m_A;
m_A = bl; m_A = bl;
} }
@ -717,7 +752,7 @@ void pps4_device::iXABL()
void pps4_device::iXBMX() void pps4_device::iXBMX()
{ {
// swap X and BM // 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_B = (m_B & ~(15 << 4)) | (m_X << 4);
m_X = bm; m_X = bm;
} }
@ -786,7 +821,7 @@ void pps4_device::iXS()
*/ */
void pps4_device::iCYS() 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_A = m_SA & 15;
m_SA = sa; m_SA = sa;
} }
@ -893,7 +928,7 @@ void pps4_device::iLBL()
*/ */
void pps4_device::iINCB() void pps4_device::iINCB()
{ {
uint8_t bl = m_B & 15; u8 bl = m_B & 15;
bl = (bl + 1) & 15; bl = (bl + 1) & 15;
if (0 == bl) { if (0 == bl) {
LOG(("%s: skip BL=%x\n", __FUNCTION__, bl)); LOG(("%s: skip BL=%x\n", __FUNCTION__, bl));
@ -919,7 +954,7 @@ void pps4_device::iINCB()
*/ */
void pps4_device::iDECB() void pps4_device::iDECB()
{ {
uint8_t bl = m_B & 15; u8 bl = m_B & 15;
bl = (bl - 1) & 15; bl = (bl - 1) & 15;
if (15 == bl) { if (15 == bl) {
LOG(("%s: skip BL=%x\n", __FUNCTION__, bl)); LOG(("%s: skip BL=%x\n", __FUNCTION__, bl));
@ -945,7 +980,7 @@ void pps4_device::iDECB()
*/ */
void pps4_device::iT() 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)); LOG(("%s: P=%03x I=%02x -> P=%03x\n", __FUNCTION__, m_P, m_I1, p));
m_P = p; m_P = p;
} }
@ -1084,8 +1119,8 @@ void pps4_device::iSKZ()
*/ */
void pps4_device::iSKBI() void pps4_device::iSKBI()
{ {
const uint8_t i4 = m_I1 & 15; const u8 i4 = m_I1 & 15;
const uint8_t bl = m_B & 15; const u8 bl = m_B & 15;
m_Skip = bl == i4 ? 1 : 0; 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 * the CPU and sets up the I/O enable signal. The second
* ROM word is then received by the I/O devices and decoded * ROM word is then received by the I/O devices and decoded
* for address and command. The contents of the accumulator * for address and command. The contents of the accumulator
* inverted are placed on the data lines for acceptance by * inverted are placed on the data lines [I/D:4-1] for
* the I/O. At the same time, input data received by the I/O * acceptance by the I/O. At the same time, input data
* device is transferred to the accumulator inverted. * 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 RAM address register (B) is placed on the address bus
* The ROM, RAM, I/O chips A17xx suggest this, because they * during the I/O request cycle. The original RAM chip ignores
* expect the value of BL to address one of the sixteen * 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. * input/output lines.
*/ */
void pps4_device::iIOL() void pps4_device::iIOL()
{ {
uint8_t ac = ((m_B & 15) << 4) | (~m_A & 15); u8 ac = (~m_A & 15);
m_I2 = ARG(); m_I2 = ARG();
m_io->write_byte(m_I2, ac); m_io->write_byte(m_I2, ac);
LOG(("%s: port:%02x <- %x\n", __FUNCTION__, 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() 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() 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() 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(); state_add( STATE_GENFLAGS, "GENFLAGS", m_C).formatstr("%3s").noshow();
m_icountptr = &m_icount; 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 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_I2 = 0; // Most recent parameter I2(8:1)
m_Ip = 0; // Previous instruction I(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_SAG,
PPS4_I1, PPS4_I1,
PPS4_I2, PPS4_I2,
PPS4_Ip, PPS4_Ip
PPS4_PORT_A = 256,
PPS4_PORT_B = 257
}; };
/*************************************************************************** //**************************************************************************
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 FUNCTION PROTOTYPES
***************************************************************************/ ***************************************************************************/
extern const device_type PPS4;
class pps4_device : public cpu_device class pps4_device : public cpu_device
{ {
public: public:
// construction/destruction // 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: protected:
// device-level overrides // device-level overrides
@ -46,10 +68,10 @@ protected:
virtual void device_reset() override; virtual void device_reset() override;
// device_execute_interface overrides // device_execute_interface overrides
virtual uint32_t execute_min_cycles() const override { return 1; } virtual u32 execute_min_cycles() const override { return 1; }
virtual uint32_t execute_max_cycles() const override { return 3; } virtual u32 execute_max_cycles() const override { return 3; }
virtual uint32_t execute_input_lines() const override { return 0; } virtual u32 execute_input_lines() const override { return 0; }
virtual uint32_t execute_default_irq_vector() const override { return 0; } virtual u32 execute_default_irq_vector() const override { return 0; }
virtual void execute_run() override; virtual void execute_run() override;
// device_memory_interface overrides // device_memory_interface overrides
@ -62,47 +84,51 @@ protected:
virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; virtual void state_string_export(const device_state_entry &entry, std::string &str) const override;
// device_disasm_interface overrides // device_disasm_interface overrides
virtual uint32_t disasm_min_opcode_bytes() const override { return 1; } virtual u32 disasm_min_opcode_bytes() const override { return 1; }
virtual uint32_t disasm_max_opcode_bytes() const override { return 2; } virtual u32 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 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_program_config;
address_space_config m_data_config; address_space_config m_data_config;
address_space_config m_io_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; address_space *m_program;
direct_read_data *m_direct; direct_read_data *m_direct;
address_space *m_data; address_space *m_data;
address_space *m_io; address_space *m_io;
int m_icount; int m_icount;
uint8_t m_A; //!< Accumulator A(4:1) u8 m_A; //!< Accumulator A(4:1)
uint8_t m_X; //!< X register X(4:1) u8 m_X; //!< X register X(4:1)
uint16_t m_P; //!< program counter P(12:1) u16 m_P; //!< program counter P(12:1)
uint16_t m_SA; //!< Shift register SA(12:1) u16 m_SA; //!< Shift register SA(12:1)
uint16_t m_SB; //!< Shift register SB(12:1) u16 m_SB; //!< Shift register SB(12:1)
uint8_t m_Skip; //!< Skip next instruction u8 m_Skip; //!< Skip next instruction
uint16_t m_SAG; //!< Special address generation mask u16 m_SAG; //!< Special address generation mask
uint16_t m_B; //!< B register B(12:1) (BL, BM and BH) u16 m_B; //!< B register B(12:1) (BL, BM and BH)
uint8_t m_C; //!< Carry flip-flop u8 m_C; //!< Carry flip-flop
uint8_t m_FF1; //!< Flip-flop 1 u8 m_FF1; //!< Flip-flop 1
uint8_t m_FF2; //!< Flip-flop 2 u8 m_FF2; //!< Flip-flop 2
uint8_t m_I1; //!< Most recent instruction I(8:1) u8 m_I1; //!< Most recent instruction I(8:1)
uint8_t m_I2; //!< Most recent parameter I2(8:1) u8 m_I2; //!< Most recent parameter I2(8:1)
uint8_t m_Ip; //!< Previous instruction I(8:1) u8 m_Ip; //!< Previous instruction I(8:1)
//! return memory at address B(12:1) //! return memory at address B(12:1)
inline uint8_t M(); inline u8 M();
//! write to memory at address B(12:1) //! 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) //! return the next opcode (also in m_I)
inline uint8_t ROP(); inline u8 ROP();
//! return the next argument (also in m_I2) //! return the next argument (also in m_I2)
inline uint8_t ARG(); inline u8 ARG();
void iAD(); //!< Add void iAD(); //!< Add
void iADC(); //!< Add with carry-in void iADC(); //!< Add with carry-in
@ -151,11 +177,33 @@ private:
void iRTNSK(); //!< Return and skip void iRTNSK(); //!< Return and skip
void iIOL(); //!< Input/Output long void iIOL(); //!< Input/Output long
void iDIA(); //!< Discrete input group A void iDIA(); //!< Discrete input group A
void iDIB(); //!< Discrete input group B virtual void iDIB(); //!< Discrete input group B
void iDOA(); //!< Discrete output group A virtual void iDOA(); //!< Discrete output group A
void iSAG(); //!< Special address generation void iSAG(); //!< Special address generation
void execute_one(); //!< execute one instruction 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__ #endif // __PPS4_H__

View File

@ -11,6 +11,7 @@
There are two basic I/O instructions: There are two basic I/O instructions:
SES = Select Enable Status and SOS = Select Output Status 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. 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 There are at most two A17XX per system, one for the lower
ROM and RAM portion and one for the higher. 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__), : device_t(mconfig, RA17XX, "Rockwell A17XX", tag, owner, clock, "ra17xx", __FILE__),
m_enable(false), m_enable(false),
m_iord(*this), 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 ) WRITE8_MEMBER( ra17xx_device::io_w )
{ {
assert(offset < 16); 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 // 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 m_line[m_bl] = 1; // enable output
// if (m_enable) // if (m_enable)
m_iowr(m_bl, 1, 1); m_iowr(m_bl, 1, 1);
} else { }
else
{
m_line[m_bl] = 0; // disable output m_line[m_bl] = 0; // disable output
// if (m_enable) // if (m_enable)
m_iowr(m_bl, 0, 1); m_iowr(m_bl, 0, 1);
} }
} else { }
else
{
// SES command // SES command
if (data & (1 << 3)) { if (data & (1 << 3))
{
// enable all outputs // enable all outputs
m_enable = true; m_enable = true;
for (int i = 0; i < 16; i++) for (int i = 0; i < 16; i++)
m_iowr(i, m_line[i], 1); m_iowr(i, m_line[i], 1);
} else { }
else
{
// disable all outputs // disable all outputs
m_enable = false; m_enable = false;
} }
@ -127,5 +144,5 @@ WRITE8_MEMBER( ra17xx_device::io_w )
READ8_MEMBER( ra17xx_device::io_r ) READ8_MEMBER( ra17xx_device::io_r )
{ {
assert(offset < 16); 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__ #define __RA17XX_H__
#include "device.h" #include "device.h"
#include "cpu/pps4/pps4.h"
/************************************* /*************************************
* *
@ -29,6 +30,10 @@
/* Set the write line handler */ /* Set the write line handler */
#define MCFG_RA17XX_WRITE(_devcb) \ #define MCFG_RA17XX_WRITE(_devcb) \
ra17xx_device::set_iowr(*device, DEVCB_##_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 class ra17xx_device : public device_t
{ {
public: 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_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); } 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: protected:
// device-level overrides // device-level overrides
virtual void device_start() override; virtual void device_start() override;
@ -51,6 +58,7 @@ private:
bool m_enable; //!< true if outputs are enabled bool m_enable; //!< true if outputs are enabled
devcb_read8 m_iord; //!< input line (read, offset = line, data = 0/1) devcb_read8 m_iord; //!< input line (read, offset = line, data = 0/1)
devcb_write8 m_iowr; //!< output line (write, 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; extern const device_type RA17XX;

View File

@ -104,8 +104,7 @@ public:
DECLARE_READ8_MEMBER (gts1_io_r); DECLARE_READ8_MEMBER (gts1_io_r);
DECLARE_WRITE8_MEMBER(gts1_io_w); DECLARE_WRITE8_MEMBER(gts1_io_w);
DECLARE_READ8_MEMBER (gts1_pa_r); DECLARE_READ8_MEMBER (gts1_pa_r);
DECLARE_WRITE8_MEMBER(gts1_pa_w); DECLARE_WRITE8_MEMBER(gts1_do_w);
DECLARE_WRITE8_MEMBER(gts1_pb_w);
private: private:
virtual void machine_reset() override; virtual void machine_reset() override;
required_device<cpu_device> m_maincpu; 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(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(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(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 ADDRESS_MAP_END
static INPUT_PORTS_START( gts1_dips ) static INPUT_PORTS_START( gts1_dips )
@ -669,27 +666,22 @@ READ8_MEMBER (gts1_state::gts1_pa_r)
return data; return data;
} }
WRITE8_MEMBER(gts1_state::gts1_pa_w) WRITE8_MEMBER(gts1_state::gts1_do_w)
{ {
// write address lines 7-4 // write address lines (DO1-4 to A0-3, DIO1-4 to A4-7)
m_6351_addr = (m_6351_addr & 0x0f) | ((data & 0x0f) << 4); m_6351_addr = (m_6351_addr & 0x300) | data;
LOG(("%s: ROM hi:%x addr:%02x\n", __FUNCTION__, data & 0x0f, m_6351_addr)); LOG(("%s: ROM addr:%02x\n", __FUNCTION__, 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));
} }
static MACHINE_CONFIG_START( gts1, gts1_state ) static MACHINE_CONFIG_START( gts1, gts1_state )
/* basic machine hardware */ /* 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_PROGRAM_MAP(gts1_map)
MCFG_CPU_DATA_MAP(gts1_data) MCFG_CPU_DATA_MAP(gts1_data)
MCFG_CPU_IO_MAP(gts1_io) 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") MCFG_NVRAM_ADD_0FILL("nvram")
@ -697,11 +689,13 @@ static MACHINE_CONFIG_START( gts1, gts1_state )
MCFG_DEVICE_ADD( "u5", RA17XX, 0 ) MCFG_DEVICE_ADD( "u5", RA17XX, 0 )
MCFG_RA17XX_READ ( READ8 (gts1_state,gts1_switches_r) ) MCFG_RA17XX_READ ( READ8 (gts1_state,gts1_switches_r) )
MCFG_RA17XX_WRITE( WRITE8(gts1_state,gts1_switches_w) ) 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) */ /* 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_DEVICE_ADD( "u4", RA17XX, 0 )
MCFG_RA17XX_READ ( READ8 (gts1_state,gts1_solenoid_r) ) MCFG_RA17XX_READ ( READ8 (gts1_state,gts1_solenoid_r) )
MCFG_RA17XX_WRITE( WRITE8(gts1_state,gts1_solenoid_w) ) MCFG_RA17XX_WRITE( WRITE8(gts1_state,gts1_solenoid_w) )
MCFG_RA17XX_CPU("maincpu")
/* 10696 General Purpose Input/Output */ /* 10696 General Purpose Input/Output */
MCFG_DEVICE_ADD( "u2", R10696, 0 ) MCFG_DEVICE_ADD( "u2", R10696, 0 )