Dodo: 6502 Game System

Handheld Game System featuring the 6502

Similar projects worth following
Dodo is a 6502 portable game system. What started as a simple homebrew computer has evolved into a retro gaming platform. Dodo uses an authentic 65C02 processor running at 1mhz without any emulation. Game development is easy with built in system functions for sprites, sound and input. Development is done in a web app that hosts an IDE, simulator, documentation and flashing utility all in one place. A completed game can easily be shown to your friends just by sending them a link, and then flashed to a game cartridge for playing on the actual device.

Check out to see some games

Dodo is comprised of two stacked boards with all through hole components for easy soldering and all parts are still in production. Nearly all Dodo technology is retro with a handful of modern parts. The screen is a beautiful 128x64 OLED and the games are stored on FRAM chips, but the heart of the machine is all 8-bit.

Coming soon as a kit!

There are many 6502 projects out there in the wild that I used to get up to speed with a basic design for this game system. I mostly followed the guidance found here. The address layout sacrifices some address space from RAM, but allows for up to 8 I/O chips to be very easily addressed. It also uses a single NAND IC for chip select logic which should limit propagation delays which should raise the potential top end speed of the circuit. However, this doesn't really matter since I am clocking it at 1mhz for now.

The display used is a pre-assembled component from Adafruit that has a SSD1305 driver chip and a 128x64 pixel OLED. The SSD1305 has a 6800 compatible bus mode which made it fairly straight-forward to interface with. I added bus tranceivers to go from 5v down to 3.3v. I also had to add a bit more complexity with the chip select logic because the SSD1305 only has a select line. The 65XX chips all have 2 chip select lines.

Dodo supports a single voice of sound. Unfortunately, there are no longer any sound generator ICs in current production like the SID from the C64. Basic sound is created through a trick with the 6522 VIA. The shift register can be set to "free run" and can be used to output a square wave.

Dodo also supports game cartridges so that the game code is separate from the system. The system software is stored on the EEPROM, it has the boot screens, the code to read and flash the game cartridges, and a game API. The API supports sprite drawing, sound playing, button interfacing, and so on. Games on Dodo target 20FPS. An interrupt fires every 50ms to coordinate a consistent game loop.

There is also a simulator for Dodo that works in both the console and through a web interface. Game development is done in C using cc65. The system API calls are all written in assembly.

  • 1 × WDC 65C02S Modern version of the 6502 that can be clocked higher, has low power mode, and is all static design
  • 1 × WDC 65C22S I/O chip, has 2x 8 bit ports as well as 2 internal timers
  • 1 × WDC 65C51N Connectors and Accessories / Miscellaneous Connectors
  • 1 × AT28C256 32k EEPROM
  • 1 × AS6C62256A 32k SRAM
  • 2 × SN74LVC245AN Bus transceiver to bridge 5v to 3.3v for display
  • 1 × L4931 3.3V regulator for display
  • 1 × MAX202CPE Interface and IO ICs / Multiprotocol Transceivers
  • 1 × 1 mhz oscillator Main clock
  • 1 × 1.8432 mhz oscillator RS232 clock

