Running Virtual Machines in 
the Wolfram Language

Daniel Sanchez · Stefano Sosa
Wolfram Research South America

(RowDefault[, (Spacer1), , (Spacer1), ])  #WolframTechConf

ABSTRACT

Software engineering meets computer archaeology in this project where we aim to preserve computational systems and architectures, spanning from the end of the 1950s to the beginning of the 1980s, by making them available in the Wolfram Language as virtual machines.

We will explore vintage architectures such as DEC’s PDP-1 minicomputer, featuring an emulation of the classic Spacewar!, as well as the MOS Technology 6502, an 8-bit microprocessor that powered popular video game consoles and computers such as the Nintendo Entertainment System (NES) and the Apple II home computer. Using the new experimental VirtualMachine framework, we will discuss some of the machines that we have implemented, how the design of these machines changed over time and what features introduced by them are still used today. Along the way, we will discuss the challenges we faced during the design of the framework and the things we learned from them.

Why virtual machines in the Wolfram Language?

Future proof language

Preserve old computer architecture and software

Ideal educational environment

Provide an environment to debug, explore and study virtual machines

Explore how computer architectures and their processors have changed over time

Virtual machines included in this project

Abstract Machines

Register Machines

Deterministic Finite Automaton (DFA)

Nondeterministic Finite Automaton (NFA)

Process Machines

Ethereum Virtual Machine (EVM)

(Vintage) Processors

PDP-1

PDP-8

Intel 4004

MOS 6502

VirtualMachine Symbols

VirtualMachine

VirtualMachine["PDP-1"]

VirtualMachineObject

VirtualMachineObject[]["ProcessorState"]

VirtualMachineExecute

VirtualMachineExecute[VirtualMachine["PDP-1"],"MemoryLoad",{0,0,0,196657,197489,197486,233505}]

PDP-1: DEC Programmed Data Processor

The Programmed Data Processor (PDP-1) is a high speed, solid state digital computer designed to operate with several types of input-output devices...
It is a single address, single instruction, stored program computer with powerful program features.
Five-megacycle circuits, a magnetic core memory, and fully parallel processing make possible a computation rate of 100,000 additions per second...

Programmed Data Processor-1 Handbook (April 1960)

PDP-1 Information and Instruction Set

$VirtualMachines["PDP-1"]["BasicInformation"]

PDP-1’s brochure (March 1961)

pdp1Instructions=$VirtualMachines["PDP-1"]["InstructionSet"];

pdp1Instructions//Length

RandomSample[pdp1Instructions[All,{"Name","Mnemonic","OperationCode","ExecutionTime","Pseudocode"}],5]

PDP-1 Demo: Running Spacewar!

Create an instance of the PDP-1 virtual machine and load Spacewar!:

pdp1=VirtualMachine["PDP-1"];
VirtualMachineExecute[pdp1,"MemoryLoad",];
VirtualMachineExecute[pdp1,"ProcessorReset",4];

Open a dynamic object representing the screen:

VirtualMachineExecute[pdp1,"ScreenVisualization"]

Run the object for 500 000 steps and see the spaceships move:

VirtualMachineExecute[pdp1,"Run",500000];

PDP-8: The first commercially successful minicomputer

Features:
						• Integrated all-silicon processor circuits						• Fully parallel arithmetic operation
						• Continuous display of active registers							• Single step and single instruction modes
						• Link bit													• Large core memory capacity
						• Indirect addressing										• 1.6 microseconds cycle time
						• Micro-programmable instructions							• Program interrupt
						• etc…

PDP-8 brochure (March 1965)

PDP-8 Information and Instruction Set

$VirtualMachines["PDP-8"]["BasicInformation"]

The PDP-8 came in several different models:

$VirtualMachines["PDP-8"]["Models"][All,KeyDrop[{"AlternateNames"}]]

PDP-8 Instruction formats (March 1965)

It only had 8 instructions:

$VirtualMachines["PDP-8"]["InstructionSet"][All,{"Opcode","Name","Pseudocode","ExecutionTime"}]

$VirtualMachines["PDP-8"]["InstructionSet"]["OPR"]["Microinstructions"]["Group2"][All,{"Name","Pseudocode","ExecutionTime"}]

PDP-8 Demo: Front Panel

Create and execute the front panel of a PDP-8:

pdp8=VirtualMachine["PDP-8"];
VirtualMachineExecute[pdp8,"MemoryLoad",{0,0,0,0,0,0,0,0,3776,528,529,3842,0,0,0,0,8^^7776,8^^0003}];
Magnify[VirtualMachineExecute[pdp8,"FrontPanel"],1.35]

Add two numbers

