

Notch's Specification for the In-Game DCPU-16 - pros
http://0x10c.com/doc/dcpu-16.txt

======
unwind
Just waiting for the first post about programming this CPU to pop up on Stack
Overflow ... :)

It's quite an interesting architecture. From an initial perusal, I found these
features note-worthy:

* Explicit access to PC as a register, makes "computed goto" trivial and very natural.

* Because of the above, there is no JMP instruction.

* Treating operations on registers as "values" makes the instruction set very orthogonal.

* No instructions for bit-manipulation.

* Lots of possible NOP instructions, like "SET PC,PC" (which I _think_ should work, depends a bit on exactly when it's incremented but it looks safe).

* Word-addressed memory will make string processing interesting to implement. Maybe in space, everyone uses UTF-16.

* Single 64 K address space will put quite the limit on the amount of code, I guess the game will show how much code is needed to do anything.

* No I/O instructions means I/O must be memory-mapped, further reducing the space available for code. Maybe there will be bank-switching?

* No interrupts.

~~~
wagabond
I'm a self-taught programmer, and don't know much about CPUs. Would someone
mind putting this into relatively plain english, I'm quite curious to know the
practical implications of this. Can we expect to see Python running on it in
the near future for example :) ?

~~~
nknight
Although some of the implications require experience to understand, I'd say it
already _is_ in "relatively plain English", you simply haven't been exposed to
the vocabulary and concepts necessary. Trying to explain in any detail would
basically be reproducing Wikipedia, so here are some links:

<http://en.wikipedia.org/wiki/Program_counter>

<http://en.wikipedia.org/wiki/Word_(computer_architecture)>

<http://en.wikipedia.org/wiki/JMP_(x86_instruction)>

<http://en.wikipedia.org/wiki/NOP>

<http://en.wikipedia.org/wiki/Orthogonal#Computer_science>

<http://en.wikipedia.org/wiki/Address_space>

<http://en.wikipedia.org/wiki/Memory-mapped_I/O>

<http://en.wikipedia.org/wiki/Interrupt>

And no, don't expect Python anytime soon. Expect a C compiler, FORTH, possibly
some sort of Pascal, but a highly dynamic language is unlikely. The system is
too resource-constrained to make it practical. A static language that looks
kind of like Python isn't out of the question, but it won't do a lot of the
things you expect from Python, Ruby, PHP, or Perl.

~~~
ac
A smarter way might be just implementing a new LLVM backend (gives us C via
Clang, some other languages). However, even with C, the standard library
probably won't leave much space for the user code itself -- so you might need
something slimmer. Also, some kind of simple RTOS (www.freertos.org, maybe?)
to run all these programs (I assume people would really want to run several
programs at a time). I wonder if the 128k limitation was intentional, to make
programming the computers more interesting. Anyway, I'm actually looking
forward to seeing what kind of clever solutions the players come up with.

~~~
jmaygarden
An RTOS won't be of much use without interrupts. You could implement
coroutines, but preemptive scheduling is not possible.

~~~
javert
Moreover, it would be very surprising if low-latency or deterministic timing
properties would actally be useful in the game.

------
phoboslab
Now here's an interesting bit:

 _"Question: can we trade the programs we create? How will you stop malicious
viruses etc?"_

 _"yes. And I won't stop viruses, the players will have to do that
themselves."_

~ <https://twitter.com/#!/notch/status/187474819980328962>

~~~
jiggy2011
I worry about the griefing potential here.

I can imagine nothing pissing off a noob more than getting a virus within 10
minutes of play and having no idea how to stop his ship from self destructing.

Perhaps this will need some sort of firewall system built in where ships
cannot communicate unless ports have been explicitly opened. Perhaps some sort
of communications proxy that can serve for safe communications.

It could have a system similar to EVE where high security systems have
infrastructural to mitigate risk whereas low sec systems lack this but contain
the best rewards.

~~~
nknight
Firewall? Ports? Communication proxy?

It has 64K 16-bit words. What _exactly_ are you expecting the default software
to do that opens it up to viruses?

~~~
jerf
Do not underestimate those old computers. When you remove audio, visual, and
textual data from your programs, remove all the code for handling those and
slinging them about and processing them, when you remove the textual file
formats and replace them with hand-optimized binary, when you give up on any
form of structured modern programming and just hand-compile custom assembler,
when your opcodes aren't 64-bits wide, and so on and so on, you can get a lot
done in 128KB of code.

Obligatory (but illustrative of my point):
<http://www.pbm.com/~lindahl/mel.html>

~~~
stephengillie
Exactly. Remember the 64kb video demos from 2004?

<http://www.theproduct.de/>

