Showing posts with label Emulation. Show all posts
Showing posts with label Emulation. Show all posts

Saturday, January 17, 2015

An overview of writing a 6502 emulator

Overview

If you are interested in writing an emulator for a CPU, this is a good guide on getting started. If your interested in emulation, starting out with a simple emulator makes more sense. If you eventually want to write a more complicated emulator, the 6502 is simple enough that it isn't overwhelming, yet complex enough that it contains a good number of concepts that a more complicated CPU would have.

Basic Components and Concepts of the 6502

There are a few components and concepts of the 6502 that you will need to understand. This is just a brief overview of concepts, and there are many wonderful informative guides about these concepts. I recommend reading from several sources to get a deeper understanding

Stack:
This is a special location in the memory between $0100 and $01FF. The stack is a LIFO (Last In First Out) type of object. Its used as a temporary storage location. There is no protection against overflows. Its also fixed in place. The stack starts at the top of memory.

Registers:
Registers are used to hold small bits of information in the CPU. They are usually extremely fast to use, and are used to perform math operations, etc. They may also hold special processor flags, or pointers and counters to different places in memory.
  
Addressing:
The 6502 has 13 different ways that memory can be addressed.

Instructions:
The 6502 has 56 official instructions or OP Codes. The instructions are what carry out the work.

Memory:
This isn't actually a part of the 6502, memory would be a separate set of chips in a real device. For the purpose of an emulator though, the memory is considered a part of the CPU. There are a few special places in memory. there is a maximum of 64kb of memory, and all of the values in memory are values from 0-255.

The first 256 bytes of memory is the Zero Page memory.
The next 256 bytes of memory is the stack.
The last 6 bytes of memory contain 3 special addresses. At $FFFA - $FFFB is the Non-Maskable Interrupt address $FFFC-$FFFD is the power on reset address. and $FFFE - $FFFF contains the BRK/IRQ address.  These addresses are used by the CPU to find the code that gets executed when one of those specific events occur.

The rest of the memory can be divided up however the hardware dictates.


Where do you begin?

The hardest part, at least for me, was figuring out where to begin. There is a lot of information to absorb, and it will take some time to build up a mental model about how things work. The documentation online will only take you so far, and you are likely to encounter gaps.

 You are going to start by writing a method that performs a single CPU Operation. Mine ended up looking like this.


     Inside the ExecuteOpCode(); is a giant switch statement that switches on the CurrentOpCode value. You will want to write code that implements each instruction inside your switch statement. Start with the easy addressing modes, and make sure they work before doing the more difficult ones. The bulk of the work is going to be getting those instructions working correctly, if the behavior deviates at all from the real CPU, it won't work correctly.

You will also need to implement all of the Processor Flags and Registers an make sure they are being set and cleared. The Overflow and Negative flags are probably the most confusing flags, and I remember them giving me some trouble when dealing with Addition and Subtraction. 

Other Functionality

There is some other functionality you will need to add in order for things to work correctly. You will want to emulate the PowerOn and reset functions. You will also need to implement Interrupt Requests and NonMaskableInterrupts. 

You also are going to want some set of tooling to verify that things are working correctly. I wrote a really fancy test harness that shows all of the information at a glance, allows me to load and save the state of my program, set breakpoints, etc. You don't need to get this fancy, but it doesn't hurt, especially if you have limited knowledge of emulation and assembly language.

How will you know it works?

You need to test and then test some more. I ended up with just under 1000 unit tests. Most of my tests just loaded an opcode into memory and ensured that it worked correctly. Once you have implemented all of the opcodes, your next focus will probably be on some integration testing. I used a wonderful and very thorough test program by Klaus Dormann https://github.com/Klaus2m5/6502_65C02_functional_test that he wrote to test 6502 hardware that he was building. There are other test programs too. If your goal is emulating a specific device, there may be additional specific test programs.


Useful Links

http://visual6502.org/wiki
http://homepage.ntlworld.com/cyborgsystems/CS_Main/6502/6502.htm
http://www.atariarchives.org/alp/
http://en.wikipedia.org/wiki/MOS_Technology_6502
http://www.obelisk.demon.co.uk/6502/
http://www.6502.org





Saturday, January 10, 2015

Writing an NES Emulator: Work has Started

dotnetNES


I have officially broke ground on my new project. You can check the progress out here. You won't see much progress yet thought. This is the layout of the project. Just three simple projects.

  • Client - WPF Client
  • Engine - Class Library
    • Main
    • PPU
    • APU
    • Utilities
  • Tests - Class Library
I will be using folders and namespaces to segregate my code in the engine project. I plan to use WPF on the client along with MVVM. for MVVM I will be using the MVVM.Light Project, as its something I am familiar with. I am a big proponent of unit tests, and I include them in nearly every personal project I undertake. I'm relying on Nunit for unit testing, for the same reason as before, its something I am familiar with, and it does everything I need it to do.


The first task I have knocked out, is writing a cartridge loader. As a first task to get the project moving along, it seemed like something that would be pretty easy to implement. I used Jon Skeet's post on Loading Binary Files to handle loading the raw binary.  These two documents

where used as a reference guide when implementing the loader. I skipped some of the functionality, mainly the Players Choice Stuff, as I do not plan to implement any of that logic. I know that I planned to start testing the CPU first, however, most of the test programs are NES roms!

My next step will be to get the 6502 working with the loader, and get some tests added to run the NES tests.

Tuesday, January 6, 2015

Writing an NES Emulator: Overview

Writing a NES Emulator

I previously completed a project that emulated a 6502 processor. It was my first venture into the world of emulation, and I enjoyed it. I always wanted to turn the 6502 into something more though, namely an emulator of a game console. Originally, I thought about writing an ATARI 2600 emulator but after spending a lot of time thinking about it, I have finally settled on the NES system. There are a couple of reasons why I decided on the NES over the ATARI, the biggest reason being that the NES was my first real game machine, and it holds a fondness in my heart more than just about any other machine. Hopefully, by picking a machine that I have nostalgia for increases my chance of success.

Now, lets define some parameters that I want to operate under, so I have a clearly defined goal to reach.  I am shooting for a basic emulator, one that lacks anything but the most basic features required to get some of the NES games up and running. An outline of my plan is below

  1. Make sure that the basic CPU tests for the NES pass. I am not planning on worrying about implementing the illegal opcodes that only a small number of games use. I used a pretty comprehensive test program to validate the 6502 previously, so this should be quick, and give me a change to re-familiarize myself with the code I wrote.
  2. Get the graphics emulation working. I'll need to figure out how to emulate the PPU, which is the chip that drives the graphics.
  3. Get the audio emulation working. This should be a fun challenge!
  4. Input. This will be the easiest of the tasks I have to complete.
  5. Miscellaneous stuff. Things like loading the cartridge, and anything else
My basic plan all laid out in front of you. What could possibly go wrong?

You can check out the source here 

 Additional Posts
Work Has Started
6502 Overview