Skip to content

Commit 045a09b

Browse files
authored
Merge branch 'mamedev:master' into 111224
2 parents 1f2dcaf + 967f15b commit 045a09b

File tree

10 files changed

+279
-111
lines changed

10 files changed

+279
-111
lines changed

src/devices/cpu/e0c6200/e0c6s46.cpp

Lines changed: 102 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ E0C6S48: 8192x12 ROM, 768x4 RAM, 2*102x4 VRAM, LCD has 16 commons and 51 segment
1010
TODO:
1111
- finish i/o ports
1212
- serial interface
13-
- buzzer envelope addition
1413
- what happens if OSC3 is selected while OSCC (bit 2) is low?
15-
- K input interrupt can trigger if input is active while writing to the mask register
1614
- add mask options for ports (eg. buzzer on output port R4x is optional)
1715
1816
*/
@@ -148,6 +146,7 @@ void e0c6s46_device::device_start()
148146
m_bz_43_on = 0;
149147
m_bz_freq = 0;
150148
m_bz_envelope = 0;
149+
m_bz_envelope_count = 0;
151150
m_bz_duty_ratio = 0;
152151
m_bz_1shot_on = 0;
153152
m_bz_1shot_running = false;
@@ -190,6 +189,7 @@ void e0c6s46_device::device_start()
190189
save_item(NAME(m_bz_43_on));
191190
save_item(NAME(m_bz_freq));
192191
save_item(NAME(m_bz_envelope));
192+
save_item(NAME(m_bz_envelope_count));
193193
save_item(NAME(m_bz_duty_ratio));
194194
save_item(NAME(m_bz_1shot_on));
195195
save_item(NAME(m_bz_1shot_running));
@@ -211,12 +211,12 @@ void e0c6s46_device::device_reset()
211211
memset(m_irqflag, 0, sizeof(m_irqflag));
212212
memset(m_irqmask, 0, sizeof(m_irqmask));
213213

214-
// reset other i/o
214+
// reset other I/O
215215
m_data->write_byte(0xf41, 0xf);
216216
m_data->write_byte(0xf54, 0xf);
217217
m_data->write_byte(0xf70, 0x0);
218218
m_data->write_byte(0xf71, 0x8);
219-
m_data->write_byte(0xf73, m_svd & 0xc0);
219+
m_data->write_byte(0xf73, m_svd & 3);
220220

