Files
2026-10-01 22:16:48 +02:00

63 KiB

H A L C Y O N   I N S T R U M E N T   &   C O N T R O L

Model HC-33
Flight Computer

Programmer's Reference Manual

Including the Ship Peripheral Interface

32-BIT  *  16 REGISTERS

35 INSTRUCTIONS  *  8 KB RAM

1 KB DAILY WORMHOLE LINK

Publication No. HIC-0033-A
First Edition

For use with command ships of the Halcyon Prospector class and compatible hulls.

RETAIN THIS MANUAL WITH THE SHIP RECORDS.
THE COMPUTER CANNOT BE REPROGRAMMED AFTER LAUNCH.
READ BEFORE YOU FLY.

NOTICE — The information in this manual is subject to change at the discretion of Halcyon Instrument & Control. Constants quoted as "standard" are the values set at the factory; belt operators may adjust them. Halcyon accepts no liability for ships lost to the Star, to the Belt, or to programmer error. The last of these is by far the most common. Halcyon and the Halcyon crescent are trademarks of Halcyon Instrument & Control. All other names are the property of their respective owners.

Contents

[TOC]

Chapter 1 — Introduction

1.1 What the HC-33 Is

The HC-33 is the flight computer fitted to every Halcyon command ship. It is a small, slow, utterly predictable 32-bit processor. It has no operating system, no clock interrupts and no operator. Once your ship leaves the dock the HC-33 is the only intelligence on board.

You cannot fly the ship. You can only tell the computer, in advance, how to fly the ship. The program is written by you, assembled on the ground into raw machine code, and sealed into the computer's program memory before launch. From that moment it is fixed for the life of the ship.

The computer talks to the outside world through two channels:

  • PERIPHERAL PORTS, which connect it to the engine, scanner, mining laser and the rest of the ship. (Chapter 5.)

  • THE WORMHOLE LINK, a message channel through which you may send the computer exactly one kilobyte per day and receive exactly one kilobyte per day. The link has no delay. The content is entirely up to you and your program. (Section 5.9.)

Because the link is so narrow, a good program is one that can run the ship for days on its own and needs only a few bytes of guidance from home.

1.2 Specifications

Word size ............................ 32 bits, two's complement
Registers ............................ 16 general purpose (r15 = stack ptr)
Instruction length ................... 4 bytes, fixed
Instruction set ...................... 35 instructions
Program memory (ROM) ................. 4096 bytes standard (1024 words)
Data memory (RAM) .................... 8192 bytes standard
Wormhole buffers ..................... 1024 bytes uplink, 1024 bytes downlink
Cycle budget ......................... 2000 cycles per turn, standard
Turns per day ........................ 1440 standard (one turn = 60 s)
Effective speed ...................... 33.3 cycles per second of ship time
Cycles per day ....................... 2,880,000
I/O .................................. IN and OUT to 16-bit port numbers
Byte order ........................... little-endian

Note: The program size, RAM size, cycle budget and turn rate are settings of the belt, not of the computer. Your belt operator can tell you the values in force. This manual quotes the standard values.

1.3 A Day in the Life of a Ship

Once every day the belt is run from start to finish. For your ship the day runs as follows:

  1. Any waiting uplink is placed in the computer's uplink buffer.
  2. The day is divided into turns. On each turn, the computer runs until it executes a YIELD or uses up its cycle budget.
  3. After the computer has stopped, the ship's physical world advances by one turn: the engine fires, the Star pulls, the ship moves, the mining laser works.
  4. After the last turn the contents of the downlink buffer are captured and made available to you.

At standard settings that is 1440 rounds of "think, then move". Between days nothing happens to your ship: it is frozen with its registers and memory intact.

1.4 Conventions Used in This Manual

ra, rb ......... any of the sixteen registers r0..r15
imm ............ a signed 16-bit immediate value, -32768 .. 32767
port ........... a port number, 0..32767 (all standard ports are below 256)
[rb+imm] ....... the RAM byte address obtained by adding imm to register rb
<- ............. "is assigned"
0x ............. prefix for hexadecimal numbers

Text in this manual marked NOTE is helpful. Text marked CAUTION describes something that can cost you a ship.

Chapter 2 — Architecture

The HC-33 is a HARVARD MACHINE: program and data live in separate memories. The program cannot be read or written by the program itself.

2.1 Registers

There are sixteen 32-bit registers, r0 through r15. They are interchangeable except for r15, which the CALL, RET, PUSH and POP instructions use as the STACK POINTER. The assembler accepts the name SP as a synonym for r15.

There is also a PROGRAM COUNTER, which holds the byte address of the next instruction. It cannot be read or written directly; it is changed only by jumps, branches, CALL and RET.

There are no condition flags. Comparison and branching are a single operation (BEQ, BNE, BLT, BGE), so no state is left behind.

At launch every register is zero, except r15, which holds the size of RAM (8192) so that the stack starts empty at the top of memory.

2.2 Program Memory

The program occupies up to 4096 bytes (1024 instructions) starting at byte address 0. Each instruction is four bytes, so a program is always a whole number of words. Program addresses are byte addresses and are always a multiple of four.

If execution runs off the end of the program the computer HALTS. This is not a fault.

2.3 Data Memory and the Memory Map

RAM is byte addressable from address 0 and is standard 8192 bytes. Words and half-words are stored least-significant byte first. No alignment is required. Any access outside RAM is a FAULT.

+-------------------------+ 8192
|                         |
|   STACK (grows down)    |   r15 starts here
|            |            |
|            v            |
|                         |
|   .  .  .  .  .  .  .  |
|                         |
|   GENERAL DATA          |
|   (about 6 KB)          |
+-------------------------+ 2048
|   DOWNLINK BUFFER  (TX) |
|   1024 bytes            |
+-------------------------+ 1024
|   UPLINK BUFFER    (RX) |
|   1024 bytes            |
+-------------------------+ 0

The two wormhole buffers are ordinary RAM. The link hardware writes the uplink into the bottom kilobyte before the first turn of the day and copies the second kilobyte out at the end of the day. Your program may read and write both buffers freely. The buffer boundaries are 0, 1024 and 2048 at standard settings.

RAM is not cleared between days, and there is no reset.

Caution: There is no memory protection. A runaway stack, or a store through a bad pointer, will happily overwrite your own buffers or data.

2.4 The Stack

The stack grows downward from the top of RAM. PUSH first subtracts four from r15 and then stores a word at the new address. POP loads the word at r15 and then adds four. CALL pushes the address of the instruction following it and jumps. RET pops an address and jumps to it.

Popping from an empty stack, or pushing past the bottom of RAM, is a fault. Nothing stops the stack from growing down into your data.

2.5 Execution, Turns and the Cycle Budget

Time on the HC-33 is measured in TURNS. On each turn the computer is given a CYCLE BUDGET, standard 2000 cycles, and runs until one of these happens:

  • the program executes YIELD;
  • the budget is used up;
  • the program HALTs or FAULTs.

Most instructions cost one cycle. MUL costs two. DIV and MOD cost eight. The budget is checked before each instruction, so the last instruction of a turn may overrun the budget by a few cycles.

WHEN THE BUDGET RUNS OUT THE COMPUTER IS NOT RESET. It is simply stopped where it was, and on the next turn it carries on from the very next instruction. A long calculation is therefore spread across as many turns as it needs. Meanwhile the ship goes on moving, which may or may not be what you want.

