Translating Classic
Arcade Games
to JavaScript
Norbert Kehrer
vienna.js Meetup, June 24, 2015
Automatic Program Translation
Is Exciting
 Objective: exact conversion of the original
 The traditional way: emulators
 Interesting alternative: static binary
translation (static recompilation)
 Examples: Asteroids (1979), Astro Fighter
(1980), Centipede (1981)
Translating 6502 to JavaScript
 Emulation vs. Recompilation of
„Asteroids“
 The Source: the 6502
 The Target: JavaScript
 „Naive“ Translation Patterns
 Code Optimization and the Exciting
Journey into Compiler Theory
The Asteroids Arcade Machine
is Based on the 6502 Processor
Program ROM
6800–7fff
Work RAM
0000–02ff
Vector ROM
5000–57ff
Vector RAM
4000–47ff
6502 DVG
Game Logic Video Hardware
Traditional Emulation of the
Hardware ...
Program ROM
6800–7fff
Work RAM
0000–02ff
Vector ROM
5000–57ff
Vector RAM
4000–47ff
6502 DVG
Emulator in
JavaScript
... or Translating the Game
Program to JavaScript, …
Program ROM
6800–7fff
Work RAM
0000–02ff
Vector ROM
5000–57ff
Vector RAM
4000–47ff
6502 DVG
JavaScript
Emulator in
JavaScript
… and by that Create a Stand-
Alone Application
Program ROM
6800–7fff
Work RAM
0000–02ff
Vector ROM
5000–57ff
Vector RAM
4000–47ff
6502 DVG
JavaScript
Emulator in
JavaScript
Translating 6502 to JavaScript
 Emulation vs. Recompilation of
„Asteroids“
 The Source: the 6502
 The Target: JavaScript
 „Naive“ Translation Patterns
 Code Optimization and the Exciting
Journey into Compiler Theory
The 6502 was a Popular
Microprocessor in the 1980s
The 6502 Is Simple and Has
Only a Few Registers
Accumulator (A)
X Register (X)
Y Register (Y)
Program Counter (PC)
Flags: NV-BDIZC
00000001 Stack Pointer (S)
0000-00ff: Zero Page
0100-01ff: Stack
0200-ffff: Program
Registers Memory
The 6502 Instructions Can Have
Three Formats
Op Code
Op Code
Para-
meter
Op Code
Address
Low
Address
High
$a9 $03 … lda #3
$8d $07 $19 … sta $1907
$0a … asl
Some Instruction Examples
 lda #1 Load accu with 1
 sta 1000 Store accu in 1000
 inx Add 1 to X
 adc #7 Add 7 to the accu
 jmp 3000 Jump to 3000
 beq 2000 Conditional branch,
if Z (zero) flag is set
Translating 6502 to JavaScript
 Emulation vs. Recompilation of
„Asteroids“
 The Source: the 6502
 The Target: JavaScript
 „Naive“ Translation Patterns
 Code Optimization and the Exciting
Journey into Compiler Theory
JavaScript is the Target
 Variables and arrays
 Assignments and arithmetics
 if (cond) { stmt1 } else { stmt2 };
 switch (var) {
case a: stmt1; break;
case b: stmt2; break;
case c: stmt3; break;
…
};
Translating 6502 to JavaScript
 Emulation vs. Recompilation of
„Asteroids“
 The Source: the 6502
 The Target: JavaScript
 „Naive“ Translation Patterns
 Code Optimization and the Exciting