221221
m_data->write_byte(0xf74, 0x0);
222222
m_data->write_byte(0xf75, 0x4);
@@ -276,13 +276,19 @@ bool e0c6s46_device::check_interrupt()
276276
for (int pri = 5; pri >= 0; pri--)
277277
{
278278
// hw glitch note, not emulated: if a new interrupt is requested in the
279-
// middle of handling this interrupt, irq vector may be an OR of 2 vectors
280-
m_irq_vector = 2*pri + 2;
279+
// middle of handling this interrupt, IRQ vector may be an OR of 2 vectors
280+
m_irq_vector = 2 * pri + 2;
281281
int reg = priorder[pri];
282282
m_irq_id = reg;
283283

284284
switch (reg)
285285
{
286+
// IK0/IK1 only have 1 flag bit
287+
case IRQREG_INPUT0: case IRQREG_INPUT1:
288+
if (m_irqflag[reg])
289+
return true;
290+
break;
291+
286292
// other: mask vs flag
287293
default:
288294
if (m_irqflag[reg] & m_irqmask[reg])
@@ -301,20 +307,24 @@ void e0c6s46_device::execute_set_input(int line, int state)
301307
return;
302308

303309
state = (state) ? 1 : 0;
304-
int port = line >> 2 & 1;
310+
u8 port = line >> 2 & 1;
305311
u8 bit = 1 << (line & 3);
306312

307313
u8 prev = m_port_k[port];
308314
m_port_k[port] = (m_port_k[port] & ~bit) | (state ? bit : 0);
309315

310-
// set interrupt on falling/rising edge of input
316+
// set IRQ flag on falling/rising edge of input
311317
u8 dfk = (port == 0) ? m_dfk0 : 0xf;
312318
u8 edge = ~(prev ^ dfk) & (m_port_k[port] ^ dfk) & bit;
313319
if (m_irqmask[IRQREG_INPUT0 + port] & edge)
314320
{
315-
m_irqflag[IRQREG_INPUT0 + port] |= edge;
321+
m_irqflag[IRQREG_INPUT0 + port] |= 1;
316322
m_possible_irq = true;
317323
}
324+
325+
// clock programmable timer on falling edge of K03
326+
if ((prev & ~m_port_k[port] & bit) && m_prgtimer_on && (m_prgtimer_select & 7) < 2)
327+
clock_prgtimer();
318328
}
319329

320330

@@ -330,28 +340,22 @@ void e0c6s46_device::write_r(u8 port, u8 data)
330340
data &= 0xf;
331341
m_port_r[port] = data;
332342

333-
// ports R0x-R3x can be high-impedance
334-
u8 out = data;
335-
if (port < 4 && !(m_r_dir >> port & 1))
336-
out = 0xf;
337-
338-
switch (port)
343+
if (port < 4)
339344
{
340-
case 0: m_write_r[0](port, out, 0xff); break;
341-
case 1: m_write_r[1](port, out, 0xff); break;
342-
case 2: m_write_r[2](port, out, 0xff); break;
343-
case 3: m_write_r[3](port, out, 0xff); break; // TODO: R33 PTCLK/_SRDY
344-
345-
// R4x: special output
346-
case 4:
347-
// d3: buzzer on: direct output or 1-shot output
348-
if ((data & 8) != m_bz_43_on)
349-
{
350-
m_bz_43_on = data & 8;
351-
reset_buzzer();
352-
}
353-
write_r4_out();
354-
break;
345+
// ports R0-R3 can be high-impedance
346+
u8 mask = BIT(m_r_dir, port) ? 0xf : 0;
347+
m_write_r[port](port, data | (mask ^ 0xf), mask);
348+
}
349+
else
350+
{
351+
// R43: buzzer on: direct output or 1-shot output
352+
if ((data & 8) != m_bz_43_on)
353+
{
354+
m_bz_43_on = data & 8;
355+
reset_bz_envelope();
356+
reset_buzzer();
357+
}
358+
write_r4_out();
355359
}
356360
}
357361

@@ -360,8 +364,8 @@ void e0c6s46_device::write_r4_out()
360364
// R40: _FOUT(clock inverted output)
361365
// R42: FOUT or _BZ
362366
// R43: BZ(buzzer)
363-
u8 out = (m_port_r[4] & 2) | (m_bz_pulse << 3) | (m_bz_pulse << 2 ^ 4);
364-
m_write_r[4](4, out, 0xff);
367+
u8 data = (m_port_r[4] & 2) | (m_bz_pulse << 3) | (m_bz_pulse << 2 ^ 4);
368+
m_write_r[4](4, data, 0xf);
365369
}
366370

367371

@@ -372,20 +376,18 @@ void e0c6s46_device::write_p(u8 port, u8 data)
372376
data &= 0xf;
373377
m_port_p[port] = data;
374378

375-
// don't output if port direction is set to input
376-
if (!(m_p_dir >> port & 1))
377-
return;
378-
379-
m_write_p[port](port, data, 0xff);
379+
// high-impedance if port is set to input
380+
u8 mask = BIT(m_p_dir, port) ? 0xf : 0;
381+
m_write_p[port](port, data | (mask ^ 0xf), mask);
380382
}
381383

382384
u8 e0c6s46_device::read_p(u8 port)
383385
{
384386
// return written value if port direction is set to output
385-
if (m_p_dir >> port & 1)
387+
if (BIT(m_p_dir, port))
386388
return m_port_p[port];
387389

388-
return m_read_p[port](port, 0xff);
390+
return m_read_p[port](port);
389391
}
390392

391393

@@ -410,6 +412,10 @@ TIMER_CALLBACK_MEMBER(e0c6s46_device::core_256_cb)
410412
if (m_bz_1shot_on != 0 && m_256_src_pulse == 1)
411413
clock_bz_1shot();
412414

415+
// clock buzzer envelope on rising edge if it's on
416+
if (m_bz_envelope & 1 && m_256_src_pulse == 1)
417+
clock_bz_envelope();
418+
413419
// clock-timer is always running, advance it on falling edge
414420
// (handle clock_clktimer last in case of watchdog reset)
415421
if (m_256_src_pulse == 0)
@@ -440,7 +446,7 @@ void e0c6s46_device::clock_clktimer()
440446
{
441447
m_clktimer_count++;
442448

443-
// irq on falling edge of 32, 8, 2, 1hz
449+
// IRQ on falling edge of 32, 8, 2, 1hz
444450
u8 flag = 0;
445451
if ((m_clktimer_count & 0x07) == 0)
446452
flag |= 1;
@@ -478,18 +484,18 @@ void e0c6s46_device::clock_stopwatch()
478484
{
479485
m_swl_slice = 0;
480486

481-
// bcd counter, irq on falling edge of 10 and 1hz
487+
// bcd counter, IRQ on falling edge of 10 and 1hz
482488
m_swl_count = (m_swl_count + 1) % 10;
483489
if (m_swl_count == 0)
484490
{
485491
m_irqflag[IRQREG_STOPWATCH] |= 1;
486492
m_swh_count = (m_swh_count + 1) % 10;
487493
if (m_swh_count == 0)
488494
m_irqflag[IRQREG_STOPWATCH] |= 2;
489-
}
490495

491-
if (m_irqflag[IRQREG_STOPWATCH] & m_irqmask[IRQREG_STOPWATCH])
492-
m_possible_irq = true;
496+
if (m_irqflag[IRQREG_STOPWATCH] & m_irqmask[IRQREG_STOPWATCH])
497+
m_possible_irq = true;
498+
}
493499
}
494500
}
495501

@@ -498,7 +504,7 @@ void e0c6s46_device::clock_stopwatch()
498504

