summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/cpu
diff options
context:
space:
mode:
author hap <happppp@users.noreply.github.com>2022-03-13 11:05:12 +0100
committer hap <happppp@users.noreply.github.com>2022-03-13 11:05:26 +0100
commitdb6c9c1d9aff7b8605f61fd07be5c3779406d54a (patch)
treeba0fdf99ede29b8117bd929c881b2d900e59a2ff /src/devices/cpu
parent1ad39cb5dd52e87c4b00b17456a1dcdbb89e74d7 (diff)
New working machines
-------------------- Star Fox (Nelsonic) New machines marked as NOT_WORKING ---------------------------------- Super Mario Bros. 3 (Nelsonic) Super Mario World (Nelsonic)
Diffstat (limited to 'src/devices/cpu')
-rw-r--r--src/devices/cpu/sm510/sm500.cpp8
-rw-r--r--src/devices/cpu/sm510/sm500.h22
-rw-r--r--src/devices/cpu/sm510/sm500op.cpp13
-rw-r--r--src/devices/cpu/sm510/sm510.cpp2
-rw-r--r--src/devices/cpu/sm510/sm510.h62
-rw-r--r--src/devices/cpu/sm510/sm510base.cpp53
-rw-r--r--src/devices/cpu/sm510/sm510base.h18
-rw-r--r--src/devices/cpu/sm510/sm510op.cpp21
-rw-r--r--src/devices/cpu/sm510/sm511.cpp6
-rw-r--r--src/devices/cpu/sm510/sm511.h1
-rw-r--r--src/devices/cpu/sm510/sm530.cpp125
-rw-r--r--src/devices/cpu/sm510/sm530.h90
-rw-r--r--src/devices/cpu/sm510/sm530op.cpp80
-rw-r--r--src/devices/cpu/sm510/sm590.cpp4
-rw-r--r--src/devices/cpu/sm510/sm590.h9
-rw-r--r--src/devices/cpu/sm510/sm590op.cpp4
-rw-r--r--src/devices/cpu/sm510/sm5a.cpp16
-rw-r--r--src/devices/cpu/sm510/sm5a.h26
18 files changed, 392 insertions, 168 deletions
diff --git a/src/devices/cpu/sm510/sm500.cpp b/src/devices/cpu/sm510/sm500.cpp
index e9772a1780c..347f17423dd 100644
--- a/src/devices/cpu/sm510/sm500.cpp
+++ b/src/devices/cpu/sm510/sm500.cpp
@@ -65,7 +65,6 @@ void sm500_device::device_start()
// init/zerofill
memset(m_ox, 0, sizeof(m_ox));
memset(m_o, 0, sizeof(m_o));
- m_cn = 0;
m_mx = 0;
m_cb = 0;
m_s = 0;
@@ -74,7 +73,6 @@ void sm500_device::device_start()
// register for savestates
save_item(NAME(m_ox));
save_item(NAME(m_o));
- save_item(NAME(m_cn));
save_item(NAME(m_mx));
save_item(NAME(m_cb));
save_item(NAME(m_s));
@@ -95,7 +93,7 @@ void sm500_device::device_reset()
// SM500 specific
push_stack();
op_idiv();
- m_1s = true;
+ m_gamma = 1;
m_cb = 0;
m_rsub = false;
m_r = 0xf;
@@ -109,14 +107,14 @@ void sm500_device::device_reset()
void sm500_device::lcd_update()
{
- // 2 columns
+ // 2 rows
for (int h = 0; h < 2; h++)
{
for (int o = 0; o < m_o_pins; o++)
{
// 4 segments per group
u8 seg = h ? m_ox[o] : m_o[o];
- m_write_segs(o << 1 | h, m_bp ? seg : 0, 0xffff);
+ m_write_segs(o << 1 | h, (m_bp & 1) ? seg : 0);
}
}
}
diff --git a/src/devices/cpu/sm510/sm500.h b/src/devices/cpu/sm510/sm500.h
index c0d097df61e..90be21ca184 100644
--- a/src/devices/cpu/sm510/sm500.h
+++ b/src/devices/cpu/sm510/sm500.h
@@ -23,20 +23,31 @@
________________________________________________
| |
O23 37 | | 24 OS2
+ | |
O13 38 | | 23 OS3
+ | |
O44 39 | | 22 OS4
+ | |
O34 40 | | 21 H1
+ | |
O24 41 | | 20 H2
-O14 42 | SM500 | 19 Vm
+ | |
+O14 42 | | 19 Vm
+ | SM500 |
O45 43 | | 18 OSCin
+ | |
O35 44 | | 17 OSCout
+ | |
O25 45 | | 16 Vdd
+ | |
O15 46 | | 15 K4
+ | |
O46 47 | | 14 K3
-O36 48 | * | 13 K2
+ | |
+O36 48 | * | 13 K2
|________________________________________________/
- 1 2 3 4 5 6 7 8 9 10 11 12
+ 1 2 3 4 5 6 7 8 9 10 11 12
O26 O16 R4 R3 R2 R1 GND _T bt al ACL K1 note: bt = beta symbol, al = alpha symbol
*/
@@ -67,7 +78,6 @@ protected:
int m_o_pins; // number of 4-bit O pins
u8 m_ox[9]; // W' latch, max 9
u8 m_o[9]; // W latch
- u8 m_cn;
u8 m_mx;
u8 m_cb;
@@ -76,11 +86,12 @@ protected:
void shift_w();
u8 get_digit();
+
+ // opcode handlers
void set_su(u8 su) { m_stack[0] = (m_stack[0] & ~0x3c0) | (su << 6 & 0x3c0); }
u8 get_su() { return m_stack[0] >> 6 & 0xf; }
virtual int get_trs_field() { return 0; }
- // opcode handlers
virtual void op_lb() override;
virtual void op_incb() override;
virtual void op_sbm() override;
@@ -92,7 +103,6 @@ protected:
virtual void op_tr();
virtual void op_trs();
- virtual void op_atbp() override;
virtual void op_ptw() override;
virtual void op_tw();
virtual void op_pdtw();
diff --git a/src/devices/cpu/sm510/sm500op.cpp b/src/devices/cpu/sm510/sm500op.cpp
index 9fb66a8a4cc..39af8e6020b 100644
--- a/src/devices/cpu/sm510/sm500op.cpp
+++ b/src/devices/cpu/sm510/sm500op.cpp
@@ -25,7 +25,9 @@ u8 sm500_device::get_digit()
0xb, 0x9, 0x7, 0xf, 0xd, 0xe, 0xe, 0xb, 0xf, 0xf, 0x4, 0x0, 0xd, 0xe, 0x4, 0x0
};
- return lut_digits[m_cn << 4 | m_acc] | (~m_cn & m_mx);
+ // row select is from BP d3 (aka CN flag)
+ u8 sel = BIT(m_bp, 3);
+ return lut_digits[sel << 4 | m_acc] | (~sel & m_mx);
}
@@ -110,13 +112,6 @@ void sm500_device::op_trs()
// Data transfer instructions
-void sm500_device::op_atbp()
-{
- // ATBP: same as SM510, and set CN with ACC3
- sm510_base_device::op_atbp();
- m_cn = m_acc >> 3 & 1;
-}
-
void sm500_device::op_ptw()
{
// PTW: partial transfer W' to W
@@ -206,5 +201,5 @@ void sm500_device::op_smf()
void sm500_device::op_comcn()
{
// COMCN: complement CN flag
- m_cn ^= 1;
+ m_bp ^= 8;
}
diff --git a/src/devices/cpu/sm510/sm510.cpp b/src/devices/cpu/sm510/sm510.cpp
index 35c141dcde8..fa35d53e0ec 100644
--- a/src/devices/cpu/sm510/sm510.cpp
+++ b/src/devices/cpu/sm510/sm510.cpp
@@ -156,7 +156,7 @@ void sm510_device::execute_one()
} // big switch
// BM high bit is only valid for 1 step
- m_sbm = (m_op == 0x02);
+ m_bmask = (m_op == 0x02) ? 0x40 : 0;
}
bool sm510_device::op_argument()
diff --git a/src/devices/cpu/sm510/sm510.h b/src/devices/cpu/sm510/sm510.h
index c85bd374eb4..af1e18d2861 100644
--- a/src/devices/cpu/sm510/sm510.h
+++ b/src/devices/cpu/sm510/sm510.h
@@ -18,30 +18,44 @@
/*
- b2 a3 b3 a4 b4 a5 b5 GNDa6 b6 a7 b7 a8 b8 a9
- 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
- ______________________________________________
- | |
-a2 46 | | 30 b9
-b1 47 | | 29 a10
-a1 48 | | 28 b10
-H4 49 | | 27 a11
-H3 50 | | 26 b11
-H2 51 | | 25 a12
-H1 52 | | 24 b12
-S1 53 | SM510 | 23 a13
-S2 54 | | 22 b13
-S3 55 | | 21 a14
-S4 56 | | 20 b14
-S5 57 | | 19 a15
-S6 58 | | 18 b15
-S7 59 | | 17 a16
-S8 60 | * | 16 b16
- |______________________________________________/
-
- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
- T K1 K2 K3 K4 ACL | GND |OSCin| bt R1 R2 bs note: bt = beta symbol
- BA OSCout Vdd
+ b2 a3 b3 a4 b4 a5 b5 GND a6 b6 a7 b7 a8 b8 a9
+ 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31
+ ____________________________________________________________
+ | |
+a2 46 | | 30 b9
+ | |
+b1 47 | | 29 a10
+ | |
+a1 48 | | 28 b10
+ | |
+H4 49 | | 27 a11
+ | |
+H3 50 | | 26 b11
+ | |
+H2 51 | | 25 a12
+ | |
+H1 52 | | 24 b12
+ | SM510 |
+S1 53 | SM511 | 23 a13
+ | |
+S2 54 | | 22 b13
+ | |
+S3 55 | | 21 a14
+ | |
+S4 56 | | 20 b14
+ | |
+S5 57 | | 19 a15
+ | |
+S6 58 | | 18 b15
+ | |
+S7 59 | | 17 a16
+ | |
+S8 60 | * | 16 b16
+ |____________________________________________________________/
+
+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ T K1 K2 K3 K4 ACL BA GND OSC OSC Vdd bt R1 R2 bs note: bt = beta symbol
+ out in
*/
class sm510_device : public sm510_base_device
diff --git a/src/devices/cpu/sm510/sm510base.cpp b/src/devices/cpu/sm510/sm510base.cpp
index c260c07667b..ec169a00e40 100644
--- a/src/devices/cpu/sm510/sm510base.cpp
+++ b/src/devices/cpu/sm510/sm510base.cpp
@@ -55,16 +55,14 @@ void sm510_base_device::device_start()
m_acc = 0;
m_bl = 0;
m_bm = 0;
- m_sbl = false;
- m_sbm = false;
+ m_bmask = 0;
m_c = 0;
m_skip = false;
m_w = 0;
m_r = 0;
m_r_out = 0;
m_div = 0;
- m_1s = false;
- m_1s_rise = false;
+ m_gamma = 0;
m_ext_wakeup = false;
m_l = 0;
m_x = 0;
@@ -89,16 +87,14 @@ void sm510_base_device::device_start()
save_item(NAME(m_acc));
save_item(NAME(m_bl));
save_item(NAME(m_bm));
- save_item(NAME(m_sbl));
- save_item(NAME(m_sbm));
+ save_item(NAME(m_bmask));
save_item(NAME(m_c));
save_item(NAME(m_skip));
save_item(NAME(m_w));
save_item(NAME(m_r));
save_item(NAME(m_r_out));
save_item(NAME(m_div));
- save_item(NAME(m_1s));
- save_item(NAME(m_1s_rise));
+ save_item(NAME(m_gamma));
save_item(NAME(m_ext_wakeup));
save_item(NAME(m_l));
save_item(NAME(m_x));
@@ -152,8 +148,7 @@ void sm510_base_device::device_reset()
// ACL
m_skip = false;
m_halt = false;
- m_sbl = false;
- m_sbm = false;
+ m_bmask = 0;
m_op = m_prev_op = 0;
reset_vector();
m_prev_pc = m_pc;
@@ -175,7 +170,7 @@ void sm510_base_device::device_reset()
inline u16 sm510_base_device::get_lcd_row(int column, u8* ram)
{
// output 0 if lcd blackpate/bleeder is off, or in case row doesn't exist
- if (ram == nullptr || m_bc || !m_bp)
+ if (ram == nullptr || m_bc || !(m_bp & 1))
return 0;
u16 rowdata = 0;
@@ -191,14 +186,14 @@ void sm510_base_device::lcd_update()
for (int h = 0; h < 4; h++)
{
// 16 segments per row from upper part of RAM
- m_write_segs(h | SM510_PORT_SEGA, get_lcd_row(h, m_lcd_ram_a), 0xffff);
- m_write_segs(h | SM510_PORT_SEGB, get_lcd_row(h, m_lcd_ram_b), 0xffff);
- m_write_segs(h | SM510_PORT_SEGC, get_lcd_row(h, m_lcd_ram_c), 0xffff);
+ m_write_segs(h | SM510_PORT_SEGA, get_lcd_row(h, m_lcd_ram_a));
+ m_write_segs(h | SM510_PORT_SEGB, get_lcd_row(h, m_lcd_ram_b));
+ m_write_segs(h | SM510_PORT_SEGC, get_lcd_row(h, m_lcd_ram_c));
// bs output from L/X and Y regs
u8 blink = (m_div & 0x4000) ? m_y : 0;
u8 bs = ((m_l & ~blink) >> h & 1) | ((m_x*2) >> h & 2);
- m_write_segs(h | SM510_PORT_SEGBS, (m_bc || !m_bp) ? 0 : bs, 0xffff);
+ m_write_segs(h | SM510_PORT_SEGBS, (m_bc || !(m_bp & 1)) ? 0 : bs);
}
}
@@ -224,12 +219,9 @@ TIMER_CALLBACK_MEMBER(sm510_base_device::div_timer_cb)
{
m_div = (m_div + 1) & 0x7fff;
- // 1S signal on overflow(falling edge of F1)
+ // 1S(gamma) signal on overflow(falling edge of F1)
if (m_div == 0)
- {
- m_1s_rise = !m_1s;
- m_1s = true;
- }
+ m_gamma |= 1;
clock_melody();
}
@@ -237,7 +229,8 @@ TIMER_CALLBACK_MEMBER(sm510_base_device::div_timer_cb)
void sm510_base_device::init_divider()
{
m_div_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sm510_base_device::div_timer_cb), this));
- m_div_timer->adjust(attotime::from_ticks(1, unscaled_clock()), 0, attotime::from_ticks(1, unscaled_clock()));
+ attotime period = attotime::from_ticks(1, unscaled_clock());
+ m_div_timer->adjust(period, 0, period);
}
@@ -279,24 +272,19 @@ void sm510_base_device::increment_pc()
void sm510_base_device::execute_run()
{
- bool prev_1s = m_1s_rise;
-
while (m_icount > 0)
{
- // in halt mode, wake up after 1S signal or K input
- bool wakeup = m_ext_wakeup || m_1s_rise;
- m_1s_rise = false;
-
+ // in halt mode, wake up after gamma signal or K input
if (m_halt)
{
- if (!wakeup)
+ if (m_ext_wakeup || m_gamma)
+ do_interrupt();
+ else
{
// got nothing to do
m_icount = 0;
return;
}
- else
- do_interrupt();
}
m_icount--;
@@ -327,10 +315,5 @@ void sm510_base_device::execute_run()
}
else
execute_one();
-
- // if CEND triggered at the same time as 1S signal, make sure it still wakes up
- if (m_halt)
- m_1s_rise = prev_1s;
- prev_1s = false;
}
}
diff --git a/src/devices/cpu/sm510/sm510base.h b/src/devices/cpu/sm510/sm510base.h
index 4cfdaa2c715..f699c035b26 100644
--- a/src/devices/cpu/sm510/sm510base.h
+++ b/src/devices/cpu/sm510/sm510base.h
@@ -61,7 +61,7 @@ public:
void set_r_mask_option(int bit) { m_r_mask_option = bit; }
static constexpr int RMASK_DIRECT = -1;
- // 4-bit K input port (pull-down)
+ // 4/8-bit K input port (pull-down)
auto read_k() { return m_read_k.bind(); }
// 1-bit BA(aka alpha) input pin (pull-up)
@@ -70,15 +70,16 @@ public:
// 1-bit B(beta) input pin (pull-up)
auto read_b() { return m_read_b.bind(); }
- // 8-bit S strobe output port
+ // 4/8-bit S strobe output port
auto write_s() { return m_write_s.bind(); }
// 1/2/4-bit R (buzzer/melody) output port
+ // may also be called F(frequency?) or SO(sound out)
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,
+ // LCD segment outputs, SM51x: H1-4 as offset(low), a/b/c 1-16 as data d0-d15,
// bs output is same as above, but only up to 2 bits used.
- // SM500/SM5A: H1/2 as a0, O group as a1-a4, O data as d0-d3
+ // SM500/SM5A/SM530: H1/2 as a0, O group as a1-a4, O data as d0-d3
auto write_segs() { return m_write_segs.bind(); }
protected:
@@ -124,8 +125,7 @@ protected:
u8 m_acc;
u8 m_bl;
u8 m_bm;
- bool m_sbm;
- bool m_sbl;
+ u8 m_bmask;
u8 m_c;
bool m_skip;
u8 m_w;
@@ -165,11 +165,10 @@ protected:
// divider
emu_timer *m_div_timer;
u16 m_div;
- bool m_1s;
- bool m_1s_rise;
+ u8 m_gamma;
virtual void init_divider();
- TIMER_CALLBACK_MEMBER(div_timer_cb);
+ virtual TIMER_CALLBACK_MEMBER(div_timer_cb);
// other i/o handlers
devcb_read8 m_read_k;
@@ -193,7 +192,6 @@ protected:
// opcode handlers
virtual void op_lb();
virtual void op_lbl();
- virtual void op_sbl();
virtual void op_sbm();
virtual void op_exbla();
virtual void op_incb();
diff --git a/src/devices/cpu/sm510/sm510op.cpp b/src/devices/cpu/sm510/sm510op.cpp
index 672209861aa..9c7aa24c85c 100644
--- a/src/devices/cpu/sm510/sm510op.cpp
+++ b/src/devices/cpu/sm510/sm510op.cpp
@@ -11,17 +11,13 @@
u8 sm510_base_device::ram_r()
{
- int blh = (m_sbl) ? 8 : 0; // from SBL (optional)
- int bmh = (m_sbm) ? (1 << (m_datawidth-1)) : 0; // from SBM
- u8 address = (bmh | blh | m_bm << 4 | m_bl) & m_datamask;
+ u8 address = (m_bmask | m_bm << 4 | m_bl) & m_datamask;
return m_data->read_byte(address) & 0xf;
}
void sm510_base_device::ram_w(u8 data)
{
- int blh = (m_sbl) ? 8 : 0; // from SBL (optional)
- int bmh = (m_sbm) ? (1 << (m_datawidth-1)) : 0; // from SBM
- u8 address = (bmh | blh | m_bm << 4 | m_bl) & m_datamask;
+ u8 address = (m_bmask | m_bm << 4 | m_bl) & m_datamask;
m_data->write_byte(address, data & 0xf);
}
@@ -70,11 +66,6 @@ void sm510_base_device::op_lbl()
m_bm = (m_param & m_datamask) >> 4;
}
-void sm510_base_device::op_sbl()
-{
- // SBL: set BL high bit for next opcode - handled in execute_one()
-}
-
void sm510_base_device::op_sbm()
{
// SBM: set BM high bit for next opcode - handled in execute_one()
@@ -229,8 +220,8 @@ void sm510_base_device::op_kta()
void sm510_base_device::op_atbp()
{
- // ATBP: output ACC to BP(internal LCD backplate signal)
- m_bp = m_acc & 1;
+ // ATBP: output ACC to BP LCD flag(s)
+ m_bp = m_acc;
}
void sm510_base_device::op_atx()
@@ -352,8 +343,8 @@ void sm510_base_device::op_tabl()
void sm510_base_device::op_tis()
{
// TIS: skip next if 1S(gamma flag) is clear, reset it after
- m_skip = !m_1s;
- m_1s = false;
+ m_skip = !m_gamma;
+ m_gamma = 0;
}
void sm510_base_device::op_tal()
diff --git a/src/devices/cpu/sm510/sm511.cpp b/src/devices/cpu/sm510/sm511.cpp
index b80427c5f8c..9ac8e36699e 100644
--- a/src/devices/cpu/sm510/sm511.cpp
+++ b/src/devices/cpu/sm510/sm511.cpp
@@ -123,8 +123,8 @@ void sm511_device::clock_melody()
m_melody_rd |= 2;
}
- // clock time base on F8(d7)
- if ((m_div & 0x7f) == 0)
+ // clock time base on divider F7/F8
+ if ((m_div & melody_step_mask()) == 0)
{
u8 mask = (cmd & 0x20) ? 0x1f : 0x0f;
m_melody_step_count = (m_melody_step_count + 1) & mask;
@@ -251,7 +251,7 @@ void sm511_device::execute_one()
} // big switch
// BM high bit is only valid for 1 step
- m_sbm = (m_op == 0x02);
+ m_bmask = (m_op == 0x02) ? 0x40 : 0;
}
bool sm511_device::op_argument()
diff --git a/src/devices/cpu/sm510/sm511.h b/src/devices/cpu/sm510/sm511.h
index 54066d1d405..463ede6be04 100644
--- a/src/devices/cpu/sm510/sm511.h
+++ b/src/devices/cpu/sm510/sm511.h
@@ -44,6 +44,7 @@ protected:
virtual void clock_melody() override;
virtual void init_melody() override;
+ virtual u16 melody_step_mask() { return 0x7f; }
};
class sm512_device : public sm511_device
diff --git a/src/devices/cpu/sm510/sm530.cpp b/src/devices/cpu/sm510/sm530.cpp
index 3b73ee036f2..ddc2e24a368 100644
--- a/src/devices/cpu/sm510/sm530.cpp
+++ b/src/devices/cpu/sm510/sm530.cpp
@@ -5,7 +5,12 @@
Sharp SM530 MCU core implementation
TODO:
- - almost everything
+ - is unused RAM unmapped? or mirrored?
+ - add BP3,BP4, they connect the 1s or 1/100s counter to some of the LCD segs
+ - what do BP1,BP2 do? datasheet block diagram shows BP is 4 bit, but it doesn't
+ explain anywhere what they're for
+ - add SM531: not just smaller ROM/RAM, melody controller supposedly supports
+ envelopes (melody ROM is 128x7 instead of 256x6)
*/
@@ -16,8 +21,7 @@
// MCU types
-DEFINE_DEVICE_TYPE(SM530, sm530_device, "sm530", "Sharp SM530") // x
-DEFINE_DEVICE_TYPE(SM531, sm531_device, "sm531", "Sharp SM531") // x
+DEFINE_DEVICE_TYPE(SM530, sm530_device, "sm530", "Sharp SM530") // 2Kx8 ROM, 88x4 RAM(24x4 for LCD), melody controller
// internal memory maps
@@ -47,11 +51,8 @@ sm530_device::sm530_device(const machine_config &mconfig, const char *tag, devic
{ }
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)
-{ }
-
-sm531_device::sm531_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
- sm530_device(mconfig, SM531, tag, owner, clock, 1, 11, address_map_constructor(FUNC(sm531_device::program_2k), this), 7, address_map_constructor(FUNC(sm531_device::data_64_24x4), this))
+ sm511_device(mconfig, type, tag, owner, clock, stack_levels, prgwidth, program, datawidth, data),
+ m_write_f(*this)
{ }
@@ -63,6 +64,21 @@ void sm530_device::device_start()
{
// common init
sm511_device::device_start();
+
+ // resolve callbacks
+ m_write_f.resolve_safe();
+
+ // zerofill
+ m_subdiv = 0;
+ m_count_1s = 0;
+ m_count_10ms = 0;
+ m_ds = false;
+
+ // register for savestates
+ save_item(NAME(m_subdiv));
+ save_item(NAME(m_count_1s));
+ save_item(NAME(m_count_10ms));
+ save_item(NAME(m_ds));
}
@@ -74,6 +90,74 @@ void sm530_device::device_reset()
{
// common reset
sm511_device::device_reset();
+
+ // assume LCD is on
+ m_bp = 0;
+ m_ds = true;
+}
+
+
+//-------------------------------------------------
+// lcd driver
+//-------------------------------------------------
+
+void sm530_device::lcd_update()
+{
+ // 2 rows
+ for (int h = 0; h < 2; h++)
+ {
+ for (int o = 0; o < m_lcd_ram_a.bytes(); o++)
+ {
+ // 4 segments per group
+ u8 seg = h ? m_lcd_ram_b[o] : m_lcd_ram_a[o];
+ m_write_segs(o << 1 | h, m_ds ? seg : 0);
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// divider
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(sm530_device::div_timer_cb)
+{
+ m_div = (m_div + 1) & 0x7fff;
+
+ if (m_div == 0)
+ {
+ // gamma signal on 1s
+ m_gamma |= 2;
+
+ // increment seconds counter
+ m_count_1s = (m_count_1s + 1) % 10;
+
+ // gamma signal on 10s
+ if (m_count_1s == 0)
+ m_gamma |= 1;
+ }
+
+ // gamma signal on 0.5s
+ if ((m_div & 0x3fff) == 0)
+ m_gamma |= 4;
+
+ // secondary timer for 1/100s intervals
+ if ((m_div & 0xff) < 250)
+ {
+ m_subdiv = (m_subdiv + 1) % 32000;
+
+ if ((m_subdiv % 320) == 0)
+ {
+ // increment 1/100s counter
+ m_count_10ms = (m_count_10ms + 1) % 10;
+
+ // gamma signal on 0.1s
+ if (m_count_10ms == 0)
+ m_gamma |= 8;
+ }
+ }
+
+ clock_melody();
}
@@ -105,19 +189,19 @@ void sm530_device::execute_one()
case 0x44: op_sm(); break;
case 0x48: op_tmi(); break; // TM
case 0x60: case 0x64: op_tl(); break;
- //case 0x6c: op_tg(); break;
+ case 0x6c: op_tg(); break;
default:
switch (m_op)
{
case 0x4c: op_incb(); break;
case 0x4d: op_decb(); break;
- //case 0x4e: op_rds(); break;
- //case 0x4f: op_sds(); break;
+ case 0x4e: op_rds(); break;
+ case 0x4f: op_sds(); break;
case 0x50: op_kta(); break;
- //case 0x51: op_keta(); break;
- //case 0x52: op_dta(); break;
+ case 0x51: op_keta(); break;
+ case 0x52: op_dta(); break;
case 0x53: op_coma(); break;
case 0x54: op_add(); break;
case 0x55: op_add11(); break; // ADDC
@@ -127,8 +211,8 @@ void sm530_device::execute_one()
case 0x59: op_tam(); break;
case 0x5a: op_exbla(); break; // EXBL
case 0x5b: op_tc(); break;
- //case 0x5c: op_ats(); break;
- //case 0x5d: op_atf(); break;
+ case 0x5c: op_ats(); break;
+ case 0x5d: op_atf(); break;
case 0x5e: op_atbp(); break;
case 0x68: op_rtn0(); break; // RTN
@@ -136,10 +220,10 @@ void sm530_device::execute_one()
case 0x6a: op_atpl(); break;
case 0x6b: op_lbl(); break;
- //case 0x70: op_idiv(); break;
- //case 0x71: op_inis(); break;
+ case 0x70: op_idiv(); break;
+ case 0x71: op_inis(); break;
case 0x72: op_sbm(); break; // SABM
- case 0x73: op_sbl(); break; // SABL
+ case 0x73: op_sabl(); break;
case 0x74: op_cend(); break;
case 0x75: op_tmel(); break;
case 0x76: op_rme(); break;
@@ -156,9 +240,8 @@ void sm530_device::execute_one()
} // big switch
- // SABL/SABM is only valid for 1 step
- m_sbl = (m_op == 0x73);
- m_sbm = (m_op == 0x72);
+ // SABM/SABL is only valid for 1 step
+ m_bmask = (m_op == 0x72) ? 0x40 : ((m_op == 0x73) ? 0x08 : 0);
}
bool sm530_device::op_argument()
diff --git a/src/devices/cpu/sm510/sm530.h b/src/devices/cpu/sm510/sm530.h
index 66136b89904..a9ea769d679 100644
--- a/src/devices/cpu/sm510/sm530.h
+++ b/src/devices/cpu/sm510/sm530.h
@@ -13,12 +13,67 @@
#include "sm511.h"
+// pinout reference
+
+/*
+ OSC OSC
+ O21 O31 O41 O11 H1 K3 out in ACL BA GND Vm Vdd DDC Vcc K4 O10 O20 O30 O40 O1B
+ 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
+ ____________________________________________________________________________________
+ | |
+O12 61 | | 39 O2B
+ | |
+O42 62 | | 38 O3B
+ | |
+O32 63 | | 37 O4B
+ | |
+O22 64 | | 36 O1A
+ | |
+O13 65 | | 35 O2A
+ | |
+O43 66 | | 34 O3A
+ | |
+O33 67 | | 33 O4A
+ | |
+O23 68 | | 32 O19
+ | |
+O14 69 | | 31 O29
+ | |
+O44 70 | | 30 O39
+ | SM530 |
+O34 71 | | 29 O49
+ | |
+O24 72 | | 28 O18
+ | |
+O15 73 | | 27 O28
+ | |
+O45 74 | | 26 O38
+ | |
+O35 75 | | 25 O48
+ | |
+O25 76 | | 24 O17
+ | |
+O16 77 | | 23 O27
+ | |
+O46 78 | | 22 O37
+ | |
+O36 79 | | 21 O47
+ | /
+O26 80 | * /
+ |__________________________________________________________________________________/
+
+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
+ H2 K2 KE1 KE2 KE3 KE3 S1 S2 S3 S4 GND SO NC NC F1 F2 F3 F4 TEST K1
+*/
class sm530_device : public sm511_device
{
public:
sm530_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 32768);
+ // 4-bit F output port
+ auto write_f() { return m_write_f.bind(); }
+
protected:
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);
@@ -39,26 +94,45 @@ protected:
virtual void reset_vector() override { do_branch(0xf, 0); }
virtual void wakeup_vector() override { do_branch(0, 0); }
+ devcb_write8 m_write_f;
+
+ // lcd driver
+ virtual void lcd_update() override;
+ bool m_ds;
+
+ // divider
+ virtual TIMER_CALLBACK_MEMBER(div_timer_cb) override;
+ u16 m_subdiv;
+ u8 m_count_1s;
+ u8 m_count_10ms;
+
+ virtual u16 melody_step_mask() override { return 0xff; }
+
// opcode handlers
- virtual void op_lb() override;
virtual void op_incb() override;
+ virtual void op_lb() override;
+ virtual void op_sabl();
virtual void op_tl() override;
virtual void op_trs();
+ virtual void op_dta() override;
+
virtual void op_adx() override;
- virtual void op_atbp() override;
-};
+ virtual void op_tg();
-class sm531_device : public sm530_device
-{
-public:
- sm531_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 32768);
+ virtual void op_keta();
+ virtual void op_ats();
+ virtual void op_atf();
+ virtual void op_sds();
+ virtual void op_rds();
+
+ virtual void op_idiv() override;
+ virtual void op_inis();
};
DECLARE_DEVICE_TYPE(SM530, sm530_device)
-DECLARE_DEVICE_TYPE(SM531, sm531_device)
#endif // MAME_CPU_SM510_SM530_H
diff --git a/src/devices/cpu/sm510/sm530op.cpp b/src/devices/cpu/sm510/sm530op.cpp
index 6beaa8905f4..a8a55d89d7b 100644
--- a/src/devices/cpu/sm510/sm530op.cpp
+++ b/src/devices/cpu/sm510/sm530op.cpp
@@ -20,6 +20,13 @@ void sm530_device::do_branch(u8 pu, u8 pl)
// RAM address instructions
+void sm530_device::op_incb()
+{
+ // INCB: increment BL, but overflow on 3rd bit!
+ sm511_device::op_incb();
+ m_skip = ((m_bl & 7) == 0);
+}
+
void sm530_device::op_lb()
{
// LB x: load BM/BL with 4-bit immediate value (partial)
@@ -27,11 +34,9 @@ void sm530_device::op_lb()
m_bm = m_op >> 2 & 3;
}
-void sm530_device::op_incb()
+void sm530_device::op_sabl()
{
- // INCB: increment BL, but overflow on 3rd bit!
- sm510_base_device::op_incb();
- m_skip = (m_bl == 8);
+ // SABL: set BL high bit for next opcode - handled in execute_one()
}
@@ -49,7 +54,16 @@ void sm530_device::op_trs()
m_icount--;
push_stack();
u8 jump = m_program->read_byte((14 << 6) | (m_op & 0x3f));
- do_branch(jump >> 5 & 7, jump & 0x1f);
+ do_branch(bitswap<3>(jump, 5,7,6), jump & 0x1f);
+}
+
+
+// Data transfer instructions
+
+void sm530_device::op_dta()
+{
+ // DTA: transfer 1/100s counter to ACC
+ m_acc = m_count_10ms;
}
@@ -64,10 +78,60 @@ void sm530_device::op_adx()
}
+// Test instructions
+
+void sm530_device::op_tg()
+{
+ // TG x: skip next if gamma flag is set, reset it after
+ m_skip = bool(m_gamma & bitmask(m_op));
+ m_gamma &= ~bitmask(m_op);
+}
+
+
// I/O instructions
-void sm530_device::op_atbp()
+void sm530_device::op_keta()
+{
+ // KETA: input KE to ACC
+ m_acc = m_read_k() >> 4 & 0xf;
+}
+
+void sm530_device::op_ats()
+{
+ // ATS: output ACC to S
+ m_write_s(m_acc);
+}
+
+void sm530_device::op_atf()
+{
+ // ATS: output ACC to F
+ m_write_f(m_acc);
+}
+
+void sm530_device::op_sds()
+{
+ // SDS: set display enable
+ m_ds = true;
+}
+
+void sm530_device::op_rds()
+{
+ // RDS: reset display enable
+ m_ds = false;
+}
+
+
+// Special instructions
+
+void sm530_device::op_idiv()
+{
+ // IDIV: reset divider and 1s counter
+ m_div = m_subdiv = 0;
+ m_count_1s = 0;
+}
+
+void sm530_device::op_inis()
{
- // ATBP: output ACC to BP
- m_bp = m_acc;
+ // INIS: reset 1/100s counter
+ m_count_10ms = 0;
}
diff --git a/src/devices/cpu/sm510/sm590.cpp b/src/devices/cpu/sm510/sm590.cpp
index d45fbbe7a82..790e8578a54 100644
--- a/src/devices/cpu/sm510/sm590.cpp
+++ b/src/devices/cpu/sm510/sm590.cpp
@@ -7,8 +7,6 @@
TODO:
- finish SM590/SM595 emulation (NES/SNES CIC)
- http://bitsavers.informatik.uni-stuttgart.de/pdf/sharp/_dataBooks/1990_Sharp_Microcomputers_Data_Book.pdf
- pdf page 35/doc page 26 thru pdf page 44/doc page 35
*/
#include "emu.h"
@@ -67,11 +65,9 @@ void sm590_device::device_reset()
// ACL
m_skip = false;
m_halt = false;
- m_sbm = false; // needed?
m_op = m_prev_op = 0;
reset_vector();
m_prev_pc = m_pc;
- m_clk_div = 4; // 4 clock oscillations per cycle on SM59x, see datasheet page 30/pdf page 39
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?
diff --git a/src/devices/cpu/sm510/sm590.h b/src/devices/cpu/sm510/sm590.h
index 5a0023642c8..93fedc460c1 100644
--- a/src/devices/cpu/sm510/sm590.h
+++ b/src/devices/cpu/sm510/sm590.h
@@ -98,10 +98,13 @@ protected:
void data_16x2x4(address_map &map);
virtual void device_reset() override;
+
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
- virtual void init_divider() override { }
- virtual void init_lcd_driver() override { }
- virtual void init_melody() override { }
+ virtual u64 execute_clocks_to_cycles(u64 clocks) const noexcept override { return (clocks + 4 - 1) / 4; } // 4 cycles per machine cycle
+ virtual u64 execute_cycles_to_clocks(u64 cycles) const noexcept override { return (cycles * 4); } // "
+
+ 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;
diff --git a/src/devices/cpu/sm510/sm590op.cpp b/src/devices/cpu/sm510/sm590op.cpp
index ff0b902c697..7a2c3f09ade 100644
--- a/src/devices/cpu/sm510/sm590op.cpp
+++ b/src/devices/cpu/sm510/sm590op.cpp
@@ -139,14 +139,14 @@ void sm590_device::op_lbmx()
void sm590_device::op_tl()
{
// TL xyz: long jump (same as sm510 TL except m_op and m_param masks)
- do_branch((m_op & 2)>>1, (((m_op & 1)<<1)|((m_param&0x80)?1:0)), m_param & 0x7f);
+ do_branch(BIT(m_op, 1), (m_op << 1 & 2) | BIT(m_param, 7), m_param & 0x7f);
}
void sm590_device::op_tml() // aka TLS
{
// TLS xyz: long call (same as sm510 TML except m_param mask)
push_stack();
- do_branch((m_op & 2)>>1, (((m_op & 1)<<1)|((m_param&0x80)?1:0)), m_param & 0x7f);
+ do_branch(BIT(m_op, 1), (m_op << 1 & 2) | BIT(m_param, 7), m_param & 0x7f);
}
void sm590_device::op_t()
diff --git a/src/devices/cpu/sm510/sm5a.cpp b/src/devices/cpu/sm510/sm5a.cpp
index a6dbf24edab..298cefe9b2f 100644
--- a/src/devices/cpu/sm510/sm5a.cpp
+++ b/src/devices/cpu/sm510/sm5a.cpp
@@ -30,16 +30,12 @@ void sm5a_device::program_1_8k(address_map &map)
void sm5a_device::data_5x13x4(address_map &map)
{
- map(0x00, 0x0b).ram();
- map(0x0c, 0x0c).ram().mirror(0x03);
- map(0x10, 0x1b).ram();
- map(0x1c, 0x1c).ram().mirror(0x03);
- map(0x20, 0x2b).ram();
- map(0x2c, 0x2c).ram().mirror(0x03);
- map(0x30, 0x3b).ram();
- map(0x3c, 0x3c).ram().mirror(0x03);
- map(0x40, 0x4b).ram().mirror(0x30);
- map(0x4c, 0x4c).ram().mirror(0x33);
+ map(0x00, 0x7f).rw(FUNC(sm5a_device::mirror_r), FUNC(sm5a_device::mirror_w)); // d,e,f -> c
+ map(0x00, 0x0c).ram();
+ map(0x10, 0x1c).ram();
+ map(0x20, 0x2c).ram();
+ map(0x30, 0x3c).ram();
+ map(0x40, 0x4c).ram().mirror(0x30);
}
diff --git a/src/devices/cpu/sm510/sm5a.h b/src/devices/cpu/sm510/sm5a.h
index de7128078d6..a44c687dfd9 100644
--- a/src/devices/cpu/sm510/sm5a.h
+++ b/src/devices/cpu/sm510/sm5a.h
@@ -23,23 +23,37 @@
____________________________________________________________
| |
OS1 46 | | 30 H1
+ | |
O41 47 | | 29 H2
+ | |
O31 48 | | 28 Vm
+ | |
O21 49 | | 27 Vdd
+ | |
O11 50 | | 26 _R2
+ | |
O42 51 | | 25 _R3
-O32 52 | SM5A | 24 _R4
-O22 53 | SM5L | 23 OSCin
+ | |
+O32 52 | | 24 _R4
+ | SM5A |
+O22 53 | SM5L | 23 OSCin
+ | |
O12 54 | | 22 OSCout
+ | |
O43 55 | | 21 _T2
+ | |
O33 56 | | 20 _T1
+ | |
O23 57 | | 19 O18
+ | |
O13 58 | | 18 O28
+ | |
O44 59 | | 17 O38
-O34 60 | * | 16 O48
+ | |
+O34 60 | * | 16 O48
|____________________________________________________________/
- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
O24 O14 O45 O35 O25 O15 O46 GND O36 O26 O16 O47 O37 O27 O17
*/
@@ -56,6 +70,10 @@ protected:
virtual std::unique_ptr<util::disasm_interface> create_disassembler() override;
virtual void execute_one() override;
+
+ u8 mirror_r(offs_t offset) { return m_data->read_byte(offset & 0x7c); }
+ void mirror_w(offs_t offset, u8 data) { m_data->write_byte(offset & 0x7c, data); }
+
virtual int get_trs_field() override { return 1; }
};