Journey into Compiler Theory
First, Write a Disassembler …
…
6834: A2 44 ldx #$44
6836: A9 02 lda #$02
6838: 85 02 sta $02
683A: 86 03 stx $03
…
…
A2 44
A9 02
85 02
86 03
…
Program ROM
(from Asteroids)
Disassembler listing
Then, Make a Code Generator
Out of It
…
… ldx #$44 x=44;
… lda #$02 a=2;
… sta $02 mem[2]=a;
… stx $03 mem[3]=x;
…
…
A2 44
A9 02
85 02
86 03
…
Program ROM
(from Asteroids)
JavaScript code instead of disassembler listing
6502 Registers and Memory
Become Variables and Arrays
Accumulator
X register
Y register
C flag
N flag
…
Memory
var a;
var x;
var y;
var c;
var n;
var mem = new
Array(65536);
„Normal“ Instructions Are Easy
to Translate
lda 1000
sta 1001
inc 1000
ldx #10
sta 2000,x
inx
a = mem[1000];
mem[1001] = a;
mem[1000] =
(mem[1000]+1)&0xff;
x = 10;
mem[2000+x] = a;
x = (x+1) & 0xff;
„GOTO Considered Harmful“
Considered Harmful
…
1000: ldx #0 ; x = 0
1002: inx ; x = x + 1
1003: stx $d020 ; x  screen color
1006: jmp 1002 ; go to 1002
…
But, JavaScript has no (real) GOTO !
An Old „Fortran to C“ Trick
pc = 1000;
while (true) {
switch (pc) {
case 1000: x = 0; //ldx
case 1002: x = (x+1) & 0xff; //inx
case 1003: mem[0xd020] = x; //stx
case 1006: pc = 1002; break; //jmp
…
};
};
Case Labels Are Only Needed
For Jump Targets
pc = 1000;
while (true) {
switch (pc) {
case 1000: x = 0; //ldx
case 1002: x = (x+1) & 0xff; //inx
case 1003: mem[0xd020] = x; //stx
case 1006: pc = 1002; break; //jmp
…
};
};
Conditional Branches Become
“If” Statements
…
if (z === 1) { // beq 3000
pc = 3000;
break;
};
…
case 3000:
…
Dr. Sheldon Cooper‘s „Fun with
Flags“
 Many 6502 instructions set flags as their
side effect
 Example:
lda 1000 if zero  Z=1 else Z=0
if neg.  N=1 else N=0
beq 4711
…
Instructions Need Additional
Flag Calculation Code
lda 1000
lda 1000
a = mem[1000];
a = mem[1000];
if (a==0) z=1; else z=0;
if (a<0) n=1; else n=0;
 Resulting programs are correct but big
Translating 6502 to JavaScript
 Emulation vs. Recompilation of
„Asteroids“
 The Source: the 6502
 The Target: JavaScript
 „Naive“ Translation Patterns
 Code Optimization and the Exciting
Journey into Compiler Theory
Flag Calculations Are Often
Redundant …
lda 1000 a = mem[1000];
if (a==0) z=1; else z=0;
if (a<0) n=1; else n=0;
ldx 1200 x = mem[1200];
if (x==0) z=1; else z=0;
if (x<0) n=1; else n=0;
beq 4711 if (z==1) …
Flag Calculations Are Often
Redundant …
lda 1000 a = mem[1000];
if (a==0) z=1; else z=0;
if (a<0) n=1; else n=0;
ldx 1200 x = mem[1200];
if (x==0) z=1; else z=0;
if (x<0) n=1; else n=0;
beq 4711 if (z==1) …
?:
yes:
… But Not Always
lda 1000 a = mem[1000];
if (a==0) z=1; else z=0;
if (a<0) n=1; else n=0;
ldx 1200 x = mem[1200];
if (x==0) z=1; else z=0;
if (x<0) n=1; else n=0;
beq 4711 if (z==1) …
Redundant Code Elimination Is
Difficult and Interesting
 „Liveness analysis“ problem
 Solution with fixpoint iteration, or more
elegantly with Datalog programs
 Many exciting further directions:
More optimizations (combinations, high-level
structure detection,…)
LLVM
asm.js
Datalog, Logic Programming, …
Summary: From Asteroids to
Liveness Analysis
 Browser-playable „Asteroids“ as an
example
 6502 Processor
 Translating 6502 code to JavaScript
 Optimizing: Redundant Code Elimination
Thank you!
http://members.aon.at/nkehrer/

