-
Notifications
You must be signed in to change notification settings - Fork 2
/
doc.txt
173 lines (148 loc) · 8.12 KB
/
doc.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
Welcome to a new generation of CPUs!
We run on 48 bits, using 4 registers, relative addressing, cyclic memory,
and last but not least a customized instruction set.
The Gentoo handbook told me once:
1: READ EVERYTHING, don't skip around. don't skim the text, but do read the whole thing once to get an idea whats going on.
2: Use your brain! Stop and think about what its saying.
3: If you have a problem, try to solve it yourself.
The same goes for you.
The memory, (which will be called: board through this manual) will be
initialized with 0s. Then the CPU will load the programs, and start them in
an arbitrary order. The CPU uses cyclic relative addressing. Therefore all addresses are relativ to the Instruction pointer.
mov *1 *0 will move the cell at IP+0 to the cell at IP+1 (thus effectivly copy the instruction to the next cell).
Furthermore the memory is cyclic (addresses that are bigger than the biggest valide address are wrapped).
Assuming a Coresize of 400 cells, trying to read from address 403 will result in reading address 3.
A program never knows its "real" address, as the current instruction will always have the address 0.
The general layout of the supported instructions is:
name_of_instruction destination source
if you feel like it you can also write:
name_of_instruction,destination,source;
or even:
name_of_instruction,,,,destination,,source;
Well, you get the idea. I will only use the first version, because it uses
less characters. Additionally, it is possible to write comments everything
after a semicolon will be ignored:
;Hi dear reader, I am a comment
same goes for //
//I am a comment, too!
You can use the special comments:
;name: $heregoesthenameofyourbot
;desc: here goes some description of your bot, to provide your bot with meta information
===Binary Layout===
Every memory cell (read: "every memory word") consists of 3 parts:
[op1] [op2] [cmd]
20 20 6 Bits
While it is possible to use operands that are not needed by the instruction, it is
considered bad style and will most probably result in unexpected crashes. Do not use
additional operands for modifying additional values by means of post decrement/increment,
because this would result in ugly code.
=== Registers ===
There are four general purpose registers.
ptr - the pointer register
acc - the accumulator register
r1 - nameless register one
r2 - nameless register two
=== CPU flags ===
There are three flags that will be set by the CPU:
equal - will be set if the result of the last instruction was zero
above - will be set if the result of the last instruction was >zero
smaller - will be set if the result of the last instruction was <zero
The flag will be set for every instruction where it makes sense ;) For example
cmp, all arithmetic and logic operations
=== Mov instructions ===
mov dest src - move stuff from the source to the destination
mvp val unused - move stuff to the *ptr register
mva val unused - move stuff to the acc register
=== Logic operations ===
xor dest src - dest xor src, the result will be saved to dest
and dest src - dest and src, the result will be saved to dest
or dest src - dest or src, the result will be saved to dest
not dest unused - binary not on destination, the result will be saved to dest
=== Arithmetic operation ===
dec dest unused - decrement destination, save the result to dest
inc dest unused - increment destination, save the result to dest
neg dest unused - negate destination, save the result to dest
add dest src - add src to dest, the result will be saved to dest
sub dest src - sub src from dest, the result will be saved to dest
mul dest src - multiply dest and src, the result will be saved to dest
div dest src - divide dest by src, the result will be saved to dest
mod dest src - the remainder of the division dest/src, the result ...
ica unused unused - increment acc
dca unused unused - decrement acc
ada val unused - same as add acc val
sba val unused - same as sub acc val
=== Jmp instructions ===
jmp dest unused - continue execution at dest
jie dest unused - jmp if equal
jia dest unused - jmp if above
jis dest unused - jmp if smaller
jne dest unused - jmp if not equal
jna dest unused - jmp if not above
jns dest unused - jmp if not smaller
=== Important and useful other stuff ===
cmp src dest -compare the src and the destination, flags will be set
splt dest unused - create a new thread at dest
die unused unused - stop execution of this thread
=== Interrupts ===
The CPU has an interrupt vector containing three interrupts. The cpu has a hidden register containing the interrupt flags. If any of this flags is set, the cpu will jump to offset stored in the interrupt vector. If two or more interrupts are set, one instruction is executed in the first interrupt handler, than the next interrupt handler is called (you can use this instruction to disable the interrupt_enable flag). The interrupts are prioritised as following: First call Imem, then cza and finally cza.
sti unused unused - enable interrupts
cli unused unused - disable interrupts
rti unused unused - return from interrupt (does not work recursively)
The next instructions are used to set the interrupt vectors.
If the dest is 0 this interrupt is disabled
clk cycles dest - jumps to dest every #cycles, the #cycles must be >=4
mem addr dest - jumps dest whenever addr is changed
cza val dest - jumps to dest if acc is equal to val
=== Labels ===
You can use labels to increase readability of your code.
:label - everything after a ":" will be a label (only [a-z] are allowed for
labeling!
jmp @label - will jump to label
it is also possible to use @label in other context, just know that @label
holds the relative addr of :label
===Constants===
$constant=42 - defines a constant, with name constant and value 42, you can
now use it whenever needed (e.g. add ptr, $stepsize+2)
===Parameters===
a parameter looks like: /(*|**)?(number|register)[+\-]?/
example: mov r1 **3-
The binary layout of the parameters:
[type][value_type][value][op]
2 1 16 2 Bit
type: 01=> direct (*ptr) 10=>indirect(**ptr) 11=> immediate (ptr) 00=> invalid
value_type: 1=>reg / 0=>constant value
op: 01=>inc 10=>dec 11=>noop 00=> invalid
===Debugging===
While writing your code you can use two different tools:
*Debugger
First of all, use `ruby debugger.rb $yourbot $otherbot` to visualise the behaviour of the bots.
This program is a graphical cpu emulator.
Commands:
* Space - pauses/restarts emulation
* Arrows / hjkl - move the cursor (the value under the cursor is shown in the lower part of the screen)
* -/+ - increase/decrease the simulation speed
* q - exit emulation
* n - abort current simulation and restart
* s - single step through emulation
* m - moves the cursor to the next running thread
* t - cycles which threads registers are displayed in the lower line
*Profiler
Then evaluate the efficiency of your bot with `ruby profiler.rb $yourbot $otherbot`.
This program will perform a huge number of games and tells you about the outcome.
===Deploying===
So you have written your Code, what now?
You will have to send the code the the server. To do that you have to use the bot_add script.
The server will have a scoreboard running on http://server:8080/scores.html you will also find the parameters of the game on top of the scoreboard (e.G. max number of threads per player, coresize etc.)
`ruby bot_add.rb $yourbot $server $username $password`
The server the tests the performance of your bot. The results will be shown on http://$server/scores.html.
For the challenge version you have to use bot_add.rb $yourbot 10.11.200.3 $password.
The password is obtained by completing either of the two challenge branches. Each challenge branch will give you two passwords.
either send $pass1$pass2 or $pass2$pass1 as password for your bot.
===Setup===
install Ruby (1.8 and 1.9 work) & ruby-dev
install ruby gems
install ruby1.9.1-dev (fixes mkmf error)
install the ncurses, json(only needed for 1.8) and the parallel gem
(gem install ncurse && gem install parallel)
(maybe you have to install the packge ruby1.8-ncurses or something like this)
=> everything should work now (note, ncurses seems to be buggy - even the samples don't work on some machines -_-)