~~~
jlawer
Problem was most of the demos used many many megs of ram as they procedurally
generated objects and stored them in memory. The 64k demos were disk size.

Assuming memory mapping is used for displays the (128k of ram (64k of words))
is also needed to hold your display buffer. Assuming a mere 320 x 200 x 8
screen will use 1/2 of your entire virtual memory space. Look for demos of
what people do on C64 demos for a better idea. Yes you can run a UNIX, yes you
can talk TCP... but its going to chew up a lot of the capacity for that
infrastructure. I expect very light weight protocols, TCP/IP is likely too
heavy weight.

------
SideburnsOfDoom
Context:

For those who are puzzled (as I was) as to what this CPU is _for_ , I found
this:

> Notch's next game, 0x10c, "will allow players to create their own spaceship
> in the far, far future of an alternate universe ... More exciting -
> especially for those versed in programming languages - is the ship's
> computer. It's a fully-functional 16-Bit CPU that controls the entire
> vessel..." [http://www.dealspwn.com/notchs-space-trading-game-real-
> calle...](http://www.dealspwn.com/notchs-space-trading-game-real-
> called-0x10c-98501)

Also: [http://www.theverge.com/2012/4/4/2924594/minecraft-
creator-n...](http://www.theverge.com/2012/4/4/2924594/minecraft-creator-
notch-names-next-project-0x10c-sci-fi-game)

<http://0x10c.com/>

~~~
stephengillie
It's good to see Notch working on the Little Coder problem, even if that's not
his direct intention. :)

~~~
SideburnsOfDoom
Little Coder problem = how to get people interested in coding by writing
little programs. Hard to do on consoles and iPhones.

I started thinking that if I was going to get people interested in coding, I'd
start with something more approachable - maybe something like a subset of
Python, Java, Ruby or even JavaScript (it's where so many people write little
programs anyway now). I heard Lua mentioned as a good scripting language too.

Then I wondered - is this CPU a reasonable target for those kinds of little
languages? Is this a way to be language independent and have them all? If so,
why not something more like the JVM to make it easy?

It seems to me that coding for this CPU is more like a mini-game in the main
game; the fact that it's a challenge is part of the game.

~~~
Zaak
It is possible that someone will implement versions of those languages, but
this CPU is so memory and speed constrained that you'd be hard pressed to get
much useful done. And if the speed of your programs executing turns out to be
relevant to success in the game, then people using an interpreted language
will be at a possibly decisive disadvantage.

That said, I can see a nice friendly language becoming popular for non-time-
critical tasks where ease of experimentation is most important. I just hope
it's not BASIC. :)

------
evilpie
Just for fun, I wrote a disassembler for his instruction set.
<https://gist.github.com/2300590>

I previously wrote some assembler routines for x86, which is very complex,
working with Notch's design is a breeze and actually enjoyable.

Does he somewhere mention if the code is loaded into the RAM? This would make
self-modifiable code possible.

~~~
evincarofautumn
It doesn’t say in the spec, unless you interpret the memory dump for his
assembled example as residing at _address_ 0x0000 rather than _offset_ 0x0000.
But I don’t see any reason why PC shouldn’t refer to a RAM address. It would
be great for code economy in such a constrained system.

~~~
eridius
It's definitely loaded into ram. Some of the operands are defined in terms of
"next word of ram", which clearly refers to reading (and incrementing) the PC.

------
SimHacker
Can't wait to see FORTH running on this CPU!

FORTH ?KNOW IF HONK ELSE FORTH LEARN THEN

~~~
tvorryn
That's my plan actually. It should be a lot easier to get going than C or an
LLVM backend as others are suggesting.

~~~
RodgerTheGreat
Same here. The main design decision is how to represent the secondary stack. I
was thinking we could reserve a pair of registers to keep the parameter stack
pointer and return stack pointer, and swap them out with SP as needed.

    
    
      1 2 + >r
    

becomes something like

    
    
      SET PUSH, 0x1
      SET PUSH, 0x2
      SET A, POP
      ADD A, POP
      SET X, SP // back up data stack pointer
      SET SP, Y // switch to return stack
      SET PUSH, A
    

Thoughts?

~~~
ericbb
My first try would probably be to use SP for one stack and some other fixed
register for the other stack. Also, traditional Forth interpreters don't use
code like you showed. I think the main benefit of using Forth (unless you just
happen to love RPN) is the compactness of the interpreted code. If you're not
going to use an interpreter, then I'm not sure if Forth is really a win.

Edit: Just to clarify about the interpreter point, I'd expect something like
"1 2 + >r" to be represented at run time as four words in memory and there'd
be an interpreter, written in machine code, reading code word sequences and
jumping to small bits of machine code to either do a built-in function or push
the call stack.

