Bedrock specification (rev. 3)

Overview

This document contains a complete set of specifications for the Bedrock 8-bit computer system, a stable and ultra-portable platform for creating compact applications that can run anywhere. The system can be implemented either as a thin emulator on top of any existing computer system, or as a minimal hardware board built around any basic microcontroller. A broad range of device interfaces allows each system to expose a variety of hardware capabilities.

The purpose of this document is to allow anyone to implement the complete system from scratch. Implementers should start by reading and implementing the architecture specification (required to run Bedrock programs), followed by any number of device specifications (required to give programs access to hardware).

Sections

This document is structured as a set of individual specifications that each specify an aspect of the Bedrock computer system. The most important specification is the architecture specification, which describes the base system; every other specification describes either standard tooling, data formats, or devices for exposing hardware capabilities to existing systems.

Core specifications

The core specifications form the foundation of the Bedrock computer system. They describe how to write, run, and inspect programs, and how to interface with virtual devices or physical device boards.

Device specifications

The device specifications describe the twelve standard devices that connect to the first twelve slots of the Bedrock device bus, providing programs with access to hardware capabilities. These devices are optional enhancements that are not required to be implemented, however most programs will be of limited use unless at least a couple of these devices are available to the system. Devices are expected to be omitted on a case-by-case basis if the necessary hardware is unavailable.

Auxiliary device specifications

The auxiliary device specifications describe devices that can connect to any of the final four slots of the Bedrock device bus, providing specialised functionality beyond the requirements of most programs. These devices are optional enhancements that are not required or even expected to be implemented.

Revisions

This is the third revision of the specification, released on TODO: Add date. It has been rewritten in a more linear format to be easier to read and includes specifications for the previously unspecified tone and waveform devices.

Previous revisions:

Glossary

This section provides definitions for common terms used across this document.

Arrays and values

  • Byte
    A byte is an 8-bit value representing an integer in the range 0 to 255. This is the base unit of data for Bedrock.
  • Double
    A double is a 16-bit value representing an integer in the range 0 to 65535. It is stored as a pair of bytes in big-endian order, with the high-order byte coming before the low-order byte.
  • Array
    An array is a fixed-length block of bytes, with each byte addressed by its position in the array. The address of the first byte in the array is zero.
  • Pointer
    A pointer is an integer that references a specific byte in an array. The value of the pointer is equal to the address of the referenced byte.
  • Signed value
    TODO: How do I do this? Devices need signed values, the core does not. All values are treated as unsigned unless otherwise stated. A signed 8-bit value represents an integer in the range -128 to 127, and a signed 16-bit value represents an integer in the range -32768 to 32767. Need a thing talking about the offset range though. Define as a remapping of the high range?? 0x0000 to 0x7FFF maps to the range / represents the range 0 to 32767, 0x8000 to 0xFFFF is -32768 to -1. This is important. Unsigned by default though.
  • Bit
    TODO. Highest order, lowest order??
  • Unicode
    TODO. Unicode scalar value. Where to find more information. The U+0000 syntax.

Bitwise operations

  • Bitwise-shift
    To bitwise-shift a value left by one bit, set each bit of the value to the original state of the next lower bit, and unset the lowest bit. To bitwise-shift right, set each bit to the original state of the next higher bit, and unset the highest bit. Repeat n times to rotate n bits.
  • Bitwise-rotate
    To bitwise-rotate a value left by one bit, set each bit of the value to the original state of the next lower bit, and set the lowest bit to the original state of the highest bit. To bitwise-rotate right, set each bit to the original state of the next higher bit, and set the highest bit to the original state of the lowest bit. Repeat n times to rotate n bits.
  • Bitwise-OR
    The bitwise-OR operation takes two equal-sized input values and returns a same-sized output value. Each input value bit corresponds to the bit at the same position in the output value. Each output bit is set only if at least one of the corresponding input bits is set.
  • Bitwise-XOR
    The bitwise-XOR operation takes two equal-sized input values and returns a same-sized output value. Each input value bit corresponds to the bit at the same position in the output value. Each output bit is set only if exactly one of the corresponding input bits is set.
  • Bitwise-AND
    The bitwise-AND operation takes two equal-sized input values and returns a same-sized output value. Each input value bit corresponds to the bit at the same position in the output value. Each output bit is set only if both of the corresponding input bits are set.
  • Bitwise-NOT
    The bitwise-NOT operation takes one input value and returns a same-sized output value. Each input value bit corresponds to the bit at the same position in the output value. Each output bit is set only if the corresponding input bit is not set.

