The PCJr was a failure of a computer created by IBM in the 80’s. At its heart is the Intel 8088 CPU. CSH happened to acquire one back in the day, and another more recently after a member interned at IBM. For a hackathon a few friends and I decided to try and write an OS for the machine. Our original goal was to get a lisp interpreter running on it, and try and emulate a TCP stack using the PCJunior’s serial port. We fell short on all our goals, so in a last ditch effort I used the base kernel we developed and wrote a small BF interpreter.
The BF Language
BF is a very simple language. The easiest way to think about BF is as a series of operations on a pointer into an array. The simplest specification for bf is below.
|array||An array of 30K bytes|
|ptr||The pointer into the array|
|iptr||The current instruction being executed|
|<||Decrement the pointer|
|>||Increment the pointer|
|-||Decrement the value at the pointer|
|+||Increment the value at the pointer|
|.||Print out the value at the pointer|
|,||Set the value at the pointer to a single character from input|
|[||Loop start, skip to matching
|[||Loop end, jump to matching
A full, but simple BF program looks like this.
This program takes 2 numbers in cells 1 and 2 and multiplies them together and puts the result in cell 3. BF programs are very verbose, but the core concepts are pretty simple.
The Interpreter Implementation
The interpreter is pretty simple, and is only 346 lines total. The main loop of the reads key presses using an interrupt, and uses them to fill a buffer. When enter is pressed the entire program is then parsed and executed.
Building the Loop Table
The interpreter goes through two phases in order to execute the brainfuck code. The first phase is the loop phase which looks for loop statements within the input code and builds a table of jump offsets so it can make the actual looping logic easier to write. Instead of making a complex stack during run time we do our loop test and then if we need to exit the loop we just lookup the jump position in our jump table.
Running the Code
To actually run through the code the interpreter starts at the first address in the input buffer and moves forward, keeping track of its position using an instruction pointer. Actual evaluation is done by a big long chain of cmp statements.
I’m currently working on a memory allocator and scheduler for the kernel. Once those are finished I plan on making a more complete operation system including a shell of some kind.
Rob Glossop and James Forcier are also working on the OS with me, and contributed significant parts.
Example of BF Running on actual hardware
View post on imgur.com
X86: Compatible To the Ends of the Universe