mirror of
https://github.com/holub/mame
synced 2025-04-22 16:31:49 +03:00
added e0c6s46 buzzer
This commit is contained in:
parent
624ea80c5d
commit
14eae1ec9b
@ -9,6 +9,8 @@
|
||||
- K input interrupts
|
||||
- finish i/o ports
|
||||
- serial interface
|
||||
- one-shot buzzer
|
||||
- buzzer envelope
|
||||
- add mask options to MCFG (eg. buzzer on output port R4x is optional)
|
||||
|
||||
*/
|
||||
@ -80,10 +82,8 @@ void e0c6s46_device::device_start()
|
||||
m_write_p3.resolve_safe();
|
||||
|
||||
// create timers
|
||||
m_clktimer_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::clktimer_cb), this));
|
||||
m_clktimer_handle->adjust(attotime::from_ticks(128, unscaled_clock()));
|
||||
m_stopwatch_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::stopwatch_cb), this));
|
||||
m_stopwatch_handle->adjust(attotime::from_ticks(64, unscaled_clock()));
|
||||
m_core_256_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::core_256_cb), this));
|
||||
m_core_256_handle->adjust(attotime::from_ticks(64, unscaled_clock()));
|
||||
m_prgtimer_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::prgtimer_cb), this));
|
||||
m_prgtimer_handle->adjust(attotime::never);
|
||||
m_buzzer_handle = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(e0c6s46_device::buzzer_cb), this));
|
||||
@ -105,11 +105,11 @@ void e0c6s46_device::device_start()
|
||||
m_lcd_control = 0;
|
||||
m_lcd_contrast = 0;
|
||||
|
||||
m_256_src_pulse = 0;
|
||||
m_watchdog_count = 0;
|
||||
m_clktimer_count = 0;
|
||||
|
||||
m_stopwatch_on = 0;
|
||||
m_swl_src_pulse = 0;
|
||||
m_swl_cur_pulse = 0;
|
||||
m_swl_slice = 0;
|
||||
m_swl_count = 0;
|
||||
@ -121,6 +121,12 @@ void e0c6s46_device::device_start()
|
||||
m_prgtimer_cur_pulse = 0;
|
||||
m_prgtimer_count = 0;
|
||||
m_prgtimer_reload = 0;
|
||||
|
||||
m_bz_43_on = 0;
|
||||
m_bz_freq = 0;
|
||||
m_bz_envelope = 0;
|
||||
m_bz_duty_ratio = 0;
|
||||
m_bz_pulse = 0;
|
||||
|
||||
// register for savestates
|
||||
save_item(NAME(m_port_r));
|
||||
@ -138,11 +144,11 @@ void e0c6s46_device::device_start()
|
||||
save_item(NAME(m_lcd_control));
|
||||
save_item(NAME(m_lcd_contrast));
|
||||
|
||||
save_item(NAME(m_256_src_pulse));
|
||||
save_item(NAME(m_watchdog_count));
|
||||
save_item(NAME(m_clktimer_count));
|
||||
|
||||
save_item(NAME(m_stopwatch_on));
|
||||
save_item(NAME(m_swl_src_pulse));
|
||||
save_item(NAME(m_swl_cur_pulse));
|
||||
save_item(NAME(m_swl_slice));
|
||||
save_item(NAME(m_swl_count));
|
||||
@ -154,6 +160,12 @@ void e0c6s46_device::device_start()
|
||||
save_item(NAME(m_prgtimer_cur_pulse));
|
||||
save_item(NAME(m_prgtimer_count));
|
||||
save_item(NAME(m_prgtimer_reload));
|
||||
|
||||
save_item(NAME(m_bz_43_on));
|
||||
save_item(NAME(m_bz_freq));
|
||||
save_item(NAME(m_bz_envelope));
|
||||
save_item(NAME(m_bz_duty_ratio));
|
||||
save_item(NAME(m_bz_pulse));
|
||||
}
|
||||
|
||||
|
||||
@ -277,9 +289,6 @@ void e0c6s46_device::write_r(UINT8 port, UINT8 data)
|
||||
data &= 0xf;
|
||||
m_port_r[port] = data;
|
||||
|
||||
if (port == 4)
|
||||
write_r4();
|
||||
|
||||
// ports R0x-R3x can be high-impedance
|
||||
UINT8 out = data;
|
||||
if (port < 4 && !(m_r_dir >> port & 1))
|
||||
@ -291,17 +300,27 @@ void e0c6s46_device::write_r(UINT8 port, UINT8 data)
|
||||
case 1: m_write_r1(port, out, 0xff); break;
|
||||
case 2: m_write_r2(port, out, 0xff); break;
|
||||
case 3: m_write_r3(port, out, 0xff); break; // TODO: R33 PTCLK/_SRDY
|
||||
|
||||
// R4x: special output
|
||||
case 4:
|
||||
// d3: buzzer on: direct output or 1-shot output
|
||||
if ((data >> 3 & 1) != m_bz_43_on)
|
||||
{
|
||||
m_bz_43_on = data >> 3 & 1;
|
||||
reset_buzzer();
|
||||
}
|
||||
write_r4_out();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void e0c6s46_device::write_r4()
|
||||
void e0c6s46_device::write_r4_out()
|
||||
{
|
||||
// R40: _FOUT(clock inverted output)
|
||||
// R42: FOUT or _BZ
|
||||
// R43: BZ(buzzer) on
|
||||
UINT8 data = m_port_r[4] & 2;
|
||||
|
||||
m_write_r4(4, data, 0xff);
|
||||
// R43: BZ(buzzer)
|
||||
UINT8 out = (m_port_r[4] & 2) | (m_bz_pulse << 3) | (m_bz_pulse << 2 ^ 4);
|
||||
m_write_r4(4, out, 0xff);
|
||||
}
|
||||
|
||||
|
||||
@ -348,7 +367,25 @@ UINT8 e0c6s46_device::read_p(UINT8 port)
|
||||
// timers
|
||||
//-------------------------------------------------
|
||||
|
||||
// clock timer
|
||||
TIMER_CALLBACK_MEMBER(e0c6s46_device::core_256_cb)
|
||||
{
|
||||
// clock-timer, stopwatch timer, and some features of the buzzer all run
|
||||
// from the same internal 256hz timer (64 ticks high+low at default clock of 32768hz)
|
||||
m_256_src_pulse ^= 1;
|
||||
m_core_256_handle->adjust(attotime::from_ticks(64, unscaled_clock()));
|
||||
|
||||
// clock-timer is always running, advance it on falling edge
|
||||
if (m_256_src_pulse == 0)
|
||||
clock_clktimer();
|
||||
|
||||
// clock stopwatch on falling edge of pulse+on
|
||||
m_swl_cur_pulse = m_256_src_pulse | (m_stopwatch_on ^ 1);
|
||||
if (m_swl_cur_pulse == 0)
|
||||
clock_stopwatch();
|
||||
}
|
||||
|
||||
|
||||
// clock-timer
|
||||
|
||||
void e0c6s46_device::clock_watchdog()
|
||||
{
|
||||
@ -361,7 +398,7 @@ void e0c6s46_device::clock_watchdog()
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(e0c6s46_device::clktimer_cb)
|
||||
void e0c6s46_device::clock_clktimer()
|
||||
{
|
||||
m_clktimer_count++;
|
||||
|
||||
@ -380,9 +417,6 @@ TIMER_CALLBACK_MEMBER(e0c6s46_device::clktimer_cb)
|
||||
if (m_irqflag[IRQREG_CLKTIMER] & m_irqmask[IRQREG_CLKTIMER])
|
||||
m_possible_irq = true;
|
||||
|
||||
// schedule next timeout (256hz at default clock of 32768hz)
|
||||
m_clktimer_handle->adjust(attotime::from_ticks(128, unscaled_clock()));
|
||||
|
||||
// 1hz falling edge also clocks the watchdog timer
|
||||
if (m_clktimer_count == 0)
|
||||
clock_watchdog();
|
||||
@ -421,19 +455,6 @@ void e0c6s46_device::clock_stopwatch()
|
||||
}
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(e0c6s46_device::stopwatch_cb)
|
||||
{
|
||||
m_swl_src_pulse ^= 1;
|
||||
m_swl_cur_pulse = m_swl_src_pulse | (m_stopwatch_on ^ 1);
|
||||
|
||||
// clock stopwatch on falling edge of pulse+on
|
||||
if (m_swl_cur_pulse == 0)
|
||||
clock_stopwatch();
|
||||
|
||||
// schedule next timeout (256hz high+low at default clock of 32768hz)
|
||||
m_stopwatch_handle->adjust(attotime::from_ticks(64, unscaled_clock()));
|
||||
}
|
||||
|
||||
|
||||
// programmable timer
|
||||
|
||||
@ -478,8 +499,34 @@ TIMER_CALLBACK_MEMBER(e0c6s46_device::prgtimer_cb)
|
||||
|
||||
// buzzer
|
||||
|
||||
void e0c6s46_device::schedule_buzzer()
|
||||
{
|
||||
// only schedule next buzzer timeout if it's on
|
||||
if (m_bz_43_on != 0)
|
||||
return;
|
||||
|
||||
// pulse width differs per frequency selection
|
||||
int mul = (m_bz_freq & 4) ? 1 : 2;
|
||||
int high = ((m_bz_freq & 2) ? 12 : 8) - m_bz_duty_ratio;
|
||||
int low = (16 + (m_bz_freq & 3)) - high;
|
||||
|
||||
m_buzzer_handle->adjust(attotime::from_ticks(m_bz_pulse ? high : low, mul * unscaled_clock()));
|
||||
}
|
||||
|
||||
TIMER_CALLBACK_MEMBER(e0c6s46_device::buzzer_cb)
|
||||
{
|
||||
// invert pulse wave and write to output
|
||||
m_bz_pulse ^= 1;
|
||||
write_r4_out();
|
||||
|
||||
schedule_buzzer();
|
||||
}
|
||||
|
||||
void e0c6s46_device::reset_buzzer()
|
||||
{
|
||||
// don't reset if the timer is running
|
||||
if (m_buzzer_handle->remaining() == attotime::never)
|
||||
schedule_buzzer();
|
||||
}
|
||||
|
||||
|
||||
@ -570,7 +617,7 @@ READ8_MEMBER(e0c6s46_device::io_r)
|
||||
case 0x7e:
|
||||
return m_p_pullup;
|
||||
|
||||
// clock timer (lo, hi)
|
||||
// clock-timer (lo, hi)
|
||||
case 0x20: case 0x21:
|
||||
return m_clktimer_count >> (4 * (offset & 1)) & 0xf;
|
||||
|
||||
@ -592,6 +639,13 @@ READ8_MEMBER(e0c6s46_device::io_r)
|
||||
case 0x79:
|
||||
return m_prgtimer_select;
|
||||
|
||||
// buzzer
|
||||
case 0x74:
|
||||
return m_bz_freq;
|
||||
case 0x75:
|
||||
// d3: 1-shot buzzer is running
|
||||
return 0 | m_bz_envelope;
|
||||
|
||||
// OSC circuit
|
||||
case 0x70:
|
||||
return m_osc;
|
||||
@ -645,7 +699,7 @@ WRITE8_MEMBER(e0c6s46_device::io_w)
|
||||
write_r(offset & 7, data);
|
||||
break;
|
||||
case 0x7b:
|
||||
// d0-d3: Rx* direction 0: high impedance, 1: output
|
||||
// d0-d3: Rx* direction 0: high-impedance, 1: output
|
||||
if (data != m_r_dir)
|
||||
{
|
||||
m_r_dir = data;
|
||||
@ -705,10 +759,10 @@ WRITE8_MEMBER(e0c6s46_device::io_w)
|
||||
m_svd = data & 7;
|
||||
break;
|
||||
|
||||
// clock timer
|
||||
// clock-timer
|
||||
case 0x76:
|
||||
// d0: reset watchdog
|
||||
// d1: reset clock timer (hw glitch note, not emulated: this also "sometimes"(when??)
|
||||
// d1: reset clktimer (hw glitch note, not emulated: this also "sometimes"(when??)
|
||||
// sets the clktimer interrupt and clocks the watchdog)
|
||||
if (data & 1)
|
||||
m_watchdog_count = 0;
|
||||
@ -727,7 +781,7 @@ WRITE8_MEMBER(e0c6s46_device::io_w)
|
||||
m_swl_count = 0;
|
||||
m_swl_slice = 0;
|
||||
}
|
||||
if (m_stopwatch_on && m_swl_cur_pulse && !m_swl_src_pulse)
|
||||
if (m_stopwatch_on && m_swl_cur_pulse && !m_256_src_pulse)
|
||||
{
|
||||
// clock stopwatch on falling edge of pulse+on
|
||||
m_swl_cur_pulse = 0;
|
||||
@ -772,6 +826,20 @@ WRITE8_MEMBER(e0c6s46_device::io_w)
|
||||
}
|
||||
m_prgtimer_select = data;
|
||||
break;
|
||||
|
||||
// buzzer
|
||||
case 0x74:
|
||||
// d0-d2: frequency (8 steps, 4096hz to ~1170hz)
|
||||
// d3: 1-shot buzzer duration 31.25ms or 62.5ms
|
||||
m_bz_freq = data;
|
||||
break;
|
||||
case 0x75:
|
||||
// d0: envelope on/off
|
||||
// d1: envelope cycle selection
|
||||
// d2: reset envelope
|
||||
// d3: trigger one-shot buzzer
|
||||
m_bz_envelope = data & 3;
|
||||
break;
|
||||
|
||||
// read-only registers
|
||||
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
|
||||
|
@ -120,7 +120,7 @@ private:
|
||||
devcb_read8 m_read_p0, m_read_p1, m_read_p2, m_read_p3;
|
||||
devcb_write8 m_write_p0, m_write_p1, m_write_p2, m_write_p3;
|
||||
void write_r(UINT8 port, UINT8 data);
|
||||
void write_r4();
|
||||
void write_r4_out();
|
||||
void write_p(UINT8 port, UINT8 data);
|
||||
UINT8 read_p(UINT8 port);
|
||||
|
||||
@ -133,12 +133,14 @@ private:
|
||||
UINT8 m_dfk0;
|
||||
|
||||
// timers
|
||||
int m_256_src_pulse;
|
||||
emu_timer *m_core_256_handle;
|
||||
TIMER_CALLBACK_MEMBER(core_256_cb);
|
||||
|
||||
int m_watchdog_count;
|
||||
void clock_watchdog();
|
||||
|
||||
UINT8 m_clktimer_count;
|
||||
emu_timer *m_clktimer_handle;
|
||||
TIMER_CALLBACK_MEMBER(clktimer_cb);
|
||||
void clock_clktimer();
|
||||
|
||||
UINT8 m_stopwatch_on;
|
||||
int m_swl_src_pulse;
|
||||
@ -146,8 +148,6 @@ private:
|
||||
int m_swl_slice;
|
||||
int m_swl_count;
|
||||
int m_swh_count;
|
||||
emu_timer *m_stopwatch_handle;
|
||||
TIMER_CALLBACK_MEMBER(stopwatch_cb);
|
||||
void clock_stopwatch();
|
||||
|
||||
UINT8 m_prgtimer_select;
|
||||
@ -161,8 +161,15 @@ private:
|
||||
bool prgtimer_reset_prescaler();
|
||||
void clock_prgtimer();
|
||||
|
||||
UINT8 m_bz_43_on;
|
||||
UINT8 m_bz_freq;
|
||||
UINT8 m_bz_envelope;
|
||||
UINT8 m_bz_duty_ratio;
|
||||
int m_bz_pulse;
|
||||
emu_timer *m_buzzer_handle;
|
||||
TIMER_CALLBACK_MEMBER(buzzer_cb);
|
||||
void schedule_buzzer();
|
||||
void reset_buzzer();
|
||||
};
|
||||
|
||||
|
||||
|
@ -27,6 +27,8 @@ public:
|
||||
required_device<e0c6s46_device> m_maincpu;
|
||||
required_device<speaker_sound_device> m_speaker;
|
||||
|
||||
DECLARE_WRITE8_MEMBER(speaker_w);
|
||||
|
||||
DECLARE_PALETTE_INIT(tama);
|
||||
DECLARE_INPUT_CHANGED_MEMBER(input_changed);
|
||||
};
|
||||
@ -59,7 +61,7 @@ static E0C6S46_PIXEL_UPDATE_CB(tama_pixel_update)
|
||||
// above screen: 0:meal, 1:lamp, 2:play, 3:medicine
|
||||
// under screen: 4:bath, 5:scales, 6:shout, 7:attention
|
||||
|
||||
// they are on pin SEG08(x=35) + COM00-03, pin SEG28(x=36) + COM12-15
|
||||
// they are on pin SEG8(x=35) + COM0-3, pin SEG28(x=36) + COM12-15
|
||||
if (x == 35 && y < 4)
|
||||
output_set_lamp_value(y, state);
|
||||
else if (x == 36 && y >= 12)
|
||||
@ -79,6 +81,20 @@ PALETTE_INIT_MEMBER(tamag1_state, tama)
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
I/O
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
WRITE8_MEMBER(tamag1_state::speaker_w)
|
||||
{
|
||||
// R43: speaker out
|
||||
m_speaker->level_w(data >> 3 & 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
|
||||
Inputs
|
||||
@ -115,6 +131,7 @@ static MACHINE_CONFIG_START( tama, tamag1_state )
|
||||
/* basic machine hardware */
|
||||
MCFG_CPU_ADD("maincpu", E0C6S46, XTAL_32_768kHz)
|
||||
MCFG_E0C6S46_PIXEL_UPDATE_CB(tama_pixel_update)
|
||||
MCFG_E0C6S46_WRITE_R_CB(4, WRITE8(tamag1_state, speaker_w))
|
||||
|
||||
/* video hardware */
|
||||
MCFG_SCREEN_ADD("screen", LCD)
|
||||
|
Loading…
Reference in New Issue
Block a user