/[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 22 by dpavlin, Mon Oct 8 16:19:37 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.329 2006/01/16 04:48:08 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;
46  extern int show_opcode_statistics;  extern int show_opcode_statistics;
47    extern int dyntrans_backend_enable;
48    
49  static struct cpu_family *first_cpu_family = NULL;  static struct cpu_family *first_cpu_family = NULL;
50    
# Line 71  struct cpu *cpu_new(struct memory *mem, Line 73  struct cpu *cpu_new(struct memory *mem,
73                  exit(1);                  exit(1);
74          }          }
75    
76          cpu = malloc(sizeof(struct cpu));          cpu = zeroed_alloc(sizeof(struct cpu));
         if (cpu == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
77    
         memset(cpu, 0, sizeof(struct cpu));  
78          cpu->memory_rw          = NULL;          cpu->memory_rw          = NULL;
79          cpu->name               = cpu_type_name;          cpu->name               = cpu_type_name;
80          cpu->mem                = mem;          cpu->mem                = mem;
# Line 87  struct cpu *cpu_new(struct memory *mem, Line 84  struct cpu *cpu_new(struct memory *mem,
84          cpu->bootstrap_cpu_flag = 0;          cpu->bootstrap_cpu_flag = 0;
85          cpu->running            = 0;          cpu->running            = 0;
86    
87            cpu_create_or_reset_tc(cpu);
88    
89          fp = first_cpu_family;          fp = first_cpu_family;
90    
91          while (fp != NULL) {          while (fp != NULL) {
# Line 183  int cpu_disassemble_instr(struct machine Line 182  int cpu_disassemble_instr(struct machine
182   *   *
183   *  Dump cpu registers in a relatively readable format.   *  Dump cpu registers in a relatively readable format.
184   *   *
185   *  gprs: set to non-zero to dump GPRs. (CPU dependant.)   *  gprs: set to non-zero to dump GPRs. (CPU dependent.)
186   *  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.)
187   */   */
188  void cpu_register_dump(struct machine *m, struct cpu *cpu,  void cpu_register_dump(struct machine *m, struct cpu *cpu,
189          int gprs, int coprocs)          int gprs, int coprocs)
# Line 231  int cpu_interrupt_ack(struct cpu *cpu, u Line 230  int cpu_interrupt_ack(struct cpu *cpu, u
230    
231    
232  /*  /*
233     *  cpu_functioncall_trace():
234     *
235     *  This function should be called if machine->show_trace_tree is enabled, and
236     *  a function call is being made. f contains the address of the function.
237     */
238    void cpu_functioncall_trace(struct cpu *cpu, uint64_t f)
239    {
240            int i, n_args = -1;
241            char *symbol;
242            uint64_t offset;
243    
244            if (cpu->machine->ncpus > 1)
245                    fatal("cpu%i:\t", cpu->cpu_id);
246    
247            cpu->trace_tree_depth ++;
248            if (cpu->trace_tree_depth > 100)
249                    cpu->trace_tree_depth = 100;
250            for (i=0; i<cpu->trace_tree_depth; i++)
251                    fatal("  ");
252    
253            fatal("<");
254            symbol = get_symbol_name_and_n_args(&cpu->machine->symbol_context,
255                f, &offset, &n_args);
256            if (symbol != NULL)
257                    fatal("%s", symbol);
258            else {
259                    if (cpu->is_32bit)
260                            fatal("0x%08x", (int)f);
261                    else
262                            fatal("0x%llx", (long long)f);
263            }
264            fatal("(");
265    
266            if (cpu->machine->cpu_family->functioncall_trace != NULL)
267                    cpu->machine->cpu_family->functioncall_trace(cpu, f, n_args);
268    
269            fatal(")>\n");
270    }
271    
272    
273    /*
274     *  cpu_functioncall_trace_return():
275     *
276     *  This function should be called if machine->show_trace_tree is enabled, and
277     *  a function is being returned from.
278     *
279     *  TODO: Print return value? This could be implemented similar to the
280     *  cpu->functioncall_trace function call above.
281     */
282    void cpu_functioncall_trace_return(struct cpu *cpu)
283    {
284            cpu->trace_tree_depth --;
285            if (cpu->trace_tree_depth < 0)
286                    cpu->trace_tree_depth = 0;
287    }
288    
289    
290    /*
291     *  cpu_create_or_reset_tc():
292     *
293     *  Create the translation cache in memory (ie allocate memory for it), if
294     *  necessary, and then reset it to an initial state.
295     */
296    void cpu_create_or_reset_tc(struct cpu *cpu)
297    {
298            size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN;
299    
300            if (cpu->translation_cache == NULL) {
301    #ifdef DYNTRANS_BACKEND
302                    if (dyntrans_backend_enable) {
303                            cpu->translation_cache = (unsigned char *) mmap(NULL,
304                                s, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON |
305                                MAP_PRIVATE, -1, 0);
306                            if (cpu->translation_cache == NULL) {
307                                    dyntrans_backend_enable = 0;
308                                    fatal("%\n%  WARNING! Dyntrans backend disabled"
309                                        ", because mmap() failed.\n%\n");
310                            }
311                    }
312    #endif
313                    if (cpu->translation_cache == NULL)
314                            cpu->translation_cache = zeroed_alloc(s);
315            }
316    
317            /*  Create an empty table at the beginning of the translation cache:  */
318            memset(cpu->translation_cache, 0, sizeof(uint32_t)
319                * N_BASE_TABLE_ENTRIES);
320    
321            cpu->translation_cache_cur_ofs =
322                N_BASE_TABLE_ENTRIES * sizeof(uint32_t);
323    
324            /*
325             *  There might be other translation pointers that still point to
326             *  within the translation_cache region. Let's invalidate those too:
327             */
328            if (cpu->invalidate_code_translation != NULL)
329                    cpu->invalidate_code_translation(cpu, 0, INVALIDATE_ALL);
330    }
331    
332    
333    /*
334   *  cpu_run():   *  cpu_run():
335   *   *
336   *  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 352  int cpu_run(struct emul *emul, struct ma
352   *  cpu_dumpinfo():   *  cpu_dumpinfo():
353   *   *
354   *  Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)   *  Dumps info about a CPU using debug(). "cpu0: CPUNAME, running" (or similar)
355   *  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.
356   */   */
357  void cpu_dumpinfo(struct machine *m, struct cpu *cpu)  void cpu_dumpinfo(struct machine *m, struct cpu *cpu)
358  {  {
# Line 274  void cpu_dumpinfo(struct machine *m, str Line 374  void cpu_dumpinfo(struct machine *m, str
374  void cpu_list_available_types(void)  void cpu_list_available_types(void)
375  {  {
376          struct cpu_family *fp;          struct cpu_family *fp;
377          int iadd = 4;          int iadd = DEBUG_INDENTATION;
378    
379          fp = first_cpu_family;          fp = first_cpu_family;
380    
# Line 304  void cpu_list_available_types(void) Line 404  void cpu_list_available_types(void)
404   *  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
405   *  should only need to be called once for each machine.)   *  should only need to be called once for each machine.)
406   */   */
407  void cpu_run_deinit(struct emul *emul, struct machine *machine)  void cpu_run_deinit(struct machine *machine)
408  {  {
409          int te;          int te;
410    
# Line 343  void cpu_run_deinit(struct emul *emul, s Line 443  void cpu_run_deinit(struct emul *emul, s
443  void cpu_show_cycles(struct machine *machine, int forced)  void cpu_show_cycles(struct machine *machine, int forced)
444  {  {
445          uint64_t offset, pc;          uint64_t offset, pc;
         int is_32bit = 0, instrs_per_cycle = 1;  
446          char *symbol;          char *symbol;
447          int64_t mseconds, ninstrs;          int64_t mseconds, ninstrs, is, avg;
448          struct timeval tv;          struct timeval tv;
449          int h, m, s, ms, d;          int h, m, s, ms, d, instrs_per_cycle = 1;
450    
451          static int64_t mseconds_last = 0;          static int64_t mseconds_last = 0;
452          static int64_t ninstrs_last = -1;          static int64_t ninstrs_last = -1;
453    
454          switch (machine->arch) {          switch (machine->arch) {
455          case ARCH_MIPS:          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;  
456                  instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]->                  instrs_per_cycle = machine->cpus[machine->bootstrap_cpu]->
457                      cd.mips.cpu_type.instrs_per_cycle;                      cd.mips.cpu_type.instrs_per_cycle;
458                  break;                  break;
         case ARCH_ARM:  
                 is_32bit = 1;  
                 break;  
459          }          }
460    
461          pc = machine->cpus[machine->bootstrap_cpu]->pc;          pc = machine->cpus[machine->bootstrap_cpu]->pc;
# Line 399  void cpu_show_cycles(struct machine *mac Line 491  void cpu_show_cycles(struct machine *mac
491                              cur_cycles_per_second) / 16;                              cur_cycles_per_second) / 16;
492                  }                  }
493    
494                  debug("[ updating emulated_hz to %lli Hz ]\n",                  /*  debug("[ updating emulated_hz to %lli Hz ]\n",
495                      (long long)machine->emulated_hz);                      (long long)machine->emulated_hz);  */
496          }          }
497    
498    
# Line 423  void cpu_show_cycles(struct machine *mac Line 515  void cpu_show_cycles(struct machine *mac
515                  s = ms / 1000;                  s = ms / 1000;
516                  ms -= 1000 * s;                  ms -= 1000 * s;
517    
518                  printf("emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);                  printf(", emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);
519          }          }
520    
521          /*  Instructions per second, and average so far:  */          /*  Instructions per second, and average so far:  */
522          printf("; i/s=%lli avg=%lli; ",          is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
523              (long long) ((long long)1000 * (ninstrs-ninstrs_last)          avg = (long long)1000 * ninstrs / mseconds;
524                  / (mseconds-mseconds_last)),          if (is < 0)
525              (long long) ((long long)1000 * ninstrs / mseconds));                  is = 0;
526            if (avg < 0)
527                    avg = 0;
528            printf("; i/s=%lli avg=%lli", (long long)is, (long long)avg);
529    
530          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
531    
532          if (is_32bit)          if (machine->ncpus == 1) {
533                  printf("pc=0x%08x", (int)pc);                  if (machine->cpus[machine->bootstrap_cpu]->is_32bit)
534          else                          printf("; pc=0x%08x", (int)pc);
535                  printf("pc=0x%016llx", (long long)pc);                  else
536                            printf("; pc=0x%016llx", (long long)pc);
537            }
538    
539          if (symbol != NULL)          if (symbol != NULL)
540                  printf(" <%s>", symbol);                  printf(" <%s>", symbol);
# Line 455  do_return: Line 552  do_return:
552   *  Prepare to run instructions on all CPUs in this machine. (This function   *  Prepare to run instructions on all CPUs in this machine. (This function
553   *  should only need to be called once for each machine.)   *  should only need to be called once for each machine.)
554   */   */
555  void cpu_run_init(struct emul *emul, struct machine *machine)  void cpu_run_init(struct machine *machine)
556  {  {
557          int ncpus = machine->ncpus;          int ncpus = machine->ncpus;
558          int te;          int te;
# Line 557  struct cpu_family *cpu_family_ptr_by_num Line 654  struct cpu_family *cpu_family_ptr_by_num
654  }  }
655    
656    
657    #ifdef DYNTRANS_BACKEND
658    /*
659     *  cpu_dtb_add_fixup():
660     *
661     *  Add a fixup entry to a currently ongoing dyntrans backend translation.
662     */
663    void cpu_dtb_add_fixup(struct cpu *cpu, int type, void *addr, size_t data)
664    {
665            struct dtb_fixup *fixup = malloc(sizeof (struct dtb_fixup));
666            if (fixup == NULL) {
667                    fprintf(stderr, "out of memory\n"),
668                    exit(1);
669            }
670    
671            /*  memset(fixup, 0, sizeof(struct dtb_fixup));  */
672    
673            fixup->next = cpu->translation_context.fixups;
674            cpu->translation_context.fixups = fixup;
675    
676            fixup->type = type;
677            fixup->addr = addr;
678            fixup->data = data;
679    
680            /*  printf("{ fixup added: host addr %p, data=%p }\n", addr,
681                (void *)data);  */
682    }
683    
684    
685    /*
686     *  cpu_dtb_do_fixups():
687     *
688     *  This function should be called when a chunk of code has been translated,
689     *  and post-fixup is to be applied (i.e. add data which for some reason was
690     *  not included in the generated code).
691     *
692     *  If no fixup is necessary for a specific host platform, then it still needs
693     *  an empty do_fixups routine here (just set done = 1).
694     */
695    void cpu_dtb_do_fixups(struct cpu *cpu)
696    {
697            for (;;) {
698                    int done = 0;
699                    size_t omit_addr;
700    
701                    struct dtb_fixup *fixup = cpu->translation_context.fixups;
702                    if (fixup == NULL)
703                            break;
704    
705                    cpu->translation_context.fixups = fixup->next;
706    
707    #ifdef DYNTRANS_BACKEND_ALPHA
708                    /*  Add the data at the end of the new translation:  */
709    /*printf("%p %p\n", fixup->addr, fixup->data);*/
710                    omit_addr = (size_t)cpu->translation_context.p -
711                        (size_t)cpu->translation_context.translation_buffer;
712    /*printf("omit_addr = %016llx\n", (long long)omit_addr);*/
713                    omit_addr = ((omit_addr - 1) | (sizeof(uint64_t) - 1)) + 1;
714    /*printf("omit_addr = %016llx\n", (long long)omit_addr);*/
715                    {
716                            uint64_t *x = (void *)(omit_addr + (size_t)cpu->
717                                translation_context.translation_buffer);
718                            uint32_t *fixup_instr = (void *)fixup->addr;
719                            size_t ofs = omit_addr;
720                            if (ofs > 0x7fff) {
721                                    fatal("Alpha fixup > 0x7fff!\n");
722                                    exit(1);
723                            }
724                            *x = fixup->data;
725    /*printf("orig instr = 0x%08x\n", *fixup_instr);*/
726                            (*fixup_instr) &= ~0xffff;
727                            (*fixup_instr) |= ofs;
728    /*printf("new instr = 0x%08x\n", *fixup_instr);*/
729                    }
730                    omit_addr += sizeof(uint64_t);
731                    cpu->translation_context.p = (void *)
732                        ((size_t)cpu->translation_context.translation_buffer
733                        + omit_addr);
734                    done = 1;
735    #endif  /*  DYNTRANS_BACKEND_ALPHA  */
736    
737                    if (!done)
738                            fatal("!!! cpu_dtb_do_fixups() not implemented yet"
739                                " for this host architecture!\n");
740            }
741    }
742    
743    #endif  /*  DYNTRANS_BACKEND  */
744    
745    
746  /*  /*
747   *  cpu_init():   *  cpu_init():
748   *   *
# Line 565  struct cpu_family *cpu_family_ptr_by_num Line 751  struct cpu_family *cpu_family_ptr_by_num
751  void cpu_init(void)  void cpu_init(void)
752  {  {
753          /*  Note: These are registered in alphabetic order.  */          /*  Note: These are registered in alphabetic order.  */
754    
755    #ifdef ENABLE_ALPHA
756            add_cpu_family(alpha_cpu_family_init, ARCH_ALPHA);
757    #endif
758    
759    #ifdef ENABLE_ARM
760          add_cpu_family(arm_cpu_family_init, ARCH_ARM);          add_cpu_family(arm_cpu_family_init, ARCH_ARM);
761    #endif
762    
763    #ifdef ENABLE_AVR
764            add_cpu_family(avr_cpu_family_init, ARCH_AVR);
765    #endif
766    
767    #ifdef ENABLE_HPPA
768            add_cpu_family(hppa_cpu_family_init, ARCH_HPPA);
769    #endif
770    
771    #ifdef ENABLE_I960
772            add_cpu_family(i960_cpu_family_init, ARCH_I960);
773    #endif
774    
775    #ifdef ENABLE_IA64
776            add_cpu_family(ia64_cpu_family_init, ARCH_IA64);
777    #endif
778    
779    #ifdef ENABLE_M68K
780            add_cpu_family(m68k_cpu_family_init, ARCH_M68K);
781    #endif
782    
783    #ifdef ENABLE_MIPS
784          add_cpu_family(mips_cpu_family_init, ARCH_MIPS);          add_cpu_family(mips_cpu_family_init, ARCH_MIPS);
785    #endif
786    
787    #ifdef ENABLE_PPC
788          add_cpu_family(ppc_cpu_family_init, ARCH_PPC);          add_cpu_family(ppc_cpu_family_init, ARCH_PPC);
789          add_cpu_family(urisc_cpu_family_init, ARCH_URISC);  #endif
790    
791    #ifdef ENABLE_SH
792            add_cpu_family(sh_cpu_family_init, ARCH_SH);
793    #endif
794    
795    #ifdef ENABLE_SPARC
796            add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
797    #endif
798    
799    #ifdef ENABLE_X86
800          add_cpu_family(x86_cpu_family_init, ARCH_X86);          add_cpu_family(x86_cpu_family_init, ARCH_X86);
801    #endif
802  }  }
803    

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

  ViewVC Help
Powered by ViewVC 1.1.26