Skip to content

Commit 510ebf5

Browse files
committed
v25: Improve peripheral emulation
- Add preliminary DMA controller (capable of doing burst memory transfers) - Make timer 1 cause two different interrupts - Add kludge for one timer edge case * tvdear: Map some more ROM; add P0 readback
1 parent 2e1f992 commit 510ebf5

File tree

4 files changed

+301
-13
lines changed

4 files changed

+301
-13
lines changed

src/devices/cpu/nec/v25.cpp

+132-1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ v25_common_device::v25_common_device(const machine_config &mconfig, device_type
6969
, m_p0_out(*this)
7070
, m_p1_out(*this)
7171
, m_p2_out(*this)
72+
, m_dma_read(*this, 0xffff)
73+
, m_dma_write(*this)
7274
, m_prefetch_size(prefetch_size)
7375
, m_prefetch_cycles(prefetch_cycles)
7476
, m_chip_type(chip_type)
@@ -215,7 +217,6 @@ void v25_common_device::device_reset()
215217
m_intm = 0;
216218
m_halted = 0;
217219

218-
m_TM0 = m_MD0 = m_TM1 = m_MD1 = 0;
219220
m_TMC0 = m_TMC1 = 0;
220221

221222
for (int i = 0; i < 2; i++)
@@ -226,6 +227,10 @@ void v25_common_device::device_reset()
226227
m_sce[i] = 0;
227228
}
228229

230+
m_dmam[0] = m_dmam[1] = 0;
231+
m_dma_channel = -1;
232+
m_last_dma_channel = 0;
233+
229234
m_RAMEN = 1;
230235
m_TB = 20;
231236
m_PCK = 8;
@@ -483,6 +488,111 @@ void v25_common_device::external_int()
483488
}
484489
}
485490

