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

What's hot (17)

PDF
The Ring programming language version 1.7 book - Part 50 of 196
Mahmoud Samir Fayed
 
PDF
NoiseGen at Arlington Ruby 2012
awwaiid
 
PPTX
C++ AMP 실천 및 적용 전략
명신 김
 
PPTX
Week One - Introduction
chriswalton
 
PPT
Device tree support on arm linux
Chih-Min Chao
 
PDF
Flappy bird
SantiagoYepesSerna
 
PDF
Design and Implementation of GCC Register Allocation
Kito Cheng
 
PDF
The Joy of Server Side Swift Development
Giordano Scalzo
 
PPTX
Raspberry Pi with Java (JJUG)
Stephen Chin
 
PPT
Intro computer
onuma ruengkaew
 
PPT
Intro computer
arpaneenasin
 
PDF
Lost in Translation: When Industrial Protocol Translation goes Wrong [CONFide...
Marco Balduzzi
 
PPTX
Panda board
Kiranmoy Misra
 
PDF
Prototipare col raspberry pi
Gabriele Guizzardi
 
PDF
Html5 game, websocket e arduino
monksoftwareit
 
PPT
Game programming with Groovy
James Williams
 
PDF
Html5 game, websocket e arduino
Giuseppe Modarelli
 
The Ring programming language version 1.7 book - Part 50 of 196
Mahmoud Samir Fayed
 
NoiseGen at Arlington Ruby 2012
awwaiid
 
C++ AMP 실천 및 적용 전략
명신 김
 
Week One - Introduction
chriswalton
 
Device tree support on arm linux
Chih-Min Chao
 
Flappy bird
SantiagoYepesSerna
 
Design and Implementation of GCC Register Allocation
Kito Cheng
 
The Joy of Server Side Swift Development
Giordano Scalzo
 
Raspberry Pi with Java (JJUG)
Stephen Chin
 
Intro computer
onuma ruengkaew
 
Intro computer
arpaneenasin
 
Lost in Translation: When Industrial Protocol Translation goes Wrong [CONFide...
Marco Balduzzi
 
Panda board
Kiranmoy Misra
 
Prototipare col raspberry pi
Gabriele Guizzardi
 
Html5 game, websocket e arduino
monksoftwareit
 
Game programming with Groovy
James Williams
 
Html5 game, websocket e arduino
Giuseppe Modarelli
 

Viewers also liked (6)

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

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

PDF
mRuby - Powerful Software for Embedded System Development
Kazuhiro Koga 古賀一博
 
PDF
Optcarrot: A Pure-Ruby NES Emulator
mametter
 
KEY
Emulating With JavaScript
alexanderdickson
 
KEY
Modified "Why MacRuby Matters"
Sean McCune
 
PDF
Now is the time to create your own (m)Ruby computer
kishima7
 
PDF
mruby/c and data-flow programming for small devices
Kazuaki Tanaka
 
ODP
Ruby C extensions at the Ruby drink-up of Sophia, April 2012
rivierarb
 
PPTX
UNIT 1 _ Embedded system -design steps PPT.pptx
CCEnotes
 
PDF
Developing cross platform desktop application with Ruby
Anis Ahmad
 
PDF
Ruby for C#-ers (ScanDevConf 2010)
Thomas Lundström
 
PDF
Urd dioscuri kbna_v1_1_en_2
seakquechchhan
 
PDF
JRuby: The Hard Parts
Charles Nutter
 
PDF
How to control physical devices with mruby
yamanekko
 
PDF
X-ISCKER
Jose Pinilla
 
ZIP
Why MacRuby Matters
importantshock
 
PDF
MacRuby For Ruby Developers
Renzo Borgatti
 
PDF
Metaprogramming in Ruby
John Vlachoyiannis
 
PPT
Open Kode, Airplay And The New Reality Of Write Once Run Anywhere
guest991eb3
 
PDF
Experiments in Sharing Java VM Technology with CRuby
Matthew Gaudet
 
PPTX
Symbian OS
Adit Pathak
 
mRuby - Powerful Software for Embedded System Development
Kazuhiro Koga 古賀一博
 
Optcarrot: A Pure-Ruby NES Emulator
mametter
 
Emulating With JavaScript
alexanderdickson
 
Modified "Why MacRuby Matters"
Sean McCune
 
Now is the time to create your own (m)Ruby computer
kishima7
 
mruby/c and data-flow programming for small devices
Kazuaki Tanaka
 
Ruby C extensions at the Ruby drink-up of Sophia, April 2012
rivierarb
 
UNIT 1 _ Embedded system -design steps PPT.pptx
CCEnotes
 
Developing cross platform desktop application with Ruby
Anis Ahmad
 
Ruby for C#-ers (ScanDevConf 2010)
Thomas Lundström
 
Urd dioscuri kbna_v1_1_en_2
seakquechchhan
 
JRuby: The Hard Parts
Charles Nutter
 
How to control physical devices with mruby
yamanekko
 
X-ISCKER
Jose Pinilla
 
Why MacRuby Matters
importantshock
 
MacRuby For Ruby Developers
Renzo Borgatti
 
Metaprogramming in Ruby
John Vlachoyiannis
 
Open Kode, Airplay And The New Reality Of Write Once Run Anywhere
guest991eb3
 
Experiments in Sharing Java VM Technology with CRuby
Matthew Gaudet
 
Symbian OS
Adit Pathak
 
Ad

More from Carlos Duarte do Nascimento (7)

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

Recently uploaded (20)

PDF
Researching The Best Chat SDK Providers in 2025
Ray Fields
 
PPTX
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
PDF
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
PDF
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
PDF
Per Axbom: The spectacular lies of maps
Nexer Digital
 
PDF
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
PDF
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
PPTX
Agentic AI in Healthcare Driving the Next Wave of Digital Transformation
danielle hunter
 
PDF
State-Dependent Conformal Perception Bounds for Neuro-Symbolic Verification
Ivan Ruchkin
 
PDF
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
PDF
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
PDF
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
PPTX
Agile Chennai 18-19 July 2025 Ideathon | AI Powered Microfinance Literacy Gui...
AgileNetwork
 
PPTX
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
PDF
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
PDF
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
PDF
AI Unleashed - Shaping the Future -Starting Today - AIOUG Yatra 2025 - For Co...
Sandesh Rao
 
PDF
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
PPTX
Agile Chennai 18-19 July 2025 | Workshop - Enhancing Agile Collaboration with...
AgileNetwork
 
PDF
Generative AI vs Predictive AI-The Ultimate Comparison Guide
Lily Clark
 
Researching The Best Chat SDK Providers in 2025
Ray Fields
 
AI and Robotics for Human Well-being.pptx
JAYMIN SUTHAR
 
Trying to figure out MCP by actually building an app from scratch with open s...
Julien SIMON
 
Make GenAI investments go further with the Dell AI Factory
Principled Technologies
 
Per Axbom: The spectacular lies of maps
Nexer Digital
 
Presentation about Hardware and Software in Computer
snehamodhawadiya
 
Research-Fundamentals-and-Topic-Development.pdf
ayesha butalia
 
Agentic AI in Healthcare Driving the Next Wave of Digital Transformation
danielle hunter
 
State-Dependent Conformal Perception Bounds for Neuro-Symbolic Verification
Ivan Ruchkin
 
How ETL Control Logic Keeps Your Pipelines Safe and Reliable.pdf
Stryv Solutions Pvt. Ltd.
 
Economic Impact of Data Centres to the Malaysian Economy
flintglobalapac
 
Google I/O Extended 2025 Baku - all ppts
HusseinMalikMammadli
 
Agile Chennai 18-19 July 2025 Ideathon | AI Powered Microfinance Literacy Gui...
AgileNetwork
 
AI in Daily Life: How Artificial Intelligence Helps Us Every Day
vanshrpatil7
 
Data_Analytics_vs_Data_Science_vs_BI_by_CA_Suvidha_Chaplot.pdf
CA Suvidha Chaplot
 
MASTERDECK GRAPHSUMMIT SYDNEY (Public).pdf
Neo4j
 
AI Unleashed - Shaping the Future -Starting Today - AIOUG Yatra 2025 - For Co...
Sandesh Rao
 
Peak of Data & AI Encore - Real-Time Insights & Scalable Editing with ArcGIS
Safe Software
 
Agile Chennai 18-19 July 2025 | Workshop - Enhancing Agile Collaboration with...
AgileNetwork
 
Generative AI vs Predictive AI-The Ultimate Comparison Guide
Lily Clark
 

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.