1 /* exhaust.c: crippled pmars-like redcode simulator
2  * $Id: exhaust.c,v 1.3 2003/09/04 15:44:24 varfar Exp $
3  */
4 
5 /* This file is part of `exhaust', a memory array redcode simulator.
6  * Copyright (C) 2002 M Joonas Pihlaja
7  *
8  * This file falls under the GNU Public License, version 2.  See the
9  * file COPYING for details.  */
10 
11 #define VERSION 1
12 #define REVISION 9
13 #define PATCHLEVEL 2
14 
15 /* Note pmars incompatibility: Minimum warrior separation (minsep) is
16    handled wrong by pmars (prior to 0.8.6) when minsep < MAXLENGTH.
17    This affects running warriors in small cores since the other
18    warriors might be loaded outside of core (it might even crash).
19 */
20 #include <stdio.h>
21 #ifdef SYSV
22 #include <strings.h>
23 #else
24 #include <string.h>
25 #endif
26 #include <stdlib.h>
27 #include <time.h>
28 #include <ctype.h>
29 
30 #include "insn.h"		/* will */
31 #include "exhaust.h"		/* types */
32 #include "asm.h"		/* assembler proto */
33 #include "sim.h"		/* simulator proto */
34 
35 #include "compress.h"
36 #define FALSE (0==1)
37 #define TRUE (1==1)
38 
39 static unsigned int NWarriors = 0;
40 static warrior_t *Warriors = NULL;	/* [NWarriors] */
41 
42 static char **WarriorNames = NULL;	/* [NWarriors] */
43 /* File names of warriors. */
44 
45 static field_t *Positions = NULL;	/* [NWarriors] */
46 static field_t *StartPositions = NULL;	/* [NWarriors] */
47 /* Starting position of each warrior.
48  * The StartPositions[] array is a copy
49  * of Positions[], rotated by the number of
50  * the round, to emulate pMARS.
51  */
52 
53 static unsigned int *Deaths = NULL;	/* [NWarriors] */
54 
55 static unsigned **ScoresMatrix = NULL;	/* [NWarriors][NWarriors] for each matching */
56 
57 static pspace_t **PSpaces = NULL;	/* [NWarriors] */
58 /* p-spaces of warriors. */
59 
60 
61 /* Globals to communicate options from readargs() to main() */
62 int OPT_cycles = 80000;		/* cycles until tie */
63 unsigned int OPT_rounds = 1;	/* number of rounds to fight */
64 unsigned int OPT_coresize = 8000;	/* default core size */
65 unsigned int OPT_minsep = 0;	/* minimum distance between warriors */
66 int OPT_processes = 8000;	/* default max. procs./warrior */
67 int OPT_F = 0;			/* initial position of warrior 2 */
68 int OPT_k = 0;			/* nothing (`koth' format flag) */
69 int OPT_b = 0;			/* nothing (we are always `brief') */
70 int OPT_m = 0;			/* multi-warrior output format. */
71 
72 char *prog_name;
73 char errmsg[256];
74 
75 /*---------------------------------------------------------------
76  * Utilities
77  */
78 
79 #define min(x,y) ((x)<(y) ? (x) : (y))
80 
81 /* xbasename(): custom basename(1); returns the filename from a path
82  */
83 static char *
xbasename(char * s)84 xbasename (char *s) {
85     char *b;
86     b = strrchr (s, '/');
87     if (!b) {
88         b = strrchr (s, '\\');
89     }
90     return b ? 1 + b : s;
91 }
92 
93 void
panic(const char * msg)94 panic (const char *msg) {
95     fprintf (stderr, "%s: ", prog_name);
96     fprintf (stderr, "%s", msg);
97     exit (1);
98 }
99 
100 
101 /* pmars/rng.c random number generator
102  */
103 s32_t
rng(s32_t seed)104 rng (s32_t seed) {
105     register s32_t temp = seed;
106     temp = 16807 * (temp % 127773) - 2836 * (temp / 127773);
107     if (temp < 0)
108         temp += 2147483647;
109     return temp;
110 }
111 
112 /* Like realloc(3), but works with NULL pointers. */
113 void *
xrealloc(void * p,size_t newsize)114 xrealloc (void *p, size_t newsize) {
115     if (p == NULL) {
116         return malloc (newsize);
117     }
118     return realloc (p, newsize);
119 }
120 
121 void
usage()122 usage () {
123     printf ("%s v%d.%d", prog_name, VERSION, REVISION);
124     if (PATCHLEVEL > 0) {
125         printf (".%d", PATCHLEVEL);
126     }
127     printf ("\n");
128     printf ("usage: %s [opts] warriors...\n", prog_name);
129     printf ("opts: -r <rounds>, -c <cycles>, -F <pos>, -s <coresize>,\n"
130             "      -p <maxprocs>, -d <minsep>, -bk\n");
131     exit (1);
132 }
133 
134 /*---------------------------------------------------------------
135  * Warrior initialisations.
136  */
137 
138 void
free_related_memory()139 free_related_memory () {
140     if (Warriors) {
141         free (Warriors);
142         Warriors = NULL;
143     }
144     if (Positions) {
145         free (Positions);
146         Positions = NULL;
147     }
148     if (StartPositions) {
149         free (StartPositions);
150         StartPositions = NULL;
151     }
152     if (Deaths) {
153         free (Deaths);
154         Deaths = NULL;
155     }
156     // free ScoreMatrix..
157     if (PSpaces) {
158         free (PSpaces);
159         PSpaces = NULL;
160     }
161     if (WarriorNames) {
162         free (WarriorNames);
163         WarriorNames = NULL;
164     }
165 }
166 
167 void
alloc_related_memory()168 alloc_related_memory () {
169     //unsigned int i;
170 
171     Warriors = (warrior_t *) malloc (sizeof (warrior_t) * NWarriors);
172     Positions = (field_t *) malloc (sizeof (field_t) * NWarriors);
173     StartPositions = (field_t *) malloc (sizeof (field_t) * NWarriors);
174     Deaths = (unsigned int *) malloc (sizeof (unsigned int *) * NWarriors);
175 
176     // ScoreMatrix..
177 
178     /* Warrior P-spaces */
179     PSpaces = (pspace_t **) malloc (sizeof (pspace_t *) * NWarriors);
180 
181 }
182 
183 
184 void
import_warriors()185 import_warriors () {
186     unsigned int i;
187 
188     for (i = 0; i < NWarriors; i++) {
189 		  fprintf(stderr,"loading %s..\n",WarriorNames[i]);
190         asm_fname (WarriorNames[i], &Warriors[i], OPT_coresize);
191     }
192 	 fprintf(stderr,"%i warriors loaded\n",NWarriors);
193 }
194 
195 void
check_sanity()196 check_sanity () {
197     u32_t space_used;
198     unsigned int i;
199 
200     /* Make sure each warrior has some code. */
201     for (i = 0; i < NWarriors; i++) {
202         if (Warriors[i].len == 0 || Warriors[i].len > MAXLENGTH) {
203             sprintf (errmsg, "warrior %d has a bad amount of code code (%i instructions)\n", i,Warriors[i].len);
204             panic (errmsg);
205         }
206     }
207 
208     /* Make sure there is some minimum sepation. */
209     if (OPT_minsep == 0) {
210         OPT_minsep = min (OPT_coresize / NWarriors, MAXLENGTH);
211     }
212 
213     /* Make sure minsep dominates the lengths of all warriors. */
214     for (i = 0; i < NWarriors; i++) {
215         if (OPT_minsep < Warriors[i].len) {
216             sprintf (errmsg, "warrior %s is too long (%i > %i)\n",
217                      WarriorNames[i], Warriors[i].len, OPT_minsep);
218             panic (errmsg);
219         }
220     }
221 
222     /* Make sure there is space for all warriors to be loaded. */
223     space_used = 2 * OPT_minsep;	// two interesting warriors
224     if (space_used > OPT_coresize) {
225         panic ("warriors or minimum separation too large to fit into core\n");
226     }
227 }
228 
229 
230 /*---------------------------------------------------------------
231  * Warrior positioning algorithms
232  *
233  * These are pMARS compatible.  Warrior 0 is always positioned at 0.
234  * posit() and npos() are transcribed from pmars/pos.c.  */
235 
236 #define RETRIES1 20		/* how many times to try generating one
237 * position */
238 #define RETRIES2 4		/* how many times to start backtracking */
239 int
posit(s32_t * seed)240 posit (s32_t * seed) {
241     unsigned int pos = 1, i;
242     unsigned int retries1 = RETRIES1, retries2 = RETRIES2;
243     int diff;
244 
245     do {
246         /* generate */
247         *seed = rng (*seed);
248         Positions[pos] =
249             (*seed % (OPT_coresize - 2 * OPT_minsep + 1)) + OPT_minsep;
250 
251         /* test for overlap */
252         for (i = 1; i < pos; ++i) {
253             /* calculate positive difference */
254             diff = (int) Positions[pos] - Positions[i];
255             if (diff < 0)
256                 diff = -diff;
257             if ((unsigned int) diff < OPT_minsep)
258                 break;		/* overlap! */
259         }
260 
261         if (i == pos)		/* no overlap, generate next number */
262             ++pos;
263         else {			/* overlap */
264             if (!retries2)
265                 return 1;		/* exceeded attempts, fail */
266             if (!retries1) {			/* backtrack: generate new sequence starting */
267                 pos = i;		/* at arbitrary position (last conflict) */
268                 --retries2;
269                 retries1 = RETRIES1;
270             } else			/* generate new current number (pos not
271                 				 * incremented) */
272                 --retries1;
273         }
274     } while (pos < NWarriors);
275     return 0;
276 }
277 
278 void
npos(s32_t * seed)279 npos (s32_t * seed) {
280     unsigned int i, j;
281     unsigned int temp;
282     unsigned int room = OPT_coresize - OPT_minsep * NWarriors + 1;
283 
284     /* Choose NWarriors-1 positions from the available room. */
285     for (i = 1; i < NWarriors; i++) {
286         *seed = rng (*seed);
287         temp = *seed % room;
288         for (j = i - 1; j > 0; j--) {
289             if (temp > Positions[j])
290                 break;
291             Positions[j + 1] = Positions[j];
292         }
293         Positions[j + 1] = temp;
294     }
295 
296     /* Separate the positions by OPT_minsep cells. */
297     temp = OPT_minsep;
298     for (i = 1; i < NWarriors; i++) {
299         Positions[i] += temp;
300         temp += OPT_minsep;
301     }
302 
303     /* Random permutation of positions. */
304     for (i = 1; i < NWarriors; i++) {
305         *seed = rng (*seed);
306         j = *seed % (NWarriors - i) + i;
307         temp = Positions[j];
308         Positions[j] = Positions[i];
309         Positions[i] = temp;
310     }
311 }
312 
313 s32_t
compute_positions(s32_t seed)314 compute_positions (s32_t seed) {
315     u32_t avail = OPT_coresize + 1 - NWarriors * OPT_minsep;
316 
317     Positions[0] = 0;
318 
319     /* Case single warrior. */
320     if (NWarriors == 1)
321         return seed;
322 
323     /* Case one on one. */
324     if (NWarriors == 2) {
325         Positions[1] = OPT_minsep + seed % avail;
326         seed = rng (seed);
327         return seed;
328     }
329 
330     if (NWarriors > 2) {
331         if (posit (&seed)) {
332             npos (&seed);
333         }
334     }
335     return seed;
336 }
337 
338 
339 /*---------------------------------------------------------------
340  * Misc.
341  */
342 
343 void
save_pspaces()344 save_pspaces () {
345     pspace_t **ps;
346     ps = sim_get_pspaces ();
347     memcpy (PSpaces, ps, sizeof (pspace_t *) * NWarriors);
348 }
349 
350 void
amalgamate_pspaces()351 amalgamate_pspaces () {
352     unsigned int i, j;
353 
354     /* Share p-space according to PINs. */
355     for (i = 0; i < NWarriors; i++) {
356         if (Warriors[i].have_pin) {
357             for (j = 0; j < i; j++) {
358                 if (Warriors[j].have_pin && Warriors[j].pin == Warriors[i].pin) {
359                     pspace_share (PSpaces[i], PSpaces[j]);
360                 }
361             }
362         }
363     }
364 }
365 
366 s32_t
load_warriors(unsigned i,unsigned j,s32_t * seed)367 load_warriors (unsigned i, unsigned j, s32_t * seed) {
368     unsigned pos = OPT_minsep + (*seed % (OPT_coresize - OPT_minsep - OPT_minsep));
369     if(j > NWarriors)
370         exit(1);
371     *seed = rng (*seed);
372     sim_load_warrior (0, &Warriors[i].code[0], Warriors[i].len);
373     sim_load_warrior (pos, &Warriors[j].code[0], Warriors[j].len);
374     if(OPT_coresize <= (pos+Warriors[j].len))
375         exit(1);
376     return pos + Warriors[j].start;
377 }
378 
379 void
set_starting_order(unsigned int round)380 set_starting_order (unsigned int round) {
381     unsigned int i;
382     pspace_t **ps;
383 
384     /* Copy load positions into starting positions array
385        with a cyclic shift of rounds places. */
386     for (i = 0; i < NWarriors; i++) {
387         unsigned int j = (i + round) % NWarriors;
388         StartPositions[i] = (Positions[j] + Warriors[j].start) % OPT_coresize;
389     }
390 
391     /* Copy p-spaces into simulator p-space array with a
392        cyclic shift of rounds places. */
393     ps = sim_get_pspaces ();
394     for (i = 0; i < NWarriors; i++) {
395         ps[i] = PSpaces[(i + round) % NWarriors];
396     }
397 }
398 
399 void
output_results(unsigned long long exec_count,time_t run_time)400 output_results (unsigned long long exec_count, time_t run_time) {
401     unsigned int i, j, op, mod;
402     unsigned long long count;
403     char //buf[128],
404     // html
405     *html_preamble = "<html>\n<body>\n<h1>%s</h1>\n",
406     *html_table_preamble = "<h2>%s</h2><table border=\"1\">\n",
407     *html_start_row = "<tr>",
408     *html_name = "<th>%s</th>",
409     *html_text = "<td>%s</td>",
410     *html_value = "<td>%i</td>",
411 	 *html_valueu32 = "<td>%u</td>",
412     *html_valueu64 = "<td>%llu</td>",
413     *html_end_row = "</tr>\n",
414     *html_table_postamble = "</table>\n",
415     *html_postamble = "</body>\n</html>\n",
416     // tab-seperated-value
417     *tsv_preamble = "",
418     *tsv_table_preamble = "",
419     *tsv_start_row = "",
420     *tsv_name = "%s\t",
421     *tsv_text = tsv_name,
422     *tsv_value = "%i\t",
423 	 *tsv_valueu32 = "%u\t",
424     *tsv_valueu64 = "%llu\t",
425     *tsv_end_row = "\n", *tsv_table_postamble = "", *tsv_postamble = "",
426     // --- actually used ones ---
427     *preamble = html_preamble,
428     *table_preamble = html_table_preamble,
429     *start_row = html_start_row,
430     *name = html_name,
431     *text = html_text,
432     *value = html_value,
433 	 *valueu32 = html_valueu32,
434     *valueu64 = html_valueu64,
435     *end_row = html_end_row,
436     *table_postamble = html_table_postamble, *postamble = html_postamble;
437 
438     printf (preamble, "RESULTS");
439 
440     printf (table_preamble, "Scores Matrix");
441     printf (start_row);
442     printf (name, "");
443     for (i = 0; i < NWarriors; i++) {
444         printf (name, xbasename (WarriorNames[i]));
445     }
446     printf (end_row);
447 
448     for (i = 0; i < NWarriors; i++) {
449         printf (start_row);
450         printf (name, xbasename (WarriorNames[i]));
451         for (j = 0; j < NWarriors; j++) {
452             printf (valueu32, ScoresMatrix[i][j]);
453         }
454         printf (end_row);
455     }
456 
457     printf (table_postamble);
458 
459     printf (table_preamble, "Opcode Execution Frequency");
460     for (op = 0; op < OPCODE_LAST; op++) {
461         for (mod = 0; mod < MODIFIER_LAST; mod++) {
462             count = get_opcode_count (_OP (op, mod));
463             if (count > 0) {
464                 printf (start_row);
465                 printf (name, MNEMONIC_OPCODE[op]);
466                 printf (name, MNEMONIC_MODIFIER[mod]);
467                 printf (valueu64, count);
468                 printf (end_row);
469             }
470         }
471     }
472     printf (table_postamble);
473 
474     printf (table_preamble, "Misc Info");
475     printf (start_row);
476     printf (name, "instructions");
477     printf (valueu64, exec_count);
478     printf(end_row);
479     printf (start_row);
480     printf (name, "checksum");
481     printf (valueu32,get_exec_trail_checksum());
482     printf (end_row);
483     printf (start_row);
484     printf (name, "rounds");
485     printf (valueu64, (NWarriors * (NWarriors / 2) * OPT_rounds));
486     printf(end_row);
487     printf (start_row);
488     printf (name, "time (secs)");
489     printf (valueu32, run_time);
490     printf(end_row);
491     printf (start_row);
492     printf (name, "rounds/sec");
493 
494     if (run_time > 0) {
495         printf (valueu64, (NWarriors * (NWarriors / 2) * OPT_rounds) / run_time);
496     } else {
497         printf (text, "all of them!");
498     }
499     printf (end_row);
500 
501     printf (start_row);
502     printf (name, "logical bytes");
503     printf (valueu64,get_logical_bytes());
504     printf(end_row);
505     printf (start_row);
506     printf (name, "physical bytes");
507     printf (valueu64,get_physical_bytes());
508     printf(end_row);
509     printf (table_postamble);
510 
511     printf (postamble);
512 }
513 
open_exec_trail(unsigned i,int append)514 FILE *open_exec_trail(unsigned i,int append) {
515     char exectrailbuf[128];
516     FILE *ret = 0;
517     sprintf (exectrailbuf, "%s.ex", xbasename (WarriorNames[i]));
518     ret = fopen (exectrailbuf, append? "ab": "wb");
519     if (!ret)
520         panic (exectrailbuf);
521     return ret;
522 }
523 
524 
525 /*---------------------------------------------------------------
526  * Command line arguments.
527  */
528 
529 /*
530  * parse options
531  */
532 void
readargs(int argc,char ** argv)533 readargs (int argc, char **argv) {
534     int n, i;
535     char c;
536     int cix;
537     int tmp;
538     FILE *exec_trail;
539 
540     n = 1;
541     while (n < argc) {
542         cix = 0;
543         c = argv[n][cix++];
544         if (c == '-' && argv[n][1]) {
545             do {
546                 c = argv[n][cix++];
547                 if (c)
548                     switch (c) {
549 
550                     case 'k':
551                         OPT_k = 1;
552                         break;
553                     case 'b':
554                         OPT_b = 1;
555                         break;
556                     case 'm':
557                         OPT_m = 1;
558                         break;
559 
560                     case 'F':
561                         if (n == argc - 1 || !isdigit (argv[n + 1][0]))
562                             panic ("bad argument for option -F\n");
563                         c = 0;
564                         OPT_F = atoi (argv[++n]);
565                         break;
566 
567                     case 's':
568                         if (n == argc - 1 || !isdigit (argv[n + 1][0]))
569                             panic ("bad argument for option -s\n");
570                         c = 0;
571                         OPT_coresize = atoi (argv[++n]);
572                         if ((int) OPT_coresize <= 0)
573                             panic ("core size must be > 0\n");
574                         break;
575 
576                     case 'd':
577                         if (n == argc - 1 || !isdigit (argv[n + 1][0]))
578                             panic ("bad argument for option -d\n");
579                         c = 0;
580                         OPT_minsep = atoi (argv[++n]);
581                         if ((int) OPT_minsep <= 0)
582                             panic ("minimum warrior separation must be > 0\n");
583                         break;
584 
585                     case 'p':
586                         if (n == argc - 1 || !isdigit (argv[n + 1][0]))
587                             panic ("bad argument for option -p\n");
588                         c = 0;
589                         OPT_processes = atoi (argv[++n]);
590                         if (OPT_processes <= 0)
591                             panic ("max processes must be > 0\n");
592                         break;
593 
594                     case 'r':
595                         if (n == argc - 1 || !isdigit (argv[n + 1][0]))
596                             panic ("bad argument for option -r\n");
597                         c = 0;
598                         tmp = atoi (argv[++n]);
599                         if (tmp < 0)
600                             panic ("can't do a negative number of rounds!\n");
601                         OPT_rounds = tmp;
602                         break;
603                     case 'c':
604                         if (n == argc - 1 || !isdigit (argv[n + 1][0]))
605                             panic ("bad argument for option -c\n");
606                         c = 0;
607                         OPT_cycles = atoi (argv[++n]);
608                         if (OPT_cycles <= 0)
609                             panic ("cycles must be > 0\n");
610                         break;
611                     default:
612                         sprintf (errmsg, "unknown option '%c'\n", c);
613                         panic (errmsg);
614                     }
615             } while (c);
616 
617         } else			/* it's a file name */ {
618             ++NWarriors;
619             WarriorNames = xrealloc (WarriorNames, NWarriors * sizeof (char *));
620             WarriorNames[NWarriors - 1] = argv[n];
621         }
622         n++;
623     }
624 
625     if (NWarriors == 0)
626         usage ();
627     else {
628         ScoresMatrix = (unsigned **) malloc (NWarriors * sizeof (unsigned *));
629         if (!ScoresMatrix)
630             panic ("x5");
631         for (i = 0; i < NWarriors; i++) {
632             exec_trail = open_exec_trail(i,FALSE);
633             if (1 != fwrite (&i, sizeof (i), 1, exec_trail))
634                 panic ("x16");
635             fclose(exec_trail); // keep file handle count low!
636             ScoresMatrix[i] = calloc (NWarriors, sizeof (unsigned));
637             if (!ScoresMatrix[i])
638                 panic ("x6");
639         }
640     }
641 }
642 
643 
644 
645 /*-------------------------------------------------------------------------
646  * Main
647  */
648 
649 int
main(int argc,char ** argv)650 main (int argc, char **argv) {
651     unsigned int i, j, len, ilen, jlen, k, m,	// matching values
652     n;				/* round counter */
653     s32_t seed;			/* rnd seed. */
654     unsigned ok = (0==0);
655     unsigned char exec_trail_op;
656     unsigned long long exec_count = 0;
657     FILE *fi, *fj;
658     time_t start_time, end_time, run_time;
659 
660     comp_buf_t desti, destj;
661 
662     prog_name = xbasename (argv[0]);
663     readargs (argc, argv);
664     alloc_related_memory ();
665 
666     import_warriors ();
667     check_sanity ();
668 
669     seed = OPT_F ? OPT_F - OPT_minsep : rng (time (0) * 0x1d872b41);
670 
671     /*
672      * Allocate simulator buffers and initialise p-spaces.
673      */
674     if (!sim_alloc_bufs (NWarriors, OPT_coresize, OPT_processes, OPT_cycles))
675         panic ("can't allocate memory.\n");
676 
677     save_pspaces ();
678     amalgamate_pspaces ();	/* Share P-spaces with equal PINs */
679 
680     /*
681      * Fight OPT_rounds rounds.
682      */
683 
684     if (OPT_rounds > 0 && NWarriors > 1)
685 
686         time (&start_time);
687 
688     for (i = 0; i < NWarriors; i++) {
689         fi = open_exec_trail(i,TRUE);
690         desti.f = fi;
691         for (j = i; j < NWarriors; j++) {
692             if (i != j) {
693                 fj = open_exec_trail(j,TRUE);
694 					 destj.f = fj;
695 					 for (n = 0; n < OPT_rounds; n++) {
696 
697                     sim_clear_core ();
698 
699                     switch (sim
700                             (2, Warriors[i].start, load_warriors (i, j, &seed),
701                              OPT_cycles, NULL)) {
702                     case 0:	// i won
703                         ScoresMatrix[i][j] += 3;
704                         break;
705                     case 1:	// j won
706                         ScoresMatrix[j][i] += 3;
707                         break;
708                     case 2:	// tie
709                         ScoresMatrix[i][j]++;
710                         ScoresMatrix[j][i]++;
711                         break;
712                     default:
713                         panic ("simulator panic!\n");
714                     }
715                     // assign exec trail
716                     len = get_exec_trail_length ();
717                     jlen = len >> 1;
718                     ilen = jlen + (len & 1);
719                     if (ilen + jlen != len)
720                         panic ("x16");
721                     if (ilen > OPT_cycles)
722                         panic ("x13");
723                     if (1 != fwrite (&j, sizeof (j), 1, fi))
724                         panic ("x14");
725                     if (1 != fwrite (&i, sizeof (i), 1, fj))
726                         panic ("x15");
727                     if (1 != fwrite (&ilen, sizeof (ilen), 1, fi))
728                         panic ("x9");
729                     if (1 != fwrite (&jlen, sizeof (jlen), 1, fj))
730                         panic ("x10");
731                     m = 0;
732 						  desti.len = 0;
733 						  destj.len = 0;
734                     for (k = 0; k < len; k++) {
735                         exec_trail_op = get_exec_trail (k);
736 								if(exec_trail_op >= _OP(OPCODE_LAST,MODIFIER_LAST))
737 									panic ("x17");
738                         switch (m++ & 1) {	// toggle between the warriors in the round
739                         case 0:
740 									write_compressed(&desti,exec_trail_op);
741                            break;
742                         case 1:
743 									write_compressed(&destj,exec_trail_op);
744                            break;
745                         }
746                         exec_count++;
747                     }
748 						  flush_compressed(&desti);
749 						  flush_compressed(&destj);
750                 }
751                 //printf("%u\r",exec_count); fflush(stdout);
752                 fclose(fj);
753             }
754         }
755         fclose(fi);
756     }
757 
758     time (&end_time);
759 
760     run_time = end_time - start_time;
761 
762     sim_free_bufs ();
763     output_results (exec_count, run_time);
764     free_related_memory ();
765     return 0;
766 }
767