Specification

This document is the full specification of the Bedrock computer system.

Revisions

This is the second revision of the specification, released on the 6th of September 2025.

Changes from previous revision

  • The specification has been reworked to become a single long document instead of multiple smaller documents
  • Many sections were reworded for clarity, including the entire assembler section
  • The expected behaviour in many edge cases was made more explicit
  • Reading from the action port on the file device returns error state instead of success state
  • An available port was added to the clipboard device

Overview

Bedrock is a portable 8-bit computer system that is designed to be straightforward to implement on a wide variety of computer architectures and form factors. The core architecture can be implemented by a solo programmer in a day, and the devices are designed to be implemented and connected as needed.

Programs written for Bedrock will be able to run on any platform for which the Bedrock system has been implemented.

Sections

  • Architecture
    Specifies the architecture required to run Bedrock programs.
  • Assembler
    Specifies the standard assembler used to assemble Bedrock programs.
  • Metadata
    Specifies the metadata format used by Bedrock programs.

Devices

All devices are optional, and can be omitted if the host system does not provide the required facilities.

  • 0x0 System device
    Provides information about the Bedrock system, and the ability to sleep, fork, and reset the system.
  • 0x1 Memory device
    Provides access to up to 16 MiB of additional working memory.
  • 0x2 Math device
    Provides access to multiplication, division, and coordinate-space conversion operations.
  • 0x3 Clock device
    Provides access to the current date, current time, and four countdown timers.
  • 0x4 Input device
    Provides access to a pointer device, a keyboard device, and up to four game controllers.
  • 0x5 Screen device
    Provides access to a two-layer screen with a sixteen colour palette.
  • 0x6 Tone device
    Provides a mechanism for synthesizing audio tones (unavailable, reserved for future revision).
  • 0x7 Sampler device
    Provides a mechanism for playing short audio samples (unavailable, reserved for future revision).
  • 0x8 Stream device
    Provides communications with local and networked systems.
  • 0x9 File device
    Provides access to a hierarchical file system.
  • 0xA Clipboard device
    Provides access to the system clipboard, and the ability to drag and drop data between programs.
  • 0xB Registry device
    Provides access to program arguments and a persistent key-value store.

The device slots 0xC, 0xD, 0xE, and 0xF are reserved for the private use of each Bedrock system implementation. Programs that access a custom device will not be portable across Bedrock system implementations.

Terminology

Byte

A byte is an 8-bit value. All byte values are treated as unsigned integers, and range from 0 to 255.

Double

A double is a 16-bit value, stored as a pair of bytes in big-endian byte order. All double values are treated as unsigned integers unless otherwise specified, and range from 0 to 65535.

When treated as a signed integer, the value of a double is encoded using two’s compliment and ranges from -32768 to 32767.

Port alias

A port alias is a device port that acts as a copy of the previous port in the port table. Port aliases are listed with the name ‘aliased’ in the port table of a device. Accessing a port alias will have identical behaviour to accessing the aliased port.

Port group

A port group is a contiguous group of device ports that acts as a single larger port, exposing a value larger than a byte. The ports belonging to the group are listed with the name ‘grouped’ in the port table of the device, and are owned by the previous port in the table. Values are exposed using big-endian byte order, with the lowest-addressed port of the group exposing the highest-order byte of the value.

Atomic read

Some port groups perform atomic reads of the exposed value. Reading from the lowest-addressed port of the group will cache the current value of the port group, and reading from any port in the group will return the corresponding byte of the cached value. The initial cached read value of each port group is zero.

Atomic write

Some port groups perform atomic writes to the exposed value. Writing to any port in the group will set the corresponding byte of a cached value, and writing to the highest-addressed port of the group will commit the cached value, overwriting the exposed value. The initial cached write value of each port group is zero.

Implementation defined value

An implementation defined value is a value that depends on the behaviour or design of the underlying system. The value used is determined independently by each implementation.

Unspecified value

An unspecified value is a value that has no effect on the operation of the system. The value used for an unspecified value can be any value.

Undefined behaviour

Undefined behaviour is behaviour that occurs when performing an unsupported action, and can include any behaviour at all, including corruption of the system state. The behaviour exhibited is determined independently by each implementation.

Architecture

This section specifies the architecture required to run Bedrock programs.

Program memory

The program memory is a 65536-byte block of readable and writeable memory that holds the current program. Each byte of memory is addressed by a 16-bit memory address. The initial value of each byte is zero.

Systems with fewer than 65536 bytes of program memory are partially supported. Reading from or writing to an unimplemented memory address will cause undefined behaviour.

To load a program into program memory, the value of each byte of memory is set to zero, and then each byte of the program is written sequentially to program memory starting from address zero. The program is truncated to fit the available memory.

Reading from memory

Reading a byte from program memory will return the byte at the given address.

Reading a double from program memory will read the high byte of the double from the given address and the low byte from the following address. Reading a double from address 0xFFFF will cause undefined behaviour.

Writing to memory

Writing a byte to program memory will write that byte to the given address.

Writing a double to program memory will write the high byte of the double to the given address and the low byte to the following address. Writing a double to address 0xFFFF will cause undefined behaviour.

Stacks

A stack is a 256-byte block of readable and writeable memory that holds temporary data, and an associated 8-bit stack pointer. Each byte of stack memory is addressed by an 8-bit memory address. The initial value of each byte of stack memory is unspecified, and the initial value of each stack pointer is zero.

There are two stacks, called the working stack and the return stack.

Systems with fewer than 256 bytes of memory per stack are partially supported. Reading from or writing to an unimplemented memory address will cause undefined behaviour.

Pushing to a stack

Pushing a byte to a stack will write that byte to the address referenced by the stack pointer, and then will increment the stack pointer by 1. Overflowing the stack pointer will cause undefined behaviour.

Pushing a double to a stack will push the high byte of the double to the stack, followed by the low byte.

Popping from a stack

Popping a byte from a stack will decrement the stack pointer by 1, and then will read and return the byte at the address referenced by the stack pointer. Underflowing the stack pointer will cause undefined behaviour.

Popping a double from a stack will pop the low byte of the double from the stack, followed by the high byte.

Device bus

The device bus is an array of 256 readable and writeable ports that interface with external devices. Each port is addressed by an 8-bit port number. Each contiguous group of sixteen ports is called a slot. Each slot is addressed by a 4-bit slot number, and can connect to a single device.

Reading from a device

Reading a byte from the device bus will send a read request to the given port, and then the device connected to that port will process the request and return a byte, with the system pausing until the request returns. The maximum duration of a read request is unlimited. If the port is not connected to a device, or if the connected device does not allow reading from that port, the request will return immediately with a value of zero.

Reading a double from the device bus will read the high byte of the double from the given port and then the low byte from the following port. Reading a double from port 0xFF will cause undefined behaviour.

Writing to a device

Writing a byte to the device bus will send a write request containing that byte to the given port, and then the device connected to that port will process the request and return, with the system pausing until the request returns. The maximum duration of a write request is unlimited. If the port is not connected to a device, or if the connected device does not allow writing to that port, the request will return immediately.

Writing a double to the device bus will write the high byte of the double to the given port and then the low byte to the following port. Writing a double to port 0xFF will cause undefined behaviour.

Processor

The processor executes instructions from program memory using an associated 16-bit instruction pointer. The initial value of the instruction pointer is zero.

Each instruction is stored as an 8-bit value. The upper three bits of the value represent the three mode flags, and the lower five bits represent the operation to be performed.

To execute an instruction, a byte is read from the program memory address referenced by the instruction pointer, then the instruction pointer is incremented by 1, and then the instruction represented by that byte is performed. Overflowing the instruction pointer will cause undefined behaviour.

Mode flags

Bit 0x80 of the instruction byte represents the return mode flag. When set, the operation will use the return stack in place of the working stack, and the working stack in place of the return stack.

Bit 0x40 of the instruction byte represents the wide mode flag. When set, each value listed in the operation description that is neither a byte or a double will be a double, otherwise each such value will be a byte.

Bit 0x20 of the instruction byte represents the immediate mode flag. When set, the first byte or double that would be popped from a stack by the operation will instead be read from program memory, from the program memory address referenced by the instruction pointer. The instruction pointer will be incremented by 1 for each byte read. Overflowing the instruction pointer will cause undefined behaviour.

Operations

