/[gxemul]/upstream/0.4.3/src/machine.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

Annotation of /upstream/0.4.3/src/machine.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 33 - (hide annotations)
Mon Oct 8 16:21:06 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 33190 byte(s)
0.4.3
1 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 2 *
4     * Redistribution and use in source and binary forms, with or without
5     * modification, are permitted provided that the following conditions are met:
6     *
7     * 1. Redistributions of source code must retain the above copyright
8     * notice, this list of conditions and the following disclaimer.
9     * 2. Redistributions in binary form must reproduce the above copyright
10     * notice, this list of conditions and the following disclaimer in the
11     * documentation and/or other materials provided with the distribution.
12     * 3. The name of the author may not be used to endorse or promote products
13     * derived from this software without specific prior written permission.
14     *
15     * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18     * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19     * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20     * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21     * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24     * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25     * SUCH DAMAGE.
26     *
27     *
28 dpavlin 32 * $Id: machine.c,v 1.689 2006/10/04 11:56:40 debug Exp $
29 dpavlin 2 */
30    
31     #include <stdio.h>
32     #include <stdlib.h>
33     #include <stdarg.h>
34     #include <string.h>
35     #include <time.h>
36     #include <unistd.h>
37    
38     #include "arcbios.h"
39 dpavlin 20 #include "bus_isa.h"
40 dpavlin 2 #include "bus_pci.h"
41     #include "cpu.h"
42 dpavlin 26 #include "debugger.h"
43 dpavlin 2 #include "device.h"
44     #include "devices.h"
45     #include "diskimage.h"
46     #include "emul.h"
47     #include "machine.h"
48 dpavlin 22 #include "machine_interrupts.h"
49 dpavlin 2 #include "memory.h"
50     #include "misc.h"
51     #include "net.h"
52 dpavlin 32 #include "settings.h"
53 dpavlin 2 #include "symbol.h"
54    
55 dpavlin 12
56 dpavlin 6 /* See main.c: */
57     extern int quiet_mode;
58 dpavlin 22 extern int verbose;
59 dpavlin 6
60    
61 dpavlin 2 /* This is initialized by machine_init(): */
62 dpavlin 22 struct machine_entry *first_machine_entry = NULL;
63 dpavlin 2
64    
65     /*
66     * machine_new():
67     *
68     * Returns a reasonably initialized struct machine.
69     */
70     struct machine *machine_new(char *name, struct emul *emul)
71     {
72     struct machine *m;
73     m = malloc(sizeof(struct machine));
74     if (m == NULL) {
75     fprintf(stderr, "machine_new(): out of memory\n");
76     exit(1);
77     }
78    
79     memset(m, 0, sizeof(struct machine));
80    
81 dpavlin 32 /* Pointer back to the emul object that this machine belongs to: */
82 dpavlin 2 m->emul = emul;
83    
84     m->name = strdup(name);
85    
86     /* Sane default values: */
87 dpavlin 10 m->serial_nr = 1;
88 dpavlin 2 m->machine_type = MACHINE_NONE;
89     m->machine_subtype = MACHINE_NONE;
90 dpavlin 12 m->arch_pagesize = 4096; /* Should be overriden in
91     emul.c for other pagesizes. */
92 dpavlin 2 m->prom_emulation = 1;
93 dpavlin 28 m->allow_instruction_combinations = 1;
94 dpavlin 2 m->byte_order_override = NO_BYTE_ORDER_OVERRIDE;
95     m->boot_kernel_filename = "";
96     m->boot_string_argument = NULL;
97     m->x11_scaledown = 1;
98 dpavlin 20 m->x11_scaleup = 1;
99 dpavlin 2 m->n_gfx_cards = 1;
100     m->dbe_on_nonexistant_memaccess = 1;
101     m->show_symbolic_register_names = 1;
102     symbol_init(&m->symbol_context);
103    
104 dpavlin 32 /* Settings: */
105     m->settings = settings_new();
106     settings_add(m->settings, "name", 0,
107     SETTINGS_TYPE_STRING, SETTINGS_FORMAT_STRING,
108     (void *) &m->name);
109     settings_add(m->settings, "serial_nr", 0,
110     SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
111     (void *) &m->serial_nr);
112     settings_add(m->settings, "arch_pagesize", 0,
113     SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
114     (void *) &m->arch_pagesize);
115     settings_add(m->settings, "prom_emulation", 0,
116     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
117     (void *) &m->prom_emulation);
118     settings_add(m->settings, "allow_instruction_combinations", 0,
119     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
120     (void *) &m->allow_instruction_combinations);
121     settings_add(m->settings, "n_gfx_cards", 0,
122     SETTINGS_TYPE_INT, SETTINGS_FORMAT_DECIMAL,
123     (void *) &m->n_gfx_cards);
124     settings_add(m->settings, "show_symbolic_register_names", 1,
125     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
126     (void *) &m->show_symbolic_register_names);
127     settings_add(m->settings, "statistics_enabled", 1,
128     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO,
129     (void *) &m->statistics_enabled);
130    
131 dpavlin 2 return m;
132     }
133    
134    
135     /*
136 dpavlin 32 * machine_destroy():
137     *
138     * Destroys a machine object.
139     */
140     void machine_destroy(struct machine *machine)
141     {
142     int i;
143    
144     for (i=0; i<machine->ncpus; i++)
145     cpu_destroy(machine->cpus[i]);
146    
147     if (machine->name != NULL)
148     free(machine->name);
149    
150     /* Remove any remaining level-1 settings: */
151     settings_remove_all(machine->settings);
152     settings_destroy(machine->settings);
153    
154     free(machine);
155     }
156    
157    
158     /*
159 dpavlin 2 * machine_name_to_type():
160     *
161     * Take a type and a subtype as strings, and convert them into numeric
162     * values used internally throughout the code.
163     *
164     * Return value is 1 on success, 0 if there was no match.
165     * Also, any errors/warnings are printed using fatal()/debug().
166     */
167     int machine_name_to_type(char *stype, char *ssubtype,
168     int *type, int *subtype, int *arch)
169     {
170     struct machine_entry *me;
171 dpavlin 12 int i, j, k, nmatches = 0;
172 dpavlin 2
173     *type = MACHINE_NONE;
174     *subtype = 0;
175    
176 dpavlin 12 /* Check stype, and optionally ssubtype: */
177 dpavlin 2 me = first_machine_entry;
178     while (me != NULL) {
179     for (i=0; i<me->n_aliases; i++)
180     if (strcasecmp(me->aliases[i], stype) == 0) {
181     /* Found a type: */
182     *type = me->machine_type;
183     *arch = me->arch;
184    
185     if (me->n_subtypes == 0)
186     return 1;
187    
188     /* Check for subtype: */
189     for (j=0; j<me->n_subtypes; j++)
190     for (k=0; k<me->subtype[j]->n_aliases;
191     k++)
192     if (strcasecmp(ssubtype,
193     me->subtype[j]->aliases[k]
194     ) == 0) {
195     *subtype = me->subtype[
196     j]->machine_subtype;
197     return 1;
198     }
199    
200 dpavlin 6 fatal("Unknown subtype '%s' for emulation"
201 dpavlin 2 " '%s'\n", ssubtype, stype);
202 dpavlin 6 if (!ssubtype[0])
203     fatal("(Maybe you forgot the -e"
204     " command line option?)\n");
205 dpavlin 2 exit(1);
206     }
207    
208     me = me->next;
209     }
210    
211 dpavlin 12 /* Not found? Then just check ssubtype: */
212     me = first_machine_entry;
213     while (me != NULL) {
214     if (me->n_subtypes == 0) {
215     me = me->next;
216     continue;
217     }
218    
219     /* Check for subtype: */
220     for (j=0; j<me->n_subtypes; j++)
221     for (k=0; k<me->subtype[j]->n_aliases; k++)
222     if (strcasecmp(ssubtype, me->subtype[j]->
223     aliases[k]) == 0) {
224     *type = me->machine_type;
225     *arch = me->arch;
226     *subtype = me->subtype[j]->
227     machine_subtype;
228     nmatches ++;
229     }
230    
231     me = me->next;
232     }
233    
234     switch (nmatches) {
235     case 0: fatal("\nSorry, emulation \"%s\"", stype);
236     if (ssubtype != NULL && ssubtype[0] != '\0')
237     fatal(" (subtype \"%s\")", ssubtype);
238     fatal(" is unknown.\n");
239     break;
240     case 1: return 1;
241     default:fatal("\nSorry, multiple matches for \"%s\"", stype);
242     if (ssubtype != NULL && ssubtype[0] != '\0')
243     fatal(" (subtype \"%s\")", ssubtype);
244     fatal(".\n");
245     }
246    
247     *type = MACHINE_NONE;
248     *subtype = 0;
249    
250     fatal("Use the -H command line option to get a list of "
251     "available types and subtypes.\n\n");
252    
253 dpavlin 2 return 0;
254     }
255    
256    
257     /*
258     * machine_add_tickfunction():
259     *
260     * Adds a tick function (a function called every now and then, depending on
261     * clock cycle count) to a machine.
262 dpavlin 24 *
263     * If tickshift is non-zero, a tick will occur every (1 << tickshift) cycles.
264     * This is used for the normal (fast dyntrans) emulation modes.
265     *
266     * If tickshift is zero, then this is a cycle-accurate tick function.
267     * The hz value is used in this case.
268 dpavlin 2 */
269     void machine_add_tickfunction(struct machine *machine, void (*func)
270 dpavlin 24 (struct cpu *, void *), void *extra, int tickshift, double hz)
271 dpavlin 2 {
272     int n = machine->n_tick_entries;
273    
274     if (n >= MAX_TICK_FUNCTIONS) {
275     fprintf(stderr, "machine_add_tickfunction(): too "
276     "many tick functions\n");
277     exit(1);
278     }
279    
280 dpavlin 24 if (!machine->cycle_accurate) {
281     /*
282     * The dyntrans subsystem wants to run code in relatively
283 dpavlin 32 * large chunks without checking for external interrupts;
284     * too low tickshifts are not allowed.
285 dpavlin 24 */
286     if (tickshift < N_SAFE_DYNTRANS_LIMIT_SHIFT) {
287     fatal("ERROR! tickshift = %i, less than "
288     "N_SAFE_DYNTRANS_LIMIT_SHIFT (%i)\n",
289     tickshift, N_SAFE_DYNTRANS_LIMIT_SHIFT);
290     exit(1);
291     }
292     }
293 dpavlin 2
294     machine->ticks_till_next[n] = 0;
295 dpavlin 24 machine->ticks_reset_value[n] = 1 << tickshift;
296 dpavlin 2 machine->tick_func[n] = func;
297     machine->tick_extra[n] = extra;
298 dpavlin 24 machine->tick_hz[n] = hz;
299 dpavlin 2
300     machine->n_tick_entries ++;
301     }
302    
303    
304 dpavlin 22 /*
305 dpavlin 28 * machine_statistics_init():
306     *
307     * Initialize the parts of a machine struct that deal with instruction
308     * statistics gathering.
309     *
310     * Note: The fname argument contains "flags:filename".
311     */
312     void machine_statistics_init(struct machine *machine, char *fname)
313     {
314     int n_fields = 0;
315     char *pcolon = fname;
316     char *mode = "a"; /* Append by default */
317    
318     machine->allow_instruction_combinations = 0;
319    
320     if (machine->statistics_fields != NULL) {
321     fprintf(stderr, "Only one -s option is allowed.\n");
322     exit(1);
323     }
324    
325     machine->statistics_fields = malloc(MAX_STATISTICS_FIELDS + 1);
326     machine->statistics_enabled = 1;
327    
328     while (*pcolon && *pcolon != ':')
329     pcolon ++;
330    
331     if (*pcolon != ':') {
332     fprintf(stderr, "The syntax for the -s option is: "
333     "-s flags:filename\nYou omitted the flags. Run g"
334     "xemul -h for a list of available flags.\n");
335     exit(1);
336     }
337    
338     while (*fname != ':') {
339     switch (*fname) {
340    
341     /* Type flags: */
342     case 'v':
343     case 'i':
344     case 'p':
345     machine->statistics_fields[n_fields ++] = *fname;
346     if (n_fields >= MAX_STATISTICS_FIELDS) {
347     fprintf(stderr, "Internal error: Too many "
348     "statistics fields used. Increase "
349     "MAX_STATISTICS_FIELDS.\n");
350     exit(1);
351     }
352     machine->statistics_fields[n_fields] = '\0';
353     break;
354    
355     /* Optional flags: */
356     case 'o':
357     mode = "w";
358     break;
359     case 'd':
360     machine->statistics_enabled = 0;
361     break;
362    
363     default:fprintf(stderr, "Unknown flag '%c' used with the"
364     " -s option. Aborting.\n", *fname);
365     exit(1);
366     }
367     fname ++;
368     }
369    
370     fname ++; /* point to the filename after the colon */
371    
372     machine->statistics_filename = strdup(fname);
373     machine->statistics_file = fopen(machine->statistics_filename, mode);
374     }
375    
376    
377     /*
378 dpavlin 22 * machine_bus_register():
379     *
380     * Registers a bus in a machine.
381     */
382     void machine_bus_register(struct machine *machine, char *busname,
383     void (*debug_dump)(void *), void *extra)
384     {
385     struct machine_bus *tmp, *last = NULL, *new;
386 dpavlin 2
387 dpavlin 22 new = zeroed_alloc(sizeof(struct machine_bus));
388     new->name = strdup(busname);
389     new->debug_dump = debug_dump;
390     new->extra = extra;
391 dpavlin 2
392 dpavlin 22 /* Register last in the bus list: */
393     tmp = machine->first_bus;
394     while (tmp != NULL) {
395     last = tmp;
396     tmp = tmp->next;
397     }
398    
399     if (last == NULL)
400     machine->first_bus = new;
401     else
402     last->next = new;
403    
404     machine->n_busses ++;
405     }
406    
407    
408     /*
409     * machine_dump_bus_info():
410     *
411     * Dumps info about registered busses.
412     */
413     void machine_dump_bus_info(struct machine *m)
414 dpavlin 2 {
415 dpavlin 22 struct machine_bus *bus = m->first_bus;
416     int iadd = DEBUG_INDENTATION;
417    
418     if (m->n_busses > 0)
419     debug("busses:\n");
420     debug_indentation(iadd);
421     while (bus != NULL) {
422     bus->debug_dump(bus->extra);
423     bus = bus->next;
424     }
425     debug_indentation(-iadd);
426 dpavlin 2 }
427    
428    
429     /*
430 dpavlin 22 * machine_dumpinfo():
431     *
432     * Dumps info about a machine in some kind of readable format. (Used by
433     * the 'machine' debugger command.)
434     */
435     void machine_dumpinfo(struct machine *m)
436     {
437     int i;
438    
439     debug("serial nr: %i", m->serial_nr);
440     if (m->nr_of_nics > 0)
441     debug(" (nr of NICs: %i)", m->nr_of_nics);
442     debug("\n");
443    
444     debug("memory: %i MB", m->physical_ram_in_mb);
445     if (m->memory_offset_in_mb != 0)
446     debug(" (offset by %i MB)", m->memory_offset_in_mb);
447     if (m->random_mem_contents)
448     debug(", randomized contents");
449     if (m->dbe_on_nonexistant_memaccess)
450     debug(", dbe_on_nonexistant_memaccess");
451     debug("\n");
452    
453     if (!m->prom_emulation)
454     debug("PROM emulation disabled\n");
455    
456     for (i=0; i<m->ncpus; i++)
457     cpu_dumpinfo(m, m->cpus[i]);
458    
459     if (m->ncpus > 1)
460     debug("Bootstrap cpu is nr %i\n", m->bootstrap_cpu);
461    
462     if (m->slow_serial_interrupts_hack_for_linux)
463     debug("Using slow_serial_interrupts_hack_for_linux\n");
464    
465     if (m->use_x11) {
466     debug("Using X11");
467     if (m->x11_scaledown > 1)
468     debug(", scaledown %i", m->x11_scaledown);
469     if (m->x11_scaleup > 1)
470     debug(", scaleup %i", m->x11_scaleup);
471     if (m->x11_n_display_names > 0) {
472     for (i=0; i<m->x11_n_display_names; i++) {
473     debug(i? ", " : " (");
474     debug("\"%s\"", m->x11_display_names[i]);
475     }
476     debug(")");
477     }
478     debug("\n");
479     }
480    
481     machine_dump_bus_info(m);
482    
483     diskimage_dump_info(m);
484    
485     if (m->force_netboot)
486     debug("Forced netboot\n");
487     }
488    
489    
490     /*
491 dpavlin 2 * dump_mem_string():
492     *
493     * Dump the contents of emulated RAM as readable text. Bytes that aren't
494     * readable are dumped in [xx] notation, where xx is in hexadecimal.
495     * Dumping ends after DUMP_MEM_STRING_MAX bytes, or when a terminating
496     * zero byte is found.
497     */
498     #define DUMP_MEM_STRING_MAX 45
499     void dump_mem_string(struct cpu *cpu, uint64_t addr)
500     {
501     int i;
502     for (i=0; i<DUMP_MEM_STRING_MAX; i++) {
503     unsigned char ch = '\0';
504    
505     cpu->memory_rw(cpu, cpu->mem, addr + i, &ch, sizeof(ch),
506     MEM_READ, CACHE_DATA | NO_EXCEPTIONS);
507     if (ch == '\0')
508     return;
509     if (ch >= ' ' && ch < 126)
510     debug("%c", ch);
511     else
512     debug("[%02x]", ch);
513     }
514     }
515    
516    
517     /*
518     * store_byte():
519     *
520     * Stores a byte in emulated ram. (Helper function.)
521     */
522     void store_byte(struct cpu *cpu, uint64_t addr, uint8_t data)
523     {
524     if ((addr >> 32) == 0)
525     addr = (int64_t)(int32_t)addr;
526     cpu->memory_rw(cpu, cpu->mem,
527     addr, &data, sizeof(data), MEM_WRITE, CACHE_DATA);
528     }
529    
530    
531     /*
532     * store_string():
533     *
534     * Stores chars into emulated RAM until a zero byte (string terminating
535     * character) is found. The zero byte is also copied.
536     * (strcpy()-like helper function, host-RAM-to-emulated-RAM.)
537     */
538     void store_string(struct cpu *cpu, uint64_t addr, char *s)
539     {
540     do {
541     store_byte(cpu, addr++, *s);
542     } while (*s++);
543     }
544    
545    
546     /*
547     * add_environment_string():
548     *
549     * Like store_string(), but advances the pointer afterwards. The most
550     * obvious use is to place a number of strings (such as environment variable
551     * strings) after one-another in emulated memory.
552     */
553     void add_environment_string(struct cpu *cpu, char *s, uint64_t *addr)
554     {
555     store_string(cpu, *addr, s);
556     (*addr) += strlen(s) + 1;
557     }
558    
559    
560     /*
561 dpavlin 12 * add_environment_string_dual():
562     *
563     * Add "dual" environment strings, one for the variable name and one for the
564     * value, and update pointers afterwards.
565     */
566     void add_environment_string_dual(struct cpu *cpu,
567     uint64_t *ptrp, uint64_t *addrp, char *s1, char *s2)
568     {
569     uint64_t ptr = *ptrp, addr = *addrp;
570    
571     store_32bit_word(cpu, ptr, addr);
572     ptr += sizeof(uint32_t);
573     if (addr != 0) {
574     store_string(cpu, addr, s1);
575     addr += strlen(s1) + 1;
576     }
577     store_32bit_word(cpu, ptr, addr);
578     ptr += sizeof(uint32_t);
579     if (addr != 0) {
580     store_string(cpu, addr, s2);
581     addr += strlen(s2) + 1;
582     }
583    
584     *ptrp = ptr;
585     *addrp = addr;
586     }
587    
588    
589     /*
590 dpavlin 2 * store_64bit_word():
591     *
592     * Stores a 64-bit word in emulated RAM. Byte order is taken into account.
593     * Helper function.
594     */
595     int store_64bit_word(struct cpu *cpu, uint64_t addr, uint64_t data64)
596     {
597     unsigned char data[8];
598     if ((addr >> 32) == 0)
599     addr = (int64_t)(int32_t)addr;
600     data[0] = (data64 >> 56) & 255;
601     data[1] = (data64 >> 48) & 255;
602     data[2] = (data64 >> 40) & 255;
603     data[3] = (data64 >> 32) & 255;
604     data[4] = (data64 >> 24) & 255;
605     data[5] = (data64 >> 16) & 255;
606     data[6] = (data64 >> 8) & 255;
607     data[7] = (data64) & 255;
608     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
609     int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
610     tmp = data[1]; data[1] = data[6]; data[6] = tmp;
611     tmp = data[2]; data[2] = data[5]; data[5] = tmp;
612     tmp = data[3]; data[3] = data[4]; data[4] = tmp;
613     }
614     return cpu->memory_rw(cpu, cpu->mem,
615     addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
616     }
617    
618    
619     /*
620     * store_32bit_word():
621     *
622     * Stores a 32-bit word in emulated RAM. Byte order is taken into account.
623     * (This function takes a 64-bit word as argument, to suppress some
624     * warnings, but only the lowest 32 bits are used.)
625     */
626     int store_32bit_word(struct cpu *cpu, uint64_t addr, uint64_t data32)
627     {
628     unsigned char data[4];
629 dpavlin 32
630     /* TODO: REMOVE THIS once everything is more stable! */
631 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
632 dpavlin 2 addr = (int64_t)(int32_t)addr;
633 dpavlin 32
634 dpavlin 2 data[0] = (data32 >> 24) & 255;
635     data[1] = (data32 >> 16) & 255;
636     data[2] = (data32 >> 8) & 255;
637     data[3] = (data32) & 255;
638     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
639     int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
640     tmp = data[1]; data[1] = data[2]; data[2] = tmp;
641     }
642     return cpu->memory_rw(cpu, cpu->mem,
643     addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
644     }
645    
646    
647     /*
648     * store_16bit_word():
649     *
650     * Stores a 16-bit word in emulated RAM. Byte order is taken into account.
651     * (This function takes a 64-bit word as argument, to suppress some
652     * warnings, but only the lowest 16 bits are used.)
653     */
654     int store_16bit_word(struct cpu *cpu, uint64_t addr, uint64_t data16)
655     {
656     unsigned char data[2];
657 dpavlin 32
658     /* TODO: REMOVE THIS once everything is more stable! */
659 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
660 dpavlin 2 addr = (int64_t)(int32_t)addr;
661 dpavlin 32
662 dpavlin 2 data[0] = (data16 >> 8) & 255;
663     data[1] = (data16) & 255;
664     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
665     int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
666     }
667     return cpu->memory_rw(cpu, cpu->mem,
668     addr, data, sizeof(data), MEM_WRITE, CACHE_DATA);
669     }
670    
671    
672     /*
673     * store_buf():
674     *
675     * memcpy()-like helper function, from host RAM to emulated RAM.
676     */
677     void store_buf(struct cpu *cpu, uint64_t addr, char *s, size_t len)
678     {
679 dpavlin 22 size_t psize = 1024; /* 1024 256 64 16 4 1 */
680 dpavlin 6
681 dpavlin 32 /* TODO: REMOVE THIS once everything is more stable! */
682 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
683 dpavlin 2 addr = (int64_t)(int32_t)addr;
684    
685 dpavlin 6 while (len != 0) {
686     if ((addr & (psize-1)) == 0) {
687     while (len >= psize) {
688     cpu->memory_rw(cpu, cpu->mem, addr,
689     (unsigned char *)s, psize, MEM_WRITE,
690     CACHE_DATA);
691     addr += psize;
692     s += psize;
693     len -= psize;
694     }
695 dpavlin 2 }
696 dpavlin 6 psize >>= 2;
697 dpavlin 2 }
698    
699     while (len-- != 0)
700     store_byte(cpu, addr++, *s++);
701     }
702    
703    
704     /*
705     * store_pointer_and_advance():
706     *
707     * Stores a 32-bit or 64-bit pointer in emulated RAM, and advances the
708 dpavlin 22 * target address. (Useful for e.g. ARCBIOS environment initialization.)
709 dpavlin 2 */
710     void store_pointer_and_advance(struct cpu *cpu, uint64_t *addrp,
711     uint64_t data, int flag64)
712     {
713     uint64_t addr = *addrp;
714     if (flag64) {
715     store_64bit_word(cpu, addr, data);
716     addr += 8;
717     } else {
718     store_32bit_word(cpu, addr, data);
719     addr += 4;
720     }
721     *addrp = addr;
722     }
723    
724    
725     /*
726 dpavlin 32 * load_64bit_word():
727     *
728     * Helper function. Emulated byte order is taken into account.
729     */
730     uint64_t load_64bit_word(struct cpu *cpu, uint64_t addr)
731     {
732     unsigned char data[8];
733    
734     cpu->memory_rw(cpu, cpu->mem,
735     addr, data, sizeof(data), MEM_READ, CACHE_DATA);
736    
737     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
738     int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
739     tmp = data[1]; data[1] = data[6]; data[6] = tmp;
740     tmp = data[2]; data[2] = data[5]; data[5] = tmp;
741     tmp = data[3]; data[3] = data[4]; data[4] = tmp;
742     }
743    
744     return
745     ((uint64_t)data[0] << 56) + ((uint64_t)data[1] << 48) +
746     ((uint64_t)data[2] << 40) + ((uint64_t)data[3] << 32) +
747     ((uint64_t)data[4] << 24) + ((uint64_t)data[5] << 16) +
748     ((uint64_t)data[6] << 8) + (uint64_t)data[7];
749     }
750    
751    
752     /*
753 dpavlin 2 * load_32bit_word():
754     *
755 dpavlin 32 * Helper function. Emulated byte order is taken into account.
756 dpavlin 2 */
757     uint32_t load_32bit_word(struct cpu *cpu, uint64_t addr)
758     {
759     unsigned char data[4];
760    
761 dpavlin 32 /* TODO: REMOVE THIS once everything is more stable! */
762 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
763 dpavlin 2 addr = (int64_t)(int32_t)addr;
764 dpavlin 32
765 dpavlin 2 cpu->memory_rw(cpu, cpu->mem,
766     addr, data, sizeof(data), MEM_READ, CACHE_DATA);
767    
768     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
769     int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
770     tmp = data[1]; data[1] = data[2]; data[2] = tmp;
771     }
772    
773     return (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + data[3];
774     }
775    
776    
777     /*
778 dpavlin 4 * load_16bit_word():
779     *
780 dpavlin 32 * Helper function. Emulated byte order is taken into account.
781 dpavlin 4 */
782     uint16_t load_16bit_word(struct cpu *cpu, uint64_t addr)
783     {
784     unsigned char data[2];
785    
786 dpavlin 32 /* TODO: REMOVE THIS once everything is more stable! */
787 dpavlin 14 if (cpu->machine->arch == ARCH_MIPS && (addr >> 32) == 0)
788 dpavlin 4 addr = (int64_t)(int32_t)addr;
789 dpavlin 32
790 dpavlin 4 cpu->memory_rw(cpu, cpu->mem,
791     addr, data, sizeof(data), MEM_READ, CACHE_DATA);
792    
793     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
794     int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
795     }
796    
797     return (data[0] << 8) + data[1];
798     }
799    
800    
801     /*
802 dpavlin 2 * store_64bit_word_in_host():
803     *
804     * Stores a 64-bit word in the _host's_ RAM. Emulated byte order is taken
805     * into account. This is useful when building structs in the host's RAM
806     * which will later be copied into emulated RAM.
807     */
808     void store_64bit_word_in_host(struct cpu *cpu,
809     unsigned char *data, uint64_t data64)
810     {
811     data[0] = (data64 >> 56) & 255;
812     data[1] = (data64 >> 48) & 255;
813     data[2] = (data64 >> 40) & 255;
814     data[3] = (data64 >> 32) & 255;
815     data[4] = (data64 >> 24) & 255;
816     data[5] = (data64 >> 16) & 255;
817     data[6] = (data64 >> 8) & 255;
818     data[7] = (data64) & 255;
819     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
820     int tmp = data[0]; data[0] = data[7]; data[7] = tmp;
821     tmp = data[1]; data[1] = data[6]; data[6] = tmp;
822     tmp = data[2]; data[2] = data[5]; data[5] = tmp;
823     tmp = data[3]; data[3] = data[4]; data[4] = tmp;
824     }
825     }
826    
827    
828     /*
829     * store_32bit_word_in_host():
830     *
831     * See comment for store_64bit_word_in_host().
832     *
833     * (Note: The data32 parameter is a uint64_t. This is done to suppress
834     * some warnings.)
835     */
836     void store_32bit_word_in_host(struct cpu *cpu,
837     unsigned char *data, uint64_t data32)
838     {
839     data[0] = (data32 >> 24) & 255;
840     data[1] = (data32 >> 16) & 255;
841     data[2] = (data32 >> 8) & 255;
842     data[3] = (data32) & 255;
843     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
844     int tmp = data[0]; data[0] = data[3]; data[3] = tmp;
845     tmp = data[1]; data[1] = data[2]; data[2] = tmp;
846     }
847     }
848    
849    
850     /*
851     * store_16bit_word_in_host():
852     *
853     * See comment for store_64bit_word_in_host().
854     */
855     void store_16bit_word_in_host(struct cpu *cpu,
856     unsigned char *data, uint16_t data16)
857     {
858     data[0] = (data16 >> 8) & 255;
859     data[1] = (data16) & 255;
860     if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {
861     int tmp = data[0]; data[0] = data[1]; data[1] = tmp;
862     }
863     }
864    
865    
866     /*
867     * machine_setup():
868     *
869     * This (rather large) function initializes memory, registers, and/or devices
870     * required by specific machine emulations.
871     */
872     void machine_setup(struct machine *machine)
873     {
874     struct memory *mem;
875 dpavlin 22 struct machine_entry *me;
876 dpavlin 2
877     /* Abreviation: :-) */
878     struct cpu *cpu = machine->cpus[machine->bootstrap_cpu];
879    
880 dpavlin 22 machine->bootdev_id = diskimage_bootdev(machine,
881     &machine->bootdev_type);
882 dpavlin 2
883     mem = cpu->mem;
884     machine->machine_name = NULL;
885    
886     /* TODO: Move this somewhere else? */
887     if (machine->boot_string_argument == NULL) {
888     switch (machine->machine_type) {
889     case MACHINE_ARC:
890     machine->boot_string_argument = "-aN";
891     break;
892 dpavlin 16 case MACHINE_CATS:
893     machine->boot_string_argument = "-A";
894     break;
895 dpavlin 22 case MACHINE_PMAX:
896 dpavlin 2 machine->boot_string_argument = "-a";
897     break;
898     default:
899     /* Important, because boot_string_argument should
900     not be set to NULL: */
901     machine->boot_string_argument = "";
902     }
903     }
904    
905    
906 dpavlin 22 /*
907     * If the machine has a setup function in src/machines/machine_*.c
908     * then use that one, otherwise use the old hardcoded stuff here:
909     */
910 dpavlin 2
911 dpavlin 22 me = first_machine_entry;
912     while (me != NULL) {
913     if (machine->machine_type == me->machine_type &&
914     me->setup != NULL) {
915     me->setup(machine, cpu);
916 dpavlin 2 break;
917     }
918 dpavlin 22 me = me->next;
919     }
920 dpavlin 2
921 dpavlin 22 if (me == NULL) {
922 dpavlin 2 fatal("Unknown emulation type %i\n", machine->machine_type);
923     exit(1);
924     }
925    
926     if (machine->machine_name != NULL)
927     debug("machine: %s", machine->machine_name);
928    
929     if (machine->emulated_hz > 0)
930     debug(" (%.2f MHz)", (float)machine->emulated_hz / 1000000);
931     debug("\n");
932    
933 dpavlin 22 if (machine->bootstr != NULL) {
934     debug("bootstring%s: %s", (machine->bootarg!=NULL &&
935     strlen(machine->bootarg) >= 1)? "(+bootarg)" : "",
936     machine->bootstr);
937     if (machine->bootarg != NULL && strlen(machine->bootarg) >= 1)
938     debug(" %s", machine->bootarg);
939 dpavlin 2 debug("\n");
940     }
941 dpavlin 22
942     if (verbose >= 2)
943     machine_dump_bus_info(machine);
944    
945     if (!machine->stable)
946     fatal("!\n! NOTE: This machine type is not implemented well"
947     " enough yet to run\n! any real-world code!"
948     " (At least, it hasn't been verified to do so.)\n!\n"
949     "! Please read the GXemul documentation for information"
950     " about which\n! machine types that actually work.\n!\n");
951 dpavlin 2 }
952    
953    
954     /*
955     * machine_memsize_fix():
956     *
957     * Sets physical_ram_in_mb (if not already set), and memory_offset_in_mb,
958     * depending on machine type.
959     */
960     void machine_memsize_fix(struct machine *m)
961     {
962     if (m == NULL) {
963     fatal("machine_defaultmemsize(): m == NULL?\n");
964     exit(1);
965     }
966    
967     if (m->physical_ram_in_mb == 0) {
968 dpavlin 22 struct machine_entry *me = first_machine_entry;
969     while (me != NULL) {
970     if (m->machine_type == me->machine_type &&
971     me->set_default_ram != NULL) {
972     me->set_default_ram(m);
973 dpavlin 2 break;
974     }
975 dpavlin 22 me = me->next;
976 dpavlin 2 }
977     }
978    
979 dpavlin 6 /* Special hack for hpcmips machines: */
980     if (m->machine_type == MACHINE_HPCMIPS) {
981 dpavlin 2 m->dbe_on_nonexistant_memaccess = 0;
982     }
983    
984 dpavlin 22 /* Special SGI memory offsets: (TODO: move this somewhere else) */
985 dpavlin 2 if (m->machine_type == MACHINE_SGI) {
986     switch (m->machine_subtype) {
987     case 20:
988     case 22:
989     case 24:
990     case 26:
991     m->memory_offset_in_mb = 128;
992     break;
993     case 28:
994     case 30:
995     m->memory_offset_in_mb = 512;
996     break;
997     }
998     }
999    
1000     if (m->physical_ram_in_mb == 0)
1001     m->physical_ram_in_mb = DEFAULT_RAM_IN_MB;
1002     }
1003    
1004    
1005     /*
1006     * machine_default_cputype():
1007     *
1008 dpavlin 22 * Sets m->cpu_name, if it isn't already set, depending on the machine type.
1009 dpavlin 2 */
1010     void machine_default_cputype(struct machine *m)
1011     {
1012 dpavlin 22 struct machine_entry *me;
1013    
1014 dpavlin 2 if (m == NULL) {
1015     fatal("machine_default_cputype(): m == NULL?\n");
1016     exit(1);
1017     }
1018    
1019 dpavlin 22 /* Already set? Then return. */
1020 dpavlin 2 if (m->cpu_name != NULL)
1021     return;
1022    
1023 dpavlin 22 me = first_machine_entry;
1024     while (me != NULL) {
1025     if (m->machine_type == me->machine_type &&
1026     me->set_default_cpu != NULL) {
1027     me->set_default_cpu(m);
1028 dpavlin 2 break;
1029     }
1030 dpavlin 22 me = me->next;
1031 dpavlin 2 }
1032    
1033     if (m->cpu_name == NULL) {
1034     fprintf(stderr, "machine_default_cputype(): no default"
1035     " cpu for machine type %i subtype %i\n",
1036     m->machine_type, m->machine_subtype);
1037     exit(1);
1038     }
1039     }
1040    
1041    
1042 dpavlin 26 /*****************************************************************************/
1043    
1044    
1045 dpavlin 2 /*
1046 dpavlin 26 * machine_run():
1047     *
1048     * Run one or more instructions on all CPUs in this machine. (Usually,
1049     * around N_SAFE_DYNTRANS_LIMIT instructions will be run by the dyntrans
1050     * system.)
1051     *
1052     * Return value is 1 if any CPU in this machine is still running,
1053     * or 0 if all CPUs are stopped.
1054     */
1055     int machine_run(struct machine *machine)
1056     {
1057     struct cpu **cpus = machine->cpus;
1058     int ncpus = machine->ncpus, cpu0instrs = 0, i, te;
1059    
1060     for (i=0; i<ncpus; i++) {
1061     if (cpus[i]->running) {
1062 dpavlin 28 int instrs_run = cpus[i]->run_instr(cpus[i]);
1063 dpavlin 26 if (i == 0)
1064     cpu0instrs += instrs_run;
1065     }
1066     }
1067    
1068     /*
1069     * Hardware 'ticks': (clocks, interrupt sources...)
1070     *
1071 dpavlin 28 * Here, cpu0instrs is the number of instructions executed on cpu0.
1072     *
1073     * TODO: This should be redesigned into some "mainbus" stuff instead!
1074 dpavlin 26 */
1075    
1076 dpavlin 28 machine->ninstrs += cpu0instrs;
1077 dpavlin 26
1078     for (te=0; te<machine->n_tick_entries; te++) {
1079     machine->ticks_till_next[te] -= cpu0instrs;
1080     if (machine->ticks_till_next[te] <= 0) {
1081     while (machine->ticks_till_next[te] <= 0) {
1082     machine->ticks_till_next[te] +=
1083     machine->ticks_reset_value[te];
1084     }
1085    
1086     machine->tick_func[te](cpus[0],
1087     machine->tick_extra[te]);
1088     }
1089     }
1090    
1091     /* Is any CPU still alive? */
1092     for (i=0; i<ncpus; i++)
1093     if (cpus[i]->running)
1094     return 1;
1095    
1096     return 0;
1097     }
1098    
1099    
1100     /*****************************************************************************/
1101    
1102    
1103     /*
1104 dpavlin 2 * machine_entry_new():
1105     *
1106     * This function creates a new machine_entry struct, and fills it with some
1107     * valid data; it is up to the caller to add additional data that weren't
1108 dpavlin 26 * passed as arguments to this function, such as alias names and machine
1109     * subtypes.
1110 dpavlin 2 */
1111 dpavlin 26 struct machine_entry *machine_entry_new(const char *name, int arch,
1112     int oldstyle_type)
1113 dpavlin 2 {
1114     struct machine_entry *me;
1115    
1116     me = malloc(sizeof(struct machine_entry));
1117     if (me == NULL) {
1118     fprintf(stderr, "machine_entry_new(): out of memory (1)\n");
1119     exit(1);
1120     }
1121    
1122     memset(me, 0, sizeof(struct machine_entry));
1123    
1124     me->name = name;
1125     me->arch = arch;
1126     me->machine_type = oldstyle_type;
1127 dpavlin 26 me->n_aliases = 0;
1128     me->aliases = NULL;
1129     me->n_subtypes = 0;
1130     me->setup = NULL;
1131    
1132     return me;
1133     }
1134    
1135    
1136     /*
1137     * machine_entry_add_alias():
1138     *
1139     * This function adds an "alias" to a machine entry.
1140     */
1141     void machine_entry_add_alias(struct machine_entry *me, const char *name)
1142     {
1143     me->n_aliases ++;
1144     me->aliases = realloc(me->aliases, sizeof(char *) * me->n_aliases);
1145 dpavlin 2 if (me->aliases == NULL) {
1146 dpavlin 26 fprintf(stderr, "out of memory\n");
1147 dpavlin 2 exit(1);
1148     }
1149    
1150 dpavlin 26 me->aliases[me->n_aliases - 1] = (char *) name;
1151 dpavlin 2 }
1152    
1153    
1154     /*
1155 dpavlin 26 * machine_entry_add_subtype():
1156 dpavlin 2 *
1157 dpavlin 26 * This function adds a subtype to a machine entry. The argument list after
1158     * oldstyle_subtype is a list of one or more char *, followed by NULL. E.g.:
1159 dpavlin 2 *
1160 dpavlin 26 * machine_entry_add_subtype(me, "Machine X", MACHINE_X,
1161     * "machine-x", "x", NULL);
1162 dpavlin 2 */
1163 dpavlin 26 void machine_entry_add_subtype(struct machine_entry *me, const char *name,
1164     int oldstyle_subtype, ...)
1165 dpavlin 2 {
1166 dpavlin 26 va_list argp;
1167 dpavlin 2 struct machine_entry_subtype *mes;
1168    
1169 dpavlin 26 /* Allocate a new subtype struct: */
1170 dpavlin 2 mes = malloc(sizeof(struct machine_entry_subtype));
1171     if (mes == NULL) {
1172     fprintf(stderr, "machine_entry_subtype_new(): out "
1173     "of memory (1)\n");
1174     exit(1);
1175     }
1176    
1177 dpavlin 26 /* Add the subtype to the machine entry: */
1178     me->n_subtypes ++;
1179     me->subtype = realloc(me->subtype, sizeof(struct
1180     machine_entry_subtype *) * me->n_subtypes);
1181     if (me->subtype == NULL) {
1182     fprintf(stderr, "out of memory\n");
1183     exit(1);
1184     }
1185     me->subtype[me->n_subtypes - 1] = mes;
1186    
1187     /* Fill the struct with subtype data: */
1188 dpavlin 2 memset(mes, 0, sizeof(struct machine_entry_subtype));
1189     mes->name = name;
1190 dpavlin 26 mes->machine_subtype = oldstyle_subtype;
1191    
1192     /* ... and all aliases: */
1193     mes->n_aliases = 0;
1194     mes->aliases = NULL;
1195    
1196     va_start(argp, oldstyle_subtype);
1197    
1198     for (;;) {
1199     char *s = va_arg(argp, char *);
1200     if (s == NULL)
1201     break;
1202    
1203     mes->n_aliases ++;
1204     mes->aliases = realloc(mes->aliases, sizeof(char *) *
1205     mes->n_aliases);
1206     if (mes->aliases == NULL) {
1207     fprintf(stderr, "out of memory\n");
1208     exit(1);
1209     }
1210    
1211     mes->aliases[mes->n_aliases - 1] = s;
1212 dpavlin 2 }
1213    
1214 dpavlin 26 va_end(argp);
1215 dpavlin 2 }
1216    
1217    
1218     /*
1219 dpavlin 26 * machine_entry_register():
1220 dpavlin 22 *
1221     * Inserts a new machine_entry into the machine entries list.
1222     */
1223 dpavlin 26 void machine_entry_register(struct machine_entry *me, int arch)
1224 dpavlin 22 {
1225     struct machine_entry *prev, *next;
1226    
1227     /* Only insert it if the architecture is implemented in this
1228     emulator configuration: */
1229     if (cpu_family_ptr_by_number(arch) == NULL)
1230     return;
1231    
1232     prev = NULL;
1233     next = first_machine_entry;
1234    
1235     for (;;) {
1236     if (next == NULL)
1237     break;
1238     if (strcasecmp(me->name, next->name) < 0)
1239     break;
1240    
1241     prev = next;
1242     next = next->next;
1243     }
1244    
1245     if (prev != NULL)
1246     prev->next = me;
1247     else
1248     first_machine_entry = me;
1249     me->next = next;
1250     }
1251    
1252    
1253     /*
1254 dpavlin 2 * machine_list_available_types_and_cpus():
1255     *
1256     * List all available machine types (for example when running the emulator
1257     * with just -H as command line argument).
1258     */
1259     void machine_list_available_types_and_cpus(void)
1260     {
1261     struct machine_entry *me;
1262 dpavlin 22 int iadd = DEBUG_INDENTATION * 2;
1263 dpavlin 2
1264     debug("Available CPU types:\n\n");
1265    
1266     debug_indentation(iadd);
1267     cpu_list_available_types();
1268     debug_indentation(-iadd);
1269    
1270     debug("\nMost of the CPU types are bogus, and not really implemented."
1271     " The main effect of\nselecting a specific CPU type is to choose "
1272     "what kind of 'id' it will have.\n\nAvailable machine types (with "
1273     "aliases) and their subtypes:\n\n");
1274    
1275     debug_indentation(iadd);
1276     me = first_machine_entry;
1277    
1278     if (me == NULL)
1279     fatal("No machines defined!\n");
1280    
1281     while (me != NULL) {
1282 dpavlin 22 int i, j, iadd = DEBUG_INDENTATION;
1283 dpavlin 2
1284 dpavlin 22 debug("%s [%s] (", me->name,
1285     cpu_family_ptr_by_number(me->arch)->name);
1286 dpavlin 2 for (i=0; i<me->n_aliases; i++)
1287     debug("%s\"%s\"", i? ", " : "", me->aliases[i]);
1288     debug(")\n");
1289    
1290     debug_indentation(iadd);
1291     for (i=0; i<me->n_subtypes; i++) {
1292     struct machine_entry_subtype *mes;
1293     mes = me->subtype[i];
1294     debug("- %s", mes->name);
1295     debug(" (");
1296     for (j=0; j<mes->n_aliases; j++)
1297     debug("%s\"%s\"", j? ", " : "",
1298     mes->aliases[j]);
1299     debug(")\n");
1300     }
1301     debug_indentation(-iadd);
1302    
1303     me = me->next;
1304     }
1305     debug_indentation(-iadd);
1306    
1307     debug("\nMost of the machine types are bogus too. Please read the "
1308 dpavlin 20 "GXemul documentation\nfor information about which machine types "
1309     "that actually work. Use the alias\nwhen selecting a machine type "
1310     "or subtype, not the real name.\n");
1311 dpavlin 2
1312 dpavlin 24 #ifdef UNSTABLE_DEVEL
1313 dpavlin 2 debug("\n");
1314    
1315     useremul_list_emuls();
1316 dpavlin 12 debug("Userland emulation works for programs with the complexity"
1317     " of Hello World,\nbut not much more.\n");
1318 dpavlin 24 #endif
1319 dpavlin 2 }
1320    
1321    
1322     /*
1323     * machine_init():
1324     *
1325     * This function should be called before any other machine_*() function
1326 dpavlin 22 * is used. automachine_init() registers all machines in src/machines/.
1327 dpavlin 2 */
1328     void machine_init(void)
1329     {
1330 dpavlin 22 if (first_machine_entry != NULL) {
1331     fatal("machine_init(): already called?\n");
1332     exit(1);
1333 dpavlin 14 }
1334    
1335 dpavlin 22 automachine_init();
1336 dpavlin 2 }
1337    

  ViewVC Help
Powered by ViewVC 1.1.26