Semantics

  • Overflow
    Overflow occurs when a value increases beyond the range representable by the underlying bytes.
  • Underflow
    Underflow occurs when a value decreases below the range representable by the underlying bytes.
  • Wrapping
    A value that wraps will roll around to the opposite end of its representable range on overflow or underflow, as if the highest representable value is directly followed by the lowest representable value.
  • Access
    A memory address or device port is accessed when it is read from or written to.

Behaviour

  • Implementation defined
    A value or behaviour that depends on the constraints or design of the underlying hardware or software. Implementations are free to choose any sensible value or behaviour. TODO: rework this at the end.
  • Undefined behaviour
    Behaviour that should not be triggered, can break the system / unstable / . Expected to never be triggered. A system is free to do anything at all, which could include corrupting data.

Device terms

  • Access
    A device port is accessed when read from or written to.
  • Atomic access
  • Port group
  • Port alias

Architecture specification

This section specifies the full architecture and instruction set of the Bedrock computer system. A system that implements this section will be able to correctly run all Bedrock programs. For useful operation, many programs will also require one or more devices to be implemented and connected to the device bus, which will allow programs to interact with users or other systems.

Program memory

The program memory is an array of 65536 bytes that holds the current program. To load a program, set every byte of program memory to zero, set the stack and instruction pointers to zero, reset every device on the device bus to their initial states, and then copy each byte of the program into program memory starting from address zero, truncating the program to fit.

To read a double from program memory, read the high byte of the double from the given address and the low byte from the following address. To write a double to program memory, write the high byte of the double to the given address and the low byte to the following address. Reading or writing a double from address 0xFFFF will cause undefined behaviour.

Systems with fewer than 65536 bytes of program memory are partially supported. Accessing an unimplemented memory address will cause undefined behaviour.

Stacks

A Bedrock system contains two stacks, called the working stack and the return stack. Each stack is an array of 256 bytes with an 8-bit stack pointer. The initial value of the pointer is zero. To push a byte to a stack, write the byte to the array address referenced by the pointer and then increment the pointer. To pop a byte from a stack, decrement the pointer and then return the byte at the referenced address. Overflowing or underflowing the stack pointer will cause undefined behaviour.

To push a double to a stack, first push the high byte of the double to the stack and then push the low byte. To pop a double from a stack, pop two bytes; the first byte popped is the low byte of the double and the second byte popped is the high byte.

Systems with fewer than 256 bytes of memory per stack are partially supported. Accessing an unimplemented memory address will cause undefined behaviour.

Device bus

The device bus is an array of 256 ports, which are grouped into 16 slots. Each port is a channel for sending and receiving bytes from a connected device, and each slot is a contiguous group of 16 ports that can connect a single device to the system. Reading from a port will send a read request containing the port number to the connected device, pausing the system until the request has completed and then returning a byte from the device. Writing a byte to a port will send a write request containing the port number and byte to the connected device, pausing the system until the request has completed. If a request is sent to a port that isn’t currently connected to a device, the request will complete immediately, returning a value of zero if it was a read request.

To read a double from the device bus, first read the high byte of the double from the given port and then read the low byte from the following port. To write a double to the device bus, first write the high byte of the double to the given port and then write the low byte to the following port. Reading or writing a double from port 0xFF will cause undefined behaviour.

The first twelve slots of the device bus are reserved for a standard set of devices (see the device specifications). The final four slots of the device bus are reserved for implementation-defined devices (called auxiliary devices).

Processor

The processor executes the current program using a 16-bit instruction pointer. To execute the next instruction of the program, read a byte from the program memory address referenced by the instruction pointer, then increment the instruction pointer, and then execute the instruction represented by that byte. Overflowing the instruction pointer will cause undefined behaviour. To run the program, repeatedly execute the next instruction until the system halts.

