1$Id: README,v 1.1 2003/06/06 12:08:39 martinus 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 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.
123sim_load_warrior() does this for you.)
124
125
126iii) Right, now you're ready to fight. If you have only one or two
127warriors, you can use sim():
128
129 result = sim( 2, w1.start, (w2.start+pos)%CORESIZE, CYCLES, NULL);
130
131The result is 0 if w1 won, 1 if w2 won, and 2 on a tie (-1 if the
132simulator panics).
133
134For multi-warrior battles with more than two warriors you need
135some extra declarations:
136
137 field_t war_pos_tab[ NWAR ]; /* a table of core addresses
138 * that specify where the warriors
139 * start their execution. */
140 int death_tab[ NWAR ]; /* the simulator stores the
141 * results here. (see below) */
142
143Then allocate the buffers and obtain the core address using
144sim_alloc_bufs(), clear the core, and load the warriors into it as
145before. Save the positions where you loaded the warriors into
146war_pos_tab[]. Now you're ready to fight, so call sim_mw():
147
148 int alive_cnt;
149 alive_cnt = sim_mw( NWAR, war_pos_tab, death_tab );
150
151The return value is the number of warriors alive at the end of the
152round. Dead warriors are recorded into death_tab[] by order of death.
153i.e. death_tab[0] contains the index of the first warrior to die,
154death_tab[1] the index of the second to go, and so on.
155
156
157* The disassembler:
158
159If you want to disassemble an instruction use dis1() or discore() from
160asm.c. Examples:
161
162#include "exhaust.h"
163#include "asm.h"
164
165 char str[60];
166 insn_t instr;
167
168 instr.in = _OP( SPL, mF, DIRECT, BPREDEC );
169 instr.a = instr.b = 0;
170 core[1234] = instr;
171
172 dis1( str, core[1234], CORESIZE ); printf("%s\n", str);
173 dis1( str, instr, CORESIZE ); printf("%s\n", str);
174
175 /* disassemble addresses 5..14 */
176 discore( core, 5, 15, CORESIZE);/* and print to stdout. */
177
178
179* P-Space
180---------
181
182The simulator interface is oriented toward playing single battles, but
183p-space by its nature requires a multi-round interface. Hence there
184are some complications when playing p-space warriors. The main change
185for P-spacer battles over normal ones is that you need to pair
186p-spaces to warriors. Also, if you are running multiple battles you
187need to reinitialise the p-spaces between each battle.
188
189The basic model is simple: the simulator maintains an array of
190NWARRIORS p-spaces that you may manipulate. The ith p-space in this
191array always corresponds to the ith warrior passed to sim() or
192sim_mw(), so that the first warrior always accesses the first p-space,
193the second the second, and so on. The pairing betweens p-spaces and
194warriors is up to you. After each round the p-space location 0 of
195each warrior is updated with either a) zero if the warrior died or b)
196the number of warriors alive at the end of the battle.
197
198[A note about naming conventions: pspace_XXX() functions are mostly
199local in nature -- they refer only to their argument p-spaces. The
200sim_XXX_pspace() functions are about the collection of p-spaces
201maintained by the simulator.]
202
203
204* Accessing p-spaces
205
206To get a pointer to the ith p-space you use the function
207sim_get_pspace():
208
209 pspace_t *p = sim_get_pspace(i);
210
211Then to access the cells of `p', use the functions pspace_get() and
212pspace_set():
213
214 contents_of_cell_123 = pspace_get(p, 123);
215
216 pspace_set(p, 123, new_contents);
217
218
219* P-space initialisation; resets
220
221 - The size of p-space is specified at memory allocation time using
222 the function sim_alloc_bufs2(). It is exactly like
223 sim_alloc_bufs(), except it takes as an additional parameter the
224 size of pspace, which must be positive. The later function
225 defaults p-space to CORESIZE/16 cells, so you don't need to change
226 it.
227
228 - The function sim_clear_pspaces() clears the p-spaces of all warriors
229 and stores CORESIZE-1 into their p-space location 0. P-Space is
230 cleared on allocation, so you only need to call this function
231 between battles, but not rounds. This function doesn't change
232 the sharing status of p-spaces.
233
234 - To completely reinitialise p-spaces and to make p-spaces of each
235 warrior private again, call the sim_reset_pspaces() function. This
236 also calls sim_clear_pspaces().
237
238
239* Pairing p-spaces to warriors
240
241If you are changing the order in which warriors execute within each
242cycle on a per-round basis, you need to order p-spaces as well. For
243example, pMARS cyclically permutes the order of warriors so that every
244even round the first warrior executes first in each cycle, and every
245odd round the second warrior executes first. With non-pspace warriors
246you only need to give the starting positions of the warriors in the
247`war_pos_tab[]' argument in the order you want the warriors to
248execute, but with p-warriors involved you need to match p-spaces to
249warriors as well.
250
251 - The simulator maintains an array of pointers to p-space structures,
252 one for each warrior. The ith p-space structure corresponds to the
253 ith warrior in the `war_pos_tab[]' array argument of warrior
254 starting positions passed to sim_mw(). Similarly for the two
255 warriors given to the sim() function. You need to order this array
256 of pointers to match the order in which you are passing warrior
257 starting positions to the simulator.
258
259 To access the array, use sim_get_pspaces():
260
261 pspace_t **pspaces;
262 pspaces = sim_get_pspaces();
263
264 // now permute the pointers in the pspaces array into the
265 // same order as your warriors.
266 ...
267
268 Of course, if you are not changing the order in which warriors
269 execute on a per-round basis, you don't need to permute the pspaces
270 array. This may be suitable in some cases.
271
272
273* Sharing p-spaces
274
275There is only minimal support for PINs and p-space sharing in that the
276assembler understands the `PIN' pseudo-op, but you must match PINs to
277p-spaces yourself.
278
279 - The warrior structure warrior_st in exhaust.h needs the extra fields
280
281 int have_pin; // boolean: is field `pin' valid?
282 u32_t pin; // PIN of warrior, possibly.
283
284 that are used when assembling from files/streams. The interface
285 to asm_line() has changed accordingly so it can identify and
286 return the PIN pseudo-op.
287
288 - To share p-spaces of two warriors, you need to call the function
289 pspace_share(p1, p2) for two pointers p1, p2 to p-spaces. The
290 contents of p-space p1 becomes the contents of the shared p-space.
291 P-space location 0 is never shared.
292
293 - The function pspace_privatise(p) resets the p-space p to be
294 private. The contents of p1 are then undefined.
295
296
297
298* Files that the assembler eats
299-------------------------------
300
301In short: the load files that the '94 draft specifies are accepted.
302Specifically, the files may contain only `;' comments, white space,
303instructions, and pseudo-ops. The instructions must follow this form:
304
305 [opt START label] OPCODE.MODIFIER MODE integer , MODE integer
306
307Various idiosyncrasies:
308
309 - You can't implicitly specify direct addressing mode by dropping `$'.
310
311 - The start of a warrior is determined by the last seen appearance of
312 the START label or `ORG'. Of the pseudo-ops using `END label' or
313 `ORG label' aren't supported; only `ORG integer' is.
314
315 - `END' stops warrior assembly. You still can assemble from the
316 same file or stream another warrior that follows though.
317
318 - special KotH comments aren't recognised.
319
320To support using pMARS as an assembler any line that begins with
321`Program' is ignored. So you could first say
322
323 pmars -r 0 Fancy_Source.red >Simple_Source.rc
324
325and then use the asm.c assembler to import Simple_Source.rc into your
326program. Note that pmars doesn't output PINs of warriors.
327
328
329* When the simulator crashes
330----------------------------
331
332... or is just plain wrong by producing incorrect results please tell
333me about it at the address given below. Ditto for the assembler or
334anything else in these files. I'd appreciate a simple test case that
335illustrates the bug if possible.
336
337The author can be reached by email at: jpihlaja@cc.helsinki.fi
338