fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
at master 620 lines 11 kB view raw
1/***************************************************************************** 2 * pce * 3 *****************************************************************************/ 4 5/***************************************************************************** 6 * File name: src/cpu/e8080/e8080.c * 7 * Created: 2012-11-28 by Hampa Hug <hampa@hampa.ch> * 8 * Copyright: (C) 2012-2025 Hampa Hug <hampa@hampa.ch> * 9 *****************************************************************************/ 10 11/***************************************************************************** 12 * This program is free software. You can redistribute it and / or modify it * 13 * under the terms of the GNU General Public License version 2 as published * 14 * by the Free Software Foundation. * 15 * * 16 * This program is distributed in the hope that it will be useful, but * 17 * WITHOUT ANY WARRANTY, without even the implied warranty of * 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * 19 * Public License for more details. * 20 *****************************************************************************/ 21 22 23#include "e8080.h" 24#include "internal.h" 25 26#include <stdlib.h> 27#include <stdio.h> 28#include <string.h> 29 30 31void e8080_init (e8080_t *c) 32{ 33 unsigned i; 34 35 c->flags = 0; 36 37 c->int_val = 0; 38 c->nmi_val = 0; 39 c->int_req = 0; 40 41 c->int_cnt = 0; 42 c->int_pc = 0; 43 44 c->mem_rd_ext = NULL; 45 c->mem_wr_ext = NULL; 46 47 c->get_uint8 = NULL; 48 c->set_uint8 = NULL; 49 50 for (i = 0; i < 64; i++) { 51 c->mem_map_rd[i] = NULL; 52 c->mem_map_wr[i] = NULL; 53 } 54 55 c->port_rd_ext = NULL; 56 c->port_wr_ext = NULL; 57 58 c->get_port8 = NULL; 59 c->set_port8 = NULL; 60 61 c->hook_exec_ext = NULL; 62 c->hook_exec = NULL; 63 64 c->hook_undef_ext = NULL; 65 c->hook_undef = NULL; 66 67 c->hook_rst_ext = NULL; 68 c->hook_rst = NULL; 69 70 c->delay = 0; 71 c->clkcnt = 0; 72 c->inscnt = 0; 73 74 e8080_set_opcodes (c); 75} 76 77e8080_t *e8080_new (void) 78{ 79 e8080_t *c; 80 81 c = malloc (sizeof (e8080_t)); 82 83 if (c == NULL) { 84 return (NULL); 85 } 86 87 e8080_init (c); 88 89 return (c); 90} 91 92void e8080_free (e8080_t *c) 93{ 94} 95 96void e8080_del (e8080_t *c) 97{ 98 if (c != NULL) { 99 e8080_free (c); 100 free (c); 101 } 102} 103 104static 105void e8080_set_mem_map (unsigned char **map, unsigned addr1, unsigned addr2, unsigned char *p) 106{ 107 if (addr1 & 1023) { 108 if (p != NULL) { 109 p += 1024 - (addr1 & 1023); 110 } 111 112 map[(addr1 >> 10) & 0x3f] = NULL; 113 addr1 = (addr1 + 1023) & ~1023U; 114 } 115 116 if ((addr2 & 1023) != 1023) { 117 map[(addr2 >> 10) & 0x3f] = NULL; 118 addr2 = addr2 & ~1023U; 119 120 if (addr2 > 0) { 121 addr2 -= 1; 122 } 123 } 124 125 while (addr1 < addr2) { 126 map[(addr1 >> 10) & 0x3f] = p; 127 128 if (p != NULL) { 129 p += 1024; 130 } 131 132 addr1 += 1024; 133 } 134} 135 136void e8080_set_mem_map_rd (e8080_t *c, unsigned addr1, unsigned addr2, unsigned char *p) 137{ 138 e8080_set_mem_map (c->mem_map_rd, addr1, addr2, p); 139} 140 141void e8080_set_mem_map_wr (e8080_t *c, unsigned addr1, unsigned addr2, unsigned char *p) 142{ 143 e8080_set_mem_map (c->mem_map_wr, addr1, addr2, p); 144} 145 146void e8080_set_8080 (e8080_t *c) 147{ 148 c->flags &= ~E8080_FLAG_Z80; 149 150 e8080_set_opcodes (c); 151} 152 153void e8080_set_z80 (e8080_t *c) 154{ 155 c->flags |= E8080_FLAG_Z80; 156 157 z80_set_opcodes (c); 158} 159 160unsigned e8080_get_flags (e8080_t *c) 161{ 162 return (c->flags); 163} 164 165void e8080_set_flags (e8080_t *c, unsigned flags) 166{ 167 c->flags = flags; 168} 169 170void e8080_set_mem_read_fct (e8080_t *c, void *ext, void *get8) 171{ 172 c->mem_rd_ext = ext; 173 c->get_uint8 = get8; 174} 175 176void e8080_set_mem_write_fct (e8080_t *c, void *ext, void *set8) 177{ 178 c->mem_wr_ext = ext; 179 c->set_uint8 = set8; 180} 181 182void e8080_set_mem_fct (e8080_t *c, void *ext, void *get8, void *set8) 183{ 184 c->mem_rd_ext = ext; 185 c->get_uint8 = get8; 186 187 c->mem_wr_ext = ext; 188 c->set_uint8 = set8; 189} 190 191void e8080_set_port_read_fct (e8080_t *c, void *ext, void *get8) 192{ 193 c->mem_rd_ext = ext; 194 c->get_port8 = get8; 195} 196 197void e8080_set_port_write_fct (e8080_t *c, void *ext, void *set8) 198{ 199 c->port_wr_ext = ext; 200 c->set_port8 = set8; 201} 202 203void e8080_set_port_fct (e8080_t *c, void *ext, void *get8, void *set8) 204{ 205 c->port_rd_ext = ext; 206 c->get_port8 = get8; 207 208 c->port_wr_ext = ext; 209 c->set_port8 = set8; 210} 211 212void e8080_set_hook_exec_fct (e8080_t *c, void *ext, void *fct) 213{ 214 c->hook_exec_ext = ext; 215 c->hook_exec = fct; 216} 217 218void e8080_set_hook_undef_fct (e8080_t *c, void *ext, void *fct) 219{ 220 c->hook_undef_ext = ext; 221 c->hook_undef = fct; 222} 223 224void e8080_set_hook_rst_fct (e8080_t *c, void *ext, void *fct) 225{ 226 c->hook_rst_ext = ext; 227 c->hook_rst = fct; 228} 229 230void e8080_rst (e8080_t *c, unsigned val) 231{ 232 e8080_set_clk (c, 0, 11); 233 234 e8080_set_sp (c, e8080_get_sp (c) - 2); 235 e8080_set_mem16 (c, e8080_get_sp (c), e8080_get_pc (c)); 236 e8080_set_pc (c, val); 237} 238 239void e8080_set_int (e8080_t *c, unsigned char val) 240{ 241 c->int_val = (val != 0); 242 243 if (c->int_val && c->iff) { 244 c->int_req = 1; 245 } 246 247} 248 249unsigned char e8080_get_port8 (e8080_t *c, unsigned addr) 250{ 251 if (c->get_port8 != NULL) { 252 return (c->get_port8 (c->port_rd_ext, addr)); 253 } 254 255 return (0); 256} 257 258void e8080_set_port8 (e8080_t *c, unsigned addr, unsigned char val) 259{ 260 if (c->set_port8 != NULL) { 261 c->set_port8 (c->port_wr_ext, addr, val); 262 } 263} 264 265int e8080_get_reg (e8080_t *c, const char *reg, unsigned long *val) 266{ 267 if (*reg == '%') { 268 reg += 1; 269 } 270 271 if (strcmp (reg, "a") == 0) { 272 *val = e8080_get_a (c); 273 return (0); 274 } 275 else if (strcmp (reg, "b") == 0) { 276 *val = e8080_get_b (c); 277 return (0); 278 } 279 else if (strcmp (reg, "c") == 0) { 280 *val = e8080_get_c (c); 281 return (0); 282 } 283 else if (strcmp (reg, "d") == 0) { 284 *val = e8080_get_d (c); 285 return (0); 286 } 287 else if (strcmp (reg, "e") == 0) { 288 *val = e8080_get_e (c); 289 return (0); 290 } 291 else if (strcmp (reg, "h") == 0) { 292 *val = e8080_get_h (c); 293 return (0); 294 } 295 else if (strcmp (reg, "l") == 0) { 296 *val = e8080_get_l (c); 297 return (0); 298 } 299 else if (strcmp (reg, "bc") == 0) { 300 *val = e8080_get_bc (c); 301 return (0); 302 } 303 else if (strcmp (reg, "de") == 0) { 304 *val = e8080_get_de (c); 305 return (0); 306 } 307 else if (strcmp (reg, "hl") == 0) { 308 *val = e8080_get_hl (c); 309 return (0); 310 } 311 else if (strcmp (reg, "ix") == 0) { 312 *val = e8080_get_ix (c); 313 return (0); 314 } 315 else if (strcmp (reg, "iy") == 0) { 316 *val = e8080_get_iy (c); 317 return (0); 318 } 319 else if (strcmp (reg, "psw") == 0) { 320 *val = e8080_get_psw (c); 321 return (0); 322 } 323 else if (strcmp (reg, "pc") == 0) { 324 *val = e8080_get_pc (c); 325 return (0); 326 } 327 else if (strcmp (reg, "sp") == 0) { 328 *val = e8080_get_sp (c); 329 return (0); 330 } 331 else if (strcmp (reg, "i") == 0) { 332 *val = e8080_get_i (c); 333 return (0); 334 } 335 else if (strcmp (reg, "icnt") == 0) { 336 *val = e8080_get_int_cnt (c); 337 return (0); 338 } 339 else if (strcmp (reg, "iff") == 0) { 340 *val = e8080_get_iff1 (c); 341 return (0); 342 } 343 else if (strcmp (reg, "iff2") == 0) { 344 *val = e8080_get_iff2 (c); 345 return (0); 346 } 347 else if (strcmp (reg, "im") == 0) { 348 *val = e8080_get_im (c); 349 return (0); 350 } 351 else if (strcmp (reg, "ipc") == 0) { 352 *val = e8080_get_int_pc (c); 353 return (0); 354 } 355 else if (strcmp (reg, "r") == 0) { 356 *val = e8080_get_r (c); 357 return (0); 358 } 359 360 return (1); 361} 362 363int e8080_set_reg (e8080_t *c, const char *reg, unsigned long val) 364{ 365 if (*reg == '%') { 366 reg += 1; 367 } 368 369 if (strcmp (reg, "a") == 0) { 370 e8080_set_a (c, val); 371 return (0); 372 } 373 else if (strcmp (reg, "b") == 0) { 374 e8080_set_b (c, val); 375 return (0); 376 } 377 else if (strcmp (reg, "c") == 0) { 378 e8080_set_c (c, val); 379 return (0); 380 } 381 else if (strcmp (reg, "d") == 0) { 382 e8080_set_d (c, val); 383 return (0); 384 } 385 else if (strcmp (reg, "e") == 0) { 386 e8080_set_e (c, val); 387 return (0); 388 } 389 else if (strcmp (reg, "h") == 0) { 390 e8080_set_h (c, val); 391 return (0); 392 } 393 else if (strcmp (reg, "l") == 0) { 394 e8080_set_l (c, val); 395 return (0); 396 } 397 else if (strcmp (reg, "bc") == 0) { 398 e8080_set_bc (c, val); 399 return (0); 400 } 401 else if (strcmp (reg, "de") == 0) { 402 e8080_set_de (c, val); 403 return (0); 404 } 405 else if (strcmp (reg, "hl") == 0) { 406 e8080_set_hl (c, val); 407 return (0); 408 } 409 else if (strcmp (reg, "ix") == 0) { 410 e8080_set_ix (c, val); 411 return (0); 412 } 413 else if (strcmp (reg, "iy") == 0) { 414 e8080_set_iy (c, val); 415 return (0); 416 } 417 else if (strcmp (reg, "psw") == 0) { 418 e8080_set_psw (c, val); 419 return (0); 420 } 421 else if (strcmp (reg, "pc") == 0) { 422 e8080_set_pc (c, val); 423 return (0); 424 } 425 else if (strcmp (reg, "sp") == 0) { 426 e8080_set_sp (c, val); 427 return (0); 428 } 429 else if (strcmp (reg, "i") == 0) { 430 e8080_set_i (c, val); 431 return (0); 432 } 433 else if (strcmp (reg, "icnt") == 0) { 434 e8080_set_int_cnt (c, val); 435 return (0); 436 } 437 else if (strcmp (reg, "iff") == 0) { 438 e8080_set_iff1 (c, val); 439 return (0); 440 } 441 else if (strcmp (reg, "iff2") == 0) { 442 e8080_set_iff2 (c, val); 443 return (0); 444 } 445 else if (strcmp (reg, "im") == 0) { 446 e8080_set_im (c, val); 447 return (0); 448 } 449 else if (strcmp (reg, "ipc") == 0) { 450 e8080_set_int_pc (c, val); 451 return (0); 452 } 453 else if (strcmp (reg, "r") == 0) { 454 e8080_set_r (c, val); 455 return (0); 456 } 457 458 return (1); 459} 460 461unsigned long e8080_get_clock (e8080_t *c) 462{ 463 return (c->clkcnt); 464} 465 466unsigned long e8080_get_opcnt (e8080_t *c) 467{ 468 return (c->inscnt); 469} 470 471unsigned e8080_get_delay (e8080_t *c) 472{ 473 return (c->delay); 474} 475 476int e8080_hook_exec (e8080_t *c) 477{ 478 if (c->hook_exec != NULL) { 479 return (c->hook_exec (c->hook_exec_ext)); 480 } 481 482 return (0); 483} 484 485int e8080_hook_undefined (e8080_t *c) 486{ 487 if (c->hook_undef != NULL) { 488 return (c->hook_undef (c->hook_undef_ext, c->inst[0])); 489 } 490 491 return (0); 492} 493 494int e8080_hook_rst (e8080_t *c) 495{ 496 if (c->hook_rst != NULL) { 497 return (c->hook_rst (c->hook_rst_ext, (c->inst[0] >> 3) & 7)); 498 } 499 500 return (0); 501} 502 503void e8080_reset (e8080_t *c) 504{ 505 unsigned i; 506 507 c->delay = 7; 508 509 for (i = 0; i < 8; i++) { 510 c->reg[i] = 0; 511 c->reg2[i] = 0; 512 } 513 514 e8080_set_psw (c, 0x02); 515 e8080_set_ix (c, 0x0000); 516 e8080_set_iy (c, 0x0000); 517 e8080_set_sp (c, 0x0000); 518 e8080_set_pc (c, 0x0000); 519 e8080_set_i (c, 0x00); 520 e8080_set_r (c, 0x00); 521 522 c->psw2 = 0x02; 523 524 c->iff = 0; 525 c->iff2 = 0; 526 527 c->int_req = 0; 528 c->int_pc = 0; 529 c->im = 0; 530 531 c->halt = 0; 532} 533 534void e8080_interrupt (e8080_t *c) 535{ 536 unsigned addr; 537 538 e8080_inc_r (c); 539 c->inscnt += 1; 540 541 if (c->halt) { 542 c->halt = 0; 543 e8080_set_pc (c, e8080_get_pc (c) + 1); 544 } 545 546 c->int_cnt += 1; 547 c->int_pc = e8080_get_pc (c); 548 549 c->int_req = 0; 550 551 if (c->im == 1) { 552 e8080_rst (c, 0x38); 553 554 c->iff = 0; 555 c->iff2 = 0; 556 } 557 else if (c->im == 2) { 558 addr = (e8080_get_i (c) << 8) | 0xff; 559 addr = e8080_get_mem16 (c, addr); 560 561 e8080_rst (c, addr); 562 563 c->iff = 0; 564 c->iff2 = 0; 565 } 566 else { 567 fprintf (stderr, "8080: interrupt mode %u\n", c->im); 568 } 569} 570 571void e8080_execute (e8080_t *c) 572{ 573 unsigned short pc; 574 unsigned char iff; 575 576 if (c->halt) { 577 if (c->int_req && c->iff) { 578 e8080_interrupt (c); 579 } 580 else { 581 c->delay += 1; 582 } 583 return; 584 } 585 586 pc = e8080_get_pc (c); 587 588 c->inst[0] = e8080_get_mem8 (c, pc); 589 590 if (c->hook_exec != NULL) { 591 if (e8080_hook_exec (c)) { 592 return; 593 } 594 } 595 596 e8080_inc_r (c); 597 598 iff = c->iff; 599 600 c->op[c->inst[0]] (c); 601 602 c->inscnt += 1; 603 604 if (c->int_req && iff && c->iff) { 605 e8080_interrupt (c); 606 } 607} 608 609void e8080_clock (e8080_t *c, unsigned n) 610{ 611 while (n >= c->delay) { 612 n -= c->delay; 613 c->clkcnt += c->delay; 614 c->delay = 0; 615 e8080_execute (c); 616 } 617 618 c->delay -= n; 619 c->clkcnt += n; 620}