/[gxemul]/trunk/src/cpu.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/cpu.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 30 by dpavlin, Mon Oct 8 16:20:40 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu.c,v 1.321 2005/10/03 01:07:40 debug Exp $   *  $Id: cpu.c,v 1.349 2006/07/26 23:21:47 debug Exp $
29   *   *
30   *  Common routines for CPU emulation. (Not specific to any CPU type.)   *  Common routines for CPU emulation. (Not specific to any CPU type.)
31   */   */
# Line 33  Line 33 
33  #include <stdio.h>  #include <stdio.h>
34  #include <stdlib.h>  #include <stdlib.h>
35  #include <sys/types.h>  #include <sys/types.h>
36    #include <sys/mman.h>
37  #include <string.h>  #include <string.h>
38    
39  #include "cpu.h"  #include "cpu.h"
# Line 41  Line 42 
42  #include "misc.h"  #include "misc.h"
43    
44    
 extern int quiet_mode;  
 extern int show_opcode_statistics;  
   
   
45  static struct cpu_family *first_cpu_family = NULL;  static struct cpu_family *first_cpu_family = NULL;
46    
47    
# Line 80  struct cpu *cpu_new(struct memory *mem, Line 77  struct cpu *cpu_new(struct memory *mem,
77          cpu->machine            = machine;          cpu->machine            = machine;
78          cpu->cpu_id             = cpu_id;          cpu->cpu_id             = cpu_id;
79          cpu->byte_order         = EMUL_LITTLE_ENDIAN;          cpu->byte_order         = EMUL_LITTLE_ENDIAN;
         cpu->bootstrap_cpu_flag = 0;  
