/[gxemul]/trunk/src/emul.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/emul.c

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

revision 4 by dpavlin, Mon Oct 8 16:18:00 2007 UTC revision 44 by dpavlin, Mon Oct 8 16:22:56 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-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: emul.c,v 1.184 2005/04/20 04:43:52 debug Exp $   *  $Id: emul.c,v 1.302 2007/08/29 20:36:49 debug Exp $
29   *   *
30   *  Emulation startup and misc. routines.   *  Emulation startup and misc. routines.
31   */   */
# Line 39  Line 39 
39  #include <unistd.h>  #include <unistd.h>
40    
41  #include "arcbios.h"  #include "arcbios.h"
 #include "bintrans.h"  
42  #include "cpu.h"  #include "cpu.h"
43  #include "emul.h"  #include "emul.h"
44  #include "console.h"  #include "console.h"
45  #include "debugger.h"  #include "debugger.h"
46  #include "device.h"  #include "device.h"
47  #include "diskimage.h"  #include "diskimage.h"
48    #include "exec_elf.h"
49  #include "machine.h"  #include "machine.h"
50  #include "memory.h"  #include "memory.h"
51  #include "mips_cpu_types.h"  #include "mips_cpu_types.h"
52  #include "misc.h"  #include "misc.h"
53  #include "net.h"  #include "net.h"
54  #include "sgi_arcbios.h"  #include "settings.h"
55    #include "timer.h"
56    #include "useremul.h"
57  #include "x11.h"  #include "x11.h"
58    
59    
 extern int force_debugger_at_exit;  
   
