OSDN Git Service

[VM][PC9801][MEMBUS] Split update_bios() to functions.
[csp-qt/common_source_project-fm7.git] / source / src / vm / i8080.cpp
1 /*
2         Skelton for retropc emulator
3
4         Origin : MAME
5         Author : Takeda.Toshiya
6         Date   : 2008.11.04 -
7
8         [ i8080 / i8085 ]
9 */
10
11 #include "./vm.h"
12 #include "../emu.h"
13 #include "i8080.h"
14 #include "./i8080_regdef.h"
15 //#ifdef USE_DEBUGGER
16 #include "debugger.h"
17 //#endif
18
19
20 #ifndef CPU_START_ADDR
21 #define CPU_START_ADDR  0
22 #endif
23
24
25 #ifdef HAS_I8085
26 void I8080::ANA(uint8_t v)
27 {
28         _A &= v; 
29         _F = ZSP[_A];
30         _F |= HF;
31 }
32 #else
33 void I8080::ANA(uint8_t v)
34 {                                                                               
35         int i = (((_A | v) >> 3) & 1) * HF;
36         _A &= v;
37         _F = ZSP[_A];
38         _F |= i;
39 }
40 #endif
41
42 #ifdef HAS_I8085
43 void I8080::JMP(uint8_t c)
44 {
45         if(c) {
46                 PC = FETCH16();
47         } else {
48                 PC += 2;
49                 count += 3;
50         }
51 }
52 void I8080::CALL(uint8_t c)
53 {
54         if(c) {
55                 uint16_t a = FETCH16();
56                 count -= 7;
57                 PUSH16(PC);
58                 PC = a;
59         } else {
60                 PC += 2;
61                 count += 2;
62         }
63 }
64 #else
65 void I8080::JMP(uint8_t c)
66 {
67         if(c) {
68                 PC = FETCH16();
69         } else {
70                 PC += 2;
71         }
72 }
73
74 void I8080::CALL(uint8_t c)
75 {
76         if(c) {
77                 uint16_t a = FETCH16();
78                 count -= 6;
79                 PUSH16(PC);
80                 PC = a;
81         } else {
82                 PC += 2;
83         }
84 }
85 #endif
86
87 void I8080::dec_count(uint8_t code)
88 {
89 #ifdef HAS_I8085
90         count -= cc_op_8085[code];
91 #else
92         count -= cc_op_8080[code];
93 #endif
94 }
95
96 void I8080::check_reg_c(uint8_t val)
97 {
98 #ifdef HAS_I8085
99         if(_C == val) _F |= XF; else _F &= ~XF;
100 #endif
101 }
102
103 void I8080::check_reg_e(uint8_t val)
104 {
105 #ifdef HAS_I8085
106         if(_E == val) _F |= XF; else _F &= ~XF;
107 #endif
108 }
109
110 void I8080::check_reg_l(uint8_t val)
111 {
112 #ifdef HAS_I8085
113         if(_L == val) _F |= XF; else _F &= ~XF;
114 #endif
115 }
116
117 void I8080::check_reg_sp(uint8_t val)
118 {
119 #ifdef HAS_I8085
120         if((SP & 0xff) == val) _F |= XF; else _F &= ~XF;
121 #endif
122 }
123
124 void I8080::INSN_0x08(void)
125 {
126 #ifdef HAS_I8085
127         DSUB();
128 #endif
129 }
130
131 void I8080::INSN_0x10(void)
132 {
133 #ifdef HAS_I8085
134         // ASRH
135         _F = (_F & ~CF) | (_L & CF);
136         HL = (HL >> 1);
137 #endif
138 }
139
140
141 void I8080::RLDE(void)
142 { // 0x18
143 #ifdef HAS_I8085
144         _F = (_F & ~(CF | VF)) | (_D >> 7);
145         DE = (DE << 1) | (DE >> 15);
146         if(0 != (((DE >> 15) ^ _F) & CF)) {
147                 _F |= VF;
148         }
149 #endif
150 }
151
152 void I8080::RIM(void)
153 { // 0x20
154 #ifdef HAS_I8085
155         _A = (IM & 0x7f) | (SID ? 0x80 : 0) | RIM_IEN;
156         RIM_IEN = 0;
157 #endif
158 }
159
160 void I8080::_DAA(void)
161 {
162         // 0x27
163         uint16_t tmp16;
164         tmp16 = _A;
165         if(_F & CF) tmp16 |= 0x100;
166         if(_F & HF) tmp16 |= 0x200;
167         if(_F & NF) tmp16 |= 0x400;
168         AF = DAA[tmp16];
169 #ifdef HAS_I8080
170         _F &= 0xd5;
171 #endif
172 }
173
174 void I8080::LDEH(void)
175 {// 0x28
176 #ifdef HAS_I8085
177         DE = (HL + FETCH8()) & 0xffff;
178 #endif
179 }
180         
181 void I8080::CMA(void)
182 { // 0x2f
183 #ifdef HAS_I8085
184         _A ^= 0xff;
185         _F |= HF + NF;
186 #else
187         _A ^= 0xff;
188 #endif
189
190 }
191
192 void I8080::SIM(void)
193 {
194 #ifdef HAS_I8085
195         if(_A & 0x40) {
196                 write_signals(&outputs_sod, (_A & 0x80) ? 0xffffffff : 0);
197         }
198         if(_A & 0x10) {
199                 IM &= ~IM_I7;
200         }
201         if(_A & 8) {
202                 IM = (IM & ~(IM_M5 | IM_M6 | IM_M7)) | (_A & (IM_M5 | IM_M6 | IM_M7));
203         }
204 #endif
205 }
206
207 void I8080::LDES(void)
208 {
209 #ifdef HAS_I8085
210                 DE = (SP + FETCH8()) & 0xffff;
211 #endif
212 }
213
214 void I8080::INSN_0xcb(void)
215 { // RST 8
216 #ifdef HAS_I8085
217         if(_F & VF) {
218                 count -= 12;
219                 RST(8);
220         } else {
221                 count -= 6;
222         }
223 #else
224         JMP(1);
225 #endif
226 }
227
228 #ifndef HAS_I8085
229 #define RET(c) { \
230         if(c) { \
231                 count -= 6; \
232                 PC = POP16(); \
233         }       \
234 }
235 #endif
236 void I8080::INSN_0xd9(void)
237 {
238 #ifdef HAS_I8085
239                 WM16(DE, HL);
240 #else
241                 RET(1);
242 #endif
243 }
244 void I8080::INSN_0xdd(void)
245 {
246 #ifdef HAS_I8085
247                 JMP(!(_F & XF));
248 #else
249                 CALL(1);
250 #endif
251 }
252
253 void I8080::INSN_0xed(void)
254 {
255 #ifdef HAS_I8085
256         HL = RM16(DE); // LHLX
257 #else
258         CALL(1);
259 #endif
260 }
261
262 void I8080::INSN_0xfd(void)
263 {
264 #ifdef HAS_I8085
265                 JMP(_F & XF);
266 #else
267                 CALL(1);
268 #endif
269 }
270
271
272 // main
273
274 void I8080::initialize()
275 {
276         I8080_BASE::initialize();
277 #ifdef USE_DEBUGGER
278         d_mem_stored = d_mem;
279         d_io_stored = d_io;
280         d_debugger->set_context_mem(d_mem);
281         d_debugger->set_context_io(d_io);
282 #endif
283 }
284
285 void I8080::reset()
286 {
287         I8080_BASE::reset();
288         // reset
289         PC = CPU_START_ADDR;
290 }
291
292 void I8080::write_signal(int id, uint32_t data, uint32_t mask)
293 {
294         if(id == SIG_CPU_NMI) {
295                 if(data & mask) {
296                         IM |= IM_NMI;
297                 } else {
298                         IM &= ~IM_NMI;
299                 }
300         } else if(id == SIG_CPU_BUSREQ) {
301                 BUSREQ = ((data & mask) != 0);
302                 write_signals(&outputs_busack, BUSREQ ? 0xffffffff : 0);
303         } else if(id == SIG_I8080_INTR) {
304                 if(data & mask) {
305                         IM |= IM_INT;
306                 } else {
307                         IM &= ~IM_INT;
308                 }
309 #ifdef HAS_I8085
310         } else if(id == SIG_I8085_RST5) {
311                 if(data & mask) {
312                         IM |= IM_I5;
313                 } else {
314                         IM &= ~IM_I5;
315                 }
316         } else if(id == SIG_I8085_RST6) {
317                 if(data & mask) {
318                         IM |= IM_I6;
319                 } else {
320                         IM &= ~IM_I6;
321                 }
322         } else if(id == SIG_I8085_RST7) {
323                 if(data & mask) {
324                         IM |= IM_I7;
325                 } else {
326                         IM &= ~IM_I7;
327                 }
328         } else if(id == SIG_I8085_SID) {
329                 SID = ((data & mask) != 0);
330 #endif
331         }
332 }
333
334
335 int I8080::run(int clock)
336 {
337         if(clock == -1) {
338                 if(BUSREQ) {
339                         // don't run cpu!
340 #ifdef USE_DEBUGGER
341                         total_count += 1;
342 #endif
343                         return 1;
344                 } else {
345                         // run only one opcode
346                         count = 0;
347                         run_one_opecode();
348                         return -count;
349                 }
350         } else {
351                 count += clock;
352                 int first_count = count;
353                 
354                 // run cpu while given clocks
355                 while(count > 0 && !BUSREQ) {
356                         run_one_opecode();
357                 }
358                 // if busreq is raised, spin cpu while remained clock
359                 if(count > 0 && BUSREQ) {
360 #ifdef USE_DEBUGGER
361                         total_count += count;
362 #endif
363                         count = 0;
364                 }
365                 return first_count - count;
366         }
367 }
368
369 void I8080::run_one_opecode()
370 {
371         // rune one opecode
372 #ifdef USE_DEBUGGER
373         bool now_debugging = d_debugger->now_debugging;
374         if(now_debugging) {
375                 d_debugger->check_break_points(PC);
376                 if(d_debugger->now_suspended) {
377                         d_debugger->now_waiting = true;
378                         emu->start_waiting_in_debugger();
379                         while(d_debugger->now_debugging && d_debugger->now_suspended) {
380                                 emu->process_waiting_in_debugger();
381                         }
382                         emu->finish_waiting_in_debugger();
383                         d_debugger->now_waiting = false;
384                 }
385                 if(d_debugger->now_debugging) {
386                         d_mem = d_io = d_debugger;
387                 } else {
388                         now_debugging = false;
389                 }
390                 
391                 afterHALT = afterEI = false;
392                 d_debugger->add_cpu_trace(PC);
393                 int first_count = count;
394                 OP(FETCHOP());
395                 total_count += first_count - count;
396                 if(!afterEI) {
397                         check_interrupt();
398                 }
399                 
400                 if(now_debugging) {
401                         if(!d_debugger->now_going) {
402                                 d_debugger->now_suspended = true;
403                         }
404                         d_mem = d_mem_stored;
405                         d_io = d_io_stored;
406                 }
407         } else {
408 #endif
409                 afterHALT = afterEI = false;
410 #ifdef USE_DEBUGGER
411                 d_debugger->add_cpu_trace(PC);
412                 int first_count = count;
413 #endif
414                 OP(FETCHOP());
415 #ifdef USE_DEBUGGER
416                 total_count += first_count - count;
417 #endif
418                 if(!afterEI) {
419                         check_interrupt();
420                 }
421 #ifdef USE_DEBUGGER
422         }
423 #endif
424         
425         // ei: run next opecode
426         if(afterEI) {
427 #ifdef USE_DEBUGGER
428                 bool now_debugging = d_debugger->now_debugging;
429                 if(now_debugging) {
430                         d_debugger->check_break_points(PC);
431                         if(d_debugger->now_suspended) {
432                                 d_debugger->now_waiting = true;
433                                 emu->start_waiting_in_debugger();
434                                 while(d_debugger->now_debugging && d_debugger->now_suspended) {
435                                         emu->process_waiting_in_debugger();
436                                 }
437                                 emu->finish_waiting_in_debugger();
438                                 d_debugger->now_waiting = false;
439                         }
440                         if(d_debugger->now_debugging) {
441                                 d_mem = d_io = d_debugger;
442                         } else {
443                                 now_debugging = false;
444                         }
445                         
446                         afterHALT = false;
447                         d_debugger->add_cpu_trace(PC);
448                         int first_count = count;
449                         OP(FETCHOP());
450                         total_count += first_count - count;
451                         d_pic->notify_intr_ei();
452                         check_interrupt();
453                         
454                         if(now_debugging) {
455                                 if(!d_debugger->now_going) {
456                                         d_debugger->now_suspended = true;
457                                 }
458                                 d_mem = d_mem_stored;
459                                 d_io = d_io_stored;
460                         }
461                 } else {
462 #endif
463                         afterHALT = false;
464 #ifdef USE_DEBUGGER
465                         d_debugger->add_cpu_trace(PC);
466                         int first_count = count;
467 #endif
468                         OP(FETCHOP());
469 #ifdef USE_DEBUGGER
470                         total_count += first_count - count;
471 #endif
472                         d_pic->notify_intr_ei();
473                         check_interrupt();
474 #ifdef USE_DEBUGGER
475                 }
476 #endif
477         }
478 }
479
480 void I8080::check_interrupt()
481 {
482 #ifdef USE_DEBUGGER
483         int first_count = count;
484 #endif
485         // check interrupt
486         if(IM & IM_REQ) {
487                 if(IM & IM_NMI) {
488                         INT(0x24);
489                         count -= 5;     // unknown
490                         RIM_IEN = IM & IM_IEN;
491                         IM &= ~(IM_IEN | IM_NMI);
492                 } else if(IM & IM_IEN) {
493 #ifdef HAS_I8085
494 #ifdef _FP200
495                         if(/*!(IM & IM_M7) &&*/ (IM & IM_I7)) {
496 #else
497                         if(!(IM & IM_M7) && (IM & IM_I7)) {
498 #endif
499                                 INT(0x3c);
500                                 count -= 7;     // unknown
501                                 RIM_IEN = 0;
502                                 IM &= ~(IM_IEN | IM_I7);
503                         } else if(!(IM & IM_M6) && (IM & IM_I6)) {
504                                 INT(0x34);
505                                 count -= 7;     // unknown
506                                 RIM_IEN = 0;
507                                 IM &= ~(IM_IEN | IM_I6);
508                         } else if(!(IM & IM_M5) && (IM & IM_I5)) {
509                                 INT(0x2c);
510                                 count -= 7;     // unknown
511                                 RIM_IEN = 0;
512                                 IM &= ~(IM_IEN | IM_I5);
513                         } else
514 #endif
515                         if(IM & IM_INT) {
516                                 uint32_t vector = ACK_INTR();
517                                 uint8_t v0 = vector;
518                                 uint16_t v12 = vector >> 8;
519                                 // support JMP/CALL/RST only
520                                 //count -= cc_op[v0];
521 #ifdef HAS_I8085
522                                 count -= cc_op_8085[v0];
523 #else
524                                 count -= cc_op_8080[v0];
525 #endif
526                                 switch(v0) {
527                                 case 0x00:      // NOP
528                                         break;
529                                 case 0xc3:      // JMP
530                                         PC = v12;
531                                         break;
532                                 case 0xcd:      // CALL
533                                         PUSH16(PC);
534                                         PC = v12;
535 #ifdef HAS_I8085
536                                         count -= 7;
537 #else
538                                         count -= 6;
539 #endif
540                                         break;
541                                 case 0xc7:      // RST 0
542                                         RST(0);
543                                         break;
544                                 case 0xcf:      // RST 1
545                                         RST(1);
546                                         break;
547                                 case 0xd7:      // RST 2
548                                         RST(2);
549                                         break;
550                                 case 0xdf:      // RST 3
551                                         RST(3);
552                                         break;
553                                 case 0xe7:      // RST 4
554                                         RST(4);
555                                         break;
556                                 case 0xef:      // RST 5
557                                         RST(5);
558                                         break;
559                                 case 0xf7:      // RST 6
560                                         RST(6);
561                                         break;
562                                 case 0xff:      // RST 7
563                                         RST(7);
564                                         break;
565                                 }
566                                 RIM_IEN = 0;
567                                 IM &= ~(IM_IEN | IM_INT);
568                         }
569                 }
570         }
571 #ifdef USE_DEBUGGER
572         total_count += first_count - count;
573 #endif
574         
575 }
576
577 #define STATE_VERSION   2
578
579 bool I8080::process_state(FILEIO* state_fio, bool loading)
580 {
581         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
582                 return false;
583         }
584         if(!state_fio->StateCheckInt32(this_device_id)) {
585                 return false;
586         }
587 #ifdef USE_DEBUGGER
588         state_fio->StateValue(total_count);
589 #endif
590         state_fio->StateValue(count);
591         state_fio->StateArray(regs, sizeof(regs), 1); // ToDo:
592         state_fio->StateValue(SP);
593         state_fio->StateValue(PC);
594         state_fio->StateValue(prevPC);
595         state_fio->StateValue(IM);
596         state_fio->StateValue(RIM_IEN);
597         state_fio->StateValue(afterHALT);
598         state_fio->StateValue(BUSREQ);
599         state_fio->StateValue(SID);
600         state_fio->StateValue(afterEI);
601         
602 #ifdef USE_DEBUGGER
603         // post process
604         if(loading) {
605                 prev_total_count = total_count;
606         }
607 #endif
608         return true;
609 }
610