The upper three bits of an instruction byte are the mode flags.

  • If bit 0x80 is set, swap the working stack and the return stack for the duration of this instruction.
  • If bit 0x40 is set, values listed without an explicit size for the operation will be doubles, otherwise bytes.
  • If bit 0x20 is set, the first value to be popped by this instruction will instead be read from the program memory address referenced by the instruction pointer, incrementing the pointer with each byte read.

The lower five bits of an instruction byte represent the operation to perform, as per the following list. WST means “working stack”, RST means “return stack”, IP means “instruction pointer”. Arithmetic wraps on overflow and underflow. All values are unsigned. Pushing and popping is to the working stack by default.

  • 0x00 — Halt the system if no mode flag is set, otherwise do nothing.
  • 0x01 — Pop x from RST, push x to WST.
  • 0x02 — Pop x from WST.
  • 0x03 — Pop x from RST, push x to RST, push x to WST.
  • 0x04 — Pop x, push x, x.
  • 0x05 — Pop y, x, push x, y, x.
  • 0x06 — Pop y, x, push y, x.
  • 0x07 — Pop z, y, x, push y, z, x.
  • 0x08 — Pop double a, write a to IP.
  • 0x09 — Pop double a, push IP to RST, write a to IP.
  • 0x0A — Pop double a, pop t. If t is not zero, write a to IP.
  • 0x0B — Pop double a, pop t. If t is not zero, push IP to RST, write a to IP.
  • 0x0C — Pop double a, read v from memory address a, push v.
  • 0x0D — Pop double a, pop v, write v to memory address a.
  • 0x0E — Pop byte p, read v from device port p, push v.
  • 0x0F — Pop byte p, pop v, write v to device port p.
  • 0x10 — Pop y, x, push result of y plus x.
  • 0x11 — Pop y, x, push result of y minus x.
  • 0x12 — Pop x, push result of x plus 1.
  • 0x13 — Pop x, push result of x minus 1.
  • 0x14 — Pop y, x. If x is less than y, push byte 0xFF, else 0x00.
  • 0x15 — Pop y, x. If x is greater than y, push byte 0xFF, else 0x00.
  • 0x16 — Pop y, x. If x is equal to y, push byte 0xFF, else 0x00.
  • 0x17 — Pop y, x, push x, y. If x is not equal to y, push byte 0xFF, else 0x00.
  • 0x18 — Pop byte y, pop x, push result of x bitwise-shifted left by y bits.
  • 0x19 — Pop byte y, pop x, push result of x bitwise-shifted right by y bits.
  • 0x1A — Pop byte y, pop x, push result of x bitwise-rotated left by y bits.
  • 0x1B — Pop byte y, pop x, push result of x bitwise-rotated right by y bits.
  • 0x1C — Pop y, x, push result of x bitwise-OR y.
  • 0x1D — Pop y, x, push result of x bitwise-XOR y.
  • 0x1E — Pop y, x, push result of x bitwise-AND y.
  • 0x1F — Pop x, push result of bitwise-NOT x.

Assembler specification

This section specifies a standard assembler that can convert human-readable source files into programs that run on the Bedrock computer system.

Source file

A source file is a sequence of characters, with each character being a single Unicode scalar value. To assemble a program, first prepend the pre-defined macros code block to the source file, then parse the source file as a sequence of tokens, convert each token to a sequence of bytes, and concatenate the sequences of bytes to create the assembled program. If the source file is invalid according to the rules of the assembler, no program will be created.

Tokens

A token is a sequence of characters from the source file that represents a single language element. The address of a token is equal to the number of bytes preceding it in the assembled program.

To parse the source file as a sequence of tokens, iterate over the characters of the source file and collect them into tokens according to the following rules:

  • The characters U+0000 to U+0020 are ignored if no token is currently being parsed.
  • The characters ', ", or ( start a span token. Collect all characters up to and including the matching terminator, ending the token. The matching terminators for ', ", and ( are ', ", and ), respectively. The source file is invalid if a matching terminator is not found.
  • All other characters start a word token. If the character is ), [, ], {, }, ;, or :, no further characters are collected, ending the token. Otherwise, collect all characters up to and including the next :, or up to and excluding the next (, ), [, ], {, }, ;, or character in the range U+0000 to U+0020, or up to the end of the source file, whichever comes first, ending the token.