60  extern int extra_argc;  extern int extra_argc;
61  extern char **extra_argv;  extern char **extra_argv;
62    
63  extern int verbose;  extern int verbose;
64  extern int quiet_mode;  extern int quiet_mode;
65    extern int force_debugger_at_exit;
66  extern struct emul *debugger_emul;  extern int single_step;
67  extern struct diskimage *diskimages[];  extern int old_show_trace_tree;
68    extern int old_instruction_trace;
69    extern int old_quiet_mode;
70    extern int quiet_mode;
71    
72    
73  /*  /*
74   *  add_dump_points():   *  add_breakpoints():
75   *   *
76   *  Take the strings breakpoint_string[] and convert to addresses   *  Take the strings breakpoint_string[] and convert to addresses
77   *  (and store them in breakpoint_addr[]).   *  (and store them in breakpoint_addr[]).
78   *   *
79   *  TODO: This function should be moved elsewhere.   *  TODO: This function should be moved elsewhere.
80   */   */
81  static void add_dump_points(struct machine *m)  static void add_breakpoints(struct machine *m)
82  {  {
83          int i;          int i;
84          int string_flag;          int string_flag;
85          uint64_t dp;          uint64_t dp;
86    
87          for (i=0; i<m->n_breakpoints; i++) {          for (i=0; i<m->breakpoints.n; i++) {
88                  string_flag = 0;                  string_flag = 0;
89                  dp = strtoull(m->breakpoint_string[i], NULL, 0);                  dp = strtoull(m->breakpoints.string[i], NULL, 0);
90    
91                  /*                  /*
92                   *  If conversion resulted in 0, then perhaps it is a                   *  If conversion resulted in 0, then perhaps it is a
# Line 92  static void add_dump_points(struct machi Line 95  static void add_dump_points(struct machi
95                  if (dp == 0) {                  if (dp == 0) {
96                          uint64_t addr;                          uint64_t addr;
97                          int res = get_symbol_addr(&m->symbol_context,                          int res = get_symbol_addr(&m->symbol_context,
98                              m->breakpoint_string[i], &addr);                              m->breakpoints.string[i], &addr);
99                          if (!res)                          if (!res) {
100                                  fprintf(stderr,                                  fprintf(stderr,
101                                      "WARNING! Breakpoint '%s' could not be"                                      "ERROR! Breakpoint '%s' could not be"
102                                          " parsed\n",                                          " parsed\n",
103                                      m->breakpoint_string[i]);                                      m->breakpoints.string[i]);
104                          else {                                  exit(1);
105                            } else {
106                                  dp = addr;                                  dp = addr;
107                                  string_flag = 1;                                  string_flag = 1;
108                          }                          }
# Line 109  static void add_dump_points(struct machi Line 113  static void add_dump_points(struct machi
113                   *  were automatically converted into the correct address.                   *  were automatically converted into the correct address.
114                   */                   */
115    
116                  if ((dp >> 32) == 0 && ((dp >> 31) & 1))                  if (m->arch == ARCH_MIPS) {
117                          dp |= 0xffffffff00000000ULL;                          if ((dp >> 32) == 0 && ((dp >> 31) & 1))
118                  m->breakpoint_addr[i] = dp;                                  dp |= 0xffffffff00000000ULL;
119                    }
120    
121                    m->breakpoints.addr[i] = dp;
122    
123                  debug("breakpoint %i: 0x%016llx", i, (long long)dp);                  debug("breakpoint %i: 0x%"PRIx64, i, dp);
124                  if (string_flag)                  if (string_flag)
125                          debug(" (%s)", m->breakpoint_string[i]);                          debug(" (%s)", m->breakpoints.string[i]);
126                  debug("\n");                  debug("\n");
127          }          }
128  }  }
# Line 126  static void add_dump_points(struct machi Line 133  static void add_dump_points(struct machi
133   */   */
134  static void fix_console(void)  static void fix_console(void)
135  {  {
136          console_deinit();          console_deinit_main();
137  }  }
138    
139    
140  /*  /*
141   *  load_bootblock():   *  emul_new():
142   *   *
143   *  For some emulation modes, it is possible to boot from a harddisk image by   *  Returns a reasonably initialized struct emul.
  *  loading a bootblock from a specific disk offset into memory, and executing  
  *  that, instead of requiring a separate kernel file.  It is then up to the  
  *  bootblock to load a kernel.  
144   */   */
145  static void load_bootblock(struct machine *m, struct cpu *cpu)  struct emul *emul_new(char *name)
146  {  {
147          int boot_disk_id;          struct emul *e;
         unsigned char minibuf[0x20];  
         unsigned char *bootblock_buf;  
         uint64_t bootblock_offset;  
         uint64_t bootblock_loadaddr, bootblock_pc;  
         int n_blocks, res, readofs;  
   
         boot_disk_id = diskimage_bootdev(m);  
         if (boot_disk_id < 0)  
                 return;  
   
         switch (m->machine_type) {  
         case MACHINE_DEC:  
                 /*  
                  *  The first few bytes of a disk contains information about  
                  *  where the bootblock(s) are located. (These are all 32-bit  
                  *  little-endian words.)  
                  *  
                  *  Offset 0x10 = load address  
                  *         0x14 = initial PC value  
                  *         0x18 = nr of 512-byte blocks to read  
                  *         0x1c = offset on disk to where the bootblocks  
                  *                are (in 512-byte units)  
                  *         0x20 = nr of blocks to read...  
                  *         0x24 = offset...  
                  *  
                  *  nr of blocks to read and offset are repeated until nr of  
                  *  blocks to read is zero.  
                  */  
                 res = diskimage_access(m, boot_disk_id, 0, 0,  
                     minibuf, sizeof(minibuf));  
   
                 bootblock_loadaddr = minibuf[0x10] + (minibuf[0x11] << 8)  
                   + (minibuf[0x12] << 16) + (minibuf[0x13] << 24);  
   
                 /*  Convert loadaddr to uncached:  */  
                 if ((bootblock_loadaddr & 0xf0000000ULL) != 0x80000000 &&  
                     (bootblock_loadaddr & 0xf0000000ULL) != 0xa0000000)  
                         fatal("\nWARNING! Weird load address 0x%08x.\n\n",  
                             (int)bootblock_loadaddr);  
                 bootblock_loadaddr &= 0x0fffffffULL;  
                 bootblock_loadaddr |= 0xffffffffa0000000ULL;  
   
                 bootblock_pc = minibuf[0x14] + (minibuf[0x15] << 8)  
                   + (minibuf[0x16] << 16) + (minibuf[0x17] << 24);  
   
                 bootblock_pc &= 0x0fffffffULL;  
                 bootblock_pc |= 0xffffffffa0000000ULL;  
                 cpu->pc = bootblock_pc;  
   
                 debug("DEC boot: loadaddr=0x%08x, pc=0x%08x",  
                     (int)bootblock_loadaddr, (int)bootblock_pc);  
   
                 readofs = 0x18;  
   
                 for (;;) {  
                         res = diskimage_access(m, boot_disk_id, 0, readofs,  
                             minibuf, sizeof(minibuf));  
                         if (!res) {  
                                 printf("couldn't read disk?\n");  
                                 exit(1);  
                         }  
   
                         n_blocks = minibuf[0] + (minibuf[1] << 8)  
                           + (minibuf[2] << 16) + (minibuf[3] << 24);  
   
                         bootblock_offset = (minibuf[4] + (minibuf[5] << 8)  
                           + (minibuf[6] << 16) + (minibuf[7] << 24)) * 512;  
   
                         if (n_blocks < 1)  
                                 break;  
   
                         debug(readofs == 0x18? ": %i" : " + %i", n_blocks);  
   
                         if (n_blocks * 512 > 65536)  
                                 fatal("\nWARNING! Unusually large bootblock "  
                                     "(%i bytes)\n\n", n_blocks * 512);  
   
                         bootblock_buf = malloc(n_blocks * 512);  
                         if (bootblock_buf == NULL) {  
                                 fprintf(stderr, "out of memory in "  
                                     "load_bootblock()\n");  
                                 exit(1);  
                         }  
   
                         res = diskimage_access(m, boot_disk_id, 0,  
                             bootblock_offset, bootblock_buf, n_blocks * 512);  
                         if (!res) {  
                                 fatal("WARNING: could not load bootblocks from"  
                                     " disk offset 0x%llx\n",  
                                     (long long)bootblock_offset);  
                         }  
   
                         store_buf(cpu, bootblock_loadaddr,  
                             (char *)bootblock_buf, n_blocks * 512);  
148    
149                          bootblock_loadaddr += 512*n_blocks;          CHECK_ALLOCATION(e = malloc(sizeof(struct emul)));
150                          free(bootblock_buf);          memset(e, 0, sizeof(struct emul));
                         readofs += 8;  
                 }  
151    
152                  debug(readofs == 0x18? ": no blocks?\n" : " blocks\n");          e->settings = settings_new();
                 break;  
153    
154          case MACHINE_X86:          settings_add(e->settings, "n_machines", 0,
155                  cpu->cd.x86.mode = 16;              SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
156                  cpu->pc = 0x7c00;              (void *) &e->n_machines);
   
                 bootblock_buf = malloc(512);  
                 if (bootblock_buf == NULL) {  
                         fprintf(stderr, "Out of memory.\n");  
                         exit(1);  
                 }  
157    
158                  res = diskimage_access(m, boot_disk_id, 0, 0,          /*  TODO: More settings?  */
                     bootblock_buf, 512);  
                 if (!res) {  
                         printf("Couldn't read the disk image. Aborting.\n");  
                         exit(1);  
                 }  
159    
160                  debug("loading PC bootsector from disk %i\n", boot_disk_id);          /*  Sane default values:  */
161                  if (bootblock_buf[510] != 0x55 || bootblock_buf[511] != 0xaa)          e->n_machines = 0;
162                          debug("WARNING! The 0x55,0xAA marker is missing! "          e->next_serial_nr = 1;
                             "Booting anyway.\n");  
                 store_buf(cpu, 0x7c00, (char *)bootblock_buf, 512);  
                 free(bootblock_buf);  
                 break;  
163    
164          default:          if (name != NULL) {
165                  fatal("Booting from disk without a separate kernel "                  CHECK_ALLOCATION(e->name = strdup(name));
166                      "doesn't work in this emulation mode.\n");                  settings_add(e->settings, "name", 0,
167                  exit(1);                      SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
168                        (void *) &e->name);
169          }          }
170    
171            return e;
172  }  }
173    
174    
175  /*  /*
176   *  emul_new():   *  emul_destroy():
177   *   *
178   *  Returns a reasonably initialized struct emul.   *  Destroys a previously created emul object.
179   */   */
180  struct emul *emul_new(char *name)  void emul_destroy(struct emul *emul)
181  {  {
182          struct emul *e;          int i;
183          e = malloc(sizeof(struct emul));  
184          if (e == NULL) {          if (emul->name != NULL) {
185                  fprintf(stderr, "out of memory in emul_new()\n");                  settings_remove(emul->settings, "name");
186                  exit(1);                  free(emul->name);
187          }          }
188    
189          memset(e, 0, sizeof(struct emul));          for (i=0; i<emul->n_machines; i++)
190                    machine_destroy(emul->machines[i]);
191    
192          /*  Sane default values:  */          if (emul->machines != NULL)
193          e->n_machines = 0;                  free(emul->machines);
194    
195          if (name != NULL) {          /*  Remove any remaining level-1 settings:  */
196                  e->name = strdup(name);          settings_remove_all(emul->settings);
197                  if (e->name == NULL) {          settings_destroy(emul->settings);
                         fprintf(stderr, "out of memory in emul_new()\n");  
                         exit(1);  
                 }  
         }  
198    
199          return e;          free(emul);
200  }  }
201    
202    
# Line 319  struct emul *emul_new(char *name) Line 211  struct emul *emul_new(char *name)
211  struct machine *emul_add_machine(struct emul *e, char *name)  struct machine *emul_add_machine(struct emul *e, char *name)
212  {  {
213          struct machine *m;          struct machine *m;
214            char tmpstr[20];
215            int i;
216    
217          m = machine_new(name, e);          m = machine_new(name, e, e->n_machines);
218          m->serial_nr = (e->next_serial_nr ++);          m->serial_nr = (e->next_serial_nr ++);
219    
220          e->n_machines ++;          i = e->n_machines ++;
221          e->machines = realloc(e->machines,  
222              sizeof(struct machine *) * e->n_machines);          CHECK_ALLOCATION(e->machines = realloc(e->machines,
223          if (e->machines == NULL) {              sizeof(struct machine *) * e->n_machines));
224                  fprintf(stderr, "emul_add_machine(): out of memory\n");  
225                  exit(1);          e->machines[i] = m;
226          }  
227            snprintf(tmpstr, sizeof(tmpstr), "machine[%i]", i);
228            settings_add(e->settings, tmpstr, 1, SETTINGS_TYPE_SUBSETTINGS, 0,
229                e->machines[i]->settings);
230    
         e->machines[e->n_machines - 1] = m;  
231          return m;          return m;
232  }  }
233    
# Line 357  static void add_arc_components(struct ma Line 253  static void add_arc_components(struct ma
253    
254          len += 1048576 * m->memory_offset_in_mb;          len += 1048576 * m->memory_offset_in_mb;
255    
256          /*  NOTE/TODO: magic 12MB end of load program area  */          /*
257             *  NOTE/TODO: magic 12MB end of load program area
258             *
259             *  Hm. This breaks the old FreeBSD/MIPS snapshots...
260             */
261    #if 0
262          arcbios_add_memory_descriptor(cpu,          arcbios_add_memory_descriptor(cpu,
263              0x60000 + m->memory_offset_in_mb * 1048576,              0x60000 + m->memory_offset_in_mb * 1048576,
264              start-0x60000 - m->memory_offset_in_mb * 1048576,              start-0x60000 - m->memory_offset_in_mb * 1048576,
265              ARCBIOS_MEM_FreeMemory);              ARCBIOS_MEM_FreeMemory);
266    #endif
267          arcbios_add_memory_descriptor(cpu,          arcbios_add_memory_descriptor(cpu,
268              start, len, ARCBIOS_MEM_LoadedProgram);              start, len, ARCBIOS_MEM_LoadedProgram);
269    
270          scsicontroller = arcbios_get_scsicontroller();          scsicontroller = arcbios_get_scsicontroller(m);
271          if (scsicontroller == 0)          if (scsicontroller == 0)
272                  return;                  return;
273    
# Line 413  static void add_arc_components(struct ma Line 315  static void add_arc_components(struct ma
315                                  snprintf(component_string,                                  snprintf(component_string,
316                                      sizeof(component_string),                                      sizeof(component_string),
317                                      "scsi(0)cdrom(%i)", d->id);                                      "scsi(0)cdrom(%i)", d->id);
318                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
319                                      component_string, scsidevice);                                      component_string, scsidevice);
320    
321                                  snprintf(component_string,                                  snprintf(component_string,
322                                      sizeof(component_string),                                      sizeof(component_string),
323                                      "scsi(0)cdrom(%i)fdisk(0)", d->id);                                      "scsi(0)cdrom(%i)fdisk(0)", d->id);
324                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
325                                      component_string, scsidisk);                                      component_string, scsidisk);
326                          } else {                          } else {
327                                  snprintf(component_string,                                  snprintf(component_string,
328                                      sizeof(component_string),                                      sizeof(component_string),
329                                      "scsi(0)disk(%i)", d->id);                                      "scsi(0)disk(%i)", d->id);
330                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
331                                      component_string, scsidevice);                                      component_string, scsidevice);
332    
333                                  snprintf(component_string,                                  snprintf(component_string,
334                                      sizeof(component_string),                                      sizeof(component_string),
335                                      "scsi(0)disk(%i)rdisk(0)", d->id);                                      "scsi(0)disk(%i)rdisk(0)", d->id);
336                                  arcbios_add_string_to_component(                                  arcbios_add_string_to_component(m,
337                                      component_string, scsidisk);                                      component_string, scsidisk);
338                          }                          }
339                  }                  }
# Line 454  static void add_arc_components(struct ma Line 356  static void add_arc_components(struct ma
356  void emul_machine_setup(struct machine *m, int n_load, char **load_names,  void emul_machine_setup(struct machine *m, int n_load, char **load_names,
357          int n_devices, char **device_names)          int n_devices, char **device_names)
358  {  {
         struct emul *emul;  
359          struct cpu *cpu;          struct cpu *cpu;
360          int i, iadd=4;          int i, iadd = DEBUG_INDENTATION;
361          uint64_t addr, memory_amount, entrypoint = 0, gp = 0, toc = 0;          uint64_t memory_amount, entrypoint = 0, gp = 0, toc = 0;
362          int byte_order;          int byte_order;
363    
364          emul = m->emul;          if (m->name != NULL)
365                    debug("machine \"%s\":\n", m->name);
366            else
367                    debug("machine:\n");
368    
         debug("machine \"%s\":\n", m->name);  
369          debug_indentation(iadd);          debug_indentation(iadd);
370    
371          /*  For userland-only, this decides which ARCH/cpu_name to use:  */          /*  For userland-only, this decides which ARCH/cpu_name to use:  */
# Line 482  void emul_machine_setup(struct machine * Line 385  void emul_machine_setup(struct machine *
385    
386          m->cpu_family = cpu_family_ptr_by_number(m->arch);          m->cpu_family = cpu_family_ptr_by_number(m->arch);
387    
388            if (m->arch == ARCH_ALPHA)
389                    m->arch_pagesize = 8192;
390    
391          machine_memsize_fix(m);          machine_memsize_fix(m);
392    
393          /*          /*
# Line 502  void emul_machine_setup(struct machine * Line 408  void emul_machine_setup(struct machine *
408                  debug(" (offset by %iMB)", m->memory_offset_in_mb);                  debug(" (offset by %iMB)", m->memory_offset_in_mb);
409                  memory_amount += 1048576 * m->memory_offset_in_mb;                  memory_amount += 1048576 * m->memory_offset_in_mb;
410          }          }
411          m->memory = memory_new(memory_amount);          m->memory = memory_new(memory_amount, m->arch);
412          if (m->machine_type != MACHINE_USERLAND)          if (m->machine_type != MACHINE_USERLAND)
413                  debug("\n");                  debug("\n");
414    
# Line 513  void emul_machine_setup(struct machine * Line 419  void emul_machine_setup(struct machine *
419                  /*  TODO: This should be moved elsewhere...  */                  /*  TODO: This should be moved elsewhere...  */
420                  if (m->machine_type == MACHINE_BEBOX)                  if (m->machine_type == MACHINE_BEBOX)
421                          m->ncpus = 2;                          m->ncpus = 2;
                 else if (m->machine_type == MACHINE_ARC &&  
                     m->machine_subtype == MACHINE_ARC_NEC_R96)  
                         m->ncpus = 2;  
                 else if (m->machine_type == MACHINE_ARC &&  
                     m->machine_subtype == MACHINE_ARC_NEC_R98)  
                         m->ncpus = 4;  
422                  else                  else
423                          m->ncpus = 1;                          m->ncpus = 1;
424          }          }
         m->cpus = malloc(sizeof(struct cpu *) * m->ncpus);  
         if (m->cpus == NULL) {  
                 fprintf(stderr, "out of memory\n");  
                 exit(1);  
         }  
         memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);  
