1 /*
2  *  KCemu -- The emulator for the KC85 homecomputer series and much more.
3  *  Copyright (C) 1997-2010 Torsten Paul
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License along
16  *  with this program; if not, write to the Free Software Foundation, Inc.,
17  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <signal.h>
23 #include <unistd.h>
24 #include <iostream>
25 #include <iomanip>
26 #include <sys/time.h>
27 
28 #include <z80ex/z80ex_dasm.h>
29 
30 #include "kc/system.h"
31 #include "kc/prefs/prefs.h"
32 
33 #include "kc/z80.h"
34 #include "kc/daisy.h"
35 #include "kc/timer.h"
36 #include "kc/ports.h"
37 #include "kc/memory.h"
38 #include "kc/z80_fdc.h"
39 #include "kc/cb_list.h"
40 
41 #include "sys/sysdep.h"
42 
43 #include "cmd/cmd.h"
44 
45 #include "ui/ui.h"
46 
47 #include "libdbg/dbg.h"
48 
49 using namespace std;
50 
51 static Z80 *self; // for the signal handler
52 static void signalHandler(int sig);
53 
54 #if 0
55 unsigned long long rdtsc(void)
56 {
57   union {
58     struct {
59       unsigned long lo;
60       unsigned long hi;
61     } l;
62     unsigned long long ll;
63   } ret;
64 
65   __asm__ volatile ("rdtsc" : "=a" (ret.l.lo), "=d" (ret.l.hi));
66 
67   return ret.ll;
68 }
69 #endif
70 
71 class CMD_single_step : public CMD
72 {
73 private:
74   Z80 *_z80;
75 public:
CMD_single_step(Z80 * z80)76   CMD_single_step(Z80 *z80) : CMD("z80-single-step")
77     {
78       _z80 = z80;
79       register_cmd("z80-single-step-on", 0);
80       register_cmd("z80-single-step-off", 1);
81       register_cmd("z80-single-step-toggle", 2);
82       register_cmd("z80-execute-step", 3);
83       register_cmd("z80-trace-on", 4);
84       register_cmd("z80-trace-off", 5);
85       register_cmd("z80-trace-toggle", 6);
86       register_cmd("z80-trace-set-delay", 7);
87     }
88 
execute(CMD_Args * args,CMD_Context context)89   void execute(CMD_Args *args, CMD_Context context)
90     {
91       switch (context)
92         {
93         case 0:
94 	  z80->singlestep(true);
95 	  break;
96         case 1:
97 	  z80->singlestep(false);
98 	  break;
99         case 2:
100 	  z80->singlestep(!z80->singlestep());
101 	  break;
102 	case 3:
103 	  z80->executestep();
104 	  break;
105 	case 4:
106 	  z80->trace(true);
107 	  break;
108 	case 5:
109 	  z80->trace(false);
110 	  break;
111 	case 6:
112 	  z80->trace(!z80->trace());
113 	  break;
114 	case 7:
115 	  if (args)
116 	    {
117 	      long delay = 1000 * args->get_long_arg("delay");
118 	      z80->tracedelay(delay);
119 	    }
120 	  break;
121 	}
122     }
123 };
124 
Z80(void)125 Z80::Z80(void)
126 {
127   self = this;
128 
129   _context = z80ex_create(z80ex_mread_cb, this, z80ex_mwrite_cb, this,
130                            z80ex_pread_cb, this, z80ex_pwrite_cb, this,
131                            z80ex_intread_cb, this);
132 
133   z80ex_set_reti_callback(_context, z80ex_reti_cb, this);
134 
135   z80ex_reset(_context);
136 
137   const EmulationType &emulation_type = Preferences::instance()->get_system_type()->get_emulation_type();
138   z80ex_set_reg(_context, regPC, emulation_type.get_power_on_addr());
139 
140   /*
141    *  FIXME: at least z1013 emulation breaks with the stackpointer
142    *  FIXME: initialized with 0xf000; the CP/M bootlader BL4 will
143    *  FIXME: overwrite it's own stack when clearing the screen :-(
144    */
145   z80ex_set_reg(_context, regSP, 0x0000);
146 
147   _counter = 0;
148 
149   _debug = false;
150   _trace = false;
151   _singlestep = false;
152   _executestep = false;
153   _enable_floppy_cpu = false;
154 
155   _tracedelay = 100000;
156 
157   _irq_line = 0;
158   _irq_mask = 1;
159 
160   _do_quit = false;
161 }
162 
163 #if 0
164 static void
165 print_regs(_Z80 *r)
166 {
167   int c1, c2;
168 
169   z80->printPC();
170 
171   cout << "a="    << setw(2) << setfill('0') << hex << r->AF.B.l
172        << ", bc=" << setw(4) << setfill('0') << hex << r->BC.W
173        << ", de=" << setw(4) << setfill('0') << hex << r->DE.W
174        << ", hl=" << setw(4) << setfill('0') << hex << r->HL.W
175        << endl;
176 
177   c1 = RdZ80(r->DE.W) & 0xff;
178   c2 = RdZ80(r->HL.W) & 0xff;
179 
180   cout << "(de)=" << setw(2) << setfill('0') << hex << c1
181        << " '" << (isprint(c1) ? c1 : '.') << "' "
182        << "(hl)=" << setw(2) << setfill('0') << hex << c2
183        << " '" << (isprint(c2) ? c2 : '.') << "'"
184        << endl;
185 }
186 #endif
187 
188 void
executestep(void)189 Z80::executestep(void)
190 {
191   _executestep = true;
192 }
193 
194 void
singlestep(bool value)195 Z80::singlestep(bool value)
196 {
197   _singlestep = value;
198 }
199 
200 bool
singlestep()201 Z80::singlestep()
202 {
203   return _singlestep;
204 }
205 
206 bool
run(void)207 Z80::run(void)
208 {
209   int a;
210   CMD *cmd;
211 
212   signal(SIGINT, signalHandler);
213 
214   if (timer)
215     timer->start();
216 
217   cmd = new CMD_single_step(this);
218 
219   a = 0;
220   while (!_do_quit)
221     {
222 //      if (DBG_check("KCemu/Z80core/trace"))
223 //	debug(true);
224 
225       //if (_regs.PC.W <= 0x8000)
226       //z80->printPC(); cout << endl;
227 
228       //if (_regs.PC.W == 0x0170)
229       //z80->debug(true);
230 
231       if (_singlestep)
232 	{
233 	  ui->update(true);
234 	  if (!_executestep)
235 	    {
236 	      sys_usleep(100000);
237 	      continue;
238 	    }
239 	  CMD_EXEC("single-step-executed");
240 	  _executestep = false;
241 
242 	}
243       else
244 	if (_trace)
245 	  {
246 	    ui->update();
247 	    CMD_EXEC("single-step-executed");
248 	    sys_usleep(_tracedelay);
249 	  }
250 
251       if (_debug)
252         {
253           int addr = getPC();
254           char buf[80];
255           int t, t2;
256           int base_addr;
257 
258           printf("%04X: ", addr);
259           addr += z80ex_dasm(buf, 80, 0, &t, &t2, z80ex_dasm_readbyte_cb, addr, &base_addr);
260           printf("%-15s  t=%d", buf, t);
261           if (t2) printf("/%d", t2);
262           printf("\n");
263 	}
264 
265       int tstates = z80ex_step(_context);
266 
267       if (_irq_line && z80ex_int_possible(_context))
268         {
269           word_t irq = daisy->irq_ack();
270           if (irq != IRQ_NOT_ACK)
271             {
272               _next_irq = (byte_t)irq;
273               z80ex_int(_context);
274             }
275         }
276 
277       if (_enable_floppy_cpu && fdc_z80)
278 	fdc_z80->execute();
279 
280       _counter += tstates;
281 
282       _cb_list.run_callbacks(_counter);
283     }
284 
285   return false;
286 }
287 
288 void
quit(void)289 Z80::quit(void)
290 {
291   _do_quit = true;
292 }
293 
294 void
addCallback(unsigned long long offset,Callback * cb,void * data)295 Z80::addCallback(unsigned long long offset, Callback *cb, void *data)
296 {
297   _cb_list.add_callback(getCounter() + offset, cb, data);
298 }
299 
300 void
remove_callback_listener(Callback * cb)301 Z80::remove_callback_listener(Callback *cb)
302 {
303   _cb_list.remove_callback_listener(cb);
304 }
305 
306 bool
debug(void)307 Z80::debug(void)
308 {
309   return _debug;
310 }
311 
312 void
debug(bool value)313 Z80::debug(bool value)
314 {
315   _debug = value;
316   if (_enable_floppy_cpu && fdc_z80)
317     fdc_z80->trace(value);
318 }
319 
320 bool
trace(void)321 Z80::trace(void)
322 {
323   return _trace;
324   //return _regs.Trace;
325 }
326 
327 void
trace(bool value)328 Z80::trace(bool value)
329 {
330   _trace = value;
331   //if (level < 0) level = 0;
332   //_regs.Trace = level;
333 }
334 
335 void
tracedelay(long delay)336 Z80::tracedelay(long delay)
337 {
338   _tracedelay = delay;
339 }
340 
341 void
reset(word_t pc,bool power_on)342 Z80::reset(word_t pc, bool power_on)
343 {
344   _cb_list.clear();
345 
346   for (ic_list_t::iterator it = _ic_list.begin();it != _ic_list.end();it++)
347     (*it)->reset(power_on);
348 
349   module->reset(power_on);
350 
351   z80ex_reset(_context);
352   z80ex_set_reg(_context, regPC, pc);
353 
354   /*
355    *  FIXME: at least z1013 emulation breaks with the stackpointer
356    *  FIXME: initialized with 0xf000; the CP/M bootlader BL4 will
357    *  FIXME: overwrite it's own stack when clearing the screen :-(
358    */
359   z80ex_set_reg(_context, regSP, 0x0000);
360 
361   halt_floppy_cpu(power_on);
362 
363   if (timer)
364     timer->start();
365 }
366 
367 void
reset(void)368 Z80::reset(void)
369 {
370   const EmulationType &emulation_type = Preferences::instance()->get_system_type()->get_emulation_type();
371   reset(emulation_type.get_reset_addr(), false);
372 }
373 
374 void
power_on(void)375 Z80::power_on(void)
376 {
377   const EmulationType &emulation_type = Preferences::instance()->get_system_type()->get_emulation_type();
378   reset(emulation_type.get_power_on_addr(), true);
379 }
380 
381 void
jump(word_t pc)382 Z80::jump(word_t pc)
383 {
384   z80ex_set_reg(_context, regPC, pc);
385 }
386 
387 void
register_ic(InterfaceCircuit * h)388 Z80::register_ic(InterfaceCircuit *h)
389 {
390   _ic_list.push_back(h);
391 }
392 
393 void
unregister_ic(InterfaceCircuit * h)394 Z80::unregister_ic(InterfaceCircuit *h)
395 {
396   _ic_list.remove(h);
397 }
398 
399 dword_t
get_irq_mask(void)400 Z80::get_irq_mask(void)
401 {
402   dword_t val = _irq_mask;
403 
404   if (val == 0)
405     {
406       DBG(0, form("KCemu/warning",
407                   "get_irq_mask(): too many interrupt sources!\n"));
408     }
409 
410   _irq_mask <<= 1;
411 
412   return val;
413 }
414 
415 void
set_irq_line(dword_t mask)416 Z80::set_irq_line(dword_t mask)
417 {
418   dword_t irq_line = _irq_line | mask;
419   DBG(2, form("KCemu/Z80/irq",
420               "set_irq_line():   %04x: %04x -> %04x\n",
421               mask, _irq_line, irq_line));
422   _irq_line = irq_line;
423 }
424 
425 void
reset_irq_line(dword_t mask)426 Z80::reset_irq_line(dword_t mask)
427 {
428   _irq_line = _irq_line & (~mask);
429   DBG(2, form("KCemu/Z80/irq",
430               "reset_irq_line(): %04x -> %04x\n",
431               mask, _irq_line));
432 }
433 
434 void
reti(void)435 Z80::reti(void)
436 {
437   daisy->reti();
438 }
439 
440 void
nmi(void)441 Z80::nmi(void)
442 {
443   z80ex_nmi(_context);
444 }
445 
446 void
printPC(void)447 Z80::printPC(void)
448 {
449   cout << setw(4) << setfill('0') << hex << getPC() << "h: ";
450 }
451 
452 void
start_floppy_cpu(void)453 Z80::start_floppy_cpu(void)
454 {
455   if (fdc_z80)
456     {
457       fdc_z80->reset();
458       _enable_floppy_cpu = true;
459     }
460 }
461 
462 void
halt_floppy_cpu(bool power_on)463 Z80::halt_floppy_cpu(bool power_on)
464 {
465   if (fdc_z80)
466     {
467       fdc_z80->reset(power_on);
468       _enable_floppy_cpu = false;
469     }
470 }
471 
472 Z80EX_BYTE
z80ex_dasm_readbyte_cb(Z80EX_WORD addr,void * user_data)473 Z80::z80ex_dasm_readbyte_cb(Z80EX_WORD addr, void *user_data)
474 {
475   return memory->memRead8(addr);
476 }
477 
478 Z80EX_BYTE
z80ex_mread_cb(Z80EX_CONTEXT * cpu,Z80EX_WORD addr,int m1_state,void * user_data)479 Z80::z80ex_mread_cb(Z80EX_CONTEXT *cpu, Z80EX_WORD addr, int m1_state, void *user_data)
480 {
481   return memory->memRead8(addr);
482 }
483 
484 void
z80ex_mwrite_cb(Z80EX_CONTEXT * cpu,Z80EX_WORD addr,Z80EX_BYTE value,void * user_data)485 Z80::z80ex_mwrite_cb(Z80EX_CONTEXT *cpu, Z80EX_WORD addr, Z80EX_BYTE value, void *user_data)
486 {
487   memory->memWrite8(addr, value);
488 }
489 
490 Z80EX_BYTE
z80ex_pread_cb(Z80EX_CONTEXT * cpu,Z80EX_WORD port,void * user_data)491 Z80::z80ex_pread_cb(Z80EX_CONTEXT *cpu, Z80EX_WORD port, void *user_data)
492 {
493   byte_t value;
494 
495   value = ports->in(port);
496   DBG(2, form("KCemu/Z80/pread_cb",
497               "Z80::z80ex_pread_cb():  %04x -> %02x\n",
498               port, value));
499   return value;
500 }
501 
502 void
z80ex_pwrite_cb(Z80EX_CONTEXT * cpu,Z80EX_WORD port,Z80EX_BYTE value,void * user_data)503 Z80::z80ex_pwrite_cb(Z80EX_CONTEXT *cpu, Z80EX_WORD port, Z80EX_BYTE value, void *user_data)
504 {
505   DBG(2, form("KCemu/Z80/pwrite_cb",
506               "Z80::z80ex_pwrite_cb(): %04x -> %02x\n",
507               port, value));
508   ports->out(port, value);
509 }
510 
511 Z80EX_BYTE
z80ex_intread_cb(Z80EX_CONTEXT * cpu,void * user_data)512 Z80::z80ex_intread_cb(Z80EX_CONTEXT *cpu, void *user_data)
513 {
514   Z80 *z80 = (Z80 *)user_data;
515   DBG(2, form("KCemu/Z80/intread_cb",
516               "Z80::z80ex_intread_cb(): %02x\n",
517               z80->_next_irq));
518   return z80->_next_irq;
519 }
520 
521 void
z80ex_reti_cb(Z80EX_CONTEXT * cpu,void * user_data)522 Z80::z80ex_reti_cb(Z80EX_CONTEXT *cpu, void *user_data)
523 {
524   Z80 *z80 = (Z80 *)user_data;
525   DBG(2, form("KCemu/Z80/reti_cb",
526               "Z80::z80ex_reti_cb(): RETI\n"));
527   z80->reti();
528 }
529 
530 static void
signalHandler(int sig)531 signalHandler(int sig)
532 {
533   static bool flag = false;
534   cout << "\n *** signal caught (" << sig << ") ***\n\n";
535   signal(sig, signalHandler);
536   flag = !flag;
537   self->debug(flag);
538 }
539