mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
sm5*: update notes (nw)
This commit is contained in:
parent
9814aba49e
commit
c7301ced32
@ -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();
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
//-------------------------------------------------
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user