summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2021-03-06 18:52:30 +0100
committer hap <happppp@users.noreply.github.com>2021-03-06 18:52:58 +0100
commitd608ebfa412d3cca7d2e9f77ace7e0c218812663 (patch)
treeee199cc8348405a71225c77db86a5333eb29623b
parent3f4045e8eab839dd35199675d7bac475e343a0c4 (diff)
pps41: add some i/o opcodes
-rw-r--r--src/devices/cpu/pps41/mm75.cpp3
-rw-r--r--src/devices/cpu/pps41/mm75.h1
-rw-r--r--src/devices/cpu/pps41/mm75op.cpp6
-rw-r--r--src/devices/cpu/pps41/mm76.cpp9
-rw-r--r--src/devices/cpu/pps41/mm76op.cpp105
-rw-r--r--src/devices/cpu/pps41/pps41base.cpp34
-rw-r--r--src/devices/cpu/pps41/pps41base.h17
7 files changed, 138 insertions, 37 deletions
diff --git a/src/devices/cpu/pps41/mm75.cpp b/src/devices/cpu/pps41/mm75.cpp
index a0fe7e2bc40..d1d4a324235 100644
--- a/src/devices/cpu/pps41/mm75.cpp
+++ b/src/devices/cpu/pps41/mm75.cpp
@@ -10,7 +10,7 @@
#include "mm75.h"
-DEFINE_DEVICE_TYPE(MM75, mm75_device, "mm75", "Rockwell MM75")
+DEFINE_DEVICE_TYPE(MM75, mm75_device, "mm75", "Rockwell MM75") // stripped-down MM76 (no serial i/o, less pins)
// constructor
@@ -24,4 +24,5 @@ void mm75_device::device_start()
{
mm76_device::device_start();
m_d_pins--;
+ m_d_mask >>= 1;
}
diff --git a/src/devices/cpu/pps41/mm75.h b/src/devices/cpu/pps41/mm75.h
index f2950207dc8..5dd036a1086 100644
--- a/src/devices/cpu/pps41/mm75.h
+++ b/src/devices/cpu/pps41/mm75.h
@@ -43,6 +43,7 @@ protected:
virtual void device_start() override;
// opcode handlers
+ virtual void op_ibm() override;
virtual void op_ios() override;
};
diff --git a/src/devices/cpu/pps41/mm75op.cpp b/src/devices/cpu/pps41/mm75op.cpp
index bea107b9fc4..3f0769ebc8f 100644
--- a/src/devices/cpu/pps41/mm75op.cpp
+++ b/src/devices/cpu/pps41/mm75op.cpp
@@ -9,6 +9,12 @@
// opcodes (differences with mm76_device)
+void mm75_device::op_ibm()
+{
+ // IBM: does not PI5-8 pins
+ op_illegal();
+}
+
void mm75_device::op_ios()
{
// IOS: does not have serial I/O
diff --git a/src/devices/cpu/pps41/mm76.cpp b/src/devices/cpu/pps41/mm76.cpp
index 11041e25ad2..38ce96ea67a 100644
--- a/src/devices/cpu/pps41/mm76.cpp
+++ b/src/devices/cpu/pps41/mm76.cpp
@@ -12,10 +12,10 @@
#include "pps41d.h"
-DEFINE_DEVICE_TYPE(MM76, mm76_device, "mm76", "Rockwell MM76")
-DEFINE_DEVICE_TYPE(MM76L, mm76l_device, "mm76l", "Rockwell MM76L")
-DEFINE_DEVICE_TYPE(MM76E, mm76e_device, "mm76e", "Rockwell MM76E")
-DEFINE_DEVICE_TYPE(MM76EL, mm76el_device, "mm76el", "Rockwell MM76EL")
+DEFINE_DEVICE_TYPE(MM76, mm76_device, "mm76", "Rockwell MM76") // 640 bytes ROM, 48 bytes RAM
+DEFINE_DEVICE_TYPE(MM76L, mm76l_device, "mm76l", "Rockwell MM76L") // low-power
+DEFINE_DEVICE_TYPE(MM76E, mm76e_device, "mm76e", "Rockwell MM76E") // ROM extended to 1KB
+DEFINE_DEVICE_TYPE(MM76EL, mm76el_device, "mm76el", "Rockwell MM76EL") // low-power
// constructor
@@ -82,7 +82,6 @@ void mm76_device::device_start()
{
pps41_base_device::device_start();
m_stack_levels = 1;
- m_d_pins = 10;
}
void mm76_device::device_reset()
diff --git a/src/devices/cpu/pps41/mm76op.cpp b/src/devices/cpu/pps41/mm76op.cpp
index fced467662c..eb0537cb78e 100644
--- a/src/devices/cpu/pps41/mm76op.cpp
+++ b/src/devices/cpu/pps41/mm76op.cpp
@@ -89,23 +89,83 @@ void mm76_device::op_eob()
void mm76_device::op_sb()
{
- // Bu != 3: SB x: set memory bit
- // Bu == 3: SOS: set output
- op_todo();
+ // SB x: set memory bit / SOS: set output
+
+ // Bu rising: opcode is invalid
+ if ((m_prev2_b & 0x30) != 0x30 && (m_prev_b & 0x30) == 0x30)
+ {
+ logerror("SB/SOS invalid access at $%03X\n", m_prev_pc);
+ return;
+ }
+
+ // Bu falling or Bu == 3: SOS
+ if (((m_prev2_b & 0x30) == 0x30 && (m_prev_b & 0x30) != 0x30) || (m_prev_b & 0x30) == 0x30)
+ {
+ if ((m_ram_addr & 0xf) > m_d_pins)
+ logerror("SOS invalid pin %d at $%03X\n", m_ram_addr & 0xf, m_prev_pc);
+ else
+ {
+ m_d_output = (m_d_output | (1 << (m_ram_addr & 0xf))) & m_d_mask;
+ m_write_d(m_d_output);
+ }
+ }
+
+ // Bu != 3: SB
+ if ((m_prev_b & 0x30) != 0x30)
+ ram_w(ram_r() | (1 << (m_op & 3)));
}
void mm76_device::op_rb()
{
- // Bu != 3: RB x: reset memory bit
- // Bu == 3: ROS: reset output
- op_todo();
+ // RB x: reset memory bit / ROS: reset output
+
+ // Bu rising: opcode is invalid
+ if ((m_prev2_b & 0x30) != 0x30 && (m_prev_b & 0x30) == 0x30)
+ {
+ logerror("RB/ROS invalid access at $%03X\n", m_prev_pc);
+ return;
+ }
+
+ // Bu falling or Bu == 3: ROS
+ if (((m_prev2_b & 0x30) == 0x30 && (m_prev_b & 0x30) != 0x30) || (m_prev_b & 0x30) == 0x30)
+ {
+ if ((m_ram_addr & 0xf) > m_d_pins)
+ logerror("ROS invalid pin %d at $%03X\n", m_ram_addr & 0xf, m_prev_pc);
+ else
+ {
+ m_d_output = m_d_output & ~(1 << (m_ram_addr & 0xf));
+ m_write_d(m_d_output);
+ }
+ }
+
+ // Bu != 3: RB
+ if ((m_prev_b & 0x30) != 0x30)
+ ram_w(ram_r() & ~(1 << (m_op & 3)));
}
void mm76_device::op_skbf()
{
- // Bu != 3: SKBF x: test memory bit
- // Bu == 3: SKISL: test input
- op_todo();
+ // SKBF x: test memory bit / SKISL: test input
+
+ // Bu rising: opcode is invalid
+ if ((m_prev2_b & 0x30) != 0x30 && (m_prev_b & 0x30) == 0x30)
+ {
+ logerror("SKBF/SKISL invalid access at $%03X\n", m_prev_pc);
+ return;
+ }
+
+ // Bu falling or Bu == 3: SKISL
+ if (((m_prev2_b & 0x30) == 0x30 && (m_prev_b & 0x30) != 0x30) || (m_prev_b & 0x30) == 0x30)
+ {
+ if ((m_ram_addr & 0xf) > m_d_pins)
+ logerror("SKISL invalid pin %d at $%03X\n", m_ram_addr & 0xf, m_prev_pc);
+ else
+ m_skip = !BIT((m_d_output | m_read_d()) & m_d_mask, m_ram_addr & 0xf);
+ }
+
+ // Bu != 3: SKBF
+ if ((m_prev_b & 0x30) != 0x30)
+ m_skip = m_skip || !BIT(ram_r(), m_op & 3);
}
@@ -257,7 +317,7 @@ void mm76_device::op_t()
cycle();
// jumps from subroutine pages reset page to SR1
- u16 mask = m_prgmask ^ 0x7f;
+ u16 mask = m_prgmask & ~0x7f;
if ((m_pc & mask) == mask)
m_pc &= ~0x40;
@@ -277,11 +337,11 @@ void mm76_device::op_tm()
cycle();
// calls from subroutine pages don't push PC
- u16 mask = m_prgmask ^ 0x7f;
+ u16 mask = m_prgmask & ~0x7f;
if ((m_pc & mask) != mask)
push_pc();
- m_pc = ((~m_op & 0x3f) | ~0x3f) & m_prgmask;
+ m_pc = ((m_prgmask & ~0x3f) | (~m_op & 0x3f));
}
void mm76_device::op_tml()
@@ -324,24 +384,27 @@ void mm76_device::op_skaei()
void mm76_device::op_ibm()
{
// IBM: input channel B to A
+ m_a &= (m_read_r() & m_r_output) >> 4;
}
void mm76_device::op_ob()
{
// OB: output from A to channel B
- op_todo();
+ m_r_output = (m_r_output & 0xf) | m_a << 4;
+ m_write_r(m_r_output);
}
void mm76_device::op_iam()
{
// IAM: input channel A to A
- op_todo();
+ m_a &= m_read_r() & m_r_output;
}
void mm76_device::op_oa()
{
// OA: output from A to channel A
- op_todo();
+ m_r_output = (m_r_output & ~0xf) | m_a;
+ m_write_r(m_r_output);
}
void mm76_device::op_ios()
@@ -353,13 +416,13 @@ void mm76_device::op_ios()
void mm76_device::op_i1()
{
// I1: input channel 1 to A
- op_todo();
+ m_a = m_read_p() & 0xf;
}
void mm76_device::op_i2c()
{
// I2C: input channel 2 to A
- op_todo();
+ m_a = ~m_read_p() >> 4 & 0xf;
}
void mm76_device::op_int1h()
@@ -389,11 +452,15 @@ void mm76_device::op_din0()
void mm76_device::op_seg1()
{
// SEG1: output A+carry through PLA to channel A
- op_todo();
+ u8 out = bitswap<8>(m_opla->read((m_c_in << 4 | (ram_r() & ~m_a)) ^ 0x1f), 7,5,3,1,0,2,4,6);
+ m_r_output = (m_r_output & ~0xf) | (out & 0xf);
+ m_write_r(m_r_output);
}
void mm76_device::op_seg2()
{
// SEG2: output A+carry through PLA to channel B
- op_todo();
+ u8 out = bitswap<8>(m_opla->read((m_c_in << 4 | (ram_r() & ~m_a)) ^ 0x1f), 7,5,3,1,0,2,4,6);
+ m_r_output = (m_r_output & 0xf) | (out & 0xf0);
+ m_write_r(m_r_output);
}
diff --git a/src/devices/cpu/pps41/pps41base.cpp b/src/devices/cpu/pps41/pps41base.cpp
index 4177c4c4841..d0d99dc960d 100644
--- a/src/devices/cpu/pps41/pps41base.cpp
+++ b/src/devices/cpu/pps41/pps41base.cpp
@@ -32,7 +32,15 @@ References:
TODO:
- add extended opcodes to disasm? it's easy to add there, but the emulation goes
through prefixes 1 cycle at the time which means the live disasm gets messy
-- WIP
+- documentation discourages long jumps to the subroutine pages, but does not
+ explain what would happen
+- documentation discourages use of some extended opcodes when in subroutine pages,
+ but again does not explain why
+- documentation is conflicting whether or not MM76/MM75 can (re)set interrupt flip-
+ flops with SOS/ROS opcodes
+- add serial i/o
+- add pseudo interrupts
+- add MM78
*/
@@ -49,6 +57,9 @@ pps41_base_device::pps41_base_device(const machine_config &mconfig, device_type
m_prgwidth(prgwidth),
m_datawidth(datawidth),
m_opla(*this, "opla"),
+ m_read_p(*this),
+ m_read_d(*this),
+ m_write_d(*this),
m_read_r(*this),
m_write_r(*this)
{ }
@@ -71,7 +82,10 @@ void pps41_base_device::device_start()
m_datamask = (1 << m_datawidth) - 1;
// resolve callbacks
- m_read_r.resolve_safe(0);
+ m_read_p.resolve_safe(0xff);
+ m_read_d.resolve_safe(0);
+ m_write_d.resolve_safe();
+ m_read_r.resolve_safe(0xff);
m_write_r.resolve_safe();
// zerofill
@@ -98,8 +112,10 @@ void pps41_base_device::device_start()
m_skip = false;
m_skip_count = 0;
- m_cha = 0;
- m_chb = 0;
+ m_d_pins = 10;
+ m_d_mask = (1 << m_d_pins) - 1;
+ m_d_output = 0;
+ m_r_output = 0;
// register for savestates
save_item(NAME(m_pc));
@@ -125,8 +141,8 @@ void pps41_base_device::device_start()
save_item(NAME(m_skip));
save_item(NAME(m_skip_count));
- save_item(NAME(m_cha));
- save_item(NAME(m_chb));
+ save_item(NAME(m_d_output));
+ save_item(NAME(m_r_output));
// register state for debugger
state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%03X").noshow();
@@ -156,14 +172,14 @@ device_memory_interface::space_config_vector pps41_base_device::memory_space_con
void pps41_base_device::device_reset()
{
- m_op = m_prev_op = 0;
+ m_op = m_prev_op = m_prev2_op = 0;
m_pc = m_prgmask >> 1 & ~0x3f;
m_skip = false;
m_skip_count = 0;
// clear outputs
- m_cha = m_chb = 0xf;
- m_write_r(0);
+ m_write_r(m_r_output = 0xff);
+ m_write_d(m_d_output = 0);
}
diff --git a/src/devices/cpu/pps41/pps41base.h b/src/devices/cpu/pps41/pps41base.h
index 5157e53f417..0834a38fb96 100644
--- a/src/devices/cpu/pps41/pps41base.h
+++ b/src/devices/cpu/pps41/pps41base.h
@@ -20,6 +20,13 @@ public:
// configuration helpers
// I/O ports:
+ // 8-bit P(parallel) input
+ auto read_p() { return m_read_p.bind(); }
+
+ // 10-bit D(discrete) I/O
+ auto read_d() { return m_read_d.bind(); }
+ auto write_d() { return m_write_d.bind(); }
+
// 8-bit R I/O
auto read_r() { return m_read_r.bind(); }
auto write_r() { return m_write_r.bind(); }
@@ -61,6 +68,9 @@ protected:
optional_device<pla_device> m_opla; // segment output PLA
// i/o handlers
+ devcb_read8 m_read_p;
+ devcb_read16 m_read_d;
+ devcb_write16 m_write_d;
devcb_read8 m_read_r;
devcb_write8 m_write_r;
@@ -73,7 +83,6 @@ protected:
u8 m_prev3_op;
int m_stack_levels;
u16 m_stack[2]; // max 2
- int m_d_pins;
u8 m_a;
u8 m_b;
@@ -90,8 +99,10 @@ protected:
bool m_skip;
int m_skip_count;
- u8 m_cha;
- u8 m_chb;
+ int m_d_pins;
+ u16 m_d_mask;
+ u16 m_d_output;
+ u8 m_r_output;
// misc handlers
virtual bool op_is_tr(u8 op) = 0;