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