trunk/src/emu/cpu/m6502/m5074x.c
| r0 | r22067 | |
| 1 | /* |
| 2 | Mitsubishi M5074x 8-bit microcontroller family |
| 3 | */ |
| 4 | |
| 5 | #include "emu.h" |
| 6 | #include "m5074x.h" |
| 7 | |
| 8 | //************************************************************************** |
| 9 | // MACROS / CONSTANTS |
| 10 | //************************************************************************** |
| 11 | |
| 12 | #define IRQ_CNTRREQ (0x80) |
| 13 | #define IRQ_CNTRENA (0x40) |
| 14 | #define IRQ_TMR1REQ (0x20) |
| 15 | #define IRQ_TMR1ENA (0x10) |
| 16 | #define IRQ_TMR2REQ (0x08) |
| 17 | #define IRQ_TMR2ENA (0x04) |
| 18 | #define IRQ_INTREQ (0x02) |
| 19 | #define IRQ_INTENA (0x01) |
| 20 | |
| 21 | #define TMRC_TMRXREQ (0x80) |
| 22 | #define TMRC_TMRXENA (0x40) |
| 23 | #define TMRC_TMRXHLT (0x20) |
| 24 | #define TMRC_TMRXMDE (0x0c) |
| 25 | |
| 26 | //************************************************************************** |
| 27 | // DEVICE DEFINITIONS |
| 28 | //************************************************************************** |
| 29 | |
| 30 | const device_type M50740 = &device_creator<m50740_device>; |
| 31 | const device_type M50741 = &device_creator<m50741_device>; |
| 32 | |
| 33 | //************************************************************************** |
| 34 | // LIVE DEVICE |
| 35 | //************************************************************************** |
| 36 | |
| 37 | //------------------------------------------------- |
| 38 | // m5074x_device - constructor |
| 39 | //------------------------------------------------- |
| 40 | m5074x_device::m5074x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map) : |
| 41 | m740_device(mconfig, type, name, tag, owner, clock), |
| 42 | m_program_config("program", ENDIANNESS_LITTLE, 8, 16, 0, internal_map), |
| 43 | read_p0(*this), |
| 44 | read_p1(*this), |
| 45 | read_p2(*this), |
| 46 | read_p3(*this), |
| 47 | write_p0(*this), |
| 48 | write_p1(*this), |
| 49 | write_p2(*this), |
| 50 | write_p3(*this) |
| 51 | { |
| 52 | } |
| 53 | |
| 54 | void m5074x_device::device_config_complete() |
| 55 | { |
| 56 | m_shortname = "m5074x"; |
| 57 | } |
| 58 | |
| 59 | //------------------------------------------------- |
| 60 | // device_start - device-specific startup |
| 61 | //------------------------------------------------- |
| 62 | |
| 63 | void m5074x_device::device_start() |
| 64 | { |
| 65 | read_p0.resolve_safe(0); |
| 66 | read_p1.resolve_safe(0); |
| 67 | read_p2.resolve_safe(0); |
| 68 | read_p3.resolve_safe(0); |
| 69 | write_p0.resolve_safe(); |
| 70 | write_p1.resolve_safe(); |
| 71 | write_p2.resolve_safe(); |
| 72 | write_p3.resolve_safe(); |
| 73 | |
| 74 | for (int i = 0; i < NUM_TIMERS; i++) |
| 75 | { |
| 76 | m_timers[i] = timer_alloc(i, NULL); |
| 77 | } |
| 78 | |
| 79 | m740_device::device_start(); |
| 80 | |
| 81 | save_item(NAME(m_ports)); |
| 82 | save_item(NAME(m_ddrs)); |
| 83 | save_item(NAME(m_intctrl)); |
| 84 | save_item(NAME(m_tmrctrl)); |
| 85 | save_item(NAME(m_tmr12pre)); |
| 86 | save_item(NAME(m_tmr1)); |
| 87 | save_item(NAME(m_tmr2)); |
| 88 | save_item(NAME(m_tmrxpre)); |
| 89 | save_item(NAME(m_tmrx)); |
| 90 | save_item(NAME(m_tmr1latch)); |
| 91 | save_item(NAME(m_tmr2latch)); |
| 92 | save_item(NAME(m_tmrxlatch)); |
| 93 | save_item(NAME(m_last_all_ints)); |
| 94 | |
| 95 | memset(m_ports, 0, sizeof(m_ports)); |
| 96 | memset(m_ddrs, 0, sizeof(m_ddrs)); |
| 97 | m_intctrl = m_tmrctrl = 0; |
| 98 | m_tmr12pre = m_tmrxpre = 0; |
| 99 | m_tmr1 = m_tmr2 = m_tmrx = 0; |
| 100 | m_last_all_ints = 0; |
| 101 | } |
| 102 | |
| 103 | |
| 104 | //------------------------------------------------- |
| 105 | // device_reset - device-specific reset |
| 106 | //------------------------------------------------- |
| 107 | |
| 108 | void m5074x_device::device_reset() |
| 109 | { |
| 110 | m740_device::device_reset(); |
| 111 | |
| 112 | // all ports reset to input on startup |
| 113 | memset(m_ports, 0, sizeof(m_ports)); |
| 114 | memset(m_ddrs, 0, sizeof(m_ddrs)); |
| 115 | m_intctrl = m_tmrctrl = 0; |
| 116 | m_tmr12pre = m_tmrxpre = 0; |
| 117 | m_tmr1 = m_tmr2 = m_tmrx = 0; |
| 118 | } |
| 119 | |
| 120 | void m5074x_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 121 | { |
| 122 | switch (id) |
| 123 | { |
| 124 | case TIMER_1: |
| 125 | m_tmr1--; |
| 126 | |
| 127 | if (m_tmr1 <= 0) |
| 128 | { |
| 129 | m_intctrl |= IRQ_TMR1REQ; |
| 130 | m_tmr1 = m_tmr1latch; |
| 131 | recalc_irqs(); |
| 132 | } |
| 133 | break; |
| 134 | |
| 135 | case TIMER_2: |
| 136 | m_tmr2--; |
| 137 | |
| 138 | if (m_tmr2 <= 0) |
| 139 | { |
| 140 | m_intctrl |= IRQ_TMR2REQ; |
| 141 | m_tmr2 = m_tmr2latch; |
| 142 | recalc_irqs(); |
| 143 | } |
| 144 | break; |
| 145 | |
| 146 | case TIMER_X: |
| 147 | m_tmrx--; |
| 148 | |
| 149 | if (m_tmrx <= 0) |
| 150 | { |
| 151 | m_tmrctrl |= TMRC_TMRXREQ; |
| 152 | m_tmrx = m_tmrxlatch; |
| 153 | recalc_irqs(); |
| 154 | } |
| 155 | break; |
| 156 | } |
| 157 | } |
| 158 | |
| 159 | void m5074x_device::execute_set_input(int inputnum, int state) |
| 160 | { |
| 161 | switch (inputnum) |
| 162 | { |
| 163 | case M5074X_INT1_LINE: |
| 164 | if (state == ASSERT_LINE) |
| 165 | { |
| 166 | m_intctrl |= IRQ_INTREQ; |
| 167 | } |
| 168 | else |
| 169 | { |
| 170 | m_intctrl &= ~IRQ_INTREQ; |
| 171 | } |
| 172 | break; |
| 173 | |
| 174 | case M5074X_SET_OVERFLOW: // the base 740 class can handle this |
| 175 | m740_device::execute_set_input(M740_SET_OVERFLOW, state); |
| 176 | break; |
| 177 | } |
| 178 | |
| 179 | recalc_irqs(); |
| 180 | } |
| 181 | |
| 182 | void m5074x_device::recalc_irqs() |
| 183 | { |
| 184 | UINT8 all_ints = 0; |
| 185 | |
| 186 | if ((m_intctrl & (IRQ_CNTRREQ|IRQ_CNTRENA)) == (IRQ_CNTRREQ|IRQ_CNTRENA)) |
| 187 | { |
| 188 | all_ints |= 0x01; |
| 189 | } |
| 190 | if ((m_tmrctrl & (TMRC_TMRXREQ|TMRC_TMRXENA)) == (TMRC_TMRXREQ|TMRC_TMRXENA)) |
| 191 | { |
| 192 | all_ints |= 0x02; |
| 193 | } |
| 194 | if ((m_intctrl & (IRQ_TMR1REQ|IRQ_TMR1ENA)) == (IRQ_TMR1REQ|IRQ_TMR1ENA)) |
| 195 | { |
| 196 | all_ints |= 0x04; |
| 197 | } |
| 198 | if ((m_intctrl & (IRQ_TMR2REQ|IRQ_TMR2ENA)) == (IRQ_TMR2REQ|IRQ_TMR2ENA)) |
| 199 | { |
| 200 | all_ints |= 0x08; |
| 201 | } |
| 202 | if ((m_intctrl & (IRQ_INTREQ|IRQ_INTENA)) == (IRQ_INTREQ|IRQ_INTENA)) |
| 203 | { |
| 204 | all_ints |= 0x10; |
| 205 | } |
| 206 | |
| 207 | // check all 6 IRQ bits for changes |
| 208 | for (int i = 0; i < 6; i++) |
| 209 | { |
| 210 | // if bit is set now |
| 211 | if (all_ints & (1 << i)) |
| 212 | { |
| 213 | // and wasn't last time |
| 214 | if (!(m_last_all_ints & (1 << i))) |
| 215 | { |
| 216 | m740_device::execute_set_input(M740_INT0_LINE + i, ASSERT_LINE); |
| 217 | } |
| 218 | } |
| 219 | else // bit is clear now |
| 220 | { |
| 221 | // ...and wasn't clear last time |
| 222 | if (m_last_all_ints & (1 << i)) |
| 223 | { |
| 224 | m740_device::execute_set_input(M740_INT0_LINE + i, CLEAR_LINE); |
| 225 | } |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | m_last_all_ints = all_ints; |
| 230 | } |
| 231 | |
| 232 | void m5074x_device::recalc_timer(int timer) |
| 233 | { |
| 234 | int hz; |
| 235 | |
| 236 | switch (timer) |
| 237 | { |
| 238 | case 0: |
| 239 | hz = clock() / 16; |
| 240 | hz /= (m_tmr12pre + 2); |
| 241 | m_timers[TIMER_1]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); |
| 242 | break; |
| 243 | |
| 244 | case 1: |
| 245 | hz = clock() / 16; |
| 246 | hz /= (m_tmr12pre + 2); |
| 247 | m_timers[TIMER_2]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); |
| 248 | break; |
| 249 | |
| 250 | case 2: |
| 251 | // Timer X modes: 00 = free run countdown, 01 = invert CNTR pin each time expires, |
| 252 | // 10 = count each time CNTR pin inverts, 11 = count when CNTR pin low |
| 253 | if ((m_tmrctrl & TMRC_TMRXMDE) == 0) |
| 254 | { |
| 255 | // stop bit? |
| 256 | if (m_tmrctrl & TMRC_TMRXHLT) |
| 257 | { |
| 258 | m_timers[TIMER_X]->adjust(attotime::never, 0, attotime::never); |
| 259 | } |
| 260 | else |
| 261 | { |
| 262 | hz = clock() / 16; |
| 263 | hz /= (m_tmrxpre + 2); |
| 264 | m_timers[TIMER_X]->adjust(attotime::from_hz(hz), 0, attotime::from_hz(hz)); |
| 265 | } |
| 266 | } |
| 267 | else |
| 268 | { |
| 269 | fatalerror("M5074x: Unhandled timer X mode %d\n", (m_tmrctrl&TMRC_TMRXMDE)>>2); |
| 270 | } |
| 271 | break; |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | void m5074x_device::send_port(address_space &space, UINT8 offset, UINT8 data) |
| 276 | { |
| 277 | switch (offset) |
| 278 | { |
| 279 | case 0: |
| 280 | write_p0(data); |
| 281 | break; |
| 282 | |
| 283 | case 1: |
| 284 | write_p1(data); |
| 285 | break; |
| 286 | |
| 287 | case 2: |
| 288 | write_p2(data); |
| 289 | break; |
| 290 | |
| 291 | case 3: |
| 292 | write_p3(data); |
| 293 | break; |
| 294 | } |
| 295 | } |
| 296 | |
| 297 | UINT8 m5074x_device::read_port(UINT8 offset) |
| 298 | { |
| 299 | UINT8 incoming = 0; |
| 300 | |
| 301 | switch (offset) |
| 302 | { |
| 303 | case 0: |
| 304 | incoming = read_p0(); |
| 305 | break; |
| 306 | |
| 307 | case 1: |
| 308 | incoming = read_p1(); |
| 309 | break; |
| 310 | |
| 311 | case 2: |
| 312 | incoming = read_p2(); |
| 313 | break; |
| 314 | |
| 315 | case 3: |
| 316 | incoming = read_p3(); |
| 317 | break; |
| 318 | } |
| 319 | |
| 320 | // apply data direction registers |
| 321 | incoming &= (m_ddrs[offset] ^ 0xff); |
| 322 | // OR in ddr-masked version of port writes |
| 323 | incoming |= (m_ports[offset] & m_ddrs[offset]); |
| 324 | |
| 325 | return incoming; |
| 326 | } |
| 327 | |
| 328 | READ8_MEMBER(m5074x_device::ports_r) |
| 329 | { |
| 330 | switch (offset) |
| 331 | { |
| 332 | case 0: |
| 333 | return read_port(0); |
| 334 | |
| 335 | case 1: |
| 336 | return m_ddrs[0]; |
| 337 | |
| 338 | case 2: |
| 339 | return read_port(1); |
| 340 | |
| 341 | case 3: |
| 342 | return m_ddrs[1]; |
| 343 | |
| 344 | case 4: |
| 345 | return read_port(2); |
| 346 | |
| 347 | case 5: |
| 348 | return m_ddrs[2]; |
| 349 | |
| 350 | case 8: |
| 351 | return read_port(3); |
| 352 | |
| 353 | case 9: |
| 354 | return m_ddrs[3]; |
| 355 | } |
| 356 | |
| 357 | return 0xff; |
| 358 | } |
| 359 | |
| 360 | WRITE8_MEMBER(m5074x_device::ports_w) |
| 361 | { |
| 362 | switch (offset) |
| 363 | { |
| 364 | case 0: // p0 |
| 365 | send_port(space, 0, data & m_ddrs[0]); |
| 366 | m_ports[0] = data; |
| 367 | break; |
| 368 | |
| 369 | case 1: // p0 ddr |
| 370 | send_port(space, 0, m_ports[0] & data); |
| 371 | m_ddrs[0] = data; |
| 372 | break; |
| 373 | |
| 374 | case 2: // p1 |
| 375 | send_port(space, 1, data & m_ddrs[1]); |
| 376 | m_ports[1] = data; |
| 377 | break; |
| 378 | |
| 379 | case 3: // p1 ddr |
| 380 | send_port(space, 1, m_ports[1] & data); |
| 381 | m_ddrs[1] = data; |
| 382 | break; |
| 383 | |
| 384 | case 4: // p2 |
| 385 | send_port(space, 2, data & m_ddrs[2]); |
| 386 | m_ports[2] = data; |
| 387 | break; |
| 388 | |
| 389 | case 5: // p2 ddr |
| 390 | send_port(space, 2, m_ports[2] & data); |
| 391 | m_ddrs[2] = data; |
| 392 | break; |
| 393 | |
| 394 | case 8: // p3 |
| 395 | send_port(space, 3, data & m_ddrs[3]); |
| 396 | m_ports[3] = data; |
| 397 | break; |
| 398 | |
| 399 | case 9: // p3 ddr |
| 400 | send_port(space, 3, m_ports[3] & data); |
| 401 | m_ddrs[3] = data; |
| 402 | break; |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | READ8_MEMBER(m5074x_device::tmrirq_r) |
| 407 | { |
| 408 | switch (offset) |
| 409 | { |
| 410 | case 0: |
| 411 | return m_tmr12pre; |
| 412 | |
| 413 | case 1: |
| 414 | return m_tmr1; |
| 415 | |
| 416 | case 2: |
| 417 | return m_tmr2; |
| 418 | |
| 419 | case 3: |
| 420 | return m_tmrxpre; |
| 421 | |
| 422 | case 4: |
| 423 | return m_tmrx; |
| 424 | |
| 425 | case 5: |
| 426 | return m_intctrl; |
| 427 | |
| 428 | case 6: |
| 429 | return m_tmrctrl; |
| 430 | } |
| 431 | |
| 432 | return 0xff; |
| 433 | } |
| 434 | |
| 435 | WRITE8_MEMBER(m5074x_device::tmrirq_w) |
| 436 | { |
| 437 | // printf("%02x to tmrirq @ %d\n", data, offset); |
| 438 | |
| 439 | switch (offset) |
| 440 | { |
| 441 | case 0: |
| 442 | m_tmr12pre = data; |
| 443 | recalc_timer(0); |
| 444 | recalc_timer(1); |
| 445 | break; |
| 446 | |
| 447 | case 1: |
| 448 | m_tmr1 = m_tmr1latch = data; |
| 449 | break; |
| 450 | |
| 451 | case 2: |
| 452 | m_tmr2 = m_tmr2latch = data; |
| 453 | break; |
| 454 | |
| 455 | case 3: |
| 456 | m_tmrxpre = m_tmrxlatch = data; |
| 457 | recalc_timer(2); |
| 458 | break; |
| 459 | |
| 460 | case 4: |
| 461 | m_tmrx = data; |
| 462 | break; |
| 463 | |
| 464 | case 5: |
| 465 | m_intctrl = data; |
| 466 | recalc_irqs(); |
| 467 | break; |
| 468 | |
| 469 | case 6: |
| 470 | m_tmrctrl = data; |
| 471 | recalc_irqs(); |
| 472 | break; |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | /* M50740 - baseline for this familiy */ |
| 477 | static ADDRESS_MAP_START( m50740_map, AS_PROGRAM, 8, m50740_device ) |
| 478 | ADDRESS_MAP_GLOBAL_MASK(0x1fff) |
| 479 | AM_RANGE(0x0000, 0x005f) AM_RAM |
| 480 | AM_RANGE(0x00e0, 0x00e9) AM_READWRITE(ports_r, ports_w) |
| 481 | AM_RANGE(0x00f9, 0x00ff) AM_READWRITE(tmrirq_r, tmrirq_w) |
| 482 | AM_RANGE(0x1400, 0x1fff) AM_ROM AM_REGION(":m50740", 0) |
| 483 | ADDRESS_MAP_END |
| 484 | |
| 485 | m50740_device::m50740_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 486 | m5074x_device(mconfig, M50740, "Mitsubishi M50740", tag, owner, clock, ADDRESS_MAP_NAME(m50740_map)) |
| 487 | { |
| 488 | } |
| 489 | |
| 490 | m50740_device::m50740_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : |
| 491 | m5074x_device(mconfig, type, name, tag, owner, clock, ADDRESS_MAP_NAME(m50740_map)) |
| 492 | { |
| 493 | } |
| 494 | |
| 495 | /* M50741 - 50740 with a larger internal ROM */ |
| 496 | static ADDRESS_MAP_START( m50741_map, AS_PROGRAM, 8, m50741_device ) |
| 497 | ADDRESS_MAP_GLOBAL_MASK(0x1fff) |
| 498 | AM_RANGE(0x0000, 0x005f) AM_RAM |
| 499 | AM_RANGE(0x00e0, 0x00e9) AM_READWRITE(ports_r, ports_w) |
| 500 | AM_RANGE(0x00f9, 0x00ff) AM_READWRITE(tmrirq_r, tmrirq_w) |
| 501 | AM_RANGE(0x1000, 0x1fff) AM_ROM AM_REGION(":m50741", 0) |
| 502 | ADDRESS_MAP_END |
| 503 | |
| 504 | m50741_device::m50741_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : |
| 505 | m5074x_device(mconfig, M50740, "Mitsubishi M50741", tag, owner, clock, ADDRESS_MAP_NAME(m50741_map)) |
| 506 | { |
| 507 | } |
| 508 | |
| 509 | m50741_device::m50741_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock) : |
| 510 | m5074x_device(mconfig, type, name, tag, owner, clock, ADDRESS_MAP_NAME(m50741_map)) |
| 511 | { |
| 512 | } |
| 513 | |
trunk/src/emu/cpu/m6502/m5074x.h
| r0 | r22067 | |
| 1 | #pragma once |
| 2 | |
| 3 | #ifndef __M5074X_H__ |
| 4 | #define __M5074X_H__ |
| 5 | |
| 6 | #include "m740.h" |
| 7 | |
| 8 | //************************************************************************** |
| 9 | // INTERFACE CONFIGURATION MACROS |
| 10 | //************************************************************************** |
| 11 | |
| 12 | #define MCFG_M5074X_PORT0_CALLBACKS(_read, _write) \ |
| 13 | downcast<m5074x_device *>(device)->set_p0_callbacks(DEVCB2_##_read, DEVCB2_##_write); |
| 14 | |
| 15 | #define MCFG_M5074X_PORT1_CALLBACKS(_read, _write) \ |
| 16 | downcast<m5074x_device *>(device)->set_p1_callbacks(DEVCB2_##_read, DEVCB2_##_write); |
| 17 | |
| 18 | #define MCFG_M5074X_PORT2_CALLBACKS(_read, _write) \ |
| 19 | downcast<m5074x_device *>(device)->set_p2_callbacks(DEVCB2_##_read, DEVCB2_##_write); |
| 20 | |
| 21 | #define MCFG_M5074X_PORT3_CALLBACKS(_read, _write) \ |
| 22 | downcast<m5074x_device *>(device)->set_p3_callbacks(DEVCB2_##_read, DEVCB2_##_write); |
| 23 | |
| 24 | //************************************************************************** |
| 25 | // TYPE DEFINITIONS |
| 26 | //************************************************************************** |
| 27 | |
| 28 | // ======================> m5074x_device |
| 29 | |
| 30 | class m5074x_device : public m740_device |
| 31 | { |
| 32 | friend class m50740_device; |
| 33 | friend class m50741_device; |
| 34 | |
| 35 | enum |
| 36 | { |
| 37 | M5074X_INT1_LINE = INPUT_LINE_IRQ0, |
| 38 | |
| 39 | M5074X_SET_OVERFLOW = M740_SET_OVERFLOW |
| 40 | }; |
| 41 | |
| 42 | enum |
| 43 | { |
| 44 | TIMER_1 = 0, |
| 45 | TIMER_2, |
| 46 | TIMER_X, |
| 47 | |
| 48 | NUM_TIMERS |
| 49 | }; |
| 50 | |
| 51 | public: |
| 52 | // construction/destruction |
| 53 | m5074x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, address_map_constructor internal_map); |
| 54 | |
| 55 | const address_space_config m_program_config; |
| 56 | |
| 57 | template<class _read, class _write> void set_p0_callbacks(_read rd, _write wr) |
| 58 | { |
| 59 | read_p0.set_callback(rd); |
| 60 | write_p0.set_callback(wr); |
| 61 | } |
| 62 | |
| 63 | template<class _read, class _write> void set_p1_callbacks(_read rd, _write wr) |
| 64 | { |
| 65 | read_p1.set_callback(rd); |
| 66 | write_p1.set_callback(wr); |
| 67 | } |
| 68 | |
| 69 | template<class _read, class _write> void set_p2_callbacks(_read rd, _write wr) |
| 70 | { |
| 71 | read_p2.set_callback(rd); |
| 72 | write_p2.set_callback(wr); |
| 73 | } |
| 74 | |
| 75 | template<class _read, class _write> void set_p3_callbacks(_read rd, _write wr) |
| 76 | { |
| 77 | read_p3.set_callback(rd); |
| 78 | write_p3.set_callback(wr); |
| 79 | } |
| 80 | |
| 81 | devcb2_read8 read_p0, read_p1, read_p2, read_p3; |
| 82 | devcb2_write8 write_p0, write_p1, write_p2, write_p3; |
| 83 | |
| 84 | DECLARE_READ8_MEMBER(ports_r); |
| 85 | DECLARE_WRITE8_MEMBER(ports_w); |
| 86 | DECLARE_READ8_MEMBER(tmrirq_r); |
| 87 | DECLARE_WRITE8_MEMBER(tmrirq_w); |
| 88 | |
| 89 | bool are_port_bits_output(UINT8 port, UINT8 mask) { return ((m_ddrs[port] & mask) == mask) ? true : false; } |
| 90 | |
| 91 | protected: |
| 92 | // device-level overrides |
| 93 | virtual void device_start(); |
| 94 | virtual void device_reset(); |
| 95 | virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); |
| 96 | virtual void device_config_complete(); |
| 97 | virtual void execute_set_input(int inputnum, int state); |
| 98 | virtual const address_space_config *memory_space_config(address_spacenum spacenum) const { return (spacenum == AS_PROGRAM) ? &m_program_config : NULL; } |
| 99 | |
| 100 | void send_port(address_space &space, UINT8 offset, UINT8 data); |
| 101 | UINT8 read_port(UINT8 offset); |
| 102 | |
| 103 | void recalc_irqs(); |
| 104 | void recalc_timer(int timer); |
| 105 | |
| 106 | UINT8 m_ports[6], m_ddrs[6]; |
| 107 | UINT8 m_intctrl, m_tmrctrl; |
| 108 | UINT8 m_tmr12pre, m_tmr1, m_tmr2, m_tmrxpre, m_tmrx; |
| 109 | UINT8 m_tmr1latch, m_tmr2latch, m_tmrxlatch; |
| 110 | UINT8 m_last_all_ints; |
| 111 | |
| 112 | private: |
| 113 | emu_timer *m_timers[NUM_TIMERS]; |
| 114 | }; |
| 115 | |
| 116 | class m50740_device : public m5074x_device |
| 117 | { |
| 118 | public: |
| 119 | m50740_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 120 | m50740_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); |
| 121 | |
| 122 | protected: |
| 123 | |
| 124 | private: |
| 125 | }; |
| 126 | |
| 127 | class m50741_device : public m5074x_device |
| 128 | { |
| 129 | public: |
| 130 | m50741_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); |
| 131 | m50741_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock); |
| 132 | |
| 133 | protected: |
| 134 | |
| 135 | private: |
| 136 | }; |
| 137 | |
| 138 | extern const device_type M50740; |
| 139 | extern const device_type M50741; |
| 140 | |
| 141 | #endif |