Wednesday, 9 April 2025

A Commodore 64 Emulator in Flutter: Part 11

Foreword

In the previous post we ran the Klaus Dormann Test Suite on our emulator. In this process we found a couple of issues with our emulator. We fixed a couple of issues, but found a couple of more issues we still need to fixed.

In this post we will look at the remaining issues. Solving these remaining issues wasn't so much of a deal at all, so this post will be shorter normal.

The remaining fixes

One of the major issues I found while running the Klaus Dormann Test Suite on my emulator, was some incorrect values for some of the CPU data tables. This include some instructions having the incorrect address mode and incorrect instruction lengths.

The other issue I experienced, was failed test cases because decimal mode wasn't implemented. Implementing Decimal mode is fairly straightforward. We start with implementing the following methods:

  int adcDecimal(int operand) {
     int l = 0;
     int h = 0;
     int result = 0;
     l = (_a & 0x0f) + (operand & 0x0f) + _c;
     if ((l & 0xff) > 9) l += 6;
     h = (_a >> 4) + (operand >> 4) + (l > 15 ? 1 : 0);
     if ((h & 0xff) > 9) h += 6;
     result = (l & 0x0f) | (h << 4);
     result &= 0xff;
     _c = (h > 15) ? 1 : 0;
     _z = (result == 0) ? 1 : 0;
     _n = 0;
     _v = 0;
     return result;
   }
 
   int sbcDecimal(int operand) {
     int l = 0;
     int h = 0;
     int result = 0;
     l = (_a & 0x0f) - (operand & 0x0f) - (1 - _c);
     if ((l & 0x10) != 0) l -= 6;
     h = (_a >> 4) - (operand >> 4) - ((l & 0x10) != 0 ? 1 : 0);
     if ((h & 0x10) != 0) h -= 6;
     result = (l & 0x0f) | (h << 4);
     _c = ((h & 0xff) < 15) ? 1 : 0;
     _z = (result == 0) ? 1 : 0;
     _n = 0;
     _v = 0;
     return (result & 0xff);
   }

We modify the applicable instruction selectors:

       case 0x69:
         adc(arg0);
         if (_d == 1) {
           _a = adcDecimal(arg0);
         } else {
           adc(arg0);
         }
       case 0x65:
       case 0x75:
       case 0x6D:
       case 0x7D:
       case 0x79:
       case 0x61:
       case 0x71:
         adc(memory.getMem(resolvedAddress));
         if (_d == 1) {
           _a = adcDecimal(memory.getMem(resolvedAddress));
         } else {
           adc(memory.getMem(resolvedAddress));
         }
         
      case 0xE9:
         sbc(arg0);
         if (_d == 1) {
           _a = sbcDecimal(arg0);
         } else {
           sbc(arg0);
         }
       case 0xE5:
       case 0xF5:
       case 0xED:
       case 0xFD:
       case 0xF9:
       case 0xE1:
       case 0xF1:
         sbc(memory.getMem(resolvedAddress));
         if (_d == 1) {
           _a = sbcDecimal(memory.getMem(resolvedAddress));
         } else {
           sbc(memory.getMem(resolvedAddress));
         }

Test Results

With everything fixed, we can see if all the tests passed.

The Test Suite runs for about two minutes on my emulator. After the two minutes, when hitting stop, the register window will look as follows:


From this point the program counter remains at 3469. Lets have a look at the assembly listing to see what is at this address:

So, this is confirmation that our emulator passed all the tests!

In Summary

In this post we confirm that we implemented all the CPU instructions correctly in our emulator, using Klaus Dormann's Test Suite.

Here is a link to the tag of this post's source code: https://github.com/ovalcode/c64_flutter/tree/c64_flutter_part11

In the next post we will start writing some more code to boot the C64 ROM's.

Until next time!