Language elements

The first character of a token determines how it will be assembled into a sequence of bytes, as follows:

  • (, ), [, and ] denote a comment, which assembles to nothing. The source file is invalid if it contains a token starting with ).
  • { and } denote an opening or closing block delimiter, respectively. A closing block delimiter matches the closest previous unmatched opening block delimiter, forming a matched pair. The opening delimiter assembles to a double with value equal to the address of the closing delimiter. The closing delimiter assembles to nothing. The source file is invalid if it contains an unmatched block delimiter, or if a delimiter inside a macro definition is matched with a delimiter outside that definition, or if the address of a closing delimiter is greater than 0xFFFF. The maximum nesting depth for blocks is implementation defined.
  • @ and & denote a global or local label definition, respectively. The remaining characters of the token are called the identifier. The name of a global label definition is given by the identifier. The name of a local label definition is given by the name of the most recent global label definition (or an empty string if none), followed by the / character (U+002F), followed by the identifier. A label definition assembles to nothing. The source file is invalid if a label definition shares a name with another label or macro definition, or if the name of a label definition is empty or longer than 63 characters, or if the address of a label definition is greater than 0xFFFF. The maximum number of label definitions supported by the assembler is implementation defined.
  • % and ; denote a macro definition or macro terminator, respectively. A macro definition matches the next macro terminator, and the sequence of tokens between the two is called the macro body. The name of a macro definition is given by the remaining characters of the macro definition token. The macro definition, macro body, and macro terminator each assemble to nothing. The source file is invalid if it contains an unmatched macro definition or macro terminator, or if a macro body contains a label or macro definition, or if a macro definition shares a name with another label or macro definition, or if the name of a macro definition is empty or longer than 63 characters. The maximum number of macro definitions supported by the assembler is implementation defined.
  • ' and " denote a raw or terminated string, respectively. The remaining characters of the token, excluding the final character, are called the string content. A raw string assembles to the string content as a UTF-8 encoded byte sequence. A terminated string assembles to the string content as a UTF-8 encoded byte sequence, followed by a zero byte.
  • # denotes a padding element. The remaining characters of the token are called the pad value, and represent an integer value in hexadecimal. A padding element assembles to a sequence of zero bytes with length equal to this value. The source file is invalid if the pad value is not exactly two or four characters long, or if the pad value contains characters that don’t fall within the ranges 0 to 9, a to f, or A to F.

If the first character of a token is any other character, then the token is either a literal or a symbol:

  • A literal is exactly two or four characters long, where each character falls within the ranges 0 to 9, a to f, or A to F. The characters of the token represent an integer value in hexadecimal. A two or four character literal assembles to a byte or a double, respectively, with value equal to this value.
  • Any other token is a symbol. The name of a symbol is given by the characters of the token. If the name begins with the ~ character (U+007E), replace this character with the name of the most recent global label (or an empty string if none), followed by the / character (U+002F). If the name of a symbol matches the name of a previous or future label definition, it assembles to a double with value equal to the address of that label definition. If the name of a symbol is equal to the name of a previous macro definition, replace the token with a copy of the tokens in the associated macro body and assemble. The name of any symbol inside a macro body is determined when the macro definition is first parsed. The source file 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.

Pre-defined macros

The assembler will prepend the following block of code to the source file before assembly:

%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 specification

This section specifies a format for embedding machine-readable metadata into a Bedrock program. This allows Bedrock programs to be automatically distinguished from other file types, and provides a method for systems to access basic program information.

The presence of the 10-byte marker sequence E8 00 18 42 45 44 52 4F 43 4B at the start of a file indicates that the file is a Bedrock program and that the following 14-byte section of the program represents a table of pointers to program metadata values. Each pointer in the table is a double representing the program address where a corresponding metadata element can be found. A pointer value of zero indicates that the corresponding element has not been provided.

Addr. Bytes Name Description
0x0000 10 Marker sequence Indicates that metadata is present.
0x000A 2 Program identifier Pointer to the program name and version
0x000C 2 Author list Pointer to a list of author names.
0x000E 2 Description Pointer to a description of the program.
0x0010 2 Release date Pointer to the program release date.
0x0012 2 Device list Pointer to a list of required auxiliary devices.
0x0014 2 Small icon Pointer to a 24x24 pixel monochrome icon.
0x0016 2 Large icon Pointer to a 64x64 pixel monochrome icon.

