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