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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
|
// license:BSD-3-Clause
// copyright-holders:Juergen Buchmueller, Mike Balfour, Howie Cohen, Olivier Galibert, Aaron Giles
#ifndef MAME_SOUND_UPD7759_H
#define MAME_SOUND_UPD7759_H
#pragma once
#include "dirom.h"
/* NEC uPD7759/55/56/P56/57/58 ADPCM Speech Processor */
/* There are two modes for the uPD7759, selected through the !MD pin.
This is the mode select input. High is stand alone, low is slave.
*/
class upd775x_device : public device_t,
public device_sound_interface,
public device_rom_interface<17>
{
public:
enum : u32 { STANDARD_CLOCK = 640'000 };
void reset_w(int state);
void start_w(int state);
int busy_r();
virtual void port_w(u8 data);
void set_start_delay(uint32_t data) { m_start_delay = data; }
protected:
virtual TIMER_CALLBACK_MEMBER(internal_start_w);
virtual TIMER_CALLBACK_MEMBER(internal_reset_w);
virtual TIMER_CALLBACK_MEMBER(internal_port_w);
enum
{
TID_PORT_WRITE,
TID_START_WRITE,
TID_RESET_WRITE,
TID_SLAVE_UPDATE,
TID_MD_WRITE
};
// chip states
enum
{
STATE_IDLE,
STATE_DROP_DRQ,
STATE_START,
STATE_FIRST_REQ,
STATE_LAST_SAMPLE,
STATE_DUMMY1,
STATE_ADDR_MSB,
STATE_ADDR_LSB,
STATE_DUMMY2,
STATE_BLOCK_HEADER,
STATE_NIBBLE_COUNT,
STATE_NIBBLE_MSN,
STATE_NIBBLE_LSN
};
// chip modes
enum
{
MODE_SLAVE,
MODE_STAND_ALONE
};
upd775x_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
// device-level overrides
virtual void device_start() override ATTR_COLD;
virtual void device_clock_changed() override;
virtual void device_reset() override ATTR_COLD;
virtual void rom_bank_pre_change() override;
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
void update_adpcm(int data);
virtual void advance_state();
// internal state
sound_stream *m_channel; // stream channel for playback
// chip configuration
uint8_t m_sample_offset_shift; // header sample address shift (access data > 0xffff)
// internal clock to output sample rate mapping
uint32_t m_pos; // current output sample position
uint32_t m_step; // step value per output sample
attotime m_clock_period; // clock period
// I/O lines
uint8_t m_fifo_in; // last data written to the sound chip
uint8_t m_reset; // current state of the RESET line
uint8_t m_start; // current state of the START line
uint8_t m_drq; // current state of the DRQ line
// internal state machine
int8_t m_state; // current overall chip state
int32_t m_clocks_left; // number of clocks left in this state
uint16_t m_nibbles_left; // number of ADPCM nibbles left to process
uint8_t m_repeat_count; // number of repeats remaining in current repeat block
int8_t m_post_drq_state; // state we will be in after the DRQ line is dropped
int32_t m_post_drq_clocks; // clocks that will be left after the DRQ line is dropped
uint8_t m_req_sample; // requested sample number
uint8_t m_last_sample; // last sample number available
uint8_t m_block_header; // header byte
uint8_t m_sample_rate; // number of UPD clocks per ADPCM nibble
uint8_t m_first_valid_header; // did we get our first valid header yet?
uint32_t m_offset; // current ROM offset
uint32_t m_repeat_offset; // current ROM repeat offset
uint32_t m_start_delay;
int m_mode; // current mode of the sound chip
// ADPCM processing
int8_t m_adpcm_state; // ADPCM state index
uint8_t m_adpcm_data; // current byte of ADPCM data
int16_t m_sample; // current sample value
// ROM access
int m_md; // High is stand alone, low is slave.
};
class upd7759_device : public upd775x_device
{
public:
auto drq() { return m_drqcallback.bind(); }
upd7759_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = STANDARD_CLOCK);
void md_w(int state);
protected:
upd7759_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual void device_start() override ATTR_COLD;
virtual void device_reset() override ATTR_COLD;
TIMER_CALLBACK_MEMBER(drq_update);
void internal_md_w(int state);
devcb_write_line m_drqcallback;
emu_timer *m_timer;
};
class upd7756_device : public upd775x_device
{
public:
upd7756_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = STANDARD_CLOCK);
protected:
upd7756_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
virtual void device_reset() override ATTR_COLD;
};
DECLARE_DEVICE_TYPE(UPD7759, upd7759_device)
DECLARE_DEVICE_TYPE(UPD7756, upd7756_device)
#endif // MAME_SOUND_UPD7759_H
|