/[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 10 by dpavlin, Mon Oct 8 16:18:27 2007 UTC revision 24 by dpavlin, Mon Oct 8 16:19:56 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.298 2005/06/27 10:43:16 debug Exp $   *  $Id: cpu.c,v 1.342 2006/06/22 13:27:03 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"
40  #include "machine.h"  #include "machine.h"
41    #include "memory.h"
42  #include "misc.h"  #include "misc.h"
43    
44    
45  extern int quiet_mode;  extern int quiet_mode;
 extern int show_opcode_statistics;  
   
46    
47  static struct cpu_family *first_cpu_family = NULL;  static struct cpu_family *first_cpu_family = NULL;
48    
# Line 71  struct cpu *cpu_new(struct memory *mem, Line 71  struct cpu *cpu_new(struct memory *mem,
71                  exit(1);                  exit(1);
72          }          }
73    
74          cpu = malloc(sizeof(struct cpu));          cpu = zeroed_alloc(sizeof(struct cpu));
         if (cpu == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
75    
         memset(cpu, 0, sizeof(struct cpu));  
76          cpu->memory_rw          = NULL;          cpu->memory_rw          = NULL;
77          cpu->name               = cpu_type_name;          cpu->name               = cpu_type_name;
78          cpu->mem                = mem;          cpu->mem                = mem;
# Line 87  struct cpu *cpu_new(struct memory *mem, Line 82  struct cpu *cpu_new(struct memory *mem,
82          cpu->bootstrap_cpu_flag = 0;          cpu->bootstrap_cpu_flag = 0;
83          cpu->running            = 0;          cpu->running            = 0;
84    
85            cpu_create_or_reset_tc(cpu);
86    
87          fp = first_cpu_family;          fp = first_cpu_family;
88    
89          while (fp != NULL) {          while (fp != NULL) {
# Line 107  struct cpu *cpu_new(struct memory *mem, Line 104  struct cpu *cpu_new(struct memory *mem,
104          }          }
105    
106          fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);          fatal("\ncpu_new(): unknown cpu type '%s'\n", cpu_type_name);
107          exit(1);          return NULL;
 }  
   
   
 /*  
  *  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);  
108  }  }
109    
110    
# Line 167  void cpu_register_match(struct machine * Line 149  void cpu_register_match(struct machine *
149   *  tracing.   *  tracing.
150   */   */
151  int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,  int cpu_disassemble_instr(struct machine *m, struct cpu *cpu,
152          unsigned char *instr, int running, uint64_t addr, int bintrans)          unsigned char *instr, int running, uint64_t addr)
153  {  {
154          if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {          if (m->cpu_family == NULL || m->cpu_family->disassemble_instr == NULL) {
155                  fatal("cpu_disassemble_instr(): NULL\n");                  fatal("cpu_disassemble_instr(): NULL\n");
156                  return 0;                  return 0;
157          } else          } else
158                  return m->cpu_family->disassemble_instr(cpu, instr,                  return m->cpu_family->disassemble_instr(cpu, instr,
159                      running, addr, bintrans);                      running, addr);
160  }  }
161    
162    
# Line 183  int cpu_disassemble_instr(struct machine Line 165  int cpu_disassemble_instr(struct machine
165   *   *
166   *  Dump cpu registers in a relatively readable format.   *  Dump cpu registers in a relatively readable format.
167   *   *
168   *  gprs: set to non-zero to dump GPRs. (CPU dependant.)   *  gprs: set to non-zero to dump GPRs. (CPU dependent.)
169   *  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.)
170   */   */
171  void cpu_register_dump(struct machine *m, struct cpu *cpu,  void cpu_register_dump(struct machine *m, struct cpu *cpu,
172          int gprs, int coprocs)          int gprs, int coprocs)
# Line 197  void cpu_register_dump(struct machine *m Line 179  void cpu_register_dump(struct machine *m
179    
180    
181  /*  /*
182     *  cpu_gdb_stub():
183     *
184     *  Execute a "remote GDB" command. Return value is a pointer to a newly
185     *  allocated response string, if the command was successfully executed. If
186     *  there was an error, NULL is returned.
187     */
188    char *cpu_gdb_stub(struct cpu *cpu, char *cmd)
189    {
190            if (cpu->machine->cpu_family == NULL ||
191                cpu->machine->cpu_family->gdb_stub == NULL) {
192                    fatal("cpu_gdb_stub(): NULL\n");
193                    return NULL;
194            } else
195                    return cpu->machine->cpu_family->gdb_stub(cpu, cmd);
196    }
197    
198    
199    /*
200   *  cpu_interrupt():   *  cpu_interrupt():
201   *   *
202   *  Assert an interrupt.   *  Assert an interrupt.
# Line 231  int cpu_interrupt_ack(struct cpu *cpu, u Line 231  int cpu_interrupt_ack(struct cpu *cpu, u
231    
232    
233  /*  /*
234     *  cpu_functioncall_trace():
235     *
236     *  This function should be called if machine->show_trace_tree is enabled, and
237     *  a function call is being made. f contains the address of the function.
238     */
239    void cpu_functioncall_trace(struct cpu *cpu, uint64_t f)
240    {
241            int i, n_args = -1;
242            char *symbol;
243            uint64_t offset;
244    
245            if (cpu->machine->ncpus > 1)
246                    fatal("cpu%i:\t", cpu->cpu_id);
247    
248            cpu->trace_tree_depth ++;
249            if (cpu->trace_tree_depth > 100)
250                    cpu->trace_tree_depth = 100;
251            for (i=0; i<cpu->trace_tree_depth; i++)
252                    fatal("  ");
253    
254            fatal("<");
255            symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context,
256                f, &offset, &n_args);
257            if (symbol != NULL)
258                    fatal("%s", symbol);
259            else {
260                    if (cpu->is_32bit)
261                            fatal("0x%"PRIx32, (uint32_t) f);
262                    else
263                            fatal("0x%"PRIx64, (uint64_t) f);
264            }
265            fatal("(");
266    
267            if (cpu->machine->cpu_family->functioncall_trace != NULL)
268                    cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);
269    
270            fatal(")>\n");
271    
272    #ifdef PRINT_MEMORY_CHECKSUM
273            /*  Temporary hack for finding bugs:  */
274            fatal("call chksum=%016"PRIx64"\n", memory_checksum(cpu->mem));
275    #endif
276    }
277    
278    
279    /*
280     *  cpu_functioncall_trace_return():
281     *
282     *  This function should be called if machine->show_trace_tree is enabled, and
283     *  a function is being returned from.
284     *
285     *  TODO: Print return value? This could be implemented similar to the
286     *  cpu->functioncall_trace function call above.
287     */
288    void cpu_functioncall_trace_return(struct cpu *cpu)
289    {
290            cpu->trace_tree_depth --;
291            if (cpu->trace_tree_depth < 0)
292                    cpu->trace_tree_depth = 0;
293    }
294    
295    
296    /*
297     *  cpu_create_or_reset_tc():
298     *
299     *  Create the translation cache in memory (ie allocate memory for it), if
300     *  necessary, and then reset it to an initial state.
301     */
302    void cpu_create_or_reset_tc(struct cpu *cpu)
303    {
304            size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN;
305    
306            if (cpu->translation_cache == NULL)
307                    cpu->translation_cache = zeroed_alloc(s);
308    
309            /*  Create an empty table at the beginning of the translation cache:  */
310            memset(cpu->translation_cache, 0, sizeof(uint32_t)
311                * N_BASE_TABLE_ENTRIES);
312    
313            cpu->translation_cache_cur_ofs =
314                N_BASE_TABLE_ENTRIES * sizeof(uint32_t);
315    
316            /*
317             *  There might be other translation pointers that still point to
318             *  within the translation_cache region. Let's invalidate those too:
319             */
320            if (cpu->invalidate_code_translation != NULL)
321                    cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL);
322    }
323    
324    
325    /*
326   *  cpu_run():   *  cpu_run():
327   *   *
328   *  Run instructions on all CPUs in this machine, for a "medium duration"   *  Run instructions on all CPUs in this machine, for a "medium duration"
# Line 252  int cpu_run(struct emul *emul, struct ma Line 344  int cpu_run(struct emul *emul, struct ma
344   *  cpu_dumpinfo():   *  cpu_dumpinfo():
345   *   *
346   *  Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)   *  Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
347   *  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.
348   */   */
349  void cpu_dumpinfo(struct machine *m, struct cpu *cpu)  void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
350  {  {
# Line 274  void cpu_dumpinfo(struct machine *m, str Line 366  void cpu_dumpinfo(struct machine *m, str
366  void cpu_list_available_types(void)  void cpu_list_available_types(void)
367  {  {
368          struct cpu_family *fp;          struct cpu_family *fp;
369          int iadd = 4;          int iadd = DEBUG_INDENTATION;
370    
371          fp = first_cpu_family;          fp = first_cpu_family;
372    
# Line 304  void cpu_list_available_types(void) Line 396  void cpu_list_available_types(void)
396   *  Shuts down all CPUs in a machine when ending a simulation. (This function   *  Shuts down all CPUs in a machine when ending a simulation. (This function
397   *  should only need to be called once for each machine.)   *  should only need to be called once for each machine.)
398   */   */
399  void cpu_run_deinit(struct emul *emul, struct machine *machine)  void cpu_run_deinit(struct machine *machine)
400  {  {
401          int te;          int te;
402    
# Line 325  void cpu_run_deinit(struct emul *emul, s Line 417  void cpu_run_deinit(struct emul *emul, s
417          if (machine->show_nr_of_instructions || !quiet_mode)          if (machine->show_nr_of_instructions || !quiet_mode)
418                  cpu_show_cycles(machine, 1);                  cpu_show_cycles(machine, 1);
419    
         if (show_opcode_statistics)  
                 cpu_show_full_statistics(machine);  
   
420          fflush(stdout);          fflush(stdout);
421  }  }
422    
# Line 343  void cpu_run_deinit(struct emul *emul, s Line 432  void cpu_run_deinit(struct emul *emul, s
432  void cpu_show_cycles(struct machine *machine, int forced)  void cpu_show_cycles(struct machine *machine, int forced)
433  {  {
434          uint64_t offset, pc;          uint64_t offset, pc;
         int is_32bit = 0, instrs_per_cycle = 1;  
435          char *symbol;          char *symbol;
436          int64_t mseconds, ninstrs;          int64_t mseconds, ninstrs, is, avg;
437          struct timeval tv;          struct timeval tv;
438          int h, m, s, ms, d;          int h, m, s, ms, d;
439    
440          static int64_t mseconds_last = 0;          static int64_t mseconds_last = 0;
441          static int64_t ninstrs_last = -1;          static int64_t ninstrs_last = -1;
442    
         switch (machine->arch) {  
         case ARCH_MIPS:  
                 if (machine->cpus[machine->bootstrap_cpu]->cd.mips.  
                     cpu_type.isa_level < 3 || machine->cpus[machine->  
                     bootstrap_cpu]->cd.mips.cpu_type.isa_level == 32)  
                         is_32bit = 1;  
                 instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]->  
                     cd.mips.cpu_type.instrs_per_cycle;  
                 break;  
         case ARCH_ARM:  
                 is_32bit = 1;  
                 break;  
         }  
   
443          pc = machine->cpus[machine->bootstrap_cpu]->pc;          pc = machine->cpus[machine->bootstrap_cpu]->pc;
444    
445          gettimeofday(&tv, NULL);          gettimeofday(&tv, NULL);
# Line 378  void cpu_show_cycles(struct machine *mac Line 452  void cpu_show_cycles(struct machine *mac
452          if (mseconds - mseconds_last == 0)          if (mseconds - mseconds_last == 0)
453                  mseconds ++;                  mseconds ++;
454    
455          ninstrs = machine->ncycles_since_gettimeofday * instrs_per_cycle;          ninstrs = machine->ncycles_since_gettimeofday;
456    
457          if (machine->automatic_clock_adjustment) {          if (machine->automatic_clock_adjustment) {
458                  static int first_adjustment = 1;                  static int first_adjustment = 1;
459    
460                  /*  Current nr of cycles per second:  */                  /*  Current nr of cycles per second:  */
461                  int64_t cur_cycles_per_second = 1000 *                  int64_t cur_cycles_per_second = 1000 *
462                      (ninstrs-ninstrs_last) / (mseconds-mseconds_last)                      (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
463                      / instrs_per_cycle;  
464                    /*  fatal("[ CYCLES PER SECOND = %"PRIi64" ]\n",
465                        cur_cycles_per_second);  */
466    
467                  if (cur_cycles_per_second < 1000000)                  if (cur_cycles_per_second < 1000000)
468                          cur_cycles_per_second = 1000000;                          cur_cycles_per_second = 1000000;
# Line 399  void cpu_show_cycles(struct machine *mac Line 475  void cpu_show_cycles(struct machine *mac
475                              cur_cycles_per_second) / 16;                              cur_cycles_per_second) / 16;
476                  }                  }
477    
478                  debug("[ updating emulated_hz to %lli Hz ]\n",                  /*  fatal("[ updating emulated_hz to %"PRIi64" Hz ]\n",
479                      (long long)machine->emulated_hz);                      machine->emulated_hz);  */
480          }          }
481    
482    
# Line 408  void cpu_show_cycles(struct machine *mac Line 484  void cpu_show_cycles(struct machine *mac
484          if (!machine->show_nr_of_instructions && !forced)          if (!machine->show_nr_of_instructions && !forced)
485                  goto do_return;                  goto do_return;
486    
487          printf("[ %lli instrs",          printf("[ %"PRIi64" instrs", (int64_t)machine->ncycles);
             (long long)(machine->ncycles * instrs_per_cycle));  
488    
489          if (!machine->automatic_clock_adjustment) {          if (!machine->automatic_clock_adjustment) {
490                  d = machine->emulated_hz / 1000;                  d = machine->emulated_hz / 1000;
# Line 423  void cpu_show_cycles(struct machine *mac Line 498  void cpu_show_cycles(struct machine *mac
498                  s = ms / 1000;                  s = ms / 1000;
499                  ms -= 1000 * s;                  ms -= 1000 * s;
500    
501                  printf("emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);                  printf(", emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);
502          }          }
503    
504          /*  Instructions per second, and average so far:  */          /*  Instructions per second, and average so far:  */
505          printf("; i/s=%lli avg=%lli; ",          is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
506              (long long) ((long long)1000 * (ninstrs-ninstrs_last)          avg = (long long)1000 * ninstrs / mseconds;
507                  / (mseconds-mseconds_last)),          if (is < 0)
508              (long long) ((long long)1000 * ninstrs / mseconds));                  is = 0;
509            if (avg < 0)
510                    avg = 0;
511            printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg);
512    
513          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
514    
515          if (is_32bit)          if (machine->ncpus == 1) {
516                  printf("pc=0x%08x", (int)pc);                  if (machine->cpus[machine->bootstrap_cpu]->is_32bit)
517          else                          printf("; pc=0x%08"PRIx32, (uint32_t) pc);
518                  printf("pc=0x%016llx", (long long)pc);                  else
519                            printf("; pc=0x%016"PRIx64, (uint64_t) pc);
520            }
521    
522          if (symbol != NULL)          if (symbol != NULL)
523                  printf(" <%s>", symbol);                  printf(" <%s>", symbol);
# Line 455  do_return: Line 535  do_return:
535   *  Prepare to run instructions on all CPUs in this machine. (This function   *  Prepare to run instructions on all CPUs in this machine. (This function
536   *  should only need to be called once for each machine.)   *  should only need to be called once for each machine.)
537   */   */
538  void cpu_run_init(struct emul *emul, struct machine *machine)  void cpu_run_init(struct machine *machine)
539  {  {
540          int ncpus = machine->ncpus;          int ncpus = machine->ncpus;
541          int te;          int te;
# Line 480  void cpu_run_init(struct emul *emul, str Line 560  void cpu_run_init(struct emul *emul, str
560          if (machine->a_few_cycles < 1)          if (machine->a_few_cycles < 1)
561                  machine->a_few_cycles = 1;                  machine->a_few_cycles = 1;
562    
563          if (ncpus > 1 && machine->max_random_cycles_per_chunk == 0)          if (ncpus > 1)
564                  machine->a_few_cycles = 1;                  machine->a_few_cycles = 1;
565    
566          /*  debug("cpu_run_init(): a_few_cycles = %i\n",          /*  debug("cpu_run_init(): a_few_cycles = %i\n",
# Line 565  struct cpu_family *cpu_family_ptr_by_num Line 645  struct cpu_family *cpu_family_ptr_by_num
645  void cpu_init(void)  void cpu_init(void)
646  {  {
647          /*  Note: These are registered in alphabetic order.  */          /*  Note: These are registered in alphabetic order.  */
648    
649    #ifdef ENABLE_ALPHA
650            add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
651    #endif
652    
653    #ifdef ENABLE_ARM
654          add_cpu_family(arm_cpu_family_init, ARCH_ARM);          add_cpu_family(arm_cpu_family_init, ARCH_ARM);
655    #endif
656    
657    #ifdef ENABLE_AVR
658            add_cpu_family(avr_cpu_family_init, ARCH_AVR);
659    #endif
660    
661    #ifdef ENABLE_HPPA
662            add_cpu_family(hppa_cpu_family_init, ARCH_HPPA);
663    #endif
664    
665    #ifdef ENABLE_I960
666            add_cpu_family(i960_cpu_family_init, ARCH_I960);
667    #endif
668    
669    #ifdef ENABLE_IA64
670            add_cpu_family(ia64_cpu_family_init, ARCH_IA64);
671    #endif
672    
673    #ifdef ENABLE_M68K
674            add_cpu_family(m68k_cpu_family_init, ARCH_M68K);
675    #endif
676    
677    #ifdef ENABLE_MIPS
678          add_cpu_family(mips_cpu_family_init, ARCH_MIPS);          add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
679    #endif
680    
681    #ifdef ENABLE_PPC
682          add_cpu_family(ppc_cpu_family_init, ARCH_PPC);          add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
683          add_cpu_family(urisc_cpu_family_init, ARCH_URISC);  #endif
684    
685    #ifdef ENABLE_SH
686            add_cpu_family(sh_cpu_family_init, ARCH_SH);
687    #endif
688    
689    #ifdef ENABLE_SPARC
690            add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
691    #endif
692    
693    #ifdef ENABLE_X86
694          add_cpu_family(x86_cpu_family_init, ARCH_X86);          add_cpu_family(x86_cpu_family_init, ARCH_X86);
695    #endif
696  }  }
697    

Legend:
Removed from v.10  
changed lines
  Added in v.24

  ViewVC Help
Powered by ViewVC 1.1.26