mirror of
https://github.com/holub/mame
synced 2025-04-23 17:00:53 +03:00
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:
parent
aabdd13259
commit
f5bcff30f6
@ -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;
|
||||
}
|
||||
|
@ -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__
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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 )
|
||||
|
Loading…
Reference in New Issue
Block a user