src/mess/machine/8155pio.c
| r0 | r4644 | |
| 1 | /* |
| 2 | |
| 3 | TODO: |
| 4 | |
| 5 | - strobed mode |
| 6 | |
| 7 | */ |
| 8 | |
| 9 | #include "8155pio.h" |
| 10 | |
| 11 | /*************************************************************************** |
| 12 | PARAMETERS |
| 13 | ***************************************************************************/ |
| 14 | |
| 15 | enum |
| 16 | { |
| 17 | PIO8155_REGISTER_COMMAND = 0, |
| 18 | PIO8155_REGISTER_STATUS = 0, |
| 19 | PIO8155_REGISTER_PORT_A, |
| 20 | PIO8155_REGISTER_PORT_B, |
| 21 | PIO8155_REGISTER_PORT_C, |
| 22 | PIO8155_REGISTER_TIMER_LOW, |
| 23 | PIO8155_REGISTER_TIMER_HIGH |
| 24 | }; |
| 25 | |
| 26 | enum |
| 27 | { |
| 28 | PIO8155_PORT_A = 0, |
| 29 | PIO8155_PORT_B, |
| 30 | PIO8155_PORT_C, |
| 31 | PIO8155_PORT_COUNT |
| 32 | }; |
| 33 | |
| 34 | enum |
| 35 | { |
| 36 | PIO8155_PORT_MODE_INPUT = 0, |
| 37 | PIO8155_PORT_MODE_OUTPUT, |
| 38 | PIO8155_PORT_MODE_STROBED_PORT_A, /* not supported */ |
| 39 | PIO8155_PORT_MODE_STROBED /* not supported */ |
| 40 | }; |
| 41 | |
| 42 | #define PIO8155_COMMAND_PA 0x01 |
| 43 | #define PIO8155_COMMAND_PB 0x02 |
| 44 | #define PIO8155_COMMAND_PC_MASK 0x0c |
| 45 | #define PIO8155_COMMAND_PC_ALT_1 0x00 |
| 46 | #define PIO8155_COMMAND_PC_ALT_2 0x0c |
| 47 | #define PIO8155_COMMAND_PC_ALT_3 0x04 /* not supported */ |
| 48 | #define PIO8155_COMMAND_PC_ALT_4 0x08 /* not supported */ |
| 49 | #define PIO8155_COMMAND_IEA 0x10 /* not supported */ |
| 50 | #define PIO8155_COMMAND_IEB 0x20 /* not supported */ |
| 51 | #define PIO8155_COMMAND_TM_MASK 0xc0 |
| 52 | #define PIO8155_COMMAND_TM_NOP 0x00 |
| 53 | #define PIO8155_COMMAND_TM_STOP 0x40 |
| 54 | #define PIO8155_COMMAND_TM_STOP_AFTER_TC 0x80 |
| 55 | #define PIO8155_COMMAND_TM_START 0xc0 |
| 56 | |
| 57 | #define PIO8155_STATUS_INTR_A 0x01 /* not supported */ |
| 58 | #define PIO8155_STATUS_A_BF 0x02 /* not supported */ |
| 59 | #define PIO8155_STATUS_INTE_A 0x04 /* not supported */ |
| 60 | #define PIO8155_STATUS_INTR_B 0x08 /* not supported */ |
| 61 | #define PIO8155_STATUS_B_BF 0x10 /* not supported */ |
| 62 | #define PIO8155_STATUS_INTE_B 0x20 /* not supported */ |
| 63 | #define PIO8155_STATUS_TIMER 0x40 |
| 64 | |
| 65 | #define PIO8155_TIMER_MODE_MASK 0xc0 |
| 66 | #define PIO8155_TIMER_MODE_LOW 0x00 |
| 67 | #define PIO8155_TIMER_MODE_SQUARE_WAVE 0x40 |
| 68 | #define PIO8155_TIMER_MODE_SINGLE_PULSE 0x80 |
| 69 | #define PIO8155_TIMER_MODE_AUTOMATIC_RELOAD 0xc0 |
| 70 | |
| 71 | /*************************************************************************** |
| 72 | TYPE DEFINITIONS |
| 73 | ***************************************************************************/ |
| 74 | |
| 75 | typedef struct _pio8155_t pio8155_t; |
| 76 | struct _pio8155_t |
| 77 | { |
| 78 | int clock; /* timer input clock */ |
| 79 | |
| 80 | devcb_resolved_read8 in_port_func[PIO8155_PORT_COUNT]; |
| 81 | devcb_resolved_write8 out_port_func[PIO8155_PORT_COUNT]; |
| 82 | devcb_resolved_write_line out_to_func; |
| 83 | |
| 84 | /* memory */ |
| 85 | UINT8 ram[256]; /* RAM */ |
| 86 | |
| 87 | /* registers */ |
| 88 | UINT8 command; /* command register */ |
| 89 | UINT8 status; /* status register */ |
| 90 | UINT8 output[3]; /* output latches */ |
| 91 | |
| 92 | /* counter */ |
| 93 | UINT16 count_length; /* count length register */ |
| 94 | UINT16 counter; /* counter register */ |
| 95 | int to; /* timer output */ |
| 96 | |
| 97 | /* timers */ |
| 98 | emu_timer *timer; /* counter timer */ |
| 99 | }; |
| 100 | |
| 101 | /*************************************************************************** |
| 102 | INLINE FUNCTIONS |
| 103 | ***************************************************************************/ |
| 104 | |
| 105 | INLINE pio8155_t *get_safe_token(const device_config *device) |
| 106 | { |
| 107 | assert(device != NULL); |
| 108 | assert(device->token != NULL); |
| 109 | return (pio8155_t *)device->token; |
| 110 | } |
| 111 | |
| 112 | INLINE const pio8155_interface *get_interface(const device_config *device) |
| 113 | { |
| 114 | assert(device != NULL); |
| 115 | assert(device->type == PIO8155); |
| 116 | return (const pio8155_interface *) device->static_config; |
| 117 | } |
| 118 | |
| 119 | INLINE UINT8 get_timer_mode(pio8155_t *pio8155) |
| 120 | { |
| 121 | return (pio8155->count_length >> 8) & PIO8155_TIMER_MODE_MASK; |
| 122 | } |
| 123 | |
| 124 | INLINE timer_output(pio8155_t *pio8155) |
| 125 | { |
| 126 | devcb_call_write_line(&pio8155->out_to_func, pio8155->to); |
| 127 | logerror("8155 Timer Output: %u\n", pio8155->to); |
| 128 | } |
| 129 | |
| 130 | INLINE pulse_timer_output(pio8155_t *pio8155) |
| 131 | { |
| 132 | pio8155->to = 0; timer_output(pio8155); |
| 133 | pio8155->to = 1; timer_output(pio8155); |
| 134 | } |
| 135 | |
| 136 | INLINE int get_port_mode(pio8155_t *pio8155, int port) |
| 137 | { |
| 138 | int mode = -1; |
| 139 | |
| 140 | switch (port) |
| 141 | { |
| 142 | case PIO8155_PORT_A: |
| 143 | mode = (pio8155->command & PIO8155_COMMAND_PA) ? PIO8155_PORT_MODE_OUTPUT : PIO8155_PORT_MODE_INPUT; |
| 144 | break; |
| 145 | |
| 146 | case PIO8155_PORT_B: |
| 147 | mode = (pio8155->command & PIO8155_COMMAND_PB) ? PIO8155_PORT_MODE_OUTPUT : PIO8155_PORT_MODE_INPUT; |
| 148 | break; |
| 149 | |
| 150 | case PIO8155_PORT_C: |
| 151 | switch (pio8155->command & PIO8155_COMMAND_PC_MASK) |
| 152 | { |
| 153 | case PIO8155_COMMAND_PC_ALT_1: mode = PIO8155_PORT_MODE_INPUT; break; |
| 154 | case PIO8155_COMMAND_PC_ALT_2: mode = PIO8155_PORT_MODE_OUTPUT; break; |
| 155 | case PIO8155_COMMAND_PC_ALT_3: mode = PIO8155_PORT_MODE_STROBED_PORT_A; break; |
| 156 | case PIO8155_COMMAND_PC_ALT_4: mode = PIO8155_PORT_MODE_STROBED; break; |
| 157 | } |
| 158 | break; |
| 159 | } |
| 160 | |
| 161 | return mode; |
| 162 | } |
| 163 | |
| 164 | INLINE UINT8 read_port(pio8155_t *pio8155, int port) |
| 165 | { |
| 166 | UINT8 data = 0; |
| 167 | |
| 168 | switch (port) |
| 169 | { |
| 170 | case PIO8155_PORT_A: |
| 171 | case PIO8155_PORT_B: |
| 172 | switch (get_port_mode(pio8155, port)) |
| 173 | { |
| 174 | case PIO8155_PORT_MODE_INPUT: |
| 175 | data = devcb_call_read8(&pio8155->in_port_func[port], 0); |
| 176 | break; |
| 177 | |
| 178 | case PIO8155_PORT_MODE_OUTPUT: |
| 179 | data = pio8155->output[port]; |
| 180 | break; |
| 181 | } |
| 182 | break; |
| 183 | |
| 184 | case PIO8155_PORT_C: |
| 185 | switch (get_port_mode(pio8155, PIO8155_PORT_C)) |
| 186 | { |
| 187 | case PIO8155_PORT_MODE_INPUT: |
| 188 | data = devcb_call_read8(&pio8155->in_port_func[port], 0) & 0x3f; |
| 189 | break; |
| 190 | |
| 191 | case PIO8155_PORT_MODE_OUTPUT: |
| 192 | data = pio8155->output[port] & 0x3f; |
| 193 | break; |
| 194 | |
| 195 | default: |
| 196 | logerror("8155 Unsupported Port C mode!\n"); |
| 197 | } |
| 198 | break; |
| 199 | } |
| 200 | |
| 201 | return data; |
| 202 | } |
| 203 | |
| 204 | INLINE void write_port(pio8155_t *pio8155, int port, UINT8 data) |
| 205 | { |
| 206 | switch (get_port_mode(pio8155, port)) |
| 207 | { |
| 208 | case PIO8155_PORT_MODE_OUTPUT: |
| 209 | pio8155->output[port] = data; |
| 210 | devcb_call_write8(&pio8155->out_port_func[port], 0, pio8155->output[port]); |
| 211 | break; |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | /*************************************************************************** |
| 216 | IMPLEMENTATION |
| 217 | ***************************************************************************/ |
| 218 | |
| 219 | /*------------------------------------------------- |
| 220 | TIMER_CALLBACK( counter_tick ) |
| 221 | -------------------------------------------------*/ |
| 222 | |
| 223 | static TIMER_CALLBACK( counter_tick ) |
| 224 | { |
| 225 | const device_config *device = ptr; |
| 226 | pio8155_t *pio8155 = get_safe_token(device); |
| 227 | |
| 228 | /* count down */ |
| 229 | pio8155->counter--; |
| 230 | |
| 231 | if (get_timer_mode(pio8155) == PIO8155_TIMER_MODE_LOW) |
| 232 | { |
| 233 | /* pulse on every count */ |
| 234 | pulse_timer_output(pio8155); |
| 235 | } |
| 236 | |
| 237 | if (pio8155->counter == 0) |
| 238 | { |
| 239 | logerror("8155 Timer Count Reached\n"); |
| 240 | |
| 241 | switch (pio8155->command & PIO8155_COMMAND_TM_MASK) |
| 242 | { |
| 243 | case PIO8155_COMMAND_TM_STOP_AFTER_TC: |
| 244 | /* stop timer */ |
| 245 | timer_enable(pio8155->timer, 0); |
| 246 | logerror("8155 Timer Stopped\n"); |
| 247 | break; |
| 248 | } |
| 249 | |
| 250 | switch (get_timer_mode(pio8155)) |
| 251 | { |
| 252 | case PIO8155_TIMER_MODE_SQUARE_WAVE: |
| 253 | /* toggle timer output */ |
| 254 | pio8155->to = !pio8155->to; |
| 255 | timer_output(pio8155); |
| 256 | break; |
| 257 | |
| 258 | case PIO8155_TIMER_MODE_SINGLE_PULSE: |
| 259 | /* single pulse upon TC being reached */ |
| 260 | pulse_timer_output(pio8155); |
| 261 | |
| 262 | /* clear timer mode setting */ |
| 263 | pio8155->command &= ~PIO8155_COMMAND_TM_MASK; |
| 264 | break; |
| 265 | |
| 266 | case PIO8155_TIMER_MODE_AUTOMATIC_RELOAD: |
| 267 | /* automatic reload, i.e. single pulse every time TC is reached */ |
| 268 | pulse_timer_output(pio8155); |
| 269 | break; |
| 270 | } |
| 271 | |
| 272 | /* set timer flag */ |
| 273 | pio8155->status |= PIO8155_STATUS_TIMER; |
| 274 | |
| 275 | /* reload timer counter */ |
| 276 | pio8155->counter = pio8155->count_length & 0x3fff; |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | /*------------------------------------------------- |
| 281 | pio8155_register_r - register read |
| 282 | -------------------------------------------------*/ |
| 283 | |
| 284 | READ8_DEVICE_HANDLER( pio8155_r ) |
| 285 | { |
| 286 | pio8155_t *pio8155 = get_safe_token(device); |
| 287 | |
| 288 | UINT8 data = 0; |
| 289 | |
| 290 | switch (offset & 0x03) |
| 291 | { |
| 292 | case PIO8155_REGISTER_STATUS: |
| 293 | data = pio8155->status; |
| 294 | |
| 295 | /* clear timer flag */ |
| 296 | pio8155->status &= ~PIO8155_STATUS_TIMER; |
| 297 | break; |
| 298 | |
| 299 | case PIO8155_REGISTER_PORT_A: |
| 300 | data = read_port(pio8155, PIO8155_PORT_A); |
| 301 | break; |
| 302 | |
| 303 | case PIO8155_REGISTER_PORT_B: |
| 304 | data = read_port(pio8155, PIO8155_PORT_B); |
| 305 | break; |
| 306 | |
| 307 | case PIO8155_REGISTER_PORT_C: |
| 308 | data = read_port(pio8155, PIO8155_PORT_C); |
| 309 | break; |
| 310 | } |
| 311 | |
| 312 | return data; |
| 313 | } |
| 314 | |
| 315 | /*------------------------------------------------- |
| 316 | pio8155_register_w - register write |
| 317 | -------------------------------------------------*/ |
| 318 | |
| 319 | WRITE8_DEVICE_HANDLER( pio8155_w ) |
| 320 | { |
| 321 | pio8155_t *pio8155 = get_safe_token(device); |
| 322 | |
| 323 | switch (offset & 0x07) |
| 324 | { |
| 325 | case PIO8155_REGISTER_COMMAND: |
| 326 | pio8155->command = data; |
| 327 | |
| 328 | logerror("8155 Port A Mode: %s\n", (data & PIO8155_COMMAND_PA) ? "output" : "input"); |
| 329 | logerror("8155 Port B Mode: %s\n", (data & PIO8155_COMMAND_PB) ? "output" : "input"); |
| 330 | |
| 331 | logerror("8155 Port A Interrupt: %s\n", (data & PIO8155_COMMAND_IEA) ? "enabled" : "disabled"); |
| 332 | logerror("8155 Port B Interrupt: %s\n", (data & PIO8155_COMMAND_IEB) ? "enabled" : "disabled"); |
| 333 | |
| 334 | switch (data & PIO8155_COMMAND_PC_MASK) |
| 335 | { |
| 336 | case PIO8155_COMMAND_PC_ALT_1: |
| 337 | logerror("8155 Port C Mode: Alt 1\n"); |
| 338 | break; |
| 339 | |
| 340 | case PIO8155_COMMAND_PC_ALT_2: |
| 341 | logerror("8155 Port C Mode: Alt 2\n"); |
| 342 | break; |
| 343 | |
| 344 | case PIO8155_COMMAND_PC_ALT_3: |
| 345 | logerror("8155 Port C Mode: Alt 3\n"); |
| 346 | break; |
| 347 | |
| 348 | case PIO8155_COMMAND_PC_ALT_4: |
| 349 | logerror("8155 Port C Mode: Alt 4\n"); |
| 350 | break; |
| 351 | } |
| 352 | |
| 353 | switch (data & PIO8155_COMMAND_TM_MASK) |
| 354 | { |
| 355 | case PIO8155_COMMAND_TM_NOP: |
| 356 | /* do not affect counter operation */ |
| 357 | break; |
| 358 | |
| 359 | case PIO8155_COMMAND_TM_STOP: |
| 360 | /* NOP if timer has not started, stop counting if the timer is running */ |
| 361 | logerror("8155 Timer Command: Stop\n"); |
| 362 | timer_enable(pio8155->timer, 0); |
| 363 | break; |
| 364 | |
| 365 | case PIO8155_COMMAND_TM_STOP_AFTER_TC: |
| 366 | /* stop immediately after present TC is reached (NOP if timer has not started) */ |
| 367 | logerror("8155 Timer Command: Stop after TC\n"); |
| 368 | break; |
| 369 | |
| 370 | case PIO8155_COMMAND_TM_START: |
| 371 | logerror("8155 Timer Command: Start\n"); |
| 372 | |
| 373 | if (timer_enabled(pio8155->timer)) |
| 374 | { |
| 375 | /* if timer is running, start the new mode and CNT length immediately after present TC is reached */ |
| 376 | } |
| 377 | else |
| 378 | { |
| 379 | /* load mode and CNT length and start immediately after loading (if timer is not running) */ |
| 380 | pio8155->counter = pio8155->count_length; |
| 381 | timer_adjust_periodic(pio8155->timer, attotime_zero, 0, ATTOTIME_IN_HZ(pio8155->clock)); |
| 382 | } |
| 383 | break; |
| 384 | } |
| 385 | break; |
| 386 | |
| 387 | case PIO8155_REGISTER_PORT_A: |
| 388 | write_port(pio8155, PIO8155_PORT_A, data); |
| 389 | break; |
| 390 | |
| 391 | case PIO8155_REGISTER_PORT_B: |
| 392 | write_port(pio8155, PIO8155_PORT_B, data); |
| 393 | break; |
| 394 | |
| 395 | case PIO8155_REGISTER_PORT_C: |
| 396 | write_port(pio8155, PIO8155_PORT_C, data); |
| 397 | break; |
| 398 | |
| 399 | case PIO8155_REGISTER_TIMER_LOW: |
| 400 | pio8155->count_length = (pio8155->count_length & 0xff00) | data; |
| 401 | logerror("8155 Count Length Low: %04x\n", pio8155->count_length); |
| 402 | break; |
| 403 | |
| 404 | case PIO8155_REGISTER_TIMER_HIGH: |
| 405 | pio8155->count_length = (data << 8) | (pio8155->count_length & 0xff); |
| 406 | logerror("8155 Count Length High: %04x\n", pio8155->count_length); |
| 407 | |
| 408 | switch (data & PIO8155_TIMER_MODE_MASK) |
| 409 | { |
| 410 | case PIO8155_TIMER_MODE_LOW: |
| 411 | /* puts out LOW during second half of count */ |
| 412 | logerror("8155 Timer Mode: LOW\n"); |
| 413 | break; |
| 414 | |
| 415 | case PIO8155_TIMER_MODE_SQUARE_WAVE: |
| 416 | /* square wave, i.e. the period of the square wave equals the count length programmed with automatic reload at terminal count */ |
| 417 | logerror("8155 Timer Mode: Square wave\n"); |
| 418 | break; |
| 419 | |
| 420 | case PIO8155_TIMER_MODE_SINGLE_PULSE: |
| 421 | /* single pulse upon TC being reached */ |
| 422 | logerror("8155 Timer Mode: Single pulse\n"); |
| 423 | break; |
| 424 | |
| 425 | case PIO8155_TIMER_MODE_AUTOMATIC_RELOAD: |
| 426 | /* automatic reload, i.e. single pulse every time TC is reached */ |
| 427 | logerror("8155 Timer Mode: Automatic reload\n"); |
| 428 | break; |
| 429 | } |
| 430 | break; |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | /*------------------------------------------------- |
| 435 | pio8155_ram_r - memory read |
| 436 | -------------------------------------------------*/ |
| 437 | |
| 438 | READ8_DEVICE_HANDLER( pio8155_ram_r ) |
| 439 | { |
| 440 | pio8155_t *pio8155 = get_safe_token(device); |
| 441 | |
| 442 | return pio8155->ram[offset & 0xff]; |
| 443 | } |
| 444 | |
| 445 | /*------------------------------------------------- |
| 446 | pio8155_ram_w - memory write |
| 447 | -------------------------------------------------*/ |
| 448 | |
| 449 | WRITE8_DEVICE_HANDLER( pio8155_ram_w ) |
| 450 | { |
| 451 | pio8155_t *pio8155 = get_safe_token(device); |
| 452 | |
| 453 | pio8155->ram[offset & 0xff] = data; |
| 454 | } |
| 455 | |
| 456 | /*------------------------------------------------- |
| 457 | DEVICE_START( pio8155 ) |
| 458 | -------------------------------------------------*/ |
| 459 | |
| 460 | static DEVICE_START( pio8155 ) |
| 461 | { |
| 462 | pio8155_t *pio8155 = device->token; |
| 463 | const pio8155_interface *intf = get_interface(device); |
| 464 | |
| 465 | /* resolve callbacks */ |
| 466 | devcb_resolve_read8(&pio8155->in_port_func[0], &intf->in_pa_func, device); |
| 467 | devcb_resolve_read8(&pio8155->in_port_func[1], &intf->in_pb_func, device); |
| 468 | devcb_resolve_read8(&pio8155->in_port_func[2], &intf->in_pc_func, device); |
| 469 | devcb_resolve_write8(&pio8155->out_port_func[0], &intf->out_pa_func, device); |
| 470 | devcb_resolve_write8(&pio8155->out_port_func[1], &intf->out_pb_func, device); |
| 471 | devcb_resolve_write8(&pio8155->out_port_func[2], &intf->out_pc_func, device); |
| 472 | devcb_resolve_write_line(&pio8155->out_to_func, &intf->out_to_func, device); |
| 473 | |
| 474 | /* create the timers */ |
| 475 | pio8155->timer = timer_alloc(device->machine, counter_tick, (void *)device); |
| 476 | |
| 477 | /* register for state saving */ |
| 478 | state_save_register_device_item(device, 0, pio8155->command); |
| 479 | state_save_register_device_item(device, 0, pio8155->status); |
| 480 | state_save_register_device_item_array(device, 0, pio8155->output); |
| 481 | state_save_register_device_item(device, 0, pio8155->count_length); |
| 482 | state_save_register_device_item(device, 0, pio8155->counter); |
| 483 | state_save_register_device_item_array(device, 0, pio8155->ram); |
| 484 | state_save_register_device_item(device, 0, pio8155->to); |
| 485 | } |
| 486 | |
| 487 | /*------------------------------------------------- |
| 488 | DEVICE_RESET( pio8155 ) |
| 489 | -------------------------------------------------*/ |
| 490 | |
| 491 | static DEVICE_RESET( pio8155 ) |
| 492 | { |
| 493 | pio8155_t *pio8155 = device->token; |
| 494 | |
| 495 | /* clear output registers */ |
| 496 | pio8155->output[PIO8155_PORT_A] = 0; |
| 497 | pio8155->output[PIO8155_PORT_B] = 0; |
| 498 | pio8155->output[PIO8155_PORT_C] = 0; |
| 499 | |
| 500 | /* set ports to input mode */ |
| 501 | pio8155_w(device, PIO8155_REGISTER_COMMAND, pio8155->command & ~(PIO8155_COMMAND_PA | PIO8155_COMMAND_PB | PIO8155_COMMAND_PC_MASK)); |
| 502 | |
| 503 | /* clear timer flag */ |
| 504 | pio8155->status &= ~PIO8155_STATUS_TIMER; |
| 505 | |
| 506 | /* stop counting */ |
| 507 | timer_enable(pio8155->timer, 0); |
| 508 | |
| 509 | /* clear timer output */ |
| 510 | pio8155->to = 1; |
| 511 | timer_output(pio8155); |
| 512 | } |
| 513 | |
| 514 | /*------------------------------------------------- |
| 515 | DEVICE_GET_INFO( pio8155 ) |
| 516 | -------------------------------------------------*/ |
| 517 | |
| 518 | DEVICE_GET_INFO( pio8155 ) |
| 519 | { |
| 520 | switch (state) |
| 521 | { |
| 522 | /* --- the following bits of info are returned as 64-bit signed integers --- */ |
| 523 | case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; |
| 524 | case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break; |
| 525 | case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(pio8155_t); break; |
| 526 | |
| 527 | /* --- the following bits of info are returned as pointers to data or functions --- */ |
| 528 | case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(pio8155); break; |
| 529 | case DEVINFO_FCT_STOP: /* Nothing */ break; |
| 530 | case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(pio8155); break; |
| 531 | |
| 532 | /* --- the following bits of info are returned as NULL-terminated strings --- */ |
| 533 | case DEVINFO_STR_NAME: strcpy(info->s, "OKI MSM81C55"); break; |
| 534 | case DEVINFO_STR_FAMILY: strcpy(info->s, "8155"); break; |
| 535 | case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; |
| 536 | case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; |
| 537 | case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break; |
| 538 | } |
| 539 | } |
src/mess/drivers/kyocera.c
| r4643 | r4644 | |
| 26 | 26 | * what are the differences between available BIOSes for trsm100 and olivm10? |
| 27 | 27 | * Tandy Model 200 support (video emulation completely different, but also |
| 28 | 28 | memory map & IO have to be adapted) |
| 29 | | * PIO8155 might be made an independent device |
| 30 | 29 | * clean up driver and split machine & video parts |
| 31 | 30 | |
| 32 | 31 | - Find dumps of systems which could easily be added: |
| r4643 | r4644 | |
| 43 | 42 | #include "driver.h" |
| 44 | 43 | #include "cpu/i8085/i8085.h" |
| 45 | 44 | #include "machine/upd1990a.h" |
| 45 | #include "machine/8155pio.h" |
| 46 | 46 | |
| 47 | 47 | static UINT8 rom_page, ram_page; |
| 48 | 48 | static UINT8 port_a, port_b, port_c; |
| r4643 | r4644 | |
| 158 | 158 | io_A1 = data & 0x0f; |
| 159 | 159 | } |
| 160 | 160 | |
| 161 | | // 0xB8 |
| 162 | | static WRITE8_HANDLER( pio8155_status_write ) |
| 163 | | { |
| 164 | | // enable-disable |
| 165 | | /* |
| 166 | | Bit: |
| 167 | | 0 - Direction of Port A (0-input, 1-output) |
| 168 | | 1 - Direction of Port B (0-input, 1-output) |
| 169 | | 2 & 3 - Port C definition (00 - All input, 11 - All output, |
| 170 | | 01 - Alt 3, 10 - Alt 4 (see Intel technical sheets |
| 171 | | for more information)) |
| 172 | | 4 - Enable Port A interrupt (1 - enable) |
| 173 | | 5 - Enable Port B interrupt (1 - enable) |
| 174 | | 6 & 7 - Timer mode (00 - No effect on counter, 01 - Stop |
| 175 | | counter immediately, 10 - Stop counter after TC, 11 |
| 176 | | - Start counter) */ |
| 177 | | } |
| 178 | | |
| 179 | | // 0xB9 |
| 180 | | static WRITE8_HANDLER( pio8155_portA_write ) |
| 181 | | { |
| 182 | | port_a = data; |
| 183 | | lcd_bank_update( port_a | ((port_b & 3) << 8) ); |
| 184 | | |
| 185 | | /* |
| 186 | | The first 5 bits of this port is used to control the 1990 real time clock chip. |
| 187 | | The configuration of these five bits are: |
| 188 | | Bit: |
| 189 | | 0 - C0 |
| 190 | | 1 - C1 |
| 191 | | 2 - C2 |
| 192 | | 3 - Clock |
| 193 | | 4 - Serial data into clock chip */ |
| 194 | | if ((data & 0x08) != (port_a & 0x08)) |
| 195 | | { |
| 196 | | const device_config *rtc = devtag_get_device(space->machine, "rtc"); |
| 197 | | upd1990a_clk_w(rtc, offset, data); |
| 198 | | logerror("CLK write %d\n", data); |
| 199 | | } |
| 200 | | } |
| 201 | | |
| 202 | | // 0xBA |
| 203 | | static WRITE8_HANDLER( pio8155_portB_write ) |
| 204 | | { |
| 205 | | /* |
| 206 | | Bit: |
| 207 | | 0 - Column 9 select line for keyboard. This line is |
| 208 | | also used for the CS-28 line of the LCD. |
| 209 | | 1 - CS 29 line of LCD |
| 210 | | 2 - Beep toggle (1-Data from bit 5, 0-Data from 8155 |
| 211 | | timer) |
| 212 | | 3 - Serial toggle (1-Modem, 0-RS232) |
| 213 | | 4 - Software on/off switch for computer |
| 214 | | 5 - Data to beeper if bit 2 set. Set if bit 2 low. |
| 215 | | 6 - DTR (not) line for RS232 |
| 216 | | 7 - RTS (not) line for RS232 */ |
| 217 | | port_b = data; |
| 218 | | lcd_bank_update( port_a | ((port_b & 3) << 8) ); |
| 219 | | } |
| 220 | | |
| 221 | | // 0xBB |
| 222 | | static WRITE8_HANDLER( pio8155_portC_write ) |
| 223 | | { |
| 224 | | port_c = data; |
| 225 | | } |
| 226 | | |
| 227 | | // 0xBC |
| 228 | | static WRITE8_HANDLER( pio8155_timer_lsb_write ) |
| 229 | | { |
| 230 | | timer_lsb = data; |
| 231 | | } |
| 232 | | |
| 233 | | // 0xBD |
| 234 | | static WRITE8_HANDLER( pio8155_timer_msb_write ) |
| 235 | | { |
| 236 | | UINT8 timer_counter = 0; |
| 237 | | |
| 238 | | timer_msb = data; |
| 239 | | timer_counter = (timer_lsb | (timer_msb & 0x3f) << 8); |
| 240 | | |
| 241 | | // set serial baud |
| 242 | | } |
| 243 | | |
| 244 | | |
| 245 | 161 | // 0xC0->0xCF |
| 246 | 162 | // serial write byet |
| 247 | 163 | |
| r4643 | r4644 | |
| 410 | 326 | return io_A1; |
| 411 | 327 | } |
| 412 | 328 | |
| 413 | | // 0xB8 |
| 414 | | static READ8_HANDLER( pio8155_status_read ) |
| 415 | | { |
| 416 | | /* |
| 417 | | Bit: |
| 418 | | 0 - Port A interrupt request |
| 419 | | 1 - Port A buffer full/empty (input/output) |
| 420 | | 2 - Port A interrupt enabled |
| 421 | | 3 - Port B interrupt request |
| 422 | | 4 - Port B buffer full/empty (input/output) |
| 423 | | 5 - Port B interrupt enabled |
| 424 | | 6 - Timer interrupt (status of TC pin) |
| 425 | | 7 - Not used */ |
| 426 | | |
| 427 | | /* Force TC high */ |
| 428 | | return 0x89; |
| 429 | | } |
| 430 | | |
| 431 | | // 0xB9 |
| 432 | | static READ8_HANDLER( pio8155_portA_read ) |
| 433 | | { |
| 434 | | return port_a; |
| 435 | | } |
| 436 | | |
| 437 | | // 0xBA |
| 438 | | static READ8_HANDLER( pio8155_portB_read ) |
| 439 | | { |
| 440 | | return port_b; |
| 441 | | } |
| 442 | | |
| 443 | | // 0xBB |
| 444 | | static READ8_HANDLER( pio8155_portC_read ) |
| 445 | | { |
| 446 | | const device_config *rtc = devtag_get_device(space->machine, "rtc"); |
| 447 | | port_c = (port_c & ~0x01) | upd1990a_data_out_r(rtc, offset); |
| 448 | | |
| 449 | | return port_c; |
| 450 | | /* |
| 451 | | Bits: |
| 452 | | 0 - Serial data input from clock chip |
| 453 | | 1 - Busy (not) signal from printer |
| 454 | | 2 - Busy signal from printer |
| 455 | | 3 - Data from BCR |
| 456 | | 4 - CTS (not) line from RS232 |
| 457 | | 5 - DSR (not) line from RS232 |
| 458 | | 6-7 - Not avaiable on 8155 */ |
| 459 | | } |
| 460 | | |
| 461 | | // 0xBC |
| 462 | | // 0xBD |
| 463 | | static READ8_HANDLER( pio8155_timer_read ) |
| 464 | | { |
| 465 | | logerror("kyocera timer r: %04x\n", offset); |
| 466 | | return 0; |
| 467 | | } |
| 468 | | |
| 469 | 329 | // 0xC0->0xCF all systems but T200 |
| 470 | 330 | // serial read byte |
| 471 | 331 | |
| r4643 | r4644 | |
| 557 | 417 | AM_RANGE(0x82, 0x82) AM_READ( io82_read ) |
| 558 | 418 | AM_RANGE(0x83, 0x9f) AM_READWRITE( unk_read, unk_write ) |
| 559 | 419 | AM_RANGE(0xa0, 0xa0) AM_READWRITE( modem_control_port_read, modem_control_port_write ) |
| 560 | | AM_RANGE(0xb9, 0xb9) AM_READWRITE( pio8155_portA_read, pio8155_portA_write ) |
| 561 | | AM_RANGE(0xba, 0xba) AM_READWRITE( pio8155_portB_read, pio8155_portB_write ) |
| 562 | | AM_RANGE(0xbb, 0xbb) AM_READWRITE( pio8155_portC_read, pio8155_portC_write ) |
| 563 | | AM_RANGE(0xbc, 0xbd) AM_READ( pio8155_timer_read ) // currently, this only logs read attempts |
| 564 | | AM_RANGE(0xbc, 0xbc) AM_WRITE( pio8155_timer_lsb_write ) // these should set serial comms but it's not yet implemented |
| 565 | | AM_RANGE(0xbd, 0xbd) AM_WRITE( pio8155_timer_msb_write ) |
| 420 | AM_RANGE(0xb8, 0xbf) AM_DEVREADWRITE( "pio8155", pio8155_r, pio8155_w ) |
| 566 | 421 | AM_RANGE(0xd8, 0xd8) AM_READ( uart_read ) |
| 567 | 422 | AM_RANGE(0xe0, 0xe8) AM_READ( keyboard_read ) |
| 568 | 423 | AM_RANGE(0xe0, 0xe8) AM_READWRITE( keyboard_read, ioE8_write ) |
| r4643 | r4644 | |
| 575 | 430 | AM_RANGE(0x90, 0x90) AM_WRITE( pc8201_io90_write ) |
| 576 | 431 | AM_RANGE(0xa0, 0xa0) AM_READWRITE( pc8201_ioa0_read, modem_control_port_write ) |
| 577 | 432 | AM_RANGE(0xa1, 0xa1) AM_READWRITE( pc8201_bank_read, pc8201_bank_write ) |
| 578 | | AM_RANGE(0xb8, 0xb8) AM_READWRITE( pio8155_status_read, pio8155_status_write ) |
| 579 | | AM_RANGE(0xb9, 0xb9) AM_READWRITE( pio8155_portA_read, pio8155_portA_write ) |
| 580 | | AM_RANGE(0xba, 0xba) AM_READWRITE( pio8155_portB_read, pio8155_portB_write ) |
| 581 | | AM_RANGE(0xbb, 0xbb) AM_READWRITE( pio8155_portC_read, pio8155_portC_write ) |
| 582 | | AM_RANGE(0xbc, 0xbd) AM_READ( pio8155_timer_read ) // currently, this only logs read attempts |
| 583 | | AM_RANGE(0xbc, 0xbc) AM_WRITE( pio8155_timer_lsb_write ) // these should set serial comms but it's not yet implemented |
| 584 | | AM_RANGE(0xbd, 0xbd) AM_WRITE( pio8155_timer_msb_write ) |
| 433 | AM_RANGE(0xb8, 0xbf) AM_DEVREADWRITE( "pio8155", pio8155_r, pio8155_w ) |
| 585 | 434 | AM_RANGE(0xd8, 0xd8) AM_READ( uart_read ) |
| 586 | 435 | AM_RANGE(0xe0, 0xe8) AM_READ( keyboard_read ) |
| 587 | 436 | // AM_RANGE(0xe0, 0xe8) AM_READWRITE( keyboard_read, ioE8_write ) |
| r4643 | r4644 | |
| 596 | 445 | // AM_RANGE(0x90, 0x90) AM_WRITE( trs200_clock_mode_write ) |
| 597 | 446 | // AM_RANGE(0x91, 0x9f) AM_READWRITE( unk_read, unk_write ) |
| 598 | 447 | AM_RANGE(0xa0, 0xa0) AM_READWRITE( modem_control_port_read, modem_control_port_write ) |
| 599 | | AM_RANGE(0xb9, 0xb9) AM_READWRITE( pio8155_portA_read, pio8155_portA_write ) |
| 600 | | AM_RANGE(0xba, 0xba) AM_READWRITE( pio8155_portB_read, pio8155_portB_write ) |
| 601 | | AM_RANGE(0xbb, 0xbb) AM_READWRITE( pio8155_portC_read, pio8155_portC_write ) |
| 602 | | AM_RANGE(0xbc, 0xbd) AM_READ( pio8155_timer_read ) // currently, this only logs read attempts |
| 603 | | AM_RANGE(0xbc, 0xbc) AM_WRITE( pio8155_timer_lsb_write ) // these should set serial comms but it's not yet implemented |
| 604 | | AM_RANGE(0xbd, 0xbd) AM_WRITE( pio8155_timer_msb_write ) |
| 448 | AM_RANGE(0xb8, 0xbf) AM_DEVREADWRITE( "pio8155", pio8155_r, pio8155_w ) |
| 605 | 449 | AM_RANGE(0xd0, 0xdf) AM_READWRITE( trs200_bank_read, trs200_bank_write ) |
| 606 | 450 | AM_RANGE(0xe0, 0xe8) AM_READ( keyboard_read ) |
| 607 | 451 | // AM_RANGE(0xe0, 0xe8) AM_READWRITE( keyboard_read, ioE8_write ) |
| r4643 | r4644 | |
| 893 | 737 | DEVCB_CPU_INPUT_LINE("maincpu", I8085_RST75_LINE) |
| 894 | 738 | }; |
| 895 | 739 | |
| 740 | static READ8_DEVICE_HANDLER( kyocera_8155_port_c_r ) |
| 741 | { |
| 742 | const device_config *rtc = devtag_get_device(device->machine, "rtc"); |
| 743 | port_c = (port_c & ~0x01) | upd1990a_data_out_r(rtc, offset); |
| 744 | |
| 745 | return port_c; |
| 746 | /* |
| 747 | Bits: |
| 748 | 0 - Serial data input from clock chip |
| 749 | 1 - Busy (not) signal from printer |
| 750 | 2 - Busy signal from printer |
| 751 | 3 - Data from BCR |
| 752 | 4 - CTS (not) line from RS232 |
| 753 | 5 - DSR (not) line from RS232 |
| 754 | 6-7 - Not avaiable on 8155 */ |
| 755 | } |
| 756 | |
| 757 | static WRITE8_DEVICE_HANDLER( kyocera_8155_port_a_w ) |
| 758 | { |
| 759 | port_a = data; |
| 760 | lcd_bank_update( port_a | ((port_b & 3) << 8) ); |
| 761 | |
| 762 | /* |
| 763 | The first 5 bits of this port is used to control the 1990 real time clock chip. |
| 764 | The configuration of these five bits are: |
| 765 | Bit: |
| 766 | 0 - C0 |
| 767 | 1 - C1 |
| 768 | 2 - C2 |
| 769 | 3 - Clock |
| 770 | 4 - Serial data into clock chip */ |
| 771 | if ((data & 0x08) != (port_a & 0x08)) |
| 772 | { |
| 773 | const device_config *rtc = devtag_get_device(device->machine, "rtc"); |
| 774 | upd1990a_clk_w(rtc, offset, data); |
| 775 | logerror("CLK write %d\n", data); |
| 776 | } |
| 777 | } |
| 778 | |
| 779 | static WRITE8_DEVICE_HANDLER( kyocera_8155_port_b_w ) |
| 780 | { |
| 781 | /* |
| 782 | Bit: |
| 783 | 0 - Column 9 select line for keyboard. This line is |
| 784 | also used for the CS-28 line of the LCD. |
| 785 | 1 - CS 29 line of LCD |
| 786 | 2 - Beep toggle (1-Data from bit 5, 0-Data from 8155 |
| 787 | timer) |
| 788 | 3 - Serial toggle (1-Modem, 0-RS232) |
| 789 | 4 - Software on/off switch for computer |
| 790 | 5 - Data to beeper if bit 2 set. Set if bit 2 low. |
| 791 | 6 - DTR (not) line for RS232 |
| 792 | 7 - RTS (not) line for RS232 */ |
| 793 | port_b = data; |
| 794 | lcd_bank_update( port_a | ((port_b & 3) << 8) ); |
| 795 | } |
| 796 | |
| 797 | static PIO8155_INTERFACE( kyocera_8155_intf ) |
| 798 | { |
| 799 | DEVCB_NULL, /* port A read */ |
| 800 | DEVCB_NULL, /* port B read */ |
| 801 | DEVCB_HANDLER(kyocera_8155_port_c_r), /* port C read */ |
| 802 | DEVCB_HANDLER(kyocera_8155_port_a_w), /* port A write */ |
| 803 | DEVCB_HANDLER(kyocera_8155_port_b_w), /* port B write */ |
| 804 | DEVCB_NULL, /* port C write */ |
| 805 | DEVCB_NULL /* timer output */ |
| 806 | }; |
| 807 | |
| 896 | 808 | static MACHINE_DRIVER_START( kyo85 ) |
| 897 | 809 | /* basic machine hardware */ |
| 898 | 810 | MDRV_CPU_ADD("maincpu", 8085A, 2400000) |
| r4643 | r4644 | |
| 922 | 834 | // MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) |
| 923 | 835 | |
| 924 | 836 | /* devices */ |
| 837 | MDRV_PIO8155_ADD("pio8155", 2400000, kyocera_8155_intf) |
| 925 | 838 | MDRV_UPD1990A_ADD("rtc", XTAL_32_768kHz, kyocera_upd1990a_intf) |
| 926 | 839 | MACHINE_DRIVER_END |
| 927 | 840 | |