SlideShare a Scribd company logo
An Atari 2600 emulator
100% written in Ruby
(and RSpec!)
Carlos Duarte do Nascimento (Chester)
@chesterbr / http://chester.me
ruby2600 - an Atari 2600 emulator written in Ruby
If so, you probably had this...
...or one of these...
...or you used an emulator
http://stella.sourceforge.net
Emulator
A program that runs software written
for one type of computer system in
another type by simulating the
hardware of the original system
ruby2600
● Atari 2600 emulator
● Written in Ruby
● Runs quite a few classic games
● Open-source
http://github.com/chesterbr/ruby2600
Why?
There are great emulators out there, but
they strive for speed above readability
A test-driven emulator in a high-level
language is a great learning tool
Always wondered how much TDD would
help on wildly unfamiliar territory
(also: why not? ☺)
Work in progress!
● A few subtle bugs
● Does not run every game
● Not full-speed
● No sound
http://github.com/chesterbr/ruby2600
We'll see
● How the Atari works
● CPU emulation
● Architecture (just a bit)
● Ruby2600 in action
● The future
@chesterbr
http://chester.me
About me (Chester)
© Ila Fox - http://www.ilafox.com
Building an Emulator:
How the Atari 2600 works
Let's peek inside...
(Atari 2600 Jr. printed circuit board)
Cartridge connector
CPU: 6507
Video:TIA
Everything else: RIOT (6532)
Challenging specs
● CPU speed: 1.19 MHz (not GHz)
● Max cart (program) size: 4 KB
● RAM: 128 bytes
● Video RAM: 0KB (game code has
to drive TIA into generating each
scanline in realtime)
Atari 2600 in a nutshell
The CPU reads a game program from
the ROM chip on the cartrigde
It confgures the pixels generated by
TIA, using RAM, I/O and timers
provided by the RIOT chip
Our goal: simulate this in software
Building an Emulator:
CPU
image CC-BY Konstantin Lanzet
65xx family: in the past...
http://en.wikipedia.org/wiki/MOS_Technology_6502#Computers_and_games
...and in the future!
http://en.wikipedia.org/wiki/MOS_Technology_6502#In_popular_culture
The 6507 CPU
Reads instructions from the cartridge
that manipulate and transfer bytes
between chips, keeping state on
internal registers and flags
http://en.wikipedia.org/wiki/Von_Neumann_architecture
Emulated 6507
As it executes each instruction, it
keeps instance variables for registers
(@a, @x, @y), flags (@n, @z, ...) and
@memory as an array
CPU.rb
module Ruby2600
class CPU
attr_accessor :memory
attr_accessor :pc, :a, :x, :y, :s
# Flags (P register): nv--dizc
attr_accessor :n, :v, :d, :i, :z, :c
def step
...runs a instruction...
end
...
module Ruby2600
class CPU
attr_accessor :memory
attr_accessor :pc, :a, :x, :y, :s
# Flags (P register): nv--dizc
attr_accessor :n, :v, :d, :i, :z, :c
def step
...runs a instruction...
end
...
CPU.rb
TESTS FIRST!TESTS FIRST!
ruby2600 - an Atari 2600 emulator written in Ruby
Assembly debugging == PAIN!
To avoid it, we need
technical specifcations
that are easy to read, yet
detail-oriented enough to
test emulator code
RSpec does the job!
http://rspec.info
6507 Instruction Set, 1/2
6507 Instruction Set, 2/2
CPU_spec.rb
context 'INX' do
before do
cpu.memory[0] = 0xE8 # INX
cpu.pc = 0x0000
cpu.x = 0x07
end
it 'should advance PC by one' do
cpu.step
cpu.pc.should == 0x0001
end
it 'should set X value' do
cpu.step
cpu.x.should == 0x08
end
...
Using shared examples
shared_examples_for 'advance PC by one' do
it { expect { cpu.step }.to change
{ cpu.pc }.by 1 }
end
shared_examples_for 'set X value' do |expected|
it do
cpu.step
value = cpu.x
value.should be(expected),
"Expected: #{hex_bye(expected)}, " +
"found: #{hex_byte(value)}"
end
end
More syntactic sugar
1.upto 3 do |number|
shared_examples_for "advance PC by
#{number.humanize}" do
it { expect { cpu.step }.to change
{ cpu.pc }.by number }
end
end
RSpec.configure do |c|
c.alias_it_should_behave_like_to :it_should,
'should'
end
“Literate Testing”
context 'INX' do
before do
cpu.memory[0] = 0xE8 # INX
cpu.x = 0x07
end
it_should 'advance PC by one'
it_should 'take two cycles'
it_should 'set X value', 0x08
it_should 'reset Z flag'
it_should 'reset N flag'
...
http://en.wikipedia.org/wiki/Literate_programming
Less effort → better coverage
● Each instruction tested in every
possible addressing mode
● Easy to understand, high-level tests
● Tests become a specifcation - specs!
CPU.rb
module Ruby2600
class CPU
attr_accessor :memory
attr_accessor :pc, :a, :x, :y, :s
# Flags (P register): nv--dizc
attr_accessor :n, :v, :d, :i, :z, :c
def step
...runs a instruction...
end
...
ruby2600 - an Atari 2600 emulator written in Ruby
def step
fetch
decode
execute
return @time_in_cycles
end
CPU.rb
No byte/word
data types :-(CPU.rb
def fetch
@opcode = memory[@pc]
@param_lo = memory[word(@pc + 1)]
@param_hi = memory[word(@pc + 2)]
@param = @param_hi * 0x100 + @param_lo
@pc = word(@pc +
OPCODE_SIZES[@opcode])
end
Lookup table
more
lookup!
CPU.rb
def decode
if (@opcode & 0b11111) == BXX
@instruction = BXX
elsif (@opcode & 0b11111) == SCX
@instruction = SCX
else
@instruction_group = @opcode & 0b11
mode_in_group = (@opcode & 0b11100) >> 2
@addressing_mode = ADDRESSING[
@instruction_group][mode_in_group]
@instruction = @opcode & 0b11100011
end
@time_in_cycles = time_in_cycles
end
CPU.rb
def execute
case @instruction
when LDA
flag_nz @a = load
when STA
store @a
when JMPabs
@pc = @param
when BXX
@pc = branch
...
Final result
Full instruction set covered
by more than 1,700 tests
Only one CPU bug so far
had to be debugged in-game
Building an Emulator:Building an Emulator:
ArchitectureArchitecture
image CC-BYimage CC-BY Benjamin EshanBenjamin Eshan
ruby2600 class diagram
Memory-based I/O
CPU “talks” to other chips by reading
and writing specifc memory locations:
0000-002C – TIA (write)
0030-003D – TIA (read)
0080-00FF – RIOT (RAM)
0280-0297 – RIOT (I/O,Timer)
F000-FFFF – Cartridge (ROM)
(very simplified, see: http://nocash.emubase.de/2k6specs.htm)
Bus
Acts as a memory façade to the
CPU, routing reads and writes
to the appropriate chip class
It is also the interface where we
“plug” an UI (anything that displays
images and reads keypresses)
ruby2600 class diagram
Ruby spice: duck typing
Instead of defning read/write
methods, make Bus,TIA, RIOT and
Cart classes “quack” like arrays
TIA.rb / RIOT.rb / Cart.rb
(and also bus.rb!)
def [](position)
...return value for position...
end
def []=(position, value)
...react to writing value to position...
end
Benefts
● High decoupling: CPU,TIA, RIOT
and Cart are (mostly) independent
● We can use regular arrays as mocks
for TIA, RIOT, Cart and Bus itself!
● We can “plug” different UIs
(e.g.: text-mode rendering, network
multiplayer, joystick interface, etc.)
Cart.rb (full source)
class Cart
def initialize(rom_file)
@bytes = File.open(rom_file, "rb") {
|f| f.read
}.unpack('C*')
@bytes += @bytes if @bytes.count == 2048
end
def [](address)
@bytes[address]
end
def []=(address, value)
# Don't write to Read-Only Memory, duh!
end
end
Timing
As TIA generates each pixel for each
scanline, it will "tick" the CPU and
RIOT to keep everything in sync
image cc-by Steve Evans
TIA.rb
def draw_scanline
scanline = []
0.upto(SCANLINE_WIDTH) do |pixel|
scanline << topmost_pixel
tick_other_chips pixel
end
return scanline
end
def topmost_pixel ...
def tick_other_chips
@cpu.tick if pixel % 3 == 2
@riot.tick if pixel % 3 == 0
end
TIA runs 3x faster
than CPU and RIOT
BALL
PLAYFIELD
PLAYERS (2)
MISSILES (2)
Graphic Objects
Graphic Objects
To keep TIA's responsibility focused
on building the frames, we will offload
object drawing to separate classes
(Playfeld, Player, Ball, Missile)
For the common behavior, should we
use composition or inheritance?
Composition and Inheritance
A common ancestor (Graphic)
contains the common behavior, and
each class adds its own flavor
Behavior that does not defne a
Graphic (position counters) is better
suited for a separate class, using
composition instead of inheritance
ruby2600 class diagram
Building an Emulator:
Let's run it!
reproduction:reproduction: Young FrankensteinYoung Frankenstein
ruby2600 - an Atari 2600 emulator written in Ruby
Building an Emulator:
Speeding up
TBBT 1-06 "The Middle-Earth Paradigm", © 2007 Chuck Lorre Productions / WB Television
Knuth, Donald (December 1974).
"Structured Programmingwith go
to Statements",ACM Journal
Me and Prof. Knuth hanging out. We're, like, bros. Really.
"We should forget
about small
efficiencies, say
about 97% of the
time: premature
optimization is the
root of all evil"
Refactoring
Thanks to test coverage, we can safely
play around and refactor for speed
(while keeping it readable)
JRuby
We have a small working set (no more
than 5KB) handled in very tight loops
Have to measure, but it smells like the
kind of modern-CPU-friendly code
that could be generated via JIT
http://en.wikipedia.org/wiki/Just-in-time_compilation
If nothing else works
The modular design gives us freedom to
rewrite any part using other languages
and/or replace them with existing code
http://www.6502.org/tools/emu/#emulation
ruby2600 - an Atari 2600 emulator written in Ruby
Questions?
Thank you!
@chesterbr
http://slideshare.net/chesterbr
http://github.com/chesterbr/ruby2600
Credits and License
This presentation is available under the
Creative Commons “by-nc” 3.0 license
noticing the exceptions below
Images from third parties were included (with due credits) under
fair use assumption and/or under their respective licenses.
These are excluded from the license above.
Atari™ and likewise characters/games/systems are mentioned uniquely
for illustrative purposes under fair use assumption. They are property of
their rights holders, and are also excluded from the license above.

More Related Content

PDF
Atari 2600 VCS Programming
PPTX
Atari 2600 Programming for Fun
PPTX
The Video Game R-Evolution
PDF
Roberto Gallea: Workshop Arduino, giorno #2 Arduino + Processing
PDF
Micro RetroKomp
PDF
PDF
Kernel Recipes 2015: Representing device-tree peripherals in ACPI
PDF
Snickers: Open Source HTTP API for Media Encoding
Atari 2600 VCS Programming
Atari 2600 Programming for Fun
The Video Game R-Evolution
Roberto Gallea: Workshop Arduino, giorno #2 Arduino + Processing
Micro RetroKomp
Kernel Recipes 2015: Representing device-tree peripherals in ACPI
Snickers: Open Source HTTP API for Media Encoding

What's hot (17)

PDF
The Ring programming language version 1.7 book - Part 50 of 196
PDF
NoiseGen at Arlington Ruby 2012
PPTX
C++ AMP 실천 및 적용 전략
PPTX
Week One - Introduction
PPT
Device tree support on arm linux
PDF
Flappy bird
PDF
Design and Implementation of GCC Register Allocation
PDF
The Joy of Server Side Swift Development
PPTX
Raspberry Pi with Java (JJUG)
PPT
Intro computer
PPT
Intro computer
PDF
Lost in Translation: When Industrial Protocol Translation goes Wrong [CONFide...
PPTX
Panda board
PDF
Prototipare col raspberry pi
PDF
Html5 game, websocket e arduino
PPT
Game programming with Groovy
PDF
Html5 game, websocket e arduino
The Ring programming language version 1.7 book - Part 50 of 196
NoiseGen at Arlington Ruby 2012
C++ AMP 실천 및 적용 전략
Week One - Introduction
Device tree support on arm linux
Flappy bird
Design and Implementation of GCC Register Allocation
The Joy of Server Side Swift Development
Raspberry Pi with Java (JJUG)
Intro computer
Intro computer
Lost in Translation: When Industrial Protocol Translation goes Wrong [CONFide...
Panda board
Prototipare col raspberry pi
Html5 game, websocket e arduino
Game programming with Groovy
Html5 game, websocket e arduino
Ad

Viewers also liked (6)

PDF
git fail --force (make it up with your pull requests)
PPT
Adventure lecture
PPT
2005 06-12-vitale-emgsession-videopreservation
PDF
Programação para Atari 2600
PDF
git fail --force (faça as pazes com seus pull requests)
PDF
"Playing Atari with Deep Reinforcement Learning"
git fail --force (make it up with your pull requests)
Adventure lecture
2005 06-12-vitale-emgsession-videopreservation
Programação para Atari 2600
git fail --force (faça as pazes com seus pull requests)
"Playing Atari with Deep Reinforcement Learning"
Ad

Similar to ruby2600 - an Atari 2600 emulator written in Ruby (20)

PDF
mRuby - Powerful Software for Embedded System Development
PDF
Optcarrot: A Pure-Ruby NES Emulator
KEY
Emulating With JavaScript
KEY
Modified "Why MacRuby Matters"
PDF
Now is the time to create your own (m)Ruby computer
PDF
mruby/c and data-flow programming for small devices
ODP
Ruby C extensions at the Ruby drink-up of Sophia, April 2012
PPTX
UNIT 1 _ Embedded system -design steps PPT.pptx
PDF
Developing cross platform desktop application with Ruby
PDF
Ruby for C#-ers (ScanDevConf 2010)
PDF
Urd dioscuri kbna_v1_1_en_2
PDF
JRuby: The Hard Parts
PDF
How to control physical devices with mruby
PDF
X-ISCKER
ZIP
Why MacRuby Matters
PDF
MacRuby For Ruby Developers
PDF
Metaprogramming in Ruby
PPT
Open Kode, Airplay And The New Reality Of Write Once Run Anywhere
PDF
Experiments in Sharing Java VM Technology with CRuby
PPTX
Symbian OS
mRuby - Powerful Software for Embedded System Development
Optcarrot: A Pure-Ruby NES Emulator
Emulating With JavaScript
Modified "Why MacRuby Matters"
Now is the time to create your own (m)Ruby computer
mruby/c and data-flow programming for small devices
Ruby C extensions at the Ruby drink-up of Sophia, April 2012
UNIT 1 _ Embedded system -design steps PPT.pptx
Developing cross platform desktop application with Ruby
Ruby for C#-ers (ScanDevConf 2010)
Urd dioscuri kbna_v1_1_en_2
JRuby: The Hard Parts
How to control physical devices with mruby
X-ISCKER
Why MacRuby Matters
MacRuby For Ruby Developers
Metaprogramming in Ruby
Open Kode, Airplay And The New Reality Of Write Once Run Anywhere
Experiments in Sharing Java VM Technology with CRuby
Symbian OS

More from Carlos Duarte do Nascimento (7)

PDF
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
PDF
Mashups: Criando Valor na Web 2.0 (BandTec)
PDF
Aplicativos Mobile: Da Idéia ao Produto (ou não)
PDF
Apontador API (para programadores Python)
PDF
Mashups: Criando Valor na Web 2.0
PDF
Cruzalinhas - Palestra Relâmpago no Fisl 11
PDF
SlideMeme - Habilitando o SlideShare dentro do Yahoo! Meme - Yahoo! Open Hack...
Desenvolvimento de Aplicações para o Google App Engine (CPBR5)
Mashups: Criando Valor na Web 2.0 (BandTec)
Aplicativos Mobile: Da Idéia ao Produto (ou não)
Apontador API (para programadores Python)
Mashups: Criando Valor na Web 2.0
Cruzalinhas - Palestra Relâmpago no Fisl 11
SlideMeme - Habilitando o SlideShare dentro do Yahoo! Meme - Yahoo! Open Hack...

Recently uploaded (20)

PDF
KodekX | Application Modernization Development
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PPTX
Cloud computing and distributed systems.
PDF
Electronic commerce courselecture one. Pdf
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PDF
Per capita expenditure prediction using model stacking based on satellite ima...
PPTX
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
DOCX
The AUB Centre for AI in Media Proposal.docx
PDF
Approach and Philosophy of On baking technology
PPTX
Spectroscopy.pptx food analysis technology
KodekX | Application Modernization Development
Chapter 3 Spatial Domain Image Processing.pdf
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
Advanced methodologies resolving dimensionality complications for autism neur...
7 ChatGPT Prompts to Help You Define Your Ideal Customer Profile.pdf
sap open course for s4hana steps from ECC to s4
Spectral efficient network and resource selection model in 5G networks
Programs and apps: productivity, graphics, security and other tools
Build a system with the filesystem maintained by OSTree @ COSCUP 2025
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Cloud computing and distributed systems.
Electronic commerce courselecture one. Pdf
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
The Rise and Fall of 3GPP – Time for a Sabbatical?
Per capita expenditure prediction using model stacking based on satellite ima...
KOM of Painting work and Equipment Insulation REV00 update 25-dec.pptx
20250228 LYD VKU AI Blended-Learning.pptx
The AUB Centre for AI in Media Proposal.docx
Approach and Philosophy of On baking technology
Spectroscopy.pptx food analysis technology

ruby2600 - an Atari 2600 emulator written in Ruby

  • 1. An Atari 2600 emulator 100% written in Ruby (and RSpec!) Carlos Duarte do Nascimento (Chester) @chesterbr / http://chester.me
  • 3. If so, you probably had this...
  • 4. ...or one of these...
  • 5. ...or you used an emulator http://stella.sourceforge.net
  • 6. Emulator A program that runs software written for one type of computer system in another type by simulating the hardware of the original system
  • 7. ruby2600 ● Atari 2600 emulator ● Written in Ruby ● Runs quite a few classic games ● Open-source http://github.com/chesterbr/ruby2600
  • 8. Why? There are great emulators out there, but they strive for speed above readability A test-driven emulator in a high-level language is a great learning tool Always wondered how much TDD would help on wildly unfamiliar territory (also: why not? ☺)
  • 9. Work in progress! ● A few subtle bugs ● Does not run every game ● Not full-speed ● No sound http://github.com/chesterbr/ruby2600
  • 10. We'll see ● How the Atari works ● CPU emulation ● Architecture (just a bit) ● Ruby2600 in action ● The future
  • 11. @chesterbr http://chester.me About me (Chester) © Ila Fox - http://www.ilafox.com
  • 12. Building an Emulator: How the Atari 2600 works
  • 13. Let's peek inside... (Atari 2600 Jr. printed circuit board)
  • 18. Challenging specs ● CPU speed: 1.19 MHz (not GHz) ● Max cart (program) size: 4 KB ● RAM: 128 bytes ● Video RAM: 0KB (game code has to drive TIA into generating each scanline in realtime)
  • 19. Atari 2600 in a nutshell The CPU reads a game program from the ROM chip on the cartrigde It confgures the pixels generated by TIA, using RAM, I/O and timers provided by the RIOT chip Our goal: simulate this in software
  • 20. Building an Emulator: CPU image CC-BY Konstantin Lanzet
  • 21. 65xx family: in the past... http://en.wikipedia.org/wiki/MOS_Technology_6502#Computers_and_games
  • 22. ...and in the future! http://en.wikipedia.org/wiki/MOS_Technology_6502#In_popular_culture
  • 23. The 6507 CPU Reads instructions from the cartridge that manipulate and transfer bytes between chips, keeping state on internal registers and flags http://en.wikipedia.org/wiki/Von_Neumann_architecture
  • 24. Emulated 6507 As it executes each instruction, it keeps instance variables for registers (@a, @x, @y), flags (@n, @z, ...) and @memory as an array
  • 25. CPU.rb module Ruby2600 class CPU attr_accessor :memory attr_accessor :pc, :a, :x, :y, :s # Flags (P register): nv--dizc attr_accessor :n, :v, :d, :i, :z, :c def step ...runs a instruction... end ...
  • 26. module Ruby2600 class CPU attr_accessor :memory attr_accessor :pc, :a, :x, :y, :s # Flags (P register): nv--dizc attr_accessor :n, :v, :d, :i, :z, :c def step ...runs a instruction... end ... CPU.rb TESTS FIRST!TESTS FIRST!
  • 28. Assembly debugging == PAIN! To avoid it, we need technical specifcations that are easy to read, yet detail-oriented enough to test emulator code RSpec does the job! http://rspec.info
  • 31. CPU_spec.rb context 'INX' do before do cpu.memory[0] = 0xE8 # INX cpu.pc = 0x0000 cpu.x = 0x07 end it 'should advance PC by one' do cpu.step cpu.pc.should == 0x0001 end it 'should set X value' do cpu.step cpu.x.should == 0x08 end ...
  • 32. Using shared examples shared_examples_for 'advance PC by one' do it { expect { cpu.step }.to change { cpu.pc }.by 1 } end shared_examples_for 'set X value' do |expected| it do cpu.step value = cpu.x value.should be(expected), "Expected: #{hex_bye(expected)}, " + "found: #{hex_byte(value)}" end end
  • 33. More syntactic sugar 1.upto 3 do |number| shared_examples_for "advance PC by #{number.humanize}" do it { expect { cpu.step }.to change { cpu.pc }.by number } end end RSpec.configure do |c| c.alias_it_should_behave_like_to :it_should, 'should' end
  • 34. “Literate Testing” context 'INX' do before do cpu.memory[0] = 0xE8 # INX cpu.x = 0x07 end it_should 'advance PC by one' it_should 'take two cycles' it_should 'set X value', 0x08 it_should 'reset Z flag' it_should 'reset N flag' ... http://en.wikipedia.org/wiki/Literate_programming
  • 35. Less effort → better coverage ● Each instruction tested in every possible addressing mode ● Easy to understand, high-level tests ● Tests become a specifcation - specs!
  • 36. CPU.rb module Ruby2600 class CPU attr_accessor :memory attr_accessor :pc, :a, :x, :y, :s # Flags (P register): nv--dizc attr_accessor :n, :v, :d, :i, :z, :c def step ...runs a instruction... end ...
  • 39. No byte/word data types :-(CPU.rb def fetch @opcode = memory[@pc] @param_lo = memory[word(@pc + 1)] @param_hi = memory[word(@pc + 2)] @param = @param_hi * 0x100 + @param_lo @pc = word(@pc + OPCODE_SIZES[@opcode]) end Lookup table
  • 40. more lookup! CPU.rb def decode if (@opcode & 0b11111) == BXX @instruction = BXX elsif (@opcode & 0b11111) == SCX @instruction = SCX else @instruction_group = @opcode & 0b11 mode_in_group = (@opcode & 0b11100) >> 2 @addressing_mode = ADDRESSING[ @instruction_group][mode_in_group] @instruction = @opcode & 0b11100011 end @time_in_cycles = time_in_cycles end
  • 41. CPU.rb def execute case @instruction when LDA flag_nz @a = load when STA store @a when JMPabs @pc = @param when BXX @pc = branch ...
  • 42. Final result Full instruction set covered by more than 1,700 tests Only one CPU bug so far had to be debugged in-game
  • 43. Building an Emulator:Building an Emulator: ArchitectureArchitecture image CC-BYimage CC-BY Benjamin EshanBenjamin Eshan
  • 45. Memory-based I/O CPU “talks” to other chips by reading and writing specifc memory locations: 0000-002C – TIA (write) 0030-003D – TIA (read) 0080-00FF – RIOT (RAM) 0280-0297 – RIOT (I/O,Timer) F000-FFFF – Cartridge (ROM) (very simplified, see: http://nocash.emubase.de/2k6specs.htm)
  • 46. Bus Acts as a memory façade to the CPU, routing reads and writes to the appropriate chip class It is also the interface where we “plug” an UI (anything that displays images and reads keypresses)
  • 48. Ruby spice: duck typing Instead of defning read/write methods, make Bus,TIA, RIOT and Cart classes “quack” like arrays
  • 49. TIA.rb / RIOT.rb / Cart.rb (and also bus.rb!) def [](position) ...return value for position... end def []=(position, value) ...react to writing value to position... end
  • 50. Benefts ● High decoupling: CPU,TIA, RIOT and Cart are (mostly) independent ● We can use regular arrays as mocks for TIA, RIOT, Cart and Bus itself! ● We can “plug” different UIs (e.g.: text-mode rendering, network multiplayer, joystick interface, etc.)
  • 51. Cart.rb (full source) class Cart def initialize(rom_file) @bytes = File.open(rom_file, "rb") { |f| f.read }.unpack('C*') @bytes += @bytes if @bytes.count == 2048 end def [](address) @bytes[address] end def []=(address, value) # Don't write to Read-Only Memory, duh! end end
  • 52. Timing As TIA generates each pixel for each scanline, it will "tick" the CPU and RIOT to keep everything in sync image cc-by Steve Evans
  • 53. TIA.rb def draw_scanline scanline = [] 0.upto(SCANLINE_WIDTH) do |pixel| scanline << topmost_pixel tick_other_chips pixel end return scanline end def topmost_pixel ... def tick_other_chips @cpu.tick if pixel % 3 == 2 @riot.tick if pixel % 3 == 0 end TIA runs 3x faster than CPU and RIOT
  • 55. Graphic Objects To keep TIA's responsibility focused on building the frames, we will offload object drawing to separate classes (Playfeld, Player, Ball, Missile) For the common behavior, should we use composition or inheritance?
  • 56. Composition and Inheritance A common ancestor (Graphic) contains the common behavior, and each class adds its own flavor Behavior that does not defne a Graphic (position counters) is better suited for a separate class, using composition instead of inheritance
  • 58. Building an Emulator: Let's run it! reproduction:reproduction: Young FrankensteinYoung Frankenstein
  • 60. Building an Emulator: Speeding up TBBT 1-06 "The Middle-Earth Paradigm", © 2007 Chuck Lorre Productions / WB Television
  • 61. Knuth, Donald (December 1974). "Structured Programmingwith go to Statements",ACM Journal Me and Prof. Knuth hanging out. We're, like, bros. Really. "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil"
  • 62. Refactoring Thanks to test coverage, we can safely play around and refactor for speed (while keeping it readable)
  • 63. JRuby We have a small working set (no more than 5KB) handled in very tight loops Have to measure, but it smells like the kind of modern-CPU-friendly code that could be generated via JIT http://en.wikipedia.org/wiki/Just-in-time_compilation
  • 64. If nothing else works The modular design gives us freedom to rewrite any part using other languages and/or replace them with existing code http://www.6502.org/tools/emu/#emulation
  • 67. Credits and License This presentation is available under the Creative Commons “by-nc” 3.0 license noticing the exceptions below Images from third parties were included (with due credits) under fair use assumption and/or under their respective licenses. These are excluded from the license above. Atari™ and likewise characters/games/systems are mentioned uniquely for illustrative purposes under fair use assumption. They are property of their rights holders, and are also excluded from the license above.