Bedrock specification (rev. 3)

Overview

This document is the complete specification for the Bedrock 8-bit computer system, a stable and ultra-portable platform for creating compact applications to run on any hardware imaginable. The system is implemented either as a thin emulator on top of any existing computer system, or as a bespoke piece of hardware built around any basic microcontroller. A broad set of device interfaces allows systems to expose a wide range of hardware capabilities.

The purpose of this document is to enable any person to implement an entire working system from scratch. Implementers will want to start by reading and implementing the architecture specification (required to run Bedrock programs), followed by any number of device specifications (required for programs to interface with 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, with all other specifications describing either standard tooling and formats, or devices that expose hardware capabilities to an existing system.

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 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 useful hardware capabilities. These devices are optional enhancements and are not required to be implemented, however most programs will be of limited use unless at least a couple of these devices are present. 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 and are not required or 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 (the high-order byte comes before the low-order byte).
  • Array
    An array is a fixed-length block of bytes. Each byte is 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.
  • Bit
    TODO. Highest order, lowest order??

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 an integer increases beyond the range that can be represented by the underlying bytes. An integer greater than 255 will overflow a byte, and an integer greater than 65535 will overflow a double.
  • Underflow
    Underflow occurs when an integer decreases below the range that can be represented by the underlying bytes. Any negative integer will underflow a byte or double.
  • Wrap
    Wrapping occurs when a value would overflow or underflow. TODO.
  • Access
    Accessing a memory address or port means to read or write a value from that memory address or port.

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 specification 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 treated as 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 an assembler program that will be able to convert a human-readable source file into a program that can run on the Bedrock computer system.

Source file

A source file is a sequence of characters, where each character is a 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 into 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 until 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 the token is exactly ).
  • { 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 a / character, 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 a ~ character, replace this character with the name of the most recent global label (or an empty string if none), followed by a / character. 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 distinguished from other file types, and provides a way for systems to retrieve basic information about a program.

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 metadata values. Each pointer in the table is a double representing the program address where a specific 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 a / character, followed by the program version. The program name and version must not contain a / character 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 a 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 a 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.

This device provides information about the Bedrock system, and allows a program to sleep, fork, and reset the system.

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 a / character, followed by the implementation version. The implementation name and version must not contain a / character 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

  • 0x000x01
    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. It behaves the same as port 0x04.
  • 0x06
    This port is associated with the device name text buffer for slot 0xE. It behaves the same as port 0x04.
  • 0x07
    This port is associated with the device name text buffer for slot 0xF. It behaves the same as port 0x04.
  • 0x08
    This port is associated with the system identifier text buffer. It behaves the same as port 0x04.
  • 0x09
    This port is associated with the system authors text buffer. It behaves the same as port 0x04.
  • 0x0A0x0B
    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. It behaves the same as port 0x0C.
  • 0x0E0x0F
    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

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

Overview

This device provides access to up to 16 megabytes of additional memory. The memory managed by this device does not share an address space with the program memory.

Memory is allocated in 256-byte chunks, called pages, which form a contiguous array of bytes starting from 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

  • 0x100x11
    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.
  • 0x120x13
    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.
  • 0x140x15
    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.
  • 0x180x19
    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.
  • 0x1A0x1B
    This port group is associated with head 2. It behaves the same as port group 0x120x13.
  • 0x1C0x1D
    This port group is associated with head 2. It behaves the same as port group 0x140x15.
  • 0x1E
    This port is associated with head 2. It behaves the same as port 0x16.
  • 0x1F
    This port is an alias for port 0x1E.

Clock device specification

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

Overview

Four timers

Screen device specification

Debug device

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).