YIELD ends the computer's turn immediately and gives up the rest of the budget. The next turn begins with the instruction after the YIELD. A typical control program is a loop that reads sensors, decides, writes the controls, YIELDs, and jumps back to the top.

Caution: The ship's controls are LATCHED. Throttle, azimuth and pitch keep whatever value was last written to them until you write another. A ship whose computer has halted or faulted continues to burn at its last setting until it runs out of fuel.

2.6 Processor States

At any moment the computer is in one of four states:

RUNNING   Executing, or interrupted by the end of its budget.
YIELDED   Gave up the rest of the turn with YIELD.  Resumes next turn.
HALTED    Executed HALT or ran off the end of the program.  Permanent.
FAULTED   Executed an illegal instruction or made an illegal access.
          Permanent.

HALTED and FAULTED are final. The processor never runs again, its engine settings are frozen, and there is no way to restart it. Appendix D lists the fault conditions.

Chapter 3 — Instruction Set

3.1 Instruction Format

Every instruction is one 32-bit word:

 31                16 15    12 11     8 7               0
+--------------------+--------+--------+-----------------+
|       IMM16        |   RA   |   RB   |     OPCODE      |
+--------------------+--------+--------+-----------------+

OPCODE   bits 0-7     which instruction (Appendix A)
RB       bits 8-11    second register field
RA       bits 12-15   first register field
IMM16    bits 16-31   signed 16-bit immediate, sign-extended to 32 bits

The word is stored in program memory least-significant byte first, so the four bytes of an instruction appear in the file as:

byte 0 = opcode     byte 1 = (RA * 16) + RB     bytes 2-3 = IMM16, low first

Unused fields are zero. You will normally never build these words by hand; the assembler does it for you.

Jump and branch offsets are counted in INSTRUCTIONS, not bytes, and are relative to the instruction FOLLOWING the jump. An offset of zero therefore continues at the next instruction, and an offset of -1 jumps to the instruction just executed. The reach is 32K instructions either way, which is more than the whole program memory.

3.2 Summary of Instructions

CONTROL         NOP   YIELD   HALT   JMP   BEQ   BNE   BLT   BGE   CALL   RET
LOAD CONSTANT   LDI   LUI
REGISTER        MOV   ADD   SUB   MUL   DIV   MOD   AND   OR   XOR
                SHL   SHR   SAR   ADDI
STACK           PUSH  POP
MEMORY          LDB   LDH   LDW   STB   STH   STW
INPUT/OUTPUT    IN    OUT

3.3 Instruction Reference

All arithmetic is 32-bit two's complement and WRAPS on overflow. No instruction sets flags.

NOP — 1 cycle

No operation.

YIELD — 1 cycle

End this turn. Execution resumes with the next instruction on the next turn.

HALT — 1 cycle

Stop the computer permanently.

LDI ra, imm — 1 cycle

ra <- imm (sign-extended)

Loads a constant from -32768 to 32767.

LUI ra, imm — 1 cycle

ra <- (imm << 16) OR (ra AND 0xFFFF)

Replaces the upper half of ra and keeps the lower half. LDI followed by LUI builds any 32-bit constant; the assembler's LI does exactly this.

MOV ra, rb — 1 cycle

ra <- rb

ADD ra, rb — 1 cycle

ra <- ra + rb

SUB ra, rb — 1 cycle

ra <- ra - rb

MUL ra, rb — 2 cycles

ra <- ra * rb (low 32 bits of the product)

DIV ra, rb — 8 cycles

ra <- ra / rb (signed, truncated toward zero)

Dividing by zero is a FAULT. Dividing by -1 negates ra.

MOD ra, rb — 8 cycles

ra <- ra REM rb (signed; the sign of the result follows ra)

Modulus by zero is a FAULT. Modulus by -1 gives zero.

AND ra, rb — 1 cycle

OR ra, rb — 1 cycle

XOR ra, rb — 1 cycle

Bitwise operations: ra <- ra AND/OR/XOR rb.

SHL ra, rb — 1 cycle

SHR ra, rb — 1 cycle

SAR ra, rb — 1 cycle

Shift ra left (SHL), right logical with zero fill (SHR) or right arithmetic with sign fill (SAR). The shift count is the low five bits of rb, so only counts 0..31 are possible.

ADDI ra, imm — 1 cycle

ra <- ra + imm (imm sign-extended)

JMP imm — 1 cycle

PC <- next instruction + imm * 4

BEQ ra, rb, imm — 1 cycle

BNE ra, rb, imm — 1 cycle

BLT ra, rb, imm — 1 cycle

BGE ra, rb, imm — 1 cycle

If the condition holds, PC <- next instruction + imm * 4. Conditions: ra = rb, ra <> rb, ra < rb, ra >= rb. BLT and BGE compare as SIGNED numbers. In assembly source, imm is normally a label.

CALL imm — 1 cycle

Push the address of the next instruction, then jump as for JMP. Faults if the stack cannot be pushed.

RET — 1 cycle

Pop an address from the stack and jump to it. Faults on an empty stack.

PUSH ra — 1 cycle

r15 <- r15 - 4; memory word at [r15] <- ra

POP ra — 1 cycle

ra <- memory word at [r15]; r15 <- r15 + 4

LDB ra, [rb+imm] — 1 cycle

LDH ra, [rb+imm] — 1 cycle

LDW ra, [rb+imm] — 1 cycle

Load a byte, half-word (2 bytes) or word (4 bytes) from RAM address rb + imm. Bytes and half-words are ZERO-EXTENDED. Fault if any part of the access lies outside RAM.

STB ra, [rb+imm] — 1 cycle

STH ra, [rb+imm] — 1 cycle

STW ra, [rb+imm] — 1 cycle

Store the low byte, half-word or word of ra at RAM address rb + imm. Note that ra is the SOURCE. Fault if outside RAM.

IN ra, port — 1 cycle

ra <- the value of the peripheral port. Ports that do not exist read

as zero.

OUT port, ra — 1 cycle

Write ra to the peripheral port. Writes to ports that do not exist, or that are read-only, are ignored.

Note: In IN and OUT the port number occupies the immediate field. Port numbers should be kept below 32768.

3.4 Missing Instructions and how to Live Without Them

The HC-33 is a small machine. Everything below is done with what exists.

Negate ra ........... ldi r9, 0  /  sub r9, ra  /  mov ra, r9
Invert bits ......... ldi r9, -1  /  xor ra, r9
Zero a register ..... ldi ra, 0
Branch if ra > rb ... blt rb, ra, label
Branch if ra <= rb .. bge rb, ra, label
Branch if ra = 0 .... keep a zero in some register and use BEQ
Compare to constant . load the constant into a register first
Absolute value ...... ldi r9, 0 / bge ra, r9, skip / sub r9, ra / mov ra, r9
Unsigned compare .... not available; keep values below 2^31
Computed jump ....... not available; use a chain of compares

A register may be used for an unusual purpose provided you keep track of it. Conventional practice: r0 as a permanent zero for base addressing, r1-r7 as scratch, r8-r14 as saved values, r15 as the stack pointer. This is a habit, not a rule.

Chapter 4 — The Assembler

Programs are written in assembly language and converted to machine code by the assembler ASM. The output is the raw binary program that is uplinked to the ship (Chapter 6).

4.1 Source Format

One statement per line. A line may hold a label, an instruction, or both.

