1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
// license:BSD-3-Clause
// copyright-holders:Barry Rodewald
/*
Hitachi HD63450 DMA Controller
*/
#ifndef MAME_MACHINE_HD63450_H
#define MAME_MACHINE_HD63450_H
#pragma once
class hd63450_device : public device_t
{
public:
template <typename T>
hd63450_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock, T &&cputag)
: hd63450_device(mconfig, tag, owner, clock)
{
set_cpu_tag(std::forward<T>(cputag));
}
hd63450_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto irq_callback() { return m_irq_callback.bind(); }
auto dma_end() { return m_dma_end.bind(); }
template <int Ch> auto dma_read() { return m_dma_read[Ch].bind(); }
template <int Ch> auto dma_write() { return m_dma_write[Ch].bind(); }
template <typename T> void set_cpu_tag(T &&cpu_tag) { m_cpu.set_tag(std::forward<T>(cpu_tag)); }
void set_clocks(const attotime &clk1, const attotime &clk2, const attotime &clk3, const attotime &clk4)
{
m_our_clock[0] = clk1;
m_our_clock[1] = clk2;
m_our_clock[2] = clk3;
m_our_clock[3] = clk4;
}
void set_burst_clocks(const attotime &clk1, const attotime &clk2, const attotime &clk3, const attotime &clk4)
{
m_burst_clock[0] = clk1;
m_burst_clock[1] = clk2;
m_burst_clock[2] = clk3;
m_burst_clock[3] = clk4;
}
uint16_t read(offs_t offset);
void write(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
DECLARE_WRITE_LINE_MEMBER(drq0_w);
DECLARE_WRITE_LINE_MEMBER(drq1_w);
DECLARE_WRITE_LINE_MEMBER(drq2_w);
DECLARE_WRITE_LINE_MEMBER(drq3_w);
uint8_t iack();
void single_transfer(int x);
void set_timer(int channel, const attotime &tm);
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
private:
struct hd63450_regs
{ // offsets in bytes
uint8_t csr; // [00] Channel status register (R/W)
uint8_t cer; // [01] Channel error register (R)
uint8_t dcr; // [04] Device control register (R/W)
uint8_t ocr; // [05] Operation control register (R/W)
uint8_t scr; // [06] Sequence control register (R/W)
uint8_t ccr; // [07] Channel control register (R/W)
uint16_t mtc; // [0a,0b] Memory Transfer Counter (R/W)
uint32_t mar; // [0c-0f] Memory Address Register (R/W)
uint32_t dar; // [14-17] Device Address Register (R/W)
uint16_t btc; // [1a,1b] Base Transfer Counter (R/W)
uint32_t bar; // [1c-1f] Base Address Register (R/W)
uint8_t niv; // [25] Normal Interrupt Vector (R/W)
uint8_t eiv; // [27] Error Interrupt Vector (R/W)
uint8_t mfc; // [29] Memory Function Code (R/W)
uint8_t cpr; // [2d] Channel Priority Register (R/W)
uint8_t dfc; // [31] Device Function Code (R/W)
uint8_t bfc; // [39] Base Function Code (R/W)
uint8_t gcr; // [3f] General Control Register (R/W)
};
devcb_write_line m_irq_callback;
devcb_write8 m_dma_end;
devcb_read8::array<4> m_dma_read;
devcb_write8::array<4> m_dma_write;
attotime m_our_clock[4];
attotime m_burst_clock[4];
// internal state
hd63450_regs m_reg[4];
emu_timer* m_timer[4]; // for timing data reading/writing each channel
uint16_t m_transfer_size[4];
bool m_halted[4]; // non-zero if a channel has been halted, and can be continued later.
required_device<cpu_device> m_cpu;
bool m_drq_state[4];
int8_t m_irq_channel;
// tell if a channel is in use
bool dma_in_progress(int channel) const { return (m_reg[channel].csr & 0x08) != 0; }
TIMER_CALLBACK_MEMBER(dma_transfer_timer);
void dma_transfer_abort(int channel);
void dma_transfer_halt(int channel);
void dma_transfer_continue(int channel);
void dma_transfer_start(int channel);
void set_error(int channel, uint8_t code);
// interrupt helpers
void set_irq(int channel);
void clear_irq(int channel);
};
DECLARE_DEVICE_TYPE(HD63450, hd63450_device)
#endif // MAME_MACHINE_HD63450_H
|