The lower five bits of an instruction represent the operation to be performed:

  • 0x00 (HLT)
    If none of the mode flags are set, the system is halted. If only the immediate mode flag is set, no operation is performed. The remaining six instruction variants will trigger implementation defined debug behaviour.
  • 0x01 (PSH)
    The value x is popped from the return stack, and then x is pushed to the working stack.
  • 0x02 (POP)
    The value x is popped from the working stack.
  • 0x03 (CPY)
    The value x is popped from the return stack, then x is pushed to the return stack, and then x is pushed to the working stack.
  • 0x04 (DUP)
    The value x is popped from the working stack, then x is pushed to the working stack, and then x is pushed to the working stack.
  • 0x05 (OVR)
    The value y is popped from the working stack, then the value x is popped from the working stack, then x is pushed to the working stack, then y is pushed to the working stack, and then x is pushed to the working stack.
  • 0x06 (SWP)
    The value y is popped from the working stack, then the value x is popped from the working stack, then y is pushed to the working stack, and then x is pushed to the working stack.
  • 0x07 (ROT)
    The value z is popped from the working stack, then the value y is popped from the working stack, then the value x is popped from the working stack, then y is pushed to the working stack, then z is pushed to the working stack, and then x is pushed to the working stack.
  • 0x08 (JMP)
    The double a is popped from the working stack, and then a is written to the instruction pointer.
  • 0x09 (JMS)
    The double a is popped from the working stack, then the double b is read from the instruction pointer, then b is pushed to the return stack, and then a is written to the instruction pointer.
  • 0x0A (JCN)
    The double a is popped from the working stack, and then the value t is popped from the working stack. If t is not zero, a is written to the instruction pointer.
  • 0x0B (JCS)
    The double a is popped from the working stack, and then the value t is popped from the working stack. If t is not zero, the double b is read from the instruction pointer, and then b is pushed to the return stack, and then a is written to the instruction pointer.
  • 0x0C (LDA)
    The double a is popped from the working stack, then the value v is read from the program memory address referenced by a, and then v is pushed to the working stack.
  • 0x0D (STA)
    The double a is popped from the working stack, then the value v is popped from the working stack, and then v is written to the program memory address referenced by a.
  • 0x0E (LDD)
    The byte p is popped from the working stack, then the value v is read from the device bus port referenced by p, and then v is pushed to the working stack.
  • 0x0F (STD)
    The byte p is popped from the working stack, then the value v is popped from the working stack, and then v is written to the device bus port referenced by p.
  • 0x10 (ADD)
    The value y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated as the wrapped addition of y to x, and then r is pushed to the working stack.
  • 0x11 (SUB)
    The value y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated as the wrapped subtraction of y from x, and then r is pushed to the working stack.
  • 0x12 (INC)
    The value x is popped from the working stack, then the value r is calculated as the wrapped addition of 1 to x, and then r is pushed to the working stack.
  • 0x13 (DEC)
    The value x is popped from the working stack, then the value r is calculated as the wrapped subtraction of 1 from x, and then r is pushed to the working stack.
  • 0x14 (LTH)
    The value y is popped from the working stack, and then the value x is popped from the working stack. If x is less than y, the byte 0xFF is pushed to the working stack, otherwise the byte 0x00 is pushed to the working stack.
  • 0x15 (GTH)
    The value y is popped from the working stack, and then the value x is popped from the working stack. If x is greater than y, the byte 0xFF is pushed to the working stack, otherwise the byte 0x00 is pushed to the working stack.
  • 0x16 (EQU)
    The value y is popped from the working stack, and then the value x is popped from the working stack. If x is equal to y, the byte 0xFF is pushed to the working stack, otherwise the byte 0x00 is pushed to the working stack.
  • 0x17 (NQK)
    The value y is popped from the working stack, then the value x is popped from the working stack, then x is pushed to the working stack, and then y is pushed to the working stack. If x is not equal to y, the byte 0xFF is pushed to the working stack, otherwise the byte 0x00 is pushed to the working stack.
  • 0x18 (SHL)
    The byte y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated by shifting the bits of x leftwards y times, and then r is pushed to the working stack. To shift the bits of a value leftwards, each bit of the value is set to the original state of the next lower bit, and the lowest bit is unset.
  • 0x19 (SHR)
    The byte y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated by shifting the bits of x rightwards y times, and then r is pushed to the working stack. To shift the bits of a value rightwards, each bit of the value is set to the original state of the next higher bit, and the highest bit is unset.
  • 0x1A (ROL)
    The byte y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated by rotating the bits of x leftwards y times, and then r is pushed to the working stack. To rotate the bits of a value leftwards, each bit of the value is set to the original state of the next lower bit, and the lowest bit is set to the original state of the highest bit.
  • 0x1B (ROR)
    The byte y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated by rotating the bits of the value x rightwards y times, and then r is pushed to the working stack. To rotate the bits of a value rightwards, each bit of the value is set to the original state of the next higher bit, and the highest bit is set to the original state of the lowest bit.
  • 0x1C (IOR)
    The value y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated by setting each bit only if at least one of the corresponding bits of x and y is set, and then r is pushed to the working stack.
  • 0x1D (XOR)
    The value y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated by setting each bit only if exactly one of the corresponding bits of x and y is set, and then r is pushed to the working stack.
  • 0x1E (AND)
    The value y is popped from the working stack, then the value x is popped from the working stack, then the value r is calculated by setting each bit only if both of the corresponding bits of x and y are set, and then r is pushed to the working stack.
  • 0x1F (NOT)
    The value x is popped from the working stack, then the value r is calculated by setting each bit only if the corresponding bit of x is not set, and then r is pushed to the working stack.

Assembler

This section specifies the standard assembler used to assemble Bedrock programs.

The assembler takes a textual source file as input and returns a binary program file as output. If the program is invalid according to the rules of the assembler, no program file will be created.

Source file

A source file is a sequence of zero or more characters representing the source code of a Bedrock program, where each character is a Unicode scalar value. The character encoding and line-ending format are implementation defined. The file extension used for source files is .brc.

Program file

A program file is a sequence of zero or more bytes representing an assembled Bedrock program. The file extension used for program files is .br.

Tokens

A token is a sequence of one or more characters representing a language element. Each token assembles to a sequence of zero or more bytes. The address of a token is equal to the number of bytes assembled before it in the program file.

The source file is parsed as a list of zero or more tokens by iterating over the characters in the file, with characters being consumed from the sequence to form tokens according to the following rules:

  • If no token is in progress, characters in the range U+0000 to U+0020 are ignored.
  • The characters ', ", and ( begin a new span-style token. Characters are consumed up to and including the matching terminator character, which ends the token. The terminators for the characters ', ", ( are ', ", ), respectively. The program is invalid if the end of the source file is reached before the matching terminator is found.
  • All other characters begin a new word-style token. If the character is ), [, ], {, }, ;, or :, no further characters are consumed by this token. Otherwise, characters are consumed up to and including the next : character, or up to and excluding the next (, ), [, ], {, }, ;, or character in the range U+0000 to U+0020, or until the end of the source file is reached, whichever comes first.

The list of tokens is then assembled sequentially into program bytes according to the description of the matching language element for each token. If the program is valid, the assembled bytes are returned as the program file.

Language elements

The first character of a token determines the language element that the token represents:

Comment

A comment token is a ( character, followed by zero or more characters, followed by a ) character. It assembles to nothing.

An unmatched comment terminator token is a single ) character. The program is invalid if it contains an unmatched comment terminator.

Marker

A marker token is a single [ or ] character. It assembles to nothing.

Block delimiter

An opening block delimiter token is a single { character. A closing block delimiter token is a single } character. Each closing block delimiter is matched with the closest previous unmatched opening block delimiter. An opening block delimiter assembles to a double with value equal to the address of the matching closing block delimiter. A closing block delimiter assembles to nothing.

The program is invalid if it contains an unmatched block delimiter, or if a block delimiter inside a macro definition is matched with a block delimiter outside that definition, or if a closing block delimiter has an address greater than 0xFFFF.

Label definition

A global label definition token is an @ character, followed by zero or more characters called the label identifier. The name of a global label definition is given by the label identifier. It assembles to nothing.

A local label definition token is an & character, followed by zero or more characters called the label identifier. The name of a local label definition is the name of the closest previous global label definition (if any), followed by a / character, followed by the label identifier. It assembles to nothing.

The program is invalid if a label definition shares a name with another label or macro definition, or if the name of a label definition is longer than 63 characters, or if a label definition has an address greater than 0xFFFF.

The maximum number of label definitions allowed in a program is implementation defined.

Macro definition

A macro definition token is a % character, followed by zero or more characters called the macro identifier. The name of a macro definition is given by the macro identifier. The body of a macro definition is the list of zero or more tokens that follows the macro definition token, up to and excluding the next macro definition terminator token. These body tokens are collected into the macro definition for later use, and are not assembled. The macro definition terminator is matched with the macro definition. The macro definition assembles to nothing.

A macro definition terminator token is a single ; character. It assembles to nothing.

The program is invalid if it contains an unmatched macro definition or macro definition terminator, or if a macro definition shares a name with another label or macro definition, or if the name of a macro definition is longer than 63 characters, or if the body of a macro definition contains a label or macro definition token.

The maximum number of macro definitions allowed in a program is implementation defined.

Padding

A padding token is a # character, followed by zero or more characters called the pad value. It assembles to a number of zero bytes equal to the pad value as interpreted as a hexadecimal value.

The program is invalid if the pad value does not contain exactly two or four characters, or if the pad value contains any character that is not in the range 0 to 9, A to F, and a to f.

String

A raw string token is a ' character, followed by zero or more characters called the string content, followed by a ' character. It assembles to the string content as a UTF-8 encoded byte sequence.

A terminated string token is a " character, followed by zero or more characters called the string content, followed by a " character. It assembles to the string content as a UTF-8 encoded byte sequence, followed by a zero byte.

Literal

A byte literal token is exactly two characters long, where each character is in the range 0 to 9, A to F, and a to f. It assembles to one byte with value equal to the token as interpreted as a hexadecimal value.

A double literal token is exactly four characters long, where each character is in the range 0 to 9, A to F, and a to f. It assembles to a double with value equal to the token as interpreted as a hexadecimal value.

Symbol

A symbol token is an optional ~ character, followed by zero or more characters called the symbol identifier. Any token that doesn’t already represent another language element is a symbol token. If the token begins with a ~ character, the name of the symbol is the name of the closest previous global label definition (if any), followed by a / character, followed by the symbol identifier. Otherwise, the name of the symbol is given by the symbol identifier. The name of a symbol in the body of a macro definition is determined once it is collected into the macro definition.

If the symbol name is equal to the name of a label definition, the symbol assembles to a double with value equal to the address of that label definition. The label definition can come either before or after the symbol token in the source file.

If the symbol name is equal to the name of a macro definition, the symbol token is replaced with a copy of the body of the macro definition, which is then assembled recursively. The maximum recursion depth is implementation defined. The macro definition must come before the symbol token in the source file.

The program is invalid if the name of a symbol is longer than 63 characters, or if the name is not equal to the name of a label or macro definition, or if the name is equal to the name of a macro definition that comes after the symbol token in the source file.

Instruction mnemonics

The following list of macro definitions is predefined by the assembler:

%HLT 00;  %NOP  20;  %DB1  40;  %DB2   60;  %DB3  80;  %DB4   A0;  %DB5   C0;  %DB6    E0;
%PSH 01;  %PSH: 21;  %PSH* 41;  %PSH*: 61;  %PSHr 81;  %PSHr: A1;  %PSHr* C1;  %PSHr*: E1;
             %: 21;                %*: 61;                %r: A1;                 %r*: E1;