0010 7300 cll,  cla  / clear the AC and the Link
     0011 1020 tad   x    / load x into the AC
     0012 1021 tad   y    / add x and y, storing the result in AC
     0013 7402 hlt        / end
     
x,   0020 7776            / first argument
y,   0021 0003            / second argument

Intel 4004: The first commercially produced microprocessor

Top left: Advertisement for Intel’s 4004
Right and bottom: MCS-4 and features (November 1971)

Intel 4004 Information and Instruction Set

$VirtualMachines["Intel4004"]["BasicInformation"]

MCS-4 Data Sheet (November 1971)

intel4004Instructions=$VirtualMachines["Intel4004"]["InstructionSet"];

intel4004Instructions//Length

RandomSample[intel4004Instructions[All,{"Name","BitPattern","ShortDescription"}],5]

Intel 4004 Demo: Debugger

Create an instance of the Intel 4004 virtual machine and run its debugger:

VirtualMachineExecute[VirtualMachine["Intel4004",<|"ROMChipCount"->2|>],"Debugger"]

4-bit “AND” routine

routineAND=({{"[◼]", "MCS4Assembler" }})["
; four bit \"AND\" routine on the Intel 4004
;
START:
	FIM 4P, 0      ; LOAD ROM PORT 0 ADDRESS
	SRC 4P		 ; SEND ROM PORT ADDRESS
	RDR            ; READ INPUT A
	XCH 0          ; A TO REGISTER 0
	INC 8          ; LOAD ROM PORT 1 ADDRESS
	SRC 4P         ; SEND ROM PORT ADDRESS
	RDR            ; READ INPUT B
	XCH 1          ; B TO REGISTER 1
	JMS AND        ; EXECUTE \"AND\"
	XCH 2          ; LOAD RESULT C
	WMP            ; STORE AT MEMORY PORT 0
	JUN START      ; RESTART
	NOP
*=104
; \"AND\" SUBROUTINE
;
AND:	CLB        ; CLEAR ACCUMULATOR AND CARRY
	XCH 2          ; CLEAR REGISTER 2
	LDM 4          ; LOAD LOOP COUNT (LC)
AND_3:
	XCH 0          ; LOAD A, LC TO REGISTER 0
	RAR            ; ROTATE LEAST SIGNIFICANT BIT TO CARRY
	XCH 0          ; RETURN ROTATED A TO REG 0, LC TO ACC
	JCN CZ, ROTR1  ; JUMP TO ROTR1 IF CARRY ZERO
	XCH 1          ; LOAD B, LC TO ACCUMULATOR
	RAR            ; ROTATE LEAST SIGNIFICANT BIT TO CARRY
	XCH 1          ; RETURN ROTATED B TO REG 1, LC TO ACC
ROTR2:
	XCH 2          ; LOAD PARTIAL RESULT C, LC TO REG 2
	RAR            ; ROTATE CARRY INTO PARTIAL RESULT MSB
	XCH 2          ; LOAD LC, RETURN C TO REGISTER 2
	DAC            ; DECREMENT THE ACCUMULATOR (LC)
	JCN ANZ, AND_3 ; LOOP IF LC NON ZERO
	BBL 0          ; RETURN
ROTR1:
	XCH 1          ; LOAD B, LC TO REGISTER 1
	RAR            ; ROTATE B
	XCH 1          ; RETURN ROTATED B TO REG 1, LC TO ACC
	CLC            ; CLEAR CARRY
	JUN ROTR2      ; RETURN TO LOOP
  CZ=10
  ANZ=12"
][[;;256]]

MOS 6502: The processor behind the home computer revolution

Left: MOS 6502 ad from IEEE Computer (September 1975)
Right: 6502 Pin configuration

MOS 6502 Information and Instruction Set

$VirtualMachines["MOS6502"]["BasicInformation"]

6502 Instruction Set at masswerk

Addressing Modes

$VirtualMachines["MOS6502"]["AddressingModes"]

Operations

mos6502Operations=$VirtualMachines["MOS6502"]["Operations"];

mos6502Operations//Length

RandomSample[mos6502Operations,10]

MOS 6502 Demo: Snake

Init

Begin["Snake`"];

palette = {,,,,,,,,,,,,,,,};

