In Rainbows


Written 2026-10-06

rainbows is a specification for units related to the ok digital machine, named after Radiohead’s album In Rainbows. okay itself solely supplies instruction analysis and the “information” and “return” stacks for fundamental computation, however when you needed to output one thing to a display or a console, or obtain enter from a mouse or keyboard, you’d should “map” these units into reminiscence.

Memory Mapping

okay calls ok_mem_read(addr) every time it must learn a byte from RAM, and ok_mem_write(addr) every time it wants to write down a byte to RAM. These are features that you outline your self, as a way to make user-defined memory-mapping potential. For instance, with no memory-mapping, your definition of ok_mem_read would possibly seem like this:

// assuming "ram" is outlined as an array of bytes elsewhere
uint8_t ok_mem_read(size_t deal with) {
  return ram[address];
}

But, as an instance you need to have the ability to learn information from a console’s normal enter (stdin). You might map a “magic” location in RAM in order that studying a byte from this deal with reads information from stdin, like so:

#outline STDIN_MAGIC (3)

uint8_t ok_mem_read(size_t deal with) {
  if (deal with == STDIN_MAGIC) {
    char ch;
    learn(STDIN_FILENO, &ch, 1);
    return (uint8_t)ch;
  }

  return ram[address];
}

With this, studying a price from RAM at this deal with (in okay’s meeting language, that may seem like #000003 lod1) will learn a byte from stdin.

The thought behind rainbows is that it defines these magic values for you, as a way to present a normal set of enter/output units for somebody to use- turning okay into a correct “fantasy laptop” moderately than only a stack-based instruction evaluator.

Devices

rainbows continues to be actively being written, so these descriptions for the units it helps could turn out to be outdated moderately quickly (however I’ll attempt to replace this web page if I alter one thing).

As of proper now, I’ve both carried out or have plans to implement the next units (so as of how assured I’m of their present definition):

  • RbConsole, for interfacing with a POSIX-style CLI
  • RbArith, for offering extra handy math operations that okay does not help very effectively by itself
  • RbDisk, for offering disk I/O and protracted storage
  • RbDatetime, for offering date/time data
  • RbScreen, for offering a display/framebuffer

Now, we’ll go over the reminiscence format I’ve for the units I’ve carried out to date, in addition to any ideas I’ve for the units that I’m nonetheless not sure about. Expect the reminiscence addresses described under to vary as I work on rainbows extra!

RbConsole

RbConsole makes use of the next addresses- the numbers on the left facet of the desk are the addresses, and the textual content on the correct facet of the desk are the “names” of these addresses that the machine makes use of (consider them like struct fields):

|---------------------|
|      RbConsole      |
|--------+------------|
| 000000 | stdin (R)  |
|--------+------------|
| 000001 | stdout (W) |
|--------+------------|
| 000002 | argc (R)   |
|--------+------------|
| 000003 | arg_index  |
|--------+------------|
| 000004 | arg_char_i |
|--------+------------|
| 000005 | arg_char   |
|--------+------------|

Reading a byte from stdin, in fact, reads from stdin, and writing a byte to stdout does precisely what you’d count on it to.

argc shops the variety of command line arguments that had been supplied (like argc in C).

From right here it will get interesting- if you wish to learn a selected command line argument, you first write a price to arg_index to find out which command line argument you are taking a look at (0-indexed, in fact). Then, you write a price to arg_char_i to find out which character of the argument at arg_index you are taking a look at, after which studying a byte from arg_char reads that character, and can learn 0 when you’re on the finish or out of bounds.

So, studying a byte from arg_char is a bit like doing this (in C):

char* argument = argv[arg_index];
uint8_t arg_char = argument[arg_char_i];

It’s a bit clunky, however the various concepts that I had had been both to have the ability to retailer an argument at a selected location in reminiscence by writing that location into a spot within the RbConsole machine (which might imply RbConsole might manipulate any arbitrary place in reminiscence, which I did not like), or it might’ve meant that RbConsole would wish a buffer with a predefined size to retailer a person argument, which I did not wanna do since I wasn’t certain what an excellent predefined size could be (plus I did not really feel like having some type of error dealing with for if an argument was too lengthy to slot in the buffer).

This machine, as of proper now, is totally carried out!

RbArith

RbArith provides help for multiplication, division, and modulo, for 1, 2, 3, and 4-byte unsigned integers. Here is its reminiscence format:

|-----------------|
|     RbArith     |
|--------+--------|
| 000006 | op     |
|--------+--------|
| 000007 | err    |
|--------+--------|
| 000008 | width  |
|--------+--------|
| 000009 | x      |
| 00000a |        |
| 00000b |        |
| 00000c |        |
|--------+--------|
| 00000d | y      |
| 00000e |        |
| 00000f |        |
| 000010 |        |
|--------+--------|
| 000011 | outcome |
| 000012 |        |
| 000013 |        |
| 000014 |        |
|--------+--------|

When you write a magic worth to op, the operation related to that worth is carried out on x and y, with the outcome being saved in outcome. When this operation is carried out, x, y, and outcome are handled as having a width of width - 1 (so 3 treats them as 4-byte values, 2 as 3-byte values, 1 as 2-byte values, and 0 as 1-byte values). The values that op can tackle are as follows:

  • 0 is a no-op, no operation is carried out.
  • 1 shops x * y into outcome
  • 2 shops x / y into outcome, setting err to 1 if y is 0
  • 3 shops x % y into outcome, setting err to 2 if y is 0

I’ll add different math operations (or maybe random quantity technology?) sooner or later. If/after I do, I’ll simply add them as new values that op might tackle (5, 6, and many others).

RbDisk

RbDisk supplies disk I/O utilizing a library I wrote lately, which I speak extra about in my “Playing with Blocks” article.

RbDisk‘s reminiscence format is as follows:

|----------------------------|
|           RbDisk           |
|--------+-------------------|
| 000015 | capability          |
| 000016 |                   |
| 000017 |                   |
| 000018 |                   |
|--------+-------------------|
| 000019 | replace            |
|--------+-------------------|
| 00001a | error             |
|--------+-------------------|
| 00001b | present           |
| 00001c |                   |
| 00001d |                   |
| 00001e |                   |
|--------+-------------------|
| 00001f | information (1024 bytes) |
| ...    |                   |
| 00041e |                   |
|--------+-------------------|

When you run the emulator for rainbows, you present a BlockFile (described in additional element within the article I discussed earier) or can select to create a brand new one. This file has a set capability, i.e. a max variety of 1024-byte “blocks” which can be saved inside it. This worth is saved in capability.

Note: if/after I ever determine to get rainbows operating on bare-metal (with out an underlying OS), moderately than utilizing a BlockFile, it might simply use the free area of the disk itself.

You can then learn a price from replace to load the contents of the block at index present into information. Writing a price to replace will then retailer information to the block at index present.

RbDatetime

This machine I’m nonetheless not sure about- the thought behind RbDatetime is that it supplies clock/date information, however I’m unsure precisely how advanced I would like it to be. I thought of taking inspiration from (i.e. principally stealing) how Varvara‘s datetime machine works, and simply have addresses in reminiscence that retailer the present yr, day, day of the week, hours, minutes, seconds, whether or not we’re in daylight financial savings time, and many others:

Varvara's datetime device

But I’ve additionally thought-about simply storing the 64-bit Unix time (i.e. the variety of “non-leap” seconds since midnight of January 1st, 1970, UTC), and simply writing software program that determines the date utilizing this information- though this would not be tremendous handy, contemplating that okay solely helps a most integer width of 32 bits. Some programs nonetheless retailer Unix time as a 32-bit worth, however this could imply that the worth would overflow in early 2038, which is a bit too quickly for me to justify utilizing it.

Plus, there’s the difficulty of representing smaller models of time like milliseconds, which can be good to have relying on what I wish to make.

All in all, this machine continues to be a work-in-progress. When I add it although, I’ve a sense I’ll put it earlier than the RbDisk machine, that means that the addresses for the desk above would must be up to date.

RbScreen

This is one other machine that I’m moderately not sure about.

For one factor, I do not know what number of colours I’d wish to support- Varvara makes use of 2-bit colour, permitting for a most of 4 totally different colours, however I’ve thought of including a solution to set the “colour mode” for the display. For smaller colour depth values, like 1, 2, 4, and 5-bit colour, they can set a palette, whereas for bigger values, I’ve thought-about including help for 8-bit colour (maybe utilizing RGB332, utilizing 3 bits for “purple”, 3 bits for “inexperienced”, and two for “blue”), in addition to 16-bit “excessive” colour (utilizing RGB565), and perhaps even 24-bit “true” colour.

However, for bigger colour depth values and bigger display resolutions, the reminiscence utilization grows moderately massive. For instance, a 1024×600 display utilizing 24-bit colour would have a framebuffer that takes up 1800 kibibytes (the place a kibibyte is 1024 bytes) of reminiscence, i.e. round 11% of the entire reminiscence that okay can entry.

Screen decision itself is an entire different problem- do I wish to permit the consumer to outline the display dimension themselves? This would permit for resizable home windows, which might be good for operating rainbows as only a program in your system, however then I’d must have one thing like a framebuffer_addr discipline within the part of reminiscence for RbScreen, pointing to the place the framebuffer begins, after which any software program focusing on rainbows must account for that (i.e. attempt to not by accident overwrite that part of reminiscence throughout computation).

This brings up different considerations too- as an illustration, potential help for multiple buffering.

If I did not permit for a resizable display/window, I’d then must determine what decision I’d wish to have, in addition to what side ratio I’d need. Right now, certainly one of my foremost objectives is to get rainbows operating bare-metal on slightly laptop computer I name my zen machine (which I have never written about but, however I’ll ultimately). This laptop computer has a decision of 1024×600 pixels, which is a bit nonstandard (it is not likely 16:9 or 4:3). I’ve additionally debated utilizing a 4:3 side ratio (maybe 640×480), largely simply because I like 4:3 a lot, however then operating rainbows full-screen could look bizarre on a 16:9 show.

As you may see, RbScreen is a tool that I’ve thought lots about, and nonetheless have not actually come to a selected resolution that I like. At this level it is actually preserving me up at night time, and has been since I used to be first writing about okay.

Other concepts for units

In phrases of different units I’d wish to outline/implement ultimately, I’ve thought a bit about an RbKeyboard machine for studying keyboard enter (maybe utilizing one thing like a round character buffer to trace a number of keypresses without delay?). Ideally, RbKeyboard would additionally help some “controller” performance, like how Varvara‘s “controller” machine helps each keyboard keys in addition to treating sure keys (like ctrl, alt, shift, and residence) as if they had been keys on a Nintendo machine (i.e. A, B, Select, and Start). I’ve debated solely utilizing a sure subset of the keyboard, as I fairly like utilizing a 60% or 75% keyboard format.

a 60% keyboard layout

Another machine I’ve strongly thought-about is RbFloat, a tool for working with 32-bit floating level values, though ideally this machine should not be that “important” for operating applications on rainbows (as maybe I’ll attempt to get rainbows software program operating on a system that does not precisely adhere to, or does not even use, the 32-bit floating level normal).

Something of notice is that I have never actually thought of a “mouse” device- personally, I do not actually like utilizing a mouse or trackpad of any type, so I have never prioritized making a tool for one. I’ll undoubtedly implement one ultimately, however I wish to (by some means) encourage software program written for rainbows to be keyboard first, i.e. all software program operating on rainbows ought to be completely usable with no mouse or pointing machine in any respect. This is very essential for working with the zen machine, since although it does have a trackpad, it’s extremely small, and the left-click button is damaged past restore (and I can not discover a lot information about alternative elements or the way to restore it generally).

I additionally have not actually thought a lot about supporting audio, as I really feel like this could be fairly the rabbit gap (do I help audio synthesis? Audio samples? MIDI? Some mixture of the three? Or perhaps I might make my very own audio format…).

I have never thought-about a networking machine for comparable reasons- though I’ve thought of including a tool that principally acts as a very-barebones Gemini protocol shopper, since I like utilizing Gemini lots.

Conclusions

As you may see, although I’ve been actively engaged on rainbows for some time, it is nonetheless received a protracted solution to go. I first began sketching concepts for it again after I wrote my undergraduate thesis on okay, the place initially I had thought-about implementing rainbows for the latter-half of the thesis moderately than trying to implement a compiler. I rapidly realized that simply writing a specification for it was a hell of an endeavor, not to mention implementing it.

As of proper now, my purpose is to at the very least get RbConsole, RbDisk, and RbArith totally carried out, after which from there I may fit on a easy compiled language (POP-2000, anybody?) to check their performance and begin writing some “helpful” software program for rainbows earlier than transferring on.

In the meantime, I’ll maintain this text up-to-date every time some new developments happen, and I hope you loved listening to me ramble in regards to the rabbit gap that this mission has taken me down.



Source link