425    
426          /*  Initialize dynamic binary translation, if available:  */          CHECK_ALLOCATION(m->cpus = malloc(sizeof(struct cpu *) * m->ncpus));
427          if (m->bintrans_enable)          memset(m->cpus, 0, sizeof(struct cpu *) * m->ncpus);
                 bintrans_init(m, m->memory);  
428    
429          debug("cpu0");          debug("cpu0");
430          if (m->ncpus > 1)          if (m->ncpus > 1)
# Line 539  void emul_machine_setup(struct machine * Line 432  void emul_machine_setup(struct machine *
432          debug(": ");          debug(": ");
433          for (i=0; i<m->ncpus; i++) {          for (i=0; i<m->ncpus; i++) {
434                  m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);                  m->cpus[i] = cpu_new(m->memory, m, i, m->cpu_name);
435                  if (m->bintrans_enable)                  if (m->cpus[i] == NULL) {
436                          bintrans_init_cpu(m->cpus[i]);                          fprintf(stderr, "Unable to create CPU object. "
437                                "Aborting.");
438                            exit(1);
439                    }
440          }          }
441          debug("\n");          debug("\n");
442    
# Line 555  void emul_machine_setup(struct machine * Line 451  void emul_machine_setup(struct machine *
451          if (m->userland_emul != NULL) {          if (m->userland_emul != NULL) {
452                  useremul_name_to_useremul(cpu,                  useremul_name_to_useremul(cpu,
453                      m->userland_emul, NULL, NULL, NULL);                      m->userland_emul, NULL, NULL, NULL);
454                  cpu->memory_rw = userland_memory_rw;  
455                    switch (m->arch) {
456    
457                    case ARCH_ALPHA:
458                            cpu->memory_rw = alpha_userland_memory_rw;
459                            break;
460    
461                    default:
462                            cpu->memory_rw = userland_memory_rw;
463                    }
464          }          }
465    
466          if (m->use_x11)          if (m->x11_md.in_use)
467                  x11_init(m);                  x11_init(m);
468    
469          /*  Fill memory with random bytes:  */          /*  Fill memory with random bytes:  */
         /*  TODO: This is MIPS-specific!  */  
