trunk/src/emu/sound/okim6258.c
| r21835 | r21836 | |
| 21 | 21 | |
| 22 | 22 | static const int dividers[4] = { 1024, 768, 512, 512 }; |
| 23 | 23 | |
| 24 | | struct okim6258_state |
| 25 | | { |
| 26 | | UINT8 status; |
| 27 | | |
| 28 | | UINT32 master_clock; /* master clock frequency */ |
| 29 | | UINT32 divider; /* master clock divider */ |
| 30 | | UINT8 adpcm_type; /* 3/4 bit ADPCM select */ |
| 31 | | UINT8 data_in; /* ADPCM data-in register */ |
| 32 | | UINT8 nibble_shift; /* nibble select */ |
| 33 | | sound_stream *stream; /* which stream are we playing on? */ |
| 34 | | |
| 35 | | UINT8 output_bits; |
| 36 | | |
| 37 | | INT32 signal; |
| 38 | | INT32 step; |
| 39 | | }; |
| 40 | | |
| 41 | 24 | /* step size index shift table */ |
| 42 | 25 | static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; |
| 43 | 26 | |
| r21835 | r21836 | |
| 47 | 30 | /* tables computed? */ |
| 48 | 31 | static int tables_computed = 0; |
| 49 | 32 | |
| 50 | | INLINE okim6258_state *get_safe_token(device_t *device) |
| 33 | |
| 34 | |
| 35 | // device type definition |
| 36 | const device_type OKIM6258 = &device_creator<okim6258_device>; |
| 37 | |
| 38 | |
| 39 | //************************************************************************** |
| 40 | // LIVE DEVICE |
| 41 | //************************************************************************** |
| 42 | |
| 43 | //------------------------------------------------- |
| 44 | // okim6258_device - constructor |
| 45 | //------------------------------------------------- |
| 46 | |
| 47 | okim6258_device::okim6258_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 48 | : device_t(mconfig, OKIM6258, "OKI6258", tag, owner, clock), |
| 49 | device_sound_interface(mconfig, *this), |
| 50 | m_status(0), |
| 51 | m_master_clock(0), |
| 52 | m_divider(0), |
| 53 | m_adpcm_type(0), |
| 54 | m_data_in(0), |
| 55 | m_nibble_shift(0), |
| 56 | m_stream(NULL), |
| 57 | m_output_bits(0), |
| 58 | m_signal(0), |
| 59 | m_step(0) |
| 51 | 60 | { |
| 52 | | assert(device != NULL); |
| 53 | | assert(device->type() == OKIM6258); |
| 54 | | return (okim6258_state *)downcast<okim6258_device *>(device)->token(); |
| 55 | 61 | } |
| 56 | 62 | |
| 63 | |
| 64 | |
| 57 | 65 | /********************************************************************************************** |
| 58 | 66 | |
| 59 | 67 | compute_tables -- compute the difference tables |
| r21835 | r21836 | |
| 94 | 102 | } |
| 95 | 103 | |
| 96 | 104 | |
| 97 | | static INT16 clock_adpcm(okim6258_state *chip, UINT8 nibble) |
| 105 | //------------------------------------------------- |
| 106 | // device_start - device-specific startup |
| 107 | //------------------------------------------------- |
| 108 | |
| 109 | void okim6258_device::device_start() |
| 98 | 110 | { |
| 99 | | INT32 max = (1 << (chip->output_bits - 1)) - 1; |
| 100 | | INT32 min = -(1 << (chip->output_bits - 1)); |
| 111 | const okim6258_interface *intf = (const okim6258_interface *)static_config(); |
| 101 | 112 | |
| 102 | | chip->signal += diff_lookup[chip->step * 16 + (nibble & 15)]; |
| 113 | compute_tables(); |
| 103 | 114 | |
| 104 | | /* clamp to the maximum */ |
| 105 | | if (chip->signal > max) |
| 106 | | chip->signal = max; |
| 107 | | else if (chip->signal < min) |
| 108 | | chip->signal = min; |
| 115 | m_master_clock = clock(); |
| 116 | m_adpcm_type = intf->adpcm_type; |
| 109 | 117 | |
| 110 | | /* adjust the step size and clamp */ |
| 111 | | chip->step += index_shift[nibble & 7]; |
| 112 | | if (chip->step > 48) |
| 113 | | chip->step = 48; |
| 114 | | else if (chip->step < 0) |
| 115 | | chip->step = 0; |
| 118 | /* D/A precision is 10-bits but 12-bit data can be output serially to an external DAC */ |
| 119 | m_output_bits = intf->output_12bits ? 12 : 10; |
| 120 | m_divider = dividers[intf->divider]; |
| 116 | 121 | |
| 117 | | /* return the signal scaled up to 32767 */ |
| 118 | | return chip->signal << 4; |
| 122 | m_stream = stream_alloc(0, 1, clock()/m_divider); |
| 123 | |
| 124 | m_signal = -2; |
| 125 | m_step = 0; |
| 126 | |
| 127 | okim6258_state_save_register(); |
| 119 | 128 | } |
| 120 | 129 | |
| 121 | | /********************************************************************************************** |
| 122 | 130 | |
| 123 | | okim6258_update -- update the sound chip so that it is in sync with CPU execution |
| 131 | //------------------------------------------------- |
| 132 | // device_reset - device-specific reset |
| 133 | //------------------------------------------------- |
| 124 | 134 | |
| 125 | | ***********************************************************************************************/ |
| 135 | void okim6258_device::device_reset() |
| 136 | { |
| 137 | m_stream->update(); |
| 126 | 138 | |
| 127 | | static STREAM_UPDATE( okim6258_update ) |
| 139 | m_signal = -2; |
| 140 | m_step = 0; |
| 141 | m_status = 0; |
| 142 | } |
| 143 | |
| 144 | |
| 145 | //------------------------------------------------- |
| 146 | // sound_stream_update - handle a stream update |
| 147 | //------------------------------------------------- |
| 148 | |
| 149 | void okim6258_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 128 | 150 | { |
| 129 | | okim6258_state *chip = (okim6258_state *)param; |
| 130 | 151 | stream_sample_t *buffer = outputs[0]; |
| 131 | 152 | |
| 132 | 153 | memset(outputs[0], 0, samples * sizeof(*outputs[0])); |
| 133 | 154 | |
| 134 | | if (chip->status & STATUS_PLAYING) |
| 155 | if (m_status & STATUS_PLAYING) |
| 135 | 156 | { |
| 136 | | int nibble_shift = chip->nibble_shift; |
| 157 | int nibble_shift = m_nibble_shift; |
| 137 | 158 | |
| 138 | 159 | while (samples) |
| 139 | 160 | { |
| 140 | 161 | /* Compute the new amplitude and update the current step */ |
| 141 | | int nibble = (chip->data_in >> nibble_shift) & 0xf; |
| 162 | int nibble = (m_data_in >> nibble_shift) & 0xf; |
| 142 | 163 | |
| 143 | 164 | /* Output to the buffer */ |
| 144 | | INT16 sample = clock_adpcm(chip, nibble); |
| 165 | INT16 sample = clock_adpcm(nibble); |
| 145 | 166 | |
| 146 | 167 | nibble_shift ^= 4; |
| 147 | 168 | |
| r21835 | r21836 | |
| 150 | 171 | } |
| 151 | 172 | |
| 152 | 173 | /* Update the parameters */ |
| 153 | | chip->nibble_shift = nibble_shift; |
| 174 | m_nibble_shift = nibble_shift; |
| 154 | 175 | } |
| 155 | 176 | else |
| 156 | 177 | { |
| r21835 | r21836 | |
| 168 | 189 | |
| 169 | 190 | ***********************************************************************************************/ |
| 170 | 191 | |
| 171 | | static void okim6258_state_save_register(okim6258_state *info, device_t *device) |
| 192 | void okim6258_device::okim6258_state_save_register() |
| 172 | 193 | { |
| 173 | | device->save_item(NAME(info->status)); |
| 174 | | device->save_item(NAME(info->master_clock)); |
| 175 | | device->save_item(NAME(info->divider)); |
| 176 | | device->save_item(NAME(info->data_in)); |
| 177 | | device->save_item(NAME(info->nibble_shift)); |
| 178 | | device->save_item(NAME(info->signal)); |
| 179 | | device->save_item(NAME(info->step)); |
| 194 | save_item(NAME(m_status)); |
| 195 | save_item(NAME(m_master_clock)); |
| 196 | save_item(NAME(m_divider)); |
| 197 | save_item(NAME(m_data_in)); |
| 198 | save_item(NAME(m_nibble_shift)); |
| 199 | save_item(NAME(m_signal)); |
| 200 | save_item(NAME(m_step)); |
| 180 | 201 | } |
| 181 | 202 | |
| 182 | 203 | |
| 183 | | /********************************************************************************************** |
| 184 | | |
| 185 | | OKIM6258_start -- start emulation of an OKIM6258-compatible chip |
| 186 | | |
| 187 | | ***********************************************************************************************/ |
| 188 | | |
| 189 | | static DEVICE_START( okim6258 ) |
| 204 | INT16 okim6258_device::clock_adpcm(UINT8 nibble) |
| 190 | 205 | { |
| 191 | | const okim6258_interface *intf = (const okim6258_interface *)device->static_config(); |
| 192 | | okim6258_state *info = get_safe_token(device); |
| 206 | INT32 max = (1 << (m_output_bits - 1)) - 1; |
| 207 | INT32 min = -(1 << (m_output_bits - 1)); |
| 193 | 208 | |
| 194 | | compute_tables(); |
| 209 | m_signal += diff_lookup[m_step * 16 + (nibble & 15)]; |
| 195 | 210 | |
| 196 | | info->master_clock = device->clock(); |
| 197 | | info->adpcm_type = intf->adpcm_type; |
| 211 | /* clamp to the maximum */ |
| 212 | if (m_signal > max) |
| 213 | m_signal = max; |
| 214 | else if (m_signal < min) |
| 215 | m_signal = min; |
| 198 | 216 | |
| 199 | | /* D/A precision is 10-bits but 12-bit data can be output serially to an external DAC */ |
| 200 | | info->output_bits = intf->output_12bits ? 12 : 10; |
| 201 | | info->divider = dividers[intf->divider]; |
| 217 | /* adjust the step size and clamp */ |
| 218 | m_step += index_shift[nibble & 7]; |
| 219 | if (m_step > 48) |
| 220 | m_step = 48; |
| 221 | else if (m_step < 0) |
| 222 | m_step = 0; |
| 202 | 223 | |
| 203 | | info->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock()/info->divider, info, okim6258_update); |
| 204 | | |
| 205 | | info->signal = -2; |
| 206 | | info->step = 0; |
| 207 | | |
| 208 | | okim6258_state_save_register(info, device); |
| 224 | /* return the signal scaled up to 32767 */ |
| 225 | return m_signal << 4; |
| 209 | 226 | } |
| 210 | 227 | |
| 211 | 228 | |
| 212 | 229 | /********************************************************************************************** |
| 213 | 230 | |
| 214 | | OKIM6258_stop -- stop emulation of an OKIM6258-compatible chip |
| 231 | okim6258::set_divider -- set the master clock divider |
| 215 | 232 | |
| 216 | 233 | ***********************************************************************************************/ |
| 217 | 234 | |
| 218 | | static DEVICE_RESET( okim6258 ) |
| 235 | void okim6258_device::set_divider(int val) |
| 219 | 236 | { |
| 220 | | okim6258_state *info = get_safe_token(device); |
| 221 | | |
| 222 | | info->stream->update(); |
| 223 | | |
| 224 | | info->signal = -2; |
| 225 | | info->step = 0; |
| 226 | | info->status = 0; |
| 227 | | } |
| 228 | | |
| 229 | | |
| 230 | | /********************************************************************************************** |
| 231 | | |
| 232 | | okim6258_set_divider -- set the master clock divider |
| 233 | | |
| 234 | | ***********************************************************************************************/ |
| 235 | | |
| 236 | | void okim6258_set_divider(device_t *device, int val) |
| 237 | | { |
| 238 | | okim6258_state *info = get_safe_token(device); |
| 239 | 237 | int divider = dividers[val]; |
| 240 | 238 | |
| 241 | | info->divider = dividers[val]; |
| 242 | | info->stream->set_sample_rate(info->master_clock / divider); |
| 239 | m_divider = dividers[val]; |
| 240 | m_stream->set_sample_rate(m_master_clock / divider); |
| 243 | 241 | } |
| 244 | 242 | |
| 245 | 243 | |
| 246 | 244 | /********************************************************************************************** |
| 247 | 245 | |
| 248 | | okim6258_set_clock -- set the master clock |
| 246 | okim6258::set_clock -- set the master clock |
| 249 | 247 | |
| 250 | 248 | ***********************************************************************************************/ |
| 251 | 249 | |
| 252 | | void okim6258_set_clock(device_t *device, int val) |
| 250 | void okim6258_device::set_clock(int val) |
| 253 | 251 | { |
| 254 | | okim6258_state *info = get_safe_token(device); |
| 255 | | |
| 256 | | info->master_clock = val; |
| 257 | | info->stream->set_sample_rate(info->master_clock / info->divider); |
| 252 | m_master_clock = val; |
| 253 | m_stream->set_sample_rate(m_master_clock / m_divider); |
| 258 | 254 | } |
| 259 | 255 | |
| 260 | 256 | |
| 261 | 257 | /********************************************************************************************** |
| 262 | 258 | |
| 263 | | okim6258_get_vclk -- get the VCLK/sampling frequency |
| 259 | okim6258::get_vclk -- get the VCLK/sampling frequency |
| 264 | 260 | |
| 265 | 261 | ***********************************************************************************************/ |
| 266 | 262 | |
| 267 | | int okim6258_get_vclk(device_t *device) |
| 263 | int okim6258_device::get_vclk() |
| 268 | 264 | { |
| 269 | | okim6258_state *info = get_safe_token(device); |
| 270 | | |
| 271 | | return (info->master_clock / info->divider); |
| 265 | return (m_master_clock / m_divider); |
| 272 | 266 | } |
| 273 | 267 | |
| 274 | 268 | |
| r21835 | r21836 | |
| 278 | 272 | |
| 279 | 273 | ***********************************************************************************************/ |
| 280 | 274 | |
| 281 | | READ8_DEVICE_HANDLER( okim6258_status_r ) |
| 275 | READ8_MEMBER( okim6258_device::okim6258_status_r ) |
| 282 | 276 | { |
| 283 | | okim6258_state *info = get_safe_token(device); |
| 277 | m_stream->update(); |
| 284 | 278 | |
| 285 | | info->stream->update(); |
| 286 | | |
| 287 | | return (info->status & STATUS_PLAYING) ? 0x00 : 0x80; |
| 279 | return (m_status & STATUS_PLAYING) ? 0x00 : 0x80; |
| 288 | 280 | } |
| 289 | 281 | |
| 290 | 282 | |
| r21835 | r21836 | |
| 293 | 285 | okim6258_data_w -- write to the control port of an OKIM6258-compatible chip |
| 294 | 286 | |
| 295 | 287 | ***********************************************************************************************/ |
| 296 | | WRITE8_DEVICE_HANDLER( okim6258_data_w ) |
| 288 | WRITE8_MEMBER( okim6258_device::okim6258_data_w ) |
| 297 | 289 | { |
| 298 | | okim6258_state *info = get_safe_token(device); |
| 299 | | |
| 300 | 290 | /* update the stream */ |
| 301 | | info->stream->update(); |
| 291 | m_stream->update(); |
| 302 | 292 | |
| 303 | | info->data_in = data; |
| 304 | | info->nibble_shift = 0; |
| 293 | m_data_in = data; |
| 294 | m_nibble_shift = 0; |
| 305 | 295 | } |
| 306 | 296 | |
| 307 | 297 | |
| r21835 | r21836 | |
| 311 | 301 | |
| 312 | 302 | ***********************************************************************************************/ |
| 313 | 303 | |
| 314 | | WRITE8_DEVICE_HANDLER( okim6258_ctrl_w ) |
| 304 | WRITE8_MEMBER( okim6258_device::okim6258_ctrl_w ) |
| 315 | 305 | { |
| 316 | | okim6258_state *info = get_safe_token(device); |
| 306 | m_stream->update(); |
| 317 | 307 | |
| 318 | | info->stream->update(); |
| 319 | | |
| 320 | 308 | if (data & COMMAND_STOP) |
| 321 | 309 | { |
| 322 | | info->status &= ~(STATUS_PLAYING | STATUS_RECORDING); |
| 310 | m_status &= ~(STATUS_PLAYING | STATUS_RECORDING); |
| 323 | 311 | return; |
| 324 | 312 | } |
| 325 | 313 | |
| 326 | 314 | if (data & COMMAND_PLAY) |
| 327 | 315 | { |
| 328 | | if (!(info->status & STATUS_PLAYING)) |
| 316 | if (!(m_status & STATUS_PLAYING)) |
| 329 | 317 | { |
| 330 | | info->status |= STATUS_PLAYING; |
| 318 | m_status |= STATUS_PLAYING; |
| 331 | 319 | |
| 332 | 320 | /* Also reset the ADPCM parameters */ |
| 333 | | info->signal = -2; |
| 334 | | info->step = 0; |
| 335 | | info->nibble_shift = 0; |
| 321 | m_signal = -2; |
| 322 | m_step = 0; |
| 323 | m_nibble_shift = 0; |
| 336 | 324 | } |
| 337 | 325 | } |
| 338 | 326 | else |
| 339 | 327 | { |
| 340 | | info->status &= ~STATUS_PLAYING; |
| 328 | m_status &= ~STATUS_PLAYING; |
| 341 | 329 | } |
| 342 | 330 | |
| 343 | 331 | if (data & COMMAND_RECORD) |
| 344 | 332 | { |
| 345 | 333 | logerror("M6258: Record enabled\n"); |
| 346 | | info->status |= STATUS_RECORDING; |
| 334 | m_status |= STATUS_RECORDING; |
| 347 | 335 | } |
| 348 | 336 | else |
| 349 | 337 | { |
| 350 | | info->status &= ~STATUS_RECORDING; |
| 338 | m_status &= ~STATUS_RECORDING; |
| 351 | 339 | } |
| 352 | 340 | } |
| 353 | 341 | |
| 354 | 342 | |
| 355 | | const device_type OKIM6258 = &device_creator<okim6258_device>; |
| 356 | | |
| 357 | | okim6258_device::okim6258_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 358 | | : device_t(mconfig, OKIM6258, "OKI6258", tag, owner, clock), |
| 359 | | device_sound_interface(mconfig, *this) |
| 360 | | { |
| 361 | | m_token = global_alloc_clear(okim6258_state); |
| 362 | | } |
| 363 | | |
| 364 | | //------------------------------------------------- |
| 365 | | // device_config_complete - perform any |
| 366 | | // operations now that the configuration is |
| 367 | | // complete |
| 368 | | //------------------------------------------------- |
| 369 | | |
| 370 | | void okim6258_device::device_config_complete() |
| 371 | | { |
| 372 | | } |
| 373 | | |
| 374 | | //------------------------------------------------- |
| 375 | | // device_start - device-specific startup |
| 376 | | //------------------------------------------------- |
| 377 | | |
| 378 | | void okim6258_device::device_start() |
| 379 | | { |
| 380 | | DEVICE_START_NAME( okim6258 )(this); |
| 381 | | } |
| 382 | | |
| 383 | | //------------------------------------------------- |
| 384 | | // device_reset - device-specific reset |
| 385 | | //------------------------------------------------- |
| 386 | | |
| 387 | | void okim6258_device::device_reset() |
| 388 | | { |
| 389 | | DEVICE_RESET_NAME( okim6258 )(this); |
| 390 | | } |
| 391 | | |
| 392 | | //------------------------------------------------- |
| 393 | | // sound_stream_update - handle a stream update |
| 394 | | //------------------------------------------------- |
| 395 | | |
| 396 | | void okim6258_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 397 | | { |
| 398 | | // should never get here |
| 399 | | fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); |
| 400 | | } |
trunk/src/emu/sound/okim6258.h
| r21835 | r21836 | |
| 3 | 3 | #ifndef __OKIM6258_H__ |
| 4 | 4 | #define __OKIM6258_H__ |
| 5 | 5 | |
| 6 | | #include "devlegcy.h" |
| 7 | | |
| 8 | | /* an interface for the OKIM6258 and similar chips */ |
| 9 | | |
| 10 | | struct okim6258_interface |
| 11 | | { |
| 12 | | int divider; |
| 13 | | int adpcm_type; |
| 14 | | int output_12bits; |
| 15 | | }; |
| 16 | | |
| 17 | | |
| 18 | 6 | #define FOSC_DIV_BY_1024 0 |
| 19 | 7 | #define FOSC_DIV_BY_768 1 |
| 20 | 8 | #define FOSC_DIV_BY_512 2 |
| r21835 | r21836 | |
| 25 | 13 | #define OUTPUT_10BITS 0 |
| 26 | 14 | #define OUTPUT_12BITS 1 |
| 27 | 15 | |
| 28 | | void okim6258_set_divider(device_t *device, int val); |
| 29 | | void okim6258_set_clock(device_t *device, int val); |
| 30 | | int okim6258_get_vclk(device_t *device); |
| 31 | 16 | |
| 32 | | DECLARE_READ8_DEVICE_HANDLER( okim6258_status_r ); |
| 33 | | DECLARE_WRITE8_DEVICE_HANDLER( okim6258_data_w ); |
| 34 | | DECLARE_WRITE8_DEVICE_HANDLER( okim6258_ctrl_w ); |
| 17 | //************************************************************************** |
| 18 | // INTERFACE CONFIGURATION MACROS |
| 19 | //************************************************************************** |
| 35 | 20 | |
| 21 | #define MCFG_OKIM6258_ADD(_tag, _clock) \ |
| 22 | MCFG_DEVICE_ADD(_tag, OKIM6258, _clock) |
| 23 | #define MCFG_OKIM6258_REPLACE(_tag, _clock) \ |
| 24 | MCFG_DEVICE_REPLACE(_tag, OKIM6258, _clock) |
| 25 | |
| 26 | |
| 27 | //************************************************************************** |
| 28 | // TYPE DEFINITIONS |
| 29 | //************************************************************************** |
| 30 | |
| 31 | struct okim6258_interface |
| 32 | { |
| 33 | int divider; |
| 34 | int adpcm_type; |
| 35 | int output_12bits; |
| 36 | }; |
| 37 | |
| 38 | |
| 39 | // ======================> okim6258_device |
| 40 | |
| 36 | 41 | class okim6258_device : public device_t, |
| 37 | | public device_sound_interface |
| 42 | public device_sound_interface |
| 38 | 43 | { |
| 39 | 44 | public: |
| 40 | 45 | okim6258_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 41 | | ~okim6258_device() { global_free(m_token); } |
| 46 | ~okim6258_device() { } |
| 42 | 47 | |
| 43 | | // access to legacy token |
| 44 | | void *token() const { assert(m_token != NULL); return m_token; } |
| 45 | 48 | protected: |
| 46 | 49 | // device-level overrides |
| 47 | | virtual void device_config_complete(); |
| 48 | 50 | virtual void device_start(); |
| 49 | 51 | virtual void device_reset(); |
| 50 | 52 | |
| 51 | 53 | // sound stream update overrides |
| 52 | 54 | virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); |
| 55 | |
| 56 | public: |
| 57 | DECLARE_READ8_MEMBER( okim6258_status_r ); |
| 58 | DECLARE_WRITE8_MEMBER( okim6258_data_w ); |
| 59 | DECLARE_WRITE8_MEMBER( okim6258_ctrl_w ); |
| 60 | |
| 61 | public: |
| 62 | void set_divider(int val); |
| 63 | void set_clock(int val); |
| 64 | int get_vclk(); |
| 65 | |
| 53 | 66 | private: |
| 54 | | // internal state |
| 55 | | void *m_token; |
| 67 | void okim6258_state_save_register(); |
| 68 | INT16 clock_adpcm(UINT8 nibble); |
| 69 | |
| 70 | private: |
| 71 | UINT8 m_status; |
| 72 | |
| 73 | UINT32 m_master_clock; /* master clock frequency */ |
| 74 | UINT32 m_divider; /* master clock divider */ |
| 75 | UINT8 m_adpcm_type; /* 3/4 bit ADPCM select */ |
| 76 | UINT8 m_data_in; /* ADPCM data-in register */ |
| 77 | UINT8 m_nibble_shift; /* nibble select */ |
| 78 | sound_stream *m_stream; /* which stream are we playing on? */ |
| 79 | |
| 80 | UINT8 m_output_bits; |
| 81 | |
| 82 | INT32 m_signal; |
| 83 | INT32 m_step; |
| 56 | 84 | }; |
| 57 | 85 | |
| 58 | 86 | extern const device_type OKIM6258; |
trunk/src/emu/sound/zsg2.c
| r21835 | r21836 | |
| 46 | 46 | #include "emu.h" |
| 47 | 47 | #include "zsg2.h" |
| 48 | 48 | |
| 49 | | // 16 registers per channel, 48 channels |
| 50 | | struct zchan |
| 51 | | { |
| 52 | | UINT16 v[16]; |
| 53 | | }; |
| 54 | 49 | |
| 55 | | struct zsg2_state |
| 50 | // device type definition |
| 51 | const device_type ZSG2 = &device_creator<zsg2_device>; |
| 52 | |
| 53 | |
| 54 | //************************************************************************** |
| 55 | // LIVE DEVICE |
| 56 | //************************************************************************** |
| 57 | |
| 58 | //------------------------------------------------- |
| 59 | // zsg2_device - constructor |
| 60 | //------------------------------------------------- |
| 61 | |
| 62 | zsg2_device::zsg2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 63 | : device_t(mconfig, ZSG2, "ZSG-2", tag, owner, clock), |
| 64 | device_sound_interface(mconfig, *this), |
| 65 | m_alow(0), |
| 66 | m_ahigh(0), |
| 67 | m_bank_samples(NULL), |
| 68 | m_sample_rate(0), |
| 69 | m_stream(NULL) |
| 56 | 70 | { |
| 57 | | zchan zc[48]; |
| 58 | | UINT16 act[3]; |
| 59 | | UINT16 alow, ahigh; |
| 60 | | UINT8 *bank_samples; |
| 71 | memset(m_act, 0, sizeof(UINT16)*3); |
| 72 | } |
| 61 | 73 | |
| 62 | | int sample_rate; |
| 63 | | sound_stream *stream; |
| 64 | | }; |
| 65 | 74 | |
| 66 | | INLINE zsg2_state *get_safe_token(device_t *device) |
| 75 | //------------------------------------------------- |
| 76 | // device_start - device-specific startup |
| 77 | //------------------------------------------------- |
| 78 | |
| 79 | void zsg2_device::device_start() |
| 67 | 80 | { |
| 68 | | assert(device != NULL); |
| 69 | | assert(device->type() == ZSG2); |
| 70 | | return (zsg2_state *)downcast<zsg2_device *>(device)->token(); |
| 81 | const zsg2_interface *intf = (const zsg2_interface *)static_config(); |
| 82 | |
| 83 | m_sample_rate = clock(); |
| 84 | |
| 85 | memset(&m_zc, 0, sizeof(m_zc)); |
| 86 | memset(&m_act, 0, sizeof(m_act)); |
| 87 | |
| 88 | m_stream = stream_alloc(0, 2, m_sample_rate); |
| 89 | |
| 90 | m_bank_samples = memregion(intf->samplergn)->base(); |
| 71 | 91 | } |
| 72 | 92 | |
| 73 | | static STREAM_UPDATE( update_stereo ) |
| 93 | |
| 94 | //------------------------------------------------- |
| 95 | // sound_stream_update - handle a stream update |
| 96 | //------------------------------------------------- |
| 97 | |
| 98 | void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 74 | 99 | { |
| 75 | | // zsg2_state *info = (zsg2_state *)param; |
| 76 | 100 | stream_sample_t *dest1 = outputs[0]; |
| 77 | 101 | stream_sample_t *dest2 = outputs[1]; |
| 78 | 102 | |
| r21835 | r21836 | |
| 80 | 104 | memset(dest2, 0, sizeof(stream_sample_t) * samples); |
| 81 | 105 | } |
| 82 | 106 | |
| 83 | | static void chan_w(zsg2_state *info, int chan, int reg, UINT16 data) |
| 107 | |
| 108 | |
| 109 | void zsg2_device::chan_w(int chan, int reg, UINT16 data) |
| 84 | 110 | { |
| 85 | | info->zc[chan].v[reg] = data; |
| 111 | m_zc[chan].v[reg] = data; |
| 86 | 112 | // log_event("ZOOMCHAN", "chan %02x reg %x = %04x", chan, reg, data); |
| 87 | 113 | } |
| 88 | 114 | |
| 89 | | static UINT16 chan_r(zsg2_state *info, int chan, int reg) |
| 115 | UINT16 zsg2_device::chan_r(int chan, int reg) |
| 90 | 116 | { |
| 91 | 117 | // log_event("ZOOMCHAN", "chan %02x read reg %x: %04x", chan, reg, zc[chan].v[reg]); |
| 92 | | return info->zc[chan].v[reg]; |
| 118 | return m_zc[chan].v[reg]; |
| 93 | 119 | } |
| 94 | 120 | |
| 95 | | static void check_channel(zsg2_state *info, int chan) |
| 121 | void zsg2_device::check_channel(int chan) |
| 96 | 122 | { |
| 97 | 123 | // log_event("ZOOM", "chan %02x e=%04x f=%04x", chan, zc[chan].v[14], zc[chan].v[15]); |
| 98 | 124 | } |
| 99 | 125 | |
| 100 | | static void keyon(zsg2_state *info, int chan) |
| 126 | void zsg2_device::keyon(int chan) |
| 101 | 127 | { |
| 102 | 128 | #if 0 |
| 103 | 129 | log_event("ZOOM", "keyon %02x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x %04x", |
| 104 | 130 | chan, |
| 105 | | info->zc[chan].v[0x0], info->zc[chan].v[0x1], info->zc[chan].v[0x2], info->zc[chan].v[0x3], |
| 106 | | info->zc[chan].v[0x4], info->zc[chan].v[0x5], info->zc[chan].v[0x6], info->zc[chan].v[0x7], |
| 107 | | info->zc[chan].v[0x8], info->zc[chan].v[0x9], info->zc[chan].v[0xa], info->zc[chan].v[0xb], |
| 108 | | info->zc[chan].v[0xc], info->zc[chan].v[0xd], info->zc[chan].v[0xe], info->zc[chan].v[0xf]); |
| 131 | m_zc[chan].v[0x0], m_zc[chan].v[0x1], m_zc[chan].v[0x2], m_zc[chan].v[0x3], |
| 132 | m_zc[chan].v[0x4], m_zc[chan].v[0x5], m_zc[chan].v[0x6], m_zc[chan].v[0x7], |
| 133 | m_zc[chan].v[0x8], m_zc[chan].v[0x9], m_zc[chan].v[0xa], m_zc[chan].v[0xb], |
| 134 | m_zc[chan].v[0xc], m_zc[chan].v[0xd], m_zc[chan].v[0xe], m_zc[chan].v[0xf]); |
| 109 | 135 | #endif |
| 110 | 136 | } |
| 111 | 137 | |
| 112 | | static void control_w(zsg2_state *info, int reg, UINT16 data) |
| 138 | void zsg2_device::control_w(int reg, UINT16 data) |
| 113 | 139 | { |
| 114 | 140 | switch(reg) |
| 115 | 141 | { |
| r21835 | r21836 | |
| 119 | 145 | int i; |
| 120 | 146 | for(i=0; i<16; i++) |
| 121 | 147 | if(data & (1<<i)) |
| 122 | | keyon(info, base+i); |
| 148 | keyon(base+i); |
| 123 | 149 | break; |
| 124 | 150 | } |
| 125 | 151 | |
| r21835 | r21836 | |
| 129 | 155 | int i; |
| 130 | 156 | for(i=0; i<16; i++) |
| 131 | 157 | if(data & (1<<i)) |
| 132 | | check_channel(info, base+i); |
| 158 | check_channel(base+i); |
| 133 | 159 | break; |
| 134 | 160 | } |
| 135 | 161 | |
| r21835 | r21836 | |
| 137 | 163 | break; |
| 138 | 164 | |
| 139 | 165 | case 0x38: |
| 140 | | info->alow = data; |
| 166 | m_alow = data; |
| 141 | 167 | break; |
| 142 | 168 | |
| 143 | 169 | case 0x3a: |
| 144 | | info->ahigh = data; |
| 170 | m_ahigh = data; |
| 145 | 171 | break; |
| 146 | 172 | |
| 147 | 173 | default: |
| r21835 | r21836 | |
| 150 | 176 | } |
| 151 | 177 | } |
| 152 | 178 | |
| 153 | | static UINT16 control_r(zsg2_state *info, int reg) |
| 179 | UINT16 zsg2_device::control_r(int reg) |
| 154 | 180 | { |
| 155 | 181 | switch(reg) |
| 156 | 182 | { |
| r21835 | r21836 | |
| 159 | 185 | |
| 160 | 186 | case 0x3c: case 0x3e: |
| 161 | 187 | { |
| 162 | | UINT32 adr = (info->ahigh << 16) | info->alow; |
| 163 | | UINT32 val = *(unsigned int *)(info->bank_samples+adr); |
| 188 | UINT32 adr = (m_ahigh << 16) | m_alow; |
| 189 | UINT32 val = *(unsigned int *)(m_bank_samples+adr); |
| 164 | 190 | // log_event("ZOOMCTRL", "rom read.%c %06x = %08x", reg == 0x3e ? 'h' : 'l', adr, val); |
| 165 | 191 | return (reg == 0x3e) ? (val >> 16) : val; |
| 166 | 192 | } |
| r21835 | r21836 | |
| 171 | 197 | return 0xffff; |
| 172 | 198 | } |
| 173 | 199 | |
| 174 | | WRITE16_DEVICE_HANDLER( zsg2_w ) |
| 200 | |
| 201 | WRITE16_MEMBER( zsg2_device::zsg2_w ) |
| 175 | 202 | { |
| 176 | | zsg2_state *info = get_safe_token(device); |
| 177 | 203 | int adr = offset * 2; |
| 178 | 204 | |
| 179 | 205 | assert(mem_mask == 0xffff); // we only support full 16-bit accesses |
| 180 | 206 | |
| 181 | | info->stream->update(); |
| 207 | m_stream->update(); |
| 182 | 208 | |
| 183 | 209 | if (adr < 0x600) |
| 184 | 210 | { |
| 185 | 211 | int chan = adr >> 5; |
| 186 | 212 | int reg = (adr >> 1) & 15; |
| 187 | 213 | |
| 188 | | chan_w(info, chan, reg, data); |
| 214 | chan_w(chan, reg, data); |
| 189 | 215 | } |
| 190 | 216 | else |
| 191 | 217 | { |
| 192 | | control_w(info, adr - 0x600, data); |
| 218 | control_w(adr - 0x600, data); |
| 193 | 219 | } |
| 194 | 220 | } |
| 195 | 221 | |
| 196 | | READ16_DEVICE_HANDLER( zsg2_r ) |
| 222 | |
| 223 | READ16_MEMBER( zsg2_device::zsg2_r ) |
| 197 | 224 | { |
| 198 | | zsg2_state *info = get_safe_token(device); |
| 199 | 225 | int adr = offset * 2; |
| 200 | 226 | |
| 201 | 227 | assert(mem_mask == 0xffff); // we only support full 16-bit accesses |
| r21835 | r21836 | |
| 204 | 230 | { |
| 205 | 231 | int chan = adr >> 5; |
| 206 | 232 | int reg = (adr >> 1) & 15; |
| 207 | | return chan_r(info, chan, reg); |
| 233 | return chan_r(chan, reg); |
| 208 | 234 | } |
| 209 | 235 | else |
| 210 | 236 | { |
| 211 | | return control_r(info, adr - 0x600); |
| 237 | return control_r(adr - 0x600); |
| 212 | 238 | } |
| 213 | 239 | |
| 214 | 240 | return 0; |
| 215 | 241 | } |
| 216 | 242 | |
| 217 | | static DEVICE_START( zsg2 ) |
| 218 | | { |
| 219 | | const zsg2_interface *intf = (const zsg2_interface *)device->static_config(); |
| 220 | | zsg2_state *info = get_safe_token(device); |
| 221 | | |
| 222 | | info->sample_rate = device->clock(); |
| 223 | | |
| 224 | | memset(&info->zc, 0, sizeof(info->zc)); |
| 225 | | memset(&info->act, 0, sizeof(info->act)); |
| 226 | | |
| 227 | | info->stream = device->machine().sound().stream_alloc(*device, 0, 2, info->sample_rate, info, update_stereo); |
| 228 | | |
| 229 | | info->bank_samples = device->machine().root_device().memregion(intf->samplergn)->base(); |
| 230 | | } |
| 231 | | |
| 232 | | const device_type ZSG2 = &device_creator<zsg2_device>; |
| 233 | | |
| 234 | | zsg2_device::zsg2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 235 | | : device_t(mconfig, ZSG2, "ZSG-2", tag, owner, clock), |
| 236 | | device_sound_interface(mconfig, *this) |
| 237 | | { |
| 238 | | m_token = global_alloc_clear(zsg2_state); |
| 239 | | } |
| 240 | | |
| 241 | | //------------------------------------------------- |
| 242 | | // device_config_complete - perform any |
| 243 | | // operations now that the configuration is |
| 244 | | // complete |
| 245 | | //------------------------------------------------- |
| 246 | | |
| 247 | | void zsg2_device::device_config_complete() |
| 248 | | { |
| 249 | | } |
| 250 | | |
| 251 | | //------------------------------------------------- |
| 252 | | // device_start - device-specific startup |
| 253 | | //------------------------------------------------- |
| 254 | | |
| 255 | | void zsg2_device::device_start() |
| 256 | | { |
| 257 | | DEVICE_START_NAME( zsg2 )(this); |
| 258 | | } |
| 259 | | |
| 260 | | //------------------------------------------------- |
| 261 | | // sound_stream_update - handle a stream update |
| 262 | | //------------------------------------------------- |
| 263 | | |
| 264 | | void zsg2_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 265 | | { |
| 266 | | // should never get here |
| 267 | | fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); |
| 268 | | } |
trunk/src/mess/drivers/x68k.c
| r21835 | r21836 | |
| 902 | 902 | WRITE8_MEMBER(x68k_state::ppi_port_c_w) |
| 903 | 903 | { |
| 904 | 904 | // ADPCM / Joystick control |
| 905 | | device_t *oki = machine().device("okim6258"); |
| 905 | okim6258_device *oki = machine().device<okim6258_device>("okim6258"); |
| 906 | 906 | |
| 907 | 907 | m_ppi_port[2] = data; |
| 908 | 908 | if((data & 0x0f) != (m_ppi_prev & 0x0f)) |
| r21835 | r21836 | |
| 910 | 910 | m_adpcm.pan = data & 0x03; |
| 911 | 911 | m_adpcm.rate = data & 0x0c; |
| 912 | 912 | x68k_set_adpcm(); |
| 913 | | okim6258_set_divider(oki, (data >> 2) & 3); |
| 913 | oki->set_divider((data >> 2) & 3); |
| 914 | 914 | } |
| 915 | 915 | |
| 916 | 916 | // The joystick enable bits also handle the multiplexer for various controllers |
| r21835 | r21836 | |
| 1077 | 1077 | |
| 1078 | 1078 | WRITE8_MEMBER(x68k_state::x68k_ct_w) |
| 1079 | 1079 | { |
| 1080 | | device_t *okim = space.machine().device("okim6258"); |
| 1080 | okim6258_device *okim = space.machine().device<okim6258_device>("okim6258"); |
| 1081 | 1081 | |
| 1082 | 1082 | // CT1 and CT2 bits from YM2151 port 0x1b |
| 1083 | 1083 | // CT1 - ADPCM clock - 0 = 8MHz, 1 = 4MHz |
| r21835 | r21836 | |
| 1085 | 1085 | m_fdc.fdc->ready_w(data & 0x01); |
| 1086 | 1086 | m_adpcm.clock = data & 0x02; |
| 1087 | 1087 | x68k_set_adpcm(); |
| 1088 | | okim6258_set_clock(okim, data & 0x02 ? 4000000 : 8000000); |
| 1088 | okim->set_clock(data & 0x02 ? 4000000 : 8000000); |
| 1089 | 1089 | } |
| 1090 | 1090 | |
| 1091 | 1091 | /* |
| r21835 | r21836 | |
| 1776 | 1776 | |
| 1777 | 1777 | WRITE8_MEMBER(x68k_state::x68030_adpcm_w) |
| 1778 | 1778 | { |
| 1779 | | device_t *device = machine().device("okim6258"); |
| 1779 | okim6258_device *device = machine().device<okim6258_device>("okim6258"); |
| 1780 | 1780 | switch(offset) |
| 1781 | 1781 | { |
| 1782 | 1782 | case 0x00: |
| 1783 | | okim6258_ctrl_w(device,space,0,data); |
| 1783 | device->okim6258_ctrl_w(space,0,data); |
| 1784 | 1784 | break; |
| 1785 | 1785 | case 0x01: |
| 1786 | | okim6258_data_w(device,space,0,data); |
| 1786 | device->okim6258_data_w(space,0,data); |
| 1787 | 1787 | break; |
| 1788 | 1788 | } |
| 1789 | 1789 | } |
| r21835 | r21836 | |
| 1879 | 1879 | // AM_RANGE(0xe8c000, 0xe8dfff) AM_READWRITE(x68k_printer_r, x68k_printer_w) |
| 1880 | 1880 | AM_RANGE(0xe8e000, 0xe8ffff) AM_READWRITE(x68k_sysport_r, x68k_sysport_w) |
| 1881 | 1881 | AM_RANGE(0xe90000, 0xe91fff) AM_READWRITE(x68k_fm_r, x68k_fm_w) |
| 1882 | | AM_RANGE(0xe92000, 0xe92001) AM_DEVREADWRITE8_LEGACY("okim6258", okim6258_status_r, okim6258_ctrl_w, 0x00ff) |
| 1883 | | AM_RANGE(0xe92002, 0xe92003) AM_DEVREADWRITE8_LEGACY("okim6258", okim6258_status_r, okim6258_data_w, 0x00ff) |
| 1882 | AM_RANGE(0xe92000, 0xe92001) AM_DEVREADWRITE8("okim6258", okim6258_device, okim6258_status_r, okim6258_ctrl_w, 0x00ff) |
| 1883 | AM_RANGE(0xe92002, 0xe92003) AM_DEVREADWRITE8("okim6258", okim6258_device, okim6258_status_r, okim6258_data_w, 0x00ff) |
| 1884 | 1884 | AM_RANGE(0xe94000, 0xe94003) AM_DEVICE8("upd72065", upd72065_device, map, 0x00ff) |
| 1885 | 1885 | AM_RANGE(0xe94004, 0xe94007) AM_READWRITE(x68k_fdc_r, x68k_fdc_w) |
| 1886 | 1886 | AM_RANGE(0xe96000, 0xe9601f) AM_DEVREADWRITE("x68k_hdc", x68k_hdc_image_device, hdc_r, hdc_w) |
| r21835 | r21836 | |
| 1917 | 1917 | // AM_RANGE(0xe8c000, 0xe8dfff) AM_READWRITE(x68k_printer_r, x68k_printer_w) |
| 1918 | 1918 | AM_RANGE(0xe8e000, 0xe8ffff) AM_READWRITE(x68k_sysport_r, x68k_sysport_w) |
| 1919 | 1919 | AM_RANGE(0xe90000, 0xe91fff) AM_READWRITE(x68k_fm_r, x68k_fm_w) |
| 1920 | | AM_RANGE(0xe92000, 0xe92001) AM_DEVREADWRITE8_LEGACY("okim6258", okim6258_status_r, okim6258_ctrl_w, 0x00ff) |
| 1921 | | AM_RANGE(0xe92002, 0xe92003) AM_DEVREADWRITE8_LEGACY("okim6258", okim6258_status_r, okim6258_data_w, 0x00ff) |
| 1920 | AM_RANGE(0xe92000, 0xe92001) AM_DEVREADWRITE8("okim6258", okim6258_device, okim6258_status_r, okim6258_ctrl_w, 0x00ff) |
| 1921 | AM_RANGE(0xe92002, 0xe92003) AM_DEVREADWRITE8("okim6258", okim6258_device, okim6258_status_r, okim6258_data_w, 0x00ff) |
| 1922 | 1922 | AM_RANGE(0xe94000, 0xe94003) AM_DEVICE8("upd72065", upd72065_device, map, 0x00ff) |
| 1923 | 1923 | AM_RANGE(0xe94004, 0xe94007) AM_READWRITE(x68k_fdc_r, x68k_fdc_w) |
| 1924 | 1924 | // AM_RANGE(0xe96000, 0xe9601f) AM_DEVREADWRITE_LEGACY("x68k_hdc",x68k_hdc_r, x68k_hdc_w) |
| r21835 | r21836 | |
| 1957 | 1957 | // AM_RANGE(0xe8c000, 0xe8dfff) AM_READWRITE(x68k_printer_r, x68k_printer_w) |
| 1958 | 1958 | AM_RANGE(0xe8e000, 0xe8ffff) AM_READWRITE16(x68k_sysport_r, x68k_sysport_w,0xffffffff) |
| 1959 | 1959 | AM_RANGE(0xe90000, 0xe91fff) AM_READWRITE16(x68k_fm_r, x68k_fm_w,0xffffffff) |
| 1960 | | AM_RANGE(0xe92000, 0xe92003) AM_DEVREAD8_LEGACY("okim6258", okim6258_status_r, 0x00ff00ff) AM_WRITE8(x68030_adpcm_w, 0x00ff00ff) |
| 1960 | AM_RANGE(0xe92000, 0xe92003) AM_DEVREAD8("okim6258", okim6258_device, okim6258_status_r, 0x00ff00ff) AM_WRITE8(x68030_adpcm_w, 0x00ff00ff) |
| 1961 | 1961 | AM_RANGE(0xe94000, 0xe94003) AM_DEVICE8("upd72065", upd72065_device, map, 0x00ff00ff) |
| 1962 | 1962 | AM_RANGE(0xe94004, 0xe94007) AM_READWRITE16(x68k_fdc_r, x68k_fdc_w,0xffffffff) |
| 1963 | 1963 | // AM_RANGE(0xe96000, 0xe9601f) AM_DEVREADWRITE16_LEGACY("x68k_hdc",x68k_hdc_r, x68k_hdc_w,0xffffffff) |
| r21835 | r21836 | |
| 2671 | 2671 | MCFG_YM2151_PORT_WRITE_HANDLER(WRITE8(x68k_state,x68k_ct_w)) // CT1, CT2 from YM2151 port 0x1b |
| 2672 | 2672 | MCFG_SOUND_ROUTE(0, "lspeaker", 0.50) |
| 2673 | 2673 | MCFG_SOUND_ROUTE(1, "rspeaker", 0.50) |
| 2674 | | MCFG_SOUND_ADD("okim6258", OKIM6258, 4000000) |
| 2674 | MCFG_OKIM6258_ADD("okim6258", 4000000) |
| 2675 | 2675 | MCFG_SOUND_CONFIG(x68k_okim6258_interface) |
| 2676 | 2676 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.50) |
| 2677 | 2677 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.50) |
trunk/src/mess/video/crt.c
| r21835 | r21836 | |
| 26 | 26 | */ |
| 27 | 27 | |
| 28 | 28 | #include <math.h> |
| 29 | | |
| 30 | 29 | #include "emu.h" |
| 31 | | |
| 32 | 30 | #include "video/crt.h" |
| 33 | 31 | |
| 34 | 32 | |
| 35 | | struct point |
| 36 | | { |
| 37 | | int intensity; /* current intensity of the pixel */ |
| 38 | | /* a node is not in the list when (intensity == -1) */ |
| 39 | | int next; /* index of next pixel in list */ |
| 40 | | }; |
| 41 | | |
| 33 | // special value that tells that the node is not in list |
| 42 | 34 | enum |
| 43 | 35 | { |
| 44 | | intensity_pixel_not_in_list = -1 /* special value that tells that the node is not in list */ |
| 36 | intensity_pixel_not_in_list = -1 |
| 45 | 37 | }; |
| 46 | 38 | |
| 47 | | struct crt_t |
| 48 | | { |
| 49 | | point *list; /* array of (crt_window_width*crt_window_height) point */ |
| 50 | | int *list_head; /* head of the list of lit pixels (index in the array) */ |
| 51 | | /* keep a separate list for each display line (makes the video code slightly faster) */ |
| 52 | 39 | |
| 53 | | int decay_counter; /* incremented each frame (tells for how many frames the CRT has decayed between two screen refresh) */ |
| 40 | // device type definition |
| 41 | const device_type CRT = &device_creator<crt_device>; |
| 54 | 42 | |
| 55 | | /* CRT window */ |
| 56 | | int num_intensity_levels; |
| 57 | | int window_offset_x, window_offset_y; |
| 58 | | int window_width, window_height; |
| 59 | | }; |
| 43 | //************************************************************************** |
| 44 | // LIVE DEVICE |
| 45 | //************************************************************************** |
| 60 | 46 | |
| 47 | //------------------------------------------------- |
| 48 | // crt_device - constructor |
| 49 | //------------------------------------------------- |
| 61 | 50 | |
| 62 | | INLINE crt_t *get_safe_token(device_t *device) |
| 51 | crt_device::crt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 52 | : device_t(mconfig, CRT, "CRT Video", tag, owner, clock), |
| 53 | m_list(NULL), |
| 54 | m_list_head(NULL), |
| 55 | m_decay_counter(0), |
| 56 | m_num_intensity_levels(0), |
| 57 | m_window_offset_x(0), |
| 58 | m_window_offset_y(0), |
| 59 | m_window_width(0), |
| 60 | m_window_height(0) |
| 63 | 61 | { |
| 64 | | assert(device != NULL); |
| 65 | | assert(device->type() == CRT); |
| 66 | | |
| 67 | | return (crt_t *)downcast<crt_device *>(device)->token(); |
| 68 | 62 | } |
| 69 | 63 | |
| 70 | | static DEVICE_START( crt ) |
| 64 | |
| 65 | //------------------------------------------------- |
| 66 | // device_start - device-specific startup |
| 67 | //------------------------------------------------- |
| 68 | |
| 69 | void crt_device::device_start() |
| 71 | 70 | { |
| 72 | | crt_t *crt = get_safe_token(device); |
| 73 | | const crt_interface *intf = (const crt_interface *)device->static_config(); |
| 71 | const crt_interface *intf = (const crt_interface *)static_config(); |
| 74 | 72 | int width = intf->width; |
| 75 | 73 | int height = intf->height; |
| 76 | 74 | int i; |
| 77 | 75 | |
| 78 | | crt->num_intensity_levels = intf->num_levels; |
| 79 | | crt->window_offset_x = intf->offset_x; |
| 80 | | crt->window_offset_y = intf->offset_y; |
| 81 | | crt->window_width = width; |
| 82 | | crt->window_height = height; |
| 76 | m_num_intensity_levels = intf->num_levels; |
| 77 | m_window_offset_x = intf->offset_x; |
| 78 | m_window_offset_y = intf->offset_y; |
| 79 | m_window_width = width; |
| 80 | m_window_height = height; |
| 83 | 81 | |
| 84 | 82 | /* alloc the arrays */ |
| 85 | | crt->list = auto_alloc_array(device->machine(), point, width * height); |
| 83 | m_list = auto_alloc_array(machine(), crt_point, width * height); |
| 86 | 84 | |
| 87 | | crt->list_head = auto_alloc_array(device->machine(), int, height); |
| 85 | m_list_head = auto_alloc_array(machine(), int, height); |
| 88 | 86 | |
| 89 | 87 | /* fill with black and set up list as empty */ |
| 90 | 88 | for (i=0; i<(width * height); i++) |
| 91 | 89 | { |
| 92 | | crt->list[i].intensity = intensity_pixel_not_in_list; |
| 90 | m_list[i].intensity = intensity_pixel_not_in_list; |
| 93 | 91 | } |
| 94 | 92 | |
| 95 | 93 | for (i=0; i<height; i++) |
| 96 | | crt->list_head[i] = -1; |
| 94 | m_list_head[i] = -1; |
| 97 | 95 | |
| 98 | | crt->decay_counter = 0; |
| 96 | m_decay_counter = 0; |
| 99 | 97 | } |
| 100 | 98 | |
| 101 | 99 | |
| 102 | | const device_type CRT = &device_creator<crt_device>; |
| 103 | | |
| 104 | | crt_device::crt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 105 | | : device_t(mconfig, CRT, "CRT Video", tag, owner, clock) |
| 100 | // |
| 101 | // crt_plot |
| 102 | // |
| 103 | // schedule a pixel to be plotted |
| 104 | // |
| 105 | void crt_device::plot(int x, int y) |
| 106 | 106 | { |
| 107 | | m_token = global_alloc_clear(crt_t); |
| 108 | | } |
| 109 | | |
| 110 | | //------------------------------------------------- |
| 111 | | // device_config_complete - perform any |
| 112 | | // operations now that the configuration is |
| 113 | | // complete |
| 114 | | //------------------------------------------------- |
| 115 | | |
| 116 | | void crt_device::device_config_complete() |
| 117 | | { |
| 118 | | } |
| 119 | | |
| 120 | | //------------------------------------------------- |
| 121 | | // device_start - device-specific startup |
| 122 | | //------------------------------------------------- |
| 123 | | |
| 124 | | void crt_device::device_start() |
| 125 | | { |
| 126 | | DEVICE_START_NAME( crt )(this); |
| 127 | | } |
| 128 | | |
| 129 | | |
| 130 | | |
| 131 | | /* |
| 132 | | crt_plot |
| 133 | | |
| 134 | | schedule a pixel to be plotted |
| 135 | | */ |
| 136 | | void crt_plot(device_t *device, int x, int y) |
| 137 | | { |
| 138 | | crt_t *crt = get_safe_token(device); |
| 139 | | point *node; |
| 107 | crt_point *node; |
| 140 | 108 | int list_index; |
| 141 | 109 | |
| 142 | 110 | /* compute pixel coordinates */ |
| 143 | 111 | if (x<0) x=0; |
| 144 | 112 | if (y<0) y=0; |
| 145 | | if ((x>(crt->window_width-1)) || ((y>crt->window_height-1))) |
| 113 | if ((x>(m_window_width-1)) || ((y>m_window_height-1))) |
| 146 | 114 | return; |
| 147 | | y = (crt->window_height-1) - y; |
| 115 | y = (m_window_height-1) - y; |
| 148 | 116 | |
| 149 | 117 | /* find entry in list */ |
| 150 | | list_index = x + y*crt->window_width; |
| 118 | list_index = x + y*m_window_width; |
| 151 | 119 | |
| 152 | | node = &crt->list[list_index]; |
| 120 | node = &m_list[list_index]; |
| 153 | 121 | |
| 154 | 122 | if (node->intensity == intensity_pixel_not_in_list) |
| 155 | 123 | { /* insert node in list if it is not in it */ |
| 156 | | node->next = crt->list_head[y]; |
| 157 | | crt->list_head[y] = list_index; |
| 124 | node->next = m_list_head[y]; |
| 125 | m_list_head[y] = list_index; |
| 158 | 126 | } |
| 159 | 127 | /* set intensity */ |
| 160 | | node->intensity = crt->num_intensity_levels; |
| 128 | node->intensity = m_num_intensity_levels; |
| 161 | 129 | } |
| 162 | 130 | |
| 163 | 131 | |
| 164 | | /* |
| 165 | | crt_eof |
| 166 | | |
| 167 | | keep track of time |
| 168 | | */ |
| 169 | | void crt_eof(device_t *device) |
| 132 | // |
| 133 | // crt_eof |
| 134 | // |
| 135 | // keep track of time |
| 136 | // |
| 137 | void crt_device::eof() |
| 170 | 138 | { |
| 171 | | crt_t *crt = get_safe_token(device); |
| 172 | | crt->decay_counter++; |
| 139 | m_decay_counter++; |
| 173 | 140 | } |
| 174 | 141 | |
| 175 | 142 | |
| 176 | | /* |
| 177 | | crt_update |
| 178 | | |
| 179 | | update the bitmap |
| 180 | | */ |
| 181 | | void crt_update(device_t *device, bitmap_ind16 &bitmap) |
| 143 | // |
| 144 | // crt_update |
| 145 | // |
| 146 | // update the bitmap |
| 147 | // |
| 148 | void crt_device::update(bitmap_ind16 &bitmap) |
| 182 | 149 | { |
| 183 | | crt_t *crt = get_safe_token(device); |
| 184 | 150 | int i, p_i; |
| 185 | 151 | int y; |
| 186 | 152 | |
| 187 | | //if (crt->decay_counter) |
| 153 | //if (m_decay_counter) |
| 188 | 154 | { |
| 189 | 155 | /* some time has elapsed: let's update the screen */ |
| 190 | | for (y=0; y<crt->window_height; y++) |
| 156 | for (y=0; y<m_window_height; y++) |
| 191 | 157 | { |
| 192 | | UINT16 *line = &bitmap.pix16(y+crt->window_offset_y); |
| 158 | UINT16 *line = &bitmap.pix16(y+m_window_offset_y); |
| 193 | 159 | |
| 194 | 160 | p_i = -1; |
| 195 | 161 | |
| 196 | | for (i=crt->list_head[y]; (i != -1); i=crt->list[i].next) |
| 162 | for (i=m_list_head[y]; (i != -1); i=m_list[i].next) |
| 197 | 163 | { |
| 198 | | point *node = &crt->list[i]; |
| 199 | | int x = (i % crt->window_width) + crt->window_offset_x; |
| 164 | crt_point *node = &m_list[i]; |
| 165 | int x = (i % m_window_width) + m_window_offset_x; |
| 200 | 166 | |
| 201 | | if (node->intensity == crt->num_intensity_levels) |
| 167 | if (node->intensity == m_num_intensity_levels) |
| 202 | 168 | /* new pixel: set to max intensity */ |
| 203 | | node->intensity = crt->num_intensity_levels-1; |
| 169 | node->intensity = m_num_intensity_levels-1; |
| 204 | 170 | else |
| 205 | 171 | { |
| 206 | 172 | /* otherwise, apply intensity decay */ |
| 207 | | node->intensity -= crt->decay_counter; |
| 173 | node->intensity -= m_decay_counter; |
| 208 | 174 | if (node->intensity < 0) |
| 209 | 175 | node->intensity = 0; |
| 210 | 176 | } |
| 211 | 177 | |
| 212 | 178 | /* draw pixel on screen */ |
| 213 | | //plot_pixel(bitmap, x, y+crt->window_offset_y, node->intensity); |
| 179 | //plot_pixel(bitmap, x, y+m_window_offset_y, node->intensity); |
| 214 | 180 | line[x] = node->intensity; |
| 215 | 181 | |
| 216 | 182 | if (node->intensity != 0) |
| r21835 | r21836 | |
| 219 | 185 | { /* delete current node */ |
| 220 | 186 | node->intensity = intensity_pixel_not_in_list; |
| 221 | 187 | if (p_i != -1) |
| 222 | | crt->list[p_i].next = node->next; |
| 188 | m_list[p_i].next = node->next; |
| 223 | 189 | else |
| 224 | | crt->list_head[y] = node->next; |
| 190 | m_list_head[y] = node->next; |
| 225 | 191 | } |
| 226 | 192 | } |
| 227 | 193 | } |
| 228 | 194 | |
| 229 | | crt->decay_counter = 0; |
| 195 | m_decay_counter = 0; |
| 230 | 196 | } |
| 231 | 197 | } |