%POP 02;  %POP: 22;  %POP* 42;  %POP*: 62;  %POPr 82;  %POPr: A2;  %POPr* C2;  %POPr*: E2;
%CPY 03;  %CPY: 23;  %CPY* 43;  %CPY*: 63;  %CPYr 83;  %CPYr: A3;  %CPYr* C3;  %CPYr*: E3;
%DUP 04;  %DUP: 24;  %DUP* 44;  %DUP*: 64;  %DUPr 84;  %DUPr: A4;  %DUPr* C4;  %DUPr*: E4;
%OVR 05;  %OVR: 25;  %OVR* 45;  %OVR*: 65;  %OVRr 85;  %OVRr: A5;  %OVRr* C5;  %OVRr*: E5;
%SWP 06;  %SWP: 26;  %SWP* 46;  %SWP*: 66;  %SWPr 86;  %SWPr: A6;  %SWPr* C6;  %SWPr*: E6;
%ROT 07;  %ROT: 27;  %ROT* 47;  %ROT*: 67;  %ROTr 87;  %ROTr: A7;  %ROTr* C7;  %ROTr*: E7;
%JMP 08;  %JMP: 28;  %JMP* 48;  %JMP*: 68;  %JMPr 88;  %JMPr: A8;  %JMPr* C8;  %JMPr*: E8;
%JMS 09;  %JMS: 29;  %JMS* 49;  %JMS*: 69;  %JMSr 89;  %JMSr: A9;  %JMSr* C9;  %JMSr*: E9;
%JCN 0A;  %JCN: 2A;  %JCN* 4A;  %JCN*: 6A;  %JCNr 8A;  %JCNr: AA;  %JCNr* CA;  %JCNr*: EA;
%JCS 0B;  %JCS: 2B;  %JCS* 4B;  %JCS*: 6B;  %JCSr 8B;  %JCSr: AB;  %JCSr* CB;  %JCSr*: EB;
%LDA 0C;  %LDA: 2C;  %LDA* 4C;  %LDA*: 6C;  %LDAr 8C;  %LDAr: AC;  %LDAr* CC;  %LDAr*: EC;
%STA 0D;  %STA: 2D;  %STA* 4D;  %STA*: 6D;  %STAr 8D;  %STAr: AD;  %STAr* CD;  %STAr*: ED;
%LDD 0E;  %LDD: 2E;  %LDD* 4E;  %LDD*: 6E;  %LDDr 8E;  %LDDr: AE;  %LDDr* CE;  %LDDr*: EE;
%STD 0F;  %STD: 2F;  %STD* 4F;  %STD*: 6F;  %STDr 8F;  %STDr: AF;  %STDr* CF;  %STDr*: EF;
%ADD 10;  %ADD: 30;  %ADD* 50;  %ADD*: 70;  %ADDr 90;  %ADDr: B0;  %ADDr* D0;  %ADDr*: F0;
%SUB 11;  %SUB: 31;  %SUB* 51;  %SUB*: 71;  %SUBr 91;  %SUBr: B1;  %SUBr* D1;  %SUBr*: F1;
%INC 12;  %INC: 32;  %INC* 52;  %INC*: 72;  %INCr 92;  %INCr: B2;  %INCr* D2;  %INCr*: F2;
%DEC 13;  %DEC: 33;  %DEC* 53;  %DEC*: 73;  %DECr 93;  %DECr: B3;  %DECr* D3;  %DECr*: F3;
%LTH 14;  %LTH: 34;  %LTH* 54;  %LTH*: 74;  %LTHr 94;  %LTHr: B4;  %LTHr* D4;  %LTHr*: F4;
%GTH 15;  %GTH: 35;  %GTH* 55;  %GTH*: 75;  %GTHr 95;  %GTHr: B5;  %GTHr* D5;  %GTHr*: F5;
%EQU 16;  %EQU: 36;  %EQU* 56;  %EQU*: 76;  %EQUr 96;  %EQUr: B6;  %EQUr* D6;  %EQUr*: F6;
%NQK 17;  %NQK: 37;  %NQK* 57;  %NQK*: 77;  %NQKr 97;  %NQKr: B7;  %NQKr* D7;  %NQKr*: F7;
%SHL 18;  %SHL: 38;  %SHL* 58;  %SHL*: 78;  %SHLr 98;  %SHLr: B8;  %SHLr* D8;  %SHLr*: F8;
%SHR 19;  %SHR: 39;  %SHR* 59;  %SHR*: 79;  %SHRr 99;  %SHRr: B9;  %SHRr* D9;  %SHRr*: F9;
%ROL 1A;  %ROL: 3A;  %ROL* 5A;  %ROL*: 7A;  %ROLr 9A;  %ROLr: BA;  %ROLr* DA;  %ROLr*: FA;
%ROR 1B;  %ROR: 3B;  %ROR* 5B;  %ROR*: 7B;  %RORr 9B;  %RORr: BB;  %RORr* DB;  %RORr*: FB;
%IOR 1C;  %IOR: 3C;  %IOR* 5C;  %IOR*: 7C;  %IORr 9C;  %IORr: BC;  %IORr* DC;  %IORr*: FC;
%XOR 1D;  %XOR: 3D;  %XOR* 5D;  %XOR*: 7D;  %XORr 9D;  %XORr: BD;  %XORr* DD;  %XORr*: FD;
%AND 1E;  %AND: 3E;  %AND* 5E;  %AND*: 7E;  %ANDr 9E;  %ANDr: BE;  %ANDr* DE;  %ANDr*: FE;
%NOT 1F;  %NOT: 3F;  %NOT* 5F;  %NOT*: 7F;  %NOTr 9F;  %NOTr: BF;  %NOTr* DF;  %NOTr*: FF;

Metadata

This section specifies the metadata format used by Bedrock programs.

The presence of the 10-byte identifier E8 00 18 42 45 44 52 4F 43 4B at the beginning of a file indicates that the file is a Bedrock program with metadata, and that the following 14 bytes of the file can be parsed as a list of pointers to metadata values.

Each pointer in the list is a double that represents the address of the first byte of the associated metadata value. An address of zero indicates that no value has been provided.

Addr. Bytes Name Description
0x0000 10 Identifier Metadata identifier.
0x000A 2 Name Pointer to program name and version
0x000C 2 Authors Pointer to list of author names.
0x000E 2 Description Pointer to program description.
0x0010 2 Background colour Pointer to icon background colour.
0x0012 2 Foreground colour Pointer to icon foreground colour.
0x0014 2 Small icon Pointer to 24x24 pixel monochrome icon.
0x0016 2 Large icon Pointer to 64x64 pixel monochrome icon.

Metadata values

Name

The name value is a UTF-8 encoded string containing the name and version of the program, followed by a zero byte. The string format is the program name, followed by the forward-slash character U+002F, followed by the program version. The program name and version must not contain the forward-slash character U+002F or any character in the range U+0000 to U+001F. The maximum length of the name value is 255 bytes, excluding the zero byte.

The name value is addressed by the pointer at address 0x000A.

Authors

The author list is a UTF-8 encoded string containing a list of names of the authors of the program, followed by a zero byte. The string format is a concatenated list of names, with every name but the last followed by the newline character U+000A. The name of each author must not contain any character in the range U+0000 to U+001F. The maximum length of each name is 255 bytes, excluding the newline character and the zero byte, and the maximum number of names in the list is 16.

The author list is addressed by the pointer at address 0x000C.

Description

The description value is a UTF-8 encoded string containing a short description of the program, followed by a zero byte. The program description must not contain any character in the range U+0000 to U+001F. The maximum length of the description value is 255 bytes, excluding the zero byte.

The description value is addressed by the pointer at address 0x000E.

Background colour

The background colour is a double representing the colour to be used for the background of each icon.

The background colour is addressed by the pointer at address 0x0010.

Foreground colour

The foreground colour is a double representing the colour to be used for the foreground of each icon.

The foreground colour is addressed by the pointer at address 0x0012.

Small icon

The small icon is a sequence of nine sprites representing a 24x24 pixel monochrome icon, ordered left-to-right and then top-to-bottom.

The small icon is addressed by the pointer at address 0x0014.

Large icon

The large icon is a sequence of sixty-four sprites representing a 64x64 pixel monochrome icon, ordered left-to-right and then top-to-bottom.

The large icon is addressed by the pointer at address 0x0016.

Types

Colour

A colour is a double that represents a 12-bit RGB colour value.

The highest four bits of the double are ignored, the next four bits represent the intensity of the red channel, the next four bits represent the intensity of the green channel, and the lowest four bits represent the intensity of the blue channel.

Bits Description
0xF000 ignored
0x0F00 Red channel
0x00F0 Green channel
0x000F Blue channel

Sprite

A sprite is a sequence of 8 bytes that represents an 8x8 pixel monochrome image.

Each byte in the sequence represents a row of the sprite, ordered top to bottom. Each bit of the byte represents a pixel in the row, ordered left to right, from highest bit to lowest. If a bit is set, the corresponding pixel will be drawn using the foreground colour, otherwise it will be drawn using the background colour. If a foreground or background colour hasn’t been provided, the colour to use as a replacement is implementation defined.

System device

This section specifies the system device of the Bedrock computer system.

The system device connects to slot 0x0 of the device bus. It provides information about the Bedrock system, and the ability to sleep, fork, and reset the system.

Ports

Port Name Description Read Write
0x00 Sleep Wait for a device event.
0x01 grouped grouped
0x02 Wake Device that woke the system.
0x03 Fork Fork or reset the system.
0x04 Device name Name of custom device 1.
0x05 Device name Name of custom device 2.
0x06 Device name Name of custom device 3.
0x07 Device name Name of custom device 4.
0x08 System name Name of this Bedrock system.
0x09 System authors Authors of this Bedrock system.
0x0A Program memory Program memory size.
0x0B grouped grouped
0x0C Working stack Working stack size.
0x0D Return stack Return stack size.
0x0E Connected devices List of connected devices.
0x0F grouped grouped

Sleep

Writing a value to this port group will perform an atomic write, putting the system to sleep on commit. The value written is a device list representing the list of devices that are allowed to wake the system from sleep. When a wake flag associated with one of those devices has been set, that flag will be cleared, the value of the wake port will be set to the slot number of that device, the system will wake from sleep, and then this write request will return. While the system is asleep, no further instructions will be executed.

If more than one wake flag associated with a device in the list is set, the flag associated with the device that least recently woke the system from sleep will be chosen. The system device will be chosen only if no other flag is set.

Wake

Reading from this port will return the slot number of the device that most recently woke the system from sleep. The initial value of this port is zero.

Fork

Writing a non-zero value to this port will fork the Bedrock system. A new instance of the Bedrock system will be created with separate devices and with all values set to their initial states, and then the program memory of the current instance will be copied over to the new instance. If this system does not support multiple instances, or if a new instance could not be created, then the current instance will be reset as if by writing a zero value to this port.

Writing a zero value to this port will reset the Bedrock system. The instruction pointer and stack pointers will be set to zero, and all devices will be reset to their initial states. The program memory will not be affected.

Device name

Each device name port is associated with a custom slot on the device bus (slots 0xC to 0xF), and a text buffer containing the name of the device connected to that slot. If no device is connected, the device name will be an empty string. The maximum length of the text buffer string is 255 bytes, excluding the zero byte.

Reading from one of these ports will read and return a byte from the associated text buffer. Writing any value to one of these ports will set the pointer of the associated text buffer to zero.

System name

This port is associated with a text buffer containing the name and version of this Bedrock system implementation. The format of the text buffer string is the system name, followed by the forward-slash character U+002F, followed by the system version. The system name and version must not contain the forward-slash character U+002F or any character in the range U+0000 to U+001F. The maximum length of the text buffer string is 255 bytes, excluding the zero byte.

Reading from this port will read and return a byte from the associated text buffer. Writing any value to this port will set the pointer of the associated text buffer to zero.

System authors

This port is associated with a text buffer containing a list of names of the authors of this Bedrock system implementation. The format of the text buffer string is a concatenated list of names, with every name but the last followed by the newline character U+000A. The name of each author must not contain any character in the range U+0000 to U+001F. The maximum length of each name is 255 bytes, excluding the newline character and the zero byte, and the maximum number of names in the list is 16.