label:      mnemonic  operand, operand      ; comment
  • Case does not matter in mnemonics and register names. It DOES matter in labels and constant names.
  • Comments start with a semicolon (;) or a hash (#) and run to the end of the line.
  • Labels end with a colon and may stand alone on a line. A label names the position of the next instruction.
  • Operands are separated by commas.
  • Memory operands are written [rb], [rb+off] or [rb-off]. There must be no arithmetic beyond a single register and a single offset.
  • Registers are r0 to r15. SP is another name for r15.

Examples:

start:   ldi   r1, 100
         add   r1, r2
         beq   r1, r2, start
         ldw   r3, [r2+8]
         stb   r3, [sp-4]
         in    r4, 0x10
         out   0x20, r4

4.2 Directives and Pseudo-instructions

.EQU name value

Defines a constant. The name may then be used in place of a number anywhere a number is expected, including as a port number or a memory offset. A definition may appear anywhere, but its value may refer only to constants defined on earlier lines; in practice put all .EQU lines at the top.

LI rd, value

Load a full 32-bit constant. The assembler always generates TWO instructions (LDI then LUI) so that labels and branch distances are never surprised. The value must be a number or a constant name, not a label.

Labels and Immediates

Jump, branch and CALL instructions take a label. They also accept a plain number, which is then used unchanged as the instruction offset.

LDI, LUI and ADDI accept values from -32768 to 65535.

Caution: The immediate is stored in 16 bits and SIGN-EXTENDED by the machine. LDI r1, 65535 therefore loads -1, and ADDI r1, 40000 subtracts 25536. If you want a large positive value, use LI.

4.3 Numbers and Names

Numbers may be written in decimal (100, -7), hexadecimal (0x64) or binary (0b1100100). A number with a leading zero and no other prefix is read as OCTAL: 010 is eight, not ten. This has cost many programmers an afternoon.

There is no expression evaluation. Write 1028, not 1024+4.

4.4 Running the Assembler

asm  prog.s  >  prog.bin

reads the source file and writes the binary program to standard output. Errors are reported with the line number and the assembler stops at the first. The size of the file must be a multiple of four (it always is) and must not exceed the program memory of your belt (4096 bytes standard). The ground interface rejects programs that are too large.

Typical assembler messages:

line 12: unknown mnemonic "lod" line 15: bad register "r16" line 20: immediate 70000 out of 16-bit range (use li) line 31: bad number or unknown name "LOOP" line 40: offset 40000 out of range

Chapter 5 — Peripherals

5.1 The Port Interface

Everything the ship can sense or do is reached through PORTS. A port is a numbered 32-bit register outside the computer's memory, accessed with IN and OUT.

in   r1, 0x10        ; read port 0x10 (position X) into r1
out  0x20, r2        ; write r2 to port 0x20 (throttle)

Ports come in two kinds, and it matters which:

  • An INPUT port can be read. Writing to it has no effect.
  • An OUTPUT port can be written. READING AN OUTPUT PORT RETURNS ZERO, not the last value written. If you need to remember what you sent, keep a copy in a register or in RAM.

A port that does not exist reads as zero and ignores writes. No port operation ever faults. Port numbers are grouped by function in blocks of 16 (0x10), as listed below and collected in Appendix B.

There are no interrupts. The computer must poll.

5.2 Units and Conventions

Every port value is a signed 32-bit integer. There are no fractions.

Distances and positions ...... kilometres (km)
Velocities ................... metres per second (m/s)
Angles ....................... milliradians (1000 = 1 radian, 3142 = pi)
Mass ......................... kilograms (kg)
Time ......................... turns, and days
Money ........................ credits

Fractional readings are ROUNDED DOWN (toward minus infinity). A position of -0.4 km reads as -1; 0.9 km reads as 0. So position is known to no better than one kilometre and velocity to no better than one metre per second.

COORDINATES. The frame is fixed in space and centred on the Star. It is right-handed. The X and Y axes lie in the ECLIPTIC, the plane in which the Station orbits. The Z axis is perpendicular to it, positive "north".

AZIMUTH is the direction in the XY plane, measured from +X towards +Y. ELEVATION (called PITCH on the engine) is the angle above the XY plane, positive towards +Z.

Azimuth 0, pitch 0 ........ along +X
Azimuth 1571, pitch 0 ..... along +Y
Azimuth any, pitch 1571 ... along +Z

5.3 System Clock

0x00  TURN   input   Turn number within the current day, 0 upwards.
0x01  DAY    input   Day number.  The first day of the belt is day 0.
0x02  TURNS  input   Turns per day (standard 1440).

The ship does not have a wristwatch. These three ports are how a program knows when it is. Turn length is 86400 divided by TURNS seconds.

5.4 Navigation Unit

Reports the ship's position relative to the Star, and its velocity.

0x10  POSX   input   Position X, km
0x11  POSY   input   Position Y, km
0x12  POSZ   input   Position Z, km
0x13  VELX   input   Velocity X, m/s
0x14  VELY   input   Velocity Y, m/s
0x15  VELZ   input   Velocity Z, m/s

The belt lies between 1,500,000 and 3,000,000 km from the Star, so the positions fit comfortably in a word. Velocity is the ship's velocity in the fixed frame, not relative to anything else.

5.5 Main Engine

The engine produces thrust along a direction chosen by two angles, at a power chosen by the throttle.

0x20  THROTTLE  output  Engine power, 0 to 1000 (permille of full thrust).
                        Values above 1000 act as 1000; zero or negative
                        switches the engine off.
0x21  AZIMUTH   output  Thrust direction azimuth, milliradians.
0x22  PITCH     output  Thrust direction elevation, milliradians.
0x23  FUEL      input   Fuel remaining, kg.
0x24  MASS      input   Total ship mass (hull + fuel + containers in tow), kg.

THE ENGINE FIRES ALONG THE DIRECTION GIVEN, for the whole of the turn, at the throttle in effect when the computer stopped. Direction is:

( cos(pitch) cos(azimuth),  cos(pitch) sin(azimuth),  sin(pitch) )

The three controls are latched, as described in section 2.5. Set them once and the ship keeps burning. Set THROTTLE to zero to coast.

Thrust and fuel. For a Prospector at standard turn length:

Full thrust ................ 6000 newtons
Exhaust velocity ........... 30,000 m/s
Fuel used at full throttle . 12 kg per turn  (thrust x turn / exhaust vel.)
Acceleration ............... thrust / mass: 0.75 m/s^2 with an empty tank
                             and nothing in tow, less with containers

Fuel use is proportional to throttle. When fuel runs out the engine falls silent; the throttle setting is remembered but has no effect. If the tank has less fuel than a full turn needs, the engine delivers a proportionally shortened burn.

Caution: Fuel is your ship's only means of changing course. There is no way to refuel. See section 7.3 before designing a manoeuvre.

5.6 Scanner

The scanner tracks one asteroid at a time, which you choose by number. Asteroids are numbered from 1. The standard belt has 500. The scanner has a range of 500,000 km: an asteroid farther away than that cannot be seen.

0x30  SELECT   output  Asteroid number to track.  Zero, or a number that
                       does not exist, clears the selection.
0x31  NEAREST  input   Number of the asteroid nearest to the ship, or 0
                       if none is within 500,000 km.

The following ports describe the TRACKED asteroid and all read zero if none is tracked, or if it is more than 500,000 km away.

0x32  RELX     input   Position of the target relative to the ship, X, km
0x33  RELY     input   ... Y, km
0x34  RELZ     input   ... Z, km
0x35  RELVX    input   Velocity of the target relative to the ship, X, m/s
0x36  RELVY    input   ... Y, m/s
0x37  RELVZ    input   ... Z, m/s
0x38  DIST     input   Straight-line distance to the target, km
0x40  ORE0     input   Iron remaining in the target, kg
0x41  ORE1     input   Nickel remaining, kg
0x42  ORE2     input   Ice remaining, kg
0x43  ORE3     input   Platinum remaining, kg
(0x44-0x47 exist for future ores and read zero.)

Relative values are TARGET MINUS SHIP: RELX is positive if the target is on the +X side of you. To fly towards the target, point the engine along (RELX, RELY, RELZ). To match its velocity, apply a thrust along (RELVX, RELVY, RELVZ).

NEAREST is decided among the asteroids within scanner range by true three-dimensional distance, and reads zero if there are none; if two are exactly equally near, the lower number wins.

Note: Every asteroid in the belt moves at the same speed, 3 km/s (section 7.2). For a ship travelling at that speed, the velocity of a target relative to the ship is therefore decided by the difference in DIRECTION of travel, not by any difference in speed.

5.7 Mining Laser and Containers

A ship has no hold. Ore travels in CONTAINERS, which the ship TOWS. A container weighs 500 kg empty and holds 2000 kg of ore. Containers belong to no one: any ship can tow any container. A container is always in one of two conditions:

  • IN TOW behind a ship: it moves exactly as the ship moves.
  • ADRIFT: it moves on its own, pulled by the Star like anything else (section 7.2). A container let go with the speed of a ship in orbit stays in orbit beside it. One that loses its speed falls inward, and is destroyed with its ore if it comes within 200,000 km of the Star. A container that stays adrift for TEN DAYS disappears, with whatever is in it, so containers that are lost cannot pile up. While a container is in tow its days do not count.
0x50  MINE      output  Non-zero: mine the tracked asteroid.  Zero: stop.
0x51  CONTS     input   Number of containers in tow.
0x52  CONTKG    input   Ore in the containers in tow, kg.
0x53  CONTROOM  input   Room left in the containers in tow, kg.
0x54  CONTMASS  input   Mass of the containers in tow, ore included, kg.
0x55  ATTACH    output  Non-zero: take the containers near the ship in tow.
0x56  DETACH    output  Non-zero: let go of every container in tow.
0x57  NEARBY    input   How many drifting containers ATTACH would take.
0x58  CONTORE0  input   Iron in the containers in tow, kg
0x59  CONTORE1  input   Nickel in the containers in tow, kg
0x5A  CONTORE2  input   Ice in the containers in tow, kg
0x5B  CONTORE3  input   Platinum in the containers in tow, kg
(0x5C-0x5F exist for future ores and read zero.)

MINING. The laser stays on, once MINE has been set, until MINE is set to zero. In each turn in which ALL of the following are true, it moves ore from the asteroid into the containers in tow:

  • an asteroid is tracked and still has ore;
  • the asteroid is within 5 km of the ship;
  • the ship's velocity relative to the asteroid is at most 100 m/s;
  • at least one container in tow has room.

The Prospector mines 10 kg per turn. The ore taken is a mixture in the same proportions as the asteroid's remaining ore. You cannot choose what to mine. It goes into the containers in the order they were made, each filled before the next. The conditions are tested at the END of the turn, after the ship has moved. With nothing in tow, or every container full, the laser does nothing.

One container takes 200 turns, a little over three hours of ship time, to fill.

ATTACH. Writing a non-zero value to ATTACH takes in tow every container that is adrift and near the ship: within 10 km, and moving at most 100 m/s relative to it. It makes no difference who ordered a container or whose ship last towed it. A container that another ship is towing is left alone. Attached containers move at once to the ship. Reading NEARBY beforehand says how many ATTACH would take.

DETACH. Writing a non-zero value to DETACH lets go of every container in tow. Each carries on drifting with the velocity the ship had at that moment, and its ten days start from then.

MASS. Everything in tow counts towards the ship's mass, empty containers as well as the ore in them, and the engine's thrust does not change. Acceleration therefore falls as the tow grows: see section 7.1. MASS (section 5.5) reports the total.

Ore is worth nothing until it reaches the Station (section 5.8). An asteroid does not replenish.

Note: The scanner reports whole kilometres (rounded down). The range to mine is 5 km. Aim for the middle of the range; do not try to close to the last kilometre.

5.8 Dropoff Station and Market

The Station is the belt's only dropoff point. It sits on a circular orbit in the ecliptic, half way through the belt, at a radius of 2,250,000 km. Your ship is launched from it.

0x60  STNX    input   Position of the Station relative to the ship, X, km
0x61  STNY    input   ... Y, km
0x62  STNZ    input   ... Z, km
0x63  STNVX   input   Velocity of the Station relative to the ship, X, m/s
0x64  STNVY   input   ... Y, m/s
0x65  STNVZ   input   ... Z, m/s
0x66  ORDER   output  1 to 10: the Station delivers that many empty containers.
0x67  EARNED  input   Credits earned by this ship so far

As with the scanner, relative values are STATION MINUS SHIP.

SELLING IS AUTOMATIC. At the start of every turn the Station buys every container that is ADRIFT within 20 km of it and has ore in it, and pays for the ore at the day's prices. THE STATION TAKES THE CONTAINER WITH THE ORE: a sold container disappears. Empty containers are not bought. Containers in tow are never touched: to sell, detach near the Station.

The credits go to the player whose ship last let go of the container, and to EARNED of that ship. Containers have no owner, so ore left adrift belongs to whoever brings it to the Station first.

ORDERING CONTAINERS. When the ship is within 20 km of the Station, writing a number from 1 to 10 to ORDER has the Station deliver that many EMPTY containers to the ship: they appear at the ship's position, adrift with the ship's own velocity, ready for ATTACH. Larger numbers act as 10; zero or less does nothing. The Station will not deliver more once 50 containers that you ordered still exist. A sale takes containers away, and so does the ten-day rule (section 5.7), so containers you lose never leave you stuck. Away from the Station ORDER does nothing, and there is no error signal. Containers are free.

A round trip is therefore: order containers, attach them, fly to an asteroid, mine until they are full, fly back, detach near the Station (which takes the containers and pays for the ore), and order fresh ones for the next trip.

PRICES. Each ore has a standard price per kilogram. The price FALLS as ore floods the market and recovers as it is used up. Prices are set once per day and do not change during the day, so it does not matter when in the day you sell.

ore        number    standard price       price is halved at
                     (credits per kg)     supply of (kg)
----------------------------------------------------------------
iron          0             2                  400,000
nickel        1             6                  200,000
ice           2             3                  300,000
platinum      3           300                    5,000

price = standard price x half-point / (half-point + supply)

"Supply" is a running total of the ore sold by everyone. At the end of each day today's sales are added to it and 10 percent of the old total is forgotten. A price never falls below one credit. Current prices are available from the ground interface (section 6.3). Your program cannot read them: it must be told, by uplink, if it should care.

The link is a pair of one-kilobyte buffers in RAM and two ports.

0x70  UPNEW   input   1 if an uplink arrived for today and has not been
                      acknowledged, else 0.
      UPNEW   output  Any value: acknowledge (clear the flag).
0x71  UPLEN   input   Length of today's uplink in bytes, 0 to 1024.

UPLINK. Before turn 0 of the day, the uplink is copied to RAM addresses 0 to UPLEN-1. Bytes beyond the end of the message are left as they were. UPNEW is set and stays set until acknowledged or until the day ends. An uplink is meant for the day on which it arrives; the flag is cleared at the end of every day whether or not you noticed.

If you send more than one uplink in a day, only the last is delivered.

DOWNLINK. At the end of the last turn of the day the ENTIRE transmit buffer, RAM addresses 1024 to 2047, is captured and made available to you. It is always exactly 1024 bytes. Whatever is in it is sent; the link does not care whether it was written today.

The wormhole has no delay and is not affected by distance. It is affected by size: the buffers are all you have. The format of the data is entirely your own invention. The link does not check it, compress it, or understand it.

Note: A ship that is destroyed sends no more downlinks. Its last message remains on file. A ship that has merely halted still sends its buffer, unchanged, every day.

5.10 Math Coprocessor

The HC-33 cannot take a square root or an arctangent. The coprocessor can, at no cost in cycles. Write the operands, then read the answer.

0x80  MATHX      output  Operand x
0x81  MATHY      output  Operand y
0x82  MATHZ      output  Operand z
0x83  ATAN2      input   atan2(y, x), in milliradians (-3142 to 3141)
0x84  HYPOT      input   sqrt(x*x + y*y)
0x85  NORM3      input   sqrt(x*x + y*y + z*z)

Operands are whole numbers, and results are rounded down. The internal arithmetic is wide enough that squaring even large operands cannot overflow, so you may feed it positions in kilometres directly. ATAN2 of (0, 0) is zero.

To find the direction from the ship to a target (dx, dy, dz):

azimuth = ATAN2 with x = dx, y = dy
range   = HYPOT with x = dx, y = dy
pitch   = ATAN2 with x = range, y = dz

Sample program 3 (Chapter 9) does exactly this.

Chapter 6 — Operations

6.1 Life Cycle of a Ship

A ship is always in one of five conditions.

INVENTORY   Built and waiting on the dock.  It can be launched.
LAUNCHING   Cleared to launch.  It will enter the belt on the next daily run.
            Its program is sealed and can no longer be changed.
ACTIVE      In the belt.
SCRAPPING   Ordered to be scrapped.  It is removed on the next daily run.
DESTROYED   Lost.  It cannot be recovered.

On registration each player is issued one command ship, in INVENTORY, and sixteen CODE SLOTS. Slots 1 to 3 hold the example programs of Chapter 9 and are read-only. Slots 4 to 16 are yours: each holds the source text of one program and a name of your choosing. Slots are kept on the belt operator's computer, so they follow you from one terminal to the next.

  1. Write a program and save it in one of your slots. Assemble it as often as you like to check it. Keep as many versions as you have slots.
  2. Launch the ship and CHOOSE THE SLOT it will fly. The slot is assembled at that moment; if it does not assemble, or is too large, or is empty, the ship is not launched. Otherwise the assembled program is sealed into the ship. There is no going back.
  3. On the next daily run the ship is placed at the Station, moving with the Station, with full tanks and a zeroed computer, and the program starts.

Later changes to a slot do not affect a ship that has already launched from it: the ship carries its own sealed copy.

A launched ship can be sent an uplink, and you can collect its downlink, but that is all. You cannot alter the program, recall the ship, or restart it.

A ship is destroyed if it comes within 200,000 km of the Star.

6.2 The Daily Run

The belt is run once per day, in a single pass over every ship. The run is DETERMINISTIC: the same belt, the same programs and the same uplinks always produce the same day, bit for bit. There is no luck in it.

Order of events within the run:

  1. Ships waiting to launch are placed at the Station. Ships being scrapped are removed; any containers they tow are left adrift, and each owner is given a new ship, in INVENTORY, with no program.
  2. Uplinks are delivered to their ships.
  3. For each turn of the day, for each ship in order of ship number: a. the computer runs until it yields or exhausts its budget; b. the engine fires and the Star pulls: velocity, then position, are updated; c. the mining laser, if on, works.
  4. Downlinks are captured, and the market is updated for tomorrow.

Ships do not collide with one another or with asteroids. They cannot see each other. Each ship's sales, however, feed the same market as everybody else's.

6.3 Ground Interface

You reach your ship over the HTTP interface of the belt operator. Every request except registration and the market carries your API key:

Authorization: Bearer <your key>

POST  /register                   {"name": "yourname"}
      Create a player and its command ship.  The reply gives the player
      number, the API KEY (shown once only: keep it) and the ship number.

GET   /me                         Your name, your credits, the current day.

GET   /market                     Current ore prices, in the order iron,
                                  nickel, ice, platinum.  No key needed.

GET   /ships                      Your ships: number, condition, program size
                                  in bytes, and day of the latest downlink.

PUT   /ships/{n}/program          Body: an assembled program, raw bytes, for
      programs built outside the slots (for example with asm).  Allowed only
      while the ship is in INVENTORY.  Between 4 and 4096 bytes, a multiple
      of four.

POST  /ships/{n}/launch           Launch the ship on the next run.  The ship
      must be in INVENTORY.  Body {"slot": 1..16}: assemble that code slot,
      seal it into the ship and launch it, in one step (400 with the
      assembler's message if it is empty or does not assemble).  With no
      body, the ship launches with the program already uploaded to it.

GET   /slots                      Your sixteen code slots: number, name, and
                                  whether each is an example or empty.

GET   /slots/{n}                  One slot with its source text.

PUT   /slots/{n}                  Body {"name": "...", "source": "..."}.  Save
                                  source in slot 4 to 16 (403 for the read-only
                                  examples in slots 1 to 3).

DELETE /slots/{n}                 Empty slot 4 to 16.

PUT   /ships/{n}/uplink           Body: up to 1024 raw bytes.  Replaces any
      message queued for the next run.  Allowed while LAUNCHING or ACTIVE.

POST  /ships/{n}/scrap            Scrap a ship that is ACTIVE (409 otherwise).
      On the next run the ship is removed from the belt and you receive a
      new ship in INVENTORY.  Its program and fuel are lost.

GET   /ships/{n}/downlink         The latest downlink, exactly 1024 raw
      bytes.  The header X-Downlink-Day tells you which day's run
      produced it.  A ship's first downlink appears after its first day.
      With ?day=D you get the downlink of that earlier day instead (404
      if there is none).

GET   /ships/{n}/downlinks        {"days":[0,1,2,...]}: the days that have a
      stored downlink, oldest first.  Every day's downlink is kept.

Typical use:

# save source in slot 4, then launch ship 1 flying it
curl -X PUT -H "Authorization: Bearer $KEY" \
     -d '{"name":"MINER","source":"..."}'  http://belt.example/slots/4
curl -X POST -H "Authorization: Bearer $KEY" \
     -d '{"slot":4}'  http://belt.example/ships/1/launch

An uplink queued today is delivered at the START of the next run and is the day's message; the downlink you collect afterwards was written during that run. In steady state you therefore exchange one kilobyte in each direction per day, as the name of the link says.

Errors are reported in the usual way: 401 for a missing or wrong key, 404 for a ship that is not yours, 409 when the ship is in the wrong condition for the request, 413 when your data is too large, 400 for malformed data.

Chapter 7 — The Ship and Its Environment

7.1 The Prospector Hull

Dry mass ............................. 8000 kg
Fuel tank ............................ 4000 kg
Cargo hold ........................... none: ore travels in containers
Container, empty ..................... 500 kg  (holds 2000 kg of ore)
Container, full ...................... 2500 kg
Total mass, full tank, nothing in tow  12,000 kg
Total mass, empty tank, nothing in tow  8,000 kg
Engine ............................... 6000 N, exhaust velocity 30 km/s
Mining laser ......................... 10 kg per turn

Acceleration is thrust divided by the total mass, containers in tow included:

full tank, nothing in tow ............ 6000 / 12,000  = 0.50 m/s^2
full tank, 3 full containers ......... 6000 / 19,500  = 0.31 m/s^2
empty tank, nothing in tow ........... 6000 /  8,000  = 0.75 m/s^2

The ship is a point. It has no orientation of its own; the engine simply pushes in whatever direction the two angles command. There are no thrusters, no spin, no fuel used to rotate.

7.2 Space, Orbits and the Star

The Star sits at the origin and pulls on everything with an acceleration

a  =  v^2 / r

directed towards it, where r is the distance from the Star and v is a constant, the ORBIT SPEED, standard 3 km/s. (In a real solar system the pull falls with the square of the distance. In the belt it falls only with the distance. Ask a cosmologist.)

The remarkable consequence is that a body on a circular orbit at ANY radius travels at exactly the same speed, v. Every asteroid, the Station, and any ship that has matched their motion, all travel at 3 km/s. What differs is the time taken to go round:

radius (km)                            period of one orbit
------------------------------------------------------
1,500,000    (inner edge of belt)       36.4 days
2,250,000    (the Station)              54.5 days
3,000,000    (outer edge of belt)       72.7 days

Asteroids travel on circles, in slightly different planes. Each orbit is tilted from the ecliptic by up to about 0.2 radian (11 degrees), most of them by a good deal less, so the belt is a thick disc with the Station in the middle. At the outer edge an asteroid may lie as much as 600,000 km above or below the ecliptic. Asteroids are not disturbed by anything you do; they follow their circles for ever.

A ship in free flight has a great deal of velocity and very little spare acceleration. At the Station's radius the Star pulls at about 4 millimetres per second squared; your engine, at 0.33 to 0.75 m/s^2, is around a hundred times stronger. The engine is the master, but the Star never relents, and a ship left alone drifts from its orbit at once if its velocity differs from 3 km/s. A ship at 3 km/s, moving tangentially, stays on its circle for ever and needs no fuel to do it.

Caution: A ship that comes within 200,000 km of the Star is destroyed. A ship that is too slow at the wrong radius falls inward and will not stop until it hits this limit.

7.3 Fuel and Delta-v

The total change of velocity available from one tank is given by

dv  =  exhaust velocity  x  ln( mass before / mass after )

For a Prospector with nothing in tow and a full tank:

30 km/s  x  ln( 12000 / 8000 )   =   about 12.2 km/s

That is roughly four times the orbit speed. Nothing is ever free: every metre per second gained going out must be paid again to slow down, and every kilogram of ore towed home, and every empty container towed out for it, makes the ship harder to reverse. The engine at full power uses the whole tank in 333 turns, a little over five hours of ship time, and yet the day is 24. Plan accordingly.

A rendezvous takes two burns: one to intercept, and one to match velocity. A program that only does the first will arrive, at speed, and pass on. See the comments in sample program 3.

Chapter 8 — Programming Notes

  1. THE BUDGET IS A BUDGET. At standard settings a turn allows 2000 cycles. A loop that copies the full kilobyte uplink a byte at a time uses over 5000, and needs three turns. That is fine, as long as the rest of the program can cope with the ship moving on meanwhile. If a control loop matters, keep it short and let the slow work run between calls.

  2. ALWAYS YIELD. A program with no YIELD uses its whole budget every turn, all day. Its main loop will read the sensors dozens of times per turn and see the same numbers each time, since the world does not move until the computer stops. Finish your work, YIELD, and start again next turn.

  3. 32 BITS IS NOT MANY. Positions of two million kilometres times a velocity of a few thousand metres per second overflows a word at once. MUL wraps silently. Scale before you multiply, or divide first.

  4. THE PORTS ROUND DOWN. The error is up to one kilometre and one metre per second on every reading. Differences of nearby readings are meaningless. Distance, sampled over a few turns, is a much better guide to closing speed than the RELV ports on a slow approach.

  5. PORTS ARE NOT MEMORY. Output ports cannot be read back. Keep a copy of every control value you might need.

  6. THE WORLD ONLY MOVES BETWEEN TURNS. Whatever you write to the engine takes effect when the computer stops for the turn and stays in force until you write something else. Do not expect any reaction in the readings until your next YIELD.

  7. DEFEND AGAINST FAULTS. A faulted computer is dead, and the engine remains latched at its last throttle. Check array bounds. Never divide by a value that might be zero. Never POP more than you PUSHed.

  8. DO NOT WASTE THE UPLINK. A kilobyte a day is 1024 bytes. A program can use it to change a target number, a threshold, or a mode. It cannot carry the whole belt. Design the ship so that most days need no uplink at all.

  9. TEST ON THE GROUND. The belt is deterministic. A program that misbehaves once will misbehave in exactly the same way every time, so a trial run of the belt on the same seed will find the fault. Do this before you launch.

  10. AN IDLE SHIP IS A SAFE SHIP. A program that does nothing at all keeps the ship on its launch orbit for ever. You can only do worse.

Chapter 9 — Sample Programs

The three programs below are complete. Each has been assembled and run. Program sizes are those of the assembled binary.

Program 1: Echo (52 bytes)

Sends back whatever you send. A useful first test of the link: uplink a message, wait for the next run, and read the same message in the downlink.

Notice how the copy loop uses the UPLEN port to stop at the length of the message, and how the acknowledge (OUT to UPNEW) comes last, so that the flag stays set for as long as the copy is unfinished. A full kilobyte takes three turns to copy at standard settings; the computer simply carries on where it left off (section 2.5).

; ECHO -- copy each day's uplink into the downlink buffer.
;
        .equ    RX      0               ; uplink buffer
        .equ    TX      1024            ; downlink buffer
        .equ    P_UPNEW 0x70            ; uplink-arrived flag / acknowledge
        .equ    P_UPLEN 0x71            ; uplink length in bytes

wait:   in      r1, P_UPNEW
        ldi     r2, 0
        beq     r1, r2, sleep           ; nothing new today
        in      r4, P_UPLEN
        ldi     r5, 0                   ; r5 = byte index
copy:   bge     r5, r4, done
        ldb     r6, [r5+RX]
        stb     r6, [r5+TX]
        addi    r5, 1
        jmp     copy
done:   out     P_UPNEW, r1             ; acknowledge
sleep:  yield
        jmp     wait

Program 2: Telemetry (52 bytes)

Reports turn number, fuel, and position to home. The five words appear in the downlink at byte offsets 0, 4, 8, 12 and 16, least-significant byte first. Because it overwrites them every turn, what you receive is the ship's state as sampled at the start of the last turn of the day.

; TELEMETRY -- every turn, write turn number, fuel and position to the
; downlink buffer as five 32-bit words.
;
        .equ    P_TURN  0x00
        .equ    P_POSX  0x10
        .equ    P_POSY  0x11
        .equ    P_POSZ  0x12
        .equ    P_FUEL  0x23
        .equ    T_TURN  1024            ; TX + 0
        .equ    T_FUEL  1028            ; TX + 4
        .equ    T_X     1032            ; TX + 8
        .equ    T_Y     1036            ; TX + 12
        .equ    T_Z     1040            ; TX + 16

        ldi     r0, 0                   ; r0 = 0, the base register
loop:   in      r1, P_TURN
        stw     r1, [r0+T_TURN]
        in      r1, P_FUEL
        stw     r1, [r0+T_FUEL]
        in      r1, P_POSX
        stw     r1, [r0+T_X]
        in      r1, P_POSY
        stw     r1, [r0+T_Y]
        in      r1, P_POSZ
        stw     r1, [r0+T_Z]
        yield
        jmp     loop

Program 3: Pursue (72 bytes)

Selects the nearest asteroid, points the engine at it, and burns at full throttle. The bearing is recomputed every turn with the math coprocessor.

This program is a beginning, not an end. It will reach its target and fly straight past it at several kilometres per second, and it will burn its whole tank in about five hours doing so. A working program brakes: it must compare its velocity with the target's (RELVX, RELVY, RELVZ), point the engine along the difference, and throttle back as the distance closes. It must also watch its fuel. That is left as an exercise.

; PURSUE -- point the engine at the nearest asteroid and burn.
; Crude: it makes no attempt to match velocity, so it will fly straight past.
;
        .equ    P_THROTTLE      0x20
        .equ    P_AZIMUTH       0x21
        .equ    P_PITCH         0x22
        .equ    P_SELECT        0x30
        .equ    P_NEAREST       0x31
        .equ    P_RELX          0x32
        .equ    P_RELY          0x33
        .equ    P_RELZ          0x34
        .equ    P_MATHX         0x80
        .equ    P_MATHY         0x81
        .equ    P_ATAN2         0x83
        .equ    P_HYPOT         0x84

        in      r1, P_NEAREST           ; id of the nearest asteroid
        out     P_SELECT, r1            ; track it
        ldi     r7, 1000
        out     P_THROTTLE, r7          ; full power

aim:    in      r1, P_RELX              ; where is it?
        in      r2, P_RELY
        in      r3, P_RELZ
        out     P_MATHX, r1
        out     P_MATHY, r2
        in      r4, P_ATAN2             ; azimuth = atan2(dy, dx)
        out     P_AZIMUTH, r4
        in      r5, P_HYPOT             ; horizontal range = hypot(dx, dy)
        out     P_MATHX, r5
        out     P_MATHY, r3
        in      r6, P_ATAN2             ; elevation = atan2(dz, range)
        out     P_PITCH, r6
        yield
        jmp     aim

Appendix A — Opcode Table

hex  mnemonic  operands              cycles   operation
---  --------  --------------------  ------   -------------------------------
00   NOP                                1      no operation
01   YIELD                              1      end this turn
02   HALT                               1      stop permanently
03   LDI       ra, imm                  1      ra <- sign-extended imm
04   LUI       ra, imm                  1      ra <- imm<<16 | (ra & 0xFFFF)
05   MOV       ra, rb                   1      ra <- rb
06   ADD       ra, rb                   1      ra <- ra + rb
07   SUB       ra, rb                   1      ra <- ra - rb
08   MUL       ra, rb                   2      ra <- ra * rb
09   DIV       ra, rb                   8      ra <- ra / rb   (fault if 0)
0A   MOD       ra, rb                   8      ra <- ra rem rb (fault if 0)
0B   AND       ra, rb                   1      ra <- ra & rb
0C   OR        ra, rb                   1      ra <- ra | rb
0D   XOR       ra, rb                   1      ra <- ra ^ rb
0E   SHL       ra, rb                   1      ra <- ra << (rb & 31)
0F   SHR       ra, rb                   1      ra <- ra >> (rb & 31), logical
10   SAR       ra, rb                   1      ra <- ra >> (rb & 31), signed
11   ADDI      ra, imm                  1      ra <- ra + imm
12   JMP       imm                      1      pc <- next + imm*4
13   BEQ       ra, rb, imm              1      if ra = rb  branch
14   BNE       ra, rb, imm              1      if ra <> rb branch
15   BLT       ra, rb, imm              1      if ra < rb  branch (signed)
16   BGE       ra, rb, imm              1      if ra >= rb branch (signed)
17   CALL      imm                      1      push next; jump
18   RET                                1      pop pc
19   PUSH      ra                       1      sp -= 4; [sp] <- ra
1A   POP       ra                       1      ra <- [sp]; sp += 4
1B   LDB       ra, [rb+imm]             1      ra <- byte, zero-extended
1C   LDH       ra, [rb+imm]             1      ra <- half-word, zero-extended
1D   LDW       ra, [rb+imm]             1      ra <- word
1E   STB       ra, [rb+imm]             1      byte <- ra
1F   STH       ra, [rb+imm]             1      half-word <- ra
20   STW       ra, [rb+imm]             1      word <- ra
21   IN        ra, port                 1      ra <- port
22   OUT       port, ra                 1      port <- ra

Any opcode of 23 hex or above is illegal and faults the computer.

Pseudo-instruction (assembler only):
     LI        rd, value                2      LDI rd, low16 ; LUI rd, high16

Appendix B — Port Map

port  name       dir  description                                     units
----  ---------  ---  ----------------------------------------------  -----
SYSTEM
0x00  TURN       in   turn within the day                             turns
0x01  DAY        in   day number                                      days
0x02  TURNS      in   turns per day                                   turns

NAVIGATION
0x10  POSX       in   position X (Star at origin)                     km
0x11  POSY       in   position Y                                      km
0x12  POSZ       in   position Z                                      km
0x13  VELX       in   velocity X                                      m/s
0x14  VELY       in   velocity Y                                      m/s
0x15  VELZ       in   velocity Z                                      m/s

ENGINE
0x20  THROTTLE   out  0..1000, latched                                permille
0x21  AZIMUTH    out  thrust direction, latched                       mrad
0x22  PITCH      out  thrust elevation, latched                       mrad
0x23  FUEL       in   fuel remaining                                  kg
0x24  MASS       in   total mass                                      kg

SCANNER
0x30  SELECT     out  asteroid to track (0 = none)
0x31  NEAREST    in   number of nearest asteroid
0x32  RELX       in   target minus ship, X                            km
0x33  RELY       in   target minus ship, Y                            km
0x34  RELZ       in   target minus ship, Z                            km
0x35  RELVX      in   target velocity minus ship, X                   m/s
0x36  RELVY      in   ... Y                                           m/s
0x37  RELVZ      in   ... Z                                           m/s
0x38  DIST       in   distance to target                              km
0x40  ORE0       in   iron in target                                  kg
0x41  ORE1       in   nickel in target                                kg
0x42  ORE2       in   ice in target                                   kg
0x43  ORE3       in   platinum in target                              kg

MINING AND CONTAINERS
0x50  MINE      out  non-zero = laser on, latched
0x51  CONTS     in   containers in tow
0x52  CONTKG    in   ore in the containers in tow                        kg
0x53  CONTROOM  in   room left in the containers in tow                  kg
0x54  CONTMASS  in   mass of the containers in tow                       kg
0x55  ATTACH    out  non-zero = tow the containers nearby
0x56  DETACH    out  non-zero = let go of everything in tow
0x57  NEARBY    in   drifting containers ATTACH would take
0x58  CONTORE0  in   iron in tow                                         kg
0x59  CONTORE1  in   nickel in tow                                       kg
0x5A  CONTORE2  in   ice in tow                                          kg
0x5B  CONTORE3  in   platinum in tow                                     kg

STATION
0x60  STNX       in   station minus ship, X                           km
0x61  STNY       in   ... Y                                           km
0x62  STNZ       in   ... Z                                           km
0x63  STNVX      in   station velocity minus ship, X                  m/s
0x64  STNVY      in   ... Y                                           m/s
0x65  STNVZ      in   ... Z                                           m/s
0x66  ORDER      out  1 to 10 = station delivers empty containers
0x67  EARNED     in   credits earned by this ship

WORMHOLE LINK
0x70  UPNEW      i/o  in: uplink pending;  out: acknowledge
0x71  UPLEN      in   uplink length                                   bytes

MATH COPROCESSOR
0x80  MATHX      out  operand x
0x81  MATHY      out  operand y
0x82  MATHZ      out  operand z
0x83  ATAN2      in   atan2(y, x)                                     mrad
0x84  HYPOT      in   sqrt(x^2 + y^2)
0x85  NORM3      in   sqrt(x^2 + y^2 + z^2)

All other ports read zero and ignore writes.

Appendix C — Standard Equate File

Paste this at the top of any program. Unused equates cost nothing.

; PORTS -- standard equate file for the HC-33 (manual, Appendix C).
; Paste at the top of a program; unused equates cost nothing.
;
        .equ    RX              0               ; uplink buffer
        .equ    TX              1024            ; downlink buffer
        .equ    RAMTOP          8192            ; initial stack pointer

        .equ    P_TURN           0x00
        .equ    P_DAY            0x01
        .equ    P_TURNS          0x02
        .equ    P_POSX           0x10
        .equ    P_POSY           0x11
        .equ    P_POSZ           0x12
        .equ    P_VELX           0x13
        .equ    P_VELY           0x14
        .equ    P_VELZ           0x15
        .equ    P_THROTTLE       0x20
        .equ    P_AZIMUTH        0x21
        .equ    P_PITCH          0x22
        .equ    P_FUEL           0x23
        .equ    P_MASS           0x24
        .equ    P_SELECT         0x30
        .equ    P_NEAREST        0x31
        .equ    P_RELX           0x32
        .equ    P_RELY           0x33
        .equ    P_RELZ           0x34
        .equ    P_RELVX          0x35
        .equ    P_RELVY          0x36
        .equ    P_RELVZ          0x37
        .equ    P_DIST           0x38
        .equ    P_ORE0           0x40
        .equ    P_ORE1           0x41
        .equ    P_ORE2           0x42
        .equ    P_ORE3           0x43
        .equ    P_MINE           0x50
        .equ    P_CONTS          0x51
        .equ    P_CONTKG         0x52
        .equ    P_CONTROOM       0x53
        .equ    P_CONTMASS       0x54
        .equ    P_ATTACH         0x55
        .equ    P_DETACH         0x56
        .equ    P_NEARBY         0x57
        .equ    P_CONTORE0       0x58
        .equ    P_CONTORE1       0x59
        .equ    P_CONTORE2       0x5A
        .equ    P_CONTORE3       0x5B
        .equ    P_STNX           0x60
        .equ    P_STNY           0x61
        .equ    P_STNZ           0x62
        .equ    P_STNVX          0x63
        .equ    P_STNVY          0x64
        .equ    P_STNVZ          0x65
        .equ    P_ORDER          0x66
        .equ    P_EARNED         0x67
        .equ    P_UPNEW          0x70
        .equ    P_UPLEN          0x71
        .equ    P_MATHX          0x80
        .equ    P_MATHY          0x81
        .equ    P_MATHZ          0x82
        .equ    P_ATAN2          0x83
        .equ    P_HYPOT          0x84
        .equ    P_NORM3          0x85

Appendix D — Fault Conditions

A fault stops the computer permanently. The cause is recorded on the ship but is not reported to you; the symptom is a ship that no longer responds.

Illegal Opcode

The instruction word's opcode is 23 hex or greater. Usually means the program has run into data, or the binary was not produced by ASM.

Division by Zero

DIV or MOD with a zero divisor.

Memory Access Out of Range

A load or store, a PUSH, a POP, a CALL or a RET touched an address below 0 or above the end of RAM. Includes a pop from an empty stack and a return with nothing to return to.

Not faults: arithmetic overflow (wraps), shifts of 32 or more (the count is masked), writing to a port that does not exist, running off the end of the program (HALT), commanding a throttle greater than 1000 (clamped).

Appendix E — Quick Reference Card

+------------------------------------------------------------------------------+
| HC-33 QUICK REFERENCE                                                        |
+------------------------------------------------------------------------------+
| REGISTERS  r0-r14 general   r15 = SP (starts at 8192)                        |
| MEMORY     0-1023 uplink   1024-2047 downlink   2048-8191 data + stack       |
| WORD       32 bit, little-endian, no flags                                   |
+------------------------------------------------------------------------------+
| ldi ra,imm    lui ra,imm    li rd,val   mov ra,rb                            |
| add sub mul div mod and or xor shl shr sar   ra,rb       addi ra,imm         |
| jmp L   beq/bne/blt/bge ra,rb,L   call L   ret   push ra   pop ra            |
| ldb/ldh/ldw ra,[rb+imm]    stb/sth/stw ra,[rb+imm]                           |
| in ra,port    out port,ra    yield    halt    nop                            |
+------------------------------------------------------------------------------+
| COSTS      most 1    mul 2    div,mod 8         BUDGET 2000/turn             |
| UNITS      km   m/s   milliradians   kg          READINGS ROUND DOWN         |
+------------------------------------------------------------------------------+
| 00 turn  01 day  02 turns/day                                                |
| 10-12 pos km   13-15 vel m/s                                                 |
| 20 throttle 0-1000   21 azimuth   22 pitch   23 fuel   24 mass               |
| 30 select   31 nearest   32-34 rel pos   35-37 rel vel   38 dist   40-43 ore |
| 50 mine   51 conts 52 ore 53 room 54 mass   55 attach 56 detach              |
| 57 nearby   58-5B ore by type in tow                                         |
| 60-62 stn pos   63-65 stn vel   66 order   67 earned                         |
| 70 uplink flag / ack   71 uplink length                                      |
| 80 x  81 y  82 z   83 atan2   84 hypot   85 norm3                            |
+------------------------------------------------------------------------------+
| MINE  within 5 km,  rel speed <= 100 m/s        10 kg/turn                   |
| ATTACH  containers within 10 km, rel speed <= 100 m/s                        |
| SALE    drifting containers with ore within 20 km: taken and paid            |
| ORDER   1-10 empty containers, near the Station (max 50 ordered)             |
| ADRIFT  a container adrift for 10 days vanishes, ore and all                 |
| STAR  a = v^2/r, v = 3 km/s.  Inside 200,000 km = destroyed.                 |
+------------------------------------------------------------------------------+

* * *   END OF MANUAL   * * *

HALCYON INSTRUMENT & CONTROL  ·  Publication HIC-0033-A  ·  First Edition
Printed in the Outer System.