screen[Hold[m6502_], opts___]:=
	ArrayPlot[
		ArrayReshape[m6502["MEM"][[16^^0200 + 1 ;; 16^^05FF + 1]], {32, 32}],
		opts,
		ColorFunction -> (palette[[BitAnd[#, 16^^0F] + 1]] &),
		ColorFunctionScaling -> False
	];

SetAttributes[snakeDynamic, HoldFirst];
snakeDynamic[obj_] :=
	Module[{iobj = obj},
		DynamicModule[{apple, m6502 = obj["symbol"]},
			Column[{
				Row @ {
					Button["Run", VirtualMachineExecute[iobj, "Run", Infinity], Method -> "Queued"],
					Button["Stop", Abort[]],
					Button["Reset",
						VirtualMachineExecute[iobj, "Reset", ByteArray[], 16^^600];
					]
				},
				EventHandler[
					InputField[],
					"KeyDown" :> (VirtualMachineExecute[iobj, "MemoryWrite", 16^^FF, First @ ToCharacterCode @ CurrentValue["EventKey"]])
				],
				Dynamic[
					apple[];
					screen[m6502, ImageSize -> 500]
				,
					UpdateInterval -> 1./60
				]
			}, Center],
			Initialization :> (
				apple[] := VirtualMachineExecute[iobj, "MemoryWrite", 16^^FE, RandomInteger[{0, 255}]];
			)
		]
	];

End[];

Demo

Create an instance of the MOS 6502 virtual machine and load the Snake binary:

mos6502=VirtualMachine["MOS6502"];
VirtualMachineExecute[mos6502,"MemoryLoad",ByteArray[],16^^600];
Snake`snakeDynamic[mos6502]

The VirtualMachine Project

We want many more processors and notable software to be preserved!

The main objectives of the project are:

A framework where enthusiasts can add other machines

A repository of machines and software that people can download and play around with

Build a community of people interested in the preservation and exploration of these systems and their software

Add more tools:

Generic/reusable peripherals

Assemblers and disassemblers

A special recognition to Brian Silverman, who shared with us his knowledge and expertise throughout the duration of the project.

Thank you Brian!

Project Contact Information

e-mail us at: virtualmachineproject@wolfram.com

VirtualMachine Paclet Download

https://wolfr.am/VMPaclet

ResourceObject["Wolfram: VirtualMachine"]

References

History

[web] https://www.computerhistory.org/timeline/

[book] Computer Engineering: A DEC View of Hardware Systems Design

Virtual Machines

[pdf] The Architecture of Virtual Machines (2005)

[pdf] SimH: a simulator for historic computer systems

PDP-1

[book] Programmed Data Processor-1 Handbook (1963)

[book] MACRO: Assembly Program For Programmed Data Processor-1 (1962)

[emulator] https://github.com/simh/simh/tree/master/PDP1

[pdf] http://simh.trailing-edge.com/pdf/pdp1_doc.pdf

[video] Lyle Bickley explains the PDP-1 (and we play the original Spacewar!)

Spacewar!

[emulator] Original 1962 game code running on a PDP-1 emulator in JavaScript

[emulator] https://www.masswerk.at/spacewar/

[web] https://www.computerhistory.org/pdp-1/spacewar/

PDP-8

[book] Small Computer Handbook (1970)

[book] MACRO-8 (1969)

[book] The Art of Digital Design: An Introduction to Top-Down Design (1987)

[web] A Programmer's Reference Manual

[web] https://en.wikipedia.org/wiki/PDP-8

[emulator] https://github.com/simh/simh/tree/master/PDP8

[pdf] http://simh.trailing-edge.com/pdf/pdp8_doc.pdf

[web] https://obsolescence.wixsite.com/obsolescence/pidp-8

[web] http://www.faqs.org/faqs/dec-faq/pdp8-models/index.html

MCS-4 (Intel 4004)

[pdf] MCS-4 Data sheet (1971)

[book] MCS-4 Users Manual (1973)

[video] Intel 4004 Microprocessor 35th Anniversary

[emulator] Intel 4004 (emulator, assembler, disassembler) in JS

[web] http://8bitforce.com/projects/4004/

Busicom

[emulator] Busicom 141-PF Emulator in Rust/WASM

[code] Annotated Busicom 141-PF software

[web] http://www.vintagecalculators.com/html/busicom_141-pf.html

MOS 6502

[web] https://www.masswerk.at/6502/6502_instruction_set.html

[emulator] Easy 6502 by skilldrick

[web] http://www.visual6502.org/

[web] A new cycle-stepped 6502 CPU emulator (2019)

[emulator] https://floooh.github.io/tiny8bit/

[video] https://eater.net/6502

NES

[emulator] https://8bitworkshop.com/redir.html?platform=nes

[book] Making Games for the NES (2019)

[video] NES Emulator from Scratch (C++)

Peripherals

VT100

[web] https://vt100.net/docs/vt100-ug/contents.html

[web] https://en.wikipedia.org/wiki/VT100

[web] https://blog.hutchins1.net/2020/02/vt102.html