1 /* sim.c: simulator functions
2  * $Id: sim.c,v 1.10 2002/12/28 05:48:16 rowan Exp $
3  */
4 
5 /* This file is part of `exhaust', a memory array redcode simulator.
6  * Author: M Joonas Pihlaja
7  * Public Domain.
8  */
9 
10 /*
11  * Thanks go to the pMARS authors and Ken Espiritu whose ideas have
12  * been used in this simulator.  Especially Ken's effective addressing
13  * calculation code in pMARS 0.8.6 has been adapted for use here.
14  */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include "exhaust.h"
21 #include "asm.h"
22 #include "sim.h"
23 #include "insn.h"
24 
25 /* Should we strip flags from instructions when loading?  By default,
26    yes.  If so, then the simulator won't bother masking them off.  */
27 #ifndef SIM_STRIP_FLAGS
28 #define SIM_STRIP_FLAGS 1
29 #endif
30 
31 
32 /* DEBUG level:
33  *     0: none
34  *   >=1: disassemble each instruction (no output)
35  *     2: print each instruction as it is executed
36  */
37 
38 /*
39  * File scoped stuff
40  */
41 
42 /* internal warrior structure */
43 typedef struct w_st {
44   field_t *tail;		/* next free location to queue a process */
45   field_t *head;		/* next process to run from queue */
46   struct w_st *succ;		/* next warrior alive */
47   u32_t nprocs;			/* number of live processes in this warrior */
48   struct w_st *pred;		/* previous warrior alive */
49   int id;			/* index (or identity) of warrior */
50 } w_t;
51 
52 #define DEF_MAX_WARS 2
53 #define DEF_CORESIZE 8000
54 #define DEF_PROCESSES 8000
55 #define DEF_CYCLES 80000
56 
57 static unsigned int Coresize  = 0;
58 static unsigned int Processes = 0;
59 static unsigned int NWarriors = 0;
60 static unsigned int Cycles    = 0;
61 
62 static w_t          *War_Tab = NULL;
63 static insn_t       *Core_Mem = NULL;
64 static field_t      *Queue_Mem = NULL;
65 
66 /* P-space */
67 static unsigned int PSpace_size = 0;    /* # p-space slots per warrior. */
68 static pspace_t	    **PSpaces;	        /* p-spaces of each warrior. */
69 
70 /* protos */
71 static int sim_proper( unsigned int, const field_t *, unsigned int * );
72 static void alloc_pspaces( unsigned int nwars, unsigned int pspacesize );
73 static void free_pspaces( unsigned int nwars );
74 
75 /*---------------------------------------------------------------
76  * Simulator memory management
77  */
78 
79 void
sim_clear_core()80 sim_clear_core()
81 {
82   memset(Core_Mem, 0, Coresize*sizeof(insn_t));
83 }
84 
85 
86 /* NAME
87  *     sim_alloc_bufs, sim_alloc_bufs2, sim_free_bufs --
88  *				alloc and free buffers used in simulation
89  *
90  * SYNOPSIS
91  *     insn_t *sim_alloc_bufs( unsigned int nwars, unsigned int coresize,
92  *                             unsigned int processes, unsigned int cycles );
93  *     insn_t *sim_alloc_bufs2( unsigned int nwars, unsigned int coresize,
94  *				unsigned int processes, unsigned int cycles,
95  *				unsigned int pspacesize );
96  *     void sim_free_bufs();
97  *
98  * INPUTS
99  *     nwar        -- number of warriors
100  *     coresize    -- size of core
101  *     processes   -- max no of processes / warrior
102  *     cycles      -- the number of cycles to play before tie.
103  *     pspacesize  -- size of p-space per warrior.  For sim_alloc_bufs(),
104  *		      it defaults to min(1,coresize/16).
105  *
106  * RESULTS
107  *     These functions manage the core, queue, and w_t warrior info
108  *     struct array memories.
109  *
110  *     Core_Mem, Queue_Mem, War_Tab and PSpace_mem memories are allocated
111  *     or freed as requested.  Any earlier memories are freed before
112  *     new allocations are made.
113  *
114  * RETURN VALUE
115  *     sim_alloc_bufs(): the address of core memory, or NULL if
116  *			 out of memory.
117  *     sim_free_bufs(): none
118  *
119  * GLOBALS
120  *     All file scoped globals.
121  */
122 
123 void
sim_free_bufs()124 sim_free_bufs()
125 {
126   free_pspaces(NWarriors);
127   if ( Core_Mem ) free( Core_Mem ); Core_Mem = NULL; Coresize = 0;
128   if ( Queue_Mem ) free( Queue_Mem ); Queue_Mem = NULL; Processes = 0;
129   if ( War_Tab ) free( War_Tab ); War_Tab = NULL; NWarriors = 0;
130 }
131 
132 
133 insn_t *
sim_alloc_bufs2(unsigned int nwars,unsigned int coresize,unsigned int processes,unsigned int cycles,unsigned int pspace)134 sim_alloc_bufs2( unsigned int nwars, unsigned int coresize,
135 		 unsigned int processes, unsigned int cycles,
136 		 unsigned int pspace )
137 {
138   unsigned int queue_size;
139 
140   sim_free_bufs();
141 
142   Core_Mem = (insn_t*)malloc( sizeof(insn_t) * coresize );
143   queue_size = nwars*processes+1;
144   Queue_Mem = (field_t*)malloc( sizeof(field_t)*queue_size );
145   War_Tab = (w_t*)malloc( sizeof(w_t)*nwars );
146   alloc_pspaces(nwars, pspace);
147 
148   if ( Core_Mem && Queue_Mem && War_Tab && PSpaces ) {
149     Cycles = cycles;
150     NWarriors = nwars;
151     Coresize = coresize;
152     Processes = processes;
153     sim_clear_pspaces();
154     return Core_Mem;
155   }
156   sim_free_bufs();
157   return NULL;
158 }
159 
160 insn_t *
sim_alloc_bufs(unsigned int nwars,unsigned int coresize,unsigned int processes,unsigned int cycles)161 sim_alloc_bufs( unsigned int nwars, unsigned int coresize,
162 		unsigned int processes, unsigned int cycles )
163 {
164   unsigned int pspace;
165   pspace = coresize/16 == 0 ? 1 : coresize/16;
166   return sim_alloc_bufs2( nwars, coresize, processes, cycles, pspace );
167 }
168 
169 
170 /* NAME
171  *     sim_load_warrior -- load warrior code into core.
172  *
173  * SYNOPSIS
174  *     sim_load_warrior(unsigned int pos, insn_t *code, unsigned int len);
175  *
176  * INPUTS
177  *     pos -- The core address to load the warrior into.
178  *     code -- array of instructions.
179  *     len --
180  *
181  * DESCRIPTION
182  *     This function is the preferred method to load warriors into core.
183  *     It strips the instructions of any flags they may possess, and
184  *     copies the instructions into core.
185  *
186  *     The code will happily overwrite any previous contents of core,
187  *     so beware not to load warriors so that their code overlaps.
188  *
189  * NOTE
190  *     The core must have been allocated previously with sim(), or
191  *     preferably sim_alloc_bufs() and not freed since.
192  *
193  * RETURN VALUE
194  *     0 -- warrior loaded OK.
195  *    -1 -- core memory not allocated.
196  *    -2 -- warrior length > core size.
197  */
198 int
sim_load_warrior(unsigned int pos,const insn_t * code,unsigned int len)199 sim_load_warrior(unsigned int pos, const insn_t *code, unsigned int len)
200 {
201   unsigned int i;
202   field_t k;
203   u32_t in;
204 
205   if ( Core_Mem == NULL )  return -1;
206   if ( len > Coresize ) return -2;
207 
208   for (i=0; i<len; i++) {
209     k = (pos+i) % Coresize;
210 
211 #if SIM_STRIP_FLAGS
212     in = code[i].in & iMASK;
213 #else
214     in = code[i].in;
215 #endif
216 
217     Core_Mem[k].in = in;
218     Core_Mem[k].a = code[i].a;
219     Core_Mem[k].b = code[i].b;
220   }
221   return 0;
222 }
223 
224 
225 
226 
227 /*---------------------------------------------------------------
228  * P-Space management.
229  */
230 
231 static void
free_pspaces(unsigned int nwars)232 free_pspaces(unsigned int nwars)
233 {
234   unsigned int i;
235   if ( nwars>0 ) {
236     if (PSpaces) {
237       for (i=0; i<nwars; i++) {
238 	pspace_free(PSpaces[i]);
239       }
240       free(PSpaces);
241     }
242   }
243   PSpace_size = 0;
244   PSpaces = NULL;
245 }
246 
247 
248 static void
alloc_pspaces(unsigned int nwars,unsigned int pspacesize)249 alloc_pspaces(unsigned int nwars, unsigned int pspacesize)
250 {
251   unsigned int i;
252   int success = 0;
253 
254   PSpaces = NULL;
255   PSpace_size = 0;
256   if (nwars==0) { return; }
257 
258   if (( PSpaces = (pspace_t**)malloc(sizeof(pspace_t*)*nwars))) {
259     success = 1;
260     for (i=0; i<nwars; i++) { PSpaces[i] = NULL; }
261     for (i=0; success && i<nwars; i++) {
262 	PSpaces[i] = pspace_alloc(pspacesize);
263 	success = success && PSpaces[i] != NULL;
264     }
265   }
266 
267   if ( !success ) {
268     free_pspaces(nwars);
269   } else {
270     PSpace_size = pspacesize;
271   }
272 }
273 
274 
275 /* NAME
276  *     sim_get_pspaces -- get array of p-spaces of warriors.
277  *     sim_get_pspace -- get a single p-space.
278  *
279  * SYNOPSIS
280  *     pspace_t **sim_get_pspaces(void);
281  *     pspace_t *sim_get_pspace(unsigned int war_id)
282  *
283  * DESCRIPTION
284  *     Return an array of pointers to p-space structures of the warriors.
285  *     The pspace at index i is used as the pspace of the ith warrior
286  *     when fighting.
287  */
288 pspace_t **
sim_get_pspaces()289 sim_get_pspaces()
290 {
291     return PSpaces;
292 }
293 
294 pspace_t *
sim_get_pspace(unsigned int war_id)295 sim_get_pspace(unsigned int war_id)
296 {
297     return PSpaces[war_id];
298 }
299 
300 /* NAME
301  *     sim_clear_pspaces -- clear and/or reinitialise p-spaces
302  *     sim_reset_pspaces
303  *
304  * SYNOPSIS
305  *     void sim_clear_pspaces(void);
306  *     void sim_reset_pspaces(void);
307  *
308  * DESCRIPTION
309  *	All p-spaces are cleared and the P-space locations 0 are set
310  *	to CORESIZE-1.  For sim_reset_pspaces(): All p-spaces are made
311  *	private.
312  * */
313 
314 void
sim_clear_pspaces()315 sim_clear_pspaces()
316 {
317   unsigned int i;
318   for (i=0; i<NWarriors; i++) {
319     pspace_clear(PSpaces[i]);
320     pspace_set(PSpaces[i], 0, Coresize-1);
321   }
322 }
323 
324 void
sim_reset_pspaces()325 sim_reset_pspaces()
326 {
327   unsigned int i;
328   for (i=0; i<NWarriors; i++) {
329     pspace_privatise(PSpaces[i]);
330   }
331   sim_clear_pspaces();
332 }
333 
334 
335 
336 /*---------------------------------------------------------------
337  * Simulator interface
338  */
339 
340 /* NAME
341  *     sim, sim_mw -- public functions to simulate a round of Core War
342  *
343  * SYNOPSIS
344  *     int sim_mw( unsigned int nwar, const field_t *war_pos_tab,
345  *                 unsigned int *death_tab );
346  *     int sim( int nwar, field_t w1_start, field_t w2_start,
347  * 		unsigned int cycles, void **ptr_result );
348  *
349  * INPUTS
350  *     nwar        -- number of warriors
351  *     w1_start, w2_start -- core addresses of first processes
352  *                    warrior 1 and warrior 2. Warrior 1 executes first.
353  *     cycles      -- the number of cycles to play before tie.
354  *     ptr_result  -- NULL, except when requesting the address of core.
355  *     war_pos_tab -- core addresses where warriors are loaded in
356  *		      the order they are to be executed.
357  *     death_tab   -- the table where dead warrior indices are stored
358  *
359  * DESCRIPTION
360  *     The real simulator is inside sim_proper() to which sim() and
361  *     sim_mw() are proxies.  sim_mw() reads the warrior position
362  *     of the ith warrior from war_tab_pos[i-1].
363  *
364  * RESULTS
365  *     The warriors fight their fight in core which gets messed up in
366  *     the process.  If a warrior died during the fight then its p-space
367  *     location 0 is cleared.  Otherwise the number of warriors alive
368  *     at the end of the battle is stored into its p-space location 0.
369  *
370  *     sim_mw() stores indices of warriors that die into the death_tab
371  *     array in the order of death.  Warrior indices start from 0.
372  *
373  *     For sim(): If nwar == -1 then buffers of default size for
374  *     max. two warriors are allocated and the address of the core
375  *     memory is returned via the ptr_result pointer.
376  *
377  * RETURN VALUE
378  *     sim_mw(): the number of warriors still alive at the end of the
379  *		 battle.
380  *       -1: simulator panic attack -- something's gone wrong
381  *
382  *     sim():
383  *       single warrior: 0: warrior suicided, 1: warrior didn't die.
384  *       one-on-one two warriors:
385  * 	      0: warrior 1 won, 1: warrior 2 won, 2: tie
386  *       -1: simulator panic attack -- something's gone wrong
387  *
388  * GLOBALS
389  *     All file scoped globals */
390 
391 int
sim_mw(unsigned int nwar,const field_t * war_pos_tab,unsigned int * death_tab)392 sim_mw( unsigned int nwar, const field_t *war_pos_tab,
393 	unsigned int *death_tab )
394 {
395   int alive_count;
396   if ( !Core_Mem || !Queue_Mem || !War_Tab || !PSpaces ) return -1;
397 
398   alive_count = sim_proper( nwar, war_pos_tab, death_tab );
399 
400   /* Update p-space locations 0. */
401   if (alive_count >= 0) {
402     unsigned int nalive = alive_count;
403     unsigned int i;
404 
405     for (i=0; i<nwar; i++) {
406       pspace_set( PSpaces[i], 0, nalive);
407     }
408     for (i=0; i<nwar-nalive; i++) {
409       pspace_set( PSpaces[death_tab[i]], 0, 0);
410     }
411   }
412   return alive_count;
413 }
414 
415 
416 int
sim(int nwar,field_t w1_start,field_t w2_start,unsigned int cycles,void ** ptr_result)417 sim( int nwar,
418      field_t w1_start,
419      field_t w2_start,
420      unsigned int cycles,
421      void **ptr_result )
422 {
423   field_t war_pos_tab[2];
424   unsigned int death_tab[2];
425   int alive_cnt;
426 
427   /* if the caller requests for the address of core, allocate
428    * the default buffers and give it
429    */
430   if ( nwar < 0 ) {
431     if ( nwar == -1 && ptr_result ) {
432       *ptr_result = sim_alloc_bufs( DEF_MAX_WARS, DEF_CORESIZE,
433 				    DEF_PROCESSES, DEF_CYCLES );
434       return 0;
435     }
436     return -1;
437   }
438   if ( nwar > 2 ) return -1;
439 
440   /* otherwise set up things for sim_mw() */
441   Cycles = cycles;
442   war_pos_tab[0] = w1_start;
443   war_pos_tab[1] = w2_start;
444 
445   alive_cnt = sim_mw( nwar, war_pos_tab, death_tab );
446   if ( alive_cnt < 0 ) return -1;
447 
448   if ( nwar == 1) return alive_cnt;
449 
450   if ( alive_cnt == 2 ) return 2;
451   return death_tab[0] == 0 ? 1 : 0;
452 }
453 
454 
455 
456 /*-------------------------------------------------------------------------
457  * private functions
458  */
459 
460 /* NAME
461  *     sim_proper -- the real simulator code
462  *
463  * SYNOPSIS
464  *     int sim_proper( unsigned int nwar,
465  *                     const field_t *war_pos_tab,
466  *                     unsigned int *death_tab );
467  *
468  * INPUTS
469  *     nwar        -- number of warriors
470  *     war_pos_tab -- core addresses where warriors are loaded in
471  *		      the order they are to be executed.
472  *     death_tab   -- the table where dead warrior indices are stored
473  *
474  * RESULTS
475  *     The warriors fight their fight in core which gets messed up in
476  *     the process.  The indices of warriors that die are stored into
477  *     the death_tab[] array in the order of death.  Warrior indices
478  *     start from 0.
479  *
480  * RETURN VALUE
481  *     The number of warriors still alive at the end of the
482  *     battle or -1 on an anomalous condition.
483  *
484  * GLOBALS
485  *     All file scoped globals
486  */
487 
488 /* Various macros:
489  *
490  *  queue(x): Inserts a core address 'x' to the head of the current
491  *            warrior's process queue.  Assumes the warrior's
492  * 	      tail pointer is inside the queue buffer.
493  *
494  * x, y must be in 0..coresize-1 for the following macros:
495  *
496  * INCMOD(x): x = x+1 mod coresize
497  * DECMOD(x): x = x-1 mod coresize
498  * ADDMOD(z,x,y): z = x+y mod coresize
499  * SUBMOD(z,x,y): z = x-y mod coresize
500  */
501 
502 #define queue(x)  do { *w->tail++ = (x); if ( w->tail == queue_end )\
503                                           w->tail = queue_start; } while (0)
504 
505 #define INCMOD(x) do { if ( ++(x) == coresize ) (x) = 0; } while (0)
506 #define DECMOD(x) do { if ((x)-- == 0) (x) = coresize1; } while (0)
507 #define ADDMOD(z,x,y) do { (z) = (x)+(y); if ((z)>=coresize) (z) -= coresize; } while (0)
508 #define SUBMOD(z,x,y) do { (z) = (x)-(y); if ((int)(z)<0) (z) += coresize; } while (0)
509 
510 /* private macros to access p-space. */
511 #define UNSAFE_PSPACE_SET(warid, paddr, val) do {\
512     if (paddr) {\
513 	pspaces_[(warid)]->mem[(paddr)] = (val);\
514     } else {\
515 	pspaces_[(warid)]->lastresult = (val);\
516     }\
517 } while(0)
518 
519 #define UNSAFE_PSPACE_GET(warid, paddr) \
520 	( (paddr) ? pspaces_[(warid)]->mem[(paddr)]\
521 		  : pspaces_[(warid)]->lastresult )
522 
523 
524 int
sim_proper(unsigned int nwar,const field_t * war_pos_tab,unsigned int * death_tab)525 sim_proper( unsigned int nwar, const field_t *war_pos_tab,
526 	    unsigned int *death_tab )
527 {
528   /*
529    * Core and Process queue memories.
530    *
531    * The warriors share a common cyclic buffer for use as a process
532    * queue which the contains core addresses where active processes
533    * are.  The buffer has size N*P+1, where N = number of warriors,
534    * P = maximum number of processes / warrior.
535    *
536    * Each warrior has a fixed slice of the buffer for its own process
537    * queue which are initially allocated to the warriors in reverse
538    * order. i.e. if the are N warriors w1, w2, ..., wN, the slice for
539    * wN is 0..P-1, w{N-1} has P..2P-1, until w1 has (N-1)P..NP-1.
540    *
541    * The core address of the instruction is fetched from the head of
542    * the process queue and processes are pushed to the tail, so the
543    * individual slices slide along at one location per executed
544    * instruction.  The extra '+1' in the buffer size is to have free
545    * space to slide the slices along.
546    *
547    * For two warriors w1, w2:
548    *
549    * |\......../|\......../| |
550    * | w2 queue | w1 queue | |
551    * 0          P         2P 2P+1
552    */
553 
554   insn_t *core;
555   field_t *queue_start, *queue_end; /* queue mem. start, end */
556 
557   /*
558    * Cache Registers.
559    *
560    * The '94 draft specifies that the redcode processor model be
561    * 'in-register'.  That is, the current instruction and the
562    * instructions at the effective addresses (ea's) be cached in
563    * registers during instruction execution, rather than have
564    * core memory accessed directly when the operands are needed.  This
565    * causes differences from the 'in-memory' model.  e.g. MOV 0,>0
566    * doesn't change the instruction's b-field since the instruction at
567    * the a-field's effective address (i.e. the instruction itself) was
568    * cached before the post-increment happened.
569    *
570    * There are conceptually three registers: IN, A, and B.  IN is the
571    * current instruction, and A, B are the ones at the a- and
572    * b-fields' effective addresses respectively.
573    *
574    * We don't actually cache the complete instructions, but rather
575    * only the *values* of their a- and b-field.  This is because
576    * currently there is no way effective address computations can
577    * modify the opcode, modifier, or addressing modes of an
578    * instruction.
579    */
580 
581   u32_t in;			/* 'in' field of current insn for decoding */
582   u32_t ra_a, ra_b,		/* A register values */
583         rb_a, rb_b;		/* B register values */
584   u32_t da, db;			/* effective address of instruction's
585 				 * a- and b-fields */
586   /*
587    * alias some register names to real variables
588    */
589 #define in_a ra_a
590 #define in_b rb_b
591 
592   field_t *pofs;
593   insn_t *pt;
594   unsigned int mode;
595 
596   /*
597    * misc.
598    */
599   w_t *w;			/* current warrior */
600   u32_t ip;			/* current instruction pointer */
601   u32_t ftmp, t;		/* temps */
602   unsigned int coresize, coresize1; /* size of core, size of core - 1 */
603   int cycles;			/* instructions to execute before tie counter*/
604   int alive_cnt;
605   pspace_t **pspaces_;
606   u32_t pspacesize;
607 
608 #if DEBUG >= 1
609   insn_t insn;			/* used for disassembly */
610   char debug_line[256];		/* ditto */
611 #endif
612 
613 
614   /*
615    * Setup queue and core pointers
616    */
617   alive_cnt = nwar;
618   cycles = nwar * Cycles; /* set instruction executions until tie counter */
619   coresize = Coresize;
620   coresize1 = Coresize-1;
621   core = Core_Mem;
622   queue_start = Queue_Mem;
623   queue_end = Queue_Mem + NWarriors*Processes+1;
624   pspaces_ = PSpaces;
625   pspacesize = PSpace_size;
626 
627   /* Setup War_Tab and links all around */
628   pofs = queue_end-1;		/* init. wars[] table */
629   War_Tab[0].succ = &War_Tab[nwar-1];
630   War_Tab[nwar-1].pred = &War_Tab[0];
631   t = nwar-1;
632   ftmp = 0;
633   do {
634     if ( t > 0 ) War_Tab[t].succ = &War_Tab[t-1];
635     if ( t < nwar-1 ) War_Tab[t].pred = &War_Tab[t+1];
636     pofs -= Processes;
637     *pofs = war_pos_tab[ftmp];
638     War_Tab[t].head = pofs;
639     War_Tab[t].tail = pofs+1;
640     War_Tab[t].nprocs = 1;
641     War_Tab[t].id = ftmp;
642     --t;
643     ftmp++;
644   } while ( ftmp < nwar );
645 
646 
647   /*
648    * Main loop is run for each executed instruction
649    */
650   w = &War_Tab[ nwar-1 ];
651   do {
652 
653     ip = *w->head++;		/* load current instruction */
654     if ( w->head == queue_end ) w->head = queue_start;
655     in = core[ ip ].in;		/* note: flags must be unset! */
656 #if !SIM_STRIP_FLAGS
657     in = in & iMASK;		/* strip flags. */
658 #endif
659     in_a = core[ ip ].a;
660     in_b = core[ ip ].b;
661 
662 #if DEBUG >= 1
663     insn = core[ip];
664     dis1( debug_line, insn, coresize);
665 #endif
666 
667     /*
668      * a-field effective address calculation.
669      *
670      * This bit was assimilated from Ken Espiritu's
671      * pmars 0.8.6 patch.  Ditto for the b-field
672      * calculation.
673      */
674     mode = in & mMASK;
675     in >>= mBITS;		/* shift out a-mode bits */
676     rb_a = in_a;		/* necessary if B-mode is immediate */
677 
678     if ( mode != IMMEDIATE ) {
679       ADDMOD( da, in_a, ip );
680       pt = core+da;		/* pt is where field points to (without */
681 				/* indirection). */
682 
683       if ( mode != DIRECT ) {
684 	if ( INDIR_A(mode) ) {
685 	  mode = RAW_MODE(mode);
686 	  pofs = &(pt->a);
687 	} else
688 	  pofs = &(pt->b);
689 
690 	t = *pofs;		/* pofs is the indirection offset */
691 	if (mode == PREDEC) {
692 	  DECMOD(t);
693 	  *pofs = t;
694 	}
695 	ADDMOD(da, t, da);
696 
697 	pt = core+da;		/* now pt is the final destination */
698 				/* of indiretion. */
699 	ra_a = pt->a;		/* read in registers */
700 	ra_b = pt->b;
701 
702 	if (mode == POSTINC) {
703 	  INCMOD(t);
704 	  *pofs = t;
705 	}
706       } else /* DIRECT */{
707 	ra_a = pt->a;
708 	ra_b = pt->b;
709       }
710     } else /* IMMEDIATE */ {
711       ra_b = in_b;
712       da = ip;
713     }
714 
715 
716     /*
717      * b-field effective address calculation
718      */
719     mode = in & mMASK;
720     in >>= mBITS;		/* shift out b-mode bits */
721 
722     if ( mode != IMMEDIATE ) {
723       ADDMOD( db, in_b, ip );
724       pt = core+db;
725 
726       if ( mode != DIRECT ) {
727 	if ( INDIR_A(mode) ) {
728 	  mode = RAW_MODE(mode);
729 	  pofs = &(pt->a);
730 	} else
731 	  pofs = &(pt->b);
732 
733 	t = *pofs;
734 	if (mode == PREDEC) {
735 	  DECMOD(t);
736 	  *pofs = t;
737 	}
738 	ADDMOD(db, t, db);
739 
740 	pt = core+db;
741 	rb_a = pt->a;
742 	rb_b = pt->b;
743 
744 	if (mode == POSTINC) {
745 	  INCMOD(t);
746 	  *pofs = t;
747 	}
748       } else /* DIRECT */{
749 	rb_a = pt->a;
750 	rb_b = pt->b;
751       }
752     } else /* IMMEDIATE */ {
753       db = ip;
754     }
755 
756 #if DEBUG == 2
757     /* Debug output */
758     printf("%6d %4ld  %s  |%4ld, d %4ld,%4ld a %4ld,%4ld b %4ld,%4ld\n",
759 	   cycles, ip, debug_line,
760 	   w->nprocs, da, db,
761 	   ra_a, ra_b, rb_a, rb_b );
762 #endif
763 
764     /*
765      * Execute the instruction on opcode.modifier
766      */
767     switch ( in ) {
768 
769     case _OP(DAT, mA):
770     case _OP(DAT, mB):
771     case _OP(DAT, mAB):
772     case _OP(DAT, mBA):
773     case _OP(DAT, mX):
774     case _OP(DAT, mF):
775     case _OP(DAT, mI):
776     die:
777       if ( --w->nprocs > 0 )
778 	goto noqueue;
779       w->pred->succ = w->succ;
780       w->succ->pred = w->pred;
781       *death_tab++ = w->id;
782       cycles = cycles - cycles/alive_cnt; /* nC+k -> (n-1)C+k */
783       if ( --alive_cnt <= 1 )
784 	goto out;
785       goto noqueue;
786 
787 
788     case _OP(SPL, mA):
789     case _OP(SPL, mB):
790     case _OP(SPL, mAB):
791     case _OP(SPL, mBA):
792     case _OP(SPL, mX):
793     case _OP(SPL, mF):
794     case _OP(SPL, mI):
795       INCMOD(ip);
796       queue(ip);
797       if ( w->nprocs < Processes ) {
798 	++w->nprocs;
799 	queue(da);
800       }
801       goto noqueue;
802 
803 
804     case _OP(MOV, mA):
805       core[db].a = ra_a;
806       break;
807     case _OP(MOV, mF):
808       core[db].a = ra_a;
809     case _OP(MOV, mB):
810       core[db].b = ra_b;
811       break;
812     case _OP(MOV, mAB):
813       core[db].b = ra_a;
814       break;
815     case _OP(MOV, mX):
816       core[db].b = ra_a;
817     case _OP(MOV, mBA):
818       core[db].a = ra_b;
819       break;
820     case _OP(MOV, mI):
821       core[db].a = ra_a;
822       core[db].b = ra_b;
823       core[db].in = core[da].in;
824       break;
825 
826 
827     case _OP(DJN,mBA):
828     case _OP(DJN,mA):
829       t = core[db].a;
830       DECMOD(t);
831       core[db].a = t;
832       if ( rb_a == 1 ) break;
833       queue(da);
834       goto noqueue;
835 
836     case _OP(DJN,mAB):
837     case _OP(DJN,mB):
838       t = core[db].b;
839       DECMOD(t);
840       core[db].b = t;
841       if ( rb_b == 1 ) break;
842       queue(da);
843       goto noqueue;
844 
845     case _OP(DJN,mX):
846     case _OP(DJN,mI):
847     case _OP(DJN,mF):
848       t = core[db].a;      DECMOD(t);      core[db].a = t;
849       t = core[db].b;      DECMOD(t);      core[db].b = t;
850       if ( rb_a == 1 && rb_b == 1 ) break;
851       queue(da);
852       goto noqueue;
853 
854 
855     case _OP(ADD, mI):
856     case _OP(ADD, mF):
857       ADDMOD( t, ra_b, rb_b ); core[db].b = t;
858     case _OP(ADD, mA):
859       ADDMOD( t, ra_a, rb_a ); core[db].a = t;
860       break;
861     case _OP(ADD, mB):
862       ADDMOD( t, ra_b, rb_b ); core[db].b = t;
863       break;
864     case _OP(ADD, mX):
865       ADDMOD( t, ra_b, rb_a ); core[db].a = t;
866     case _OP(ADD, mAB):
867       ADDMOD( t, ra_a, rb_b ); core[db].b = t;
868       break;
869     case _OP(ADD, mBA):
870       ADDMOD( t, ra_b, rb_a ); core[db].a = t;
871       break;
872 
873 
874     case _OP(JMZ, mBA):
875     case _OP(JMZ, mA):
876       if ( rb_a )
877 	break;
878       queue(da);
879       goto noqueue;
880 
881     case _OP(JMZ, mAB):
882     case _OP(JMZ, mB):
883       if ( rb_b )
884 	break;
885       queue(da);
886       goto noqueue;
887 
888     case _OP(JMZ, mX):
889     case _OP(JMZ, mF):
890     case _OP(JMZ, mI):
891       if ( rb_a || rb_b )
892 	break;
893       queue(da);
894       goto noqueue;
895 
896 
897     case _OP(SUB, mI):
898     case _OP(SUB, mF):
899       SUBMOD( t, rb_b, ra_b ); core[db].b = t;
900     case _OP(SUB, mA):
901       SUBMOD( t, rb_a, ra_a); core[db].a = t;
902       break;
903     case _OP(SUB, mB):
904       SUBMOD( t, rb_b, ra_b ); core[db].b = t;
905       break;
906     case _OP(SUB, mX):
907       SUBMOD( t, rb_a, ra_b ); core[db].a = t;
908     case _OP(SUB, mAB):
909       SUBMOD( t, rb_b, ra_a ); core[db].b = t;
910       break;
911     case _OP(SUB, mBA):
912       SUBMOD( t, rb_a, ra_b ); core[db].a = t;
913       break;
914 
915 
916     case _OP(SEQ, mA):
917       if ( ra_a == rb_a )
918 	INCMOD(ip);
919       break;
920     case _OP(SEQ, mB):
921       if ( ra_b == rb_b )
922 	INCMOD(ip);
923       break;
924     case _OP(SEQ, mAB):
925       if ( ra_a == rb_b )
926 	INCMOD(ip);
927       break;
928     case _OP(SEQ, mBA):
929       if ( ra_b == rb_a )
930 	INCMOD(ip);
931       break;
932 
933     case _OP(SEQ, mI):
934 #if !SIM_STRIP_FLAGS
935 #define mask  (1<<(flPOS)-1)
936       if ( core[da].in & bitmask != core[db].in & bitmask )
937 	break;
938 #else
939       if ( core[da].in != core[db].in )
940 	break;
941 #endif
942       /* fallthrough */
943     case _OP(SEQ, mF):
944       if ( ra_a == rb_a && ra_b == rb_b )
945 	INCMOD(ip);
946       break;
947     case _OP(SEQ, mX):
948       if ( ra_a == rb_b && ra_b == rb_a )
949 	INCMOD(ip);
950       break;
951 
952 
953     case _OP(SNE, mA):
954       if ( ra_a != rb_a )
955 	INCMOD(ip);
956       break;
957     case _OP(SNE, mB):
958       if ( ra_b != rb_b )
959 	INCMOD(ip);
960       break;
961     case _OP(SNE, mAB):
962       if ( ra_a != rb_b )
963 	INCMOD(ip);
964       break;
965     case _OP(SNE, mBA):
966       if ( ra_b != rb_a )
967 	INCMOD(ip);
968       break;
969 
970     case _OP(SNE, mI):
971       if ( core[da].in != core[db].in ) {
972 	INCMOD(ip);
973 	break;
974       }
975       /* fall through */
976     case _OP(SNE, mF):
977       if ( ra_a != rb_a || ra_b != rb_b )
978 	INCMOD(ip);
979       break;
980     case _OP(SNE, mX):
981       if ( ra_a != rb_b || ra_b != rb_a )
982 	INCMOD(ip);
983       break;
984 
985 
986     case _OP(JMN, mBA):
987     case _OP(JMN, mA):
988       if (! rb_a )
989 	break;
990       queue(da);
991       goto noqueue;
992 
993     case _OP(JMN, mAB):
994     case _OP(JMN, mB):
995       if (! rb_b )
996 	break;
997       queue(da);
998       goto noqueue;
999 
1000     case _OP(JMN, mX):
1001     case _OP(JMN, mF):
1002     case _OP(JMN, mI):
1003       if (!rb_a && !rb_b)
1004 	break;
1005       queue(da);
1006       goto noqueue;
1007 
1008 
1009     case _OP(JMP, mA):
1010     case _OP(JMP, mB):
1011     case _OP(JMP, mAB):
1012     case _OP(JMP, mBA):
1013     case _OP(JMP, mX):
1014     case _OP(JMP, mF):
1015     case _OP(JMP, mI):
1016       queue(da);
1017       goto noqueue;
1018 
1019 
1020 
1021     case _OP(SLT, mA):
1022       if (ra_a < rb_a)
1023 	INCMOD(ip);
1024       break;
1025     case _OP(SLT, mAB):
1026       if (ra_a < rb_b)
1027 	INCMOD(ip);
1028       break;
1029     case _OP(SLT, mB):
1030       if (ra_b < rb_b)
1031 	INCMOD(ip);
1032       break;
1033     case _OP(SLT, mBA):
1034       if (ra_b < rb_a)
1035 	INCMOD(ip);
1036       break;
1037     case _OP(SLT, mI):
1038     case _OP(SLT, mF):
1039       if (ra_a < rb_a && ra_b < rb_b)
1040 	INCMOD(ip);
1041       break;
1042     case _OP(SLT, mX):
1043       if (ra_a < rb_b && ra_b < rb_a)
1044 	INCMOD(ip);
1045       break;
1046 
1047 
1048     case _OP(MODM, mI):
1049     case _OP(MODM, mF):
1050       ftmp = 0;			/* we must try to do both modulos even if
1051 				   one fails */
1052       if ( ra_a ) core[db].a = rb_a % ra_a; else ftmp = 1;
1053       if ( ra_b ) core[db].b = rb_b % ra_b; else ftmp = 1;
1054       if ( ftmp ) goto die;
1055       break;
1056     case _OP(MODM, mX):
1057       ftmp = 0;			/* we must try to do both modulos even if
1058 				   one fails */
1059       if ( ra_b ) core[db].a = rb_a%ra_b; else ftmp = 1;
1060       if ( ra_a ) core[db].b = rb_b%ra_a; else ftmp = 1;
1061       if ( ftmp ) goto die;
1062       break;
1063     case _OP(MODM, mA):
1064       if ( !ra_a ) goto die;
1065       core[db].a = rb_a % ra_a;
1066       break;
1067     case _OP(MODM, mB):
1068       if ( !ra_b ) goto die;
1069       core[db].b = rb_b % ra_b;
1070       break;
1071     case _OP(MODM, mAB):
1072       if ( !ra_a ) goto die;
1073       core[db].b = rb_b % ra_a;
1074       break;
1075     case _OP(MODM, mBA):
1076       if ( !ra_b ) goto die;
1077       core[db].a = rb_a % ra_b;
1078       break;
1079 
1080 
1081     case _OP(MUL, mI):
1082     case _OP(MUL, mF):
1083       core[db].b = (rb_b * ra_b) % coresize;
1084     case _OP(MUL, mA):
1085       core[db].a = (rb_a * ra_a) % coresize;
1086       break;
1087     case _OP(MUL, mB):
1088       core[db].b = (rb_b * ra_b) % coresize;
1089       break;
1090     case _OP(MUL, mX):
1091       core[db].a = (rb_a * ra_b) % coresize;
1092     case _OP(MUL, mAB):
1093       core[db].b = (rb_b * ra_a) % coresize;
1094       break;
1095     case _OP(MUL, mBA):
1096       core[db].a = (rb_a * ra_b) % coresize;
1097       break;
1098 
1099 
1100     case _OP(DIV, mI):
1101     case _OP(DIV, mF):
1102       ftmp = 0;			/* we must try to do both divisions even if
1103 				   one fails */
1104       if ( ra_a ) core[db].a = rb_a / ra_a; else ftmp = 1;
1105       if ( ra_b ) core[db].b = rb_b / ra_b; else ftmp = 1;
1106       if ( ftmp ) goto die;
1107       break;
1108     case _OP(DIV, mX):
1109       ftmp = 0;			/* we must try to do both divisions even if
1110 				   one fails */
1111       if ( ra_b ) core[db].a = rb_a / ra_b; else ftmp = 1;
1112       if ( ra_a ) core[db].b = rb_b / ra_a; else ftmp = 1;
1113       if ( ftmp ) goto die;
1114       break;
1115     case _OP(DIV, mA):
1116       if ( !ra_a ) goto die;
1117       core[db].a = rb_a / ra_a;
1118       break;
1119     case _OP(DIV, mB):
1120       if ( !ra_b ) goto die;
1121       core[db].b = rb_b / ra_b;
1122       break;
1123     case _OP(DIV, mAB):
1124       if ( !ra_a ) goto die;
1125       core[db].b = rb_b / ra_a;
1126       break;
1127     case _OP(DIV, mBA):
1128       if ( !ra_b ) goto die;
1129       core[db].a = rb_a / ra_b;
1130       break;
1131 
1132 
1133     case _OP(NOP,mI):
1134     case _OP(NOP,mX):
1135     case _OP(NOP,mF):
1136     case _OP(NOP,mA):
1137     case _OP(NOP,mAB):
1138     case _OP(NOP,mB):
1139     case _OP(NOP,mBA):
1140       break;
1141 
1142     case _OP(LDP,mA):
1143       ftmp = ra_a % pspacesize;
1144       core[db].a = UNSAFE_PSPACE_GET(w->id, ftmp);
1145       break;
1146     case _OP(LDP,mAB):
1147       ftmp = ra_a % pspacesize;
1148       core[db].b = UNSAFE_PSPACE_GET(w->id, ftmp);
1149       break;
1150     case _OP(LDP,mBA):
1151       ftmp = ra_b % pspacesize;
1152       core[db].a = UNSAFE_PSPACE_GET(w->id, ftmp);
1153       break;
1154     case _OP(LDP,mF):
1155     case _OP(LDP,mX):
1156     case _OP(LDP,mI):
1157     case _OP(LDP,mB):
1158       ftmp = ra_b % pspacesize;
1159       core[db].b = UNSAFE_PSPACE_GET(w->id, ftmp);
1160       break;
1161 
1162     case _OP(STP,mA):
1163       ftmp = rb_a % pspacesize;
1164       UNSAFE_PSPACE_SET(w->id, ftmp, ra_a);
1165       break;
1166     case _OP(STP,mAB):
1167       ftmp = rb_b % pspacesize;
1168       UNSAFE_PSPACE_SET(w->id, ftmp, ra_a);
1169       break;
1170     case _OP(STP,mBA):
1171       ftmp = rb_a % pspacesize;
1172       UNSAFE_PSPACE_SET(w->id, ftmp, ra_b);
1173       break;
1174     case _OP(STP,mF):
1175     case _OP(STP,mX):
1176     case _OP(STP,mI):
1177     case _OP(STP,mB):
1178       ftmp = rb_b % pspacesize;
1179       UNSAFE_PSPACE_SET(w->id, ftmp, ra_b);
1180       break;
1181 
1182 #if DEBUG > 0
1183     default:
1184       alive_cnt = -1;
1185       goto out;
1186 #endif
1187     }
1188 
1189     INCMOD(ip);
1190     queue(ip);
1191   noqueue:
1192     w = w->succ;
1193   } while(--cycles>0);
1194 
1195  out:
1196 #if DEBUG == 1
1197   printf("cycles: %d\n", cycles);
1198 #endif
1199   return alive_cnt;
1200 }
1201