What’s a computer without I/O? Hot Silicon At Best…

[FYI: Matt Hellige’s excellent GoForth runs on this]

I’m completely astonished at how quickly a community has sprung up around Notch’s DCPU-16. In the first 24 hours there were already tens of implementations in various languages (including mine). Now there’s a web-based IDE, a whole C compiler/assembler tool chain, an LLVM backend, … It’s craziness!

So I’m way behind in the times (almost a week has gone by!), but I’m now adding I/O to my emulator. Notch has yet to officially publish any I/O specs, but there seems to be a de facto standard. Input is a 16-cell ring buffer at 0x9000 and video is 32x12 cells memory mapped at 0x8000 with characters and foreground/background colors encoded in the high byte. I’ll support everything from this spec (in 25 lines of F#!) except fonts and blinking; just using the standard console.


Input is easy enough. Just call this on every cycle:

 open Systemlet mutable buf = 0let input () =    let buffer = 0x9000    let size = 16    if Console.KeyAvailable then<br>        let b = buffer + buf<br>        memory.[b] <- uint16 (Console.ReadKey true).KeyChar        if memory.[b] = 13us then memory.[b] <- 10us // CR –> LF        memory.[buffer + size] <- uint16 (b)<br>        buf <- (buf + 1) % size


Output too is pretty simple. The output function is called on every memory set:

 let vidwidth, vidheight = 32, 12<br>Console.Clear()<br>Console.WindowWidth <- vidwidth<br>Console.WindowHeight <- vidheight<br>Console.Title <- "F# DCPU-16"let output i =    let vidmem = 0x8000    if i >= vidmem && i <= vidmem + vidwidth * vidheight then<br>        let p = i - vidmem<br>        Console.SetCursorPosition(p % vidwidth, p / vidwidth)        let v = int memory.[i]<br>        Console.BackgroundColor <- (v >>> 8) &&& 0x0f |> enum<br>        Console.ForegroundColor <- v >>> 12 |> enum<br>        Console.Write(v &&& 0x7f |> char) 


I still have no assembler. I’m working on a Forth instead. For now just straight machine code (fun!):

 let boot image = List.iteri (fun i c -> memory.[i] <- uint16 c) image; cycle () 

You could modify to load an image from a file and use with the DCPU Toolchain if you like. For a quick demo, let’s just take a couple of samples from the wonderful http://0x10co.de site:

  // Screen test (see http://0x10co.de/y5096)boot [0x7c01; 0xf030; 0x7c61; 0x8000; 0x7c0c; 0xf838; 0x7c03; 0xf000<br>      0x7c0c; 0x0a3a; 0x9c02; 0x00e1; 0x7c02; 0x0101; 0x8462; 0x19fe<br>      0x8010; 0x7dc1; 0x0004; 0x0020; 0x0000] 


 // Keyboard test (see http://0x10co.de/h6bbv)boot [0x7c01; 0x8000; 0x8021; 0x8011; 0x4811; 0x0063; 0x781a; 0x0062<br>      0x0481; 0x8402; 0x8422; 0x812d; 0x0063; 0x7dc1; 0x0004; 0x81ec<br>      0x9010; 0x7dc1; 0x000f; 0x7c10; 0x0056; 0x7c81; 0x20df; 0x81ec<br>      0x9010; 0x7dc1; 0x0015; 0x7821; 0x9010; 0x2811; 0x81e1; 0x9010<br>      0x8021; 0x8121; 0x9000; 0x8422; 0xc02d; 0x7dc1; 0x0021; 0xa01c<br>      0x7c10; 0x0037; 0xa81c; 0x7c10; 0x0044; 0x781a; 0x0062; 0x0481<br>      0x8402; 0x7c0e; 0x817f; 0x7dc1; 0x000f; 0x7dc1; 0x0015; 0x7c81<br>      0x0020; 0x7c0d; 0x8000; 0x8403; 0x788a; 0x0062; 0x7c8c; 0x2020<br>      0x7dc1; 0x0037; 0x7dc1; 0x0015; 0x7c0e; 0x815f; 0x7dc1; 0x0015<br>      0x7c81; 0xf000; 0x7c03; 0x8000; 0x7c02; 0x0020; 0x7c05; 0x0020<br>      0x7c04; 0x0020; 0x7c02; 0x8000; 0x7dc1; 0x0015; 0x7c01; 0x8000<br>      0x7c81; 0x0020; 0x8402; 0x7c0d; 0x8180; 0x7dc1; 0x0058; 0x7c01<br>      0x8000; 0x61c1; 0x2000; 0x0054; 0x0079; 0x0070; 0x0065; 0x0020<br>      0x0073; 0x006f; 0x006d; 0x0065; 0x0074; 0x0068; 0x0069; 0x006e<br>      0x0067; 0x0021; 0x0000; 0x0000]


  // Matrix Screen Saver (see http://0x10co.de/gpoke)boot [0x7c51; 0x1234; 0x1441; 0x7dc1; 0x0009; 0x7c44; 0x274d; 0x8442<br>      0x61c1; 0x8061; 0x1031; 0x1441; 0x7c01; 0x8000; 0x8071; 0x7c10<br>      0x0005; 0x808c; 0x7dc1; 0x0024; 0x7c4f; 0x7000; 0x7dc1; 0x0024<br>      0x11a1; 0x0c41; 0x7c10; 0x0005; 0x7c89; 0xff00; 0x7c49; 0x003f<br>      0x508a; 0x0080; 0x1031; 0x6041; 0x8472; 0x8402; 0x1dfe; 0x0020<br>      0x7dc1; 0x000f; 0x8462; 0x1ace; 0x7dc1; 0x000e; 0x0c41; 0xb061<br>      0x7c01; 0x817f; 0x7c71; 0x0020; 0x808c; 0x7dc1; 0x004d; 0x7d0f<br>      0x0020; 0xffff; 0x7dc1; 0x004f; 0x7c10; 0x0005; 0x2101; 0x0020<br>      0x7d09; 0x0020; 0xff00; 0x1031; 0x7c39; 0x003f; 0x4d0a; 0x0020<br>      0x0080; 0x7c89; 0x7fff; 0x7dc1; 0x0052; 0x8101; 0x0020; 0x7d09<br>      0x0020; 0x7fff; 0x8473; 0x8403; 0x807e; 0x7dc1; 0x0034; 0x8463<br>      0x806e; 0x7dc1; 0x0032; 0x0c41; 0x7c01; 0x8000; 0x8071; 0x7c10<br>      0x0005; 0x7c4f; 0x0700; 0x7dc1; 0x0077; 0x7c8f; 0xffff; 0x7dc1<br>      0x0076; 0x7c81; 0x2000; 0x7c4f; 0x0800; 0x7c81; 0xa000; 0x1031<br>      0x7c39; 0x003f; 0x4c8a; 0x0080; 0x7dc1; 0x0077; 0x8081; 0x8472<br>      0x8402; 0x1dfe; 0x0020; 0x7dc1; 0x005f; 0x7dc1; 0x0009; 0x85c3<br>      0x0030; 0x0030; 0x0031; 0x0031; 0x0032; 0x0033; 0x0033; 0x0034<br>      0x0035; 0x0036; 0x0037; 0x0038; 0x0038; 0x0039; 0x0026; 0x007c<br>      0x007c; 0x0021; 0x0021; 0x0040; 0x003d; 0x003d; 0x003a; 0x003a<br>      0x002a; 0x002a; 0x0023; 0x0023; 0x003c; 0x003e; 0x003e; 0x005f<br>      0x005f; 0x0054; 0x0059; 0x0059; 0x0055; 0x0044; 0x0051; 0x005a<br>      0x004a; 0x004a; 0x0049; 0x0058; 0x002d; 0x0020; 0x007e; 0x007e<br>      0x006f; 0x0069; 0x0077; 0x006c; 0x0072; 0x006b; 0x006d; 0x002f<br>      0x002f; 0x005c; 0x0027; 0x005b; 0x005d; 0x005e; 0x0029; 0x0060] 


  // Psychedelic Screensaver (see http://0x10co.de/4r80g)boot [0x7801; 0x002c; 0x7c10; 0x0025; 0x01e1; 0x002c; 0x0011; 0x7c16<br>      0x004f; 0x7c12; 0x0021; 0x7801; 0x002d; 0x7c10; 0x0025; 0x01e1<br>      0x002d; 0x7c09; 0xf000; 0x001a; 0x7801; 0x002e; 0x7c10; 0x0025<br>      0x01e1; 0x002e; 0x7c06; 0x0180; 0x0501; 0x8000; 0x8071; 0x8472<br>      0x1f4e; 0x7dc1; 0x001f; 0x7dc1; 0x0000; 0x19a1; 0x0061; 0x1864<br>      0x946a; 0x1802; 0x6061; 0x61c1; 0x3241; 0x3432; 0x2837; 0x0000] 


Pretty fun stuff!