~~~
RodgerTheGreat
What you've described is a threaded Forth, which is indeed the most common
type of implementation. I was thinking about writing a subroutine-threaded (no
inner interpreter) Forth that inlines common primitives and does some peephole
optimization. Not necessarily as compact, but much faster. Forth still
provides a flexible, structured programming environment compared to raw
assembly, to say nothing of Forth's metaprogramming facilities. I'd also say
that a fair amount of Forth's compactness comes from the programming style-
lots of tiny subroutines allowing extensive code reuse.

~~~
ericbb
That's interesting. Sorry for not getting it right away. It's making more
sense on second reading. :)

Now I'm curious how you'd encode subroutine calls. Your example was completely
inlined but the call-sequence will be critical in determining how compact the
code ends up.

Also, were you thinking of using a cross-compiler and keeping the dictionary
out of the DCPU-16s memory? Let me know if you create a public repo. I'd be
interested to see what you come up with!

~~~
RodgerTheGreat
No worries, I should've been more detailed in my original post- what I'm
describing is definitely an atypical (if not unprecedented) Forth. I agree,
the call-sequence is critical. My initial thought was to ensure that we always
leave the stack pointers in "return stack mode" before calling, and return
them to that state before exiting a routine. Thus, procedures:

    
    
      : A   dup * ;
      : B   2 A A 1 A ;
    

would look like:

    
    
      A:
        SET Y, SP
        SET SP, X // switch to data
        SET PUSH, PEEK
        SET A, POP
        SET B, POP
        MUL A, B
        SET PUSH, A
        SET X, SP
        SET SP, Y // switch to return
        SET PC, POP
    
      B:
        SET Y, SP
        SET SP, X // switch to data
        SET PUSH, 2
        SET X, SP
        SET SP, Y // switch to return
        JSR A
        JSR A
        SET Y, SP
        SET SP, X // switch to data
        SET PUSH, 1
        SET X, SP
        SET SP, Y // switch to return
        JSR A
    

As you can see, a little bulky, but doable. Optimizing stack operations to
make better use of the registers can get rather nasty- still thinking about
the best way to approach it. I'm definitely thinking in terms of a cross-
compiler, and ignoring things like defining words for the sake of simplicity,
at least at first. I'll drop you a comment if I get a prototype working.

------
acron0
I will admit, I used to think Notch was just a regular-joe programmer who had
gotten extremely lucky with his strain of adventure game.

Now I know I was dead wrong.

~~~
Ralith
Emulating a very simple computer like this isn't hard at all; it's basically
just a big array for memory, a few variables for registers, and a switch
statement for instruction handling.

~~~
starwed
I _think_ OP's point was not that Notch was a stellar programmer, but that he
is a good game designer. (And that the popularity of Minecraft was a result of
his skill and not of luck.)

------
davedx
I guess we'll be able to write our own malware to take over other peoples'
ships, then? Pretty awesome, just call me Locutus :)

~~~
gnarbarian
the borg vs the binars.

------
DanBC
This might be a stupid question but where does the output go? Is it just a
memory location? And does that memory location map to a "ship function"?

So, er, on a PC if I write data to address 0x378 it'll appear on LPT1. What's
the equivalent on DCPU-16? If I write data to a certain address it'll appear
on the missile bay ports?

Or is there a level of abstraction?

~~~
a-priori
If I had to guess, he's going to implement memory-mapped I/O. So, there's
going to be another specification that lists various memory locations'
functions. Reading from some will return information about the ship's systems;
writing to other locations will control the ship.

------
rcamera
For those interested, there is a C based implementation of Notch's DCPU-16 in
github: <https://github.com/swetland/dcpu16>

I haven't tested it much, but it seems to work pretty well.

------
overshard
I wonder if it's just me but this game has me more excited about programming
in ASM than I ever have, ever...

Also in this game I feel like I'll be playing the reverse role I play in real
life. IRL I generally always advocate using things like Python and open
sourcing everything. In this game I'm definitely going to pull a Steve Jobs,
hire out a few friends of mine to program my ASM apps and sell them in some
kind of Market for insanely marked up prices telling people that my Orange(TM)
software is so much better than Macrosofts(TM)! (And it will be!)

~~~
redthrowaway
When you sell it, however, you'll be selling the source. No pre-compiled
binaries, here. Might be a bit difficult to charge for something people can
trade for free.

~~~
Benjo
No, the binaries may be easier to disassemble, but it's still machine code. I
don't have to include the assembly source if I don't want to.

------
clavalle
I created a subreddit for this interesting aspect of 0x10c if anyone is
interested:

<http://www.reddit.com/r/dcpu_16_programming/>

