summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/cdicdic.h
blob: 3eafa710345dbf38c16679a407f1ec77f49cc721 (plain) (blame)
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// license:BSD-3-Clause
// copyright-holders:Ryan Holtz
/******************************************************************************


    CD-i Mono-I CDIC MCU simulation
    -------------------

    written by Ryan Holtz


*******************************************************************************

STATUS:

- Just enough for the Mono-I CD-i board to work somewhat properly.

TODO:

- Decapping and proper emulation.

*******************************************************************************/

#ifndef MAME_MACHINE_CDICDIC_H
#define MAME_MACHINE_CDICDIC_H

#pragma once

#include "imagedev/chd_cd.h"
#include "machine/scc68070.h"
#include "sound/cdda.h"
#include "sound/dmadac.h"
#include "cdrom.h"


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

// ======================> cdicdic_device

class cdicdic_device : public device_t
{
public:
	// construction/destruction
	cdicdic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	void set_clock2(uint32_t clock) { m_clock2 = clock; }
	void set_clock2(const XTAL &xtal) { set_clock2(xtal.value()); }
	uint32_t clock2() const { return m_clock2; }

	auto intreq_callback() { return m_intreq_callback.bind(); }

	// non-static internal members
	void sample_trigger();
	void process_delayed_command();

	uint16_t regs_r(offs_t offset, uint16_t mem_mask = ~0);
	void regs_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);
	uint16_t ram_r(offs_t offset, uint16_t mem_mask = ~0);
	void ram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0);

	uint8_t intack_r();

protected:
	// device-level overrides
	virtual void device_resolve_objects() override;
	virtual void device_start() override;
	virtual void device_reset() override;

	// internal callbacks
	TIMER_CALLBACK_MEMBER( periodic_sample_trigger );
	TIMER_CALLBACK_MEMBER( audio_sample_trigger );
	TIMER_CALLBACK_MEMBER( initial_sample_trigger );
	TIMER_CALLBACK_MEMBER( trigger_readback_int );

private:
	enum
	{
		CDIC_SECTOR_SYNC        = 0,

		CDIC_SECTOR_HEADER      = 12,

		CDIC_SECTOR_MODE        = 15,

		CDIC_SECTOR_FILE1       = 16,
		CDIC_SECTOR_CHAN1       = 17,
		CDIC_SECTOR_SUBMODE1    = 18,
		CDIC_SECTOR_CODING1     = 19,

		CDIC_SECTOR_FILE2       = 20,
		CDIC_SECTOR_CHAN2       = 21,
		CDIC_SECTOR_SUBMODE2    = 22,
		CDIC_SECTOR_CODING2     = 23,

		CDIC_SECTOR_DATA        = 24,

		CDIC_SECTOR_SIZE        = 2352,

		CDIC_SECTOR_DATASIZE    = 2048,
		CDIC_SECTOR_AUDIOSIZE   = 2304,
		CDIC_SECTOR_VIDEOSIZE   = 2324,

		CDIC_SUBMODE_EOF        = 0x80,
		CDIC_SUBMODE_RT         = 0x40,
		CDIC_SUBMODE_FORM       = 0x20,
		CDIC_SUBMODE_TRIG       = 0x10,
		CDIC_SUBMODE_DATA       = 0x08,
		CDIC_SUBMODE_AUDIO      = 0x04,
		CDIC_SUBMODE_VIDEO      = 0x02,
		CDIC_SUBMODE_EOR        = 0x01
	};

	int is_valid_sample_buf(uint16_t addr) const;
	double sample_buf_freq(uint16_t addr) const;
	int sample_buf_size(uint16_t addr) const;

	devcb_write_line m_intreq_callback;

	required_address_space m_memory_space;
	required_device_array<dmadac_sound_device, 2> m_dmadac;
	required_device<scc68070_device> m_scc;
	required_device<cdda_device> m_cdda;
	optional_device<cdrom_image_device> m_cdrom_dev;

	uint32_t m_clock2;

	// internal state
	uint16_t m_command;           // CDIC Command Register            (0x303c00)
	uint32_t m_time;              // CDIC Time Register               (0x303c02)
	uint16_t m_file;              // CDIC File Register               (0x303c06)
	uint32_t m_channel;           // CDIC Channel Register            (0x303c08)
	uint16_t m_audio_channel;     // CDIC Audio Channel Register      (0x303c0c)

	uint16_t m_audio_buffer;      // CDIC Audio Buffer Register       (0x303ff4)
	uint16_t m_x_buffer;          // CDIC X-Buffer Register           (0x303ff6)
	uint16_t m_dma_control;       // CDIC DMA Control Register        (0x303ff8)
	uint16_t m_z_buffer;          // CDIC Z-Buffer Register           (0x303ffa)
	uint16_t m_interrupt_vector;  // CDIC Interrupt Vector Register   (0x303ffc)
	uint16_t m_data_buffer;       // CDIC Data Buffer Register        (0x303ffe)

	emu_timer *m_interrupt_timer;
	cdrom_file *m_cd;

	emu_timer *m_audio_sample_timer;
	emu_timer *m_audio_playback_timer;
	emu_timer *m_periodic_sample_timer[2];
	int32_t m_audio_sample_freq;
	int32_t m_audio_sample_size;

	uint16_t m_decode_addr;
	uint8_t m_decode_delay;
	attotime m_decode_period;
	bool m_break_on_achan;
	bool m_valid_audio_sample;

	int m_xa_last[4];
	std::unique_ptr<uint16_t[]> m_ram;
	std::unique_ptr<int16_t[]> m_samples[2];

	static void decode_xa_mono(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp);
	static void decode_xa_mono8(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp);
	static void decode_xa_stereo(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp);
	static void decode_xa_stereo8(int32_t *cdic_xa_last, const uint8_t *xa, int16_t *dp);

	static const int32_t s_cdic_adpcm_filter_coef[5][2];

	uint32_t increment_cdda_frame_bcd(uint32_t bcd);
	uint32_t increment_cdda_sector_bcd(uint32_t bcd);
	void decode_audio_sector(const uint8_t *xa, int32_t triggered);
	void play_audio_sector();
};

// device type definition
DECLARE_DEVICE_TYPE(CDI_CDIC, cdicdic_device)

#endif // MAME_MACHINE_CDICDIC_H