Metadata elements

  • The program identifier is a UTF-8 encoded string followed by a zero byte. The string contains the program name, followed by the / character (U+002F), followed by the program version. The program name and version must not contain the / character (U+002F) or any character in the range U+0000 to U+001F. The maximum length of the program identifier is 255 bytes, excluding the zero byte. The address of the program identifier is given by the double at address 0x000A.
  • The author list is a UTF-8 encoded string followed by a zero byte. The string is a concatenated list of the names of all program authors, 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 zero byte. The address of the author list is given by the double at address 0x000C.
  • The description is a UTF-8 encoded string followed by a zero byte. The string is a brief description that summarises the category and purpose of the program. The description must not contain any character in the range U+0000 to U+001F. The maximum length of the description is 255 bytes, excluding the zero byte. The address of the description is given by the double at address 0x000E.
  • The release date is a sequence of three bytes representing the date when this version of the program was authored. The first byte in the sequence represents the number of full years elapsed since the start of the year 2000, the second byte represents the number of full months elapsed since the start of the year, and the third byte represents the number of full days elapsed since the start of the month. The address of the release date is given by the double at address 0x0010.
  • The device list is a UTF-8 encoded string followed by a zero byte. The string is a concatenated list of the names of the auxiliary devices expected by this program, with every name but the last followed by the newline character U+000A. The name of each auxiliary device 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 zero byte. The maximum number of names in the list is four. The order of names in the list represents the order in which the corresponding devices are expected to be connected to slots 0xC to 0xF of the device bus. The address of the device list is given by the double at address 0x0012.
  • The small icon is a sequence of 72 bytes representing a 24x24 pixel monochrome program icon. Each group of 8 bytes in the sequence represents an 8x8 pixel monochrome sprite, with sprites ordered left-to-right in rows of three, and rows ordered from top to bottom. Each byte in a sprite represents a row of eight pixels, with rows ordered top to bottom, and each bit represents a pixel in that row, ordered left to right from highest bit to lowest. Each set bit represents a pixel drawn using the foreground colour, and each unset bit using the background colour. The address of the small icon is given by the double at address 0x0014.
  • The large icon is a sequence of 512 bytes representing a 64x64 pixel monochrome program icon. Each group of 8 bytes in the sequence represents an 8x8 monochrome pixel sprite (as per the small icon description), with sprites ordered left-to-right in rows of eight, and rows ordered from top to bottom. The address of the large icon is given by the double at address 0x0016.

System device specification

This section specifies the standard system device of the Bedrock computer system. This device connects to slot 0x0 of the device bus.

The system device provides access to information about the Bedrock system, and allows a program to sleep, fork, and reset the system. Implementions need to be able to query devices on the device bus for their name, connection state, and wake flag.

Operations

A device map is a 16-bit value that represents the 16 slots on the device bus. Each bit of a device map represents a slot on the device bus, ordered high to low.

Text buffers

A text buffer is an array of bytes with an associated pointer. The array contains a UTF-8 encoded string followed by a zero byte. The initial value of the pointer is zero, and the maximum value of the pointer is at least one greater than the address of the zero byte. Reading a byte from the text buffer will return the byte at the array address referenced by the pointer, and then the pointer will increment. Reading a byte when the value of the pointer is greater than the address of the zero byte will cause undefined behaviour. Restarting the text buffer will set the value of the pointer to zero.

This device contains six text buffers: a system identifier text buffer, a system authors text buffer, and a device name text buffer for each slot 0xC to 0xF on the device bus.

The system identifier text buffer contains a string that identifies this Bedrock system implementation. The string contains the implementation name, followed by the / character (U+002F), followed by the implementation version. The implementation name and version must not contain the / character (U+002F) or any character in the range U+0000 to U+001F. The maximum length of the string is 255 bytes.

The system authors text buffer contains a string that identifies the authors of this Bedrock system implementation. The string is a concatenated list of the names of the system authors, 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, and the maximum number of names in the list is 16.

