1 unstable release
0.1.0 | May 30, 2022 |
---|
#3 in #nucleus
34KB
597 lines
This is an intro to the Nucleus game and the kaon language. The goal is to write a program (quark) that will outlive every other program, in a shared memory core.
Installation instructions
You can install lepton (the implimentation of nucleus) using flakes or
cargo (TODO!). Using nix flakes:
nix run git+https://time.ta.rdis.dev/el/lepton
Using cargo:
cargo install leptonvm(!)
(TODO!)
Tutorial
The "core" is a linear sequence of random-access memory, 4096 instructions wide. Access are 0-indexed and wrap around (Address 4096 is the same as address 0)
Example core (4 instructions wide)
Index | Instruction |
---|---|
0 |
JUMP |
1 |
ADD |
2 |
JUMP |
3 |
DIE |
Quarks are written in a language called kaon. Every quark must start
with an author + title line. The format for a so-called "title line" is
@ Author name : Program Name
, such as @ John Doe : Brutus
. Quarks
are encouraged to have unique program names to reduce confusion about
winners
After the title line, one or more instructions follow. Each instruction takes the form of keyword, followed by one or more arguments. Arguments are comma-separated, with one or more spaces between the arguments and keyword.
All arguments are also addresses. There are four kinds of addresses:
literal, absolute, relative, and relative-offset. Literal addresses are
a number, used as a value in a computation. They are stored in the core
as a DIE
instruction. Absolute addresses are prefixed with a #
, such
as #3
. They reference addresses from the start of the core. A relative
address is a number of instructions ahead or behind the current
instruction, like .1
(the next instruction). Each relative instruction
is prefixed with a .
. The last type of address, a relative-offset
address takes the form of .x#y
. This behaves like a relative address
except that the value of address y
is added to the computed
relative address. This could be written as "The address x units from
where I am plus the value of address y".
Jumps six instructions ahead
die 5
jump .1#-1
If the instruction at y
is not a DIE
, the quark will stop execution.
For example, .1#-1
will move the value of .-1
spaces past the next
instruction (.1
).
Each quark has its own thread. Each cycle, the computer switches between threads. For two threads, A & B, this looks like: ABABABABABABAB; for three: ABCABCABCABCABC. When a program dies, it is no longer executed. If program C dies: ABC ABC AB AB AB. Dead quarks do not have their memory zeroed or otherwise removed. This means you could jump into a dead thread and revive it (though unlikely). A winner is declared when there is only one thread left.
Usage of lepton
Lepton is the reference implementation of nucleus. It is available at
https://time.ta.rdis.dev/el/lepton. Pass each program as an argument
to the command line. Use RUST_LOG
to enable logging. debug
will list
the loading and unloading of quarks. trace
will print each instruction
being executed. Passing -p
/ --playback
will produce a dump of the
core at each cycle for debugging / inspection. Each line contains the
state from the current cycle (first line is before execution, second
line is after cycle 1). To set the number of iterations, use -i
/
--iterations
(The default is 4096*8)
Example quarks
A simple loop
@ Ellie : Loop
jump .0
Jumps to the current address
A quark that moves forward
@ Ellie : Jogger
mov .0 .1
Copy the current instruction to the next instruction (which is then executed)
A quark that bombs the core with DIE
@ Ellie : Bomber
jump .2
die 0
mov .-1 .3#-1
add 1, .-2
jump .-2
This uses relative-offset addresses to make the target of the bomb move
forward (ADD
).
Instruction reference
Instruction syntax |
Arguments |
Results |
Notes |
|
x: The source address; y: the destination address |
Copies value x to y |
y should not be constant. |
|
x: any value; y: any value |
Compares x to y and sets the equality flag if they are |
Only compares equality |
|
x: any value; y: any value |
Compares the instruction type of a to b. Sets the flag if they are |
|
|
a: any address |
Jumps to a if the equality flag is set
(i.e. the last |
A constant is treated as an absolute address. |
|
a: any address |
Moves execution of the current thread to address a. |
A constant is treated as an absolute address. |
|
a: any value; b: any address |
Adds a to b and stores the result in b |
b should not be constant. If b is constant, the program dies. |
|
a: any value; b: any address |
Subtracts a from b and stores the result in b |
b should not be constant. If b is constant, the programs dies. |
|
a: any value; b: any address |
Multiplies a and b and stores the result in b |
b should not be constant. If b is constant, the programs dies. |
|
a: any value; b: any address |
divides a by b and stores the value in b |
b should not be constant. The value of b should not b 0. If either of these is true, the program dies. |
|
x: any literal |
If this instruction is executed, the program stops. However, it stores data for use by other instructions. |
Magic death trap |
Dependencies
~5–15MB
~178K SLoC