Architecture manual

This is the user manual for the architecture of the Bedrock computer system.

This document is aimed at people who are learning about or writing programs for the Bedrock system. For people who are implementing the system from scratch, the architecture specification will provide more relevant information.

Overview

This document describes the core architecture required to run a Bedrock program.

Components

The Bedrock computer system is made up of four separate components: the program memory holds the current program, the two stacks hold temporary data, the device bus connects the system to peripheral devices, and the processor runs the program and ties the whole system together.

Program memory

The system has 64 kilobytes of program memory, which is used to store the current program. Each program instruction takes up one byte of memory, meaning that any one program can contain tens of thousands of instructions. Any assets and resources that a program uses (such as fonts and text) are packed into the program, so they will also be kept in program memory.

A program is able to modify itself by reading and writing to program memory. This is normally used for accessing resources that have been packed into the program, or for working with large pieces of data.

See the loading a program example.

Stacks

The system has two stacks, called the working stack and the return stack, with each one able to hold 256 bytes at a time. The stacks are used to store temporary values that are being used by the program, such as pointers and loop counters.

A stack is a data structure for storing bytes. When a byte is pushed onto a stack, it gets placed on top, above all of the previously pushed bytes. The byte at the top is the only byte that can be popped off, meaning that bytes have to be removed in the opposite order to how they were pushed on.

Stacks make it straightforward to use recursion in a program: the contents of a stack aren’t overwritten when a new value is pushed on, so any function can push values onto the stack and pop them off once they’re finished, and the stack will have been returned to exactly the state it was in before the function was called.

The working stack is normally used for working on values, and for passing arguments to functions. Arguments are pushed onto the stack, the function consumes them from the stack, and any return values are pushed onto the stack for later.

The return stack is normally used for storing return addresses for functions. Each address takes up two bytes on the stack, meaning that a program can recurse through 127 function calls at a time.

Device bus

The system uses a device bus to communicate with other devices, such as a mouse or keyboard. The device bus has slots for up to sixteen devices to connect to, and each slot has sixteen ports for reading and writing to the device.

The program can read a byte from a device port to get information out of the device, or can write a byte to a port to make the device perform an action. The device manuals section of the user manual lists all of the device manuals, which explain how to use the ports on each device.

Each port is addressed by a single byte. The first digit of the byte determines the device slot, and the second digit determines a port on that device. For example, port 86 points to port 6 (the ‘head’ port) of device 8 (the ‘stream’ device). Writing a byte to this port will print a character to the terminal.

Processor

The processor runs the program and controls the whole system, moving data between all of the other components.

The program is executed one instruction at a time, with a program counter keeping track of the address of the next instruction. The program counter starts at address zero and increments every time an instruction is loaded, moving through the entire program from top to bottom. Some instructions can write to the program counter, making it possible for programs to contain loops and branches. The instruction set manual describes the full instruction set used by the processor.

When a program is started, the byte stored at address zero is loaded into the processor, the program counter is incremented by one, and then the processor executes the instruction. Most instructions interact with the values on the top of the stacks, performing calculations or interacting with devices or memory. Once the instruction has finished, the process is repeated, with the byte at address one being the next to be loaded and executed.

See the running a program example.

Examples

Loading a program

A Bedrock program is a sequence of bytes, with each byte representing an instruction or a piece of data. The assembler is used to convert readable program source code into this byte format.

When a program is loaded into a Bedrock system, the bytes of that program are copied into program memory, starting from address zero. For example, look at the following Bedrock program. This will need to be assembled before it can be run:

PSH:05 PSH:03 SUB

This program assembles to the following five bytes. You can see that each instruction becomes a byte, and that the 05 and 03 bytes are embedded as data:

21 05 21 03 11

After this program is loaded into a Bedrock system, the first ten bytes of the program memory will be the following:

21 05 21 03 11 00 00 00 00 00 (...)

Running a program

The program counter keeps track of the address of the next instruction in memory, incrementing each time a byte is loaded. The following example shows the value of the program counter after each instruction is executed. The PSH: instruction loads the next byte 01 as data, so the program counter increments twice on the first line:

PSH: 01  ( counter is now 2 )
DUP      ( counter is now 3 )
ADD      ( counter is now 4 )
POP      ( counter is now 5 )

A jump instruction can be used to set the program counter, creating a loop in the program. The JMP instruction on the final line of this example will set the program counter to 2, which is the address of the DUP instruction. This will cause the program to jump back to the DUP instruction, looping endlessly:

PSH: 01    ( counter is now 2 )
DUP        ( counter is now 3 )
ADD        ( counter is now 4 )
POP        ( counter is now 5 )
JMP: 0002  ( counter is now 2 )