View all 14 components

  • Final Stretch

    Peter Noyes04/16/2017 at 21:47 0 comments

    The past few months have been spent getting Dodo ready to be available as a kit. Its a lot of work to get a kit together of this complexity! The hardware is final, the firmware final, parts have arrived, and most importably the documentation is complete!

    Check out the documentation at I have provided both assembly instructions and information pages on the sub-systems of Dodo.

    The last change to the firmware was to support versioning and improved flashing. There is now a version number built in that can be queried over the serial connection. Games record what version of the firmware they were built to target. Semantic versioning has been adopted and there is a version check when games load to avoid unexpected behaviors and allow for continued development.

    There is no longer a flash button on the splash screen. The flash button has been replaced with an Info button that will show the firmware version. Dodo listens for a flash command as it sits on the splash screen indefinitely. The user experience is now much improved.

    Be sure to check out, follow on twitter, and sign up for the e-mail list to stay updated on the latest Dodo news! The Tindie page will go live soon!

  • Happy Holidays

    Peter Noyes12/23/2016 at 04:24 0 comments

    For fun I hacked together a Christmas demo for Dodo. I found an animated GIF of a retro graphics style Santa which I then manually converted to monochrome. I use the program Pixen for laying out sprites. From there I took the 7 frames and dumped them as byte arrays and wrote a quick little program to cycle through the frames. The resulting sprite size was 42x48 so there were room to show 3 of them. The finishing touch was to get Jingle Bells playing in the background. Unfortunately 256 bytes are not enough to hold the complete song. I will go back and update the firmware to support longer music.

    See it in the playground here:

    Here is the original GIF:

  • Assembly Language and More

    Peter Noyes12/20/2016 at 02:56 0 comments

    The Dodo Playground now supports writing games in 6502 assembly. Some of the initial feedback I received for Dodo is that C is great and all, but a big part of the nostalgia for a 6502 retro system is to be able to write in 6502 assembly. I totally get it, I have had a lot of fun writing the system firmware in assembly. Now in the Playground, it is easy to make a language choice using the dropdown in the top navigation bar.

    Here is a working example in Assembly

    Making the change wasn't all that difficult, the back end compilation still uses cc65. Basically I just needed to author a thin set of assembly routines for calling each API, and update the backend with two different make files. The thin wrappers each hardcode an index into the API's jump table. The calling convention for C is pretty friendly for making assembly calls so that is left in place. Basically each parameter needs to be pushed onto a stack and I incorporated helper functions to do so. Here is a simple API call example:

            lda #<message
            ldx #>message
            jsr pushax
            jsr draw_string

    To support this new functionality involved making changes across the board so it was a good opportunity to finally make the last changes to fully take advantage of the updated address space in Dodo 1.2 and above. Video memory and user code space are now moved around to now give a game 22KB of available RAM.

    Another reason for supporting assembly in the playground is to make it much easier to iterate while implementing my 1KB challenge submission, which is to implement image compression for Dodo.

    The challenge for 1KB is to compress a single image such that the image data and algorithm all fit under the 1KB limit. As an extension to this I also want to challenge myself to fit 20 compressed images into 8KB. With 20 images, the new 22KB of avilable RAM and the fact that Dodo operates at 20FPS, it should be possible to store 1s of looping video in memory and be able to play it back! I just need to find the perfect idea for a 1s monochrome video loop. Any ideas?

  • Batteries

    Peter Noyes12/16/2016 at 05:42 0 comments

    Dodo has nearly reached its final form by now having integrated batteries! The Hackaday Superconference badge gave me the inspiration I needed to finally figure out a way to mount the batteries. By mounting the battery holders sideways on either side of the board, they are unobtrusive yet still accessible. To fit, I needed to downside to AAA batteries, but I think the tradeoff is worth it.

    I also now have a working boost regulator circuit on board. The previous revision (Rev 2) had the MAX756 but it didn't work. For Rev 3 I switched to the LT1303 and very carefully laid out the PCB after researching the best practices for laying out such a circuit. I also experimented with different capacitors. I am happy to report that it is running at 85% efficiency, which is as good as expected for this part.

    Unfortunately, Dodo does not run for long on typical alkaline batteries. However, with Ni-MH rechargeable batteries, or with lithium batteries the life is much better. My rechargeable batteries yield a life of around 3 hours and the lithium batteries from Energizer last nearly 5 hours.

    Dodo uses around 100mA at 5V. Below is the formula for the current draw from the batteries based upon the 85% efficiency. At 3v, the current draw is around 200mA. Once the batteries are nearly depleted at 2V, the current draw is nearly 300mA.

    200-300mA is quite high for an alkaline battery and significantly degrades the capacity. For instance, a 750mAh alkaline battery might instead only provide 500mAh when the current is large. The voltage also falls quickly with the alkaline batteries. On the other hand, a lithium battery holds a voltage closer to 1.5V for much longer. Also, the lithium battery is able to provide a high current without losing capacity. The rechargeable batteries seem to behave similar to the lithium batteries. I therefore recommend that rechargeable batteries be used with Dodo.

    The battery indicator is also working spot on. I have it tweaked to go off when the voltage reaches 2V. The LT1303 has an internal voltage comparator and the LBO pin goes low when that threshold is reached. The trip voltage is 1.24v which is too low for a pair of AAA batteries. I use a voltage divider to scale that threshold. I am using values of 255k and 412k resistors for the divider. For my rechargeable batteries, the battery indicator goes off when there is right around 10 minutes of life remaining.

    Unfortunately, version 1.3 is still not right :( There is a problem with the wiring of the low battery indicator on the top board. I was able to fix it with patch wires but a new PCB will be needed. I guess the 4th try will be a charm.

  • EEPROM Flashing

    Peter Noyes11/16/2016 at 06:06 3 comments

    One of the big remaining tasks before Dodo is ready to be available as a kit is to support in-circuit flashing of the 32kb EEPROM that holds the system firmware. I want to continue to add functionality and it would be a major bummer to require everyone to pull a chip out and use a separate EEPROM burner. As of this week, Dodo now officially supports EEPROM flashing over the serial cable!

    Version 1.2 of the hardware hooked up the control signals such that in theory the flashing could work, but it took software changes to make it a reality. The trickiest part is that the system code basically needs to overwrite itself which is not straightforward. I ended up creating a small standalone routine that reads from the serial port and writes to the ROM and it is embedded as a resource in the system firmware. This routine is copied into a reserved area in RAM and then executed from there so that no code is read from the ROM while its being written to.

    I am pretty happy for my own sake that this now works. I have pulled the chip and reprogrammed it over 100 times during development. I can now iterate much faster when making firmware changes.

    In other news, I ported a simple version of Tetris to Dodo. Here is a playable version in the playground.

  • See Dodo at SuperCon

    Peter Noyes11/05/2016 at 07:27 5 comments

    I will be at SuperCon tomorrow with version 1.2 of the Dodo hardware!

    This new revision was a bit painful to get up and running. There were two mistakes made on the PCB, the MAX756 battery regulator doesn't have enough oomph for Dodo, and there is a mechanical clearance problem. The wires coming out the top of Dodo in the picture above are a patch to fix one of the PCB issues.

    The good news is that I have found a replacement regulator that works (I have a breadboard of it), the new memory decoding scheme works and gives close to the full 32KB of RAM. And, I got to buy a logic analyzer to help troubleshooting!

    With hopefully all the issues now resolved I plan to start offering kits soon on Tindie. If anyone is interested hop on over to to get on a mailing list for updates. Also, I ported the old QBASIC classic Nibbles over to Dodo and there is a link to play it on the same page.

  • Hardware v1.2

    Peter Noyes10/12/2016 at 03:29 0 comments

    At this point, there is only one working Dodo in existence, so not quite extinct ;-), but this needs to change! The next step in getting more Dodos out there is a new hardware revision.

    For a bit of history, the version 1.0 boards had several known problems, so it never seemed worth it to make any more prototypes. There was a version 1.1 that was designed to correct the most glaring issues, but no boards were ever fabricated because a more extensive update is really what was needed. Well, the time is now! Version 1.2 boards are off for fabrication.

    Here are the highlights:

    • RAM Upgrade. Now all 32KB is accessible
    • In place firmware updates
    • Faster game flashing
    • Thinner, no longer uses IDC cables between boards
    • Battery powered. Will run off of 2 AA Batteries.

    Above is a mockup of the new PCBs that I printed out. I have learned my lesson and will now always print these out and do some test placements of components.

    The RAM upgrade opens up the possibility of adding a BASIC interpreter to Dodo. The plan is to allow 6502 Assembly, C, and BASIC as different options for game development, but all using the same API.

    Dodo 1.0 supported flashing game cartridges over serial, but updating the firmware stored in the EEPROM required extracting the chip and using a dedicated programmer. The new Dodo will be able to program the EEPROM over the serial port.

    The new Dodo will also have RS232 control lines connected which will enable more efficient communication that will ultimately result in faster game flashing.

    Now the boards will be able to be mounted closer together, which means that the overall thickness of the device will be substantially less.

    Finally the new Dodo is battery powered. Two AA batteries should last around 10 hours. There will even be a low battery indicator!

    The battery circuit uses the Max756CPA+ which is able to boost the voltage of 2 AA batteries up to the 5V that Dodo needs. In the video above I am showing the test circuit I breadboarded to help fine tune the resistor values needed for the low battery indicator. The Max756 chip has an open drain low battery output pin that is driven low when a reference voltage falls below a 1.25v threshold. I wanted to show the low battery indicator when the voltage is 2v, so a voltage divider is needed to drop it down to around the threshold. In the video you see the second LED turn on as soon as the voltage falls to 2v, which is exactly what I want! The 2v is chosen based upon looking at the discharge curve of AA batteries and that is around the inflection point where the voltage really starts to tailspin.

    Once I have the new boards in my hands and have assembled a few prototypes, the next step will be to make some software updates to take advantage of the new hardware features. At that point the project is basically complete. If there is interest I will make a kit available on Tindie.

  • Playground Flashing

    Peter Noyes10/01/2016 at 04:00 0 comments

    Last update introduced the Playground, where games can be written in simulated all from within the web browser. Now, users of Chrome will be able to flash games right from within the browser, with the help of a Chrome App. Chrome Apps have the capability of interfacing directly with hardware, such as USB, Serial, and Bluetooth. Additionally, web pages can send and receive messages with Chrome Apps if they are white-listed by the App. With those two pieces web flashing is possible!

    When the playground website loads, it checks for the existence of the App and if found it reveals a flash button. The website queries the App for a list of COM ports, and then when flashing commences, it sends the App the compiled game binary that was built in the cloud and then the App sends the bytes over Serial to the real Dodo hardware. As the bytes are transmitted, progress messages are sent back so that a progress bar can be updated. Check out the video to see how it all works.

    Additionally, this means that a Chromebook can be used as a complete development environment for Dodo. The only feature missing from the Playground at this point is a way to more easily save games as they are being developed. Right now, a user would have to save a unique hyperlink every time they want to 'save' to get back to where they were. The problem is that for persistent storage I probably need to introduce the concept of a logged in user as an option to the playground. Perhaps I will use Github for single sign on using OAuth2.

  • Playground

    Peter Noyes09/15/2016 at 05:03 8 comments

    I am back! I had to take a hiatus from working on this project for the past several months, but over the past few weeks I have been busy. My most recent advancement is a playground!

    The playground is a web application that simplifies developing games for Dodo by having an IDE and Simulator that run as a hosted service. For everything developed there is a shareable link that is generated.

    For instance here is a a link to the game 0xDEADBEEF

    0xDEADBEEF in Playground

    Note that it is not playable on a mobile device at the moment

    The playground was a concept that I wanted to pursue since the beginning of the project. I thought it would be awesome to bring 6502 development into the cloud era. Having a Web IDE with an integrated simulator lowers the barrier to entry to get people to experiment with the project, and for my own development it seriously improves the speed at which I can iterate.

    The first step was to write a simulator, which I did a while back in the language Go. The initial simulator ran as a console application. I then developed a web version that used Websockets to stream the graphics from a backend server to the client in real-time. The approach of running the simulation in the cloud worked, but it just consumed too many resources and scaling it would be difficult.

    The solution would need to have the simulator run locally on the client. I put the playground on the backburner because I really wanted to stick with Go as a language, porting to JavaScript is not my idea of fun. Thankfully, I randomly stumbled across the project GopherJS which transpiles Go code into JavaScript so that it can run locally in the browser. I could stick with Go! Using GopherJS wasn't competely seamless, because the simulator ran painfully slow at first. Also, my orginal code relied on multi-threading and JavaScript is single threaded. It took several passes at optimizing the code to achieve a playable framerate in most browsers. Chrome works the best.

    The development language for Dodo is 'C' and it is compiled using cc65. The playground works by hosting cc65 in the cloud.

    Here is roughly how the whole system works:

    • The user vists the webpage and gets served the HTML file and the transpiled Go code which is now JavaScript
    • The code starts by requesting the firmware from the website, as well as the 'C' code associated with the particular hyperlink
    • The code is then placed within the Ace editor that is running locally in the browser
    • When the user clicks Run it sends the 'C' code back up to the cloud where it attempts to compile it.
    • The web service returns either with the compiled game as a chunk of bytes, or an error message
    • If it gets the firmware it then fires up the simulator with the game and it all runs local

    With this design the heavy lifting is mostly done by the client. The server just has to compile the code. This is also scaleable.

    I also made some advancements with the simulator. Because there is an easy to use Audio API in most browsers, I was able to get sound simulated fairly easily. I also pulled it into its own library so it could be embedded in other contexts.

    Here are some other playground links:

    Slide puzzle from last post

    Proof of concept of bird version of space invaders 'Poovaders'

    Hello World

    Here is the repository on Github

  • Mother's Day Slide Puzzle

    Peter Noyes05/14/2016 at 16:12 1 comment

    For Mother's Day a few weeks ago I made my wife a game on Dodo! It is basically one of those plastic slide puzzle games like this:

    The picture for the puzzle is of our two kids. My wife loves big band music so I set the background to 'Moonlight Serenade', which is her favorite. That era of music reminds her of her Grandparents. The game is written in 'C' and is only a few hundred lines of code. The screen is 128x64, so the puzzle is rectangular instead of square. At first I sliced the image up so that the puzzle would be 8x4 (32 pieces). This proved to be very difficult to solve, especially with the image being low resolution and dithered. Each piece is completely unrecognizable until it forms the final image and you look at it from a distance. I then changed it to 4x2 (8 pieces) which felt about right in terms of difficulty.

    To load the image I found this great little project on Github that simulates the Atkinson Dithering from early the early Macs. I use this to create the bitonal image needed for Dodo.

    The game has the concept of a Cursor. If you click 'A' while the Cursor is on a piece next to the hole, the piece then moves to occupy that hole. To support the cursor I added the XOR drawing mode to the sprite drawing function. Repeatadly drawing a white block in XOR mode over the piece causes it to flash.

    The music is encoded by hand in the following manner:

    #define Cs1 224
    #define D1  210
    #define E1  188
    #define F1  177
    #define Fs1 168
    #define G1  158
    #define Gs1 149
    #define A1  140
    #define Bb1 133
    #define C2  118
    #define D2  104
    static byte const _music[92] = { Cs1, 12, D1, 40, E1, 4, F1, 4, D1, 40, E1, 4, F1, 4, D1, 16, E1, 4, F1, 4, D1, 16, E1 ...

    I have defined the various notes needed by the music. Each represents a number that is used by the VIA shift register to ultimately output the correct frequency. The music is a byte array alternating between notes and durations. A duration of 1 amounts to 50ms. For the tempo of the song, and to make it possible to encode triplets, I chose that a quarter note will be represented by 12.

    Looking at the sheet music it starts with a quarter note of C#, which is encoded by Cs1, 12. The next note is tricky. It is a dotted half note that is connected to the first note in the triplet. A triplet as a whole is meant to fill the space of a quarter note. So the duration of each note in the triplet is 4 (12/3). The dotted half note is meant to then represent 3/4 of the total measure. Each measure is a total duration of 48, so the dotted half note should be 36, however because it is connected to the triplet it gets 4 added for a total duration of 40, the next two notes complete the triplet and have a duration of 4.

    If a note of 0 is output, it represents silence.

    As you can see, encoding music can be a touch complicated, but to me, it is actually pretty fun!

    Thankfully my wife loved the present. I gave it to her on a game cartridge in a card! Here is the finished project:

View all 34 project logs

Enjoy this project?



Jim wrote 04/14/2017 at 19:00 point

I have played with the assembler in the play ground. I'm having issues with drawing a line with the set_pixel subroutine. If I run a counter from 0 to 19 (just picking a random end point), I can do an "lda counter" (loading from a memory address) and push to the stack for both x and y. That draws a line where x=y just like it should. But when I try to draw a vertical line with "lda #10" for x and "lda counter" for y, it just hangs.

I've also noticed that when I load an existing assembly language program, I have to select "c" and then select "assembly" before I can run it. Other wise it loads with the same type it was saved as ("assembly"), but tries to initially run as "C".

Hoping you kit some up soon and I can melt some solder... :-)

  Are you sure? yes | no