Reading from this port will read and return a byte from the associated text buffer. Writing any value will set the pointer of the associated text buffer to zero.

Program memory

Reading from this port group will return the number of bytes of program memory implemented by this system. A value of zero represents 65536 bytes.

Working stack

Reading from this port will return the number of bytes of working stack memory implemented by this system. A value of zero represents 256 bytes.

Return stack

Reading from this port will return the number of bytes of return stack memory implemented by this system. A value of zero represents 256 bytes.

Connected devices

Reading from this port group will return a device list representing the list of devices currently connected to this system.

Types

Device list

A device list is a 16-bit value representing a list of devices. Each bit of the value (from highest bit to lowest) represents a slot on the device bus (from lowest slot to highest), with a bit being set only if the list contains the device connected to the corresponding slot.

Slot Bit Device
0x0 0x8000 System device
0x1 0x4000 Memory device
0x2 0x2000 Math device
0x3 0x1000 Clock device
0x4 0x0800 Input device
0x5 0x0400 Screen device
0x6 0x0200 Tone device
0x7 0x0100 Sampler device
0x8 0x0080 Stream device
0x9 0x0040 File device
0xA 0x0020 Clipboard device
0xB 0x0010 Registry device
0xC 0x0008 Custom device 1
0xD 0x0004 Custom device 2
0xE 0x0002 Custom device 3
0xF 0x0001 Custom device 4

Wake flag

A wake flag is a 1-bit value associated with a slot on the device bus. A wake flag is set when a wake request is received from the device connected to that slot. A device will send a wake request to the system device according to the ‘wake behaviour’ section in the specification for that device. The initial state of each wake flag is unset.

This device contains sixteen wake flags: one for each of the sixteen slots on the device bus.

Text buffer

A text buffer is a UTF-8 encoded string terminated by a zero byte, and an associated pointer to a byte in the string. The initial value of the pointer is zero.

Reading a byte from a text buffer will return the byte of the string referenced by the pointer, and then will increment the pointer by 1. Reading past the terminating zero byte will cause undefined behaviour.

This device contains six text buffers: one for the name port, one for the authors port, and one for each of the four device name ports.

Wake behaviour

The wake flag for this device is always set, and can never be cleared.

Memory device

This section specifies the memory device of the Bedrock computer system.

The memory device connects to slot 0x1 of the device bus. It provides access to up to 16 MiB of additional working memory.

Ports

Port Name Description Read Write
0x10 Count Number of pages allocated.
0x11 grouped grouped
0x12 Page offset Page offset for first head.
0x13 grouped grouped
0x14 Address offset Address offset for first head.
0x15 grouped grouped
0x16 Head Read and write with first head.
0x17 aliased aliased
0x18 Copy Copy one page to another.
0x19 grouped grouped
0x1A Page offset Page offset for second head.
0x1B grouped grouped
0x1C Address offset Address offset for second head.
0x1D grouped grouped
0x1E Head Read and write with second head.
0x1F aliased aliased

Count

Reading from this port group will return the number of pages currently allocated.

Writing to this port group will perform an atomic write, requesting on commit that the number of pages allocated be changed to the value written. Pages will be sequentially allocated or deallocated from the end of allocated memory until the requested value is reached or until an implementation defined minimum or maximum value has been reached.

Page offset

Each page offset port group is associated with a read-write head.

Reading from one of these port groups will return the page offset of the associated head. Writing to one of these port groups will set the page offset to the value written.

Address offset

Each address offset port group is associated with a read-write head.

Reading from one of these port groups will return the address offset of the associated head. Writing to one of these port groups will set the address offset to the value written.

Head

Each head port is associated with a read-write head.

Reading from one of these ports will read and return a byte from the memory address referenced by that read-write head, and then will increment the address offset by 1, wrapping to zero on overflow. Reading from an unallocated memory address will cause undefined behaviour.

Writing to one of these ports will write the byte to the memory address referenced by that read-write head, and then will increment the address offset by 1, wrapping to zero on overflow. Writing to an unallocated memory address will cause undefined behaviour.

Copy

Writing to this port group will perform an atomic write, requesting on commit that a number of pages be copied equal to the value written. The initial source page is addressed by the page offset of the second read-write head. The initial destination page is addressed by the page offset of the first read-write head.

To copy pages of memory, the contents of the source page will be copied to the destination page, the page directly following the source page will become the new source page, and the page directly following the destination page will become the new destination page, repeating until the requested number of pages has been copied. Copying to or from an unallocated page will cause undefined behaviour.

Types

Page

A page is a 256-byte block of readable and writeable memory that must be allocated before it can be accessed. Memory is allocated as a continuous array of bytes, starting from page zero. Each page is addressed by a 16-bit page address, and each byte of memory is addressed by a 24-bit memory address. The value of each byte on an unallocated page is unspecified. Each time a page is allocated, the value of each byte on that page becomes zero.

The initial number of pages allocated is implementation defined. The minimum and maximum number of pages that can be allocated is implementation defined. The maximum number of pages allocated cannot exceed 65535.

Read-write head

A read-write head is a pointer used to access allocated memory. Each head has an associated 16-bit page offset and 16-bit address offset. The initial value of each offset is zero. The memory address referenced by a head is calculated by multiplying the page offset by 256 and then adding the address offset, causing undefined behaviour if the result exceeds the range of an unsigned 24-bit integer.

This device contains two read-write heads: one head is controlled using the first half of the device, and the other head is controlled using the second half.

Wake behaviour

This device will never send a wake request to the system device.

Math device

This section specifies the math device of the Bedrock computer system.

The math device connects to slot 0x2 of the device bus. It provides access to multiplication, division, and coordinate-space conversion operations.

Ports

Port Name Description Read Write
0x20 x coordinate Horizontal coordinate.
0x21 grouped grouped
0x22 y coordinate Vertical coordinate.
0x23 grouped grouped
0x24 r coordinate Radial coordinate.
0x25 grouped grouped
0x26 t coordinate Angular coordinate.
0x27 grouped grouped
0x28 Product Product of multiplication.
0x29 grouped grouped
0x2A grouped grouped
0x2B grouped grouped
0x2C Quotient Quotient of division.
0x2D grouped grouped
0x2E Remainder Remainder of division.
0x2F grouped grouped

x coordinate

Reading from this port group will return the x coordinate of the polar point after conversion to the cartesian coordinate system. If the coordinate exceeds the range of a signed 16-bit integer, the value returned will be zero. The x coordinate is calculated by taking the signed floor of cos(\frac{2 \pi t}{65536}) \times r, where the cosine function takes an angle in radians.

Writing to this port group will set the x coordinate of the cartesian point to the value written.

y coordinate

Reading from this port group will return the y coordinate of the polar point after conversion to the cartesian coordinate system. If the coordinate exceeds the range of a signed 16-bit integer, the value returned will be zero. The y coordinate is calculated by taking the signed floor of sin(\frac{2 \pi t}{65536}) \times r, where the sine function takes an angle in radians.

Writing to this port group will set the y coordinate of the cartesian point to the value written.

r coordinate

Reading from this port group will return the r coordinate of the cartesian point after conversion to the polar coordinate system. The r coordinate is calculated by taking the unsigned floor of \sqrt{x^2 + y^2}.

Writing to this port group will set the r coordinate of the polar point to the value written.

t coordinate

Reading from this port group will return the t coordinate of the cartesian point after conversion to the polar coordinate system. If the x and y coordinates are both zero, the value returned will be zero. The t coordinate is calculated by taking the unsigned floor of atan2(y,x) \times \frac{65536}{2\pi}.

Writing to this port group will set the t coordinate of the polar point to the value written.

Product

Reading from this port group will return the product of the multiplication of the x operand by the y operand.

Quotient

Reading from this port group will return the quotient of the division of the x operand by the y operand. If the y operand is zero, the value returned will be zero.

Remainder

Reading from this port group will return the remainder of the division of the x operand by the y operand. If the y operand is zero, the value returned will be zero.

Types

Cartesian point

The cartesian point is a pair of coordinates representing a two-dimensional point in the cartesian coordinate system, where each coordinate is a signed 16-bit integer. The x coordinate represents the signed distance from the origin along the horizontal axis, and the y coordinate represents the signed distance from the origin along the vertical axis. The initial value of each coordinate is zero.

Polar point

The polar point is a pair of coordinates representing a two-dimensional point in the polar coordinate system, where each coordinate is an unsigned 16-bit integer. The r coordinate represents the unsigned distance from the origin, and the t coordinate represents the angle anti-clockwise around the origin from the positive horizontal axis. The angle unit is \frac{2\pi}{65536} radians. The initial value of each coordinate is zero.

x operand

The x operand is the x coordinate of the cartesian point, reinterpreted as an unsigned 16-bit value and having the same bit pattern.

y operand

The y operand is the y coordinate of the cartesian point, reinterpreted as an unsigned 16-bit value and having the same bit pattern.

Wake behaviour

This device will never send a wake request to the system device.

Clock device

This section specifies the clock device of the Bedrock computer system.

The clock device connects to slot 0x3 of the device bus. It provides access to the current date, current time, and four countdown timers.

The year, month, day, hour, minute, and second ports return the local date and time. The accuracy is implementation defined.

Ports

Port Name Description Read Write
0x30 Year Current year.
0x31 Month Current month of the year.
0x32 Day Current day of the month.
0x33 Hour Current hour of the day.
0x34 Minute Current minute of the hour.
0x35 Second Current second of the minute.
0x36 Uptime Incrementing uptime counter.
0x37 grouped grouped
0x38 Timer Countdown timer 1.
0x39 grouped grouped
0x3A Timer Countdown timer 2.
0x3B grouped grouped
0x3C Timer Countdown timer 3.
0x3D grouped grouped
0x3E Timer Countdown timer 4.
0x3F grouped grouped

Year

Reading from this port will return the number of full years elapsed since the start of the year 2000. The value returned after the year 2255 is implementation defined.

Writing to this port will set the year on the clock to the value written, if supported by the system. Invalid values are ignored.

Month

Reading from this port will return the number of full months elapsed since the start of the year. The maximum value returned by this port is 0x0B.

Writing to this port will set the month on the clock to the value written, if supported by the system. Invalid values are ignored.

Day

Reading from this port will return the number of full days elapsed since the start of the month. The maximum value returned by this port is 0x1E.

Writing to this port will set the day on the clock to the value written, if supported by the system. Invalid values are ignored.

Hour

Reading from this port will return the number of full hours elapsed since the start of the day. The maximum value returned by this port is 0x17.

Writing to this port will set the hour on the clock to the value written, if supported by the system. Invalid values are ignored.

Minute

Reading from this port will return the number of full minutes elapsed since the start of the hour. The maximum value returned by this port is 0x3B.