Each device name text buffer contains a string that represents the name of the device currently connected to the corresponding slot. The string must not contain any character in the range U+0000 to U+001F. The maximum length of the string is 255 bytes. If no device is connected to the corresponding slot or if no device name is available, the string will be empty. Connecting or disconnecting a device from the slot will set the pointer of the text buffer to zero.

Ports

  • 0x00–0x01
    Writing to this port group will request that the system be put to sleep. Write access is atomic.
  • 0x02
    Reading from this port will return the slot number of the device that most recently woke the system from sleep. If the system has not yet been woken from sleep, the value returned will be 0x00.
  • 0x03
    Writing a non-zero value to this port will create a new Bedrock system instance, with separate core and devices to the current instance, and then the program memory of the current instance will be copied into the new instance. If a new instance cannot be created, the current instance will be reset as if a zero value had been written to this port. Writing a zero value to this port will reset this Bedrock system instance, by setting the instruction pointer and stack pointers to zero, leaving the program memory unmodified, and resetting all devices to their initial states.
  • 0x04
    This port is associated with the device name text buffer for slot 0xC. 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.
  • 0x05
    This port is associated with the device name text buffer for slot 0xD. The behaviour is the same as for port 0x04.
  • 0x06
    This port is associated with the device name text buffer for slot 0xE. The behaviour is the same as for port 0x04.
  • 0x07
    This port is associated with the device name text buffer for slot 0xF. The behaviour is the same as for port 0x04.
  • 0x08
    This port is associated with the system identifier text buffer. The behaviour is the same as for port 0x04.
  • 0x09
    This port is associated with the system authors text buffer. The behaviour is the same as for port 0x04.
  • 0x0A–0x0B
    Reading from this port group will return the number of bytes of program memory implemented on this system. If the number of bytes implemented is 65536, the value returned will be 0x0000.
  • 0x0C
    This port is associated with the working stack of the Bedrock system. Reading from this port will return the number of bytes of memory implemented for the associated stack on this system. If the number of bytes implemented is 256, the value returned will be 0x00.
  • 0x0D
    This port is associated with the return stack of the Bedrock system. The behaviour is the same as for port 0x0C.
  • 0x0E–0x0F
    Reading from this port group returns a device map, where each bit of the map is set only if a device is connected to the corresponding slot on the device bus.

Memory device specification

This section specifies the standard memory device of the Bedrock computer system. This device connects to slot 0x1 of the device bus.

The memory device provides access to up to 16 megabytes of additional working memory.

Overview

This device provides access to up to 16 megabytes of additional memory. The memory managed by this device uses a separate address space to the program memory.

Memory is allocated in 256-byte chunks, called pages, which form a contiguous array of bytes starting from memory address zero. Pages are allocated and deallocated from the end of this array. Accessing an unallocated memory address will cause undefined behaviour. When a page is allocated, the value of each byte on that page is zero. The initial number of pages allocated is zero, and the minimum and maximum numbers of pages that can be allocated are implementation defined.

Memory is accessed via two independent read-write heads (called head 1 and head 2). Each head contains an unsigned 16-bit page offset value and an unsigned 16-bit address offset value. The memory address that will be accessed by a given 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.

Ports

  • 0x10–0x11
    Reading from this port group will return the number of pages allocated. Writing to this port group will request that the number of pages allocated be changed to the value written. Pages will be sequentially allocated or deallocated until either the requested value or an implementation defined minimum or maximum value is reached. Write access is atomic.
  • 0x12–0x13
    This port group is associated with head 1. Reading from this port group will return the page offset of the associated head. Writing to this port group will set the page offset of the associated head to the value written.
  • 0x14–0x15
    This port group is associated with head 1. Reading from this port group will return the address offset of the associated head. Writing to this port group will set the address offset of the associated head to the value written.
  • 0x16
    This port is associated with head 1. Reading from this port will return the byte stored at the memory address referenced by the associated head, and then will increment the address offset of the associated head by 1, wrapping to zero on overflow.
  • 0x17
    This port is an alias for port 0x16.
  • 0x18–0x19
    Writing to this port group will request that a number of pages be copied equal to the value written. The initial source and destination page are given by the page offset value of head 2 and head 1, respectively. The contents of the source page will be copied into the destination page, the page following the source or destination page will become the new source or destination page, respectively, and the process will repeat until the requested number of pages has been copied. Copying to or from an unallocated page will cause undefined behaviour. Write access is atomic.
  • 0x1A–0x1B
    This port group is associated with head 2. The behaviour is the same as for port group 0x12–0x13.
  • 0x1C–0x1D
    This port group is associated with head 2. The behaviour is the same as for port group 0x14–0x15.
  • 0x1E
    This port is associated with head 2. The behaviour is the same as for port 0x16.
  • 0x1F
    This port is an alias for port 0x1E.