Translating Classic Arcade Games to JavaScript

  • 1.
    Translating Classic Arcade Games toJavaScript Norbert Kehrer vienna.js Meetup, June 24, 2015
  • 2.
    Automatic Program Translation IsExciting  Objective: exact conversion of the original  The traditional way: emulators  Interesting alternative: static binary translation (static recompilation)  Examples: Asteroids (1979), Astro Fighter (1980), Centipede (1981)
  • 3.
    Translating 6502 toJavaScript  Emulation vs. Recompilation of „Asteroids“  The Source: the 6502  The Target: JavaScript  „Naive“ Translation Patterns  Code Optimization and the Exciting Journey into Compiler Theory
  • 4.
    The Asteroids ArcadeMachine is Based on the 6502 Processor Program ROM 6800–7fff Work RAM 0000–02ff Vector ROM 5000–57ff Vector RAM 4000–47ff 6502 DVG Game Logic Video Hardware
  • 5.
    Traditional Emulation ofthe Hardware ... Program ROM 6800–7fff Work RAM 0000–02ff Vector ROM 5000–57ff Vector RAM 4000–47ff 6502 DVG Emulator in JavaScript
  • 6.
    ... or Translatingthe Game Program to JavaScript, … Program ROM 6800–7fff Work RAM 0000–02ff Vector ROM 5000–57ff Vector RAM 4000–47ff 6502 DVG JavaScript Emulator in JavaScript
  • 7.
    … and bythat Create a Stand- Alone Application Program ROM 6800–7fff Work RAM 0000–02ff Vector ROM 5000–57ff Vector RAM 4000–47ff 6502 DVG JavaScript Emulator in JavaScript
  • 8.
    Translating 6502 toJavaScript  Emulation vs. Recompilation of „Asteroids“  The Source: the 6502  The Target: JavaScript  „Naive“ Translation Patterns  Code Optimization and the Exciting Journey into Compiler Theory
  • 9.
    The 6502 wasa Popular Microprocessor in the 1980s
  • 10.
    The 6502 IsSimple and Has Only a Few Registers Accumulator (A) X Register (X) Y Register (Y) Program Counter (PC) Flags: NV-BDIZC 00000001 Stack Pointer (S) 0000-00ff: Zero Page 0100-01ff: Stack 0200-ffff: Program Registers Memory
  • 11.
    The 6502 InstructionsCan Have Three Formats Op Code Op Code Para- meter Op Code Address Low Address High $a9 $03 … lda #3 $8d $07 $19 … sta $1907 $0a … asl
  • 12.
    Some Instruction Examples lda #1 Load accu with 1  sta 1000 Store accu in 1000  inx Add 1 to X  adc #7 Add 7 to the accu  jmp 3000 Jump to 3000  beq 2000 Conditional branch, if Z (zero) flag is set
  • 13.
    Translating 6502 toJavaScript  Emulation vs. Recompilation of „Asteroids“  The Source: the 6502  The Target: JavaScript  „Naive“ Translation Patterns  Code Optimization and the Exciting Journey into Compiler Theory
  • 14.
    JavaScript is theTarget  Variables and arrays  Assignments and arithmetics  if (cond) { stmt1 } else { stmt2 };  switch (var) { case a: stmt1; break; case b: stmt2; break; case c: stmt3; break; … };
  • 15.
    Translating 6502 toJavaScript  Emulation vs. Recompilation of „Asteroids“  The Source: the 6502  The Target: JavaScript  „Naive“ Translation Patterns  Code Optimization and the Exciting Journey into Compiler Theory
  • 16.
    First, Write aDisassembler … … 6834: A2 44 ldx #$44 6836: A9 02 lda #$02 6838: 85 02 sta $02 683A: 86 03 stx $03 … … A2 44 A9 02 85 02 86 03 … Program ROM (from Asteroids) Disassembler listing
  • 17.
    Then, Make aCode Generator Out of It … … ldx #$44 x=44; … lda #$02 a=2; … sta $02 mem[2]=a; … stx $03 mem[3]=x; … … A2 44 A9 02 85 02 86 03 … Program ROM (from Asteroids) JavaScript code instead of disassembler listing
  • 18.
    6502 Registers andMemory Become Variables and Arrays Accumulator X register Y register C flag N flag … Memory var a; var x; var y; var c; var n; var mem = new Array(65536);
  • 19.
    „Normal“ Instructions AreEasy to Translate lda 1000 sta 1001 inc 1000 ldx #10 sta 2000,x inx a = mem[1000]; mem[1001] = a; mem[1000] = (mem[1000]+1)&0xff; x = 10; mem[2000+x] = a; x = (x+1) & 0xff;
  • 20.
    „GOTO Considered Harmful“ ConsideredHarmful … 1000: ldx #0 ; x = 0 1002: inx ; x = x + 1 1003: stx $d020 ; x  screen color 1006: jmp 1002 ; go to 1002 … But, JavaScript has no (real) GOTO !
  • 21.
    An Old „Fortranto C“ Trick pc = 1000; while (true) { switch (pc) { case 1000: x = 0; //ldx case 1002: x = (x+1) & 0xff; //inx case 1003: mem[0xd020] = x; //stx case 1006: pc = 1002; break; //jmp … }; };
  • 22.
    Case Labels AreOnly Needed For Jump Targets pc = 1000; while (true) { switch (pc) { case 1000: x = 0; //ldx case 1002: x = (x+1) & 0xff; //inx case 1003: mem[0xd020] = x; //stx case 1006: pc = 1002; break; //jmp … }; };
  • 23.
    Conditional Branches Become “If”Statements … if (z === 1) { // beq 3000 pc = 3000; break; }; … case 3000: …
  • 24.
    Dr. Sheldon Cooper‘s„Fun with Flags“  Many 6502 instructions set flags as their side effect  Example: lda 1000 if zero  Z=1 else Z=0 if neg.  N=1 else N=0 beq 4711 …
  • 25.
    Instructions Need Additional FlagCalculation Code lda 1000 lda 1000 a = mem[1000]; a = mem[1000]; if (a==0) z=1; else z=0; if (a<0) n=1; else n=0;  Resulting programs are correct but big
  • 26.
    Translating 6502 toJavaScript  Emulation vs. Recompilation of „Asteroids“  The Source: the 6502  The Target: JavaScript  „Naive“ Translation Patterns  Code Optimization and the Exciting Journey into Compiler Theory
  • 27.
    Flag Calculations AreOften Redundant … lda 1000 a = mem[1000]; if (a==0) z=1; else z=0; if (a<0) n=1; else n=0; ldx 1200 x = mem[1200]; if (x==0) z=1; else z=0; if (x<0) n=1; else n=0; beq 4711 if (z==1) …
  • 28.
    Flag Calculations AreOften Redundant … lda 1000 a = mem[1000]; if (a==0) z=1; else z=0; if (a<0) n=1; else n=0; ldx 1200 x = mem[1200]; if (x==0) z=1; else z=0; if (x<0) n=1; else n=0; beq 4711 if (z==1) …
  • 29.
    ?: yes: … But NotAlways lda 1000 a = mem[1000]; if (a==0) z=1; else z=0; if (a<0) n=1; else n=0; ldx 1200 x = mem[1200]; if (x==0) z=1; else z=0; if (x<0) n=1; else n=0; beq 4711 if (z==1) …
  • 30.
    Redundant Code EliminationIs Difficult and Interesting  „Liveness analysis“ problem  Solution with fixpoint iteration, or more elegantly with Datalog programs  Many exciting further directions: More optimizations (combinations, high-level structure detection,…) LLVM asm.js Datalog, Logic Programming, …
  • 31.
    Summary: From Asteroidsto Liveness Analysis  Browser-playable „Asteroids“ as an example  6502 Processor  Translating 6502 code to JavaScript  Optimizing: Redundant Code Elimination
  • 32.