Writing to this port will set the minute on the clock to the value written, if supported by the system. Invalid values are ignored.

Second

Reading from this port will return the number of full seconds elapsed since the start of the minute. The maximum value returned by this port is 0x3B. The value returned during a leap second is implementation defined.

Writing to this port will set the second on the clock to the value written, if supported by the system. Invalid values are ignored.

Uptime

Reading from this port group will perform an atomic read, returning the number of full 1/256 second durations elapsed since the system was last reset. The value will wrap to zero on overflow.

Timer

Each timer port group is associated with a countdown timer.

Reading from one of these port groups will perform an atomic read, returning the current value of the associated timer. Writing to one of these port groups will perform an atomic write, setting the timer to the value written on commit.

Types

Countdown timer

A countdown timer is an unsigned 16-bit integer. The value of a timer will decrement by 1 for each full 1/256 second duration elapsed, stopping at zero. The initial value of each timer is zero.

This device contains four countdown timers: one for each of the four timer port groups.

Wake behaviour

This device will send a wake request to the system device when a countdown timer reaches zero, other than by writing to a device port.

Input device

This section specifies the input device of the Bedrock computer system.

The input device connects to slot 0x4 of the device bus. It provides access to a pointer device, a keyboard device, and up to four game controllers.

Ports

Port Name Description Read Write
0x40 Horizontal position Pointer position.
0x41 grouped grouped
0x42 Vertical position Pointer position.
0x43 grouped grouped
0x44 Horizontal scroll Horizontal scroll delta.
0x45 grouped grouped
0x46 Vertical scroll Vertical scroll delta.
0x47 grouped grouped
0x48 Pointer active Pointer active state.
0x49 Pointer button Pointer button states.
0x4A Character input Keyboard character queue.
0x4B Modifier Keyboard modifier states.
0x4C Controller Controller 1.
0x4D Controller Controller 2.
0x4E Controller Controller 3.
0x4F Controller Controller 4.

Horizontal position

Reading from this port group will perform an atomic read, returning the horizontal coordinate of the pointer position.

Vertical position

Reading from this port group will perform an atomic read, returning the vertical coordinate of the pointer position.

Horizontal scroll

Reading from this port will return the horizontal scroll delta, and then will set the horizontal scroll delta to zero.

Vertical scroll

Reading from this port will return the vertical scroll delta, and then will set the vertical scroll delta to zero.

Pointer active

Reading from this port will return 0xFF if the pointer is active, or 0x00 otherwise.

The pointer is active only while the pointer position is within screen bounds, or while a pointer button is still being held that was pressed while within screen bounds. If the pointer device is a touchscreen, it is only active while touched.

Pointer button

Reading from this port will return a button list representing the list of buttons that are currently held down on any pointer device, mapped according to the following table:

Bit Button
0x80 Primary
0x40 Secondary
0x20 Tertiary
0x10 Auxiliary 1
0x08 Auxiliary 2
0x04 Auxiliary 3
0x02 Auxiliary 4
0x01 Auxiliary 5

If the pointer device is a right-handed mouse, primary is the left-mouse button, secondary is the right-mouse button, and tertiary is the middle-mouse button. For a left-handed mouse, primary and secondary will be reversed. If the pointer device is a touchscreen, primary is the touchscreen surface.

The auxiliary buttons are implementation defined.

Character input

Reading from this port will remove and return a byte from the front of the character queue. If the character queue is empty, the value returned will be zero.

Writing to this port will clear the character queue. If a non-zero byte was written and the system uses an on-screen keyboard for text entry, the on-screen keyboard will be made available. If a zero byte was written, the on-screen keyboard will be hidden.

Modifier

Reading from this port will return a button list representing the list of modifier keys that are currently held down on any keyboard device, mapped according to the following table:

Bit Button
0x80 Control
0x40 Shift
0x20 Alt
0x10 Super
0x08 Auxiliary 1
0x04 Auxiliary 2
0x02 Auxiliary 3
0x01 Auxiliary 4

The auxiliary modifier keys are implementation defined.

Controller

Each controller port is associated with a game controller, ordered from least-recently to most-recently connected. On systems where a physical keyboard is the primary input device, the first controller will also be emulated by the keyboard, with the port returning the union of the emulated and physical controller states. The mapping of keyboard buttons to controller buttons is implementation defined.

Reading from one of these ports will return a button list representing the list of buttons that are currently held down on the associated game controller, mapped according to the following table:

Bit Button
0x80 Up
0x40 Down
0x20 Left
0x10 Right
0x08 Confirm
0x04 Cancel
0x02 Primary
0x01 Secondary

All analog sticks and directional pads on a game controller map to the up, down, left, and right buttons.

The affirmative face button maps to confirm, the negative face button maps to cancel, the primary action face button maps to primary, and the secondary action face button maps to secondary. The face buttons used by popular game consoles map to controller buttons according to the following table:

PlayStation Xbox Nintendo
Confirm Cross A A
Cancel Circle B B
Primary Square X X
Secondary Triangle Y Y

Types

Pointer position

The pointer position is a pair of coordinates representing the last known position of the pointer on the screen, where each coordinate is a signed 16-bit integer. The initial value of each coordinate is zero. The pointer position will update only while the pointer is active.

The pointer position uses the same coordinate space as the screen device: the distance unit is one pixel, the horizontal coordinate increases rightwards, the vertical coordinate increases downwards, and the origin is the top-left pixel of the screen device. The pointer position is within screen bounds when the horizontal position is at least zero and is less than the screen width, and when the vertical position is at least zero and is less than the screen height.

Scroll delta

Each scroll delta is a signed 16-bit integer representing the distance scrolled along the respective axis since the delta was last read. The initial value of each delta is zero.

The horizontal scroll delta increases when scrolling rightwards (the action that would slide content leftwards) and decreases when scrolling leftwards. The vertical scroll delta increases when scrolling downwards (the action that would slide content upwards) and decreases when scrolling upwards. If a value would overflow or underflow, it will instead saturate at bounds.

For a device with discrete scrolling, such as a traditional scroll wheel, the scroll unit is equal to one increment of the scroll device. For a device with continuous scrolling, such as a touchpad, the scroll unit is implementation defined.

Button list

A button list is an 8-bit value representing a list of held buttons. Each bit of the value represents a button on an input device, with a bit being set only if the corresponding button is currently held down.

Character queue

The character queue is a first-in first-out byte queue that buffers received characters. The maximum length of the queue is implementation defined.

When a character is received from a keyboard device, the character is encoded as a UTF-8 byte sequence and then all bytes are pushed to the back of the queue. If the queue has insufficient capacity for the full sequence, no bytes will be pushed.

The enter key (called return on Apple keyboards) is represented by the Unicode code point U+000A. The backspace key (called delete on Apple keyboards) is represented by the Unicode code point U+0008. The delete key is represented by the Unicode code point U+007F.

Wake behaviour

This device will send a wake request to the system device when any of the following events occur, other than by writing to a device port:

Screen device

This section specifies the screen device of the Bedrock computer system.

The screen device connects to slot 0x5 of the device bus. It provides access to a two-layer screen with a sixteen colour palette.

Ports

Port Name Description Read Write
0x50 Horizontal position Screen cursor position.
0x51 grouped grouped
0x52 Vertical position Screen cursor position.
0x53 grouped grouped
0x54 Screen width Width of screen.
0x55 grouped grouped
0x56 Screen height Height of screen.
0x57 grouped grouped
0x58 Palette Change colour palette.
0x59 grouped grouped
0x5A Selection Select sprite colours.
0x5B grouped grouped
0x5C Sprite Write to sprite buffer.
0x5D aliased aliased
0x5E Draw Draw to screen.
0x5F Move Move screen cursor.

Horizontal position

Reading from this port group will return the horizontal coordinate of the screen cursor. Writing to this port group will set the horizontal coordinate to the value written.

Vertical position

Reading from this port group will return the vertical coordinate of the screen cursor. Writing to this port group will set the vertical coordinate to the value written.

Screen width

Reading from this port group will perform an atomic read, returning the width of the screen in pixels. If no screen is available, the value returned will be zero.

Writing to this port group will perform an atomic write, requesting that the screen width be changed and then locked to the value written on commit. If the screen is resizeable, the screen width will be set to the requested value, or to the closest value supported by the system, and will be prevented from being resized other than by a write to this port. The values of the screen pixels after a resize are implementation defined.

Screen height

Reading from this port group will perform an atomic read, returning the height of the screen in pixels. If no screen is available, the value returned will be zero.

Writing to this port group will perform an atomic write, requesting that the screen height be changed and then locked to the value written on commit. If the screen is resizeable, the screen height will be set to the requested value, or to the closest value supported by the system, and will be prevented from being resized other than by a write to this port. The values of the screen pixels after a resize are implementation defined.

Palette

Writing to this port group will perform an atomic write, writing a colour to the screen palette on commit. The highest four bits of the value represents the palette index to be overwritten, and the remaining 4-bit groups each represent the intensities of the red, green, and blue colour channels:

Bits Description
0xF000 Palette index
0x0F00 Red channel
0x00F0 Green channel
0x000F Blue channel

Selection

Reading from this port will return a 16-bit value representing the palette indices of each of the four selected colours. Writing to this port will change the selected colours to the palette indices represented by the value written.

Each 4-bit group in the value represents the palette index of one of the four selected colours:

Bits Description
0xF000 Selected colour 0
0x0F00 Selected colour 1
0x00F0 Selected colour 2
0x000F Selected colour 3

Sprite

Writing to this port will push the byte written into the sprite buffer.

Draw

Writing to this port will perform a draw operation according to the byte written. The upper four bits determine the operation to be performed, according to the following table:

Value Operation
0x0_ Set the colour of a pixel in the background layer.
0x1_ Draw a 1-bit sprite to the background layer.
0x2_ Fill the background layer with a solid colour.
0x3_ Draw a 2-bit sprite to the background layer.
0x4_ Draw a solid line to the background layer.
0x5_ Draw a 1-bit textured line to the background layer.
0x6_ Draw a solid rectangle to the background layer.
0x7_ Draw a 1-bit textured rectangle to the background layer.
0x8_ Set the colour of a pixel in the foreground layer.
0x9_ Draw a 1-bit sprite to the foreground layer.
0xA_ Fill the foreground layer with a solid colour.
0xB_ Draw a 2-bit sprite to the foreground layer.
0xC_ Draw a solid line to the foreground layer.
0xD_ Draw a 1-bit textured line to the foreground layer.
0xE_ Draw a solid rectangle to the foreground layer.
0xF_ Draw a 1-bit textured rectangle to the foreground layer.

If bit 0x10 of the byte is unset, the lower four bits of the byte will represent the palette index of the colour to use for the operation. Otherwise, the lower four bits will represent the transformation value to use for the operation.

