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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
|
// license:BSD-3-Clause
// copyright-holders:David Haywood
/*****************************************************************************
SunPlus SPG110-series SoC peripheral emulation
0032xx looks like it could be the same as 003dxx on spg2xx
but the video seems to have differences, and data
is fetched from private buffers filled by DMA instead of
main space? tile attributes different? palette format different
**********************************************************************/
#include "emu.h"
#include "spg110.h"
DEFINE_DEVICE_TYPE(SPG110, spg110_device, "spg110", "SPG110 System-on-a-Chip")
spg110_device::spg110_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, address_map_constructor internal) :
unsp_device(mconfig, type, tag, owner, clock, internal),
device_mixer_interface(mconfig, *this, 2),
m_screen(*this, finder_base::DUMMY_TAG),
m_spg_io(*this, "spg_io"),
m_spg_video(*this, "spg_video"),
m_spg_audio(*this, "spgaudio"),
m_porta_out(*this),
m_portb_out(*this),
m_portc_out(*this),
m_porta_in(*this, 0),
m_portb_in(*this, 0),
m_portc_in(*this, 0),
m_adc_in(*this, 0x0fff),
m_chip_sel(*this)
{
}
spg110_device::spg110_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: spg110_device(mconfig, SPG110, tag, owner, clock, address_map_constructor(FUNC(spg110_device::internal_map), this))
{
}
void spg110_device::videoirq_w(int state)
{
set_state_unsynced(UNSP_IRQ0_LINE, state);
}
void spg110_device::timerirq_w(int state)
{
set_state_unsynced(UNSP_IRQ3_LINE, state);
}
void spg110_device::uartirq_w(int state)
{
set_state_unsynced(UNSP_IRQ4_LINE, state);
}
void spg110_device::extirq_w(int state)
{
// External Int1 is IRQ4 (was 5 on SPG2xx)
// External Int2 is IRQ2 (was 5 on SPG2xx)
set_state_unsynced(UNSP_IRQ4_LINE, state);
}
void spg110_device::ffreq1_w(int state)
{
set_state_unsynced(UNSP_IRQ5_LINE, state);
}
void spg110_device::ffreq2_w(int state)
{
set_state_unsynced(UNSP_IRQ6_LINE, state);
}
// notes about IRQ differences from 2xx
//
// TMB1 / TMB2 are IRQ7 (same as SPG2xx)
// Key Change is IRQ4 (was 7 on SPG2xx)
// LVD (Low Voltage Reset) is IRQ6 (doesn't exist on SPG2xx?)
// ADC is IRQ1 (was 3 on SPG2xx)
//
// on SPG2xx 0x3D2E can redirect any other interrupt to the FIQ
// on SPG110 FIQ is always from SPUIRQ (sound)
//
// on SPG2xx SPU_Ch_Irq (sound) is IRQ1, and SPU_Env_Irq / SPU_Beat_Irq is IRQ4
// SPU_Ch_Irq / SPU_Env_Irq and SPU_Beat_Irq don't exist on SPG110? (assume SPU_Ch_Irq is SPUIRQ?)
//
// SPG2xx has SPI Interrupt on IRQ3, no SPI interrupt on SPG110?
void spg110_device::configure_spg_io(spg2xx_io_device* io)
{
io->porta_in().set(FUNC(spg110_device::porta_r));
io->portb_in().set(FUNC(spg110_device::portb_r));
io->portc_in().set(FUNC(spg110_device::portc_r));
io->porta_out().set(FUNC(spg110_device::porta_w));
io->portb_out().set(FUNC(spg110_device::portb_w));
io->portc_out().set(FUNC(spg110_device::portc_w));
io->adc_in<0>().set(FUNC(spg110_device::adc_r<0>));
io->adc_in<1>().set(FUNC(spg110_device::adc_r<1>));
io->adc_in<2>().set(FUNC(spg110_device::adc_r<2>));
io->adc_in<3>().set(FUNC(spg110_device::adc_r<3>));
io->chip_select().set(FUNC(spg110_device::cs_w));
// io->pal_read_callback().set(FUNC(spg110_device::get_pal_r));
io->write_timer_irq_callback().set(FUNC(spg110_device::timerirq_w));
io->write_uart_adc_irq_callback().set(FUNC(spg110_device::uartirq_w));
io->write_external_irq_callback().set(FUNC(spg110_device::extirq_w));
io->write_ffrq_tmr1_irq_callback().set(FUNC(spg110_device::ffreq1_w));
io->write_ffrq_tmr2_irq_callback().set(FUNC(spg110_device::ffreq2_w));
}
uint16_t spg110_device::space_r(offs_t offset)
{
address_space &cpuspace = this->space(AS_PROGRAM);
return cpuspace.read_word(offset);
}
void spg110_device::audioirq_w(int state)
{
set_state_unsynced(UNSP_FIQ_LINE, state);
}
void spg110_device::device_add_mconfig(machine_config &config)
{
SPG24X_IO(config, m_spg_io, DERIVED_CLOCK(1, 1), DEVICE_SELF, m_screen);
configure_spg_io(m_spg_io);
SPG110_VIDEO(config, m_spg_video, DERIVED_CLOCK(1, 1), DEVICE_SELF, m_screen);
m_spg_video->write_video_irq_callback().set(FUNC(spg110_device::videoirq_w));
SPG110_AUDIO(config, m_spg_audio, DERIVED_CLOCK(1, 1));
m_spg_audio->write_irq_callback().set(FUNC(spg110_device::audioirq_w));
m_spg_audio->space_read_callback().set(FUNC(spg110_device::space_r));
m_spg_audio->add_route(0, *this, 1.0, AUTO_ALLOC_INPUT, 0);
m_spg_audio->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1);
}
void spg110_device::internal_map(address_map &map)
{
map(0x000000, 0x000fff).ram();
// vregs are at 2000?
map(0x002010, 0x002015).rw(m_spg_video, FUNC(spg110_video_device::tmap0_regs_r), FUNC(spg110_video_device::tmap0_regs_w));
map(0x002016, 0x00201b).rw(m_spg_video, FUNC(spg110_video_device::tmap1_regs_r), FUNC(spg110_video_device::tmap1_regs_w));
map(0x00201c, 0x00201c).w(m_spg_video, FUNC(spg110_video_device::vcomp_val_201c_w)); // P_VComp_Value (vertical compression)
map(0x002020, 0x002027).w(m_spg_video, FUNC(spg110_video_device::segment_202x_w)); // P_Segment0-7 (tilebases)
map(0x002028, 0x002028).rw(m_spg_video, FUNC(spg110_video_device::adr_mode_2028_r), FUNC(spg110_video_device::adr_mode_2028_w)); // P_Adr_mode
map(0x002029, 0x002029).rw(m_spg_video, FUNC(spg110_video_device::ext_bus_2029_r), FUNC(spg110_video_device::ext_bus_2029_w)); // P_Ext_Bus
// 0x202a // P_Blending
// 0x2030 // P_Eff_color
map(0x002031, 0x002031).w(m_spg_video, FUNC(spg110_video_device::win_mask_1_2031_w)); // P_Win_mask1 - sometimes 14a?
map(0x002032, 0x002032).w(m_spg_video, FUNC(spg110_video_device::win_mask_2_2032_w)); // P_Win_mask2 - always 14a?
map(0x002033, 0x002033).w(m_spg_video, FUNC(spg110_video_device::win_attribute_w)); // P_Win_attrribute
map(0x002034, 0x002034).w(m_spg_video, FUNC(spg110_video_device::win_mask_3_2034_w)); // P_Win_mask3
map(0x002035, 0x002035).w(m_spg_video, FUNC(spg110_video_device::win_mask_4_2035_w)); // P_Win_mask4
map(0x002036, 0x002036).w(m_spg_video, FUNC(spg110_video_device::irq_tm_v_2036_w)); // P_IRQTMV
map(0x002037, 0x002037).rw(m_spg_video, FUNC(spg110_video_device::irq_tm_h_2037_r), FUNC(spg110_video_device::irq_tm_h_2037_w)); // P_IRQTMH
// 0x2038 // P_Effect_color (not the same as 2030)
map(0x002039, 0x002039).w(m_spg_video, FUNC(spg110_video_device::effect_control_2039_w)); // P_Effect_control
// 0x203a // P_Mix_offset
// 0x203b // P_Fan_effect_th
map(0x00203c, 0x00203c).w(m_spg_video, FUNC(spg110_video_device::huereference_203c_w)); // P_203C_HueRefer (should be set based on PAL/NTSC)
map(0x00203d, 0x00203d).w(m_spg_video, FUNC(spg110_video_device::lum_adjust_203d_w)); // P_Lum_Adjust
// 0x203e // P_LPVPosition
// 0x203f // P_LPHPosition
map(0x002042, 0x002042).rw(m_spg_video, FUNC(spg110_video_device::sp_control_2042_r),FUNC(spg110_video_device::sp_control_2042_w)); // P_Sp_control
map(0x002045, 0x002045).w(m_spg_video, FUNC(spg110_video_device::spg110_2045_w)); // not documented?
map(0x002050, 0x00205f).ram().w(m_spg_video, FUNC(spg110_video_device::transparent_color_205x_w)).share("spg_video:palctrlram"); // P_Trptcolor0 - 15
map(0x002060, 0x002060).w(m_spg_video, FUNC(spg110_video_device::dma_dst_2060_w)); // P_DMA_Target_adr
map(0x002061, 0x002061).w(m_spg_video, FUNC(spg110_video_device::dma_dst_seg_2061_w)); // P_DMA_Target_seg
map(0x002062, 0x002062).rw(m_spg_video, FUNC(spg110_video_device::dma_len_status_2062_r),FUNC(spg110_video_device::dma_len_trigger_2062_w)); // P_DMA_numbr
map(0x002063, 0x002063).rw(m_spg_video, FUNC(spg110_video_device::spg110_2063_r),FUNC(spg110_video_device::spg110_2063_w)); // P_DMA_control - Video IRQ source / ack (3 different things checked here instead of 2 on spg2xx?)
map(0x002064, 0x002064).w(m_spg_video, FUNC(spg110_video_device::dma_dst_step_2064_w)); // P_DMA_Target_step
map(0x002065, 0x002065).rw(m_spg_video, FUNC(spg110_video_device::dma_manual_2065_r), FUNC(spg110_video_device::dma_manual_2065_w)); // P_DMA_data
map(0x002066, 0x002066).w(m_spg_video, FUNC(spg110_video_device::dma_source_2066_w)); // P_DMA_Source_adr
map(0x002067, 0x002067).w(m_spg_video, FUNC(spg110_video_device::dma_source_seg_2067_w)); // P_DMA_Source_seg
map(0x002068, 0x002068).rw(m_spg_video, FUNC(spg110_video_device::dma_src_step_2068_r), FUNC(spg110_video_device::dma_src_step_2068_w)); // P_DMA_Source_step
map(0x002100, 0x0021ff).ram(); // P_Tx_Hvoffset0 - P_Tx_Hvoffset255 // rowscroll table
map(0x002200, 0x0022ff).ram(); // P_HComp_Value0 - P_HComp_Value255 // horizontal compression table
/// sound registers? seems to be 8 long entries, only uses up to 0x7f? (register mapping seems similar to spg2xx, maybe with less channels?)
map(0x003000, 0x00307f).rw(m_spg_audio, FUNC(spg110_audio_device::audio_r), FUNC(spg110_audio_device::audio_w));
map(0x003080, 0x0030ff).ram(); // extra ram? doesn't seem to be phase, and there only appear to be 8 channels on SPG110
map(0x003100, 0x00310f).rw(m_spg_audio, FUNC(spg110_audio_device::audio_ctrl_r), FUNC(spg2xx_audio_device::audio_ctrl_w));
// 0032xx looks like it could be the same as 003d00 on spg2xx
map(0x003200, 0x00322f).rw(m_spg_io, FUNC(spg2xx_io_device::io_r), FUNC(spg2xx_io_device::io_w));
}
void spg110_device::device_reset()
{
unsp_device::device_reset();
}
|