fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
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}