mirror of
https://github.com/holub/mame
synced 2025-04-16 05:24:54 +03:00
sm590: added i/o ports
This commit is contained in:
parent
ca467d4cdb
commit
f1f36c9ba0
@ -36,15 +36,15 @@ void sm500_device::data_4x10x4(address_map &map)
|
||||
|
||||
|
||||
// device definitions
|
||||
sm500_device::sm500_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm500_device(mconfig, SM500, tag, owner, clock, 1 /* stack levels */, 7 /* o group pins */, 11 /* prg width */, address_map_constructor(FUNC(sm500_device::program_1_2k), this), 6 /* data width */, address_map_constructor(FUNC(sm500_device::data_4x10x4), this))
|
||||
{ }
|
||||
|
||||
sm500_device::sm500_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int o_pins, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) :
|
||||
sm510_base_device(mconfig, type, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data),
|
||||
m_o_pins(o_pins)
|
||||
{ }
|
||||
|
||||
sm500_device::sm500_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm500_device(mconfig, SM500, tag, owner, clock, 1 /* stack levels */, 7 /* o group pins */, 11 /* prg width */, address_map_constructor(FUNC(sm500_device::program_1_2k), this), 6 /* data width */, address_map_constructor(FUNC(sm500_device::data_4x10x4), this))
|
||||
{ }
|
||||
|
||||
|
||||
// disasm
|
||||
std::unique_ptr<util::disasm_interface> sm500_device::create_disassembler()
|
||||
|
@ -36,6 +36,7 @@ void sm510_base_device::device_start()
|
||||
m_data = &space(AS_DATA);
|
||||
m_prgmask = (1 << m_prgwidth) - 1;
|
||||
m_datamask = (1 << m_datawidth) - 1;
|
||||
m_pagemask = 0x3f;
|
||||
|
||||
// resolve callbacks
|
||||
m_read_k.resolve_safe(0);
|
||||
@ -266,8 +267,9 @@ void sm510_base_device::increment_pc()
|
||||
{
|
||||
// PL(program counter low 6 bits) is a simple LFSR: newbit = (bit0==bit1)
|
||||
// PU,PM(high bits) specify page, PL specifies steps within page
|
||||
int feed = ((m_pc >> 1 ^ m_pc) & 1) ? 0 : 0x20;
|
||||
m_pc = feed | (m_pc >> 1 & 0x1f) | (m_pc & ~0x3f);
|
||||
int msb = m_pagemask >> 1 ^ m_pagemask;
|
||||
int feed = ((m_pc >> 1 ^ m_pc) & 1) ? 0 : msb;
|
||||
m_pc = feed | (m_pc >> 1 & m_pagemask >> 1) | (m_pc & ~m_pagemask);
|
||||
}
|
||||
|
||||
void sm510_base_device::execute_run()
|
||||
|
@ -37,21 +37,24 @@ class sm510_base_device : public cpu_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
sm510_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data)
|
||||
: cpu_device(mconfig, type, tag, owner, clock)
|
||||
, m_program_config("program", ENDIANNESS_LITTLE, 8, prgwidth, 0, program)
|
||||
, m_data_config("data", ENDIANNESS_LITTLE, 8, datawidth, 0, data)
|
||||
, m_prgwidth(prgwidth)
|
||||
, m_datawidth(datawidth)
|
||||
, m_stack_levels(stack_levels)
|
||||
, m_r_mask_option(RMASK_DIRECT)
|
||||
, m_lcd_ram_a(*this, "lcd_ram_a"), m_lcd_ram_b(*this, "lcd_ram_b"), m_lcd_ram_c(*this, "lcd_ram_c")
|
||||
, m_write_segs(*this)
|
||||
, m_melody_rom(*this, "melody")
|
||||
, m_read_k(*this)
|
||||
, m_read_ba(*this), m_read_b(*this)
|
||||
, m_write_s(*this)
|
||||
, m_write_r(*this)
|
||||
sm510_base_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) :
|
||||
cpu_device(mconfig, type, tag, owner, clock),
|
||||
m_program_config("program", ENDIANNESS_LITTLE, 8, prgwidth, 0, program),
|
||||
m_data_config("data", ENDIANNESS_LITTLE, 8, datawidth, 0, data),
|
||||
m_prgwidth(prgwidth),
|
||||
m_datawidth(datawidth),
|
||||
m_stack_levels(stack_levels),
|
||||
m_r_mask_option(RMASK_DIRECT),
|
||||
m_lcd_ram_a(*this, "lcd_ram_a"),
|
||||
m_lcd_ram_b(*this, "lcd_ram_b"),
|
||||
m_lcd_ram_c(*this, "lcd_ram_c"),
|
||||
m_write_segs(*this),
|
||||
m_melody_rom(*this, "melody"),
|
||||
m_read_k(*this),
|
||||
m_read_ba(*this),
|
||||
m_read_b(*this),
|
||||
m_write_s(*this),
|
||||
m_write_r(*this)
|
||||
{ }
|
||||
|
||||
// For SM510, SM500, SM5A, R port output is selected with a mask option,
|
||||
@ -73,8 +76,9 @@ public:
|
||||
// 4/8-bit S strobe output port
|
||||
auto write_s() { return m_write_s.bind(); }
|
||||
|
||||
// 1/2/4-bit R (buzzer/melody) output port
|
||||
// 1/2-bit R (buzzer/melody) output port
|
||||
// may also be called F(frequency?) or SO(sound out)
|
||||
// SM590 has 4 R ports, don't use this one, see sm590.h
|
||||
auto write_r() { return m_write_r.bind(); }
|
||||
|
||||
// LCD segment outputs, SM51x: H1-4 as offset(low), a/b/c 1-16 as data d0-d15,
|
||||
@ -114,6 +118,7 @@ protected:
|
||||
int m_datawidth;
|
||||
int m_prgmask;
|
||||
int m_datamask;
|
||||
int m_pagemask;
|
||||
|
||||
u16 m_pc, m_prev_pc;
|
||||
u16 m_op, m_prev_op;
|
||||
|
@ -74,9 +74,8 @@ const char *const sm510_common_disassembler::s_mnemonics[] =
|
||||
"INIS",
|
||||
|
||||
// SM590
|
||||
"NOP", "CCTRL", "INBL", "DEBL", "XBLA", "ADCS", "TR",
|
||||
// "
|
||||
"TAX", "LBLX", "MTR", "STR", "INBM", "DEBM", "RTA", "BLTA", "EXAX", "TBA", "ADS", "ADC", "LBMX", "TLS"
|
||||
"TAX", "LBLX", "MTR", "STR", "INBM", "DEBM", "RTA", "BLTA", "EXAX", "TBA", "ADS", "ADC", "LBMX", "TLS",
|
||||
"NOP", "CCTRL", "INBL", "DEBL", "XBLA", "ADCS", "TR"
|
||||
};
|
||||
|
||||
// number of bits per opcode parameter, 8 or larger means 2-byte opcode
|
||||
@ -108,9 +107,8 @@ const u8 sm510_common_disassembler::s_bits[] =
|
||||
0,
|
||||
|
||||
// SM590
|
||||
0, 0, 0, 0, 0, 0, 7,
|
||||
// "
|
||||
4, 4, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2+8
|
||||
4, 4, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 2+8,
|
||||
0, 0, 0, 0, 0, 0, 7
|
||||
};
|
||||
|
||||
const u32 sm510_common_disassembler::s_flags[] =
|
||||
@ -141,9 +139,8 @@ const u32 sm510_common_disassembler::s_flags[] =
|
||||
0,
|
||||
|
||||
// SM590
|
||||
0, 0, 0, 0, 0, 0, STEP_OVER,
|
||||
// "
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, STEP_OVER
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, STEP_OVER,
|
||||
0, 0, 0, 0, 0, 0, STEP_OVER
|
||||
};
|
||||
|
||||
|
||||
@ -361,7 +358,7 @@ offs_t sm5a_disassembler::disassemble(std::ostream &stream, offs_t pc, const dat
|
||||
const u8 sm530_disassembler::sm530_mnemonic[0x100] =
|
||||
{
|
||||
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
|
||||
mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, // 0 - note: $00 has synonym SKIP
|
||||
mSKIP, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, mADX, // 0
|
||||
mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, mLAX, // 1
|
||||
mLDA, mLDA, mLDA, mLDA, mEXC, mEXC, mEXC, mEXC, mEXCI, mEXCI, mEXCI, mEXCI, mEXCD, mEXCD, mEXCD, mEXCD, // 2
|
||||
mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, mLB, // 3
|
||||
|
@ -52,10 +52,9 @@ protected:
|
||||
mKETA, mATF, mSDS, mRDS,
|
||||
mINIS,
|
||||
|
||||
// SM590 aliases
|
||||
mNOP, mCCTRL, mINBL, mDEBL, mXBLA, mADCS, mTR7,
|
||||
// SM590 uniques
|
||||
mTAX, mLBLX, mMTR, mSTR, mINBM, mDEBM, mRTA, mBLTA, mEXAX, mTBA2, mADS, mADC, mLBMX, mTLS
|
||||
// SM590 common
|
||||
mTAX, mLBLX, mMTR, mSTR, mINBM, mDEBM, mRTA, mBLTA, mEXAX, mTBA2, mADS, mADC, mLBMX, mTLS,
|
||||
mNOP, mCCTRL, mINBL, mDEBL, mXBLA, mADCS, mTR7 // aliases
|
||||
};
|
||||
|
||||
static const char *const s_mnemonics[];
|
||||
|
@ -118,7 +118,7 @@ void sm510_base_device::op_rtn1()
|
||||
void sm510_base_device::op_t()
|
||||
{
|
||||
// T xy: jump(transfer) within current page
|
||||
m_pc = (m_pc & ~0x3f) | (m_op & 0x3f);
|
||||
m_pc = (m_pc & ~m_pagemask) | (m_op & m_pagemask);
|
||||
}
|
||||
|
||||
void sm510_base_device::op_tl()
|
||||
|
@ -54,14 +54,14 @@ std::unique_ptr<util::disasm_interface> sm511_device::create_disassembler()
|
||||
|
||||
|
||||
// device definitions
|
||||
sm511_device::sm511_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm511_device(mconfig, SM511, tag, owner, clock, 2 /* stack levels */, 12 /* prg width */, address_map_constructor(FUNC(sm511_device::program_4k), this), 7 /* data width */, address_map_constructor(FUNC(sm511_device::data_96_32x4), this))
|
||||
{ }
|
||||
|
||||
sm511_device::sm511_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) :
|
||||
sm510_base_device(mconfig, type, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data)
|
||||
{ }
|
||||
|
||||
sm511_device::sm511_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm511_device(mconfig, SM511, tag, owner, clock, 2 /* stack levels */, 12 /* prg width */, address_map_constructor(FUNC(sm511_device::program_4k), this), 7 /* data width */, address_map_constructor(FUNC(sm511_device::data_96_32x4), this))
|
||||
{ }
|
||||
|
||||
sm512_device::sm512_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm511_device(mconfig, SM512, tag, owner, clock, 2, 12, address_map_constructor(FUNC(sm512_device::program_4k), this), 7, address_map_constructor(FUNC(sm512_device::data_80_48x4), this))
|
||||
{ }
|
||||
|
@ -46,15 +46,15 @@ std::unique_ptr<util::disasm_interface> sm530_device::create_disassembler()
|
||||
|
||||
|
||||
// device definitions
|
||||
sm530_device::sm530_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm530_device(mconfig, SM530, tag, owner, clock, 1 /* stack levels */, 11 /* prg width */, address_map_constructor(FUNC(sm530_device::program_2k), this), 7 /* data width */, address_map_constructor(FUNC(sm530_device::data_64_24x4), this))
|
||||
{ }
|
||||
|
||||
sm530_device::sm530_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) :
|
||||
sm511_device(mconfig, type, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data),
|
||||
m_write_f(*this)
|
||||
{ }
|
||||
|
||||
sm530_device::sm530_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm530_device(mconfig, SM530, tag, owner, clock, 1 /* stack levels */, 11 /* prg width */, address_map_constructor(FUNC(sm530_device::program_2k), this), 7 /* data width */, address_map_constructor(FUNC(sm530_device::data_64_24x4), this))
|
||||
{ }
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
|
@ -89,8 +89,6 @@ protected:
|
||||
virtual void execute_one() override;
|
||||
virtual bool op_argument() override;
|
||||
|
||||
using sm510_base_device::do_branch;
|
||||
virtual void do_branch(u8 pu, u8 pl); // does not have Pm
|
||||
virtual void reset_vector() override { do_branch(0xf, 0); }
|
||||
virtual void wakeup_vector() override { do_branch(0, 0); }
|
||||
|
||||
@ -109,6 +107,9 @@ protected:
|
||||
virtual u16 melody_step_mask() override { return 0xff; }
|
||||
|
||||
// opcode handlers
|
||||
using sm510_base_device::do_branch;
|
||||
virtual void do_branch(u8 pu, u8 pl); // does not have Pm
|
||||
|
||||
virtual void op_incb() override;
|
||||
virtual void op_lb() override;
|
||||
virtual void op_sabl();
|
||||
|
@ -5,7 +5,8 @@
|
||||
Sharp SM590 MCU core implementation
|
||||
|
||||
TODO:
|
||||
- finish SM590/SM595 emulation (NES/SNES CIC)
|
||||
- if BL >= 4, are port accesses mirrored or ignored? (right now assuming mirrored)
|
||||
- R port mask options
|
||||
|
||||
*/
|
||||
|
||||
@ -17,60 +18,96 @@
|
||||
|
||||
// MCU types
|
||||
DEFINE_DEVICE_TYPE(SM590, sm590_device, "sm590", "Sharp SM590") // 512x8 ROM, 32x4 RAM
|
||||
//DEFINE_DEVICE_TYPE(SM591, sm591_device, "sm591", "Sharp SM591") // 1kx8 ROM, 56x4 RAM
|
||||
//DEFINE_DEVICE_TYPE(SM595, sm595_device, "sm595", "Sharp SM595") // 768x8 ROM, 32x4 RAM
|
||||
DEFINE_DEVICE_TYPE(SM591, sm591_device, "sm591", "Sharp SM591") // 1kx8 ROM, 56x4 RAM
|
||||
DEFINE_DEVICE_TYPE(SM595, sm595_device, "sm595", "Sharp SM595") // 768x8 ROM, 32x4 RAM
|
||||
|
||||
|
||||
// internal memory maps
|
||||
void sm590_device::program_1x128x4(address_map &map)
|
||||
void sm590_device::program_512x8(address_map &map)
|
||||
{
|
||||
map(0x000, 0x1ff).rom();
|
||||
}
|
||||
|
||||
void sm590_device::data_16x2x4(address_map &map)
|
||||
void sm590_device::program_768x8(address_map &map)
|
||||
{
|
||||
map(0x00, 0x0f).ram();
|
||||
map(0x10, 0x1f).ram();
|
||||
map(0x000, 0x2ff).rom();
|
||||
}
|
||||
|
||||
void sm590_device::program_1kx8(address_map &map)
|
||||
{
|
||||
map(0x000, 0x3ff).rom();
|
||||
}
|
||||
|
||||
void sm590_device::data_32x4(address_map &map)
|
||||
{
|
||||
map(0x00, 0x1f).ram();
|
||||
}
|
||||
|
||||
void sm590_device::data_56x4(address_map &map)
|
||||
{
|
||||
map(0x00, 0x2f).ram();
|
||||
map(0x30, 0x37).mirror(0x08).ram();
|
||||
}
|
||||
|
||||
|
||||
// device definitions
|
||||
sm590_device::sm590_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm590_device(mconfig, SM590, tag, owner, clock, 4 /* stack levels */, 9 /* prg width */, address_map_constructor(FUNC(sm590_device::program_1x128x4), this), 5 /* data width */, address_map_constructor(FUNC(sm590_device::data_16x2x4), this))
|
||||
{ }
|
||||
|
||||
//sm591_device::sm591_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
// sm510_base_device(mconfig, SM591, tag, owner, clock, 4 /* stack levels */, 10 /* prg width */, address_map_constructor(FUNC(sm591_device::program_2x128x4), this), 6 /* data width */, address_map_constructor(FUNC(sm591_device::data_16x3.5x4), this))
|
||||
//{ }
|
||||
|
||||
//sm595_device::sm595_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
// sm510_base_device(mconfig, SM595, tag, owner, clock, 4 /* stack levels */, 10 /* prg width */, address_map_constructor(FUNC(sm595_device::program_1x128x4_1x128x2), this), 5 /* data width */, address_map_constructor(FUNC(sm595_device::data_16x2x4), this))
|
||||
//{ }
|
||||
|
||||
sm590_device::sm590_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) :
|
||||
sm510_base_device(mconfig, type, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data)
|
||||
sm510_base_device(mconfig, type, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data),
|
||||
m_write_rx(*this),
|
||||
m_read_rx(*this)
|
||||
{ }
|
||||
|
||||
sm590_device::sm590_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm590_device(mconfig, SM590, tag, owner, clock, 4 /* stack levels */, 9 /* prg width */, address_map_constructor(FUNC(sm590_device::program_512x8), this), 5 /* data width */, address_map_constructor(FUNC(sm590_device::data_32x4), this))
|
||||
{ }
|
||||
|
||||
sm591_device::sm591_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm590_device(mconfig, SM591, tag, owner, clock, 4, 10, address_map_constructor(FUNC(sm591_device::program_1kx8), this), 6, address_map_constructor(FUNC(sm591_device::data_56x4), this))
|
||||
{ }
|
||||
|
||||
sm595_device::sm595_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm590_device(mconfig, SM595, tag, owner, clock, 4, 10, address_map_constructor(FUNC(sm595_device::program_768x8), this), 5, address_map_constructor(FUNC(sm595_device::data_32x4), this))
|
||||
{ }
|
||||
|
||||
|
||||
// disasm
|
||||
std::unique_ptr<util::disasm_interface> sm590_device::create_disassembler()
|
||||
{
|
||||
return std::make_unique<sm590_disassembler>();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void sm590_device::device_start()
|
||||
{
|
||||
// common init
|
||||
sm510_base_device::device_start();
|
||||
|
||||
// resolve callbacks
|
||||
m_read_rx.resolve_all_safe(0);
|
||||
m_write_rx.resolve_all_safe();
|
||||
|
||||
// init/register for savestates
|
||||
m_pagemask = 0x7f;
|
||||
save_item(NAME(m_rports));
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
//-------------------------------------------------
|
||||
|
||||
void sm590_device::device_reset()
|
||||
{
|
||||
// ACL
|
||||
m_skip = false;
|
||||
m_halt = false;
|
||||
m_op = m_prev_op = 0;
|
||||
reset_vector();
|
||||
m_prev_pc = m_pc;
|
||||
// common reset
|
||||
sm510_base_device::device_reset();
|
||||
|
||||
m_rports[0] = m_rports[1] = m_rports[2] = m_rports[3] = 0;
|
||||
//m_write_r(0); // TODO: are the four ports zeroed on reset?
|
||||
// clear outputs
|
||||
for (int i = 0; i < 4; i++)
|
||||
port_w(i, 0);
|
||||
}
|
||||
|
||||
|
||||
@ -78,17 +115,9 @@ void sm590_device::device_reset()
|
||||
// execute
|
||||
//-------------------------------------------------
|
||||
|
||||
void sm590_device::increment_pc()
|
||||
{
|
||||
// PL(program counter low 7 bits) is a simple LFSR: newbit = (bit0==bit1)
|
||||
// PU,PM(high bits) specify page, PL specifies steps within page
|
||||
int feed = ((m_pc >> 1 ^ m_pc) & 1) ? 0 : 0x40;
|
||||
m_pc = feed | (m_pc >> 1 & 0x3f) | (m_pc & ~0x7f);
|
||||
}
|
||||
|
||||
void sm590_device::execute_one()
|
||||
{
|
||||
switch (m_op & 0xf0) // opcodes with 4 bit params
|
||||
switch (m_op & 0xf0)
|
||||
{
|
||||
case 0x00: op_adx(); break;
|
||||
case 0x10: op_tax(); break;
|
||||
@ -96,20 +125,20 @@ void sm590_device::execute_one()
|
||||
case 0x30: op_lax(); break;
|
||||
case 0x80: case 0x90: case 0xa0: case 0xb0:
|
||||
case 0xc0: case 0xd0: case 0xe0: case 0xf0:
|
||||
op_t(); break; // aka tr
|
||||
op_t(); break; // TR
|
||||
|
||||
default: // opcodes with 2 bit params
|
||||
default:
|
||||
switch (m_op & 0xfc)
|
||||
{
|
||||
case 0x60: op_tmi(); break; // aka tm
|
||||
case 0x60: op_tmi(); break; // TM
|
||||
case 0x64: op_tba(); break;
|
||||
case 0x68: op_rm(); break;
|
||||
case 0x6c: op_sm(); break;
|
||||
case 0x74: op_lbmx(); break;
|
||||
case 0x78: op_tl(); break;
|
||||
case 0x7c: op_tml(); break; // aka tls
|
||||
case 0x7c: op_tls(); break;
|
||||
|
||||
default: // everything else
|
||||
default:
|
||||
switch (m_op)
|
||||
{
|
||||
case 0x40: op_lda(); break;
|
||||
@ -123,27 +152,23 @@ void sm590_device::execute_one()
|
||||
case 0x48: op_rc(); break;
|
||||
case 0x49: op_sc(); break;
|
||||
case 0x4a: op_str(); break;
|
||||
case 0x4b: op_cend(); break; // aka cctrl
|
||||
case 0x4c: op_rtn0(); break; // aka rtn
|
||||
case 0x4d: op_rtn1(); break; // aka rtns
|
||||
// 4e, 4f illegal
|
||||
case 0x4b: op_cend(); break; // CCTRL
|
||||
case 0x4c: op_rtn0(); break; // RTN
|
||||
case 0x4d: op_rtn1(); break; // RTNS
|
||||
case 0x50: op_inbm(); break;
|
||||
case 0x51: op_debm(); break;
|
||||
case 0x52: op_incb(); break; // aka inbl
|
||||
case 0x53: op_decb(); break; // aka debl
|
||||
case 0x52: op_incb(); break; // INBL
|
||||
case 0x53: op_decb(); break; // DEBL
|
||||
case 0x54: op_tc(); break;
|
||||
case 0x55: op_rta(); break;
|
||||
case 0x56: op_blta(); break;
|
||||
case 0x57: op_exbla(); break; // aka xbla
|
||||
// 58, 59, 5a, 5b illegal
|
||||
case 0x57: op_exbla(); break; // XBLA
|
||||
case 0x5c: op_atx(); break;
|
||||
case 0x5d: op_exax(); break;
|
||||
// 5e is illegal???
|
||||
// 5f is illegal
|
||||
case 0x70: op_add(); break;
|
||||
case 0x71: op_ads(); break;
|
||||
case 0x72: op_adc(); break;
|
||||
case 0x73: op_add11(); break; // aka adcs
|
||||
case 0x73: op_add11(); break; // ADCS
|
||||
|
||||
default: op_illegal(); break;
|
||||
}
|
||||
|
@ -89,14 +89,23 @@ R3.3/CL2 => |_|6 15|_| <> R1.3
|
||||
class sm590_device : public sm510_base_device
|
||||
{
|
||||
public:
|
||||
sm590_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 32768);
|
||||
sm590_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
// four 4-bit R I/O ports
|
||||
using sm510_base_device::write_r;
|
||||
template <std::size_t Bit> auto write_r() { return m_write_rx[Bit].bind(); }
|
||||
template <std::size_t Bit> auto read_r() { return m_read_rx[Bit].bind(); }
|
||||
|
||||
protected:
|
||||
sm590_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data);
|
||||
|
||||
void program_1x128x4(address_map &map);
|
||||
void data_16x2x4(address_map &map);
|
||||
void program_512x8(address_map &map);
|
||||
void program_768x8(address_map &map);
|
||||
void program_1kx8(address_map &map);
|
||||
void data_32x4(address_map &map);
|
||||
void data_56x4(address_map &map);
|
||||
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
|
||||
@ -105,89 +114,62 @@ protected:
|
||||
|
||||
virtual void init_divider() override { } // no divider timer
|
||||
virtual void init_lcd_driver() override { } // no lcd driver
|
||||
virtual void increment_pc() override;
|
||||
virtual void execute_one() override;
|
||||
virtual bool op_argument() override;
|
||||
virtual void do_branch(u8 pu, u8 pm, u8 pl) override;
|
||||
|
||||
virtual void reset_vector() override { do_branch(0, 0, 0); }
|
||||
virtual void wakeup_vector() override { do_branch(0, 1, 0); }
|
||||
|
||||
// opcode handlers
|
||||
// 00-3f
|
||||
virtual void op_adx() override;
|
||||
virtual void op_tax();
|
||||
virtual void op_lblx();
|
||||
// lax (same as sm510)
|
||||
// R ports
|
||||
devcb_write8::array<4> m_write_rx;
|
||||
devcb_read8::array<4> m_read_rx;
|
||||
u8 m_rports[4];
|
||||
|
||||
// 40-43
|
||||
// opcode handlers
|
||||
virtual void do_branch(u8 pu, u8 pm, u8 pl) override;
|
||||
void port_w(offs_t offset, u8 data);
|
||||
|
||||
virtual void op_tl() override;
|
||||
virtual void op_tls();
|
||||
|
||||
virtual void op_lblx();
|
||||
virtual void op_lbmx();
|
||||
virtual void op_str();
|
||||
virtual void op_lda() override;
|
||||
virtual void op_exc() override;
|
||||
// exci (same as sm510)
|
||||
// excd (same as sm510)
|
||||
|
||||
// 44-47
|
||||
// coma (same as sm510)
|
||||
// tam (same as sm510)
|
||||
virtual void op_atr() override;
|
||||
virtual void op_mtr();
|
||||
|
||||
// 48-4b
|
||||
// rc (same as sm510)
|
||||
// sc (same as sm510)
|
||||
virtual void op_str();
|
||||
// cctrl (same as sm510 cend)
|
||||
|
||||
// 4c-4f
|
||||
// rtn (same as sm510 rtn0)
|
||||
// rtns (same as sm510 rtn1)
|
||||
// 4e illegal
|
||||
// 4f illegal
|
||||
|
||||
// 50-53
|
||||
virtual void op_inbm();
|
||||
virtual void op_debm();
|
||||
// inbl (same as sm510 incb)
|
||||
// debl (same as sm510 decb)
|
||||
|
||||
// 54-57
|
||||
virtual void op_tc() override;
|
||||
virtual void op_rta();
|
||||
virtual void op_blta();
|
||||
// xbla (same as sm510 exbla)
|
||||
|
||||
// 58-5b are all illegal
|
||||
|
||||
// 5c-5f
|
||||
// atx (same as sm510)
|
||||
virtual void op_exax();
|
||||
// 5e illegal???
|
||||
// 5f illegal
|
||||
virtual void op_blta();
|
||||
|
||||
// 60-6f
|
||||
// tm (same as sm510 tmi)
|
||||
virtual void op_tba();
|
||||
// rm (same as sm510)
|
||||
// sm (same as sm510)
|
||||
|
||||
// 70-73
|
||||
// add (same as sm510)
|
||||
virtual void op_adx() override;
|
||||
virtual void op_ads();
|
||||
virtual void op_adc();
|
||||
// adcs (same as sm510 add11)
|
||||
virtual void op_inbm();
|
||||
virtual void op_debm();
|
||||
|
||||
// 74-7f
|
||||
virtual void op_lbmx();
|
||||
virtual void op_tl() override;
|
||||
virtual void op_tml() override; // aka TLS
|
||||
virtual void op_tax();
|
||||
virtual void op_tba();
|
||||
virtual void op_tc() override;
|
||||
|
||||
// 80-ff
|
||||
virtual void op_t() override; // aka TR
|
||||
virtual void op_atr() override;
|
||||
virtual void op_mtr();
|
||||
virtual void op_rta();
|
||||
};
|
||||
|
||||
u8 m_rports[4];
|
||||
class sm591_device : public sm590_device
|
||||
{
|
||||
public:
|
||||
sm591_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
};
|
||||
|
||||
class sm595_device : public sm590_device
|
||||
{
|
||||
public:
|
||||
sm595_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(SM590, sm590_device)
|
||||
DECLARE_DEVICE_TYPE(SM591, sm591_device)
|
||||
DECLARE_DEVICE_TYPE(SM595, sm595_device)
|
||||
|
||||
#endif // MAME_CPU_SM510_SM590_H
|
||||
|
@ -11,95 +11,71 @@
|
||||
|
||||
void sm590_device::do_branch(u8 pu, u8 pm, u8 pl)
|
||||
{
|
||||
// set new PC(Pu/Pm/Pl)
|
||||
m_pc = (((u16)pu << 9 & 0x200) | ((u16)pm << 7 & 0x180) | (pl & 0x07f)) & m_prgmask;
|
||||
// set new PC(Pu/Pm/Pl) (Pu is not used on SM590)
|
||||
m_pc = ((pu << 9 & 0x200) | (pm << 7 & 0x180) | (pl & 0x07f)) & m_prgmask;
|
||||
}
|
||||
|
||||
void sm590_device::port_w(offs_t offset, u8 data)
|
||||
{
|
||||
offset &= 3;
|
||||
data &= 0xf;
|
||||
m_rports[offset] = data;
|
||||
m_write_rx[offset](offset, data);
|
||||
}
|
||||
|
||||
|
||||
// instruction set
|
||||
|
||||
void sm590_device::op_adx()
|
||||
// ROM address instructions
|
||||
|
||||
void sm590_device::op_tl()
|
||||
{
|
||||
// ADX x: add immediate value to ACC, skip next on carry
|
||||
m_acc += (m_op & 0xf);
|
||||
m_skip = bool(m_acc & 0x10);
|
||||
m_acc &= 0xf;
|
||||
// TL xyz: long jump
|
||||
do_branch(BIT(m_op, 1), (m_op << 1 & 2) | BIT(m_param, 7), m_param & 0x7f);
|
||||
}
|
||||
|
||||
void sm590_device::op_tax()
|
||||
void sm590_device::op_tls()
|
||||
{
|
||||
// TAX: skip next if ACC equals 4-bit immediate value
|
||||
m_skip = (m_acc == (m_op & 0xf));
|
||||
// TLS xyz: long call
|
||||
push_stack();
|
||||
do_branch(BIT(m_op, 1), (m_op << 1 & 2) | BIT(m_param, 7), m_param & 0x7f);
|
||||
}
|
||||
|
||||
|
||||
// Data transfer instructions
|
||||
|
||||
void sm590_device::op_lblx()
|
||||
{
|
||||
// LBL x: load BL with 4-bit immediate value
|
||||
m_bl = (m_op & 0xf);
|
||||
}
|
||||
|
||||
void sm590_device::op_lbmx()
|
||||
{
|
||||
// LBM x: load BM with 2-bit immediate value
|
||||
m_bm = (m_op & 0x3);
|
||||
}
|
||||
|
||||
void sm590_device::op_str()
|
||||
{
|
||||
// STR: store ACC to RAM
|
||||
ram_w(m_acc);
|
||||
}
|
||||
|
||||
void sm590_device::op_lda()
|
||||
{
|
||||
// LDA: load ACC with RAM
|
||||
// LDA: load ACC with RAM (no BM xor)
|
||||
m_acc = ram_r();
|
||||
}
|
||||
|
||||
void sm590_device::op_exc()
|
||||
{
|
||||
// EXC: exchange ACC with RAM
|
||||
// EXC: exchange ACC with RAM (no BM xor)
|
||||
u8 a = m_acc;
|
||||
m_acc = ram_r();
|
||||
ram_w(a);
|
||||
}
|
||||
|
||||
void sm590_device::op_atr()
|
||||
{
|
||||
// ATR: output ACC to R(BL)
|
||||
m_rports[m_bl & 0x3] = m_acc; // is the mask for BL correct here? if BL is >= 4, do the writes just go nowhere?
|
||||
}
|
||||
|
||||
void sm590_device::op_mtr()
|
||||
{
|
||||
// MTR: output RAM to R(BL)
|
||||
m_rports[m_bl & 0x3] = ram_r(); // is the mask for BL correct here? if BL is >= 4, do the writes just go nowhere?
|
||||
}
|
||||
|
||||
void sm590_device::op_str()
|
||||
{
|
||||
// STR: output ACC to RAM
|
||||
ram_w(m_acc);
|
||||
}
|
||||
|
||||
void sm590_device::op_inbm()
|
||||
{
|
||||
// INBM: increment BM
|
||||
m_bm = (m_bm + 1) & 0x3; // is this mask correct?
|
||||
}
|
||||
|
||||
void sm590_device::op_debm()
|
||||
{
|
||||
// DEBM: decrement BM
|
||||
m_bm = (m_bm - 1) & 0x3; // is this mask correct?
|
||||
}
|
||||
|
||||
void sm590_device::op_tc()
|
||||
{
|
||||
// TC: skip next if carry
|
||||
m_skip = bool(m_c);
|
||||
}
|
||||
|
||||
void sm590_device::op_rta()
|
||||
{
|
||||
// RTA: load ACC with R(BL)
|
||||
m_acc = m_rports[m_bl & 0x3]; // TODO: need a read function for this; is the mask for BL correct here? if BL is >= 4, do we always read 0 or F?
|
||||
}
|
||||
|
||||
void sm590_device::op_blta()
|
||||
{
|
||||
// BLTA: load ACC with BL
|
||||
m_acc = m_bl;
|
||||
}
|
||||
|
||||
void sm590_device::op_exax()
|
||||
{
|
||||
// EXAX: exchange X with ACC
|
||||
@ -108,10 +84,21 @@ void sm590_device::op_exax()
|
||||
m_x = a;
|
||||
}
|
||||
|
||||
void sm590_device::op_tba()
|
||||
void sm590_device::op_blta()
|
||||
{
|
||||
// TBA x: skip next if ACC bit is set
|
||||
m_skip = ((m_acc & bitmask(m_op)) != 0);
|
||||
// BLTA: load ACC with BL
|
||||
m_acc = m_bl;
|
||||
}
|
||||
|
||||
|
||||
// Arithmetic instructions
|
||||
|
||||
void sm590_device::op_adx()
|
||||
{
|
||||
// ADX x: add immediate value to ACC, skip next on carry
|
||||
m_acc += (m_op & 0xf);
|
||||
m_skip = bool(m_acc & 0x10);
|
||||
m_acc &= 0xf;
|
||||
}
|
||||
|
||||
void sm590_device::op_ads()
|
||||
@ -125,32 +112,61 @@ void sm590_device::op_ads()
|
||||
void sm590_device::op_adc()
|
||||
{
|
||||
// ADC: add RAM and carry to ACC and carry
|
||||
m_acc += ram_r() + m_c;
|
||||
m_c = m_acc >> 4 & 1;
|
||||
m_acc &= 0xf;
|
||||
op_add11();
|
||||
m_skip = false; // no skip
|
||||
}
|
||||
|
||||
void sm590_device::op_lbmx()
|
||||
void sm590_device::op_inbm()
|
||||
{
|
||||
// LBM x: load BM with 2-bit immediate value
|
||||
m_bm = (m_op & 0x3);
|
||||
// INBM: increment BM
|
||||
m_bm = (m_bm + 1) & m_datamask >> 4;
|
||||
}
|
||||
|
||||
void sm590_device::op_tl()
|
||||
void sm590_device::op_debm()
|
||||
{
|
||||
// TL xyz: long jump (same as sm510 TL except m_op and m_param masks)
|
||||
do_branch(BIT(m_op, 1), (m_op << 1 & 2) | BIT(m_param, 7), m_param & 0x7f);
|
||||
// DEBM: decrement BM
|
||||
m_bm = (m_bm - 1) & m_datamask >> 4;
|
||||
}
|
||||
|
||||
void sm590_device::op_tml() // aka TLS
|
||||
|
||||
// Test instructions
|
||||
|
||||
void sm590_device::op_tax()
|
||||
{
|
||||
// TLS xyz: long call (same as sm510 TML except m_param mask)
|
||||
push_stack();
|
||||
do_branch(BIT(m_op, 1), (m_op << 1 & 2) | BIT(m_param, 7), m_param & 0x7f);
|
||||
// TAX: skip next if ACC equals 4-bit immediate value
|
||||
m_skip = (m_acc == (m_op & 0xf));
|
||||
}
|
||||
|
||||
void sm590_device::op_t()
|
||||
void sm590_device::op_tba()
|
||||
{
|
||||
// TR xy: jump(transfer) within current page (same as sm510 T except m_op/m_pc mask)
|
||||
m_pc = (m_pc & ~0x7f) | (m_op & 0x7f);
|
||||
// TBA x: skip next if ACC bit is set
|
||||
m_skip = ((m_acc & bitmask(m_op)) != 0);
|
||||
}
|
||||
|
||||
void sm590_device::op_tc()
|
||||
{
|
||||
// TC: skip next if carry
|
||||
m_skip = bool(m_c);
|
||||
}
|
||||
|
||||
|
||||
// I/O instructions
|
||||
|
||||
void sm590_device::op_atr()
|
||||
{
|
||||
// ATR: output ACC to R(BL)
|
||||
port_w(m_bl, m_acc);
|
||||
}
|
||||
|
||||
void sm590_device::op_mtr()
|
||||
{
|
||||
// MTR: output RAM to R(BL)
|
||||
port_w(m_bl, ram_r());
|
||||
}
|
||||
|
||||
void sm590_device::op_rta()
|
||||
{
|
||||
// RTA: load ACC with R(BL)
|
||||
u8 offset = m_bl & 3;
|
||||
m_acc = (m_rports[offset] | m_read_rx[offset]()) & 0xf;
|
||||
}
|
||||
|
@ -40,14 +40,14 @@ void sm5a_device::data_5x13x4(address_map &map)
|
||||
|
||||
|
||||
// device definitions
|
||||
sm5a_device::sm5a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm5a_device(mconfig, SM5A, tag, owner, clock, 1 /* stack levels */, 9 /* o group pins */, 11 /* prg width */, address_map_constructor(FUNC(sm5a_device::program_1_8k), this), 7 /* data width */, address_map_constructor(FUNC(sm5a_device::data_5x13x4), this))
|
||||
{ }
|
||||
|
||||
sm5a_device::sm5a_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock, int stack_levels, int o_pins, int prgwidth, address_map_constructor program, int datawidth, address_map_constructor data) :
|
||||
sm500_device(mconfig, type, tag, owner, clock, stack_levels, o_pins, prgwidth, program, datawidth, data)
|
||||
{ }
|
||||
|
||||
sm5a_device::sm5a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm5a_device(mconfig, SM5A, tag, owner, clock, 1 /* stack levels */, 9 /* o group pins */, 11 /* prg width */, address_map_constructor(FUNC(sm5a_device::program_1_8k), this), 7 /* data width */, address_map_constructor(FUNC(sm5a_device::data_5x13x4), this))
|
||||
{ }
|
||||
|
||||
sm5l_device::sm5l_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||
sm5a_device(mconfig, SM5L, tag, owner, clock, 1, 9, 11, address_map_constructor(FUNC(sm5l_device::program_1_8k), this), 7, address_map_constructor(FUNC(sm5l_device::data_5x13x4), this))
|
||||
{ }
|
||||
|
Loading…
Reference in New Issue
Block a user