470          if (m->random_mem_contents) {          if (m->random_mem_contents) {
471                  for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {                  for (i=0; i<m->physical_ram_in_mb * 1048576; i+=256) {
472                          unsigned char data[256];                          unsigned char data[256];
473                          unsigned int j;                          unsigned int j;
474                          for (j=0; j<sizeof(data); j++)                          for (j=0; j<sizeof(data); j++)
475                                  data[j] = random() & 255;                                  data[j] = random() & 255;
476                          addr = 0xffffffff80000000ULL + i;                          cpu->memory_rw(cpu, m->memory, i, data, sizeof(data),
477                          cpu->memory_rw(cpu, m->memory, addr, data, sizeof(data),                              MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS | PHYSICAL);
                             MEM_WRITE, CACHE_NONE | NO_EXCEPTIONS);  
478                  }                  }
479          }          }
480    
         if ((m->machine_type == MACHINE_ARC ||  
             m->machine_type == MACHINE_SGI) && m->prom_emulation)  
                 arcbios_init();  
   
481          if (m->userland_emul != NULL) {          if (m->userland_emul != NULL) {
482                  /*                  /*
483                   *  For userland-only emulation, no machine emulation                   *  For userland-only emulation, no machine emulation
# Line 592  void emul_machine_setup(struct machine * Line 491  void emul_machine_setup(struct machine *
491          }          }
492    
493          diskimage_dump_info(m);          diskimage_dump_info(m);
494            console_debug_dump(m);
495    
496          /*  Load files (ROM code, boot code, ...) into memory:  */          /*  Load files (ROM code, boot code, ...) into memory:  */
497          if (n_load == 0) {          if (n_load == 0) {
498                  if (m->first_diskimage != NULL)                  if (m->first_diskimage != NULL) {
499                          load_bootblock(m, cpu);                          if (!load_bootblock(m, cpu, &n_load, &load_names)) {
500                  else {                                  fprintf(stderr, "\nNo executable files were"
501                                        " specified, and booting directly from disk"
502                                        " failed.\n");
503                                    exit(1);
504                            }
505                    } else {
506                          fprintf(stderr, "No executable file(s) loaded, and "                          fprintf(stderr, "No executable file(s) loaded, and "
507                              "we are not booting directly from a disk image."                              "we are not booting directly from a disk image."
508                              "\nAborting.\n");                              "\nAborting.\n");
# Line 606  void emul_machine_setup(struct machine * Line 511  void emul_machine_setup(struct machine *
511          }          }
512    
513          while (n_load > 0) {          while (n_load > 0) {
514                    FILE *tmp_f;
515                    char *name_to_load = *load_names;
516                    int remove_after_load = 0;
517    
518                    /*  Special hack for removing temporary files:  */
519                    if (name_to_load[0] == 8) {
520                            name_to_load ++;
521                            remove_after_load = 1;
522                    }
523    
524                    /*
525                     *  gzipped files are automagically gunzipped:
526                     *  NOTE/TODO: This isn't secure. system() is used.
527                     */
528                    tmp_f = fopen(name_to_load, "r");
529                    if (tmp_f != NULL) {
530                            unsigned char buf[2];           /*  gzip header  */
531                            memset(buf, 0, sizeof(buf));
532                            fread(buf, 1, sizeof(buf), tmp_f);
533                            if (buf[0]==0x1f && buf[1]==0x8b) {
534                                    size_t zzlen = strlen(name_to_load)*2 + 100;
535                                    char *zz;
536    
537                                    CHECK_ALLOCATION(zz = malloc(zzlen));
538                                    debug("gunziping %s\n", name_to_load);
539    
540                                    /*
541                                     *  gzip header found.  If this was a file
542                                     *  extracted from, say, a CDROM image, then it
543                                     *  already has a temporary name. Otherwise we
544                                     *  have to gunzip into a temporary file.
545                                     */
546                                    if (remove_after_load) {
547                                            snprintf(zz, zzlen, "mv %s %s.gz",
548                                                name_to_load, name_to_load);
549                                            system(zz);
550                                            snprintf(zz, zzlen, "gunzip %s.gz",
551                                                name_to_load);
552                                            system(zz);
553                                    } else {
554                                            /*  gunzip into new temp file:  */
555                                            int tmpfile_handle;
556                                            char *new_temp_name;
557                                            char *tmpdir = getenv("TMPDIR");
558    
559                                            if (tmpdir == NULL)
560                                                    tmpdir = DEFAULT_TMP_DIR;
561    
562                                            CHECK_ALLOCATION(new_temp_name =
563                                                malloc(300));
564                                            snprintf(new_temp_name, 300,
565                                                "%s/gxemul.XXXXXXXXXXXX", tmpdir);
566    
567                                            tmpfile_handle = mkstemp(new_temp_name);
568                                            close(tmpfile_handle);
569                                            snprintf(zz, zzlen, "gunzip -c '%s' > "
570                                                "%s", name_to_load, new_temp_name);
571                                            system(zz);
572                                            name_to_load = new_temp_name;
573                                            remove_after_load = 1;
574                                    }
575                                    free(zz);
576                            }
577                            fclose(tmp_f);
578                    }
579    
580                  byte_order = NO_BYTE_ORDER_OVERRIDE;                  byte_order = NO_BYTE_ORDER_OVERRIDE;
581    
582                  file_load(m, m->memory, *load_names, &entrypoint,                  /*
583                     *  Load the file:  :-)
584                     */
585                    file_load(m, m->memory, name_to_load, &entrypoint,
586                      m->arch, &gp, &byte_order, &toc);                      m->arch, &gp, &byte_order, &toc);
587    
588                    if (remove_after_load) {
589                            debug("removing %s\n", name_to_load);
590                            unlink(name_to_load);
591                    }
592    
593                  if (byte_order != NO_BYTE_ORDER_OVERRIDE)                  if (byte_order != NO_BYTE_ORDER_OVERRIDE)
594                          cpu->byte_order = byte_order;                          cpu->byte_order = byte_order;
595    
596                  cpu->pc = entrypoint;                  cpu->pc = entrypoint;
597    
598                  switch (m->arch) {                  switch (m->arch) {
599    
600                    case ARCH_ALPHA:
601                            /*  For position-independent code:  */
602                            cpu->cd.alpha.r[ALPHA_T12] = cpu->pc;
603                            break;
604    
605                    case ARCH_ARM:
606                            if (cpu->pc & 3) {
607                                    fatal("ARM: lowest bits of pc set: TODO\n");
608                                    exit(1);
609                            }
610                            cpu->pc &= 0xfffffffc;
611                            break;
612    
613                    case ARCH_M32R:
614                            if (cpu->pc & 3) {
615                                    fatal("M32R: lowest bits of pc set: TODO\n");
616                                    exit(1);
617                            }
618                            cpu->pc &= 0xfffffffc;
619                            break;
620    
621                    case ARCH_M88K:
622                            if (cpu->pc & 3) {
623                                    fatal("M88K: lowest bits of pc set: TODO\n");
624                                    exit(1);
625                            }
626                            cpu->pc &= 0xfffffffc;
627                            break;
628    
629                  case ARCH_MIPS:                  case ARCH_MIPS:
630                          if ((cpu->pc >> 32) == 0                          if ((cpu->pc >> 32) == 0 && (cpu->pc & 0x80000000ULL))
                             && (cpu->pc & 0x80000000ULL))  
631                                  cpu->pc |= 0xffffffff00000000ULL;                                  cpu->pc |= 0xffffffff00000000ULL;
632    
633                          cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;                          cpu->cd.mips.gpr[MIPS_GPR_GP] = gp;
# Line 631  void emul_machine_setup(struct machine * Line 639  void emul_machine_setup(struct machine *
639                          break;                          break;
640    
641                  case ARCH_PPC:                  case ARCH_PPC:
642                            /*  See http://www.linuxbase.org/spec/ELF/ppc64/
643                                spec/x458.html for more info.  */
644                          cpu->cd.ppc.gpr[2] = toc;                          cpu->cd.ppc.gpr[2] = toc;
645                            /*  TODO  */
646                            if (cpu->cd.ppc.bits == 32)
647                                    cpu->pc &= 0xffffffffULL;
648                          break;                          break;
649    
650                  case ARCH_ALPHA:                  case ARCH_SH:
651                  case ARCH_HPPA:                          if (cpu->cd.sh.cpu_type.bits == 32)
652                  case ARCH_SPARC:                                  cpu->pc &= 0xffffffffULL;
653                  case ARCH_URISC:                          cpu->pc &= ~1;
654                          break;                          break;
655    
656                  case ARCH_X86:                  case ARCH_SPARC:
                         /*  
                          *  NOTE: The toc field is used to indicate an ELF64  
                          *  load, on AMD64!  
                          */  
                         if (toc != 0) {  
                                 cpu->cd.x86.mode = 64;  
                         } else  
                                 cpu->pc &= 0xffffffffULL;  
657                          break;                          break;
658    
659                  default:                  default:
# Line 686  void emul_machine_setup(struct machine * Line 691  void emul_machine_setup(struct machine *
691                  useremul_setup(cpu, n_load, load_names);                  useremul_setup(cpu, n_load, load_names);
692    
693          /*  Startup the bootstrap CPU:  */          /*  Startup the bootstrap CPU:  */
694          cpu->bootstrap_cpu_flag = 1;          cpu->running = 1;
         cpu->running            = 1;  
695    
696          /*  ... or pause all CPUs, if start_paused is set:  */          /*  ... or pause all CPUs, if start_paused is set:  */
697          if (m->start_paused) {          if (m->start_paused) {
# Line 695  void emul_machine_setup(struct machine * Line 699  void emul_machine_setup(struct machine *
699                          m->cpus[i]->running = 0;                          m->cpus[i]->running = 0;
700          }          }
701    
702          /*  Add PC dump points:  */          /*  Parse and add breakpoints:  */
703          add_dump_points(m);          add_breakpoints(m);
704    
705          /*  TODO: This is MIPS-specific!  */          /*  TODO: This is MIPS-specific!  */
706          if (m->machine_type == MACHINE_DEC &&          if (m->machine_type == MACHINE_PMAX &&
707              cpu->cd.mips.cpu_type.mmu_model == MMU3K)              cpu->cd.mips.cpu_type.mmu_model == MMU3K)
708                  add_symbol_name(&m->symbol_context,                  add_symbol_name(&m->symbol_context,
709                      0x9fff0000, 0x10000, "r2k3k_cache", 0);                      0x9fff0000, 0x10000, "r2k3k_cache", 0, 0);
710    
711          symbol_recalc_sizes(&m->symbol_context);          symbol_recalc_sizes(&m->symbol_context);
712    
         if (m->max_random_cycles_per_chunk > 0)  
                 debug("using random cycle chunks (1 to %i cycles)\n",  
                     m->max_random_cycles_per_chunk);  
   
713          /*  Special hack for ARC/SGI emulation:  */          /*  Special hack for ARC/SGI emulation:  */
714          if ((m->machine_type == MACHINE_ARC ||          if ((m->machine_type == MACHINE_ARC ||
715              m->machine_type == MACHINE_SGI) && m->prom_emulation)              m->machine_type == MACHINE_SGI) && m->prom_emulation)
716                  add_arc_components(m);                  add_arc_components(m);
717    
718          debug("starting cpu%i at ", m->bootstrap_cpu);          debug("cpu%i: starting at ", m->bootstrap_cpu);
719    
720          switch (m->arch) {          switch (m->arch) {
721    
722          case ARCH_MIPS:          case ARCH_MIPS:
723                  if (cpu->cd.mips.cpu_type.isa_level < 3 ||                  if (cpu->is_32bit) {
724                      cpu->cd.mips.cpu_type.isa_level == 32) {                          debug("0x%08"PRIx32, (uint32_t)
725                          debug("0x%08x", (int)m->cpus[                              m->cpus[m->bootstrap_cpu]->pc);
                             m->bootstrap_cpu]->pc);  
726                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
727                                  debug(" (gp=0x%08x)", (int)m->cpus[                                  debug(" (gp=0x%08"PRIx32")", (uint32_t)
728                                      m->bootstrap_cpu]->cd.mips.gpr[                                      m->cpus[m->bootstrap_cpu]->cd.mips.gpr[
729                                      MIPS_GPR_GP]);                                      MIPS_GPR_GP]);
730                  } else {                  } else {
731                          debug("0x%016llx", (long long)m->cpus[                          debug("0x%016"PRIx64, (uint64_t)
732                              m->bootstrap_cpu]->pc);                              m->cpus[m->bootstrap_cpu]->pc);
733                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)                          if (cpu->cd.mips.gpr[MIPS_GPR_GP] != 0)
734                                  debug(" (gp=0x%016llx)", (long long)                                  debug(" (gp=0x%016"PRIx64")", (uint64_t)
735                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);                                      cpu->cd.mips.gpr[MIPS_GPR_GP]);
736                  }                  }
737                  break;                  break;
         case ARCH_PPC:  
                 if (cpu->cd.ppc.bits == 32)  
                         debug("0x%08x", (int)entrypoint);  
                 else  
                         debug("0x%016llx", (long long)entrypoint);  
                 break;  
         case ARCH_URISC:  
                 {  
                         char tmps[100];  
                         unsigned char buf[sizeof(uint64_t)];  
   
                         cpu->memory_rw(cpu, m->memory, 0, buf, sizeof(buf),  
                             MEM_READ, CACHE_NONE | NO_EXCEPTIONS);  
   
                         entrypoint = 0;  
                         for (i=0; i<cpu->cd.urisc.wordlen/8; i++) {  
                                 entrypoint <<= 8;  
                                 if (cpu->byte_order == EMUL_BIG_ENDIAN)  
                                         entrypoint += buf[i];  
                                 else  
                                         entrypoint += buf[cpu->  
                                             cd.urisc.wordlen/8 - 1 - i];  
                         }  
738    
                         sprintf(tmps, "0x%%0%illx", cpu->cd.urisc.wordlen / 4);  
                         debug(tmps, (long long)entrypoint);  
                         cpu->pc = entrypoint;  
                 }  
                 break;  
         case ARCH_X86:  
                 if (cpu->cd.x86.mode == 16)  
                         debug("0x%04x:0x%04x", cpu->cd.x86.s[X86_S_CS],  
                             (int)cpu->pc);  
                 else if (cpu->cd.x86.mode == 32)  
                         debug("0x%08x", (int)cpu->pc);  
                 else  
                         debug("0x%016llx", (long long)cpu->pc);  
                 break;  
739          default:          default:
740                  debug("0x%016llx", (long long)cpu->pc);                  if (cpu->is_32bit)
741                            debug("0x%08"PRIx32, (uint32_t) cpu->pc);
742                    else
743                            debug("0x%016"PRIx64, (uint64_t) cpu->pc);
744          }          }
745          debug("\n");          debug("\n");
746    
# Line 788  void emul_machine_setup(struct machine * Line 755  void emul_machine_setup(struct machine *
755   */   */
756  void emul_dumpinfo(struct emul *e)  void emul_dumpinfo(struct emul *e)
757  {  {
758          int j, nm, iadd = 4;          int i;
759    
760          if (e->net != NULL)          if (e->net != NULL)
761                  net_dumpinfo(e->net);                  net_dumpinfo(e->net);
762    
763          nm = e->n_machines;          for (i = 0; i < e->n_machines; i++) {
764          for (j=0; j<nm; j++) {                  if (e->n_machines > 1)
765                  debug("machine %i: \"%s\"\n", j, e->machines[j]->name);                          debug("machine %i: \"%s\"\n", i, e->machines[i]->name);
766                  debug_indentation(iadd);                  else
767                  machine_dumpinfo(e->machines[j]);                          debug("machine:\n");
768                  debug_indentation(-iadd);  
769                    debug_indentation(DEBUG_INDENTATION);
770    
771                    machine_dumpinfo(e->machines[i]);
772    
773                    debug_indentation(-DEBUG_INDENTATION);
774          }          }
775  }  }
776    
# Line 817  void emul_dumpinfo(struct emul *e) Line 789  void emul_dumpinfo(struct emul *e)
789   */   */
790  void emul_simple_init(struct emul *emul)  void emul_simple_init(struct emul *emul)
791  {  {
792          int iadd=4;          int iadd = DEBUG_INDENTATION;
793          struct machine *m;          struct machine *m;
794    
795          if (emul->n_machines != 1) {          if (emul->n_machines != 1) {
# Line 831  void emul_simple_init(struct emul *emul) Line 803  void emul_simple_init(struct emul *emul)
803                  debug("Simple setup...\n");                  debug("Simple setup...\n");
804                  debug_indentation(iadd);                  debug_indentation(iadd);
805    
806                  /*  Create a network:  */                  /*  Create a simple network:  */
807                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,                  emul->net = net_init(emul, NET_INIT_FLAG_GATEWAY,
808                      "10.0.0.0", 8);                      NET_DEFAULT_IPV4_MASK,
809                        NET_DEFAULT_IPV4_LEN,
810                        NULL, 0, 0, NULL);
811          } else {          } else {
812                  /*  Userland pseudo-machine:  */                  /*  Userland pseudo-machine:  */
813                  debug("Syscall emulation (userland-only) setup...\n");                  debug("Syscall emulation (userland-only) setup...\n");
# Line 854  void emul_simple_init(struct emul *emul) Line 828  void emul_simple_init(struct emul *emul)
828   */   */
829  struct emul *emul_create_from_configfile(char *fname)  struct emul *emul_create_from_configfile(char *fname)
830  {  {
831          int iadd = 4;          int iadd = DEBUG_INDENTATION;
832          struct emul *e = emul_new(fname);          struct emul *e = emul_new(fname);
         FILE *f;  
         char buf[128];  
         size_t len;  
833    
834          debug("Creating emulation from configfile \"%s\":\n", fname);          debug("Creating emulation from configfile \"%s\":\n", fname);
835          debug_indentation(iadd);          debug_indentation(iadd);
836    
837          f = fopen(fname, "r");          emul_parse_config(e, fname);
         if (f == NULL) {  
                 perror(fname);  
                 exit(1);  
         }  
   
         /*  Read header: (must be !!gxemul)  */  
         len = fread(buf, 1, 8, f);  
         if (len != 8 || strncmp(buf, "!!gxemul", 8) != 0) {  
                 fprintf(stderr, "%s: must start with '!!gxemul'\n", fname);  
                 exit(1);  
         }  
   
         /*  Restart from beginning:  */  
         rewind(f);  
838    
         emul_parse_config(e, f);  
   
         fclose(f);  
839          debug_indentation(-iadd);          debug_indentation(-iadd);
840          return e;          return e;
841  }  }
# Line 890  struct emul *emul_create_from_configfile Line 844  struct emul *emul_create_from_configfile
844  /*  /*
845   *  emul_run():   *  emul_run():
846   *   *
847   *      o)  Set up things needed before running emulations.   *      o)  Set up things needed before running an emulation.
848   *   *
849   *      o)  Run emulations (one or more, in parallel).   *      o)  Run instructions in all machines.
850   *   *
851   *      o)  De-initialize things.   *      o)  De-initialize things.
852   */   */
853  void emul_run(struct emul **emuls, int n_emuls)  void emul_run(struct emul *emul)
854  {  {
         struct emul *e;  
855          int i = 0, j, go = 1, n, anything;          int i = 0, j, go = 1, n, anything;
856    
         if (n_emuls < 1) {  
                 fprintf(stderr, "emul_run(): no thing to do\n");  
                 return;  
         }  
   
857          atexit(fix_console);          atexit(fix_console);
858    
         i = 79;  
         while (i-- > 0)  
                 debug("-");  
         debug("\n\n");  
   
859          /*  Initialize the interactive debugger:  */          /*  Initialize the interactive debugger:  */
860          debugger_init(emuls, n_emuls);          debugger_init(emul);
861    
862            /*  Run any additional debugger commands before starting:  */
863            if (emul->n_debugger_cmds > 0) {
864                    int j;
865                    if (i == 0)
866                            print_separator_line();
867                    for (j = 0; j < emul->n_debugger_cmds; j ++) {
868                            debug("> %s\n", emul->debugger_cmds[j]);
869                            debugger_execute_cmd(emul->debugger_cmds[j],
870                                strlen(emul->debugger_cmds[j]));
871                    }
872            }
873    
874            print_separator_line();
875            debug("\n");
876    
877    
878          /*          /*
879           *  console_init_main() makes sure that the terminal is in a           *  console_init_main() makes sure that the terminal is in a
# Line 926  void emul_run(struct emul **emuls, int n Line 885  void emul_run(struct emul **emuls, int n
885           *  (or sends SIGSTOP) and then continues. It makes sure that the           *  (or sends SIGSTOP) and then continues. It makes sure that the
886           *  terminal is in an expected state.           *  terminal is in an expected state.
887           */           */
888          console_init_main(emuls[0]);    /*  TODO: what is a good argument?  */          console_init_main(emul);
889    
890          signal(SIGINT, debugger_activate);          signal(SIGINT, debugger_activate);
891          signal(SIGCONT, console_sigcont);          signal(SIGCONT, console_sigcont);
892    
# Line 934  void emul_run(struct emul **emuls, int n Line 894  void emul_run(struct emul **emuls, int n
894          if (!verbose)          if (!verbose)
895                  quiet_mode = 1;                  quiet_mode = 1;
896    
897          /*  Initialize all CPUs in all machines in all emulations:  */  
898          for (i=0; i<n_emuls; i++) {          /*  Initialize all CPUs in all machines:  */
899                  e = emuls[i];          for (j=0; j<emul->n_machines; j++)
900                  if (e == NULL)                  cpu_run_init(emul->machines[j]);
901                          continue;  
902                  for (j=0; j<e->n_machines; j++)          /*  TODO: Generalize:  */
903                          cpu_run_init(e, e->machines[j]);          if (emul->machines[0]->show_trace_tree)
904          }                  cpu_functioncall_trace(emul->machines[0]->cpus[0],
905                        emul->machines[0]->cpus[0]->pc);
906    
907            /*  Start emulated clocks:  */
908            timer_start();
909    
910    
911          /*          /*
912           *  MAIN LOOP:           *  MAIN LOOP:
913           *           *
914           *  Run all emulations in parallel, running each machine in           *  Run all emulations in parallel, running instructions from each
915           *  each emulation.           *  cpu in each machine.
916           */           */
917          while (go) {          while (go) {
918                    struct cpu *bootcpu = emul->machines[0]->cpus[
919                        emul->machines[0]->bootstrap_cpu];
920    
921                  go = 0;                  go = 0;
922    
923                  x11_check_event(emuls, n_emuls);                  /*  Flush X11 and serial console output every now and then:  */
924                    if (bootcpu->ninstrs > bootcpu->ninstrs_flush + (1<<19)) {
925                            x11_check_event(emul);
926                            console_flush();
927                            bootcpu->ninstrs_flush = bootcpu->ninstrs;
928                    }
929    
930                  for (i=0; i<n_emuls; i++) {                  if (bootcpu->ninstrs > bootcpu->ninstrs_show + (1<<25)) {
931                          e = emuls[i];                          bootcpu->ninstrs_since_gettimeofday +=
932                          if (e == NULL)                              (bootcpu->ninstrs - bootcpu->ninstrs_show);
933                                  continue;                          cpu_show_cycles(emul->machines[0], 0);
934                            bootcpu->ninstrs_show = bootcpu->ninstrs;
935                          for (j=0; j<e->n_machines; j++) {                  }
936                                  /*  TODO: cpu_run() is a strange name, since  
937                                      there can be multiple cpus in a machine  */                  if (single_step == ENTER_SINGLE_STEPPING) {
938                                  anything = cpu_run(e, e->machines[j]);                          /*  TODO: Cleanup!  */
939                                  if (anything)                          old_instruction_trace =
940                                          go = 1;                              emul->machines[0]->instruction_trace;
941                          }                          old_quiet_mode = quiet_mode;
942                            old_show_trace_tree =
943                                emul->machines[0]->show_trace_tree;
944                            emul->machines[0]->instruction_trace = 1;
945                            emul->machines[0]->show_trace_tree = 1;
946                            quiet_mode = 0;
947                            single_step = SINGLE_STEPPING;
948                  }                  }
         }  
949    
950          /*  Deinitialize all CPUs in all machines in all emulations:  */                  if (single_step == SINGLE_STEPPING)
951          for (i=0; i<n_emuls; i++) {                          debugger();
952                  e = emuls[i];  
953                  if (e == NULL)                  for (j=0; j<emul->n_machines; j++) {
954                          continue;                          anything = machine_run(emul->machines[j]);
955                  for (j=0; j<e->n_machines; j++)                          if (anything)
956                          cpu_run_deinit(e, e->machines[j]);                                  go = 1;
957                    }
958          }          }
959    
960            /*  Stop any running timers:  */
961            timer_stop();
962    
963            /*  Deinitialize all CPUs in all machines:  */
964            for (j=0; j<emul->n_machines; j++)
965                    cpu_run_deinit(emul->machines[j]);
966    
967          /*  force_debugger_at_exit flag set? Then enter the debugger:  */          /*  force_debugger_at_exit flag set? Then enter the debugger:  */
968          if (force_debugger_at_exit) {          if (force_debugger_at_exit) {
969                  quiet_mode = 0;                  quiet_mode = 0;
# Line 985  void emul_run(struct emul **emuls, int n Line 971  void emul_run(struct emul **emuls, int n
971                  debugger();                  debugger();
972          }          }
973    
974          /*  Any machine using X11? Then we should wait before exiting:  */          /*  Any machine using X11? Then wait before exiting:  */
975          n = 0;          n = 0;
976          for (i=0; i<n_emuls; i++)          for (j=0; j<emul->n_machines; j++)
977                  for (j=0; j<emuls[i]->n_machines; j++)                  if (emul->machines[j]->x11_md.in_use)
978                          if (emuls[i]->machines[j]->use_x11)                          n++;
979                                  n++;  
980          if (n > 0) {          if (n > 0) {
981                  printf("Press enter to quit.\n");                  printf("Press enter to quit.\n");
982                  while (!console_charavail(MAIN_CONSOLE)) {                  while (!console_charavail(MAIN_CONSOLE)) {
983                          x11_check_event(emuls, n_emuls);                          x11_check_event(emul);
984                          usleep(1);                          usleep(10000);
985                  }                  }
986                  console_readchar(MAIN_CONSOLE);                  console_readchar(MAIN_CONSOLE);
987          }          }
988    
989          console_deinit();          console_deinit_main();
990  }  }
991    

Legend:
Removed from v.4  
changed lines
  Added in v.44

  ViewVC Help
Powered by ViewVC 1.1.26