1$Id: README,v 1.1.1.1 2003/08/26 16:57:02 varfar Exp $
2
3This is exhaust version 1.9, a memory array redcode simulator.  It is
4mostly in the public domain (see the file COPYING for details).
5
6Files:
7        changelog          Log of Change.
8        COPYING            lack of license.
9        Makefile           file for make.
10        README             This file.
11	NEWS		   Notes about things that might break.
12        asm.c              (Dis)Assembler.
13        asm.h              Token codes and prototypes for assembler.
14        exhaust.c          Simplified pMARS-like simulator.
15        exhaust.h          Global constants, structures and types.
16        insn.h             Instruction encoding specs.
17        sim.c              Simulator proper.
18        sim.h              Simulator prototypes.
19	pspace.c	   P-space implementation.
20	pspace.h	   P-space prototypes.
21        test.pl            Perl program to test for differences between
22                           simulators.
23        t/*.red		   Redcode for tests.
24	t/*.rc		   Load files for tests.
25
26To compile on UNIX or on DOS with djgpp first edit the makefile to
27your comfort and then run `make' to get an executable `exhaust'.  If
28you have gcc you hopefully don't need to make any large makefile
29modifications.  See the section `How to use the simulator and friends'
30below for an overview of how to use the simulator in your programs.
31
32Thanks to the pMARS authors and Ken Espiritu for ideas implemented in
33this simulator.  Especially Ken's effective addressing calculation code
34from pMARS 0.8.6 was adapted for a great speed-up.
35
36
37* How to use the simulator and friends
38--------------------------------------
39
40This is a quick run-down on how to use the simulator and assembler
41with your program.  Special considerations for P-Space are detailed in
42the section about p-space below, so here non-P warriors are assumed.
43After munging your source file, remember to link your executable with
44sim.o, pspace.o, and asm.o!  You don't need asm.o if you don't use the
45assembler or disassembler.
46
47The main things that you should do are:
48  - generate (perhaps by assembling) the warrior code
49  - allocate the internal buffers
50  - clear core and load the warriors into it
51  - call the simulator to do it's thing
52
53In the examples, I assume you use a warrior structure similar to
54exhaust.h's struct warrior_st, but it is not canonical in any way.
55Here I rely on the following fields:
56
57        insn_t code[ MAXLENGTH ];   /* code of warrior */
58        int len;                    /* length of warrior code */
59        int start;                  /* start relative to first insn */
60
61* The assembler:
62
63i) You need some declarations and includes:
64
65#include "exhaust.h"
66#include "asm.h"
67
68        warrior_t w1, w2;       /* warrior structs hold code and misc. info */
69        int CORESIZE = 8000,    /* size of core */
70            PROCESSES = 8000,   /* max. number of processes per warrior */
71            NWARRIORS = 2,      /* number of warriors */
72            CYCLES = 80000;     /* cycles until tie */
73
74ii) Then you want to assemble your warriors, say aeka and Rave:
75
76        asm_fname( "aeka.rc", &w1, CORESIZE );
77        asm_fname( "rave.rc", &w2, CORESIZE );
78
79You could also use asm_file(FILE *, warrior_t *, CORESIZE) to assemble
80from a stream.
81
82
83* Simulator:
84
85i) The simulator interface is simple.  First you need to allocate and
86query the address of the core memory:
87
88#include "exhaust.h"
89#include "sim.h"
90        insn_t *core;
91
92        core = sim_alloc_bufs( NWARRIORS, CORESIZE, PROCESSES, CYCLES );
93
94If any of the allocations failed the returned value will be NULL.  You
95should check for that. When you're done with the core memory and other
96buffers, call sim_free_bufs(void), but note that sim_alloc_bufs()
97frees any memory it previously allocated.  i.e. you can successively
98call it without intervening calls to sim_free_bufs().
99
100For backward compatibility you can also use use sim() as follows to
101allocate with the default CORESIZE=PROCESSES=8000:
102
103        (void) sim( -1, 0, 0, CYCLES, &core );
104
105ii) Then you clear core and load the warriors:
106
107        memset( core, 0, sizeof(insn_t) * CORESIZE );
108or
109	sim_clear_core();
110
111and
112	sim_load_warrior(0,   &(w1.code[0]), w1.len );
113	sim_load_warrior(pos, &(w2.code[0]), w2.len );
114
115where `pos' is the core address where you want to load w2.  This
116differs slightly from the previous release where you had to:
117
118        memcpy( core,       w1.code, sizeof(insn_t) * w1.len );
119        memcpy( core + pos, w2.code, sizeof(insn_t) * w2.len );
120
121You can still do that.  (Note however, that the flags field of
122instructions should be cleared as the simulator won't do it anymore.
123sim_load_warrior() does this for you.  You can get the old behaviour
124by defining the preprocessor variable SIM_STRIP_FLAGS to 1 at compile
125time.)
126
127
128iii) Right, now you're ready to fight.  If you have only one or two
129warriors, you can use sim():
130
131        result = sim( 2, w1.start, (w2.start+pos)%CORESIZE, CYCLES, NULL);
132
133The result is 0 if w1 won, 1 if w2 won, and 2 on a tie (-1 if the
134simulator panics).
135
136For multi-warrior battles with more than two warriors you need
137some extra declarations:
138
139        field_t war_pos_tab[ NWAR ];    /* a table of core addresses
140                                         * that specify where the warriors
141                                         * start their execution. */
142        int death_tab[ NWAR ];          /* the simulator stores the
143                                         * results here. (see below) */
144
145Then allocate the buffers and obtain the core address using
146sim_alloc_bufs(), clear the core, and load the warriors into it as
147before.  Save the positions where you loaded the warriors into
148war_pos_tab[].  Now you're ready to fight, so call sim_mw():
149
150        int alive_cnt;
151        alive_cnt = sim_mw( NWAR, war_pos_tab, death_tab );
152
153The return value is the number of warriors alive at the end of the
154round.  Dead warriors are recorded into death_tab[] by order of death.
155i.e. death_tab[0] contains the index of the first warrior to die,
156death_tab[1] the index of the second to go, and so on.
157
158
159* The disassembler:
160
161If you want to disassemble an instruction use dis1() or discore() from
162asm.c.  Examples:
163
164#include "exhaust.h"
165#include "asm.h"
166
167        char str[60];
168        insn_t instr;
169
170        instr.in = _OP( SPL, mF, DIRECT, BPREDEC );
171        instr.a = instr.b = 0;
172        core[1234] = instr;
173
174        dis1( str, core[1234], CORESIZE ); printf("%s\n", str);
175        dis1( str, instr, CORESIZE );      printf("%s\n", str);
176
177                                        /* disassemble addresses 5..14 */
178        discore( core, 5, 15, CORESIZE);/* and print to stdout. */
179
180
181* P-Space
182---------
183
184The simulator interface is oriented toward playing single battles, but
185p-space by its nature requires a multi-round interface.  Hence there
186are some complications when playing p-space warriors.  The main change
187for P-spacer battles over normal ones is that you need to pair
188p-spaces to warriors.  Also, if you are running multiple battles you
189need to reinitialise the p-spaces between each battle.
190
191The basic model is simple: the simulator maintains an array of
192NWARRIORS p-spaces that you may manipulate.  The ith p-space in this
193array always corresponds to the ith warrior passed to sim() or
194sim_mw(), so that the first warrior always accesses the first p-space,
195the second the second, and so on.  The pairing betweens p-spaces and
196warriors is up to you.  After each round the p-space location 0 of
197each warrior is updated with either a) zero if the warrior died or b)
198the number of warriors alive at the end of the battle.
199
200[A note about naming conventions: pspace_XXX() functions are mostly
201local in nature -- they refer only to their argument p-spaces.  The
202sim_XXX_pspace() functions are about the collection of p-spaces
203maintained by the simulator.]
204
205
206* Accessing p-spaces
207
208To get a pointer to the ith p-space you use the function
209sim_get_pspace():
210
211	pspace_t *p = sim_get_pspace(i);
212
213Then to access the cells of `p', use the functions pspace_get() and
214pspace_set():
215
216	contents_of_cell_123 = pspace_get(p, 123);
217
218	pspace_set(p, 123, new_contents);
219
220
221* P-space initialisation; resets
222
223 - The size of p-space is specified at memory allocation time using
224   the function sim_alloc_bufs2().  It is exactly like
225   sim_alloc_bufs(), except it takes as an additional parameter the
226   size of pspace, which must be positive.  The later function
227   defaults p-space to CORESIZE/16 cells, so you don't need to change
228   it.
229
230 - The function sim_clear_pspaces() clears the p-spaces of all warriors
231   and stores CORESIZE-1 into their p-space location 0.  P-Space is
232   cleared on allocation, so you only need to call this function
233   between battles, but not rounds.  This function doesn't change
234   the sharing status of p-spaces.
235
236 - To completely reinitialise p-spaces and to make p-spaces of each
237   warrior private again, call the sim_reset_pspaces() function.  This
238   also calls sim_clear_pspaces().
239
240
241* Pairing p-spaces to warriors
242
243If you are changing the order in which warriors execute within each
244cycle on a per-round basis, you need to order p-spaces as well.  For
245example, pMARS cyclically permutes the order of warriors so that every
246even round the first warrior executes first in each cycle, and every
247odd round the second warrior executes first.  With non-pspace warriors
248you only need to give the starting positions of the warriors in the
249`war_pos_tab[]' argument in the order you want the warriors to
250execute, but with p-warriors involved you need to match p-spaces to
251warriors as well.
252
253 - The simulator maintains an array of pointers to p-space structures,
254   one for each warrior.  The ith p-space structure corresponds to the
255   ith warrior in the `war_pos_tab[]' array argument of warrior
256   starting positions passed to sim_mw().  Similarly for the two
257   warriors given to the sim() function.  You need to order this array
258   of pointers to match the order in which you are passing warrior
259   starting positions to the simulator.
260
261   To access the array, use sim_get_pspaces():
262
263	pspace_t **pspaces;
264	pspaces = sim_get_pspaces();
265
266	// now permute the pointers in the pspaces array into the
267	// same order as your warriors.
268	...
269
270   Of course, if you are not changing the order in which warriors
271   execute on a per-round basis, you don't need to permute the pspaces
272   array.  This may be suitable in some cases.
273
274
275* Sharing p-spaces
276
277There is only minimal support for PINs and p-space sharing in that the
278assembler understands the `PIN' pseudo-op, but you must match PINs to
279p-spaces yourself.
280
281  - The warrior structure warrior_st in exhaust.h needs the extra fields
282
283	int have_pin;			// boolean: is field `pin' valid?
284	u32_t pin;			// PIN of warrior, possibly.
285
286    that are used when assembling from files/streams.  The interface
287    to asm_line() has changed accordingly so it can identify and
288    return the PIN pseudo-op.
289
290  - To share p-spaces of two warriors, you need to call the function
291    pspace_share(p1, p2) for two pointers p1, p2 to p-spaces.  The
292    contents of p-space p1 becomes the contents of the shared p-space.
293    P-space location 0 is never shared.
294
295  - The function pspace_privatise(p) resets the p-space p to be
296    private.  The contents of p1 are then undefined.
297
298
299
300* Files that the assembler eats
301-------------------------------
302
303In short: the load files that the '94 draft specifies are accepted.
304Specifically, the files may contain only `;' comments, white space,
305instructions, and pseudo-ops.  The instructions must follow this form:
306
307  [opt START label]    OPCODE.MODIFIER  MODE integer , MODE integer
308
309Various idiosyncrasies:
310
311 - You can't implicitly specify direct addressing mode by dropping `$'.
312
313 - The start of a warrior is determined by the last seen appearance of
314   the START label or `ORG'.  Of the pseudo-ops using `END label' or
315   `ORG label' aren't supported; only `ORG integer' is.
316
317 - `END' stops warrior assembly.  You still can assemble from the
318   same file or stream another warrior that follows though.
319
320 - special KotH comments aren't recognised.
321
322To support using pMARS as an assembler any line that begins with
323`Program' is ignored.  So you could first say
324
325  pmars -r 0 Fancy_Source.red >Simple_Source.rc
326
327and then use the asm.c assembler to import Simple_Source.rc into your
328program.  Note that pmars doesn't output PINs of warriors.
329
330
331* When the simulator crashes
332----------------------------
333
334... or is just plain wrong by producing incorrect results please tell
335me about it at the address given below.  Ditto for the assembler or
336anything else in these files.  I'd appreciate a simple test case that
337illustrates the bug if possible.
338
339The author can be reached by email at: jpihlaja@cc.helsinki.fi
340