Wake flag

The wake flag of this device will never be set for this device.

Math device specification

This section specifies the standard math device of the Bedrock computer system. This device connects to slot 0x2 of the device bus.

The math device provides functionality for multiplying and dividing integers, and for converting between cartesian and polar coordinate systems.

Operands

Multiplication, division, and coordinate conversion operations are performed using a set of four unsigned 16-bit input values, called the x, y, r, and t operands. The initial value of each operand is zero.

The x and y operands represent a point in the cartesian coordinate system called the cartesian point. The x coordinate of this point is given by the x operand, and the y coordinate is given by the y operand. The x and y operands are treated as signed values for this purpose.

The r and t operands represent a point in the polar coordinate system called the polar point. The r coordinate of this point is given by the r operand, and the t coordinate is given by the t operand.

Coordinate systems

The cartesian coordinate system represents a point as the distance travelled from the origin along a horizontal axis and a vertical axis. A point is represented by an x coordinate, which gives the distance travelled along the horizontal axis as a signed 16-bit integer, and a y coordinate, which gives the distance travelled along the vertical axis as a signed 16-bit integer. The x and y coordinates of the origin are both zero.

The polar coordinate system represents a point as a radius measured between the origin and the point, and as an angle measured counter-clockwise around the origin from the positive horizontal axis to the point (starting towards the positive vertical axis). A point is represented by an r coordinate, which gives the length of the radius as an unsigned 16-bit integer, and a t coordinate, which gives the angle as an unsigned 16-bit integer. The r and t coordinates of the origin are both zero.

The distance units of the x, y, and r coordinates are all of equal length. The angle unit of the t coordinate is measured as one 65536th of a full turn. The origins of the two coordinate systems coincide.

Some points cannot be losslessly converted between coordinate systems. If either coordinate of a point would be fractional after conversion, that coordinate will instead be rounded down to the nearest integer (rounding towards zero). If either coordinate of a point would exceed the range of the type used to represent it after conversion (-32768 to 32767 inclusive for cartesian coordinates, 0 to 65535 inclusive for polar coordinates), a value of zero will be returned instead for both coordinates.

Ports

  • 0x20–0x21
    Reading from this port group will return the x coordinate of the polar point after conversion to the cartesian coordinate system. Writing to this port will set the value of the x operand to the value written.
  • 0x22–0x23
    Reading from this port group will return the y coordinate of the polar point after conversion to the cartesian coordinate system. Writing to this port will set the value of the y operand to the value written.
  • 0x24–0x25
    Reading from this port group will return the r coordinate of the cartesian point after conversion to the polar coordinate system. Writing to this port will set the value of the r operand to the value written.
  • 0x26–0x27
    Reading from this port group will return the t coordinate of the cartesian point after conversion to the polar coordinate system. Writing to this port will set the value of the t operand to the value written.
  • 0x28–0x2B
    Reading from this port group will return the product of the x and y operands.
  • 0x2C–0x2D
    Reading from this port group will return the quotient of the integer division of the x operand by the y operand. If the y operand is zero, the value returned will be zero.
  • 0x2E–0x2F
    Reading from this port group will return the remainder of the integer division of the x operand by the y operand. If the y operand is zero, the value returned will be zero.

Wake flag

The wake flag of this device will never be set for this device.

Clock device specification

This section specifies the standard clock device of the Bedrock computer system. This device connects to slot 0x3 of the device bus.

The clock device provides access to the current date and time, and to four high-resolution countdown timers.

Date and time

This device tracks the current date and time in the local timezone, with a resolution of one second.

The date and time can be set to a different value if supported by the host system. When writing to a port that would set a component of the date or time, the component associated with that port will be changed to the value written, with all other components left unchanged. Values which would exceed the maximum value of that component are ignored.