------
sp332
Here's some work (not mine) on a third-party implementation in Go :)
<https://github.com/kballard/dcpu.go/tree/master/dcpu>

------
ekosz
I'm not a low level programmer, but could someone tell me if you could write a
LLVM backend for this CPU? If one does that, could it not then work with many
programming languages that support LLVM?

<http://llvm.org/docs/WritingAnLLVMBackend.html>

~~~
cobbal
I've never written an LLVM backend, but one difficulty that immediately jumps
out at me is the 16-bit architecture.

LLVM specifies types with bitwidths and 32 is most commonly used, meaning a
backend would have to either emulate 32 bits, forbid the frontends from
generating 32 bits, or silently cast them all down to 16 bits.

~~~
_sh
32-bit types are only common in LLVM because typically the target architecture
is 32/64-bit. LLVM will handle 16-bit (and even 8-bit or 13-bit) targets just
fine.

That said, a LLVM backend is overkill for this and I'm sure the simple
interpreter Notch has rigged up will be just fine for its purpose.

------
Symmetry
I've been tempted to learn Verilog, looks like I might have a fun project to
start here, trying to pipeline this. If I were writing the instruction set I'd
be tempted to put all the value codes for next word or PC next to each other
so it would be easier to figure out at decode state if the PC would be doing
anything wonky, but that isn't a huge impediment or anything. The instruction
boundary problem with regards to going super scalar looks as bad as it is in
x86, but that's straying pretty far from the design goals.

------
duaneb
I'd be interested to see details on memory protection. Self-modifying code
means evolutionary programming, which I am very much for.

Conditional branching is strange.

~~~
Zaak
I very much hope there will be some kind of memory protection mechanism.
Virtual memory would enable wonderful things.

~~~
duaneb
On the other hand, if there is no protected memory.... code wars abound!

------
Florin_Andrei
I'm guessing someone is already working on a real-world version of it in an
FPGA. Just for fun.

------
uvdiv
I'm not sure if it's well-specified. What does this do?

    
    
        JSR POP
    

Does the argument POP (or [SP++]) get evaluated before, or after, the "[--SP]
<\- PC" implicit in JSR?

~~~
Anderkent
Interesting question.

Spec says 'a is always handled by the processor before b, and is the lower six
bits.'

For Non-basic opcodes, 'a' is actually the opcode, and b is the argument. This
would imply JSR is evaluated before POP.

What we want JSR POP to mean, of course, is 'jump to the last item on the
stack, then push PC+1 to stack'. So I would guess that's how it actually
works, and the spec needs a revision.

~~~
uvdiv
I think that line is specific to the basic instructions only (if it weren't,
"...and is the lower six bits" would be false).

 _"For Non-basic opcodes, 'a' is actually the opcode"_

Actually it's the single argument -- 'o' is the opcode.

------
rg0ne
That compulses me to take Compiler class next semester, and write a C compiler
for this precious fictional CPU.

And what about creating this cpu?

~~~
clavalle
Already done in a few languages:

<http://www.reddit.com/r/dcpu_16_programming/>

~~~
Tichy
I think so far there are only assemblers, not C compilers (or any high level
languages)?

~~~
clavalle
Ahh, I was only answering the last question.

Now that we have some emulators, people are working on compilers.

~~~
rg0ne
Very good subreddit but, I meant physically assembling a DCPU :) If not
physically, with verilog or vhdl at least

------
JEBailey
I follow most of what's occurring within this document, but there's a bit
that's throwing me and I hope someone can shed some light. When you're
processing the step

SET A,B

Does A have to represent a register, or is it a memory location or is it both
and the registry is just a location in ram?

~~~
viraptor
a and b are just decoded value bits. That means they can be either one of
those things. 0x00-0x07: registers themselves, 0x08-0x0f: addressing via
register, etc.

------
lukesd
Hey guys. If you're interesting in discussing this, head on over to #0x10c-dev
on Freenode!

------
kierdavis
Is there an official assembler for this yet, or shall I roll my own?

~~~
wccrawford
No, but there's an emulator!

<https://github.com/swetland/dcpu16>

(Found on Reddit. I haven't tried it.)

------
mappum
I'm making a compiler/executor for it: <https://github.com/mappum/DCPU-16>.

------
chj
I think he should just use PDP8 ISA, just 6 instructions, even stupid people
can manage that much.

~~~
Zaak
Notch's original intention was to implement a real CPU like the 6502, but he
decided to create a CPU optimized for software emulation instead.

The PDP-8 was designed to be inexpensive to implement with the hardware
available at the time. It would not be an ideal choice for this purpose.

------
rplacd
Ready - steady - port tcc!

------
hobojoe
Ok. Start coding now please.

