mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
hmcs400: add i/o ports
This commit is contained in:
parent
2d74a4e866
commit
819379be1e
@ -247,13 +247,8 @@ void hmcs40_cpu_device::device_reset()
|
||||
m_iri = m_irt = 0;
|
||||
m_if[0] = m_if[1] = m_tf = 1;
|
||||
|
||||
// clear i/o
|
||||
m_d = m_polarity;
|
||||
for (int i = 0; i < 16; i++)
|
||||
hmcs40_cpu_device::write_d(i, m_polarity);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
hmcs40_cpu_device::write_r(i, m_polarity & 0xf);
|
||||
// all I/O ports set to input
|
||||
reset_io();
|
||||
}
|
||||
|
||||
|
||||
@ -325,13 +320,22 @@ device_memory_interface::space_config_vector hmcs40_cpu_device::memory_space_con
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// i/o handling
|
||||
// i/o ports
|
||||
//-------------------------------------------------
|
||||
|
||||
u8 hmcs40_cpu_device::read_r(int index)
|
||||
void hmcs40_cpu_device::reset_io()
|
||||
{
|
||||
m_d = m_polarity;
|
||||
m_write_d(m_polarity);
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
hmcs40_cpu_device::write_r(i, m_polarity);
|
||||
}
|
||||
|
||||
u8 hmcs40_cpu_device::read_r(u8 index)
|
||||
{
|
||||
index &= 7;
|
||||
u8 inp = m_read_r[index](index, 0xff);
|
||||
u8 inp = m_read_r[index](index);
|
||||
|
||||
if (m_polarity)
|
||||
return (inp & m_r[index]) & 0xf;
|
||||
@ -339,38 +343,39 @@ u8 hmcs40_cpu_device::read_r(int index)
|
||||
return (inp | m_r[index]) & 0xf;
|
||||
}
|
||||
|
||||
void hmcs40_cpu_device::write_r(int index, u8 data)
|
||||
void hmcs40_cpu_device::write_r(u8 index, u8 data)
|
||||
{
|
||||
index &= 7;
|
||||
data &= 0xf;
|
||||
m_r[index] = data;
|
||||
m_write_r[index](index, data, 0xff);
|
||||
m_write_r[index](index, data);
|
||||
}
|
||||
|
||||
int hmcs40_cpu_device::read_d(int index)
|
||||
int hmcs40_cpu_device::read_d(u8 index)
|
||||
{
|
||||
index &= 15;
|
||||
index &= 0xf;
|
||||
u16 inp = m_read_d(0, 1 << index);
|
||||
|
||||
if (m_polarity)
|
||||
return (m_read_d(index, 0xffff) & m_d) >> index & 1;
|
||||
return BIT(inp & m_d, index);
|
||||
else
|
||||
return (m_read_d(index, 0xffff) | m_d) >> index & 1;
|
||||
return BIT(inp | m_d, index);
|
||||
}
|
||||
|
||||
void hmcs40_cpu_device::write_d(int index, int state)
|
||||
void hmcs40_cpu_device::write_d(u8 index, int state)
|
||||
{
|
||||
index &= 15;
|
||||
state = (state) ? 1 : 0;
|
||||
index &= 0xf;
|
||||
u16 mask = 1 << index;
|
||||
|
||||
m_d = (m_d & ~(1 << index)) | state << index;
|
||||
m_write_d(index, m_d, 0xffff);
|
||||
m_d = (m_d & ~mask) | (state ? mask : 0);
|
||||
m_write_d(0, m_d, mask);
|
||||
}
|
||||
|
||||
// HMCS43:
|
||||
// R0 is input-only, R1 is i/o, R2,R3 are output-only, no R4-R7
|
||||
// D0-D3 are i/o, D4-D15 are output-only
|
||||
|
||||
u8 hmcs43_cpu_device::read_r(int index)
|
||||
u8 hmcs43_cpu_device::read_r(u8 index)
|
||||
{
|
||||
index &= 7;
|
||||
|
||||
@ -380,7 +385,7 @@ u8 hmcs43_cpu_device::read_r(int index)
|
||||
return hmcs40_cpu_device::read_r(index);
|
||||
}
|
||||
|
||||
void hmcs43_cpu_device::write_r(int index, u8 data)
|
||||
void hmcs43_cpu_device::write_r(u8 index, u8 data)
|
||||
{
|
||||
index &= 7;
|
||||
|
||||
@ -390,7 +395,7 @@ void hmcs43_cpu_device::write_r(int index, u8 data)
|
||||
logerror("ineffective write to port R%d = $%X at $%04X\n", index, data & 0xf, m_prev_pc);
|
||||
}
|
||||
|
||||
int hmcs43_cpu_device::read_d(int index)
|
||||
int hmcs43_cpu_device::read_d(u8 index)
|
||||
{
|
||||
index &= 15;
|
||||
|
||||
@ -404,7 +409,7 @@ int hmcs43_cpu_device::read_d(int index)
|
||||
// R0-R3 are i/o, R4,R5 are extra registers, no R6,R7
|
||||
// D0-D15 are i/o
|
||||
|
||||
u8 hmcs44_cpu_device::read_r(int index)
|
||||
u8 hmcs44_cpu_device::read_r(u8 index)
|
||||
{
|
||||
index &= 7;
|
||||
|
||||
@ -414,7 +419,7 @@ u8 hmcs44_cpu_device::read_r(int index)
|
||||
return hmcs40_cpu_device::read_r(index);
|
||||
}
|
||||
|
||||
void hmcs44_cpu_device::write_r(int index, u8 data)
|
||||
void hmcs44_cpu_device::write_r(u8 index, u8 data)
|
||||
{
|
||||
index &= 7;
|
||||
|
||||
@ -428,7 +433,7 @@ void hmcs44_cpu_device::write_r(int index, u8 data)
|
||||
// R0-R5 are i/o, R6 is output-only, no R7
|
||||
// D0-D15 are i/o
|
||||
|
||||
u8 hmcs45_cpu_device::read_r(int index)
|
||||
u8 hmcs45_cpu_device::read_r(u8 index)
|
||||
{
|
||||
index &= 7;
|
||||
|
||||
@ -438,7 +443,7 @@ u8 hmcs45_cpu_device::read_r(int index)
|
||||
return hmcs40_cpu_device::read_r(index);
|
||||
}
|
||||
|
||||
void hmcs45_cpu_device::write_r(int index, u8 data)
|
||||
void hmcs45_cpu_device::write_r(u8 index, u8 data)
|
||||
{
|
||||
index &= 7;
|
||||
|
||||
@ -450,7 +455,7 @@ void hmcs45_cpu_device::write_r(int index, u8 data)
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// interrupt/timer handling
|
||||
// interrupt/timer
|
||||
//-------------------------------------------------
|
||||
|
||||
void hmcs40_cpu_device::do_interrupt()
|
||||
|
@ -12,7 +12,7 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
// I/O ports setup
|
||||
// input lines
|
||||
|
||||
enum
|
||||
{
|
||||
@ -195,10 +195,11 @@ protected:
|
||||
void pop_stack();
|
||||
void push_stack();
|
||||
|
||||
virtual u8 read_r(int index);
|
||||
virtual void write_r(int index, u8 data);
|
||||
virtual int read_d(int index);
|
||||
virtual void write_d(int index, int state);
|
||||
virtual void reset_io();
|
||||
virtual u8 read_r(u8 index);
|
||||
virtual void write_r(u8 index, u8 data);
|
||||
virtual int read_d(u8 index);
|
||||
virtual void write_d(u8 index, int state);
|
||||
|
||||
void cycle();
|
||||
void increment_tc();
|
||||
@ -309,9 +310,9 @@ protected:
|
||||
hmcs43_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 polarity);
|
||||
|
||||
// overrides
|
||||
virtual u8 read_r(int index) override;
|
||||
virtual void write_r(int index, u8 data) override;
|
||||
virtual int read_d(int index) override;
|
||||
virtual u8 read_r(u8 index) override;
|
||||
virtual void write_r(u8 index, u8 data) override;
|
||||
virtual int read_d(u8 index) override;
|
||||
};
|
||||
|
||||
class hd38750_device : public hmcs43_cpu_device
|
||||
@ -345,8 +346,8 @@ protected:
|
||||
hmcs44_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 polarity);
|
||||
|
||||
// overrides
|
||||
virtual u8 read_r(int index) override;
|
||||
virtual void write_r(int index, u8 data) override;
|
||||
virtual u8 read_r(u8 index) override;
|
||||
virtual void write_r(u8 index, u8 data) override;
|
||||
};
|
||||
|
||||
class hd38800_device : public hmcs44_cpu_device
|
||||
@ -380,8 +381,8 @@ protected:
|
||||
hmcs45_cpu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, u16 polarity);
|
||||
|
||||
// overrides
|
||||
virtual u8 read_r(int index) override;
|
||||
virtual void write_r(int index, u8 data) override;
|
||||
virtual u8 read_r(u8 index) override;
|
||||
virtual void write_r(u8 index, u8 data) override;
|
||||
};
|
||||
|
||||
class hd38820_device : public hmcs45_cpu_device
|
||||
|
@ -663,24 +663,24 @@ void hmcs40_cpu_device::op_lrb()
|
||||
|
||||
void hmcs40_cpu_device::op_p()
|
||||
{
|
||||
// P p: Pattern Generation
|
||||
cycle();
|
||||
|
||||
// P p: Pattern Generation
|
||||
u16 address = m_a | m_b << 4 | m_c << 8 | (m_op & 7) << 9 | (m_pc & ~0x3f);
|
||||
u16 o = m_program->read_word(address & m_prgmask);
|
||||
u16 data = m_program->read_word(address & m_prgmask);
|
||||
|
||||
// destination is determined by the 2 highest bits
|
||||
if (o & 0x100)
|
||||
if (data & 0x100)
|
||||
{
|
||||
// B3 B2 B1 B0 A0 A1 A2 A3
|
||||
m_a = bitswap<4>(o,0,1,2,3);
|
||||
m_b = o >> 4 & 0xf;
|
||||
m_a = bitswap<4>(data,0,1,2,3);
|
||||
m_b = data >> 4 & 0xf;
|
||||
}
|
||||
if (o & 0x200)
|
||||
if (data & 0x200)
|
||||
{
|
||||
// R20 R21 R22 R23 R30 R31 R32 R33
|
||||
o = bitswap<8>(o,0,1,2,3,4,5,6,7);
|
||||
write_r(2, o & 0xf);
|
||||
write_r(3, o >> 4 & 0xf);
|
||||
data = bitswap<8>(data,0,1,2,3,4,5,6,7);
|
||||
write_r(2, data & 0xf);
|
||||
write_r(3, data >> 4 & 0xf);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,8 @@ TODO:
|
||||
way to save this register when using interrupts
|
||||
- what happens when accessing ROM/RAM out of address range? Hitachi documentation
|
||||
says 'unused', but maybe it's mirrored?
|
||||
- current I/O ports are hardcoded for HMS402/4/8, which will need to be changed
|
||||
when other MCU types are added
|
||||
|
||||
*/
|
||||
|
||||
@ -73,7 +75,11 @@ hmcs400_cpu_device::hmcs400_cpu_device(const machine_config &mconfig, device_typ
|
||||
m_rom_size(rom_size),
|
||||
m_ram_size(ram_size),
|
||||
m_has_div(false),
|
||||
m_divider(8)
|
||||
m_divider(8),
|
||||
m_read_r(*this, 0),
|
||||
m_write_r(*this),
|
||||
m_read_d(*this, 0),
|
||||
m_write_d(*this)
|
||||
{ }
|
||||
|
||||
hmcs400_cpu_device::~hmcs400_cpu_device() { }
|
||||
@ -185,8 +191,6 @@ void hmcs400_cpu_device::device_start()
|
||||
save_item(NAME(m_prev_pc));
|
||||
save_item(NAME(m_sp));
|
||||
save_item(NAME(m_op));
|
||||
save_item(NAME(m_param));
|
||||
save_item(NAME(m_i));
|
||||
|
||||
save_item(NAME(m_a));
|
||||
save_item(NAME(m_b));
|
||||
@ -198,6 +202,9 @@ void hmcs400_cpu_device::device_start()
|
||||
save_item(NAME(m_st));
|
||||
save_item(NAME(m_ca));
|
||||
|
||||
save_item(NAME(m_r));
|
||||
save_item(NAME(m_d));
|
||||
|
||||
// register state for debugger
|
||||
state_add(STATE_GENPC, "GENPC", m_pc).formatstr("%04X").noshow();
|
||||
state_add(STATE_GENPCBASE, "CURPC", m_pc).formatstr("%04X").noshow();
|
||||
@ -225,6 +232,9 @@ void hmcs400_cpu_device::device_reset()
|
||||
m_pc = 0;
|
||||
m_sp = 0x3ff;
|
||||
m_st = 1;
|
||||
|
||||
// all I/O ports set to input
|
||||
reset_io();
|
||||
}
|
||||
|
||||
|
||||
@ -278,6 +288,78 @@ device_memory_interface::space_config_vector hmcs400_cpu_device::memory_space_co
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// i/o ports
|
||||
//-------------------------------------------------
|
||||
|
||||
void hmcs400_cpu_device::reset_io()
|
||||
{
|
||||
// D4-D15 are high-voltage
|
||||
m_d_mask = m_d = 0x000f;
|
||||
m_write_d(m_d_mask);
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
// R0-R2 and RA are high-voltage
|
||||
u8 mask = (i >= 3 && i <= 9) ? 0xf : 0;
|
||||
|
||||
m_r_mask[i] = m_r[i] = mask;
|
||||
m_write_r[i](i, mask);
|
||||
}
|
||||
}
|
||||
|
||||
u8 hmcs400_cpu_device::read_r(u8 index)
|
||||
{
|
||||
// reads from write-only or non-existent ports are invalid
|
||||
bool write_only = index == 0 || (index >= 6 && index <= 8);
|
||||
if (write_only || index > 10)
|
||||
{
|
||||
logerror("read from %s port R%X at $%04X\n", write_only ? "output" : "unknown", index, m_prev_pc);
|
||||
return 0xf;
|
||||
}
|
||||
|
||||
u8 inp = m_read_r[index].isunset() ? m_r_mask[index] : m_read_r[index](index);
|
||||
u8 mask = (index == 10) ? 3 : 0xf; // port A is 2-bit
|
||||
|
||||
if (m_r_mask[index])
|
||||
return (inp & m_r[index]) & mask;
|
||||
else
|
||||
return (inp | m_r[index]) & mask;
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::write_r(u8 index, u8 data)
|
||||
{
|
||||
// ignore writes to read-only or non-existent ports
|
||||
if (index > 8)
|
||||
return;
|
||||
|
||||
data &= 0xf;
|
||||
m_r[index] = data;
|
||||
m_write_r[index](index, data);
|
||||
}
|
||||
|
||||
int hmcs400_cpu_device::read_d(u8 index)
|
||||
{
|
||||
index &= 0xf;
|
||||
u16 mask = 1 << index;
|
||||
u16 inp = m_read_d.isunset() ? m_d_mask : m_read_d(0, mask);
|
||||
|
||||
if (m_d_mask & mask)
|
||||
return BIT(inp & m_d, index);
|
||||
else
|
||||
return BIT(inp | m_d, index);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::write_d(u8 index, int state)
|
||||
{
|
||||
index &= 0xf;
|
||||
u16 mask = 1 << index;
|
||||
|
||||
m_d = (m_d & ~mask) | (state ? mask : 0);
|
||||
m_write_d(0, m_d, mask);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// execute
|
||||
//-------------------------------------------------
|
||||
|
@ -19,6 +19,14 @@ public:
|
||||
|
||||
// configuration helpers
|
||||
|
||||
// 10 4-bit R ports (port A is 2-bit)
|
||||
template <std::size_t N> auto read_r() { return m_read_r[N].bind(); }
|
||||
template <std::size_t N> auto write_r() { return m_write_r[N].bind(); }
|
||||
|
||||
// 16-bit discrete
|
||||
auto read_d() { return m_read_d.bind(); }
|
||||
auto write_d() { return m_write_d.bind(); }
|
||||
|
||||
// system clock divider mask option (only for HMCS408, HMCS414, HMCS424)
|
||||
// valid options: 4, 8, 16, default to 8
|
||||
auto &set_divider(u8 div) { assert(m_has_div); m_divider = div; return *this; }
|
||||
@ -81,7 +89,16 @@ protected:
|
||||
u8 m_st; // status flag
|
||||
u8 m_ca; // carry flag
|
||||
|
||||
u16 fetch();
|
||||
u8 m_r[10]; // R outputs state
|
||||
u8 m_r_mask[10];
|
||||
u16 m_d; // D pins state
|
||||
u16 m_d_mask;
|
||||
|
||||
// I/O handlers
|
||||
devcb_read8::array<8> m_read_r;
|
||||
devcb_write8::array<8> m_write_r;
|
||||
devcb_read16 m_read_d;
|
||||
devcb_write16 m_write_d;
|
||||
|
||||
// misc internal helpers
|
||||
u8 ram_r(u8 mem_mask = 0xf);
|
||||
@ -89,7 +106,14 @@ protected:
|
||||
void pop_stack();
|
||||
void push_stack();
|
||||
|
||||
void reset_io();
|
||||
u8 read_r(u8 index);
|
||||
void write_r(u8 index, u8 data);
|
||||
int read_d(u8 index);
|
||||
void write_d(u8 index, int state);
|
||||
|
||||
void cycle();
|
||||
u16 fetch();
|
||||
|
||||
// opcode handlers
|
||||
void op_illegal();
|
||||
|
@ -534,9 +534,9 @@ void hmcs400_cpu_device::op_cal()
|
||||
// CAL a: Subroutine Jump on Status 1
|
||||
if (m_st)
|
||||
{
|
||||
cycle();
|
||||
push_stack();
|
||||
m_pc = m_op & 0x3f;
|
||||
cycle();
|
||||
}
|
||||
else
|
||||
m_st = 1;
|
||||
@ -563,9 +563,9 @@ void hmcs400_cpu_device::op_tbr()
|
||||
void hmcs400_cpu_device::op_rtn()
|
||||
{
|
||||
// RTN: Return from Subroutine
|
||||
cycle();
|
||||
cycle();
|
||||
pop_stack();
|
||||
cycle();
|
||||
cycle();
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_rtni()
|
||||
@ -580,56 +580,82 @@ void hmcs400_cpu_device::op_rtni()
|
||||
void hmcs400_cpu_device::op_sed()
|
||||
{
|
||||
// SED: Set Discrete I/O Latch
|
||||
write_d(m_y, 1);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_sedd()
|
||||
{
|
||||
// SEDD m: Set Discrete I/O Latch Direct
|
||||
write_d(m_i, 1);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_red()
|
||||
{
|
||||
// RED: Reset Discrete I/O Latch
|
||||
write_d(m_y, 0);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_redd()
|
||||
{
|
||||
// REDD m: Reset Discrete I/O Latch Direct
|
||||
write_d(m_i, 0);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_td()
|
||||
{
|
||||
// TD: Test Discrete I/O Latch
|
||||
m_st = read_d(m_y);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_tdd()
|
||||
{
|
||||
// TDD m: Test Discrete I/O Latch Direct
|
||||
m_st = read_d(m_i);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_lar()
|
||||
{
|
||||
// LAR m: Load A from R Port Register
|
||||
m_a = read_r(m_i);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_lbr()
|
||||
{
|
||||
// LBR m: Load B from R Port Register
|
||||
m_b = read_r(m_i);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_lra()
|
||||
{
|
||||
// LRA m: Load R Port Register from A
|
||||
write_r(m_i, m_a);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_lrb()
|
||||
{
|
||||
// LRB m: Load R Port Register from B
|
||||
write_r(m_i, m_b);
|
||||
}
|
||||
|
||||
void hmcs400_cpu_device::op_p()
|
||||
{
|
||||
// P p: Pattern Generation
|
||||
cycle();
|
||||
u16 data = m_program->read_word(m_i << 8 | m_b << 4 | m_a);
|
||||
|
||||
// destination is determined by the 2 highest bits
|
||||
if (data & 0x100)
|
||||
{
|
||||
// to A/B registers
|
||||
m_a = data & 0xf;
|
||||
m_b = data >> 4 & 0xf;
|
||||
}
|
||||
if (data & 0x200)
|
||||
{
|
||||
// to R1/R2 ports
|
||||
write_r(1, data & 0xf);
|
||||
write_r(2, data >> 4 & 0xf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user