Countdown timers

This device contains four identical countdown timers, called timers 1 through 4. The resolution of each timer is one 256th of a second, called a tick. Each timer is represented by an unsigned 16-bit integer, representing the number of ticks remaining until that timer expires. Each timer will decrement by one for every tick elapsed, stopping once zero is reached. A timer expires when the value transitions from one to zero in this manner. The initial value of each timer is zero.

Ports

  • 0x30
    Reading from this port will return the number of full years elapsed since the start of the year 2000. The value returned from the year 2256 onwards is implementation-defined. Writing to this port will attempt to set the year component of the date and time to the value written. The maximum value is 255.
  • 0x31
    Reading from this port will return the number of full months elapsed since the start of the year. Writing to this port will attempt to set the month component of the date and time to the value written. The maximum value is 11.
  • 0x32
    Reading from this port will return the number of full days elapsed since the start of the month. Writing to this port will attempt to set the day component of the date and time to the value written. The maximum value is 28 when the month component is 1 and the year component is evenly divisible by 4, otherwise is 27 when the month component is 1, otherwise is 29 when the month component is 3, 5, 8, or 10, otherwise is 30.
  • 0x33
    Reading from this port will return the number of full hours elapsed since the start of the day. Writing to this port will attempt to set the hour component of the date and time to the value written. The maximum value is 23.
  • 0x34
    Reading from this port will return the number of full minutes elapsed since the start of the hour. Writing to this port will attempt to set the minute component of the date and time to the value written. The maximum value is 59.
  • 0x35
    Reading from this port will return the number of full seconds elapsed since the start of the minute. Writing to this port will attempt to set the second component of the date and time to the value written. The maximum value is 59. The value during a leap second is implementation defined.
  • 0x36–0x37
    Reading from this port group will return the number of ticks elapsed since the system started or was last reset. The value will wrap on overflow. Read access is atomic.
  • 0x38–0x39
    This port group is associated with timer 1. Reading from this port group will return the number of ticks remaining until the associated timer expires. Writing to this port group will set the number of ticks remaining until the associated timer expires to the value written. Read and write access is atomic.
  • 0x3A–0x3B
    This port group is associated with timer 2. The behaviour is the same as for port group 0x38–0x39.
  • 0x3C–0x3D
    This port group is associated with timer 3. The behaviour is the same as for port group 0x38–0x39.
  • 0x3E–0x3F
    This port group is associated with timer 4. The behaviour is the same as for port group 0x38–0x39.

Wake flag

The wake flag of this device will be set when any countdown timer expires.

Input device specification

This section specifies the standard input device of the Bedrock computer system. This device connects to slot 0x4 of the device bus.

The input device provides access to keyboard input, pointer input, and inputs from up to four game controllers.

Screen device specification

This section specifies the standard screen device of the Bedrock computer system. This device connects to slot 0x5 of the device bus.

The screen device provides access to a rectangular drawing surface with two layers and a configurable 16-colour palette.

Screen device specification

Tone device specification

This section specifies the standard tone device of the Bedrock computer system. This device connects to slot 0x6 of the device bus.

The tone device provides access to four tone generators TODO

Waveform device specification

This section specifies the standard waveform device of the Bedrock computer system. This device connects to slot 0x7 of the device bus.

The waveform device TODO

Stream device specification

This section specifies the standard stream device of the Bedrock computer system. This device connects to slot 0x8 of the device bus.

The stream device provides access to two bi-directional bytestream interfaces, one for communicating with a local system, and the other for connecting to a remote system via a network path. TODO

File device specification

This section specifies the standard file device of the Bedrock computer system. This device connects to slot 0x9 of the device bus.

The file device provides access to a hierarchical file system TODO

Clipboard device specification

This section specifies the standard clipboard device of the Bedrock computer system. This device connects to slot 0xA of the device bus.

The clipboard device provides access to TODO

Registry device specification

This section specifies the standard registry device of the Bedrock computer system. This device connects to slot 0xB of the device bus.

The registry device provides access to TODO

Debug device specification

GPIO device

  • Implementation-defined voltage.
  • Read mode back to check if mode change was valid (some pins might not allow one mode or the other).