mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
pps41: add some i/o opcodes
This commit is contained in:
parent
3f4045e8ea
commit
d608ebfa41
@ -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;
|
||||
}
|
||||
|
@ -43,6 +43,7 @@ protected:
|
||||
virtual void device_start() override;
|
||||
|
||||
// opcode handlers
|
||||
virtual void op_ibm() override;
|
||||
virtual void op_ios() override;
|
||||
};
|
||||
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user