diff --git a/src/emu/cpu/sm510/sm510.c b/src/emu/cpu/sm510/sm510.c index ddd6c6f29e1..393f920ce79 100644 --- a/src/emu/cpu/sm510/sm510.c +++ b/src/emu/cpu/sm510/sm510.c @@ -6,6 +6,9 @@ - SM510: x - SM511: x - SM512: x + + Other chips that may be in the same family, investigate more when one of + them needs to get emulated: SM500, SM530, SM531, .. References: - 1990 Sharp Microcomputers Data Book @@ -63,6 +66,7 @@ void sm510_base_device::device_start() m_c = 0; m_skip = false; m_w = 0; + m_r = 0; m_div = 0; m_1s = false; m_k_active = false; @@ -72,6 +76,11 @@ void sm510_base_device::device_start() m_bp = false; m_bc = false; m_halt = false; + m_melody_rd = 0; + m_melody_step_count = 0; + m_melody_duty_count = 0; + m_melody_duty_index = 0; + m_melody_address = 0; // register for savestates save_item(NAME(m_stack)); @@ -86,6 +95,7 @@ void sm510_base_device::device_start() save_item(NAME(m_c)); save_item(NAME(m_skip)); save_item(NAME(m_w)); + save_item(NAME(m_r)); save_item(NAME(m_div)); save_item(NAME(m_1s)); save_item(NAME(m_k_active)); @@ -95,6 +105,11 @@ void sm510_base_device::device_start() save_item(NAME(m_bp)); save_item(NAME(m_bc)); save_item(NAME(m_halt)); + save_item(NAME(m_melody_rd)); + save_item(NAME(m_melody_step_count)); + save_item(NAME(m_melody_duty_count)); + save_item(NAME(m_melody_duty_index)); + save_item(NAME(m_melody_address)); // register state for debugger state_add(SM510_PC, "PC", m_pc).formatstr("%04X"); @@ -109,8 +124,10 @@ void sm510_base_device::device_start() m_icountptr = &m_icount; + // init peripherals init_divider(); init_lcd_driver(); + init_melody(); } @@ -132,6 +149,7 @@ void sm510_base_device::device_reset() m_bc = false; m_y = 0; + m_r = 0; m_write_r(0, 0, 0xff); } @@ -175,6 +193,7 @@ TIMER_CALLBACK_MEMBER(sm510_base_device::lcd_timer_cb) void sm510_base_device::init_lcd_driver() { + // note: in reality, this timer runs at high frequency off the main divider, strobing one segment at a time m_lcd_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sm510_base_device::lcd_timer_cb), this)); m_lcd_timer->adjust(attotime::from_ticks(0x200, unscaled_clock())); // 64hz default } @@ -182,7 +201,83 @@ void sm510_base_device::init_lcd_driver() //------------------------------------------------- -// interrupt/timer +// melody controller +//------------------------------------------------- + +void sm510_base_device::clock_melody() +{ + if (!m_melody_rom) + return; + + // tone cycle table (SM511/SM512 datasheet fig.5) + // cmd 0 = cmd, 1 = stop, > 13 = illegal(unknown) + static const UINT8 lut_tone_cycles[4*16] = + { + 0, 0, 7, 8, 8, 9, 9, 10,11,11,12,13,14,14, 7*2, 8*2, + 0, 0, 8, 8, 9, 9, 10,11,11,12,13,13,14,15, 8*2, 8*2, + 0, 0, 8, 8, 9, 9, 10,10,11,12,12,13,14,15, 8*2, 8*2, + 0, 0, 8, 9, 9, 10,10,11,11,12,13,14,14,15, 8*2, 9*2 + }; + + UINT8 cmd = m_melody_rom[m_melody_address] & 0x3f; + UINT8 out = 0; + + // clock duty cycle if tone is active + if ((cmd & 0xf) > 1) + { + out = m_melody_duty_index & m_melody_rd & 1; + m_melody_duty_count++; + int index = m_melody_duty_index << 4 | (cmd & 0xf); + int shift = ~cmd >> 4 & 1; // OCT + + if (m_melody_duty_count >= (lut_tone_cycles[index] << shift)) + { + m_melody_duty_count = 0; + m_melody_duty_index = (m_melody_duty_index + 1) & 3; + } + } + else if ((cmd & 0xf) == 1) + { + // rest tell signal + m_melody_rd |= 2; + } + + // clock time base on F8(d7) + if ((m_div & 0x7f) == 0) + { + UINT8 mask = (cmd & 0x20) ? 0x1f : 0x0f; + m_melody_step_count = (m_melody_step_count + 1) & mask; + + if (m_melody_step_count == 0) + m_melody_address++; + } + + // output to R pin + if (out != m_r) + { + m_write_r(0, out, 0xff); + m_r = out; + } +} + +void sm510_base_device::init_melody() +{ + if (!m_melody_rom) + return; + + // verify melody rom + for (int i = 0; i < 0x100; i++) + { + UINT8 data = m_melody_rom[i]; + if (data & 0xc0 || (data & 0x0f) > 13) + logerror("%s unknown melody ROM data $%02X at $%02X\n", tag(), data, i); + } +} + + + +//------------------------------------------------- +// interrupt/divider //------------------------------------------------- bool sm510_base_device::wake_me_up() @@ -213,28 +308,19 @@ void sm510_base_device::execute_set_input(int line, int state) TIMER_CALLBACK_MEMBER(sm510_base_device::div_timer_cb) { - // no need to increment it by 1 everytime, since only the - // highest bits are accessible - m_div = (m_div + 0x800) & 0x7fff; - + m_div = (m_div + 1) & 0x7fff; + // 1S signal on overflow(falling edge of f1) if (m_div == 0) m_1s = true; - - // schedule next timeout - m_div_timer->adjust(attotime::from_ticks(0x800, unscaled_clock())); -} - -void sm510_base_device::reset_divider() -{ - m_div = 0; - m_div_timer->adjust(attotime::from_ticks(0x800, unscaled_clock())); + + clock_melody(); } void sm510_base_device::init_divider() { m_div_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sm510_base_device::div_timer_cb), this)); - reset_divider(); + m_div_timer->adjust(attotime::from_ticks(1, unscaled_clock()), 0, attotime::from_ticks(1, unscaled_clock())); } diff --git a/src/emu/cpu/sm510/sm510.h b/src/emu/cpu/sm510/sm510.h index a25deb938b0..bf691650547 100644 --- a/src/emu/cpu/sm510/sm510.h +++ b/src/emu/cpu/sm510/sm510.h @@ -77,6 +77,7 @@ public: , m_stack_levels(stack_levels) , 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_sega(*this), m_write_segb(*this), m_write_segc(*this), m_write_segbs(*this) + , m_melody_rom(*this, "music") , m_read_k(*this) , m_read_ba(*this), m_read_b(*this) , m_write_s(*this) @@ -140,6 +141,7 @@ protected: UINT8 m_c; bool m_skip; UINT8 m_w; + UINT8 m_r; bool m_k_active; bool m_halt; @@ -156,16 +158,27 @@ protected: TIMER_CALLBACK_MEMBER(lcd_timer_cb); virtual void init_lcd_driver(); - // clock divider + // melody controller + optional_region_ptr m_melody_rom; + UINT8 m_melody_rd; + UINT8 m_melody_step_count; + UINT8 m_melody_duty_count; + UINT8 m_melody_duty_index; + UINT8 m_melody_address; + + void clock_melody(); + void init_melody(); + + // interrupt/divider emu_timer *m_div_timer; UINT16 m_div; bool m_1s; - TIMER_CALLBACK_MEMBER(div_timer_cb); bool wake_me_up(); - virtual void reset_divider(); - void init_divider(); - + virtual void reset_divider() { m_div = 0; } + virtual void init_divider(); + virtual TIMER_CALLBACK_MEMBER(div_timer_cb); + // other i/o handlers devcb_read8 m_read_k; devcb_read_line m_read_ba; @@ -175,7 +188,7 @@ protected: // misc internal helpers void increment_pc(); - virtual void get_opcode_param() { } // -> child class + virtual void get_opcode_param() { } virtual void update_w_latch() { } UINT8 ram_r(); @@ -264,6 +277,11 @@ protected: virtual void get_opcode_param(); virtual void update_w_latch() { m_write_s(0, m_w, 0xff); } // W is connected directly to S + + // divider + virtual TIMER_CALLBACK_MEMBER(div_timer_cb); + virtual void reset_divider(); + virtual void init_divider(); }; diff --git a/src/emu/cpu/sm510/sm510core.c b/src/emu/cpu/sm510/sm510core.c index 0ac9d7d3caf..cbdb4c37edd 100644 --- a/src/emu/cpu/sm510/sm510core.c +++ b/src/emu/cpu/sm510/sm510core.c @@ -43,6 +43,40 @@ offs_t sm510_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *op } + + +//------------------------------------------------- +// divider +//------------------------------------------------- + +TIMER_CALLBACK_MEMBER(sm510_device::div_timer_cb) +{ + // no need to increment it by 1 everytime, since only the + // highest bits are accessible + m_div = (m_div + 0x800) & 0x7fff; + + // 1S signal on overflow(falling edge of f1) + if (m_div == 0) + m_1s = true; + + // schedule next timeout + m_div_timer->adjust(attotime::from_ticks(0x800, unscaled_clock())); +} + +void sm510_device::reset_divider() +{ + m_div = 0; + m_div_timer->adjust(attotime::from_ticks(0x800, unscaled_clock())); +} + +void sm510_device::init_divider() +{ + m_div_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sm510_device::div_timer_cb), this)); + reset_divider(); +} + + + //------------------------------------------------- // execute //------------------------------------------------- diff --git a/src/emu/cpu/sm510/sm510op.c b/src/emu/cpu/sm510/sm510op.c index 16aa00dc507..f6c097932d3 100644 --- a/src/emu/cpu/sm510/sm510op.c +++ b/src/emu/cpu/sm510/sm510op.c @@ -248,7 +248,11 @@ void sm510_base_device::op_atfc() void sm510_base_device::op_atr() { // ATR: output ACC to R - m_write_r(0, m_acc & 3, 0xff); + if (m_r != (m_acc & 3)) + { + m_r = m_acc & 3; + m_write_r(0, m_r, 0xff); + } } @@ -387,26 +391,28 @@ void sm510_base_device::op_sm() void sm510_base_device::op_pre() { - // PRE x: x - op_illegal(); + // PRE x: melody ROM pointer preset + m_melody_address = m_param; + m_melody_step_count = 0; } void sm510_base_device::op_sme() { - // SME: x - op_illegal(); + // SME: set melody enable + m_melody_rd |= 1; } void sm510_base_device::op_rme() { - // RME: x - op_illegal(); + // RME: reset melody enable + m_melody_rd &= ~1; } void sm510_base_device::op_tmel() { - // TMEL: x - op_illegal(); + // TMEL: skip next if rest signal is set, reset it + m_skip = ((m_melody_rd & 2) != 0); + m_melody_rd &= ~2; } diff --git a/src/emu/cpu/sm510/sm511core.c b/src/emu/cpu/sm510/sm511core.c index 87c4ad72bc8..07f88152e27 100644 --- a/src/emu/cpu/sm510/sm511core.c +++ b/src/emu/cpu/sm510/sm511core.c @@ -64,7 +64,7 @@ sm512_device::sm512_device(const machine_config &mconfig, const char *tag, devic void sm511_device::get_opcode_param() { // LBL, PRE, TL, TML and prefix opcodes are 2 bytes - if ((m_op >= 0x5f && m_op <= 0x61) || (m_op & 0xf0) == 0x70 || (m_op & 0xfc) == 0x68) + if (m_op == 0x01 || (m_op >= 0x5f && m_op <= 0x61) || (m_op & 0xf0) == 0x70 || (m_op & 0xfc) == 0x68) { m_icount--; m_param = m_program->read_byte(m_pc); @@ -102,6 +102,7 @@ void sm511_device::execute_one() switch (m_op) { case 0x00: op_rot(); break; +// case 0x01: op_xxx(); break; // ? case 0x02: op_sbm(); break; case 0x03: op_atpl(); break; case 0x08: op_add(); break; @@ -129,8 +130,6 @@ void sm511_device::execute_one() // case 0x65: op_idiv(); break; case 0x66: op_rc(); break; case 0x67: op_sc(); break; -// case 0x68: op_tf1(); break; -// case 0x69: op_tf4(); break; case 0x6c: op_decb(); break; case 0x6d: op_ptw(); break; case 0x6e: op_rtn0(); break; diff --git a/src/mess/drivers/hh_sm510.c b/src/mess/drivers/hh_sm510.c index f6d0c51d5e3..ff7e4b7b9cc 100644 --- a/src/mess/drivers/hh_sm510.c +++ b/src/mess/drivers/hh_sm510.c @@ -261,10 +261,10 @@ static INPUT_PORTS_START( ktmnt ) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) PORT_START("IN.1") - PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) - PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) - PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) - PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) // game select + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) // sound on/off + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) // off + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) // on/start PORT_START("IN.2") PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_CHANGED_MEMBER(DEVICE_SELF, hh_sm510_state, input_changed, NULL) @@ -381,8 +381,10 @@ ROM_END ROM_START( ktmnt ) ROM_REGION( 0x1000, "maincpu", 0 ) - ROM_LOAD( "kms_73b_774.music", 0x0000, 0x100, CRC(8270d626) SHA1(bd91ca1d5cd7e2a62eef05c0033b19dcdbe441ca) ) //todo ROM_LOAD( "kms_73b_774.prog", 0x0000, 0x1000, CRC(a1064f87) SHA1(92156c35fbbb414007ee6804fe635128a741d5f1) ) + + ROM_REGION( 0x100, "maincpu:music", 0 ) + ROM_LOAD( "kms_73b_774.music", 0x000, 0x100, CRC(8270d626) SHA1(bd91ca1d5cd7e2a62eef05c0033b19dcdbe441ca) ) ROM_END