src/mess/machine/6530miot.c
| r7586 | r7587 | |
| 1 | | /*************************************************************************** |
| 2 | | |
| 3 | | MIOT 6530 emulation |
| 4 | | |
| 5 | | The timer seems to follow these rules: |
| 6 | | - When the timer flag changes from 0 to 1 the timer continues to count |
| 7 | | down at a 1 cycle rate. |
| 8 | | - When the timer is being read or written the timer flag is reset. |
| 9 | | - When the timer flag is set and the timer contents are 0, the counting |
| 10 | | stops. |
| 11 | | |
| 12 | | From the operation of the KIM1 it expects the irqflag to be set whenever |
| 13 | | the unit is reset. This is something that is not clear from the datasheet |
| 14 | | and should be verified against real hardware. |
| 15 | | |
| 16 | | ***************************************************************************/ |
| 17 | | |
| 18 | | #include "emu.h" |
| 19 | | #include "6530miot.h" |
| 20 | | |
| 21 | | |
| 22 | | /*************************************************************************** |
| 23 | | CONSTANTS |
| 24 | | ***************************************************************************/ |
| 25 | | |
| 26 | | enum |
| 27 | | { |
| 28 | | TIMER_IDLE, |
| 29 | | TIMER_COUNTING, |
| 30 | | TIMER_FINISHING |
| 31 | | }; |
| 32 | | |
| 33 | | #define TIMER_FLAG 0x80 |
| 34 | | |
| 35 | | |
| 36 | | |
| 37 | | /*************************************************************************** |
| 38 | | TYPE DEFINITIONS |
| 39 | | ***************************************************************************/ |
| 40 | | |
| 41 | | typedef struct _miot6530_port miot6530_port; |
| 42 | | struct _miot6530_port |
| 43 | | { |
| 44 | | UINT8 in; |
| 45 | | UINT8 out; |
| 46 | | UINT8 ddr; |
| 47 | | miot_read_func in_func; |
| 48 | | miot_write_func out_func; |
| 49 | | }; |
| 50 | | |
| 51 | | |
| 52 | | typedef struct _miot6530_state miot6530_state; |
| 53 | | struct _miot6530_state |
| 54 | | { |
| 55 | | const miot6530_interface *intf; |
| 56 | | |
| 57 | | miot6530_port port[2]; |
| 58 | | |
| 59 | | UINT8 irqstate; |
| 60 | | UINT8 irqenable; |
| 61 | | |
| 62 | | UINT8 timershift; |
| 63 | | UINT8 timerstate; |
| 64 | | emu_timer * timer; |
| 65 | | |
| 66 | | UINT32 clock; |
| 67 | | }; |
| 68 | | |
| 69 | | |
| 70 | | |
| 71 | | /*************************************************************************** |
| 72 | | INLINE FUNCTIONS |
| 73 | | ***************************************************************************/ |
| 74 | | |
| 75 | | /*------------------------------------------------- |
| 76 | | get_safe_token - convert a device's token |
| 77 | | into a miot6530_state |
| 78 | | -------------------------------------------------*/ |
| 79 | | |
| 80 | | INLINE miot6530_state *get_safe_token(running_device *device) |
| 81 | | { |
| 82 | | assert(device != NULL); |
| 83 | | assert(device->token != NULL); |
| 84 | | assert(device->type == MIOT6530); |
| 85 | | return (miot6530_state *)device->token; |
| 86 | | } |
| 87 | | |
| 88 | | |
| 89 | | /*------------------------------------------------- |
| 90 | | update_irqstate - update the IRQ state |
| 91 | | based on interrupt enables |
| 92 | | -------------------------------------------------*/ |
| 93 | | |
| 94 | | INLINE void update_irqstate(running_device *device) |
| 95 | | { |
| 96 | | miot6530_state *miot = get_safe_token(device); |
| 97 | | UINT8 out = miot->port[1].out; |
| 98 | | |
| 99 | | if ( miot->irqenable ) |
| 100 | | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); |
| 101 | | |
| 102 | | if (miot->port[1].out_func != NULL) |
| 103 | | (*miot->port[1].out_func)(device, out, out); |
| 104 | | else |
| 105 | | logerror("6530MIOT chip %s: Port B is being written to but has no handler.\n", device->tag()); |
| 106 | | } |
| 107 | | |
| 108 | | |
| 109 | | /*------------------------------------------------- |
| 110 | | get_timer - return the current timer value |
| 111 | | -------------------------------------------------*/ |
| 112 | | |
| 113 | | INLINE UINT8 get_timer(miot6530_state *miot) |
| 114 | | { |
| 115 | | /* if idle, return 0 */ |
| 116 | | if (miot->timerstate == TIMER_IDLE) |
| 117 | | return 0; |
| 118 | | |
| 119 | | /* if counting, return the number of ticks remaining */ |
| 120 | | else if (miot->timerstate == TIMER_COUNTING) |
| 121 | | return attotime_to_ticks(timer_timeleft(miot->timer), miot->clock) >> miot->timershift; |
| 122 | | |
| 123 | | /* if finishing, return the number of ticks without the shift */ |
| 124 | | else |
| 125 | | return attotime_to_ticks(timer_timeleft(miot->timer), miot->clock); |
| 126 | | } |
| 127 | | |
| 128 | | |
| 129 | | /*************************************************************************** |
| 130 | | INTERNAL FUNCTIONS |
| 131 | | ***************************************************************************/ |
| 132 | | |
| 133 | | /*------------------------------------------------- |
| 134 | | timer_end_callback - callback to process the |
| 135 | | timer |
| 136 | | -------------------------------------------------*/ |
| 137 | | |
| 138 | | static TIMER_CALLBACK( timer_end_callback ) |
| 139 | | { |
| 140 | | running_device *device = (running_device *)ptr; |
| 141 | | miot6530_state *miot = get_safe_token(device); |
| 142 | | |
| 143 | | assert(miot->timerstate != TIMER_IDLE); |
| 144 | | |
| 145 | | /* if we finished counting, switch to the finishing state */ |
| 146 | | if (miot->timerstate == TIMER_COUNTING) |
| 147 | | { |
| 148 | | miot->timerstate = TIMER_FINISHING; |
| 149 | | timer_adjust_oneshot(miot->timer, ticks_to_attotime(256, miot->clock), 0); |
| 150 | | |
| 151 | | /* signal timer IRQ as well */ |
| 152 | | miot->irqstate |= TIMER_FLAG; |
| 153 | | update_irqstate(device); |
| 154 | | } |
| 155 | | |
| 156 | | /* if we finished finishing, switch to the idle state */ |
| 157 | | else if (miot->timerstate == TIMER_FINISHING) |
| 158 | | { |
| 159 | | miot->timerstate = TIMER_IDLE; |
| 160 | | timer_adjust_oneshot(miot->timer, attotime_never, 0); |
| 161 | | } |
| 162 | | } |
| 163 | | |
| 164 | | |
| 165 | | |
| 166 | | /*************************************************************************** |
| 167 | | I/O ACCESS |
| 168 | | ***************************************************************************/ |
| 169 | | |
| 170 | | /*------------------------------------------------- |
| 171 | | miot6530_w - master I/O write access |
| 172 | | -------------------------------------------------*/ |
| 173 | | |
| 174 | | WRITE8_DEVICE_HANDLER( miot6530_w ) |
| 175 | | { |
| 176 | | miot6530_state *miot = get_safe_token(device); |
| 177 | | |
| 178 | | /* if A2 == 1, we are writing to the timer */ |
| 179 | | if (offset & 0x04) |
| 180 | | { |
| 181 | | static const UINT8 timershift[4] = { 0, 3, 6, 10 }; |
| 182 | | attotime curtime = timer_get_time(device->machine); |
| 183 | | INT64 target; |
| 184 | | |
| 185 | | /* A0-A1 contain the timer divisor */ |
| 186 | | miot->timershift = timershift[offset & 3]; |
| 187 | | |
| 188 | | /* A3 contains the timer IRQ enable */ |
| 189 | | if (offset & 8) |
| 190 | | miot->irqenable |= TIMER_FLAG; |
| 191 | | else |
| 192 | | miot->irqenable &= ~TIMER_FLAG; |
| 193 | | |
| 194 | | /* writes here clear the timer flag */ |
| 195 | | if (miot->timerstate != TIMER_FINISHING || get_timer(miot) != 0xff) |
| 196 | | miot->irqstate &= ~TIMER_FLAG; |
| 197 | | update_irqstate(device); |
| 198 | | |
| 199 | | /* update the timer */ |
| 200 | | miot->timerstate = TIMER_COUNTING; |
| 201 | | target = attotime_to_ticks(curtime, miot->clock) + 1 + (data << miot->timershift); |
| 202 | | timer_adjust_oneshot(miot->timer, attotime_sub(ticks_to_attotime(target, miot->clock), curtime), 0); |
| 203 | | } |
| 204 | | |
| 205 | | /* if A2 == 0, we are writing to the I/O section */ |
| 206 | | else |
| 207 | | { |
| 208 | | /* A1 selects the port */ |
| 209 | | miot6530_port *port = &miot->port[(offset >> 1) & 1]; |
| 210 | | |
| 211 | | /* if A0 == 1, we are writing to the port's DDR */ |
| 212 | | if (offset & 1) |
| 213 | | port->ddr = data; |
| 214 | | |
| 215 | | /* if A0 == 0, we are writing to the port's output */ |
| 216 | | else |
| 217 | | { |
| 218 | | UINT8 olddata = port->out; |
| 219 | | port->out = data; |
| 220 | | |
| 221 | | if ( ( offset & 2 ) && miot->irqenable ) |
| 222 | | { |
| 223 | | olddata = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( olddata & 0x7F ); |
| 224 | | data = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( data & 0x7F ); |
| 225 | | } |
| 226 | | |
| 227 | | if (port->out_func != NULL) |
| 228 | | (*port->out_func)(device, data, olddata); |
| 229 | | else |
| 230 | | logerror("6530MIOT chip %s: Port %c is being written to but has no handler. PC: %08X - %02X\n", device->tag(), 'A' + (offset & 1), cpu_get_pc(device->machine->firstcpu), data); |
| 231 | | } |
| 232 | | } |
| 233 | | } |
| 234 | | |
| 235 | | |
| 236 | | /*------------------------------------------------- |
| 237 | | miot6530_r - master I/O read access |
| 238 | | -------------------------------------------------*/ |
| 239 | | |
| 240 | | READ8_DEVICE_HANDLER( miot6530_r ) |
| 241 | | { |
| 242 | | miot6530_state *miot = get_safe_token(device); |
| 243 | | UINT8 val = 0; |
| 244 | | |
| 245 | | /* if A2 == 1 and A0 == 1, we are reading interrupt flags */ |
| 246 | | if ((offset & 0x05) == 0x05) |
| 247 | | { |
| 248 | | val = miot->irqstate; |
| 249 | | } |
| 250 | | |
| 251 | | /* if A2 == 1 and A0 == 0, we are reading the timer */ |
| 252 | | else if ((offset & 0x05) == 0x04) |
| 253 | | { |
| 254 | | val = get_timer(miot); |
| 255 | | |
| 256 | | /* A3 contains the timer IRQ enable */ |
| 257 | | if (offset & 8) |
| 258 | | miot->irqenable |= TIMER_FLAG; |
| 259 | | else |
| 260 | | miot->irqenable &= ~TIMER_FLAG; |
| 261 | | |
| 262 | | /* implicitly clears the timer flag */ |
| 263 | | if (miot->timerstate != TIMER_FINISHING || val != 0xff) |
| 264 | | miot->irqstate &= ~TIMER_FLAG; |
| 265 | | update_irqstate(device); |
| 266 | | } |
| 267 | | |
| 268 | | /* if A2 == 0 and A0 == anything, we are reading from ports */ |
| 269 | | else |
| 270 | | { |
| 271 | | /* A1 selects the port */ |
| 272 | | miot6530_port *port = &miot->port[(offset >> 1) & 1]; |
| 273 | | |
| 274 | | /* if A0 == 1, we are reading the port's DDR */ |
| 275 | | if (offset & 1) |
| 276 | | val = port->ddr; |
| 277 | | |
| 278 | | /* if A0 == 0, we are reading the port as an input */ |
| 279 | | else |
| 280 | | { |
| 281 | | UINT8 out = port->out; |
| 282 | | |
| 283 | | if ( ( offset & 2 ) && miot->irqenable ) |
| 284 | | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); |
| 285 | | |
| 286 | | /* call the input callback if it exists */ |
| 287 | | if (port->in_func != NULL) |
| 288 | | { |
| 289 | | port->in = (*port->in_func)(device, port->in); |
| 290 | | } |
| 291 | | else |
| 292 | | logerror("6530MIOT chip %s: Port %c is being read but has no handler. PC: %08X\n", device->tag(), 'A' + (offset & 1), cpu_get_pc(device->machine->firstcpu)); |
| 293 | | |
| 294 | | /* apply the DDR to the result */ |
| 295 | | val = (out & port->ddr) | (port->in & ~port->ddr); |
| 296 | | } |
| 297 | | } |
| 298 | | return val; |
| 299 | | } |
| 300 | | |
| 301 | | |
| 302 | | /*------------------------------------------------- |
| 303 | | miot6530_porta_in_set - set port A input |
| 304 | | value |
| 305 | | -------------------------------------------------*/ |
| 306 | | |
| 307 | | void miot6530_porta_in_set(running_device *device, UINT8 data, UINT8 mask) |
| 308 | | { |
| 309 | | miot6530_state *miot = get_safe_token(device); |
| 310 | | miot->port[0].in = (miot->port[0].in & ~mask) | (data & mask); |
| 311 | | } |
| 312 | | |
| 313 | | |
| 314 | | /*------------------------------------------------- |
| 315 | | miot6530_portb_in_set - set port B input |
| 316 | | value |
| 317 | | -------------------------------------------------*/ |
| 318 | | |
| 319 | | void miot6530_portb_in_set(running_device *device, UINT8 data, UINT8 mask) |
| 320 | | { |
| 321 | | miot6530_state *miot = get_safe_token(device); |
| 322 | | miot->port[1].in = (miot->port[1].in & ~mask) | (data & mask); |
| 323 | | } |
| 324 | | |
| 325 | | |
| 326 | | /*------------------------------------------------- |
| 327 | | miot6530_porta_in_get - return port A input |
| 328 | | value |
| 329 | | -------------------------------------------------*/ |
| 330 | | |
| 331 | | UINT8 miot6530_porta_in_get(running_device *device) |
| 332 | | { |
| 333 | | miot6530_state *miot = get_safe_token(device); |
| 334 | | return miot->port[0].in; |
| 335 | | } |
| 336 | | |
| 337 | | |
| 338 | | /*------------------------------------------------- |
| 339 | | miot6530_portb_in_get - return port B input |
| 340 | | value |
| 341 | | -------------------------------------------------*/ |
| 342 | | |
| 343 | | UINT8 miot6530_portb_in_get(running_device *device) |
| 344 | | { |
| 345 | | miot6530_state *miot = get_safe_token(device); |
| 346 | | return miot->port[1].in; |
| 347 | | } |
| 348 | | |
| 349 | | |
| 350 | | /*------------------------------------------------- |
| 351 | | miot6530_porta_in_get - return port A output |
| 352 | | value |
| 353 | | -------------------------------------------------*/ |
| 354 | | |
| 355 | | UINT8 miot6530_porta_out_get(running_device *device) |
| 356 | | { |
| 357 | | miot6530_state *miot = get_safe_token(device); |
| 358 | | return miot->port[0].out; |
| 359 | | } |
| 360 | | |
| 361 | | |
| 362 | | /*------------------------------------------------- |
| 363 | | miot6530_portb_in_get - return port B output |
| 364 | | value |
| 365 | | -------------------------------------------------*/ |
| 366 | | |
| 367 | | UINT8 miot6530_portb_out_get(running_device *device) |
| 368 | | { |
| 369 | | miot6530_state *miot = get_safe_token(device); |
| 370 | | return miot->port[1].out; |
| 371 | | } |
| 372 | | |
| 373 | | |
| 374 | | /*************************************************************************** |
| 375 | | DEVICE INTERFACE |
| 376 | | ***************************************************************************/ |
| 377 | | |
| 378 | | static DEVICE_START( miot6530 ) |
| 379 | | { |
| 380 | | miot6530_state *miot = get_safe_token(device); |
| 381 | | |
| 382 | | /* validate arguments */ |
| 383 | | assert(device != NULL); |
| 384 | | assert(device->tag() != NULL); |
| 385 | | |
| 386 | | /* set static values */ |
| 387 | | miot->intf = (const miot6530_interface*)device->baseconfig().static_config; |
| 388 | | miot->clock = device->clock; |
| 389 | | |
| 390 | | /* configure the ports */ |
| 391 | | miot->port[0].in_func = miot->intf->in_a_func; |
| 392 | | miot->port[0].out_func = miot->intf->out_a_func; |
| 393 | | miot->port[1].in_func = miot->intf->in_b_func; |
| 394 | | miot->port[1].out_func = miot->intf->out_b_func; |
| 395 | | |
| 396 | | /* allocate timers */ |
| 397 | | miot->timer = timer_alloc(device->machine, timer_end_callback, (void *)device); |
| 398 | | |
| 399 | | /* register for save states */ |
| 400 | | state_save_register_device_item(device, 0, miot->port[0].in); |
| 401 | | state_save_register_device_item(device, 0, miot->port[0].out); |
| 402 | | state_save_register_device_item(device, 0, miot->port[0].ddr); |
| 403 | | state_save_register_device_item(device, 0, miot->port[1].in); |
| 404 | | state_save_register_device_item(device, 0, miot->port[1].out); |
| 405 | | state_save_register_device_item(device, 0, miot->port[1].ddr); |
| 406 | | |
| 407 | | state_save_register_device_item(device, 0, miot->irqstate); |
| 408 | | state_save_register_device_item(device, 0, miot->irqenable); |
| 409 | | |
| 410 | | state_save_register_device_item(device, 0, miot->timershift); |
| 411 | | state_save_register_device_item(device, 0, miot->timerstate); |
| 412 | | } |
| 413 | | |
| 414 | | |
| 415 | | static DEVICE_RESET( miot6530 ) |
| 416 | | { |
| 417 | | miot6530_state *miot = get_safe_token(device); |
| 418 | | |
| 419 | | /* reset I/O states */ |
| 420 | | miot->port[0].out = 0; |
| 421 | | miot->port[0].ddr = 0; |
| 422 | | miot->port[1].out = 0; |
| 423 | | miot->port[1].ddr = 0; |
| 424 | | |
| 425 | | /* reset IRQ states */ |
| 426 | | miot->irqenable = 0; |
| 427 | | miot->irqstate = TIMER_FLAG; |
| 428 | | update_irqstate(device); |
| 429 | | |
| 430 | | /* reset timer states */ |
| 431 | | miot->timershift = 0; |
| 432 | | miot->timerstate = TIMER_IDLE; |
| 433 | | timer_adjust_oneshot(miot->timer, attotime_never, 0); |
| 434 | | } |
| 435 | | |
| 436 | | |
| 437 | | DEVICE_GET_INFO( miot6530 ) |
| 438 | | { |
| 439 | | switch (state) |
| 440 | | { |
| 441 | | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 442 | | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(miot6530_state); break; |
| 443 | | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 444 | | case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break; |
| 445 | | |
| 446 | | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 447 | | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(miot6530);break; |
| 448 | | case DEVINFO_FCT_STOP: /* Nothing */ break; |
| 449 | | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(miot6530);break; |
| 450 | | |
| 451 | | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 452 | | case DEVINFO_STR_NAME: strcpy(info->s, "6530 (MIOT)"); break; |
| 453 | | case DEVINFO_STR_FAMILY: strcpy(info->s, "I/O devices"); break; |
| 454 | | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 455 | | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 456 | | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; |
| 457 | | } |
| 458 | | } |
src/mess/machine/mos6530.c
| r7586 | r7587 | |
| 1 | | /********************************************************************** |
| 1 | /*************************************************************************** |
| 2 | 2 | |
| 3 | | MOS Technology 6530 Memory, I/O, Timer Array emulation |
| 3 | MIOT 6530 emulation |
| 4 | 4 | |
| 5 | | Copyright MESS Team. |
| 6 | | Visit http://mamedev.org for licensing and usage restrictions. |
| 5 | The timer seems to follow these rules: |
| 6 | - When the timer flag changes from 0 to 1 the timer continues to count |
| 7 | down at a 1 cycle rate. |
| 8 | - When the timer is being read or written the timer flag is reset. |
| 9 | - When the timer flag is set and the timer contents are 0, the counting |
| 10 | stops. |
| 7 | 11 | |
| 8 | | **********************************************************************/ |
| 12 | From the operation of the KIM1 it expects the irqflag to be set whenever |
| 13 | the unit is reset. This is something that is not clear from the datasheet |
| 14 | and should be verified against real hardware. |
| 9 | 15 | |
| 10 | | /* |
| 16 | ***************************************************************************/ |
| 11 | 17 | |
| 12 | | TODO: |
| 18 | #include "emu.h" |
| 19 | #include "mos6530.h" |
| 13 | 20 | |
| 14 | | - interrupt flag register |
| 15 | | - internal RAM |
| 16 | | - internal ROM |
| 17 | 21 | |
| 18 | | */ |
| 19 | | |
| 20 | | #include "mos6530.h" |
| 21 | | |
| 22 | 22 | /*************************************************************************** |
| 23 | | PARAMETERS |
| 23 | CONSTANTS |
| 24 | 24 | ***************************************************************************/ |
| 25 | 25 | |
| 26 | | #define LOG 1 |
| 27 | | |
| 28 | 26 | enum |
| 29 | 27 | { |
| 30 | | REGISTER_PORT_A = 0, |
| 31 | | REGISTER_PORT_A_DDR, |
| 32 | | REGISTER_PORT_B, |
| 33 | | REGISTER_PORT_B_DDR, |
| 34 | | REGISTER_TIMER_1T, REGISTER_TIMER = REGISTER_TIMER_1T, |
| 35 | | REGISTER_TIMER_8T, REGISTER_INTERRUPT_FLAG = REGISTER_TIMER_8T, |
| 36 | | REGISTER_TIMER_64T, |
| 37 | | REGISTER_TIMER_1024T |
| 28 | TIMER_IDLE, |
| 29 | TIMER_COUNTING, |
| 30 | TIMER_FINISHING |
| 38 | 31 | }; |
| 39 | 32 | |
| 40 | | enum |
| 41 | | { |
| 42 | | PORT_A = 0, |
| 43 | | PORT_B, |
| 44 | | PORT_COUNT |
| 45 | | }; |
| 33 | #define TIMER_FLAG 0x80 |
| 46 | 34 | |
| 47 | | static const int PRESCALER[] = { 1, 8, 64, 1024 }; |
| 48 | 35 | |
| 36 | |
| 49 | 37 | /*************************************************************************** |
| 50 | 38 | TYPE DEFINITIONS |
| 51 | 39 | ***************************************************************************/ |
| 52 | 40 | |
| 53 | | typedef struct _mos6530_t mos6530_t; |
| 54 | | struct _mos6530_t |
| 41 | typedef struct _mos6530_port mos6530_port; |
| 42 | struct _mos6530_port |
| 55 | 43 | { |
| 44 | devcb_resolved_read8 in_port_func; |
| 45 | devcb_resolved_write8 out_port_func; |
| 46 | |
| 47 | UINT8 in; |
| 48 | UINT8 out; |
| 49 | UINT8 ddr; |
| 50 | }; |
| 51 | |
| 52 | |
| 53 | typedef struct _mos6530_state mos6530_state; |
| 54 | struct _mos6530_state |
| 55 | { |
| 56 | 56 | devcb_resolved_write_line out_irq_func; |
| 57 | 57 | |
| 58 | | devcb_resolved_read8 in_port_func[PORT_COUNT]; |
| 59 | | devcb_resolved_write8 out_port_func[PORT_COUNT]; |
| 58 | mos6530_port port[2]; |
| 60 | 59 | |
| 61 | | /* registers */ |
| 62 | | UINT8 output[PORT_COUNT]; /* output latches */ |
| 63 | | UINT8 ddr[PORT_COUNT]; /* DDR latches */ |
| 64 | | UINT8 counter; /* counter */ |
| 65 | | int irq_enabled; |
| 60 | UINT8 irqstate; |
| 61 | UINT8 irqenable; |
| 66 | 62 | |
| 67 | | /* timers */ |
| 68 | | emu_timer *timer; /* timer */ |
| 63 | UINT8 timershift; |
| 64 | UINT8 timerstate; |
| 65 | emu_timer * timer; |
| 66 | |
| 67 | UINT32 clock; |
| 69 | 68 | }; |
| 70 | 69 | |
| 70 | |
| 71 | |
| 71 | 72 | /*************************************************************************** |
| 72 | 73 | INLINE FUNCTIONS |
| 73 | 74 | ***************************************************************************/ |
| 74 | 75 | |
| 75 | | INLINE mos6530_t *get_safe_token(running_device *device) |
| 76 | /*------------------------------------------------- |
| 77 | get_safe_token - convert a device's token |
| 78 | into a mos6530_state |
| 79 | -------------------------------------------------*/ |
| 80 | |
| 81 | INLINE mos6530_state *get_safe_token(running_device *device) |
| 76 | 82 | { |
| 77 | 83 | assert(device != NULL); |
| 78 | 84 | assert(device->token != NULL); |
| 79 | | return (mos6530_t *)device->token; |
| 85 | assert(device->type == MIOT6530); |
| 86 | return (mos6530_state *)device->token; |
| 80 | 87 | } |
| 81 | 88 | |
| 82 | | INLINE const mos6530_interface *get_interface(running_device *device) |
| 89 | |
| 90 | /*------------------------------------------------- |
| 91 | update_irqstate - update the IRQ state |
| 92 | based on interrupt enables |
| 93 | -------------------------------------------------*/ |
| 94 | |
| 95 | INLINE void update_irqstate(running_device *device) |
| 83 | 96 | { |
| 84 | | assert(device != NULL); |
| 85 | | assert(device->type == MOS6530); |
| 86 | | return (const mos6530_interface *) device->baseconfig().static_config; |
| 97 | mos6530_state *miot = get_safe_token(device); |
| 98 | UINT8 out = miot->port[1].out; |
| 99 | |
| 100 | if ( miot->irqenable ) |
| 101 | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); |
| 102 | |
| 103 | if (miot->port[1].out_port_func.target != NULL) |
| 104 | devcb_call_write8(&miot->port[1].out_port_func, 0, out); |
| 105 | else |
| 106 | logerror("6530MIOT chip %s: Port B is being written to but has no handler.\n", device->tag()); |
| 87 | 107 | } |
| 88 | 108 | |
| 89 | | INLINE UINT8 read_port(mos6530_t *mos6530, int port) |
| 109 | |
| 110 | /*------------------------------------------------- |
| 111 | get_timer - return the current timer value |
| 112 | -------------------------------------------------*/ |
| 113 | |
| 114 | INLINE UINT8 get_timer(mos6530_state *miot) |
| 90 | 115 | { |
| 91 | | UINT8 data = mos6530->output[port] & mos6530->ddr[port]; |
| 116 | /* if idle, return 0 */ |
| 117 | if (miot->timerstate == TIMER_IDLE) |
| 118 | return 0; |
| 92 | 119 | |
| 93 | | if (mos6530->ddr[port] != 0xff) |
| 94 | | { |
| 95 | | data |= devcb_call_read8(&mos6530->in_port_func[port], 0) & ~mos6530->ddr[port]; |
| 96 | | } |
| 120 | /* if counting, return the number of ticks remaining */ |
| 121 | else if (miot->timerstate == TIMER_COUNTING) |
| 122 | return attotime_to_ticks(timer_timeleft(miot->timer), miot->clock) >> miot->timershift; |
| 97 | 123 | |
| 98 | | return data; |
| 124 | /* if finishing, return the number of ticks without the shift */ |
| 125 | else |
| 126 | return attotime_to_ticks(timer_timeleft(miot->timer), miot->clock); |
| 99 | 127 | } |
| 100 | 128 | |
| 101 | | INLINE void write_port(mos6530_t *mos6530, int port, UINT8 data) |
| 129 | |
| 130 | /*************************************************************************** |
| 131 | INTERNAL FUNCTIONS |
| 132 | ***************************************************************************/ |
| 133 | |
| 134 | /*------------------------------------------------- |
| 135 | timer_end_callback - callback to process the |
| 136 | timer |
| 137 | -------------------------------------------------*/ |
| 138 | |
| 139 | static TIMER_CALLBACK( timer_end_callback ) |
| 102 | 140 | { |
| 103 | | mos6530->output[port] = data; |
| 141 | running_device *device = (running_device *)ptr; |
| 142 | mos6530_state *miot = get_safe_token(device); |
| 104 | 143 | |
| 105 | | devcb_call_write8(&mos6530->out_port_func[port], 0, mos6530->output[port] & mos6530->ddr[port]); |
| 144 | assert(miot->timerstate != TIMER_IDLE); |
| 145 | |
| 146 | /* if we finished counting, switch to the finishing state */ |
| 147 | if (miot->timerstate == TIMER_COUNTING) |
| 148 | { |
| 149 | miot->timerstate = TIMER_FINISHING; |
| 150 | timer_adjust_oneshot(miot->timer, ticks_to_attotime(256, miot->clock), 0); |
| 151 | |
| 152 | /* signal timer IRQ as well */ |
| 153 | miot->irqstate |= TIMER_FLAG; |
| 154 | update_irqstate(device); |
| 155 | } |
| 156 | |
| 157 | /* if we finished finishing, switch to the idle state */ |
| 158 | else if (miot->timerstate == TIMER_FINISHING) |
| 159 | { |
| 160 | miot->timerstate = TIMER_IDLE; |
| 161 | timer_adjust_oneshot(miot->timer, attotime_never, 0); |
| 162 | } |
| 106 | 163 | } |
| 107 | 164 | |
| 165 | |
| 166 | |
| 108 | 167 | /*************************************************************************** |
| 109 | | IMPLEMENTATION |
| 168 | I/O ACCESS |
| 110 | 169 | ***************************************************************************/ |
| 111 | 170 | |
| 112 | 171 | /*------------------------------------------------- |
| 113 | | TIMER_CALLBACK( timer_tick ) |
| 172 | mos6530_w - master I/O write access |
| 114 | 173 | -------------------------------------------------*/ |
| 115 | 174 | |
| 116 | | static TIMER_CALLBACK( timer_tick ) |
| 175 | WRITE8_DEVICE_HANDLER( mos6530_w ) |
| 117 | 176 | { |
| 118 | | running_device *device = (running_device *)ptr; |
| 119 | | mos6530_t *mos6530 = get_safe_token(device); |
| 177 | mos6530_state *miot = get_safe_token(device); |
| 120 | 178 | |
| 121 | | if (mos6530->counter == 0xff) |
| 179 | /* if A2 == 1, we are writing to the timer */ |
| 180 | if (offset & 0x04) |
| 122 | 181 | { |
| 123 | | if (mos6530->irq_enabled) |
| 182 | static const UINT8 timershift[4] = { 0, 3, 6, 10 }; |
| 183 | attotime curtime = timer_get_time(device->machine); |
| 184 | INT64 target; |
| 185 | |
| 186 | /* A0-A1 contain the timer divisor */ |
| 187 | miot->timershift = timershift[offset & 3]; |
| 188 | |
| 189 | /* A3 contains the timer IRQ enable */ |
| 190 | if (offset & 8) |
| 191 | miot->irqenable |= TIMER_FLAG; |
| 192 | else |
| 193 | miot->irqenable &= ~TIMER_FLAG; |
| 194 | |
| 195 | /* writes here clear the timer flag */ |
| 196 | if (miot->timerstate != TIMER_FINISHING || get_timer(miot) != 0xff) |
| 197 | miot->irqstate &= ~TIMER_FLAG; |
| 198 | update_irqstate(device); |
| 199 | |
| 200 | /* update the timer */ |
| 201 | miot->timerstate = TIMER_COUNTING; |
| 202 | target = attotime_to_ticks(curtime, miot->clock) + 1 + (data << miot->timershift); |
| 203 | timer_adjust_oneshot(miot->timer, attotime_sub(ticks_to_attotime(target, miot->clock), curtime), 0); |
| 204 | } |
| 205 | |
| 206 | /* if A2 == 0, we are writing to the I/O section */ |
| 207 | else |
| 208 | { |
| 209 | /* A1 selects the port */ |
| 210 | mos6530_port *port = &miot->port[(offset >> 1) & 1]; |
| 211 | |
| 212 | /* if A0 == 1, we are writing to the port's DDR */ |
| 213 | if (offset & 1) |
| 214 | port->ddr = data; |
| 215 | |
| 216 | /* if A0 == 0, we are writing to the port's output */ |
| 217 | else |
| 124 | 218 | { |
| 125 | | /* interrupt */ |
| 126 | | logerror("MOS6530 '%s' Interrupt\n", device->tag()); |
| 127 | | devcb_call_write_line(&mos6530->out_irq_func, ASSERT_LINE); |
| 219 | UINT8 olddata = port->out; |
| 220 | port->out = data; |
| 221 | |
| 222 | if ( ( offset & 2 ) && miot->irqenable ) |
| 223 | { |
| 224 | olddata = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( olddata & 0x7F ); |
| 225 | data = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( data & 0x7F ); |
| 226 | } |
| 227 | |
| 228 | if (port->out_port_func.target != NULL) |
| 229 | devcb_call_write8(&port->out_port_func, 0, data); |
| 230 | else |
| 231 | logerror("6530MIOT chip %s: Port %c is being written to but has no handler. PC: %08X - %02X\n", device->tag(), 'A' + (offset & 1), cpu_get_pc(device->machine->firstcpu), data); |
| 128 | 232 | } |
| 129 | 233 | } |
| 130 | | |
| 131 | | mos6530->counter--; |
| 132 | 234 | } |
| 133 | 235 | |
| 236 | |
| 134 | 237 | /*------------------------------------------------- |
| 135 | | mos6530_register_r - register read |
| 238 | mos6530_r - master I/O read access |
| 136 | 239 | -------------------------------------------------*/ |
| 137 | 240 | |
| 138 | 241 | READ8_DEVICE_HANDLER( mos6530_r ) |
| 139 | 242 | { |
| 140 | | mos6530_t *mos6530 = get_safe_token(device); |
| 141 | | int port = BIT(offset, 1); |
| 243 | mos6530_state *miot = get_safe_token(device); |
| 244 | UINT8 val = 0; |
| 142 | 245 | |
| 143 | | UINT8 data = 0; |
| 246 | /* if A2 == 1 and A0 == 1, we are reading interrupt flags */ |
| 247 | if ((offset & 0x05) == 0x05) |
| 248 | { |
| 249 | val = miot->irqstate; |
| 250 | } |
| 144 | 251 | |
| 145 | | switch (offset & 0x07) |
| 252 | /* if A2 == 1 and A0 == 0, we are reading the timer */ |
| 253 | else if ((offset & 0x05) == 0x04) |
| 146 | 254 | { |
| 147 | | case REGISTER_PORT_A: |
| 148 | | case REGISTER_PORT_B: |
| 149 | | data = read_port(mos6530, port); |
| 150 | | break; |
| 255 | val = get_timer(miot); |
| 151 | 256 | |
| 152 | | case REGISTER_PORT_A_DDR: |
| 153 | | case REGISTER_PORT_B_DDR: |
| 154 | | data = mos6530->ddr[port]; |
| 155 | | break; |
| 257 | /* A3 contains the timer IRQ enable */ |
| 258 | if (offset & 8) |
| 259 | miot->irqenable |= TIMER_FLAG; |
| 260 | else |
| 261 | miot->irqenable &= ~TIMER_FLAG; |
| 156 | 262 | |
| 157 | | default: |
| 158 | | switch (offset & 0x05) |
| 263 | /* implicitly clears the timer flag */ |
| 264 | if (miot->timerstate != TIMER_FINISHING || val != 0xff) |
| 265 | miot->irqstate &= ~TIMER_FLAG; |
| 266 | update_irqstate(device); |
| 267 | } |
| 268 | |
| 269 | /* if A2 == 0 and A0 == anything, we are reading from ports */ |
| 270 | else |
| 271 | { |
| 272 | /* A1 selects the port */ |
| 273 | mos6530_port *port = &miot->port[(offset >> 1) & 1]; |
| 274 | |
| 275 | /* if A0 == 1, we are reading the port's DDR */ |
| 276 | if (offset & 1) |
| 277 | val = port->ddr; |
| 278 | |
| 279 | /* if A0 == 0, we are reading the port as an input */ |
| 280 | else |
| 159 | 281 | { |
| 160 | | case REGISTER_TIMER: |
| 161 | | data = mos6530->counter; |
| 162 | | devcb_call_write_line(&mos6530->out_irq_func, CLEAR_LINE); |
| 163 | | logerror("MOS6530 '%s' Interrupt Cleared\n", device->tag()); |
| 164 | | break; |
| 282 | UINT8 out = port->out; |
| 165 | 283 | |
| 166 | | case REGISTER_INTERRUPT_FLAG: |
| 167 | | break; |
| 284 | if ( ( offset & 2 ) && miot->irqenable ) |
| 285 | out = ( ( miot->irqstate & TIMER_FLAG ) ? 0x00 : 0x80 ) | ( out & 0x7F ); |
| 286 | |
| 287 | /* call the input callback if it exists */ |
| 288 | if (port->in_port_func.target != NULL) |
| 289 | { |
| 290 | port->in = devcb_call_read8(&port->in_port_func, 0); |
| 291 | } |
| 292 | else |
| 293 | logerror("6530MIOT chip %s: Port %c is being read but has no handler. PC: %08X\n", device->tag(), 'A' + (offset & 1), cpu_get_pc(device->machine->firstcpu)); |
| 294 | |
| 295 | /* apply the DDR to the result */ |
| 296 | val = (out & port->ddr) | (port->in & ~port->ddr); |
| 168 | 297 | } |
| 169 | 298 | } |
| 299 | return val; |
| 300 | } |
| 170 | 301 | |
| 171 | | return data; |
| 302 | |
| 303 | /*------------------------------------------------- |
| 304 | mos6530_porta_in_set - set port A input |
| 305 | value |
| 306 | -------------------------------------------------*/ |
| 307 | |
| 308 | void mos6530_porta_in_set(running_device *device, UINT8 data, UINT8 mask) |
| 309 | { |
| 310 | mos6530_state *miot = get_safe_token(device); |
| 311 | miot->port[0].in = (miot->port[0].in & ~mask) | (data & mask); |
| 172 | 312 | } |
| 173 | 313 | |
| 314 | |
| 174 | 315 | /*------------------------------------------------- |
| 175 | | mos6530_register_w - register write |
| 316 | mos6530_portb_in_set - set port B input |
| 317 | value |
| 176 | 318 | -------------------------------------------------*/ |
| 177 | 319 | |
| 178 | | WRITE8_DEVICE_HANDLER( mos6530_w ) |
| 320 | void mos6530_portb_in_set(running_device *device, UINT8 data, UINT8 mask) |
| 179 | 321 | { |
| 180 | | mos6530_t *mos6530 = get_safe_token(device); |
| 181 | | int port = BIT(offset, 1); |
| 322 | mos6530_state *miot = get_safe_token(device); |
| 323 | miot->port[1].in = (miot->port[1].in & ~mask) | (data & mask); |
| 324 | } |
| 182 | 325 | |
| 183 | | switch (offset & 0x07) |
| 184 | | { |
| 185 | | case REGISTER_PORT_A: |
| 186 | | case REGISTER_PORT_B: |
| 187 | | if (LOG) logerror("MOS6530 '%s' Port %c Write %02x\n", device->tag(), 'A' + port, data); |
| 188 | | write_port(mos6530, port, data); |
| 189 | | break; |
| 190 | 326 | |
| 191 | | case REGISTER_PORT_A_DDR: |
| 192 | | case REGISTER_PORT_B_DDR: |
| 193 | | if (LOG) logerror("MOS6530 '%s' Port %c DDR: %02x\n", device->tag(), 'A' + port, data); |
| 194 | | mos6530->ddr[port] = data; |
| 195 | | write_port(mos6530, port, data); |
| 196 | | break; |
| 327 | /*------------------------------------------------- |
| 328 | mos6530_porta_in_get - return port A input |
| 329 | value |
| 330 | -------------------------------------------------*/ |
| 197 | 331 | |
| 198 | | case REGISTER_TIMER_1T: |
| 199 | | case REGISTER_TIMER_8T: |
| 200 | | case REGISTER_TIMER_64T: |
| 201 | | case REGISTER_TIMER_1024T: |
| 202 | | if (LOG) logerror("MOS6530 '%s' Timer: %02x, %uT, IRQ %s\n", device->tag(), data, PRESCALER[offset & 0x03], BIT(offset, 3) ? "enabled" : "disabled"); |
| 203 | | mos6530->counter = data; |
| 204 | | mos6530->irq_enabled = BIT(offset, 3); |
| 205 | | timer_adjust_periodic(mos6530->timer, attotime_zero, 0, ATTOTIME_IN_HZ(device->clock / PRESCALER[offset & 0x03])); |
| 206 | | devcb_call_write_line(&mos6530->out_irq_func, CLEAR_LINE); |
| 207 | | break; |
| 208 | | } |
| 332 | UINT8 mos6530_porta_in_get(running_device *device) |
| 333 | { |
| 334 | mos6530_state *miot = get_safe_token(device); |
| 335 | return miot->port[0].in; |
| 209 | 336 | } |
| 210 | 337 | |
| 338 | |
| 211 | 339 | /*------------------------------------------------- |
| 212 | | DEVICE_START( mos6530 ) |
| 340 | mos6530_portb_in_get - return port B input |
| 341 | value |
| 213 | 342 | -------------------------------------------------*/ |
| 214 | 343 | |
| 215 | | static DEVICE_START( mos6530 ) |
| 344 | UINT8 mos6530_portb_in_get(running_device *device) |
| 216 | 345 | { |
| 217 | | mos6530_t *mos6530 = (mos6530_t *)device->token; |
| 218 | | const mos6530_interface *intf = get_interface(device); |
| 346 | mos6530_state *miot = get_safe_token(device); |
| 347 | return miot->port[1].in; |
| 348 | } |
| 219 | 349 | |
| 220 | | /* resolve callbacks */ |
| 221 | | devcb_resolve_write_line(&mos6530->out_irq_func, &intf->out_irq_func, device); |
| 222 | | devcb_resolve_read8(&mos6530->in_port_func[PORT_A], &intf->in_pa_func, device); |
| 223 | | devcb_resolve_read8(&mos6530->in_port_func[PORT_B], &intf->in_pb_func, device); |
| 224 | | devcb_resolve_write8(&mos6530->out_port_func[PORT_A], &intf->out_pa_func, device); |
| 225 | | devcb_resolve_write8(&mos6530->out_port_func[PORT_B], &intf->out_pb_func, device); |
| 226 | 350 | |
| 227 | | /* allocate timer */ |
| 228 | | mos6530->timer = timer_alloc(device->machine, timer_tick, (void *)device); |
| 351 | /*------------------------------------------------- |
| 352 | mos6530_porta_in_get - return port A output |
| 353 | value |
| 354 | -------------------------------------------------*/ |
| 229 | 355 | |
| 230 | | /* register for state saving */ |
| 231 | | state_save_register_device_item_array(device, 0, mos6530->output); |
| 232 | | state_save_register_device_item_array(device, 0, mos6530->ddr); |
| 356 | UINT8 mos6530_porta_out_get(running_device *device) |
| 357 | { |
| 358 | mos6530_state *miot = get_safe_token(device); |
| 359 | return miot->port[0].out; |
| 233 | 360 | } |
| 234 | 361 | |
| 362 | |
| 235 | 363 | /*------------------------------------------------- |
| 236 | | DEVICE_RESET( mos6530 ) |
| 364 | mos6530_portb_in_get - return port B output |
| 365 | value |
| 237 | 366 | -------------------------------------------------*/ |
| 238 | 367 | |
| 368 | UINT8 mos6530_portb_out_get(running_device *device) |
| 369 | { |
| 370 | mos6530_state *miot = get_safe_token(device); |
| 371 | return miot->port[1].out; |
| 372 | } |
| 373 | |
| 374 | |
| 375 | /*************************************************************************** |
| 376 | DEVICE INTERFACE |
| 377 | ***************************************************************************/ |
| 378 | |
| 379 | static DEVICE_START( mos6530 ) |
| 380 | { |
| 381 | mos6530_state *miot = get_safe_token(device); |
| 382 | const mos6530_interface *intf = (const mos6530_interface*)device->baseconfig().static_config; |
| 383 | |
| 384 | /* validate arguments */ |
| 385 | assert(device != NULL); |
| 386 | assert(device->tag() != NULL); |
| 387 | |
| 388 | /* set static values */ |
| 389 | miot->clock = device->clock; |
| 390 | |
| 391 | /* resolve callbacks */ |
| 392 | devcb_resolve_read8(&miot->port[0].in_port_func, &intf->in_pa_func, device); |
| 393 | devcb_resolve_read8(&miot->port[1].in_port_func, &intf->in_pb_func, device); |
| 394 | devcb_resolve_write8(&miot->port[0].out_port_func, &intf->out_pa_func, device); |
| 395 | devcb_resolve_write8(&miot->port[1].out_port_func, &intf->out_pb_func, device); |
| 396 | |
| 397 | /* allocate timers */ |
| 398 | miot->timer = timer_alloc(device->machine, timer_end_callback, (void *)device); |
| 399 | |
| 400 | /* register for save states */ |
| 401 | state_save_register_device_item(device, 0, miot->port[0].in); |
| 402 | state_save_register_device_item(device, 0, miot->port[0].out); |
| 403 | state_save_register_device_item(device, 0, miot->port[0].ddr); |
| 404 | state_save_register_device_item(device, 0, miot->port[1].in); |
| 405 | state_save_register_device_item(device, 0, miot->port[1].out); |
| 406 | state_save_register_device_item(device, 0, miot->port[1].ddr); |
| 407 | |
| 408 | state_save_register_device_item(device, 0, miot->irqstate); |
| 409 | state_save_register_device_item(device, 0, miot->irqenable); |
| 410 | |
| 411 | state_save_register_device_item(device, 0, miot->timershift); |
| 412 | state_save_register_device_item(device, 0, miot->timerstate); |
| 413 | } |
| 414 | |
| 415 | |
| 239 | 416 | static DEVICE_RESET( mos6530 ) |
| 240 | 417 | { |
| 241 | | mos6530_t *mos6530 = (mos6530_t *)device->token; |
| 418 | mos6530_state *miot = get_safe_token(device); |
| 242 | 419 | |
| 243 | | /* set ports to input mode */ |
| 244 | | mos6530->ddr[PORT_A] = 0; |
| 245 | | mos6530->ddr[PORT_B] = 0; |
| 420 | /* reset I/O states */ |
| 421 | miot->port[0].out = 0; |
| 422 | miot->port[0].ddr = 0; |
| 423 | miot->port[1].out = 0; |
| 424 | miot->port[1].ddr = 0; |
| 425 | |
| 426 | /* reset IRQ states */ |
| 427 | miot->irqenable = 0; |
| 428 | miot->irqstate = TIMER_FLAG; |
| 429 | update_irqstate(device); |
| 430 | |
| 431 | /* reset timer states */ |
| 432 | miot->timershift = 0; |
| 433 | miot->timerstate = TIMER_IDLE; |
| 434 | timer_adjust_oneshot(miot->timer, attotime_never, 0); |
| 246 | 435 | } |
| 247 | 436 | |
| 248 | | /*------------------------------------------------- |
| 249 | | DEVICE_GET_INFO( mos6530 ) |
| 250 | | -------------------------------------------------*/ |
| 251 | 437 | |
| 252 | 438 | DEVICE_GET_INFO( mos6530 ) |
| 253 | 439 | { |
| 254 | 440 | switch (state) |
| 255 | 441 | { |
| 256 | 442 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 443 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mos6530_state); break; |
| 257 | 444 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 258 | 445 | case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break; |
| 259 | | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(mos6530_t); break; |
| 260 | 446 | |
| 261 | 447 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 262 | 448 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(mos6530); break; |
| r7586 | r7587 | |
| 268 | 454 | case DEVINFO_STR_FAMILY: strcpy(info->s, "MOS6500"); break; |
| 269 | 455 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 270 | 456 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 271 | | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; |
| 457 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright MESS Team"); break; |
| 272 | 458 | } |
| 273 | 459 | } |
src/mess/machine/c2040.c
| r7586 | r7587 | |
| 29 | 29 | #include "formats/g64_dsk.h" |
| 30 | 30 | #include "machine/6522via.h" |
| 31 | 31 | #include "machine/6532riot.h" |
| 32 | | #include "machine/6530miot.h" |
| 32 | #include "machine/mos6530.h" |
| 33 | 33 | #include "machine/ieee488.h" |
| 34 | 34 | |
| 35 | 35 | /*************************************************************************** |
| r7586 | r7587 | |
| 422 | 422 | ADDRESS_MAP_GLOBAL_MASK(0x1fff) |
| 423 | 423 | AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530 |
| 424 | 424 | AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via_r, via_w) |
| 425 | | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, miot6530_r, miot6530_w) |
| 425 | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, mos6530_r, mos6530_w) |
| 426 | 426 | AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") |
| 427 | 427 | AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") |
| 428 | 428 | AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") |
| r7586 | r7587 | |
| 455 | 455 | ADDRESS_MAP_GLOBAL_MASK(0x1fff) |
| 456 | 456 | AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530 |
| 457 | 457 | AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via_r, via_w) |
| 458 | | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, miot6530_r, miot6530_w) |
| 458 | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, mos6530_r, mos6530_w) |
| 459 | 459 | AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") |
| 460 | 460 | AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") |
| 461 | 461 | AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") |
| r7586 | r7587 | |
| 487 | 487 | ADDRESS_MAP_GLOBAL_MASK(0x1fff) |
| 488 | 488 | AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530 |
| 489 | 489 | AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via_r, via_w) |
| 490 | | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, miot6530_r, miot6530_w) |
| 490 | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, mos6530_r, mos6530_w) |
| 491 | 491 | AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") |
| 492 | 492 | AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") |
| 493 | 493 | AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") |
| r7586 | r7587 | |
| 519 | 519 | ADDRESS_MAP_GLOBAL_MASK(0x1fff) |
| 520 | 520 | AM_RANGE(0x0000, 0x003f) AM_MIRROR(0x0300) AM_RAM // 6530 |
| 521 | 521 | AM_RANGE(0x0040, 0x004f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6522_TAG, via_r, via_w) |
| 522 | | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, miot6530_r, miot6530_w) |
| 522 | AM_RANGE(0x0080, 0x008f) AM_MIRROR(0x0330) AM_DEVREADWRITE(M6530_TAG, mos6530_r, mos6530_w) |
| 523 | 523 | AM_RANGE(0x0400, 0x07ff) AM_RAM AM_SHARE("share1") |
| 524 | 524 | AM_RANGE(0x0800, 0x0bff) AM_RAM AM_SHARE("share2") |
| 525 | 525 | AM_RANGE(0x0c00, 0x0fff) AM_RAM AM_SHARE("share3") |
| r7586 | r7587 | |
| 946 | 946 | mos6530_interface miot_intf uk3 |
| 947 | 947 | -------------------------------------------------*/ |
| 948 | 948 | |
| 949 | | static UINT8 pi_r(running_device *device, UINT8 olddata) |
| 949 | static READ8_DEVICE_HANDLER( pi_r ) |
| 950 | 950 | { |
| 951 | 951 | /* |
| 952 | 952 | |
| r7586 | r7587 | |
| 968 | 968 | return c2040->pi; |
| 969 | 969 | } |
| 970 | 970 | |
| 971 | | static void pi_w(running_device *device, UINT8 newdata, UINT8 olddata) |
| 971 | static WRITE8_DEVICE_HANDLER( pi_w ) |
| 972 | 972 | { |
| 973 | 973 | /* |
| 974 | 974 | |
| r7586 | r7587 | |
| 987 | 987 | |
| 988 | 988 | c2040_t *c2040 = get_safe_token(device->owner); |
| 989 | 989 | |
| 990 | | c2040->pi = newdata; |
| 990 | c2040->pi = data; |
| 991 | 991 | } |
| 992 | 992 | |
| 993 | | static UINT8 miot_pb_r(running_device *device, UINT8 olddata) |
| 993 | static READ8_DEVICE_HANDLER( miot_pb_r ) |
| 994 | 994 | { |
| 995 | 995 | /* |
| 996 | 996 | |
| r7586 | r7587 | |
| 1020 | 1020 | return data; |
| 1021 | 1021 | } |
| 1022 | 1022 | |
| 1023 | | static void miot_pb_w(running_device *device, UINT8 newdata, UINT8 olddata) |
| 1023 | static WRITE8_DEVICE_HANDLER( miot_pb_w ) |
| 1024 | 1024 | { |
| 1025 | 1025 | /* |
| 1026 | 1026 | |
| r7586 | r7587 | |
| 1040 | 1040 | c2040_t *c2040 = get_safe_token(device->owner); |
| 1041 | 1041 | |
| 1042 | 1042 | /* drive select */ |
| 1043 | | c2040->drive = BIT(newdata, 0); |
| 1043 | c2040->drive = BIT(data, 0); |
| 1044 | 1044 | |
| 1045 | 1045 | /* density select */ |
| 1046 | | int ds = (newdata >> 1) & 0x03; |
| 1046 | int ds = (data >> 1) & 0x03; |
| 1047 | 1047 | |
| 1048 | 1048 | if (c2040->ds != ds) |
| 1049 | 1049 | { |
| r7586 | r7587 | |
| 1052 | 1052 | } |
| 1053 | 1053 | |
| 1054 | 1054 | /* interrupt */ |
| 1055 | | if (c2040->miot_irq != BIT(newdata, 7)) |
| 1055 | if (c2040->miot_irq != BIT(data, 7)) |
| 1056 | 1056 | { |
| 1057 | | cpu_set_input_line(c2040->cpu_fdc, M6502_IRQ_LINE, BIT(newdata, 7) ? CLEAR_LINE : ASSERT_LINE); |
| 1058 | | c2040->miot_irq = BIT(newdata, 7); |
| 1057 | cpu_set_input_line(c2040->cpu_fdc, M6502_IRQ_LINE, BIT(data, 7) ? CLEAR_LINE : ASSERT_LINE); |
| 1058 | c2040->miot_irq = BIT(data, 7); |
| 1059 | 1059 | } |
| 1060 | 1060 | } |
| 1061 | 1061 | |
| 1062 | | static const miot6530_interface miot_intf = |
| 1062 | static MOS6530_INTERFACE( miot_intf ) |
| 1063 | 1063 | { |
| 1064 | | pi_r, |
| 1065 | | miot_pb_r, |
| 1066 | | pi_w, |
| 1067 | | miot_pb_w |
| 1064 | DEVCB_HANDLER(pi_r), |
| 1065 | DEVCB_HANDLER(pi_w), |
| 1066 | DEVCB_HANDLER(miot_pb_r), |
| 1067 | DEVCB_HANDLER(miot_pb_w) |
| 1068 | 1068 | }; |
| 1069 | 1069 | |
| 1070 | 1070 | /*------------------------------------------------- |
| 1071 | 1071 | mos6530_interface c8050_miot_intf uk3 |
| 1072 | 1072 | -------------------------------------------------*/ |
| 1073 | 1073 | |
| 1074 | | static UINT8 c8050_miot_pb_r(running_device *device, UINT8 olddata) |
| 1074 | static READ8_DEVICE_HANDLER( c8050_miot_pb_r ) |
| 1075 | 1075 | { |
| 1076 | 1076 | /* |
| 1077 | 1077 | |
| r7586 | r7587 | |
| 1107 | 1107 | return data; |
| 1108 | 1108 | } |
| 1109 | 1109 | |
| 1110 | | static void c8050_miot_pb_w(running_device *device, UINT8 newdata, UINT8 olddata) |
| 1110 | static WRITE8_DEVICE_HANDLER( c8050_miot_pb_w ) |
| 1111 | 1111 | { |
| 1112 | 1112 | /* |
| 1113 | 1113 | |
| r7586 | r7587 | |
| 1129 | 1129 | /* drive select */ |
| 1130 | 1130 | if ((device->owner->type == C8050) || (device->owner->type == C8250)) |
| 1131 | 1131 | { |
| 1132 | | c2040->drive = BIT(newdata, 0); |
| 1132 | c2040->drive = BIT(data, 0); |
| 1133 | 1133 | } |
| 1134 | 1134 | |
| 1135 | 1135 | /* density select */ |
| 1136 | | int ds = (newdata >> 1) & 0x03; |
| 1136 | int ds = (data >> 1) & 0x03; |
| 1137 | 1137 | |
| 1138 | 1138 | if (c2040->ds != ds) |
| 1139 | 1139 | { |
| r7586 | r7587 | |
| 1144 | 1144 | /* side select */ |
| 1145 | 1145 | if ((device->owner->type == C8250) || (device->owner->type == SFD1001)) |
| 1146 | 1146 | { |
| 1147 | | c2040->side = !BIT(newdata, 4); |
| 1147 | c2040->side = !BIT(data, 4); |
| 1148 | 1148 | } |
| 1149 | 1149 | |
| 1150 | 1150 | /* interrupt */ |
| 1151 | | if (c2040->miot_irq != BIT(newdata, 7)) |
| 1151 | if (c2040->miot_irq != BIT(data, 7)) |
| 1152 | 1152 | { |
| 1153 | | cpu_set_input_line(c2040->cpu_fdc, M6502_IRQ_LINE, BIT(newdata, 7) ? CLEAR_LINE : ASSERT_LINE); |
| 1154 | | c2040->miot_irq = BIT(newdata, 7); |
| 1153 | cpu_set_input_line(c2040->cpu_fdc, M6502_IRQ_LINE, BIT(data, 7) ? CLEAR_LINE : ASSERT_LINE); |
| 1154 | c2040->miot_irq = BIT(data, 7); |
| 1155 | 1155 | } |
| 1156 | 1156 | } |
| 1157 | 1157 | |
| 1158 | | static const miot6530_interface c8050_miot_intf = |
| 1158 | static MOS6530_INTERFACE( c8050_miot_intf ) |
| 1159 | 1159 | { |
| 1160 | | pi_r, |
| 1161 | | c8050_miot_pb_r, |
| 1162 | | pi_w, |
| 1163 | | c8050_miot_pb_w |
| 1160 | DEVCB_HANDLER(pi_r), |
| 1161 | DEVCB_HANDLER(pi_w), |
| 1162 | DEVCB_HANDLER(c8050_miot_pb_r), |
| 1163 | DEVCB_HANDLER(c8050_miot_pb_w) |
| 1164 | 1164 | }; |
| 1165 | 1165 | |
| 1166 | 1166 | /*------------------------------------------------- |
| r7586 | r7587 | |
| 1279 | 1279 | MDRV_CPU_PROGRAM_MAP(c2040_fdc_map) |
| 1280 | 1280 | |
| 1281 | 1281 | MDRV_VIA6522_ADD(M6522_TAG, XTAL_16MHz/16, via_intf) |
| 1282 | | MDRV_MIOT6530_ADD(M6530_TAG, XTAL_16MHz/16, miot_intf) |
| 1282 | MDRV_MOS6530_ADD(M6530_TAG, XTAL_16MHz/16, miot_intf) |
| 1283 | 1283 | |
| 1284 | 1284 | MDRV_FLOPPY_2_DRIVES_ADD(c2040_floppy_config) |
| 1285 | 1285 | MACHINE_DRIVER_END |
| r7586 | r7587 | |
| 1301 | 1301 | MDRV_CPU_PROGRAM_MAP(c4040_fdc_map) |
| 1302 | 1302 | |
| 1303 | 1303 | MDRV_VIA6522_ADD(M6522_TAG, XTAL_16MHz/16, via_intf) |
| 1304 | | MDRV_MIOT6530_ADD(M6530_TAG, XTAL_16MHz/16, miot_intf) |
| 1304 | MDRV_MOS6530_ADD(M6530_TAG, XTAL_16MHz/16, miot_intf) |
| 1305 | 1305 | |
| 1306 | 1306 | MDRV_FLOPPY_2_DRIVES_ADD(c4040_floppy_config) |
| 1307 | 1307 | MACHINE_DRIVER_END |
| r7586 | r7587 | |
| 1323 | 1323 | MDRV_CPU_PROGRAM_MAP(c8050_fdc_map) |
| 1324 | 1324 | |
| 1325 | 1325 | MDRV_VIA6522_ADD(M6522_TAG, XTAL_12MHz/12, c8050_via_intf) |
| 1326 | | MDRV_MIOT6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf) |
| 1326 | MDRV_MOS6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf) |
| 1327 | 1327 | |
| 1328 | 1328 | MDRV_FLOPPY_2_DRIVES_ADD(c8050_floppy_config) |
| 1329 | 1329 | MACHINE_DRIVER_END |
| r7586 | r7587 | |
| 1345 | 1345 | MDRV_CPU_PROGRAM_MAP(c8050_fdc_map) |
| 1346 | 1346 | |
| 1347 | 1347 | MDRV_VIA6522_ADD(M6522_TAG, XTAL_12MHz/12, c8050_via_intf) |
| 1348 | | MDRV_MIOT6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf) |
| 1348 | MDRV_MOS6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf) |
| 1349 | 1349 | |
| 1350 | 1350 | MDRV_FLOPPY_2_DRIVES_ADD(c8250_floppy_config) |
| 1351 | 1351 | MACHINE_DRIVER_END |
| r7586 | r7587 | |
| 1367 | 1367 | MDRV_CPU_PROGRAM_MAP(sfd1001_fdc_map) |
| 1368 | 1368 | |
| 1369 | 1369 | MDRV_VIA6522_ADD(M6522_TAG, XTAL_12MHz/12, c8050_via_intf) |
| 1370 | | MDRV_MIOT6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf) |
| 1370 | MDRV_MOS6530_ADD(M6530_TAG, XTAL_12MHz/12, c8050_miot_intf) |
| 1371 | 1371 | |
| 1372 | 1372 | MDRV_FLOPPY_DRIVE_ADD(FLOPPY_0, c8250_floppy_config) |
| 1373 | 1373 | MACHINE_DRIVER_END |
src/mess/drivers/kim1.c
| r7586 | r7587 | |
| 82 | 82 | #include "emu.h" |
| 83 | 83 | #include "cpu/m6502/m6502.h" |
| 84 | 84 | #include "sound/dac.h" |
| 85 | | #include "machine/6530miot.h" |
| 85 | #include "machine/mos6530.h" |
| 86 | 86 | #include "devices/cassette.h" |
| 87 | 87 | #include "formats/kim1_cas.h" |
| 88 | 88 | #include "kim1.lh" |
| r7586 | r7587 | |
| 96 | 96 | |
| 97 | 97 | static ADDRESS_MAP_START ( kim1_map , ADDRESS_SPACE_PROGRAM, 8) |
| 98 | 98 | AM_RANGE(0x0000, 0x03ff) AM_MIRROR(0xe000) AM_RAM |
| 99 | | AM_RANGE(0x1700, 0x173f) AM_MIRROR(0xe000) AM_DEVREADWRITE("miot_u3", miot6530_r, miot6530_w ) |
| 100 | | AM_RANGE(0x1740, 0x177f) AM_MIRROR(0xe000) AM_DEVREADWRITE("miot_u2", miot6530_r, miot6530_w ) |
| 99 | AM_RANGE(0x1700, 0x173f) AM_MIRROR(0xe000) AM_DEVREADWRITE("miot_u3", mos6530_r, mos6530_w ) |
| 100 | AM_RANGE(0x1740, 0x177f) AM_MIRROR(0xe000) AM_DEVREADWRITE("miot_u2", mos6530_r, mos6530_w ) |
| 101 | 101 | AM_RANGE(0x1780, 0x17bf) AM_MIRROR(0xe000) AM_RAM |
| 102 | 102 | AM_RANGE(0x17c0, 0x17ff) AM_MIRROR(0xe000) AM_RAM |
| 103 | 103 | AM_RANGE(0x1800, 0x1bff) AM_MIRROR(0xe000) AM_ROM |
| r7586 | r7587 | |
| 157 | 157 | INPUT_PORTS_END |
| 158 | 158 | |
| 159 | 159 | |
| 160 | | static UINT8 kim1_u2_read_a(running_device *device, UINT8 olddata) |
| 160 | static READ8_DEVICE_HANDLER( kim1_u2_read_a ) |
| 161 | 161 | { |
| 162 | 162 | UINT8 data = 0xff; |
| 163 | 163 | |
| r7586 | r7587 | |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | 179 | |
| 180 | | static void kim1_u2_write_a(running_device *device, UINT8 newdata, UINT8 olddata) |
| 180 | static WRITE8_DEVICE_HANDLER( kim1_u2_write_a ) |
| 181 | 181 | { |
| 182 | 182 | UINT8 idx = ( kim1_u2_port_b >> 1 ) & 0x0f; |
| 183 | 183 | |
| 184 | 184 | if ( idx >= 4 && idx < 10 ) |
| 185 | 185 | { |
| 186 | | if ( newdata & 0x80 ) |
| 186 | if ( data & 0x80 ) |
| 187 | 187 | { |
| 188 | | output_set_digit_value( idx-4, newdata & 0x7f ); |
| 188 | output_set_digit_value( idx-4, data & 0x7f ); |
| 189 | 189 | kim1_led_time[idx - 4] = 15; |
| 190 | 190 | } |
| 191 | 191 | } |
| 192 | 192 | } |
| 193 | 193 | |
| 194 | | |
| 195 | | static UINT8 kim1_u2_read_b(running_device *device, UINT8 olddata) |
| 194 | static READ8_DEVICE_HANDLER( kim1_u2_read_b ) |
| 196 | 195 | { |
| 197 | | if ( miot6530_portb_out_get(device) & 0x20 ) |
| 196 | if ( mos6530_portb_out_get(device) & 0x20 ) |
| 198 | 197 | return 0xFF; |
| 199 | 198 | |
| 200 | 199 | return 0x7F | ( kim1_311_output ^ 0x80 ); |
| 201 | 200 | } |
| 202 | 201 | |
| 203 | 202 | |
| 204 | | static void kim1_u2_write_b(running_device *device, UINT8 newdata, UINT8 olddata) |
| 203 | static WRITE8_DEVICE_HANDLER( kim1_u2_write_b ) |
| 205 | 204 | { |
| 206 | | kim1_u2_port_b = newdata; |
| 205 | kim1_u2_port_b = data; |
| 207 | 206 | |
| 208 | | if ( newdata & 0x20 ) |
| 207 | if ( data & 0x20 ) |
| 209 | 208 | { |
| 210 | 209 | /* cassette write/speaker update */ |
| 211 | | cassette_output( devtag_get_device(device->machine, "cassette"), ( newdata & 0x80 ) ? -1.0 : 1.0 ); |
| 210 | cassette_output( devtag_get_device(device->machine, "cassette"), ( data & 0x80 ) ? -1.0 : 1.0 ); |
| 212 | 211 | } |
| 213 | 212 | |
| 214 | 213 | /* Set IRQ when bit 7 is cleared */ |
| 215 | 214 | } |
| 216 | 215 | |
| 217 | 216 | |
| 218 | | static const miot6530_interface kim1_u2_miot6530_interface = |
| 217 | static MOS6530_INTERFACE( kim1_u2_mos6530_interface ) |
| 219 | 218 | { |
| 220 | | kim1_u2_read_a, |
| 221 | | kim1_u2_read_b, |
| 222 | | kim1_u2_write_a, |
| 223 | | kim1_u2_write_b |
| 219 | DEVCB_HANDLER(kim1_u2_read_a), |
| 220 | DEVCB_HANDLER(kim1_u2_write_a), |
| 221 | DEVCB_HANDLER(kim1_u2_read_b), |
| 222 | DEVCB_HANDLER(kim1_u2_write_b) |
| 224 | 223 | }; |
| 225 | 224 | |
| 226 | | |
| 227 | | static UINT8 kim1_u3_read_a(running_device *device, UINT8 olddata) |
| 225 | static MOS6530_INTERFACE( kim1_u3_mos6530_interface ) |
| 228 | 226 | { |
| 229 | | return 0xFF; |
| 230 | | } |
| 231 | | |
| 232 | | |
| 233 | | static void kim1_u3_write_a(running_device *device, UINT8 newdata, UINT8 olddata) |
| 234 | | { |
| 235 | | } |
| 236 | | |
| 237 | | |
| 238 | | static UINT8 kim1_u3_read_b(running_device *device, UINT8 olddata) |
| 239 | | { |
| 240 | | return 0xFF; |
| 241 | | } |
| 242 | | |
| 243 | | |
| 244 | | static void kim1_u3_write_b(running_device *device, UINT8 newdata, UINT8 olddata) |
| 245 | | { |
| 246 | | } |
| 247 | | |
| 248 | | |
| 249 | | static const miot6530_interface kim1_u3_miot6530_interface = |
| 250 | | { |
| 251 | | kim1_u3_read_a, |
| 252 | | kim1_u3_read_b, |
| 253 | | kim1_u3_write_a, |
| 254 | | kim1_u3_write_b |
| 227 | DEVCB_NULL, |
| 228 | DEVCB_NULL, |
| 229 | DEVCB_NULL, |
| 230 | DEVCB_NULL |
| 255 | 231 | }; |
| 256 | 232 | |
| 257 | 233 | |
| r7586 | r7587 | |
| 331 | 307 | MDRV_MACHINE_START( kim1 ) |
| 332 | 308 | MDRV_MACHINE_RESET( kim1 ) |
| 333 | 309 | |
| 334 | | MDRV_MIOT6530_ADD( "miot_u2", 1000000, kim1_u2_miot6530_interface ) |
| 335 | | MDRV_MIOT6530_ADD( "miot_u3", 1000000, kim1_u3_miot6530_interface ) |
| 310 | MDRV_MOS6530_ADD( "miot_u2", 1000000, kim1_u2_mos6530_interface ) |
| 311 | MDRV_MOS6530_ADD( "miot_u3", 1000000, kim1_u3_mos6530_interface ) |
| 336 | 312 | |
| 337 | 313 | /* sound hardware */ |
| 338 | 314 | MDRV_SPEAKER_STANDARD_MONO("mono") |