/[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 26 by dpavlin, Mon Oct 8 16:20:10 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-2007  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.344 2006/06/24 21:47:22 debug Exp $   *  $Id: cpu.c,v 1.370 2007/02/10 14:29:54 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 40  Line 40 
40  #include "machine.h"  #include "machine.h"
41  #include "memory.h"  #include "memory.h"
42  #include "misc.h"  #include "misc.h"
43    #include "settings.h"
44    
45    
46  extern int quiet_mode;  extern size_t dyntrans_cache_size;
47    extern int native_code_translation_enabled;
48    
49  static struct cpu_family *first_cpu_family = NULL;  static struct cpu_family *first_cpu_family = NULL;
50    
# Line 52  static struct cpu_family *first_cpu_fami Line 54  static struct cpu_family *first_cpu_fami
54   *   *
55   *  Create a new cpu object.  Each family is tried in sequence until a   *  Create a new cpu object.  Each family is tried in sequence until a
56   *  CPU family recognizes the cpu_type_name.   *  CPU family recognizes the cpu_type_name.
57     *
58     *  If there was no match, NULL is returned. Otherwise, a pointer to an
59     *  initialized cpu struct is returned.
60   */   */
61  struct cpu *cpu_new(struct memory *mem, struct machine *machine,  struct cpu *cpu_new(struct memory *mem, struct machine *machine,
62          int cpu_id, char *name)          int cpu_id, char *name)
# Line 59  struct cpu *cpu_new(struct memory *mem, Line 64  struct cpu *cpu_new(struct memory *mem,
64          struct cpu *cpu;          struct cpu *cpu;
65          struct cpu_family *fp;          struct cpu_family *fp;
66          char *cpu_type_name;          char *cpu_type_name;
67            char tmpstr[30];
68    
69          if (name == NULL) {          if (name == NULL) {
70                  fprintf(stderr, "cpu_new(): cpu name = NULL?\n");                  fprintf(stderr, "cpu_new(): cpu name = NULL?\n");
# Line 73  struct cpu *cpu_new(struct memory *mem, Line 79  struct cpu *cpu_new(struct memory *mem,
79    
80          cpu = zeroed_alloc(sizeof(struct cpu));          cpu = zeroed_alloc(sizeof(struct cpu));
81    
82          cpu->memory_rw          = NULL;          cpu->path = malloc(strlen(machine->path) + 15);
83          cpu->name               = cpu_type_name;          if (cpu->path == NULL) {
84          cpu->mem                = mem;                  fprintf(stderr, "cpu_new(): out of memory\n");
85          cpu->machine            = machine;                  exit(1);
86          cpu->cpu_id             = cpu_id;          }
87          cpu->byte_order         = EMUL_LITTLE_ENDIAN;          snprintf(cpu->path, strlen(machine->path) + 15,
88          cpu->bootstrap_cpu_flag = 0;              "%s.cpu[%i]", machine->path, cpu_id);
89          cpu->running            = 0;  
90            cpu->memory_rw  = NULL;
91            cpu->name       = cpu_type_name;
92            cpu->mem        = mem;
93            cpu->machine    = machine;
94            cpu->cpu_id     = cpu_id;
95            cpu->byte_order = EMUL_UNDEFINED_ENDIAN;
96            cpu->running    = 0;
97    
98            /*  Create settings, and attach to the machine:  */
99            cpu->settings = settings_new();
100            snprintf(tmpstr, sizeof(tmpstr), "cpu[%i]", cpu_id);
101            settings_add(machine->settings, tmpstr, 1,
102                SETTINGS_TYPE_SUBSETTINGS, 0, cpu->settings);
103    
104            settings_add(cpu->settings, "name", 0, SETTINGS_TYPE_STRING,
105                SETTINGS_FORMAT_STRING, (void *) &cpu->name);
106            settings_add(cpu->settings, "running", 0, SETTINGS_TYPE_INT,
107                SETTINGS_FORMAT_YESNO, (void *) &cpu->running);
108    
109          cpu_create_or_reset_tc(cpu);          cpu_create_or_reset_tc(cpu);
110    
# Line 110  struct cpu *cpu_new(struct memory *mem, Line 134  struct cpu *cpu_new(struct memory *mem,
134    
135          fp->init_tables(cpu);          fp->init_tables(cpu);
136    
137            if (cpu->byte_order == EMUL_UNDEFINED_ENDIAN) {
138                    fatal("\ncpu_new(): Internal bug: Endianness not set.\n");
139                    exit(1);
140            }
141    
142          return cpu;          return cpu;
143  }  }
144    
145    
146  /*  /*
147     *  cpu_destroy():
148     *
149     *  Destroy a cpu object.
150     */
151    void cpu_destroy(struct cpu *cpu)
152    {
153            settings_remove(cpu->settings, "name");
154            settings_remove(cpu->settings, "running");
155    
156            /*  Remove any remaining level-1 settings:  */
157            settings_remove_all(cpu->settings);
158    
159            settings_destroy(cpu->settings);
160    
161            if (cpu->path != NULL)
162                    free(cpu->path);
163    
164            /*  TODO: This assumes that zeroed_alloc() actually succeeded
165                with using mmap(), and not malloc()!  */
166            munmap((void *)cpu, sizeof(struct cpu));
167    }
168    
169    
170    /*
171   *  cpu_tlbdump():   *  cpu_tlbdump():
172   *   *
173   *  Called from the debugger to dump the TLB in a readable format.   *  Called from the debugger to dump the TLB in a readable format.
# Line 133  void cpu_tlbdump(struct machine *m, int Line 186  void cpu_tlbdump(struct machine *m, int
186    
187    
188  /*  /*
  *  cpu_register_match():  
  *  
  *  Used by the debugger.  
  */  
 void cpu_register_match(struct machine *m, char *name,  
         int writeflag, uint64_t *valuep, int *match_register)  
 {  
         if (m->cpu_family == NULL || m->cpu_family->register_match == NULL)  
                 fatal("cpu_register_match(): NULL\n");  
         else  
                 m->cpu_family->register_match(m, name, writeflag,  
                     valuep, match_register);  
 }  
   
   
 /*  
189   *  cpu_disassemble_instr():   *  cpu_disassemble_instr():
190   *   *
191   *  Convert an instruction word into human readable format, for instruction   *  Convert an instruction word into human readable format, for instruction
# Line 203  char *cpu_gdb_stub(struct cpu *cpu, char Line 240  char *cpu_gdb_stub(struct cpu *cpu, char
240    
241    
242  /*  /*
  *  cpu_interrupt():  
  *  
  *  Assert an interrupt.  
  *  Return value is 1 if the interrupt was asserted, 0 otherwise.  
  */  
 int cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)  
 {  
         if (cpu->machine->cpu_family == NULL ||  
             cpu->machine->cpu_family->interrupt == NULL) {  
                 fatal("cpu_interrupt(): NULL\n");  
                 return 0;  
         } else  
                 return cpu->machine->cpu_family->interrupt(cpu, irq_nr);  
 }  
   
   
 /*  
  *  cpu_interrupt_ack():  
  *  
  *  Acknowledge an interrupt.  
  *  Return value is 1 if the interrupt was deasserted, 0 otherwise.  
  */  
 int cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)  
 {  
         if (cpu->machine->cpu_family == NULL ||  
             cpu->machine->cpu_family->interrupt_ack == NULL) {  
                 /*  debug("cpu_interrupt_ack(): NULL\n");  */  
                 return 0;  
         } else  
                 return cpu->machine->cpu_family->interrupt_ack(cpu, irq_nr);  
 }  
   
   
 /*  
243   *  cpu_functioncall_trace():   *  cpu_functioncall_trace():
244   *   *
245   *  This function should be called if machine->show_trace_tree is enabled, and   *  This function should be called if machine->show_trace_tree is enabled, and
# Line 307  void cpu_functioncall_trace_return(struc Line 310  void cpu_functioncall_trace_return(struc
310   */   */
311  void cpu_create_or_reset_tc(struct cpu *cpu)  void cpu_create_or_reset_tc(struct cpu *cpu)
312  {  {
313          size_t s = DYNTRANS_CACHE_SIZE + DYNTRANS_CACHE_MARGIN;          size_t s = dyntrans_cache_size + DYNTRANS_CACHE_MARGIN;
314    
315          if (cpu->translation_cache == NULL)          if (cpu->translation_cache == NULL) {
316                  cpu->translation_cache = zeroed_alloc(s);                  cpu->translation_cache = zeroed_alloc(s);
317    
318    #ifdef NATIVE_CODE_GENERATION
319                    if (native_code_translation_enabled) {
320                            mprotect(cpu->translation_cache, s,
321                                PROT_READ | PROT_WRITE | PROT_EXEC);
322                    }
323    #endif
324            }
325    
326            cpu->currently_translating_to_native = 0;
327    
328          /*  Create an empty table at the beginning of the translation cache:  */          /*  Create an empty table at the beginning of the translation cache:  */
329          memset(cpu->translation_cache, 0, sizeof(uint32_t)          memset(cpu->translation_cache, 0, sizeof(uint32_t)
330              * N_BASE_TABLE_ENTRIES);              * N_BASE_TABLE_ENTRIES);
# Line 389  void cpu_run_deinit(struct machine *mach Line 402  void cpu_run_deinit(struct machine *mach
402          int te;          int te;
403    
404          /*          /*
405           *  Two last ticks of every hardware device.  This will allow           *  Two last ticks of every hardware device.  This will allow e.g.
406           *  framebuffers to draw the last updates to the screen before           *  framebuffers to draw the last updates to the screen before halting.
407           *  halting.           *
408             *  TODO: This should be refactored when redesigning the mainbus
409             *        concepts!
410           */           */
411          for (te=0; te<machine->n_tick_entries; te++) {          for (te=0; te<machine->n_tick_entries; te++) {
412                  machine->tick_func[te](machine->cpus[0],                  machine->tick_func[te](machine->cpus[0],
# Line 400  void cpu_run_deinit(struct machine *mach Line 415  void cpu_run_deinit(struct machine *mach
415                      machine->tick_extra[te]);                      machine->tick_extra[te]);
416          }          }
417    
418          debug("cpu_run_deinit(): All CPUs halted.\n");          if (machine->show_nr_of_instructions)
   
         if (machine->show_nr_of_instructions || !quiet_mode)  
419                  cpu_show_cycles(machine, 1);                  cpu_show_cycles(machine, 1);
420    
421          fflush(stdout);          fflush(stdout);
# Line 412  void cpu_run_deinit(struct machine *mach Line 425  void cpu_run_deinit(struct machine *mach
425  /*  /*
426   *  cpu_show_cycles():   *  cpu_show_cycles():
427   *   *
428   *  If automatic adjustment of clock interrupts is turned on, then recalculate   *  If show_nr_of_instructions is on, then print a line to stdout about how
429   *  emulated_hz.  Also, if show_nr_of_instructions is on, then print a   *  many instructions/cycles have been executed so far.
  *  line to stdout about how many instructions/cycles have been executed so  
  *  far.  
430   */   */
431  void cpu_show_cycles(struct machine *machine, int forced)  void cpu_show_cycles(struct machine *machine, int forced)
432  {  {
# Line 423  void cpu_show_cycles(struct machine *mac Line 434  void cpu_show_cycles(struct machine *mac
434          char *symbol;          char *symbol;
435          int64_t mseconds, ninstrs, is, avg;          int64_t mseconds, ninstrs, is, avg;
436          struct timeval tv;          struct timeval tv;
437          int h, m, s, ms, d;          struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
438    
439          static int64_t mseconds_last = 0;          static int64_t mseconds_last = 0;
440          static int64_t ninstrs_last = -1;          static int64_t ninstrs_last = -1;
441    
442          pc = machine->cpus[machine->bootstrap_cpu]->pc;          pc = cpu->pc;
443    
444          gettimeofday(&tv, NULL);          gettimeofday(&tv, NULL);
445          mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000          mseconds = (tv.tv_sec - machine->starttime.tv_sec) * 1000
# Line 440  void cpu_show_cycles(struct machine *mac Line 451  void cpu_show_cycles(struct machine *mac
451          if (mseconds - mseconds_last == 0)          if (mseconds - mseconds_last == 0)
452                  mseconds ++;                  mseconds ++;
453    
454          ninstrs = machine->ncycles_since_gettimeofday;          ninstrs = machine->ninstrs_since_gettimeofday;
   
         if (machine->automatic_clock_adjustment) {  
                 static int first_adjustment = 1;  
   
                 /*  Current nr of cycles per second:  */  
                 int64_t cur_cycles_per_second = 1000 *  
                     (ninstrs-ninstrs_last) / (mseconds-mseconds_last);  
   
                 /*  fatal("[ CYCLES PER SECOND = %"PRIi64" ]\n",  
                     cur_cycles_per_second);  */  
   
                 if (cur_cycles_per_second < 1000000)  
                         cur_cycles_per_second = 1000000;  
   
                 if (first_adjustment) {  
                         machine->emulated_hz = cur_cycles_per_second;  
                         first_adjustment = 0;  
                 } else {  
                         machine->emulated_hz = (15 * machine->emulated_hz +  
                             cur_cycles_per_second) / 16;  
                 }  
   
                 /*  fatal("[ updating emulated_hz to %"PRIi64" Hz ]\n",  
                     machine->emulated_hz);  */  
         }  
   
455    
456          /*  RETURN here, unless show_nr_of_instructions (-N) is turned on:  */          /*  RETURN here, unless show_nr_of_instructions (-N) is turned on:  */
457          if (!machine->show_nr_of_instructions && !forced)          if (!machine->show_nr_of_instructions && !forced)
458                  goto do_return;                  goto do_return;
459    
460          printf("[ %"PRIi64" instrs", (int64_t)machine->ncycles);          printf("[ %"PRIi64" instrs", (int64_t)machine->ninstrs);
   
         if (!machine->automatic_clock_adjustment) {  
                 d = machine->emulated_hz / 1000;  
                 if (d < 1)  
                         d = 1;  
                 ms = machine->ncycles / d;  
                 h = ms / 3600000;  
                 ms -= 3600000 * h;  
                 m = ms / 60000;  
                 ms -= 60000 * m;  
                 s = ms / 1000;  
                 ms -= 1000 * s;  
   
                 printf(", emulated time = %02i:%02i:%02i.%03i; ", h, m, s, ms);  
         }  
461    
462          /*  Instructions per second, and average so far:  */          /*  Instructions per second, and average so far:  */
463          is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);          is = 1000 * (ninstrs-ninstrs_last) / (mseconds-mseconds_last);
# Line 496  void cpu_show_cycles(struct machine *mac Line 466  void cpu_show_cycles(struct machine *mac
466                  is = 0;                  is = 0;
467          if (avg < 0)          if (avg < 0)
468                  avg = 0;                  avg = 0;
469          printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg);  
470            if (cpu->has_been_idling) {
471                    printf("; idling");
472                    cpu->has_been_idling = 0;
473            } else
474                    printf("; i/s=%"PRIi64" avg=%"PRIi64, is, avg);
475    
476          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);          symbol = get_symbol_name(&machine->symbol_context, pc, &offset);
477    
478          if (machine->ncpus == 1) {          if (machine->ncpus == 1) {
479                  if (machine->cpus[machine->bootstrap_cpu]->is_32bit)                  if (cpu->is_32bit)
480                          printf("; pc=0x%08"PRIx32, (uint32_t) pc);                          printf("; pc=0x%08"PRIx32, (uint32_t) pc);
481                  else                  else
482                          printf("; pc=0x%016"PRIx64, (uint64_t) pc);                          printf("; pc=0x%016"PRIx64, (uint64_t) pc);
# Line 525  do_return: Line 500  do_return:
500   */   */
501  void cpu_run_init(struct machine *machine)  void cpu_run_init(struct machine *machine)
502  {  {
503          int ncpus = machine->ncpus;          machine->ninstrs_flush = 0;
504          int te;          machine->ninstrs = 0;
505            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->a_few_cycles = 1;  
   
         /*  debug("cpu_run_init(): a_few_cycles = %i\n",  
             machine->a_few_cycles);  */  
506    
507          /*  For performance measurement:  */          /*  For performance measurement:  */
508          gettimeofday(&machine->starttime, NULL);          gettimeofday(&machine->starttime, NULL);
509          machine->ncycles_since_gettimeofday = 0;          machine->ninstrs_since_gettimeofday = 0;
510  }  }
511    
512    
# Line 629  struct cpu_family *cpu_family_ptr_by_num Line 579  struct cpu_family *cpu_family_ptr_by_num
579   *  cpu_init():   *  cpu_init():
580   *   *
581   *  Should be called before any other cpu_*() function.   *  Should be called before any other cpu_*() function.
582     *
583     *  TODO: Make this nicer by moving out the conditional stuff to
584     *  an automagically generated file? Or a define in config.h?
585   */   */
586  void cpu_init(void)  void cpu_init(void)
587  {  {
# Line 646  void cpu_init(void) Line 599  void cpu_init(void)
599          add_cpu_family(avr_cpu_family_init, ARCH_AVR);          add_cpu_family(avr_cpu_family_init, ARCH_AVR);
600  #endif  #endif
601    
602  #ifdef ENABLE_HPPA  #ifdef ENABLE_RCA180X
603          add_cpu_family(hppa_cpu_family_init, ARCH_HPPA);          add_cpu_family(rca180x_cpu_family_init, ARCH_RCA180X);
 #endif  
   
 #ifdef ENABLE_I960  
         add_cpu_family(i960_cpu_family_init, ARCH_I960);  
 #endif  
   
 #ifdef ENABLE_IA64  
         add_cpu_family(ia64_cpu_family_init, ARCH_IA64);  
604  #endif  #endif
605    
606  #ifdef ENABLE_M68K  #ifdef ENABLE_M68K
# Line 678  void cpu_init(void) Line 623  void cpu_init(void)
623          add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);          add_cpu_family(sparc_cpu_family_init, ARCH_SPARC);
624  #endif  #endif
625    
626  #ifdef ENABLE_X86  #ifdef ENABLE_TRANSPUTER
627          add_cpu_family(x86_cpu_family_init, ARCH_X86);          add_cpu_family(transputer_cpu_family_init, ARCH_TRANSPUTER);
628  #endif  #endif
629  }  }
630    

Legend:
Removed from v.26  
changed lines
  Added in v.34

  ViewVC Help
Powered by ViewVC 1.1.26