Each bit of the transformation value represents a transformation to apply to the sprite used by the operation, with a transformation being applied only if the corresponding bit is set. The ‘flip x’ and ‘flip y’ transformations are applied before the ‘flip diagonal’ transformation.

Bit Name Description
0x_1 Flip X Flip sprite across vertical center-line.
0x_2 Flip Y Flip sprite across horizontal center-line.
0x_4 Flip diagonal Flip sprite across top-left bottom-right diagonal.
0x_8 Transparent Don’t draw sprite pixels that use sprite colour 0.

The current cursor position is the current position of the screen cursor. The previous cursor position is the position of the screen cursor when this port was last written to, or the origin if this port had not previously been written to.

When setting the colour of a pixel on a layer, the pixel at the current cursor position on that layer is changed to the given colour.

When filling a layer with a solid colour, each pixel on that layer is changed to the given colour.

When drawing a sprite to a layer, the sprite is read from the sprite buffer, then the given transformations are applied to the sprite, and then each pixel of the sprite is drawn to that layer using the selected colours, with the top-left pixel of the sprite being placed at the current cursor position.

When drawing a line to a layer, each pixel on that layer that belongs to the shortest and straightest line connecting the previous and current cursor positions is affected. Line pixels can connect diagonally or orthogonally. If there are multiple possible lines, the choice is implementation defined.

When drawing a rectangle to a layer, each pixel on that layer that belongs to the smallest axis-aligned rectangle containing both the previous and current cursor positions is affected.

When drawing a solid line or rectangle, each pixel belonging to the line or rectangle is changed to the given colour.

When drawing a textured line or rectangle, a 1-bit sprite is read from the sprite buffer, then the given transformations are applied to the sprite, and then each pixel belonging to the line or rectangle is drawn as the corresponding sprite pixel, as if the sprite were tiled outwards from the top-left corner of the screen.

Move

Writing to this port will move the screen cursor a number of pixels in a given direction according to the byte written. The upper two bits determine the direction to move, and the lower six bits determine the distance:

Bit Name
0x80 Negative
0x40 Vertical
0x3F Distance

If bit 0x40 is set, the vertical coordinate of the screen cursor will be modified, else the horizontal coordinate will be modified. If bit 0x80 is set, the distance will be subtracted from the coordinate, else the distance will be added. The coordinate value wraps on overflow.

Types

Screen palette

The screen has a palette of sixteen colours, with each colour in the palette assigned an index from zero to fifteen. Each colour in the palette is selected from a 12-bit RGB colour space. Changing the colour stored at a palette index will change the colour of all pixels on the screen that use that index.

The initial value of each colour in the palette is implementation defined.

If the system has a fixed-palette screen with two colours, every second palette index will map to the on colour and every other index will map to the off colour. For three colours, every fourth index will map instead to the grey colour. For four colours, the third and four index of every four will map instead to the dim and bright colours. For more than four colours, the mapping is implementation defined.

Index 2 colours 3 colours 4 colours
0/4/8/C Off Off Off
1/5/9/D On On On
2/6/A/E Off Off Dim
3/7/B/F On Grey Bright

Screen layer

The screen contains two overlapping layers of pixels, called the foreground layer and the background layer. The colour of each pixel on each layer is represented by a palette index. When rendering the screen, each pixel of the screen is rendered using the colour of the foreground pixel if it is not palette index zero, otherwise it is rendered using the colour of the background pixel.

The initial colour of each pixel on each layer of the screen is palette index zero.

Screen cursor

The screen cursor is a pair of coordinates representing the position of a pixel on the screen, where each coordinate is a signed 16-bit integer. The horizontal coordinate increases rightwards, the vertical coordinate increases downwards, and the origin is the top-left pixel of the screen. The initial value of each coordinate is zero.

Sprite buffer

The sprite buffer is a 16-byte block of readable and writeable memory and an associated 4-bit pointer. The initial value of each byte of buffer memory is zero, and the initial value of the pointer is unspecified.

Pushing a byte into the sprite buffer will write that byte to the buffer address referenced by the pointer, and then will increment the pointer by 1, wrapping to zero on overflow.

The sprite buffer is treated as a circular buffer that is split into two 8-byte planes by the current pointer value. The high plane consists of the eight bytes starting from the address referenced by the pointer, and the low plane consists of the remaining eight bytes.

Sprite data

A sprite is an 8x8 pixel image. A 1-bit sprite is encoded as a sequence of eight bytes, and a 2-bit sprite is encoded as a sequence of sixteen bytes.

Sprites are read from the sprite buffer. Each plane of the sprite buffer contains 1 bit of data per sprite pixel. Each byte of a plane maps to a row of the sprite, ordered top to bottom, and each bit of a byte maps to a pixel in the row, ordered left to right, from highest bit to lowest.

A 1-bit sprite is drawn using the low plane of the sprite buffer, with each pixel corresponding with a 1-bit colour value.

A 2-bit sprite is drawn using both planes of the sprite buffer, with each pixel corresponding with a 2-bit colour value. The high plane determines the high bit of each colour value and the low plane defines the low bit.

Each pixel of a 1-bit or 2-bit sprite is drawn using the selected colour that corresponds with the colour value of that pixel:

High Low Description
0 0 Drawn using selected colour 0
0 1 Drawn using selected colour 1
1 0 Drawn using selected colour 2
1 1 Drawn using selected colour 3

Selected colours

The selected colours are the four palette indices that are used to draw sprites to the screen. The initial value of each selected colour is zero.

Wake behaviour

This device will send a wake request to the system device when the width or height of the screen changes, other than by writing to a device port.

Tone device

This section specifies the tone device of the Bedrock computer system.

The tone device connects to slot 0x6 of the device bus. It provides a mechanism for synthesizing audio tones.

Sampler device

This section specifies the sampler device of the Bedrock computer system.

The sampler device connects to slot 0x7 of the device bus. It provides a mechanism for playing short audio samples.

Stream device

This section specifies the stream device of the Bedrock computer system.

The stream device connects to slot 0x8 of the device bus. It provides communications with local and networked systems.

Ports

Port Name Description Read Write
0x80 Input connection Connection state of local input channel.
0x81 Output connection Connection state of local output channel.
0x82 Input transmission Transmission state of local input channel.
0x83 Output transmission Transmission state of local output channel.
0x84 Input queue Bytes waiting in local input queue.
0x85 Output queue Bytes free in local output queue.
0x86 Head Read and write to the local bytestream.
0x87 aliased aliased
0x88 Input connection Connection state of remote input channel.
0x89 Output connection Connection state of remote output channel.
0x8A Input transmission Transmission state of remote input channel.
0x8B Output transmission Transmission state of remote output channel.
0x8C Input queue Bytes waiting in remote input queue.
0x8D Output queue Bytes free in remote output queue.
0x8E Head Read and write to the remote bytestream.
0x8F aliased aliased

Input connection

Each input connection port is associated with the input channel of a bytestream.

Reading from one of these ports will return 0xFF if the associated input channel is connected to another system, or 0x00 otherwise. Writing a byte to the remote input connection port will write that byte to the remote path buffer.

Output connection

Each output connection port is associated with the output channel of a bytestream.

Reading from one of these ports will return 0xFF if the associated output channel is connected to another system, or 0x00 otherwise. Writing a byte to the remote output connection port will write that byte to the remote path buffer.

Input transmission

Each input transmission port is associated with the input channel of a bytestream.

Reading from one of these ports will return 0xFF if the transmission control flag of the associated input channel is set, or 0x00 otherwise. Writing any value to one of these ports will clear the buffer queue of the associated input channel and then will set the transmission control flag of that channel.

Output transmission

Each output transmission port is associated with the output channel of a bytestream.

Reading from one of these ports will return 0xFF if the transmission control flag of the associated output channel is set, or 0x00 otherwise. Writing any value to one of these ports will clear the transmission control flag of the associated output channel.

Input queue

Each input queue port is associated with the input channel of a bytestream.

Reading from one of these ports will return the number of bytes waiting in the buffer queue of the associated input channel. If the queue contains more than 255 bytes, the value returned will be 0xFF.

Writing any value to one of these ports will drop the incoming transmission. This will remove all bytes from the buffer queue of the associated input channel, and then will drop all newly received bytes on that channel until the transmission control flag has been cleared.

Output queue

Each output queue port is associated with the output channel of a bytestream.

Reading from one of these ports will return the number of bytes of free space in the buffer queue of the associated output channel. If the queue has more than 255 bytes of free space, the value returned will be 0xFF.

Head

Each head port is associated with a bytestream.

Reading from one of these ports will remove and return a byte from the front of the input queue of the associated bytestream. If the queue is empty, the value returned will be zero.

Writing a byte to one of these ports will push that byte to the back of the output queue of the associated bytestream. The byte will be dropped instead if the output channel is disconnected, the output queue is full, or the transmission control flag of the output channel is not set.

Types

Bytestream

A bytestream is a bi-directional interface that connects this system to another system. This other system is called the connected system. Each bytestream contains two channels, called the input channel and the output channel. The input channel receives transmissions from the connected system, and the output channel sends transmissions to the connected system.

A transmission is the sequence of bytes that are sent through a channel from when the transmission control flag of that channel is set to when it is cleared.

This device contains two bytestreams: the local bytestream is controlled using the first half of the device, and the remote bytestream is controlled using the second half.

Channel

A channel is a uni-directional interface that connects a transmitting system to a receiving system. Each channel contains a buffer queue and a transmission control flag.

Bytes are sent through a channel by the transmitting system, are buffered in the buffer queue, and then are received by the receiving system. Bytes can only be sent through a channel while the transmission control flag is set.

Buffer queue

A buffer queue is a first-in first-out byte queue that buffers bytes sent through a channel. The maximum length of each queue is implementation defined. While a queue is full, all newly received bytes will be dropped.

Transmission control flag

A transmission control flag is a 1-bit value that determines whether bytes can be sent through a channel. The initial state of each transmission control flag is unset.

The receiving system on a channel can set the transmission control flag. The transmitting system can send bytes through the channel while the flag is set, and can clear the flag to end the transmission.

Local bytestream

The local bytestream will connect and disconnect with another system via an implementation defined process.

Remote bytestream

The remote bytestream will attempt to connect to a remote system in either server mode or client mode after a network address is written to the remote path buffer via either of the remote connection ports. The connection will be made in server mode if the terminating zero byte is written to the remote input connection port, or in client mode if the terminating zero byte is written to the remote output connection port.

