I’ve been working on a virtual machine under 9front implementing the LC3 educational ISA. This has been a lot of fun, and I realise that probably sounds weird to a bunch of people who did CompSci at university and were made to do this sort of thing. In that sense I’m like a mature student - I’m actually doing it because I care.
Initially I started out when I was on a 7 week trip through Asia (I know, I never update this thing, but then nobody reads it either). I was in Kuala Lumpur and taking a much needed rest, and for some reason that I can’t quite remember I just decided to search “how to write a virtual machine” and a blog post came up which essentially lined up the problem of how you’d go about implementing LC3. So I just started.
And I continued in Nepal, where I finished off the majority of the VM and a
rudimentary assembler and patched vexed
hex editor for binary input to help
with my hand-hacked test machine code.
And I continued on a beach in Thailand, where I wrote the beginnings of an assembler.
Yesterday I reached an important milestone - I was able to assemble and run the following program:
.ORIG x3000
NOP
ADD R2,R2,x6 ; we need 6 loops to get to 'h'
NOT R2,R2 ; we want to be able to subtract this number so we'll 2's complements it
ADD R2,R2,x1
LOOPH
ADD R0,R0,xf
ADD R1,R1,x1
ADD R3,R1,R2 ; compare if we're at 6 loops yet
BRn LOOPH
ADD R0,R0,xe
OUT
E .FILL x65
L .FILL x6c
O .FILL x6f
LD R0,E
OUT
LD R0,L
OUT
OUT
LD R0,O
OUT
.BLKW x5
LEA R0,WRLD
PUTSP
HALT
WRLD
.STRINGZ x20776f726c64210a
.END
Which runs thusly:
cpu% lc3/lc3 -f out.hex
hello world!
Program complete, exiting
I think it’s quite a fun “hello world” because I wrote it as I was implementing features of the assembler…
Up until the first OUT
(which was a TRAP 0x21
at the time) I only just had assembling into a binary format working, with none
of the raw data loading directives so I had to ADD
the largest positive value
supported by ADD
’s immediate mode (which only supports a 5 bit signed
operand) 6 times and then add the remainder to get to 0x68
or h
.
To get the rest of ello
I then implemented .FILL
and (now that I think
about it) just let the machine blast through trying to interpret those
instructions (I should probalby fix that hahah), but this means that we’re then
able to LD
those memory locations into R0
which then means we can use the
OUT
trap to print each one in turn.
Then we have .BLKW
which I didn’t have much use for in this program but it
was easy to implement after .FILL
so my implementation also initializes to
0x0
which maps to NOP
(or more strictly, unconditional branch to PC
).
Finally, .STRINGZ
. As you can see, I’ve not implemented any data literals
other than hex yet, so I still have string literals and decimal to implement
but I don’t need those to demo that my VM is working.
I have some plans for this VM which I’m not going to talk about, because I’ve found in my life that talking about an idea to people often exhausts the need to actually follow through on it - needless to say it’s weird dumb bullshit like you’d expect from me.
The plans which I am going to talk about here are the 9p debugging features I’d like to implement.
Essentially, I’d like to write a filesystem which has something like the following layout:
reg/
pc
cond
r0
r1
r2
r3
r4
r5
r6
mem/
full
0/
0/
0/
0
1
...
1/
...
1/
2/
3/
...
clk
cons
The idea here is that you can read and update the state of any given memory
address or register at any point, and you can step the clock simply by reading
clk
. You can follow the program along by reading reg/pc
and then reading
the corresponding address.
In fact, beyond that I doubt it would be that hard to also have a disasm/
tree as well which will allow you to follow along with a disassembled version
of the program.
This then means that your debugger is a simple filesystem API which you can
then instrument and script around using rc
, awk
, whatever. In that sense,
I’m kind of surprised that acid
was never designed in this way, because I’d
say one of the huge advantages of Plan 9 is that you don’t have to learn
someone’s implementation of a given API or language when you can simply explore
a filesystem and write tools to manipulate it.
Anyway, that’s what I’ve been up to.