Saturday, March 13, 2021

Vaccinate! Vaccinate!

A lot of emotions today.

It was exactly one year ago today, March 13, 2020, we decided to send everyone home from work because of the Coronavirus. Our IT dept. stepped up and quickly installed remote desktop software and VPN solutions on hundreds of workstations. Some of us, like me, had dedicated development hardware, so I had to take everything home and then get a hardware VPN shipped to my house.

The following weeks were scary. We didn't fully understand how the virus was transmitted. We were scared to leave the house and store shelves were emptied. I ordered some necessary medications and cat food from the internet,  and when boxes were delivered, I'd just leave them sitting by the door for several days before opening them. 

I'm reliving these emotions today, not just because it's the one-year anniversary, but I also got my first of two vaccination shots today! What a year we've gone through collectively and some trials my family has gone through as well. We thought we'd be working from home for 2 weeks, a month at the worse. I haven't seen the inside of my office for 365 days now. One year!  I've heard from co-workers that needed to go in our office that it's a time capsule from life one year ago, pre-COVID.

As I waited for my shot, I remembered everything that happened this past year. In one week last December a family member was diagnosed with cancer, my granddaughter was born, and my father-in-law passed away from COVID.

When I got the call that I could get vaccinated, it was like a huge weight was lifted from my shoulders and I could finally see the light at the end of the tunnel. It will still be years before we're back to normal if there even is a normal anymore. I have no idea if I'll even be working in an office building again. But things are looking up. When it's your turn, do us all a favor and get your vaccine!

Friday, March 12, 2021

Emulation!

It's been close to 25 years since I last worked on writing an emulator. When I undertook that project, it was to prove that a game console (in my case, the Sega Genesis) could be emulated on a PC. I didn't even realize there was an emulation scene and I wasn't the first. I discovered all that after I wrote the emulator. I didn't really even know what I was doing with the emulator, so it wasn't code to be proud of. It did work and I could play a large percentage of Sega Genesis games and even emulated the 32X add-on decently well. Apparently, I was the first to do so. As I tried for more accurate emulation, it was clear my ad hoc experiments weren't the proper method for emulation. I would need to start from scratch.

I do remember briefly starting on a new architecture, but it didn't get far and I got distracted by other things that life throws at you. But, in the intervening 25 years or so, I've never stopped thinking about emulation. I think I've even coded a few in my dreams. It's great therapy when you can't fall asleep.

One week ago, on March 5, 2021, I loaded up Visual Studio and started coding. It's now been seven days and I have a running NMOS 6502 core running at a cycle level and it passed a functional test I found on GitHub.

So what are my goals with this thing? Let's start with a quick list:

  • Cycle accuracy. I don't mean I run an instruction and it updates the clock by 3 because it's a 3 cycle instruction. No, I mean I want to emulate what happens during each cycle of an instruction. Typically this means slow emulation, but I have some ideas to make this quick, and let's admit it, today's processors are wicked fast and we have a lot of cores to play with.
  • Each device (CPU, I/O, Video Chips, etc) will be self-contained. They will not know anything outside of what the chip can do.
  • A bus architecture to connect the devices (chips.)
  • An architecture plus a scripting language that will allow the user to quickly connect various devices (chips) together to create a wide variety of different computers and game consoles.
There! That shouldn't be too hard, right?

By my second day of coding, I had a base device class, a bus class, memory devices, RAM, and ROM. I also came up with the idea of a pin class. A device could have any number of pins, such as RES (for reset), IRQ (for interrupt), etc. and the pins could be connected between devices. A DMA chip could lower the RDY pin on the CPU so the processor would stop processing while the DMA happened. These are the sorts of details needed for highly accurate emulation. Along with the Pin class, I added some basic gate classes, such as AND and OR for connecting them like a real digital circuit.

I spent 3 more days and coded up a NMOS 6502 emulator. After bouncing around ideas for months, I ended up with a large table that was 7 TStates wide by 256 opcodes tall. Each entry would be a 'task' that would be completed by that opcode during a specific TState (cycle.) I started coding these up, and I was going to need too many unique tasks that were really similar. Then I realized I could encode the command in the higher bit ranges and the lower bits could encode registers, etc. I had basically just re-invented micro-coding, which is how most CPUs after the 6502 were implemented in silicon. I ended up with 33 microcode ops, but if I was a bit more clever I could write fewer. I haven't yet implemented the illegal 6502 instructions, but due to the nature of how they work, they are basically combinations of existing instructions so they shouldn't need any new micro-ops. I will simply need to update the table.

I do plan on emulating every variant of the 6502 ever made. And since I have this table of microcode, I won't need to hack my actual C++ code, but instead, just have an alternate microcode table for processor variants.

Tonight I finished testing with Klaus Dormann's 6502 Functional Test. I added some timing info and the test is running at the equivalent of a 109 MHz 6502! Just a tad faster than the Apple ][+ I grew up with!

I'll finish up this first (of many, I hope!) development blogs with a small bit of code. This function creates a computer using a 6502 and 64K of RAM then starts running the functional test.


static void DormannFunctionalTest( void ) { 

// create a test 6502 computer

RAM ram( 0x10000 );

Bus bus;

MCS650X cpu( MCS650X::MOS6502 );


bus.AddMemory( &ram, 0x0000 );

cpu.SetBus( &bus );

        cpu.AttachRDY( &VCC ); 


bus.LoadBinary( "6502_functional_test.bin", 0x0000 );

bus.Write16( 0xfffc, 0x0400 ); // start vector


// Run for awhile

for (;;) {

cpu.Update();

}

}

For now, I directly called the CPU's Update function. Later, I'll add a Machine class that will have a clock and will automatically call the Update functions for all the devices in the machine.

If anyone knows a nice way to imbed code in blogger.com, let me know!