491+
void v25_common_device::dma_process()
492+
{
493+
uint16_t sar = m_internal_ram[m_dma_channel * 4];
494+
uint16_t dar = m_internal_ram[m_dma_channel * 4 + 1];
495+
uint16_t sarh_darh = m_internal_ram[m_dma_channel * 4 + 2];
496+
uint8_t dmamode = BIT(m_dmam[m_dma_channel], 5, 3);
497+
bool w = BIT(m_dmam[m_dma_channel], 4);
498+
499+
uint32_t saddr = (BIT(dmamode, 0) ? 0 : (uint32_t(sarh_darh) & 0xff00) << 4) + sar;
500+
uint32_t daddr = (BIT(dmamode, 1) ? 0 : (uint32_t(sarh_darh) & 0x00ff) << 12) + dar;
501+
502+
switch (dmamode & 3)
503+
{
504+
case 0:
505+
// Memory to memory transfer
506+
if (w)
507+
{
508+
uint16_t data = v25_read_word(saddr);
509+
v25_write_word(daddr, data);
510+
}
511+
else
512+
{
513+
uint8_t data = v25_read_byte(saddr);
514+
v25_write_byte(daddr, data);
515+
}
516+
m_icount -= (w && m_program->addr_width() == 8) ? 8 : 4;
517+
break;
518+
519+
case 1:
520+
// I/O to memory transfer
521+
if (w && m_program->addr_width() == 16)
522+
{
523+
uint16_t data = m_dma_read[m_dma_channel](daddr);
524+
v25_write_word(daddr, data);
525+
}
526+
else
527+
{
528+
uint8_t data = m_dma_read[m_dma_channel](daddr);
529+
v25_write_byte(daddr, data);
530+
if (w)
531+
{
532+
logerror("Warning: V25 16-bit I/O to memory transfer\n");
533+
data = m_dma_read[m_dma_channel](daddr + 1);
534+
v25_write_byte(daddr + 1, data);
535+
m_icount -= 2;
536+
}
537+
}
538+
m_icount -= 2;
539+
break;
540+
541+
case 2:
542+
// Memory to I/O transfer
543+
if (w && m_program->addr_width() == 16)
544+
{
545+
uint16_t data = v25_read_word(saddr);
546+
m_dma_write[m_dma_channel](saddr, data);
547+
}
548+
else
549+
{
550+
uint8_t data = v25_read_byte(saddr);
551+
m_dma_write[m_dma_channel](saddr, data);
552+
if (w)
553+
{
554+
logerror("Warning: V25 16-bit memory to I/O transfer\n");
555+
data = v25_read_byte(saddr + 1);
556+
m_dma_write[m_dma_channel](saddr + 1, data);
557+
m_icount -= 2;
558+
}
559+
}
560+
m_icount -= 2;
561+
break;
562+
563+
default:
564+
logerror("Reserved DMA transfer mode\n");
565+
m_icount--;
566+
break;
567+
}
568+
569+
// Update source and destination based on address control
570+
uint8_t dmac = m_dmac[m_dma_channel];
571+
if (BIT(dmac, 0, 2) == 1)
572+
m_internal_ram[m_dma_channel * 4] = sar + (w ? 2 : 1);
573+
else if (BIT(dmac, 0, 2) == 2)
574+
m_internal_ram[m_dma_channel * 4] = sar - (w ? 2 : 1);
575+
if (BIT(dmac, 4, 2) == 1)
576+
m_internal_ram[m_dma_channel * 4 + 1] = dar + (w ? 2 : 1);
577+
else if (BIT(dmac, 4, 2) == 2)
578+
m_internal_ram[m_dma_channel * 4 + 1] = dar - (w ? 2 : 1);
579+
580+
// Update TC
581+
uint16_t tc = --m_internal_ram[m_dma_channel * 4 + 3];
582+
if (tc == 0)
583+
{
584+
m_dmam[m_dma_channel] &= 0xf0; // disable channel
585+
m_pending_irq |= m_dma_channel ? INTD1 : INTD0; // request interrupt
586+
}
587+
588+
if (dmamode == 0 || dmamode > 4 || tc == 0)
589+
{
590+
// Single step/single transfer modes (or end of burst)
591+
m_last_dma_channel = m_dma_channel;
592+
m_dma_channel = -1;
593+
}
594+
}
595+
486596
/****************************************************************************/
487597
/* OPCODES */
488598
/****************************************************************************/
@@ -570,6 +680,9 @@ void v25_common_device::device_start()
570680
m_EO = 0;
571681
m_E16 = 0;
572682

683+
m_TM0 = m_MD0 = m_TM1 = m_MD1 = 0;
684+
m_dmac[0] = m_dmac[1] = 0;
685+
573686
for (i = 0; i < 4; i++)
574687
m_timers[i] = timer_alloc(FUNC(v25_common_device::v25_timer_callback), this);
575688

@@ -630,6 +743,10 @@ void v25_common_device::device_start()
630743
save_item(NAME(m_scc));
631744
save_item(NAME(m_brg));
632745
save_item(NAME(m_sce));
746+
save_item(NAME(m_dmac));
747+
save_item(NAME(m_dmam));
748+
save_item(NAME(m_dma_channel));
749+
save_item(NAME(m_last_dma_channel));
633750
save_item(NAME(m_RAMEN));
634751
save_item(NAME(m_TB));
635752
save_item(NAME(m_PCK));
@@ -790,6 +907,12 @@ void v25_common_device::execute_run()
790907
}
791908

792909
while(m_icount>0) {
910+
if (m_dma_channel != -1)
911+
{
912+
dma_process();
913+
continue;
914+
}
915+
793916
/* Dispatch IRQ */
794917
m_prev_ip = m_ip;
795918
if (m_no_interrupt==0 && (m_pending_irq & m_unmasked_irq))
@@ -808,5 +931,13 @@ void v25_common_device::execute_run()
808931
prev_ICount = m_icount;
809932
(this->*s_nec_instruction[fetchop()])();
810933
do_prefetch(prev_ICount);
934+
935+
if ((m_dmam[0] & 0x0c) == 0x0c || (m_dmam[1] & 0x0c) == 0x0c)
936+
{
937+
if ((m_dmam[1 - m_last_dma_channel] & 0x0c) == 0x0c)
938+
m_dma_channel = 1 - m_last_dma_channel;
939+
else
940+
m_dma_channel = m_last_dma_channel;
941+
}
811942
}
812943
}

src/devices/cpu/nec/v25.h

+32-4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ class v25_common_device : public cpu_device, public nec_disassembler::config
3939
auto p1_out_cb() { return m_p1_out.bind(); }
4040
auto p2_out_cb() { return m_p2_out.bind(); }
4141

42+
auto dma0_read_cb() { return m_dma_read[0].bind(); }
43+
auto dma1_read_cb() { return m_dma_read[1].bind(); }
44+
45+
auto dma0_write_cb() { return m_dma_write[0].bind(); }
46+
auto dma1_write_cb() { return m_dma_write[1].bind(); }
47+
4248
TIMER_CALLBACK_MEMBER(v25_timer_callback);
4349

4450
protected:
@@ -113,19 +119,25 @@ class v25_common_device : public cpu_device, public nec_disassembler::config
113119
uint8_t m_no_interrupt;
114120
uint8_t m_halted;
115121

116-
/* timer related */
122+
// timer related
117123
uint16_t m_TM0, m_MD0, m_TM1, m_MD1;
118124
uint8_t m_TMC0, m_TMC1;
119125
emu_timer *m_timers[4];
120126

121-
/* serial interface related */
127+
// serial interface related
122128
uint8_t m_scm[2];
123129
uint8_t m_scc[2];
124130
uint8_t m_brg[2];
125131
uint8_t m_sce[2];
126132

127-
/* system control */
128-
uint8_t m_RAMEN, m_TB, m_PCK; /* PRC register */
133+
// DMA related
134+
uint8_t m_dmac[2];
135+
uint8_t m_dmam[2];
136+
int8_t m_dma_channel;
137+
int8_t m_last_dma_channel;
138+
139+
// system control
140+
uint8_t m_RAMEN, m_TB, m_PCK; // PRC register
129141
uint8_t m_RFM;
130142
uint16_t m_WTC;
131143
uint32_t m_IDB;
@@ -146,6 +158,9 @@ class v25_common_device : public cpu_device, public nec_disassembler::config
146158
devcb_write8 m_p1_out;
147159
devcb_write8 m_p2_out;
148160

161+
devcb_read16::array<2> m_dma_read;
162+
devcb_write16::array<2> m_dma_write;
163+
149164
uint8_t m_prefetch_size;
150165
uint8_t m_prefetch_cycles;
151166
int8_t m_prefetch_count;
@@ -177,6 +192,7 @@ class v25_common_device : public cpu_device, public nec_disassembler::config
177192
void nec_bankswitch(unsigned bank_num);
178193
void nec_trap();
179194
void external_int();
195+
void dma_process();
180196

181197
void ida_sfr_map(address_map &map) ATTR_COLD;
182198
uint8_t read_irqcontrol(int /*INTSOURCES*/ source, uint8_t priority);
@@ -257,6 +273,18 @@ class v25_common_device : public cpu_device, public nec_disassembler::config
257273
void tmic1_w(uint8_t d);
258274
uint8_t tmic2_r();
259275
void tmic2_w(uint8_t d);
276+
uint8_t dmac0_r();
277+
void dmac0_w(uint8_t d);
278+
uint8_t dmam0_r();
279+
void dmam0_w(uint8_t d);
280+
uint8_t dmac1_r();
281+
void dmac1_w(uint8_t d);
282+
uint8_t dmam1_r();
283+
void dmam1_w(uint8_t d);
284+
uint8_t dic0_r();
285+
void dic0_w(uint8_t d);
286+
uint8_t dic1_r();
287+
void dic1_w(uint8_t d);
260288
uint8_t rfm_r();
261289
void rfm_w(uint8_t d);
262290
uint16_t wtc_r();

0 commit comments

Comments
 (0)