80          cpu->running            = 0;          cpu->running            = 0;
81    
82          cpu_create_or_reset_tc(cpu);          cpu_create_or_reset_tc(cpu);
# Line 97  struct cpu *cpu_new(struct memory *mem, Line 93  struct cpu *cpu_new(struct memory *mem,
93                                              "NULL\n");                                              "NULL\n");
94                                          exit(1);                                          exit(1);
95                                  }                                  }
96                                  return cpu;                                  break;
97                          }                          }
98                  }                  }
99    
100                  fp = fp->next;                  fp = fp->next;
101          }          }
102    
103          fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);          if (fp == NULL) {
104          exit(1);                  fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
105  }                  return NULL;
106            }
107    
108            fp->init_tables(cpu);
109    
110  /*          return cpu;
  *  cpu_show_full_statistics():  
  *  
  *  Show detailed statistics on opcode usage on each cpu.  
  */  
 void cpu_show_full_statistics(struct machine *m)  
 {  
         if (m->cpu_family == NULL ||  
             m->cpu_family->show_full_statistics == NULL)  
                 fatal("cpu_show_full_statistics(): NULL\n");  
         else  
                 m->cpu_family->show_full_statistics(m);  
111  }  }
112    
113    
# Line 165  void cpu_register_match(struct machine * Line 152  void cpu_register_match(struct machine *
152   *  tracing.   *  tracing.
153   */   */
154  int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,  int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,
155          unsigned char *instr, int running, uint64_t addr, int bintrans)          unsigned char *instr, int running, uint64_t addr)
156  {  {
157          if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {          if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {
158                  fatal("cpu_disassemble_instr(): NULL\n");                  fatal("cpu_disassemble_instr(): NULL\n");
159                  return 0;                  return 0;
160          } else          } else
161                  return m->cpu_family->disassemble_instr(cpu, instr,                  return m->cpu_family->disassemble_instr(cpu, instr,
162                      running, addr, bintrans);                      running, addr);
163  }  }
164    
165    
# Line 181  int cpu_disassemble_instr(struct machine Line 168  int cpu_disassemble_instr(struct machine
168   *   *
169   *  Dump cpu registers in a relatively readable format.   *  Dump cpu registers in a relatively readable format.
170   *   *
171   *  gprs: set to non-zero to dump GPRs. (CPU dependant.)   *  gprs: set to non-zero to dump GPRs. (CPU dependent.)
172   *  coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependant.)   *  coprocs: set bit 0..x to dump registers in coproc 0..x. (CPU dependent.)
173   */   */
174  void cpu_register_dump(struct machine *m, struct cpu *cpu,  void cpu_register_dump(struct machine *m, struct cpu *cpu,
175          int gprs, int coprocs)          int gprs, int coprocs)
# Line 195  void cpu_register_dump(struct machine *m Line 182  void cpu_register_dump(struct machine *m
182    
183    
184  /*  /*
185     *  cpu_gdb_stub():
186     *
187     *  Execute a "remote GDB" command. Return value is a pointer to a newly
188     *  allocated response string, if the command was successfully executed. If
189     *  there was an error, NULL is returned.
190     */
191    char *cpu_gdb_stub(struct cpu *cpu, char *cmd)
192    {
193            if (cpu->machine->cpu_family == NULL ||
194                cpu->machine->cpu_family->gdb_stub == NULL) {
195                    fatal("cpu_gdb_stub(): NULL\n");
196                    return NULL;
197            } else
198                    return cpu->machine->cpu_family->gdb_stub(cpu, cmd);
199    }
200    
201    
202    /*
203   *  cpu_interrupt():   *  cpu_interrupt():
204   *   *
205   *  Assert an interrupt.   *  Assert an interrupt.
# Line 256  void cpu_functioncall_trace(struct cpu * Line 261  void cpu_functioncall_trace(struct cpu *
261                  fatal("%s", symbol);                  fatal("%s", symbol);
262          else {          else {
263                  if (cpu->is_32bit)                  if (cpu->is_32bit)
264                          fatal("0x%08x", (int)f);                          fatal("0x%"PRIx32, (uint32_t) f);
265                  else                  else
266                          fatal("0x%llx", (long long)f);                          fatal("0x%"PRIx64, (uint64_t) f);
267          }          }
268          fatal("(");          fatal("(");
269    
# Line 266  void cpu_functioncall_trace(struct cpu * Line 271  void cpu_functioncall_trace(struct cpu *
271                  cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);                  cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);
272    
273          fatal(")>\n");          fatal(")>\n");
274    
275    #ifdef PRINT_MEMORY_CHECKSUM
276            /*  Temporary hack for finding bugs:  */
277            fatal("call chksum=%016"PRIx64"\n", memory_checksum(cpu->mem));
278    #endif
279  }  }
280    
281    
# Line 294  void cpu_functioncall_trace_return(struc Line 304  void cpu_functioncall_trace_return(struc
304   */   */
305  void cpu_create_or_reset_tc(struct cpu *cpu)  void cpu_create_or_reset_tc(struct cpu *cpu)
306  {  {
307            size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN;
308    
309          if (cpu->translation_cache == NULL)          if (cpu->translation_cache == NULL)
310                  cpu->translation_cache = zeroed_alloc(DYNTRANS_CACHE_SIZE +                  cpu->translation_cache = zeroed_alloc(s);
                     DYNTRANS_CACHE_MARGIN);  
311    
312          /*  Create an empty table at the beginning of the translation cache:  */          /*  Create an empty table at the beginning of the translation cache:  */
313          memset(cpu->translation_cache, 0, sizeof(uint32_t)          memset(cpu->translation_cache, 0, sizeof(uint32_t)
# Line 315  void cpu_create_or_reset_tc(struct cpu * Line 326  void cpu_create_or_reset_tc(struct cpu *
326    
327    
328  /*  /*
  *  cpu_run():  
  *  
  *  Run instructions on all CPUs in this machine, for a "medium duration"  
  *  (or until all CPUs have halted).  
  *  
  *  Return value is 1 if anything happened, 0 if all CPUs are stopped.  
  */  
 int cpu_run(struct emul *emul, struct machine *m)  
 {  
         if (m->cpu_family == NULL || m->cpu_family->run == NULL) {  
                 fatal("cpu_run(): NULL\n");  
                 return 0;  
         } else  
                 return m->cpu_family->run(emul, m);  
 }  
   
   
 /*  
329   *  cpu_dumpinfo():   *  cpu_dumpinfo():
330   *   *
331   *  Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)   *  Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
332   *  is outputed, and it is up to CPU dependant code to complete the line.   *  is outputed, and it is up to CPU dependent code to complete the line.
333   */   */
334  void cpu_dumpinfo(struct machine *m, struct cpu *cpu)  void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
335  {  {
# Line 358  void cpu_dumpinfo(struct machine *m, str Line 351  void cpu_dumpinfo(struct machine *m, str
351  void cpu_list_available_types(void)  void cpu_list_available_types(void)
352  {  {
353          struct cpu_family *fp;          struct cpu_family *fp;
354          int iadd = 4;          int iadd = DEBUG_INDENTATION;
355    
356          fp = first_cpu_family;          fp = first_cpu_family;
357    
# Line 393  void cpu_run_deinit(struct machine *mach Line 386  void cpu_run_deinit(struct machine *mach
386          int te;          int te;
387    
388          /*          /*
389           *  Two last ticks of every hardware device.  This will allow           *  Two last ticks of every hardware device.  This will allow e.g.
390           *  framebuffers to draw the last updates to the screen before           *  framebuffers to draw the last updates to the screen before halting.
391           *  halting.           *
392             *  TODO: This should be refactored when redesigning the mainbus
393             *        concepts!
394           */           */
395          for (te=0; te<machine->n_tick_entries; te++) {          for (te=0; te<machine->n_tick_entries; te++) {
396                  machine->tick_func[te](machine->cpus[0],                  machine->tick_func[te](machine->cpus[0],
# Line 404  void cpu_run_deinit(struct machine *mach Line 399  void cpu_run_deinit(struct machine *mach
399                      machine->tick_extra[te]);                      machine->tick_extra[te]);
400          }          }
401    
402          debug("cpu_run_deinit(): All CPUs halted.\n");          if (machine->show_nr_of_instructions)
   
         if (machine->show_nr_of_instructions || !quiet_mode)  
403                  cpu_show_cycles(machine, 1);                  cpu_show_cycles(machine, 1);
404    
         if (show_opcode_statistics)  
                 cpu_show_full_statistics(machine);  
   
405          fflush(stdout);          fflush(stdout);
406  }  }
407    
# Line 430  void cpu_show_cycles(struct machine *mac Line 420  void cpu_show_cycles(struct machine *mac
420          char *symbol;          char *symbol;
421          int64_t mseconds, ninstrs, is, avg;          int64_t mseconds, ninstrs, is, avg;
422          struct timeval tv;          struct timeval tv;
423          int h, m, s, ms, d, instrs_per_cycle = 1;          int h, m, s, ms, d;
424    
425          static int64_t mseconds_last = 0;          static int64_t mseconds_last = 0;
426          static int64_t ninstrs_last = -1;          static int64_t ninstrs_last = -1;
427    
         switch (machine->arch) {  
         case ARCH_MIPS:  
                 instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]->  
                     cd.mips.cpu_type.instrs_per_cycle;  
                 break;  
         }  
   
428          pc = machine->cpus[machine->bootstrap_cpu]->pc;          pc = machine->cpus[machine->bootstrap_cpu]->pc;
429    
430          gettimeofday(&tv, NULL);          gettimeofday(&tv, NULL);
# Line 454  void cpu_show_cycles(struct machine *mac Line 437  void cpu_show_cycles(struct machine *mac
437          if (mseconds - mseconds_last == 0)          if (mseconds - mseconds_last == 0)
438                  mseconds ++;                  mseconds ++;
439    
440          ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle;          ninstrs = machine->ninstrs_since_gettimeofday;
441    
442          if (machine->automatic_clock_adjustment) {          if (machine->automatic_clock_adjustment) {
443                  static int first_adjustment = 1;                  static int first_adjustment = 1;
444    
445                  /*  Current nr of cycles per second:  */                  /*  Current nr of cycles per second:  */
446                  int64_t cur_cycles_per_second = 1000 *                  int64_t cur_cycles_per_second = 1000 *
447                      (ninstrs-ninstrs_last) / (mseconds-mseconds_last)                      (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
448                      / instrs_per_cycle;  
449                    /*  fatal("[ CYCLES PER SECOND = %"PRIi64" ]\n",
450                        cur_cycles_per_second);  */
451    
452                  if (cur_cycles_per_second < 1000000)                  if (cur_cycles_per_second < 1000000)
453                          cur_cycles_per_second = 1000000;                          cur_cycles_per_second = 1000000;
# Line 475  void cpu_show_cycles(struct machine *mac Line 460  void cpu_show_cycles(struct machine *mac
460                              cur_cycles_per_second) / 16;                              cur_cycles_per_second) / 16;
461                  }                  }
462    
463                  /*  debug("[ updating emulated_hz to %lli Hz ]\n",                  /*  fatal("[ updating emulated_hz to %"PRIi64" Hz ]\n",
464                      (long long)machine->emulated_hz);  */                      machine->emulated_hz);  */
465          }          }
466    
467    
# Line 484  void cpu_show_cycles(struct machine *mac Line 469  void cpu_show_cycles(struct machine *mac
469          if (!machine->show_nr_of_instructions && !forced)          if (!machine->show_nr_of_instructions && !forced)
470                  goto do_return;                  goto do_return;
471    
472          printf("[ %lli instrs",          printf("[ %"PRIi64" instrs", (int64_t)machine->ninstrs);
             (long long)(machine->ncycles * instrs_per_cycle));  
473    
474          if (!machine->automatic_clock_adjustment) {          if (!machine->automatic_clock_adjustment) {
475                  d = machine->emulated_hz / 1000;                  d = machine->emulated_hz / 1000;
476                  if (d < 1)                  if (d < 1)
477                          d = 1;                          d = 1;
478                  ms = machine->ncycles / d;                  ms = machine->ninstrs / d;
479                  h = ms / 3600000;                  h = ms / 3600000;
480                  ms -= 3600000 * h;                  ms -= 3600000 * h;
481                  m = ms / 60000;                  m = ms / 60000;
# Line 499  void cpu_show_cycles(struct machine *mac Line 483  void cpu_show_cycles(struct machine *mac
483                  s = ms / 1000;                  s = ms / 1000;
484                  ms -= 1000 * s;                  ms -= 1000 * s;
485    
486                  printf("emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);                  printf(", emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);
487          }          }
488    
489          /*  Instructions per second, and average so far:  */          /*  Instructions per second, and average so far:  */
# Line 509  void cpu_show_cycles(struct machine *mac Line 493  void cpu_show_cycles(struct machine *mac
493                  is = 0;                  is = 0;
494          if (avg < 0)          if (avg < 0)
495                  avg = 0;                  avg = 0;
496          printf("; i/s=%lli avg=%lli", (long long)is, (long long)avg);          printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg);
497    
498          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
499    
500          if (machine->ncpus == 1) {          if (machine->ncpus == 1) {
501                  if (machine->cpus[machine->bootstrap_cpu]->is_32bit)                  if (machine->cpus[machine->bootstrap_cpu]->is_32bit)
502                          printf("; pc=0x%08x", (int)pc);                          printf("; pc=0x%08"PRIx32, (uint32_t) pc);
503                  else                  else
504                          printf("; pc=0x%016llx", (long long)pc);                          printf("; pc=0x%016"PRIx64, (uint64_t) pc);
505          }          }
506    
507          if (symbol != NULL)          if (symbol != NULL)
# Line 538  do_return: Line 522  do_return:
522   */   */
523  void cpu_run_init(struct machine *machine)  void cpu_run_init(struct machine *machine)
524  {  {
525          int ncpus = machine->ncpus;          machine->ninstrs_flush = 0;
526          int te;          machine->ninstrs = 0;
527            machine->ninstrs_show = 0;
         machine->a_few_cycles = 1048576;  
         machine->ncycles_flush = 0;  
         machine->ncycles = 0;  
         machine->ncycles_show = 0;  
   
         /*  
          *  Instead of doing { one cycle, check hardware ticks }, we  
          *  can do { n cycles, check hardware ticks }, as long as  
          *  n is at most as much as the lowest number of cycles/tick  
          *  for any hardware device.  
          */  
         for (te=0; te<machine->n_tick_entries; te++) {  
                 if (machine->ticks_reset_value[te] < machine->a_few_cycles)  
                         machine->a_few_cycles = machine->ticks_reset_value[te];  
         }  
   
         machine->a_few_cycles >>= 1;  
         if (machine->a_few_cycles < 1)  
                 machine->a_few_cycles = 1;  
   
         if (ncpus > 1 && machine->max_random_cycles_per_chunk == 0)  
                 machine->a_few_cycles = 1;  
   
         /*  debug("cpu_run_init(): a_few_cycles = %i\n",  
             machine->a_few_cycles);  */  
528    
529          /*  For performance measurement:  */          /*  For performance measurement:  */
530          gettimeofday(&machine->starttime, NULL);          gettimeofday(&machine->starttime, NULL);
531          machine->ncycles_since_gettimeofday = 0;          machine->ninstrs_since_gettimeofday = 0;
532  }  }
533    
534    
# Line 691  void cpu_init(void) Line 650  void cpu_init(void)
650          add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);          add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
651  #endif  #endif
652    
653    #ifdef ENABLE_TRANSPUTER
654            add_cpu_family(transputer_cpu_family_init, ARCH_TRANSPUTER);
655    #endif
656    
657  #ifdef ENABLE_X86  #ifdef ENABLE_X86
658          add_cpu_family(x86_cpu_family_init, ARCH_X86);          add_cpu_family(x86_cpu_family_init, ARCH_X86);
659  #endif  #endif

Legend:
Removed from v.14  
changed lines
  Added in v.30

  ViewVC Help
Powered by ViewVC 1.1.26