When the remote bytestream connects to an address in server mode, the bytestream will bind to that address and listen for incoming connections. This system will act as a server, and other systems that connect to the bound address will act as clients. Each incoming transmission represents an incoming request from a remote system, and each outgoing transmission represents a response to that remote system. The remote system will be disconnected after writing to either the remote input transmission, output transmission, or input queue port. This system will remain bound to the address after a remote system is disconnected. The remote input connection state represents whether a remote system is currently connected, and the remote output connection state represents whether this system is still bound to a network address.

When the remote bytestream connects to an address in client mode, the stream device will connect to the remote system at that address. Both systems can send and receive transmissions until either system disconnects.

Remote path buffer

The remote path buffer is a 256-byte block of readable and writeable memory and an associated 8-bit pointer. The initial value of each byte of buffer memory is zero, and the initial value of the pointer is zero.

Writing a non-zero byte to the remote path buffer will write that byte to the buffer address referenced by the pointer, and then will increment the pointer by 1, wrapping to zero on overflow.

Writing a zero byte to the remote path buffer will disconnect the current remote connection, then will attempt to open a connection only if the final byte of the buffer is zero, and then will set the pointer and every byte of buffer memory to zero. The connection will be made in server mode if the zero byte was written to the remote input connection port, or in client mode if the zero byte was written to the remote output connection port.

When attempting to open a connection, the buffer content up to and excluding the first zero byte will be interpreted as a UTF-8 encoded string representing the network address to connect to. The connection fails if this buffer content is empty, is not a valid UTF-8 string, or contains any character in the range U+0000 to U+001F. The address format is implementation defined.

Wake behaviour

This device will send a wake request to the system device when any of the following events occur, other than by writing to a device port:

File device

This section specifies the file device of the Bedrock computer system.

The file device connects to slot 0x9 of the device bus. It provides access to a hierarchical file system.

Ports

Port Name Description Read Write
0x90 Open Open a filesystem entry.
0x91 Action Perform a filesystem action.
0x92 Head Read and write to an open file.
0x93 aliased aliased
0x94 Path Path of current entry.
0x95 Type Type of current entry.
0x96 Child path Path of selected child entry.
0x97 Child type Type of selected child entry.
0x98 Address Pointer into the current entry.
0x99 grouped grouped
0x9A grouped grouped
0x9B grouped grouped
0x9C Length Length of the current entry.
0x9D grouped grouped
0x9E grouped grouped
0x9F grouped grouped

Open

This port is associated with a path buffer.

Reading from this port will return 0xFF if a filesystem entry is currently open, or 0x00 otherwise.

Writing a non-zero byte to this port will write that byte to the associated path buffer.

Writing a zero byte to this port will read a filesystem path from the associated path buffer, then will close the current entry, and then will attempt to open the entry referenced by the path read. If the path is invalid or the entry could not be opened, no entry will be opened and the error flag will be set.

Action

This port is associated with a path buffer.

Reading from this port will return 0xFF if the error flag is set, or 0x00 otherwise. The error flag will then be cleared.

Writing a non-zero byte to this port will write that byte to the associated path buffer.

Writing a zero byte to this port will read a filesystem path from the associated path buffer, then will attempt to perform a filesystem action, and then will close the current entry. The source path is the path of the current entry, and the destination path is the path that was read from the path buffer. The source path is not provided if no entry is open, and the destination path is not provided if the path buffer was empty. If the provided destination path addresses an existing entry or is invalid, no action will be performed and the error flag will be set.

Source Destination Action
No action.
Create empty file at destination.
Delete source.
Move source to destination.

If only the destination path has been provided, an empty file will be created at the destination path, with all parent directories being created as needed. If the file or any directory could not be created, the error flag will be set.

If only the source path has been provided, the entry at the source path will be deleted. If the entry could not be deleted and still exists, the error flag will be set.

If both paths have been provided, the entry at the source path will be moved to the destination path, with all parent directories being created as needed. If the entry could not be moved, or if any directory could not be created, the error flag will be set.

Head

Reading from this port while the current entry is a file will return the byte of the file referenced by the entry address, and then will increment the entry address by 1. If no byte could be read from that address, the entry address will not be incremented, the error flag will be set, and the value returned will be zero. Overflowing the entry address will cause undefined behaviour.

Reading from this port while the current entry is a directory or while no entry is open will return zero.

Writing a byte to this port while the current entry is a file will write that byte to the byte of the file referenced by the entry address, and then will increment the entry address by 1. If the entry address does not reference a byte of the file, the file will first be resized by appending a number of zero bytes such that the file length is one greater than the entry address. If the file could not be resized or written to, the error flag will be set. Overflowing the entry address will cause undefined behaviour.

Writing to this port while the current entry is a directory or while no entry is open will have no effect.

Path

This port is associated with a path buffer. When an entry is opened, the buffer will be populated with the path of that entry. When an entry is closed, the buffer will be cleared.

Reading from this port will read and return a byte from the associated path buffer.

Writing a non-zero value to this port will set the pointer of the associated path buffer to the address of the byte following the final path separator 0x2F, or otherwise to zero.

Writing a zero value to this port will set the pointer of the associated path buffer to zero.

Type

Reading from this port will return 0xFF if the current entry is a directory, or 0x00 otherwise.

Writing to this port while an entry is open will close that entry and then will attempt to open the parent directory of the entry. If the entry has no parent directory or if that directory could not be opened, the original entry will be opened and the error flag will be set.

Writing to this port while no entry is open will close the current entry and then will attempt to open the default directory. If the default directory could not be opened, the original entry will be reopened and the error flag will be set. The path of the default directory is implementation defined.

Child path

This port is associated with a path buffer. When a child entry is selected, the buffer will be populated with the path of the child entry. When a child entry is deselected, the buffer will be cleared.

Reading from this port will read and return a byte from the associated path buffer.

Writing a non-zero value to this port will set the pointer of the associated path buffer to the address of the byte following the final path separator 0x2F, or otherwise to zero.

Writing a zero value to this port will set the pointer of the associated path buffer to zero.

Child type

Reading from this port will return 0xFF if the selected child is a directory, or 0x00 otherwise.

Writing to this port while a child entry is selected will close the current entry and then will attempt to open the child entry. If the child entry could not be opened, the original entry will be reopened and the error flag will be set.

Address

Reading from this port group will perform an atomic read, returning the entry address.

Writing to this port group will perform an atomic write, setting the entry address to the value written on commit. If the current entry is a directory and the value written is the index of a child entry, that child entry will become the selected child, otherwise the current selected child will be deselected.

Length

Reading from this port group will perform an atomic read, returning the length of the current entry, or zero if no entry is open. The length of a file is the number of bytes stored in the file. The length of a directory is the number of child entries in that directory. If the value exceeds the range of an unsigned 32-bit integer, the value returned will be 0xFFFFFFFF.

Writing to this port group will perform an atomic write, requesting that the current entry be resized to the value written on commit. If the current entry is a file, it will be truncated or zero-padded such that the file length is equal to the value written. If the current entry is a directory, or if no entry is open, or if the file could not be resized to the requested size, the error flag will be set.

Types

Filesystem entry

A filesystem entry is an object stored in the filesystem that can be addressed by at least one filesystem path. Each entry is either a file or a directory.

A file is a block of zero or more bytes. Whether a file can be read from or written to is implementation defined. The maximum length of a file is implementation defined.

A directory is an ordered list of zero or more filesystem entries, called child entries. Child entries are indexed starting from zero. A directory can contain itself. The sort order of a directory is implementation defined. The maximum length of a directory is implementation defined.

Filesystem path

A filesystem path is a UTF-8 encoded string representing the address of a filesystem entry.

A path separator is a single forward-slash character U+002F. A path component is a string that is at least one character long, and that does not contain the character U+002F or any character in the range U+0000 to U+001F.

A path must begin with a path separator, followed by zero or more alternating path components and path separators. A path containing a path component cannot end with a path separator. A path cannot exceed 255 bytes in length. A path must be a valid UTF-8 string. If a path does not meet all of these requirements, it is invalid, and it cannot address a filesystem entry.

The case sensitivity of a path is implementation defined. The set of additional characters that are not allowed to be used in a path is implementation defined.

Path buffer

A path buffer is a 256-byte block of readable and writeable memory and an associated 8-bit pointer. The initial value of each byte of buffer memory is zero, and the initial value of the pointer is zero.

Reading a byte from a path buffer will return the byte referenced by the pointer, and then will increment the pointer by 1, wrapping to zero on overflow.

Writing a byte to a path buffer will write that byte to the buffer address referenced by the pointer, and then will increment the pointer by 1, wrapping to zero on overflow.

When a path buffer is populated with a filesystem path, the buffer will be cleared, then each byte of the path will be written to the buffer, and then the pointer will be set to zero.

When a path buffer is cleared, the pointer and each byte of buffer memory will be set to zero.

When a filesystem path is read from a path buffer, the buffer content up to and excluding the first zero byte will be interpreted as the path. If the buffer contains no zero bytes, the path is invalid.

This device contains four path buffers: one for each of the open, action, path, and child path ports.

Entry address

The entry address is a 32-bit value that represents the address of a byte in a file or the index of a child entry in a directory. The initial value of the entry address is zero.

Current entry

The current entry is the filesystem entry that is currently open. At most one entry can be open at a time. Initially no entry will be open.

When the current entry is closed, the path buffers associated with the open, action, path, and child path ports will be cleared, the entry address is set to zero, and the selected child is deselected.

Selected child

The selected child is a filesystem entry descending from the current entry. Initially no child will be selected.

Error flag

The error flag is a 1-bit value that indicates when set that an error occurred while accessing the filesystem. The initial state of the error flag is unset.

Wake behaviour

This device will never send a wake request to the system device.

Clipboard device

This section specifies the clipboard device of the Bedrock computer system.

The clipboard device connects to slot 0xA of the device bus. It provides access to the system clipboard, and the ability to drag and drop data between programs.

Ports

Port Name Description Read Write
0xA0 Available Availability of primary clipboard.
0xA1 reserved reserved
0xA2 Read entry Read entry from primary clipboard.
0xA3 Write entry Write entry to primary clipboard.
0xA4 Read queue Bytes waiting in the primary read queue.
0xA5 Write queue Bytes free in the primary write queue.
0xA6 Head Read and write to the primary access queues.
0xA7 aliased aliased
0xA8 Drag entry Drag an entry into or out of this system.
0xA9 Drop entry Drop an entry into or out of this system.
0xAA Read entry Read entry from secondary clipboard.
0xAB Write entry Write entry to secondary clipboard.
0xAC Read queue Bytes waiting in the secondary read queue.
0xAD Write queue Bytes free in the secondary write queue.
0xAE Head Read and write to the secondary access queues.
0xAF aliased aliased

Available

Reading from this port will return 0xFF if the primary clipboard is available, or 0x00 otherwise.

Read entry

Each read entry port is associated with a clipboard.

