diff --git a/src/devices/cpu/sm510/sm500.h b/src/devices/cpu/sm510/sm500.h index 57b89202c3b..e09ef52147d 100644 --- a/src/devices/cpu/sm510/sm500.h +++ b/src/devices/cpu/sm510/sm500.h @@ -16,7 +16,7 @@ // I/O ports setup -// .. +// see sm510.h for ACL, K, R, alpha, beta // pinout reference @@ -81,14 +81,18 @@ protected: virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) override; virtual void execute_one() override; virtual void get_opcode_param() override; + + virtual void reset_vector() override { do_branch(0, 0xf, 0); } + virtual void wakeup_vector() override { do_branch(0, 0, 0); } int m_o_mask; // number of 4-bit O pins minus 1 u8 m_ox[9]; // W' latch, max 9 - u8 m_o[9]; // W latch(O outputs) - u8 m_cn; // CN(digit select) - u8 m_mx; // m'(digit DP select) - u8 m_cb; // CB(PC high bit buffer) - bool m_rsub; // R(in subroutine) + u8 m_o[9]; // W latch + u8 m_cn; + u8 m_mx; + u8 m_cb; + u8 m_s; + bool m_rsub; void shift_w(); u8 get_digit(); diff --git a/src/devices/cpu/sm510/sm500core.cpp b/src/devices/cpu/sm510/sm500core.cpp index 1df14d4d147..f09fc515f5c 100644 --- a/src/devices/cpu/sm510/sm500core.cpp +++ b/src/devices/cpu/sm510/sm500core.cpp @@ -3,6 +3,9 @@ /* Sharp SM500 MCU core implementation + + TODO: + - EXKSA, EXKFA opcodes */ @@ -12,7 +15,7 @@ // MCU types -DEFINE_DEVICE_TYPE(SM500, sm500_device, "sm500", "SM500") +DEFINE_DEVICE_TYPE(SM500, sm500_device, "sm500", "SM500") // 1.2K ROM, 4x10x4 RAM, shift registers for LCD // internal memory maps @@ -91,7 +94,7 @@ void sm500_device::execute_one() case 0x14: op_exci(); break; case 0x18: op_lda(); break; case 0x1c: op_excd(); break; - case 0x54: op_tmi(); break; // aka tm + case 0x54: op_tmi(); break; // TM default: switch (m_op) @@ -101,15 +104,15 @@ void sm500_device::execute_one() case 0x02: op_exksa(); break; case 0x03: op_atbp(); break; case 0x08: op_add(); break; - case 0x09: op_add11(); break; // aka addc + case 0x09: op_add11(); break; // ADDC case 0x0a: op_coma(); break; case 0x0b: op_exbla(); break; - case 0x50: op_tal(); break; // aka ta: test alpha + case 0x50: op_tal(); break; // TA case 0x51: op_tb(); break; case 0x52: op_tc(); break; case 0x53: op_tam(); break; - case 0x58: op_tis(); break; // aka tg: test gamma + case 0x58: op_tis(); break; // TG case 0x59: op_ptw(); break; case 0x5a: op_ta0(); break; case 0x5b: op_tabl(); break; @@ -131,8 +134,8 @@ void sm500_device::execute_one() case 0x6b: op_exkfa(); break; case 0x6c: op_decb(); break; case 0x6d: op_comcb(); break; - case 0x6e: op_rtn0(); break; // aka rtn - case 0x6f: op_rtn1(); break; // aka rtns + case 0x6e: op_rtn0(); break; // RTN + case 0x6f: op_rtn1(); break; // RTNS // extended opcodes case 0x5e: diff --git a/src/devices/cpu/sm510/sm500op.cpp b/src/devices/cpu/sm510/sm500op.cpp index fc18e279894..acb2864cec2 100644 --- a/src/devices/cpu/sm510/sm500op.cpp +++ b/src/devices/cpu/sm510/sm500op.cpp @@ -166,14 +166,18 @@ void sm500_device::op_ws() void sm500_device::op_ats() { + // ATS: transfer ACC to S + m_s = m_acc; } void sm500_device::op_exksa() { + // EXKSA: x } void sm500_device::op_exkfa() { + // EXKFA: x } diff --git a/src/devices/cpu/sm510/sm510.h b/src/devices/cpu/sm510/sm510.h index 0fecde8e447..63c9b21d498 100644 --- a/src/devices/cpu/sm510/sm510.h +++ b/src/devices/cpu/sm510/sm510.h @@ -32,7 +32,7 @@ #define MCFG_SM510_WRITE_S_CB(_devcb) \ devcb = &sm510_base_device::set_write_s_callback(*device, DEVCB_##_devcb); -// 2-bit R melody output port +// 2/4-bit R (melody) output port #define MCFG_SM510_WRITE_R_CB(_devcb) \ devcb = &sm510_base_device::set_write_r_callback(*device, DEVCB_##_devcb); @@ -155,6 +155,9 @@ protected: address_space_config m_data_config; address_space *m_program; address_space *m_data; + + virtual void reset_vector() { do_branch(3, 7, 0); } + virtual void wakeup_vector() { do_branch(1, 0, 0); } // after halt int m_prgwidth; int m_datawidth; @@ -190,6 +193,7 @@ protected: bool m_bc; u16 get_lcd_row(int column, u8* ram); + virtual void lcd_update(); TIMER_CALLBACK_MEMBER(lcd_timer_cb); virtual void init_lcd_driver(); diff --git a/src/devices/cpu/sm510/sm510base.cpp b/src/devices/cpu/sm510/sm510base.cpp index f77bfeb451d..07bda795f71 100644 --- a/src/devices/cpu/sm510/sm510base.cpp +++ b/src/devices/cpu/sm510/sm510base.cpp @@ -2,42 +2,21 @@ // copyright-holders:hap /* - Supported chips: (* means not finished emulated yet) - - Sharp SM510 MCU family: - - SM510: 2.7Kx8 ROM, 128x4 RAM(32x4 for LCD) - - SM511: 4Kx8 ROM, 128x4 RAM(32x4 for LCD), melody controller - - SM512: 4Kx8 ROM, 128x4 RAM(48x4 for LCD), melody controller - - Sharp SM500 MCU family: - - *SM500: x - - *SM5A: x - - *SM5L: low-power version of SM5A - - *KB1013VK1-2: Soviet-era clone of SM5A - - Sharp SM590 MCU family: - - *SM590: 512x8 ROM, 32x4 RAM - - *SM591: 1kx8 ROM, 56x4 RAM - - *SM595: 768x8 ROM, 32x4 RAM + Sharp SM5xx family, using SM510 as parent device References: + - 1986 Sharp Semiconductor Data Book - 1990 Sharp Microcomputers Data Book - 1996 Sharp Microcomputer Databook - KB1013VK1-2/KB1013VK4-2 manual TODO: - - finish SM500 emulation (gen.1 Game & Watch) - - finish SM590/SM595 emulation (NES/SNES CIC) + - source organiziation between files is a mess - proper support for LFSR program counter in debugger - - callback for lcd screen as MAME bitmap (when needed) - LCD bs pin blink mode via Y register (0.5s off, 0.5s on) - wake up after CEND doesn't work right - - SM510 buzzer control divider bit is mask-programmable? - - SM511 undocumented/guessed opcodes: - * $01 is guessed as DIV to ACC transfer, unknown which bits - * $5d is certainly CEND - * $65 is certainly divider reset, but not sure if it behaves same as on SM510 - * $6036 and $6037 may be instruction timing? (16kHz and 8kHz), mnemonics unknown + + for more, see the *core.cpp file notes */ @@ -173,7 +152,7 @@ void sm510_base_device::device_reset() m_halt = false; m_sbm = false; m_op = m_prev_op = 0; - do_branch(3, 7, 0); + reset_vector(); m_prev_pc = m_pc; // lcd is on (Bp on, BC off, bs(y) off) @@ -204,7 +183,7 @@ inline u16 sm510_base_device::get_lcd_row(int column, u8* ram) return rowdata; } -TIMER_CALLBACK_MEMBER(sm510_base_device::lcd_timer_cb) +void sm510_base_device::lcd_update() { // 4 columns for (int h = 0; h < 4; h++) @@ -218,16 +197,19 @@ TIMER_CALLBACK_MEMBER(sm510_base_device::lcd_timer_cb) u8 bs = (m_l >> h & 1) | ((m_x*2) >> h & 2); m_write_segbs(h | SM510_PORT_SEGBS, (m_bc || !m_bp) ? 0 : bs, 0xffff); } +} - // schedule next timeout - m_lcd_timer->adjust(attotime::from_ticks(0x200, unscaled_clock())); +TIMER_CALLBACK_MEMBER(sm510_base_device::lcd_timer_cb) +{ + lcd_update(); } 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 + attotime period = attotime::from_ticks(0x200, unscaled_clock()); // 64hz default + m_lcd_timer->adjust(period, 0, period); } @@ -244,7 +226,7 @@ bool sm510_base_device::wake_me_up() // note: official doc warns that Bl/Bm and the stack are undefined // after waking up, but we leave it unchanged m_halt = false; - do_branch(1, 0, 0); + wakeup_vector(); standard_irq_callback(0); return true; diff --git a/src/devices/cpu/sm510/sm510core.cpp b/src/devices/cpu/sm510/sm510core.cpp index 6dd60abccd8..e9bb5c5b089 100644 --- a/src/devices/cpu/sm510/sm510core.cpp +++ b/src/devices/cpu/sm510/sm510core.cpp @@ -4,6 +4,9 @@ Sharp SM510 MCU core implementation + TODO: + - buzzer control divider bit is mask-programmable? + */ #include "emu.h" @@ -12,7 +15,7 @@ // MCU types -DEFINE_DEVICE_TYPE(SM510, sm510_device, "sm510", "SM510") +DEFINE_DEVICE_TYPE(SM510, sm510_device, "sm510", "SM510") // 2.7Kx8 ROM, 128x4 RAM(32x4 for LCD) // internal memory maps diff --git a/src/devices/cpu/sm510/sm511core.cpp b/src/devices/cpu/sm510/sm511core.cpp index d2e911b02dd..04f3cdfee24 100644 --- a/src/devices/cpu/sm510/sm511core.cpp +++ b/src/devices/cpu/sm510/sm511core.cpp @@ -3,6 +3,13 @@ /* Sharp SM511 MCU core implementation + + TODO: + - undocumented/guessed opcodes: + * $01 is guessed as DIV to ACC transfer, unknown which bits + * $5d is certainly CEND + * $65 is certainly divider reset, but not sure if it behaves same as on SM510 + * $6036 and $6037 may be instruction timing? (16kHz and 8kHz), mnemonics unknown */ @@ -12,8 +19,8 @@ // MCU types -DEFINE_DEVICE_TYPE(SM511, sm511_device, "sm511", "SM511") -DEFINE_DEVICE_TYPE(SM512, sm512_device, "sm512", "SM512") +DEFINE_DEVICE_TYPE(SM511, sm511_device, "sm511", "SM511") // 4Kx8 ROM, 128x4 RAM(32x4 for LCD), melody controller +DEFINE_DEVICE_TYPE(SM512, sm512_device, "sm512", "SM512") // 4Kx8 ROM, 128x4 RAM(48x4 for LCD), melody controller // internal memory maps diff --git a/src/devices/cpu/sm510/sm590.h b/src/devices/cpu/sm510/sm590.h index 517aebe37f6..42cdb879cec 100644 --- a/src/devices/cpu/sm510/sm590.h +++ b/src/devices/cpu/sm510/sm590.h @@ -102,14 +102,17 @@ protected: virtual void device_reset() override; virtual offs_t disasm_disassemble(std::ostream &stream, offs_t pc, const u8 *oprom, const u8 *opram, u32 options) override; - virtual void init_divider() override; - virtual void init_lcd_driver() override; - virtual void init_melody() override; + virtual void init_divider() override { } + virtual void init_lcd_driver() override { } + virtual void init_melody() override { } virtual void increment_pc() override; virtual void execute_one() override; virtual void get_opcode_param() 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; diff --git a/src/devices/cpu/sm510/sm590core.cpp b/src/devices/cpu/sm510/sm590core.cpp index 4abe76a2d80..a44f7c83296 100644 --- a/src/devices/cpu/sm510/sm590core.cpp +++ b/src/devices/cpu/sm510/sm590core.cpp @@ -3,6 +3,9 @@ /* Sharp SM590 MCU core implementation + + TODO: + - finish SM590/SM595 emulation (NES/SNES CIC) */ @@ -12,9 +15,9 @@ // MCU types -DEFINE_DEVICE_TYPE(SM590, sm590_device, "sm590", "SM590") -//DEFINE_DEVICE_TYPE(SM591, sm591_device, "sm591", "SM591") -//DEFINE_DEVICE_TYPE(SM595, sm595_device, "sm595", "SM595") +DEFINE_DEVICE_TYPE(SM590, sm590_device, "sm590", "SM590") // 512x8 ROM, 32x4 RAM +//DEFINE_DEVICE_TYPE(SM591, sm591_device, "sm591", "SM591") // 1kx8 ROM, 56x4 RAM +//DEFINE_DEVICE_TYPE(SM595, sm595_device, "sm595", "SM595") // 768x8 ROM, 32x4 RAM // internal memory maps static ADDRESS_MAP_START(program_1x128x4, AS_PROGRAM, 8, sm510_base_device) @@ -83,20 +86,13 @@ void sm590_device::device_reset() m_halt = false; m_sbm = false; // needed? m_op = m_prev_op = 0; - do_branch(0, 0, 0); + reset_vector(); m_prev_pc = m_pc; m_rports[0] = m_rports[1] = m_rports[2] = m_rports[3] = 0; //m_write_r(0, 0, 0xff); // TODO: are the four ports zeroed on reset? } -//------------------------------------------------- -// init overrides -//------------------------------------------------- -void sm590_device::init_divider() {} // doesn't have it -void sm590_device::init_lcd_driver() {} // doesn't have it -void sm590_device::init_melody() {} // doesn't have it - //------------------------------------------------- // execute //------------------------------------------------- diff --git a/src/devices/cpu/sm510/sm5acore.cpp b/src/devices/cpu/sm510/sm5acore.cpp index ab402e535ba..04989bef418 100644 --- a/src/devices/cpu/sm510/sm5acore.cpp +++ b/src/devices/cpu/sm510/sm5acore.cpp @@ -3,6 +3,9 @@ /* Sharp SM5A MCU core implementation + + TODO: + - confirm SM5A mnemonics */ @@ -12,9 +15,9 @@ // MCU types -DEFINE_DEVICE_TYPE(SM5A, sm5a_device, "sm5a", "SM5A") -DEFINE_DEVICE_TYPE(SM5L, sm5l_device, "sm5l", "SM5L") -DEFINE_DEVICE_TYPE(KB1013VK12, kb1013vk12_device, "kb1013vk1_2", "KB1013VK1-2") +DEFINE_DEVICE_TYPE(SM5A, sm5a_device, "sm5a", "SM5A") // 1.8K ROM, 5x13x4 RAM, shift registers for LCD +DEFINE_DEVICE_TYPE(SM5L, sm5l_device, "sm5l", "SM5L") // low-power version of SM5A +DEFINE_DEVICE_TYPE(KB1013VK12, kb1013vk12_device, "kb1013vk1_2", "KB1013VK1-2") // Soviet-era clone of SM5A // internal memory maps @@ -71,75 +74,75 @@ void sm5a_device::execute_one() { switch (m_op & 0xf0) { - case 0x20: op_lax(); break; // LC - case 0x30: op_adx(); break; // AS/A10 - case 0x40: op_lb(); break; // LAS - case 0x70: op_ssr(); break; // LP + case 0x20: op_lax(); break; + case 0x30: op_adx(); break; + case 0x40: op_lb(); break; + case 0x70: op_ssr(); break; case 0x80: case 0x90: case 0xa0: case 0xb0: - op_tr(); break; // BR (LP+this=JMP) + op_tr(); break; case 0xc0: case 0xd0: case 0xe0: case 0xf0: - op_trs(); break; // CBR/CZP (LP+this=CAL) + op_trs(); break; default: switch (m_op & 0xfc) { - case 0x04: op_rm(); break; // BM0 - case 0x0c: op_sm(); break; // BM1 - case 0x10: op_exc(); break; // XM/XE - case 0x14: op_exci(); break; // XI/XEI - case 0x18: op_lda(); break; // LE - case 0x1c: op_excd(); break; // XD/XED - case 0x54: op_tmi(); break; // SM1 + case 0x04: op_rm(); break; + case 0x0c: op_sm(); break; + case 0x10: op_exc(); break; + case 0x14: op_exci(); break; + case 0x18: op_lda(); break; + case 0x1c: op_excd(); break; + case 0x54: op_tmi(); break; default: switch (m_op) { - case 0x00: op_skip(); break; // NOP - case 0x01: op_atr(); break; // OAR - case 0x02: op_sbm(); break; // *BS1 + case 0x00: op_skip(); break; + case 0x01: op_atr(); break; + case 0x02: op_sbm(); break; case 0x03: op_atbp(); break; - case 0x08: op_add(); break; // AM - case 0x09: op_add11(); break; // AC - case 0x0a: op_coma(); break; // COM - case 0x0b: op_exbla(); break; // XL + case 0x08: op_add(); break; + case 0x09: op_add11(); break; + case 0x0a: op_coma(); break; + case 0x0b: op_exbla(); break; - case 0x50: op_tal(); break; // SI1 - case 0x51: op_tb(); break; // SI0 - case 0x52: op_tc(); break; // SCO - case 0x53: op_tam(); break; // SAM - case 0x58: op_tis(); break; // TIM + case 0x50: op_tal(); break; + case 0x51: op_tb(); break; + case 0x52: op_tc(); break; + case 0x53: op_tam(); break; + case 0x58: op_tis(); break; case 0x59: op_ptw(); break; - case 0x5a: op_ta0(); break; // SAO - case 0x5b: op_tabl(); break; // SAL + case 0x5a: op_ta0(); break; + case 0x5b: op_tabl(); break; case 0x5c: op_tw(); break; case 0x5d: op_dtw(); break; - case 0x5f: op_lbl(); break; // LAF + case 0x5f: op_lbl(); break; case 0x60: op_comcn(); break; case 0x61: op_pdtw(); break; case 0x62: op_wr(); break; case 0x63: op_ws(); break; - case 0x64: op_incb(); break; // INC - case 0x65: op_idiv(); break; // SYN - case 0x66: op_rc(); break; // CLC - case 0x67: op_sc(); break; // STC - case 0x68: op_rmf(); break; // CLL - case 0x69: op_smf(); break; // LD0 - case 0x6a: op_kta(); break; // ICD - case 0x6b: op_rbm(); break; // *BS0 - case 0x6c: op_decb(); break; // DEC - case 0x6d: op_comcb(); break; // CMS - case 0x6e: op_rtn0(); break; // RT - case 0x6f: op_rtn1(); break; // RTS + case 0x64: op_incb(); break; + case 0x65: op_idiv(); break; + case 0x66: op_rc(); break; + case 0x67: op_sc(); break; + case 0x68: op_rmf(); break; + case 0x69: op_smf(); break; + case 0x6a: op_kta(); break; + case 0x6b: op_rbm(); break; + case 0x6c: op_decb(); break; + case 0x6d: op_comcb(); break; + case 0x6e: op_rtn0(); break; + case 0x6f: op_rtn1(); break; // extended opcodes case 0x5e: m_op = m_op << 8 | m_param; switch (m_param) { - case 0x00: op_cend(); break; // HLT - case 0x04: op_dta(); break; // LDF + case 0x00: op_cend(); break; + case 0x04: op_dta(); break; default: op_illegal(); break; }