499505
void e0c6s46_device::clock_prgtimer()
500506
{
501-
// irq and reload when it reaches zero
507+
// IRQ and reload when it reaches zero
502508
if (--m_prgtimer_count == 0)
503509
{
504510
m_irqflag[IRQREG_PRGTIMER] |= 1;
@@ -540,7 +546,7 @@ TIMER_CALLBACK_MEMBER(e0c6s46_device::prgtimer_cb)
540546
void e0c6s46_device::schedule_buzzer()
541547
{
542548
// only schedule next buzzer timeout if it's on
543-
if (m_bz_43_on != 0 && !m_bz_1shot_running)
549+
if (m_bz_43_on && !m_bz_1shot_running)
544550
return;
545551

546552
// pulse width differs per frequency selection
@@ -558,10 +564,13 @@ void e0c6s46_device::schedule_buzzer()
558564

559565
TIMER_CALLBACK_MEMBER(e0c6s46_device::buzzer_cb)
560566
{
561-
// invert pulse wave and write to output
562-
m_bz_pulse ^= 1;
563-
write_r4_out();
567+
// invert pulse wave if buzzer is on
568+
if (m_bz_43_on && !m_bz_1shot_running)
569+
m_bz_pulse = 0;
570+
else
571+
m_bz_pulse ^= 1;
564572

573+
write_r4_out();
565574
schedule_buzzer();
566575
}
567576

@@ -579,8 +588,8 @@ void e0c6s46_device::clock_bz_1shot()
579588
// reload counter the 1st time
580589
if (m_bz_1shot_count == 0)
581590
{
582-
reset_buzzer();
583591
m_bz_1shot_count = (m_bz_freq & 8) ? 16 : 8;
592+
reset_buzzer();
584593
}
585594

586595
// stop ringing when counter reaches 0
@@ -591,6 +600,24 @@ void e0c6s46_device::clock_bz_1shot()
591600
}
592601
}
593602

603+
void e0c6s46_device::clock_bz_envelope()
604+
{
605+
if (--m_bz_envelope_count == 0)
606+
{
607+
m_bz_envelope_count = (m_bz_envelope & 2) ? 32 : 16;
608+
609+
// maximum duty addition is 7
610+
if (m_bz_duty_ratio < 7)
611+
m_bz_duty_ratio++;
612+
}
613+
}
614+
615+
void e0c6s46_device::reset_bz_envelope()
616+
{
617+
m_bz_envelope_count = (m_bz_envelope & 2) ? 32 : 16;
618+
m_bz_duty_ratio = 0;
619+
}
620+
594621

595622

596623
//-------------------------------------------------
@@ -667,17 +694,17 @@ u8 e0c6s46_device::io_r(offs_t offset)
667694
{
668695
switch (offset)
669696
{
670-
// irq flags, masks
697+
// IRQ flags, masks
671698
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05:
672699
{
673-
// irq flags are reset(acked) when read
700+
// IRQ flags are reset(acked) when read
674701
u8 flag = m_irqflag[offset];
675702
if (!machine().side_effects_disabled())
676703
m_irqflag[offset] = 0;
677704
return flag;
678705
}
679706
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15:
680-
return m_irqmask[offset-0x10];
707+
return m_irqmask[offset & 7];
681708

682709
// K input ports
683710
case 0x40: case 0x42:
@@ -761,18 +788,34 @@ void e0c6s46_device::io_w(offs_t offset, u8 data)
761788
{
762789
switch (offset)
763790
{
764-
// irq masks
791+
// IRQ masks
765792
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15:
766793
{
767794
static const u8 maskmask[6] = { 0xf, 3, 1, 1, 0xf, 0xf };
768-
m_irqmask[offset-0x10] = data & maskmask[offset-0x10];
769-
m_possible_irq = true;
795+
u8 prev = m_irqmask[offset & 7];
796+
m_irqmask[offset & 7] = data & maskmask[offset & 7];
797+
u8 rise = ~prev & m_irqmask[offset & 7];
798+
799+
if (rise)
800+
{
801+
m_possible_irq = true;
802+
803+
if (offset >= 0x14)
804+
{
805+
u8 port = offset & 1;
806+
u8 dfk = (port == 0) ? m_dfk0 : 0xf;
807+
808+
// IK flag gets set if input is active at rising edge of mask bit
809+
if (rise & (m_port_k[port] ^ dfk))
810+
m_irqflag[offset & 7] |= 1;
811+
}
812+
}
770813
break;
771814
}
772815

773816
// K input ports
774817
case 0x41:
775-
// d0-d3: K0x irq on 0: rising edge, 1: falling edge
818+
// d0-d3: K0x IRQ on 0: rising edge, 1: falling edge
776819
m_dfk0 = data;
777820
break;
778821

@@ -926,8 +969,8 @@ void e0c6s46_device::io_w(offs_t offset, u8 data)
926969
// d1: envelope cycle selection
927970
// d2: reset envelope
928971
// d3: trigger one-shot buzzer
929-
if (data & 1)
930-
logerror("io_w enabled envelope, PC=$%04X\n", m_prev_pc);
972+
if (~m_bz_envelope & data & 1 || data & 4)
973+
reset_bz_envelope();
931974
m_bz_envelope = data & 3;
932975
m_bz_1shot_on |= data & 8;
933976
break;

src/devices/cpu/e0c6200/e0c6s46.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ class e0c6s46_device : public e0c6200_cpu_device
159159
u8 m_bz_43_on;
160160
u8 m_bz_freq;
161161
u8 m_bz_envelope;
162+
u8 m_bz_envelope_count;
162163
u8 m_bz_duty_ratio;
163164
u8 m_bz_1shot_on;
164165
bool m_bz_1shot_running;
@@ -169,6 +170,8 @@ class e0c6s46_device : public e0c6200_cpu_device
169170
void schedule_buzzer();
170171
void reset_buzzer();
171172
void clock_bz_1shot();
173+
void clock_bz_envelope();
174+
void reset_bz_envelope();
172175

173176
u32 m_osc1;
174177
u32 m_osc3;

0 commit comments

Comments
 (0)