Writing to one of these ports will remove all bytes from the read queue of the associated clipboard, and then will read the current entry on the clipboard into that queue. If a non-zero value was written to the port, a text entry will be read. If a zero value was written to the port, a binary entry will be read. If the clipboard could not be accessed, or if the clipboard does not contain an entry of the chosen type, or if the entry is larger than the read queue, or if the entry is a text entry that is not a valid UTF-8 string, no entry will be read.

Write entry

Each write entry port is associated with a clipboard.

Writing to one of these ports will remove the current entry from the associated clipboard, then will write the contents of the associated write queue as an entry to that clipboard, and then will remove all bytes from that queue. If a non-zero value was written to the port, a text entry will be written. If a zero value was written to the port, a binary entry will be written. If the clipboard could not be accessed, or if the entry is a text entry that is not a valid UTF-8 string, no entry will be written.

Read queue

Each read queue port is associated with a clipboard.

Reading from one of these ports will return the number of bytes waiting in the read queue of the associated clipboard. If the queue contains more than 255 bytes, the value returned will be 0xFF.

Write queue

Each write queue port is associated with a clipboard.

Reading from one of these ports will return the number of bytes of free space in the write queue of the associated clipboard. If the queue has more than 255 bytes of free space, the value returned will be 0xFF.

Writing to one of these ports will remove all bytes from the write queue of the associated clipboard.

Head

Each head port is associated with a clipboard.

Reading from one of these ports will remove and return a byte from the front of the read queue of the associated clipboard. If the queue is empty, the value returned will be zero.

Writing a byte to one of these ports will push that byte to the back of the write queue of the associated clipboard. If the queue is full, no byte will be pushed.

Drag entry

Reading from this port will return 0xFF if the entry on the secondary clipboard is currently being dragged over this system, or 0x00 otherwise.

Writing a non-zero value to this port will set the drag flag, and writing a zero value will clear the drag flag.

Drop entry

Reading from this port will return 0xFF if the drop flag is set, or 0x00 otherwise. The drop flag will then be cleared.

Writing a byte to this port will indicate that the entry on the secondary clipboard has been dropped by this system, and then the drag flag will be cleared.

Types

Clipboard

A clipboard is a shared data structure that holds at most one entry. Each clipboard is shared across all Bedrock instances.

Each clipboard contains two access queues, a read queue and a write queue. The read queue is used to read an entry from the clipboard, and the write queue is used to write an entry to the clipboard.

This device contains two clipboards: the primary clipboard is controlled using the first half of the device, and the secondary clipboard is controlled using the second half.

Entry

An entry is a sequence of zero or more bytes, and can be either a text entry or a binary entry. A text entry represents a UTF-8 encoded string. A binary entry represents raw data. The maximum length of an entry is implementation defined.

Primary clipboard

The primary clipboard provides access to data that the user has explicitly requested to be copied.

Secondary clipboard

The secondary clipboard provides access to the span of data that the user is currently interacting with

Access queue

An access queue is a first-in first-out byte queue for accessing clipboard entry data. The maximum length of each queue is implementation defined.

Drag flag

The drag flag is a 1-bit value that indicates when set that the entry on the secondary clipboard is currently being dragged by this system. The initial value of the drag flag is unset.

Drop flag

The drop flag is a 1-bit value that indicates when set that the entry on the secondary clipboard has been dropped on this system. The initial value of the drag flag is unset.

When the entry on the secondary clipboard is dropped on this system, the drop flag will be set.

When the entry on the secondary clipboard is dragged over this system, or when an entry is written to the secondary clipboard, the drop flag will be cleared.

Wake behaviour

This device will send a wake request to the system device when the entry on the secondary clipboard starts being dragged over this system, stops being dragged over this system, or is dropped on this system.

Registry device

This section specifies the registry device of the Bedrock computer system.

The registry device connects to slot 0xB of the device bus. It provides access to program arguments and a persistent key-value store.

Ports

Port Name Description Read Write
0xB0 Select namespace Select a namespace by name.
0xB1 Select key Select a key by name.
0xB2 Read entry Read entry from selected key.
0xB3 Write entry Write entry to selected key.
0xB4 Read queue Bytes waiting in the read queue.
0xB5 Write queue Bytes free in the write queue.
0xB6 Head Read and write to the access queues.
0xB7 aliased aliased
0xB8 Index namespace Select a namespace by index.
0xB9 grouped grouped
0xBA Index key Select a key by index.
0xBB grouped grouped
0xBC Namespace name Name of the selected namespace.
0xBD Key name Name of the selected key.
0xBE Delete namespace Delete the selected namespace.
0xBF Delete key Delete the selected key.

Select namespace

This port is associated with a name buffer.

Writing a non-zero byte to this port will write that byte to the associated name buffer.

Writing a zero byte to this port will read a name from the associated name buffer, and then will clear that buffer. If the name is valid, that name will become the selected namespace, otherwise the null namespace will become the selected namespace.

Select key

This port is associated with a name buffer.

Writing a non-zero byte to this port will write that byte to the associated name buffer.

Writing a zero byte to this port will read a name from the associated name buffer, and then will clear that buffer. If the name is valid, that name will become the selected key, otherwise the null key will become the selected key.

Read entry

Writing a value to this port will remove all bytes from the read queue, and then if an entry of the correct type exists in the selected key of the selected namespace, it will be read into the read queue. If a non-zero value was written to the port, the entry must be a text entry. If a zero value was written to the port, the entry must be a binary entry. If a text entry is invalid, no entry will be read.

Write entry

Writing a value to this port will write an empty entry to the selected key of the selected namespace, then will write the contents of the write queue to that key, and then will remove all bytes from the write queue. If a non-zero value was written to the port, a text entry will be written. If a zero value was written to the port, a binary entry will be written. If attempting to write an invalid text entry, or if writing the entry would exceed the maximum number of registered namespaces or keys, no entry will be written.

Read queue

Reading from this port will return the number of bytes waiting in the read queue.

Write queue

Reading from this port will return the number of bytes of free space in the write queue.

Writing any value to this port will remove all bytes from the write queue.

Head

Reading from this port will remove and return a byte from the front of the read queue. If the queue is empty, the value returned will be zero.

Writing a byte to this port will push that byte to the back of the write queue. If the queue is full, no byte will be pushed.

Index namespace

Reading from this port will return the number of namespaces in the registry (excluding the null namespace).

Writing a value to this port will perform an atomic write, selecting a namespace on commit. If the value written is the index of a namespace in the registry, that namespace will become the selected namespace, otherwise the null namespace will become the selected namespace.

Index key

Reading from this port will return the number of keys registered to the selected namespace (excluding the null key).

Writing a value to this port will perform an atomic write, selecting a key on commit. If the value written is the index of a key in the selected namespace, that key will become the selected key, otherwise the null key will become the selected key.

Namespace name

This port is associated with a name buffer. When the selected namespace changes, the buffer will be populated with the new name. The name buffer will initially contain the name of the null namespace.

Reading from this port will read and return a byte from the associated name buffer.

Writing a value to this port will set the pointer of the associated name buffer to zero.

Key name

This port is associated with a name buffer. When the selected key changes, the buffer will be populated with the new name. The name buffer will initially contain the name of the null key.

Reading from this port will read and return a byte from the associated name buffer.

Writing a value to this port will set the pointer of the associated name buffer to zero.

Delete namespace

Writing any value to this port will write an empty entry to every key in the selected namespace.

Delete key

Writing any value to this port will write an empty entry to the selected key.

Types

Registry

The registry is an ordered list of zero or more namespaces. The registry is shared across all Bedrock instances, and the contents persist after the system is halted. The null namespace is not shared or persisted.

Namespace

A namespace is a name that is associated with an ordered list of zero or more keys.

Each registered namespace is addressed by a 16-bit index, starting from zero. The sort order is implementation defined. The maximum number of namespaces that can be registered is implementation defined, but must be no greater than 65535. The null namespace does not count as a registered namespace.

Registering a key to a namespace will register that namespace, and unregistering all keys from a namespace will unregister that namespace.

Key

A key is a name that is associated with a namespace and at most one entry.

Each registered key is addressed by a 16-bit index, starting from zero. The sort order is implementation defined. The maximum number of keys that can be registered to a namespace is implementation defined, but must be no greater than 65535. The null key does not count as a registered key.

Writing a non-empty entry to a key will register that key, and writing an empty entry to a key will unregister that key.

Entry

An entry is a sequence of zero or more bytes associated with a key in a namespace, and can be either a text entry or a binary entry. A text entry represents a UTF-8 encoded string, and does not contain any character in the range U+0000 to U+001F. If a text entry does not meet these requirements, it is invalid, and cannot be read or written. A binary entry represents raw data. The maximum length of an entry is 255 bytes.

Selected namespace

The selected namespace is a name that represents the namespace to access in future operations. The initial selected namespace is the null namespace.

Selected key

The selected key is a name that represents the key in the selected namespace to access in future operations. The initial selected key is the null key.

Null namespace

The null namespace is a special namespace that is used to pass named values into a program on launch. The name of the null namespace is the empty string. The initial contents of the null namespace are implementation defined.

The contents of the null namespace are not shared across Bedrock instances. They will be copied over to the new instance if the system is forked and will persist after the system is reset, but will not persist after the system is halted.

Null key

The null key is a special key in every namespace that cannot contain an entry. When an entry is written to the null key, that entry is discarded. The name of the null key is the empty string.

Name

A name represents a key or a namespace. A name is a UTF-8 encoded string that does not contain the character U+002F or any character in the range U+0000 to U+001F. The maximum length of a name is 127 bytes. If a name does not meet these requirements, it is invalid, and cannot represent a key or a namespace.

Name buffer

A name buffer is a 128-byte block of readable and writeable memory and an associated 7-bit pointer. The initial value of each byte of buffer memory is zero, and the initial value of the pointer is zero.

Reading a byte from a name buffer will return the byte referenced by the pointer, and then will increment the pointer by 1, wrapping to zero on overflow.

Writing a byte to a name buffer will write that byte to the buffer address referenced by the pointer, and then will increment the pointer by 1, wrapping to zero on overflow.

When a name buffer is populated with a name, the buffer will be cleared, then each byte of the name will be written to the buffer, and then the pointer will be set to zero.

When a name buffer is cleared, the pointer and each byte of buffer memory will be set to zero.

When a name is read from a name buffer, the buffer content up to and excluding the first zero byte will be interpreted as the name. If the buffer contains no zero bytes, the name is invalid.

This device contains two name buffers: one for each of the select namespace and select key ports.

Access queue

An access queue is a first-in first-out byte queue for accessing registry entry data. The maximum length of each queue is implementation defined.

This device contains two access queues: a read queue and a write queue.

Wake behaviour

This device will never send a wake request to the system device.