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