---
title: "Redcode, instruction by instruction"
description: "Redcode, the language of Core War, with every addressing mode, modifier and opcode as an animation you can step through, and a debugger for your own warriors."
date: 2026-10-01T00:00:00Z
lastmod: 2026-10-16T19:06:54+02:00
url: https://klimek.link/posts/redcode/
author: "Marcin Klimek"
source: https://klimek.link/posts/redcode/
---

# Redcode, instruction by instruction

<!-- interactive element omitted in the Markdown version -->

**Redcode** is the assembly language of [Core War](/posts/core-war/), and it's small, with 16 opcodes, 7 modifiers and 8 addressing modes. Every warrior, from the one-line Imp to a tournament winner, is built out of those pieces, and this page goes through what they do, one animation at a time. At the end there's a **debugger** where you can run any warrior step by step and go back in time.

All the animations run on the same simulator as the [arena](/posts/core-war/) (ICWS'94 rules, an 8000-cell core), and what you see here is exactly how a battle plays out.

## An instruction

Every memory cell holds exactly one instruction. Redcode has no bytes, no registers and no separate data memory, and numbers live in the two fields of an instruction, most of the time a `DAT`.

<!-- interactive element omitted in the Markdown version -->

## Addresses are relative, and the core is a ring

Redcode has no address 0. Every number is a **distance from the instruction that is running**, which means `1` is the next cell and `-1` the previous one, and since the core is circular, counting past the last cell brings you back to the first. Warriors never refer to fixed places, which is why they work wherever they get loaded.

<!-- interactive element omitted in the Markdown version -->

## How one instruction runs

Every instruction goes through the same five phases, and the animations use the same colours for them:

1. **Fetch.** The warrior whose turn it is takes the first process from its queue and reads the instruction at that address.
2. **A-operand** (<span style="color:#f5b942">amber</span>). Work out which cell the A-operand points to, following pointers if the mode is indirect.
3. **B-operand** (<span style="color:#b69cff">violet</span>). The same for B.
4. **Effect.** Do the work: copy, add, compare, jump… <span style="color:#4ade80">Green</span> shows a write, white a jump, <span style="color:#fb7185">red</span> a dying process.
5. **Re-queue.** Put the process back at the end of the queue with its next address. A process that ran a `DAT` doesn't go back, because it's dead.

In every demo, **Step ▸** runs one instruction and animates its phases, and if you tick **pause at each phase** you can go through them at your own pace. Coloured bars to the left of an address show which warrior wrote to that cell, and round markers on the right are the processes waiting there.

## Addressing modes

The mode is the character in front of a number, and it decides how that number turns into an address.

| Mode | Name | Where the operand points |
|---|---|---|
| `#` | immediate | at the instruction itself; the number is just a value |
| `$` | direct | the cell *number* cells away (the default) |
| `*` | A-indirect | go to that cell, then go on by the value in its **A**-field |
| `@` | B-indirect | the same, using the **B**-field |
| `{` | A-predecrement | like `*`, but first subtract 1 from that A-field |
| `<` | B-predecrement | like `@`, but first subtract 1 from that B-field |
| `}` | A-postincrement | like `*`, and add 1 to that A-field afterwards |
| `>` | B-postincrement | like `@`, and add 1 to that B-field afterwards |

In this demo `MOV.I` copies something into `dest`. Only the A-mode changes, and every mode picks a different source. The pointer cell `ptr` has `#3` in the A-field and `#1` in the B-field. Pick a mode and press **Step ▸**:

<!-- interactive element omitted in the Markdown version -->

Indirect modes are what keeps Redcode programs short. `MOV bomb, @bomb` drops a bomb wherever the B-field of `bomb` points, and the increment modes turn cells into moving pointers, and with them `MOV >-1, }-1` manages to copy a line and advance two pointers in a single instruction.

## Modifiers

The modifier after the dot says **which fields** of the source (A) instruction get used and **which fields** of the destination (B) instruction get changed.

| Modifier | From A | To B |
|---|---|---|
| `.A` | A-field | A-field |
| `.B` | B-field | B-field |
| `.AB` | A-field | B-field |
| `.BA` | B-field | A-field |
| `.F` | both fields | both fields |
| `.X` | both fields | both fields, crossed (A→B, B→A) |
| `.I` | the whole instruction | the whole instruction (for arithmetic, the same as `.F`) |

Here the source is `SPL #7, #9` and the destination is `DAT #10, #20`, so you can follow which number goes where. Try `MOV.X`, `ADD.F` and `SEQ.I`:

<!-- interactive element omitted in the Markdown version -->

If you leave the modifier out, the assembler picks one based on the opcode and the modes, and `MOV 0, 1` becomes `MOV.I` and `ADD #4, 3` becomes `ADD.AB`. I write modifiers explicitly anyway, because I find them easier to read that way.

## The instructions

### DAT: data, and death

`DAT` holds numbers, and processes that try to *execute* one get removed. Once a warrior has no processes left, it loses, which is why most bombs in Core War are `DAT`s.

<!-- interactive element omitted in the Markdown version -->

### MOV: copy

`MOV` copies from the A-address to the B-address. With `.I` it copies the whole instruction, and that's how warriors copy themselves and drop bombs. The Imp is a single `MOV.I 0, 1` that copies itself to the next cell and then runs that copy. Press **Run** to watch it walk.

<!-- interactive element omitted in the Markdown version -->

### ADD, SUB, MUL, DIV, MOD: arithmetic

Arithmetic changes fields of the B-instruction using the A-values. Results wrap around the core size (8000), which leaves no negative numbers inside the core, and `-1` gets stored as `7999`. Dividing by zero kills the process.

<!-- interactive element omitted in the Markdown version -->

### JMP: jump

The process continues at the A-address. `JMP` never uses the B-operand's value, yet it still evaluates the operand, which lets `JMP 0, <5` jump and decrement a pointer at the same time.

<!-- interactive element omitted in the Markdown version -->

### JMZ and JMN: conditional jumps

`JMZ` jumps to A when the B-value is **zero**, and `JMN` jumps when it's **not** zero. With `.F` or `.I` both fields get tested.

<!-- interactive element omitted in the Markdown version -->

### DJN: decrement and jump

`DJN` subtracts 1 from the B-target and jumps to A if the result isn't zero, which makes it the classic loop counter. The decrement is a write, and `DJN` can use it to damage enemy code too.

<!-- interactive element omitted in the Markdown version -->

### SEQ, SNE, SLT: compare and skip

When the test holds, a comparison **skips** the next instruction. `SEQ` (also written `CMP`) tests for equality, `SNE` for inequality and `SLT` for "A is less than B", and scanners use them to tell empty cells from enemy code.

<!-- interactive element omitted in the Markdown version -->

### SPL: a new process

`SPL` starts a new process at the A-address. The new process goes to the end of the warrior's queue, *after* the current one, which carries on with the next instruction, and a warrior can have up to 8000 processes.

<!-- interactive element omitted in the Markdown version -->

### NOP

`NOP` does nothing, but the operands still get evaluated, which means the increment and decrement modes work as usual.

## Processes and turns

Each warrior has a **queue** of processes, and the simulator alternates between warriors: one instruction of warrior 1, one of warrior 2, and so on. A warrior with more processes does **not** get more turns. Those turns get shared among all of its processes, and each of them has to run more slowly. In this demo warrior 1 splits into four processes and warrior 2 has one:

<!-- interactive element omitted in the Markdown version -->

## Putting it together: the Dwarf

```
dwarf   ADD.AB  #4, bomb      ; move the target 4 cells further
        MOV.I   bomb, @bomb   ; drop the bomb where its B-field points
        JMP     dwarf
bomb    DAT     #0, #0
```

Three instructions in a loop. `ADD.AB` adds 4 to the B-field of `bomb`, `MOV.I bomb, @bomb` follows that B-field (B-indirect) and copies the `DAT` there, and `JMP` goes back to the start. Press **Run** to see the bombs land 4, 8, 12… cells away, and once the target leaves the window, the arrow points off the edge and shows the address.

<!-- interactive element omitted in the Markdown version -->

## The debugger

Load any warrior, with or without an opponent:

- **Step ▸** (<kbd>→</kbd>) runs one instruction with the full animation. At the **phase by phase** speed, each click shows one phase.
- **◂ Back** (<kbd>←</kbd>) goes back one instruction. The debugger saves the core every 1000 steps and replays the rest, so you can rewind a long way.
- **Run ▶** (<kbd>Space</kbd>) animates at the slow speeds and runs without animation at the fast ones. It stops at **breakpoints**: click the dot column next to an address.
- **Process queues** show every warrior's processes in turn order. The highlighted one runs next. Click an address to jump there.
- **Core map** shows all 8000 cells. Hover to read a cell, click to open it in the listing. The white frame is the part shown in the listing.
- **Recent steps** lists the last instructions of both warriors and what they did.
- **Edit the source** to change a warrior and load it again.

<!-- interactive element omitted in the Markdown version -->

Try:

- Load **Mice** and step through its copy loop at the **phase by phase** speed. Watch `<dest` move the pointer backwards before each copy.
- Load **Paper**, run it at 2 000 / s for a moment, then step back and find the line where the first copy starts running.
- Load **Scanner** against **Dwarf**, set a breakpoint on the `MOV.I trap, @ptr` line and see what the scanner found when it stops.

Source: https://klimek.link/posts/redcode/