Yvan256 wrote 11/15/2016 at 20:00 point

"Unfortunately, there are no longer any sound generator ICs in current production like the SID from the C64."

Unless you are planning on manufacturing thousands of units, this shouldn't be a problem. There's still dozens of vendors on eBay selling the SN76489AN in various quantities from 1 to 50 units. I just bought five of them for only 2.82$CAD total, shipping included. At that price you could even use two of them to have stereo audio. A lot of work has already been done for this IC, see the wikipedia page for it. In my opinion this a low-cost, simple solution which fits perfectly with your project.

edit:  granted, the SN76489AN is no SID, but unlike the SID it's easily available.

  Are you sure? yes | no

Rosmianto Aji Saputro wrote 09/15/2016 at 05:57 point

Love reading the documentations here...

  Are you sure? yes | no

Jasmine Brackett wrote 04/02/2016 at 02:38 point

Great to see Dodo yesterday. Thanks for coming and bringing it!

Some photos are up:

  Are you sure? yes | no

Peter Noyes wrote 02/03/2016 at 21:08 point

Thanks man! Your bread project looks great too. My dad is really into baking sourdough bread and he doesn't have a proofing box. I can't wait to see how it turns out. I might need to build one someday!

  Are you sure? yes | no

Jan wrote 02/03/2016 at 20:22 point

Nice project there, mate! I always envy people who do things totally bare bone. I´m more like "a bit c++ here, a few libraries there" :)
Your board looks fantastic. I´m doing my first board in KiCAD. Hope it´ll turn out as nice!

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates