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. ## 5.9 Wormhole Link 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 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). ```asm ; 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. ```asm ; 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. ```asm ; 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. ```asm ; 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.