Sunday, 30 October 2016

Part 12: Emulating the keyboard

Foreword

In the previous post we managed to emulate a text mode C64 screen, together with a flashing cursor.

In this post we will be adding keyboard emulation. Specifically, we will be sourcing keys from an Android on screen keyboard (aka soft keyboard) and not a physical keyboard attached to our Android device.

Trapping Key Events from an on Screen Keyboard

In order to emulate a keyboard within our C64 emulator, it is important that we know at any point in time the complete state of our keyboard, that is which keys are down and which keys up.

In the Android world where it is more in common to use an On Screen keyboard than a psychical one, it is quite ironic that it is easier to trap up/down key events within an Android app from a physical keyboard than from an On screen keyboard.

Within Activities there exists the methods onKeyDown and onKeyUp that you can override to trap key events. These events, however, is only applicable for physical keyboards.

Another hiccup of an on screen keyboard is getting it to display. By default an on screen keyboard will only display if an editable control has focus. This is problematic in our situation, since we don't have editable controls on our screen.

Luckily the Android Framework provides us with a way out that allows us to create an explicit on screen keyboard by means of a KeyboardView. The details will become clear as we go along.

First, we need to add a KeyboardView to the layout of our FrontActivity:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.johan.emulator.activities.FrontActivity"
    tools:showIn="@layout/activity_front">
    
    <com.johan.emulator.view.C64SurfaceView
        android:id="@+id/Video"
        android:layout_width="320px"
        android:layout_height="200px" />

    <android.inputmethodservice.KeyboardView
        android:id="@+id/keyboardview"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:focusable="true"
        android:focusableInTouchMode="true"
        android:visibility="visible"/>

</RelativeLayout>

This will add an explicit keyboard at the bottom of the FrontActivity screen, which will be visible when the FrontActivity launches.

A KeyboardView needs to be provided with a keyboard layout. This layout is specified within a xml file. The following is an example xml layout file for a single key keyboard:

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="11%p"
    android:keyHeight="10%p" >

    <Row>
        <Key android:codes="49"    android:keyLabel="1"/>

    </Row>

</Keyboard>

Each layout consists out of a couple of rows and each row consists out of a couple of keys.

Each key element consists out of two main attributes. The first attribute is keyLabel which is the text to be displayed on the button. The second attribute is the codes property. This is the scan code to pass when that button is pressed or released. Usually the ASCII code of the label  is passed through as the scan code.

We can actually make the scan code work for us. For the scan code we can pass the actual C64 scan code, which will simplify our live a lot. A list of C64 scan codes can found here.

Next, let us write some code to associate the layout with our KeyboardView. So, within onCreate of the FrontActivity, at the following code:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    ...
        // Create the Keyboard
        Keyboard mKeyboard= new Keyboard(this,R.xml.kbd);

        // Lookup the KeyboardView
        KeyboardView mKeyboardView= (KeyboardView)findViewById(R.id.keyboardview);

        mKeyboardView.setKeyboard(mKeyboard);



        mKeyboardView.setPreviewEnabled(false);
        mKeyboardView.setOnKeyboardActionListener(new KeyboardView.OnKeyboardActionListener() {

            @Override
            public void onPress(int i) {
            }

            @Override
            public void onRelease(int i) {
            }

            @Override
            public void onKey(int i, int[] ints) {
            }

            @Override
            public void onText(CharSequence charSequence) {

            }

            @Override
            public void swipeLeft() {

            }

            @Override
            public void swipeRight() {

            }

            @Override
            public void swipeDown() {

            }

            @Override
            public void swipeUp() {

            }
        });


    }


The mKeyBoard instance contains a parsed version of the xml layout file. We can then assosiate this layout with our KeyboardView by calling mKeyboardView.setKeyboard(mKeyboard).

We also need to add an event listener to our KeyboardView. Currently all events defined in the listener are currently empty. We will give these methods some meat in the next section. For now it is worthwhile to mention that the onPress and onRelease are our key methods that can trap events when a key is pressed or released.

This is how the finished keyboard will look like in our FrontActivity:


I used characters from the Unicode character set for the labels of Return, BackSpace and Shift. Alternatively, KeyboardView provides the option to specify an image as label for these buttons. I will however not be exploring this option.

You will also realise something interesting going on with the shift key. This is in effect a toggle key. If it is on the green light will lit. If not it will be off. So, our shift key is in actual fact a Shift Lock key.

This toggle functionality is built in with KeyBoardView. To make a button toggable you just need to add the isSticky attribute for the particular key in the xml layout file, as shown below:

<?xml version="1.0" encoding="utf-8"?>
<Keyboard xmlns:android="http://schemas.android.com/apk/res/android"
    android:keyWidth="11%p"
    android:keyHeight="10%p" >
...
    <Row>
        <Key android:codes="15"    android:keyLabel="↥" android:isSticky="true" android:keyEdgeFlags="left" />
        <Key android:codes="12"    android:keyLabel="Z"  />
        <Key android:codes="23"    android:keyLabel="X" />
        <Key android:codes="20"    android:keyLabel="C" />
        <Key android:codes="31"    android:keyLabel="V" />
        <Key android:codes="28"    android:keyLabel="B" />
        <Key android:codes="39"    android:keyLabel="N" />
        <Key android:codes="36"    android:keyLabel="M" />
        <Key android:codes="0"    android:keyLabel="↤" />
    </Row>

    <Row>
        <Key android:codes="60"    android:keyLabel="SP" />
     </Row>


</Keyboard>

Integrating Keyboard with Emulator

Let us now integrate our On Screen Keyboard with our emulator.

Firstly, within our FrontActivity, define a private variable for the C64 Keyboard Matrix. Here is the variable declaration, together with the initialisation:

...
    private ByteBuffer keyBoardMatrix;
...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
...
        keyBoardMatrix = ByteBuffer.allocateDirect(8);
...
    }


So, the keyboard matrix is basically an 8 byte buffer. For more information on the ins and outs of the C64 keyboard, please have a look at the following post of JavaScript emulator series:

http://emufromscratch.blogspot.co.za/2016/06/part-13-implementing-workable-keyboard.html

We will also be using a ByteBuffer in the same way as we did in the previous post. In this way our native code can access the keyBoard matrix directly at any time without encountering JNI overhead when scanning the keyboard.

For completeness, let us cover the code for passing this ByteBuffer to the native code.

We start by defining the following native method stub within Emu6502:

    public native void setKeyboardMatrix(ByteBuffer keyBoardMatrix);

And we implement this method within memory.c:

...
jbyte* keyboardMatrix;
...
void Java_com_johan_emulator_engine_Emu6502_setKeyboardMatrix(JNIEnv* pEnv, jobject pObj, jobject oBuf) {
  keyboardMatrix = (jbyte *) (*pEnv)->GetDirectBufferAddress(pEnv, oBuf);
}
...


Obviously, this method needs to be invoked from our FrontActivity:

...
    @Override
    protected void onCreate(Bundle savedInstanceState) {
...
        keyBoardMatrix = ByteBuffer.allocateDirect(8);
        emuInstance.setKeyboardMatrix(keyBoardMatrix);
...
    }


Let us now implement the code for populating the Keyboard matrix:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    ...
        List<Keyboard.Key> keys = mKeyboard.getKeys();
        for (Keyboard.Key currentKey : keys) {
            if (currentKey.codes[0] == 15)
                shiftKey = currentKey;
        }
    ...
        mKeyboardView.setOnKeyboardActionListener(new KeyboardView.OnKeyboardActionListener() {

            @Override
            public void onPress(int i) {
                if (i == 15)
                    return;
                System.out.println("Kode: "+i);
                byte col = (byte)(i & 7);
                col = (byte) (1 << col);
                byte row = (byte)(i & 0x38);
                row = (byte) (row >> 3);
                row = (byte)(7 - row);
                System.out.println("Row: "+row);
                System.out.println("Col: "+col);
                byte tempKey = keyBoardMatrix.get(row);
                tempKey = (byte)(tempKey | col);
                keyBoardMatrix.put(row, tempKey);
            }

            @Override
            public void onRelease(int i) {
                if (i == 15)
                    return;
                byte col = (byte)(i & 7);
                col = (byte) (1 << col);
                byte row = (byte)(i & 0x38);
                row = (byte) (row >> 3);
                row = (byte)(7 - row);
                byte tempKey = keyBoardMatrix.get(row);
                tempKey = (byte)(tempKey & ~col);
                keyBoardMatrix.put(row, tempKey);
            }

            @Override
            public void onKey(int i, int[] ints) {
                if (i != 15)
                    return;
                if (shiftKey.on) {
                    byte tempKey = keyBoardMatrix.get(6);
                    tempKey = (byte)(tempKey | (1 << 7));
                    keyBoardMatrix.put(6, tempKey);

                } else {
                    byte tempKey = keyBoardMatrix.get(6);
                    tempKey = (byte)(tempKey & ~ (1 << 7));
                    keyBoardMatrix.put(6, tempKey);

                }
            }
           ...
        });

The code is very similar as described in my JavaScript emulator post I mentioned earlier on. Basically what happens is that each bit within the 8-byte ByteBuffer represent a specific key. If a particular bit is set to one, it means that the associated key is down. Conversely, if a bit is zero, the associated key is up.

In the above code, the shift key gets special attention since it is a toggable key. On initialisation we first loop through the keys within the mKeyboard instance, looking for a key with scan code 15 (e.g. the C64 scan code for Shift). Once we have found this key, we assign it to the shiftKey private variable.

We don't do anything with this key within the OnPress and Onrelease methods. We do, however, handle this key within the OnKey method. Within the Onkey method method we check the on value of the shiftKey. If true, we set the shift key bit within the matrix to one. Zero otherwise.

Now it is time to move onto the keyboard related native code within memory.c. This is, luckily, just a handful of code:

jchar getKeyPortByte(int outPortBits) {
  int temp = 0;
  int i;
  for (i = 0; i < 8; i++) {
    if ((outPortBits & 0x80) == 0)
      temp = temp | keyboardMatrix[i];
    outPortBits = outPortBits << 1;
  }
  return ~temp & 0xff;
}

jchar memory_read(int address) {
  if (address == 0xdc01)
    return getKeyPortByte(mainMem[0xdc00]);
  else
    return mainMem[address];
}

Let us have a look at the method getKeyPortByte. It accepts an parameter with name outPortBits. This is effectively the contents of memory location dc00 that falls within CIA#1. In its configuration within the C64, this location is responsible for energising selected rows on the keyboard matrix.

A row is energised by applying a logic zero to it. Each key in a row that is down, will pull the column in which it lives down.

Should you have a couple of rows pulled low and you have a couple of keys in these rows that is down for a specific column, the column will be pulled down. This sounds like a logical OR operation, but just with reversed polarity.

We make use of the logical OR property within the getKeyPortByte method. However, to make a logical OR work for us, we need to work with the assumption that active is a logic 1 instead of a logic 0. We do the inversion to active-when-low just before getKeyPortByte returns.

getKeyPortByte get used within memory_read when the requested address to read is dc01.

A quick Test Run

We end off this post with a quick test run.

I have entered a quick Hello World program in C64 Basic and gave a run:


That's it for this post.

In Summary

In this post we implemented an emulated keyboard to our emulator using an On screen keyboard.

In the next post we will be adding Tape emulation.

Till next time!

Tuesday, 25 October 2016

Part 11: Emulating the screen.

Foreword

In the previous post we managed to boot the C64 system with its ROMs.

Our Android C64 emulator, however, didn't have a emulated screen in which we could see the boot message. We had to manually inspect the contents of screen memory to confirm that the boot message was written.

In this section we are going to develop the emulated screen. This is going to be a very simple emulated screen having just the capability to show textmode graphics in monochrome.

Our current Android app currently consists out of a single page showing debug information. Now, we could add our emulated screen to this page, but this will cause our page to look very squashed.

A better alternative would be to move the emulated screen into a page of its own.

Therefore, in this post we will be developing a two page solution and cover the implications of doing it this way.

Process Flow

Let us start off by first looking on a high level what we want to achieve in this post.

When starting our Android application, we would like to show the emulated screen as the first page of the application:

At any point in time we can decide that we want to pause our emulator and inspect the state of it. This pause action can be activated by the user by means of a menu action which will pause execution and move to the Debug page.

In our application the menu will be opened by pressing the three dots, as I have highlighted in the screenshot above. The menu will typically look as follows:

Hitting Stop, will pause execution and bring up the Debug Page:

Within this screen you can step and inspect in the same way as is previous posts.

Hitting RUN will take you back to the emulated screen and resume execution.

Creating emulated screen page

Let us now proceed to create the emulated screen page.

The first step would be to create a new activity. So within Android Studio, Select File/New/Activity/Empty Activity. Go through the set of wizard pages keeping the defaults for each one. When prompted for an activity name, specify FrontActivity.

One of the items created by the Empty Activity wizard is a overflow menu, similar is the own highlighted in the previous section.

Let us now add a item to the menu allowing you to pause emulator execution. Within the app folder structure, under res/menu, create a file named menu_front.xml. Contents of this file should be as follows:

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    tools:context="com.johan.emulator.activities.FrontActivity">
    <item
        android:id="@+id/action_stop"
        android:orderInCategory="100"
        android:title="Stop"
        app:showAsAction="never" />
</menu>


Now, within FrontActivity, add the following method:

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_front, menu);
        return true;
    }


In effect we are overriding the onCreateOptionsMenu method of the Activity base class.

You will also see that for the inflate method, we are passing R.menu.menu_front as one of the parameters. This is a points to the xml file we have created earlier on. By convention the Android Build system knows by convention that all xml files within res/menu should be treated as property files of menus.

We haven't implemented an on tap event yet for this menu item. We will do so in another section.

With our application containing two activities, one might be tempted to wonder how the Android knows which Activity should be shown first on startup.

The answer lies within the AndroidManifest.xml file:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.johan.emulator">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".activities.FrontActivity"
            android:label="@string/title_activity_front"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".activities.DebugActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar"></activity>
    </application>

</manifest>

You will see that one the activities have an intent-filter element, as highlighted. So, in short, the activity with an intent-filter element, as shown above, will be the activity that Android will first show when the application has started.

Refactoring

With our application containing two activities, one should ensure that both of them should access the same emulator state.

This may sound that I am stating the obvious, but this is indeed a brain teaser for our situation.

As our emulator stands in its current state, all of the emulator state is contained within our Debug Activity. The problem here is that within Android, Activity instances is not aware aware of each other's existence. So, as it stands, the two activities would not to be able to access common emulator state.

A solution to this issue would be to move all the emulator functionality out of the DebugActivity into a class of its own. This will involve a bit of refactoring which I will explain in this section.

We start of by creating a class called Emu6502. As explained we will move all the emulator functionality into this class. This includes things like getting debug strings of emulator state and native method stub. I will not go into very deep detail into this class, but I will highlight one thing though:

public class Emu6502 {
...
    private static Emu6502 emu6502Instance = null;
...
    protected Emu6502() {

    }
...
    static public Emu6502 getInstance(AssetManager mgr) {
      if (emu6502Instance != null)
          return emu6502Instance;
        loadROMS(mgr);
        resetCpu();
        emu6502Instance = new Emu6502();
       return emu6502Instance;

    }
..
}

Here I have hidden the Object constructor and the only way to get an instance of the class Emu6502 is via the method getInstance. This method will only create an instance once the first time. For all subsequent calls to getInstance, the same instance will be returned.

This methodology is called a singleton and is perfect for our brain teaser. Both our FrontActivity and Debug Activity can call this method and we can be sure they oth share the same emulator instance.

As part of our refactoring, let us have a look again at FrontActivity, with a couple of changes applied:

public class FrontActivity extends AppCompatActivity {
    Timer timer;
    TimerTask timerTask;

    private boolean running = false;
    private boolean switchToDebug = false;
    final Handler handler = new Handler();
    private Emu6502 emuInstance; //Emu6502.getInstance(getResources().getAssets());

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_front);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        emuInstance = Emu6502.getInstance(getResources().getAssets());

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        //noinspection SimplifiableIfStatement
        if (id == R.id.action_stop) {
            switchToDebug = true;
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onPause() {
        super.onPause();
        running = false;
    }

    @Override
    protected  void onResume() {
        super.onResume();
        running = true;
        switchToDebug = false;
        timer = new Timer();
        //breakAddress = getBreakAddress();

        timerTask = new TimerTask() {
            @Override
            public void run() {
                final int result = emuInstance.runBatch(0);
                if (result > 0) {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            timer.cancel();
                            doAlert(result);
                        }
                    });
                } else if (!running | (result < 0) | switchToDebug) {
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            timer.cancel();
                            running = false;

                        }
                    });

                }
                if (switchToDebug) {
                    Intent i = new Intent(FrontActivity.this, DebugActivity.class);
                    FrontActivity.this.startActivity(i);
                }
            }
        };

        timer.schedule(timerTask, 20, 20);

    }

}


In the onCreate method we get an Emu6502 instance and store it as a private variable.

You will also realise that I have moved all the timer scheduling code within the Debug Activity to this activity.

You will also realise that I have implemented the methods onPause and onResume, which are in fact overidden methods of Activity.

Let us pause for moment and just discuss the purpose of the onPause and onResume methods.

The onPause method gets invoked when the current activity is entering the paused state. An activity enters the pause state when either switching to another activity or going to the home screen.

One thing to keep in mind with paused activities is that timer threads of paused activities will still run in the background. So, when a activity gets paused, it is important to also stop its timers within the onPause method.

As an Activity can get paused, similarly it can also be re-activated. The process of activity reactivation is called Resuming within the Android jargon. As you might have guest, the onResume method of an activity will be called when it resumes.

You might recognise the running variable from the previous post as a very important variable that is used to decide when a timer should be stopped. In this refactoring exercise we introduce yet another boolean variable called switchToDebug. This variable is set to true when you tap the STOP menu item.

The question at this point in time would be why define two booleans for more or less the same purpose. The answer is that the FrontActivity can pause for two reasons:

  • The user hit stop and we need to go to the Debug Activity
  • The user hit the Home button. In this scenario we would not to transition to the Debug Activity
So, the switchToDebug variable is just an indication when we should really be switching to the DebugActivity.

The actual switching to the DebugActivity happens in the following if statement:

                if (switchToDebug) {
                    Intent i = new Intent(FrontActivity.this, DebugActivity.class);
                    FrontActivity.this.startActivity(i);
                }


Drawing

Let us spend some time now on the actual drawing process of the emulated screen.

To facilitate the drawing we need to define a dedicated drawing element on the FrontActivity.

The type of element we will be using for this purpose will be a SurfaceView. The nice thing about SurfaceViews is that the draw commands is not processed by the GUI event queue, so it can give you better performance!

To use SurfaceView, we first need to create a class that subclass from SurfaceView:

public class C64SurfaceView extends SurfaceView {

    private SurfaceHolder surfaceHolder;
    public C64SurfaceView(Context context) {
        super(context);
        init();
    }

    public SurfaceHolder getCreatedHolder() {
        return surfaceHolder;
    }

    public C64SurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public C64SurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        surfaceHolder= getHolder();
        surfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) {

            }

            @Override
            public void surfaceChanged(SurfaceHolder holder,
                                       int format, int width,int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) {

            }
        });
    }
}


Next, we should add an element to content_front.xml, the resource file associated with the FrontActivity:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.johan.emulator.activities.FrontActivity"
    tools:showIn="@layout/activity_front">
    
    <com.johan.emulator.view.C64SurfaceView
        android:id="@+id/Video"
        android:layout_width="320px"
        android:layout_height="200px" />

</RelativeLayout>

So, when an instance is created of FrontActivity, an instance of C64SurfaceView will automatically be added to it, having dimensions 320 by 200 pixels, the dimensions of the C64 screen.

We have now defined an area on the screen of the FrontActivity on which we can draw. So the question is: How do we do the actual drawing on this area?

Let us do this question step for step.

Firstly, we need to create the following private variables within FrontActivity:

    private ByteBuffer mByteBuffer;
    private Bitmap mBitmap;

The purpose of these two variables will become clear in a moment.

Let us proceed to initialize these variables within onCreate:

        
        mByteBuffer = ByteBuffer.allocateDirect(320*200*2);
        mBitmap = Bitmap.createBitmap(320,200, Bitmap.Config.RGB_565);
        emuInstance.setFrameBuffer(mByteBuffer);

mByteBuffer defines a fixed area in memory defining pixel data to be displayed. Native code can directly write to this area that can dramatically improve performance. The format for each pixel in the buffer is 5 bits for red, 6 bits for green and 5 bits for blue. This equals two bytes per pixel.

We give our native code a handle to this buffer by calling setFrameBuffer on emuInstance. This is a native method stub within EmuInstance:

    public native void setFrameBuffer(ByteBuffer buf);

The implementation of this native stub lives within memory.c:

...
jchar* g_buffer;
...

void Java_com_johan_emulator_engine_Emu6502_setFrameBuffer(JNIEnv* pEnv, jobject pObj, jobject oBuf) {
  g_buffer = (jchar *) (*pEnv)->GetDirectBufferAddress(pEnv, oBuf);

}

The buffer pointer being passed to this method is a java Object reference. To get the physical memory address, you need to call the GetDirectBufferAddress method on the JNI environment.

You will notice that although a ByteBuffer is an actual fact an array of byte, I am casting it as an array of char, which is an array with two bytes per element.

This just makes working with individual pixels so much easier and you don't need to worry if the underlining architecture store the two bytes per pixel in Big Endian format, or not.

While at the native code, let us look at the rest rest of the native code related to drawing. After that we will return to the Java Code.

First important thing for native code, is to load character ROM into memory:

...
jchar charRom[4096];
...
void Java_com_johan_emulator_engine_Emu6502_loadROMS(JNIEnv* env, jobject pObj, jobject pAssetManager) {
...
  assetF = AAssetManager_open(assetManager, "characters.bin", AASSET_MODE_UNKNOWN);
  AAsset_read(assetF, buffer, 4096);

  for (i = 0x0; i < 0x1000; i++) {
    charRom[i] = buffer[i];
  }
  AAsset_close(assetF);
}

Next up, is to write a method for populating the ByteBuffer:

void Java_com_johan_emulator_engine_Emu6502_populateFrame(JNIEnv* pEnv, jobject pObj) {
  int currentLine;
  int currentCharInLine;
  int currentPixel;
  int currentPosInCharMem = 1024;
  int posInBuffer = 0;
  for (currentLine = 0; currentLine < 200; currentLine++) {
    int currentLineInChar = currentLine & 7;
    if ((currentLine != 0) && ((currentLineInChar) == 0))
      currentPosInCharMem = currentPosInCharMem + 40;
    for (currentCharInLine = 0; currentCharInLine < 40; currentCharInLine++) {
      jchar currentChar = mainMem[currentPosInCharMem + currentCharInLine];
      jchar dataLine = charRom[(currentChar << 3) | currentLineInChar];
      int posToWriteBegin = posInBuffer + (currentCharInLine << 3);
      int posToWrite;
      for (posToWrite = posToWriteBegin; posToWrite < (posToWriteBegin + 8); posToWrite++) {
        if ((dataLine & 0x80) != 0)
          g_buffer[posToWrite] = 0xffff;
        else
          g_buffer[posToWrite] = 0x0;
        dataLine = dataLine << 1;
      }
    }
    posInBuffer = posInBuffer + 320;
  }
}

So, the buffer gets drawn to with the aid of the screen memory, starting at address 1024 and the character ROM.

This method gets called once by the Java code every time when runBatch gets invoked.

This concludes the native part of drawing.

Back to the Java code. In the onResume() method, we add the following code:

    @Override
    protected  void onResume() {
        super.onResume();
        running = true;
        switchToDebug = false;
        timer = new Timer();

        timerTask = new TimerTask() {
            @Override
            public void run() {
                final int result = emuInstance.runBatch(0);
                C64SurfaceView surfaceView = (C64SurfaceView) findViewById(R.id.Video);
                SurfaceHolder holder = surfaceView.getCreatedHolder();
                Canvas canvas = null;
                if (holder != null)
                    canvas = holder.lockCanvas();
                if (canvas != null) {
                    emuInstance.populateFrame();
                    mByteBuffer.rewind();
                    mBitmap.copyPixelsFromBuffer(mByteBuffer);
                    canvas.drawBitmap(mBitmap,0,0, null);
                    holder.unlockCanvasAndPost(canvas);
...
    }


We get the SurfaceView by ID and subsequently we get the SurfaceHolder and then canvas. You will see a couple of null checks along the way. This just to ensure that everything is properly created within the surface view before we do anything.

When we are sure we have a valid canvas, we call populateFrame(), which we described previously. We then copy this buffer to Bitmap object, which we then use to draw to the canvas.

You might find the call to rewind on the ByteBuffer a bit strange. the copyPixelsFromBuffer almost treat the ByteBuffer as file. Everytime it gets information from the buffer, it keeps track where it last ended within the buffer. So, when this method reads from the buffer a second time, it will not start at the beginnining, but just after the place it ended off the first time. For that reason it is nesseary to rewind() each time.

Implementing the flashing cursor

It could be nice if we could end off this post showing the flashing cursor as well within our Surface view together with the boot message.

To implement the flashing cursor, I am going to use the same hack I used JavaScript emulator here. This hack involves simulating an IRQ after each execution of runBatch.

So, first we implement the following method within cpu.c:

void Java_com_johan_emulator_engine_Emu6502_interruptCpu(JNIEnv* pEnv, jobject pObj)
{
  if (interruptFlag == 1)
    return;
  pushWord(pc);
  breakFlag = 0;
  Push(getStatusFlagsAsByte());
  breakFlag = 1;
  interruptFlag = 1;
  int tempVal = memory_read(0xffff) * 256;
  tempVal = tempVal + memory_read(0xfffe);
  pc = tempVal;
}

This is a method we can call to simulate an interrupt. We need to call this method within the OnResume method of FrontActivity:

    @Override
    protected  void onResume() {
        super.onResume();
        running = true;
        switchToDebug = false;
        timer = new Timer();
        //breakAddress = getBreakAddress();

        timerTask = new TimerTask() {
            @Override
            public void run() {
                final int result = emuInstance.runBatch(0);
                emuInstance.interruptCpu();
...


A Test Run

Let us do a quick test run.

Everything looks perfect, except the number of bytes available:


I actually had the same issue when I developed my JavaScript emulator. The way it is calculating this number involves testing memory from a very early location in memory, just after screen memory. For each location it writes a value to RAM and then check if it gets the same value back. This process stops when it gets to the beginning of BASIC ROM, where the check will obviously will fail, so the number of free bytes will in effect be the number of bytes tested successfully.

This is just where our emulator will fall on its face: Memory tests in the ROM areas will succeed!

So, to get the free byte count right, we need to ignore writes within the ROM area. For now, this is just going to be a quick hack in memory.c:

void memory_write(int address, jchar value) {
  if (((address >= 0xa000) && (address < 0xc000)) |
       ((address >= 0xe000) && (address < 0x10000)))
    return;
  mainMem[address] = value;
}


This will do the trick!

In Summary

In this post we have implemented an emulated screen for our emulator.

In the next post we will be implementing a virtual keyboard that will allow us to interact with the emulator.

Till next time!

Thursday, 13 October 2016

Part 10: Booting C64 system

Foreword

In the previous post we ran Klaus Test Suite on our Android C64 emulator, and fixed the bugs that surfaced.

In this post we will be booting the C64 system on our Android emulator by loading its two code ROMs, Kernal and BASIC, into memory.

However, before we start with booting the C64 system, I am just briefly going to cover something else: Compacting the code of our instruction decoding switch statement with the help of inlining.

Compacting code with Inlining

If you had been following this series of posts, you might have realised that there is lots of repeating code within the instruction decoding switch statement within cpu.c. From these repeating code includes:
  • Setting the Negative and Zero Flag when the contents of a register or memory locations changes, 
  • masking off the lower 8-bits of a result

@WhiteFlame, one of the members at 6502.org gave a very interesting suggestion on reducing the amount of repeated code involving the use of small utility functions. To avoid the potential overhead of calling these functions lot of times, one can hint the C compiler to inline these functions, that is substituting places where these functions gets called, with the body of the applicable function.

I actually ended off having great fun compacting the code of our Android emulator with inlining. All the code changes I did, I have made available on my GitHub repository.

In this section I will be giving a very brief overview on what I did, just to give a taste of the power of using small utility functions for compressing the code for our emulator.

Here is a quick list most of the utility functions I wrote:

  inline unsigned char setNZ(unsigned char value) {
      value = value & 0xff;
      zeroFlag = (value == 0) ? 1 : 0;
      negativeFlag = ((value & 0x80) != 0) ? 1 : 0;
      return value;
  }

  inline unsigned char resolveRead() {
    unsigned char addressMode = addressModes[opcode];
    if (addressMode == ADDRESS_MODE_IMMEDIATE)
      return (arg1 & 0xff);
    int effectiveAdrress = calculateEffevtiveAdd(addressMode, arg1, arg2);
    return memory_read(effectiveAdrress) & 0xff;
  }

  inline void resolveWrite(unsigned char value) {
    unsigned char addressMode = addressModes[opcode];
    int effectiveAdrress = calculateEffevtiveAdd(addressMode, arg1, arg2);
    memory_write(effectiveAdrress, value & 0xff );
  }

  inline unsigned char shiftLeft (unsigned char value, int shiftInBit) {
    int temp = (value << 1) | shiftInBit;
    carryFlag = ((temp & 0x100) == 0x100) ? 1 : 0;
    temp = temp & 0xff;
    return temp;
  }

  inline unsigned char shiftRight (unsigned char value, int shiftInBit) {
    carryFlag = value & 1;
    int temp = (value >> 1) | (shiftInBit << 7);
    temp = temp & 0xff;
    return temp;
  }


As you can see each of these functions have the word inline in the function signature, hinting the Compiler to inline the function body each place where it is called, if at all possible.

The functionality of these inline functions will become clear in a moment.

Let us work through a couple of examples where these functions are used.

The first example is the LDA instruction:

        case 0xa9:
        case 0xA5:
        case 0xB5:
        case 0xAD:
        case 0xBD:
        case 0xB9:
        case 0xA1:
        case 0xB1:
          acc = setNZ(resolveRead());
        break;

The call to resolveRead() resolves the address for the applicable instruction and returns the value in the resulting address. Please note that in order for the resolveRead() and resolveWrite() functions to work without passing parameters, I had to make the variables opcode, arg1 and arg2 global variables.

If you have a look at the implementation of resolveRead(), you will see that I have also managed to accommodate the immediate mode of the LDA instruction, which is done by just passing the value of arg1.

With the immediate mode also rolled into resolveRead(), we managed to make the opcode a9 also make use of the same case selector. Previously A9 had its own case selector.

The setNZ function takes care of setting the Negative and Zero flag with the value provided and returns the same vlaue, but trunacted to 8 bits. This value gets assigned to the accumulator.

Let us quickly have a look at the STA instruction as the next example:

        case 0x85:
        case 0x95:
        case 0x8D:
        case 0x9D:
        case 0x99:
        case 0x81:
        case 0x91:
          resolveWrite(acc);
        break;


The resolveWrite function receives a value as a parameter, figures out the resulting address and stores the value at that address.

Let us move unto a slightly more complex example, which is the INC instruction for memory:

          case 0xE6:
          case 0xF6:
          case 0xEE:
          case 0xFE:
              resolveWrite(setNZ(resolveRead() + 1));
              break;

We begin by getting the value from the applicable memory location, incrementing it and then passing it to setNZ and finally to resolveWrite().

This whole calling-train reminds me of fluent interfaces in Java where you call a train a methods and each method call returns a value object.

The final set examples we will have a look at, is the rotate instructions. Let us start with these instructions by listing all their implementations:

/*ASL  Shift Left One Bit (Memory or Accumulator)
     C <- [76543210] <- 0             N Z C I D V
                                      + + + - - -
     addressing    assembler    opc  bytes  cyles
     --------------------------------------------
     accumulator   ASL A         0A    1     2
     zeropage      ASL oper      06    2     5
     zeropage,X    ASL oper,X    16    2     6
     absolute      ASL oper      0E    3     6
     absolute,X    ASL oper,X    1E    3     7 */

        case 0x0A:
          acc = setNZ(shiftLeft(acc, 0));
              break;
        case 0x06:
        case 0x16:
        case 0x0E:
        case 0x1E:
             resolveWrite(setNZ(shiftLeft(resolveRead(), 0)));
              break;



/*LSR  Shift One Bit Right (Memory or Accumulator)
     0 -> [76543210] -> C             N Z C I D V
                                      - + + - - -
     addressing    assembler    opc  bytes  cyles
     --------------------------------------------
     accumulator   LSR A         4A    1     2
     zeropage      LSR oper      46    2     5
     zeropage,X    LSR oper,X    56    2     6
     absolute      LSR oper      4E    3     6
     absolute,X    LSR oper,X    5E    3     7 */

        case 0x4A:
          acc = setNZ(shiftRight(acc, 0));
              break;
        case 0x46:
        case 0x56:
        case 0x4E:
        case 0x5E:
             resolveWrite(setNZ(shiftRight(resolveRead(), 0)));
              break;


/*ROL  Rotate One Bit Left (Memory or Accumulator)
     C <- [76543210] <- C             N Z C I D V
                                      + + + - - -
     addressing    assembler    opc  bytes  cyles
     --------------------------------------------
     accumulator   ROL A         2A    1     2
     zeropage      ROL oper      26    2     5
     zeropage,X    ROL oper,X    36    2     6
     absolute      ROL oper      2E    3     6
     absolute,X    ROL oper,X    3E    3     7 */


        case 0x2A:
          acc = setNZ(shiftLeft(acc, carryFlag));
              break;
        case 0x26:
        case 0x36:
        case 0x2E:
        case 0x3E:
              resolveWrite(setNZ(shiftLeft(resolveRead(), carryFlag)));
              break;

/*ROR  Rotate One Bit Right (Memory or Accumulator)
     C -> [76543210] -> C             N Z C I D V
                                      + + + - - -
     addressing    assembler    opc  bytes  cyles
     --------------------------------------------
     accumulator   ROR A         6A    1     2
     zeropage      ROR oper      66    2     5
     zeropage,X    ROR oper,X    76    2     6
     absolute      ROR oper      6E    3     6
     absolute,X    ROR oper,X    7E    3     7  */

        case 0x6A:
          acc = setNZ(shiftRight(acc, carryFlag));
              break;
        case 0x66:
        case 0x76:
        case 0x6E:
        case 0x7E:
              resolveWrite(setNZ(shiftRight(resolveRead(), carryFlag)));
              break;


As you can see, there are four groups of rotate instructions. In the end, however, I found that I could get away by implementing two utility functions for rotates: shiftLeft and shiftRight :-)

The difference between the versions of a shift left instruction is really just the bit that gets shift in. The ASL instruction shifts in a 0 from the right hand side, whereas the ROL shifts in the current Carry value from the right hand side.

With the above mentioned knowledge, one can create a single shiftLeft instruction accepting a shiftInBit as a parameter.

One can apply the same reasoning to the shiftRight Instruction.

Loading ROMs into memory

Let us now start with preparing our Android emulator to boot te C64 system.

In principle the C64 boot process is simple. Just load two ROMS, Kernal and BASIC into its relevant area in memory and just kick off the emulator at a specific address in memory.

A key question at this point will be how to ship these ROMS with an Android application and how to access them when the application is running.

We will now cover the two parts of this question separately.

Shipping the ROMS

To ship the two C64 ROMS with our Android application you need to place them within an asset folder. Here is a quick screenshot on how the asset folder will look like within Android Studio:


If it is a new Android Studio project, you will not have a assets folder. In such a scenario just right click on the app node and select New/Folder/Assets Folder

Once you have created the Assets Folder, you can just copy the two ROMS with the help of a File manager to the Assets Folder.

When you build an Android Project with an Assets folder, all the files contained in it will automatically be copied over to the resulting APK file.

Accessing the ROMS

How do we access the ROMS copied to the Asset Folder within our Android Application?

We access the stored assets via the AssetsManager.

Like the other components of the Android Application Framework, the AssetManager is written mostly in Java.

This means that for our native code to access the AssetManager, we need to make use of JNI. Luckily the NDK provide us with a very nice wrapper for AssetManager that our native code can use.

Despite the wrapper, we still need to write some Java code that injects an AssetManager instance into our native code. So, let us start on the Java side.

First we need to create a native  method stub within our MainActivity class that we will use to inject an Assetmanager instance into our native code:

    private native void loadROMS (AssetManager pAssetManager);

Next let us write code within the onCreate method of MainActivity to perform the injection:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        AssetManager mgr = getResources().getAssets();
        loadROMS(mgr);

        refreshControls();
        //TextView view = (TextView) findViewById(R.id.memoryDump);
        //view.setText(mem.getMemDump());
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }


Next, we should implement the loadROMS method in memory.c:

void Java_com_johan_emulator_MainActivity_loadROMS(JNIEnv* env, jobject pObj, jobject pAssetManager) {
  AAssetManager* assetManager = AAssetManager_fromJava(env, pAssetManager);
  AAsset* assetF = AAssetManager_open(assetManager, "basic.bin", AASSET_MODE_UNKNOWN);
  uint8_t buffer[8192];
  AAsset_read(assetF, buffer, 8192);
  int i;
  for (i = 0xa000; i < 0xc000; i++) {
    mainMem[i] = buffer[i & 0x1fff];
  }
  AAsset_close(assetF);

  assetF = AAssetManager_open(assetManager, "kernal.bin", AASSET_MODE_UNKNOWN);
  AAsset_read(assetF, buffer, 8192);

  for (i = 0xe000; i < 0x10000; i++) {
    mainMem[i] = buffer[i & 0x1fff];
  }
  AAsset_close(assetF);

}


In this method we receive the AssestManager object. We then proceed open both the basic and the kernal ROM and populate the respective areas in memory with their content.

Booting and Testing

We now proceed to boot the C64 system.

On our emulator we just need to specify the correct start address for the system to start.

The start address is stored as a vector in memory locations FFFC/FFFD, with FFFD having the high byte of the start address and FFFC having the low byte of the start address.

With this info at hand, we implement a reset function within cpu.c:

void Java_com_johan_emulator_MainActivity_resetCpu(JNIEnv* pEnv, jobject pObj) 
{
  pc = memory_read (0xfffc) | (memory_read(0xfffd) << 8);
  pc = pc & 0xffff;

}


We call this function within the onCreate method in MainActivity:

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        AssetManager mgr = getResources().getAssets();
        loadROMS(mgr);
        resetCpu();

        refreshControls();
        //TextView view = (TextView) findViewById(R.id.memoryDump);
        //view.setText(mem.getMemDump());
        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
    }


We are now ready to fire up our emulator again.

Build and install the app on you mobile device.

When the app eventually starts up, the screen will look as follows:


At this point we know that our reset functionality worked ok, because we are at fce2, which is the value stored in the reset vector.

From one of my JavaScript emualtor episodes, here, you will know that hitting RUN at this point will cause our emulator to get stuck in this loop:

FF5E   AD 12 D0   LDA $D012
FF61   D0 FB      BNE $FF5E

To get past this point we need to implement a hack to change the memory location D012 periodically to zero. We do this within the runBatch method in cpu.c:

int runBatch(int address) {
  remainingCycles = 20000;
  int lastResult = 0;
  while ((remainingCycles > 0) && (lastResult == 0)) {
    lastResult = step();
    if (lastResult != 0)
      break;
    if ((address > 0) && (pc == address)) {
      lastResult = -1;
      break;
    }
    memory_write(0xd012, (remainingCycles < 50) ? 0 : 1);
  }

  return lastResult;
}


With this change build and redeploy the app.

When we now run the app for a couple of seconds and then stop, we should see some interesting stuff in screen memory at location 0x420:



OK, we know know for sure that our emulator at least got to the point of showing the welcome message during the booting process.


In Summary

In this post we have implemented the functionality to boot the C64 system.

We ended of booting the system and confirmed that the C64 welcome message got written to screen memory.

In the next post I will be adding a screen to our emulator to display the contents of screen memory together with a flashing cursor.

Till next time!

Friday, 7 October 2016

Part 9: Running a Test Suite

Foreword

In the previous post we have added the remaining 6502 instructions to our emulator.

In this post we will be putting our emulator through its paces by means of a Test Suite. We will be using the Klaus Test Suite for this purpose.

During my C64 Android Emulator series I have been copying and pasting most of the source code from my JavaScript emulator series, so one can expect that one will get more or less the same bugs when running the Test Suite as in my JavaScript series.For this reason, I will not be focusing so much on how to debug the Android emulator in this post.

What I will be focusing on in this post, however, is how to extend our Android Emulator to provide the necessary debugging functionality.

A quick Introduction to the Klaus Test Suite

Before we jump into coding I quickly want to give a quick introduction to the Klaus Test Suite.

The Klaus Test Suite is a very Comprehensive Test Suite that you can use to test any 6502 implementation.

This Test Suite is available on GitHub: https://github.com/Klaus2m5/6502_65C02_functional_tests

The Test Suite is provided in both 6502 assembly source or binary form.

Personally I prefer using the binary form since it is less painful to use.

The binary is a 64kilobyte binary file that you can just assign to a memory array.

When running the Test Suite, execution should start at memory address 0x400.

When a particular Test Suite fails, the emulator been tested will enter  an endless loop at a particular memory location. So, checking at which memory location the emulator is at an endless loop, will be an indication of which test failed.

If all tests succeeded, the emulator will running in an endless loop at address 0x3399.

GUI changes

To extend the debug functionality of our emulator we will adding some extra controls to the GUI of our emulator. The picture below show how the new GUI will look like:


I have marked in red the new controls. Let us quickly explain them:
  • A run button for continuous execution.
  • A Stop button pause continuous execution any point in time. You can then view the state of the emulator the moment execution was paused. You can then single step, if desired, or resume continuous execution by hitting RUN again.
  • Break edit box: You can specify an address (in hex) at which your emulator should pause continuous execution when reached.
To add these controls, you just need to add the following lines at the bottom of content_main.xml:

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="RUN"
            android:id="@+id/button3"
            android:layout_row="6"
            android:layout_column="0"
            android:onClick="onRunClick" />

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="STOP"
            android:id="@+id/button4"
            android:layout_row="6"
            android:layout_column="1"
            android:onClick="onStopClick" />

        <EditText
            android:id="@+id/breakAddress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:ellipsize="start"

            android:hint="Break"
            android:inputType="text"
            android:background="@drawable/edittextstyle"
            android:layout_row="7"
            android:layout_column="0"/>

 

The highlighted onClick events (onRunClick and onStopClick), will be implemented in subsequent sections.

Continuous execution

Up to this point in time, our emulator was only able to manual step one instruction at a time.

The time has come that we implement automatic program execution without involving you to hit step for each and every instruction.

The simplest way for this would be to just call step() from within an endless loop. This would, however, make your front end unresponsive and you will soon get a popup message confirmation this situation.

A solution to this problem would be to break down the instructions to be executed in small batches and running them at regular time intervals. When emulating a C64 having a clock speed of 1Mhz and displaying 50 frames per second, assuming a PAL model, you would run batches of 20000 cycles, executing 50 times per second.

Within Android scheduling of running batches in regular time intervals can be achieved with timers. The following changes need to be done within the class MainActivity:
...
    Timer timer;
    TimerTask timerTask;
...
    public void onRunClick(View v) {
        timer = new Timer();

        timerTask = new TimerTask() {
            @Override
            public void run() {
              runBatch();
            }
        };

        timer.schedule(timerTask, 20, 20);
    }


The onRunClick method will be invoked when tapping the RUN button. Within this method we set up the timer so that a task gets run every 20 milliseconds, that is 50 times per second.

In above mentioned code, the instantiation of a TimerTask instance might look a bit confusing. In the Java world, the term for what is going on here is anonymous classes.

When an instance of TimerTask gets created via the code above, a new class gets created extending TimerTask and overriding the Run method. This new class is a called an anonymous class because the new class isn't given a name. The rest of the code doesn't care of the fact that the new doesn't have a name. All that matters is that the timerTask variable now points to an instance that has a run method that you can call.

So, in effect every 20 milliseconds a method runBatch() will be called. We haven't defined runBatch() yet, so let us do that quickly.

As mentioned earlier, runBatch() is supposed to run 20000 cycles worth of instructions, so it is worthwhile to run this method within native code for minimum overhead.

So, firstly we need to create a native stub for runBatch() within MainActivity:

public native void runBatch();

Before we implement the runBatch method within cpu.c, we need to implement a mechanism for keeping track of the number of cycles that has passed. So, we need to modify cpu.c as follows:

...
    int remainingCycles;
...
  int step() {
      int opcode = memory_read(pc);
      remainingCycles -= instructionCycles[opcode];
...
  }

...

Now we can implement the runBatch method:

void runBatch() {
  remainingCycles = 20000;
  while (remainingCycles > 0) {
    step();
  }
}

void Java_com_johan_emulator_MainActivity_runBatch(JNIEnv* pEnv, jobject pObj) {
  runBatch();
}

Pausing Code Execution

It would also be nice to pause execution at any point in time and inspect the current state of the emulator.

To pause execution, one needs to call the cancel() method on the timer object to stop the timer from scheduling any future runs of runBatch()

Where do you need to call cancel()? The first instinct would be to call it within the onStopClick event handler.

There is, however, an issue calling cancel() within onStopClick: onStopClick and a timerTask runs in two different threads. This may cause potential threading issues when you immediately want to read the state of the emulator for display purposes, after calling cancel on the timer object. The state that you might get back in such a situation might not truly reflect the real emulator state, since the timerTask might still be running a half completed batch.

A way to solve this issue, would be to introduce a global variable and do the cancelling of the timerTask within the run method of the timer Task.

At first everything will sound a bit confusing, but it will become clear in a moment.

First we introduce a global variable called running within MainActivity:

 private boolean running = false;

Next, we alter the existing onRunClick method and add a new method onStopClick:

    public void onRunClick(View v) {
        running = true;
        timer = new Timer();

        timerTask = new TimerTask() {
            @Override
            public void run() {
              runBatch();
              if (!running) {
                handler.post(new Runnable() {
                      @Override
                      public void run() {
                          timer.cancel();
                          refreshControls();
                      }
                  });      
               }
        };

        timer.schedule(timerTask, 20, 20);
    }

    public void onStopClick(View v) {
        running = false;
    }


As you can see the variable running gets set to true when the Run Button is click and gets set to false when the Stop Button gets clicked.

The state of the run variable gets checked just after the runBatch method was called.

You will an interesting piece of code getting executed when the running variable is set to false. First of all, handler is also a global variable, so let us quickly define it within MainActivity:

final Handler handler = new Handler();

What does handler.post do? In effect this method call adds a piece of code to be executed to the  event queue of the Main Thread, which is the Thread of the GUI. What we want to achieve if running is false, is to stop the timer and to refresh the controls showing the state of the emulator when it stopped.

However, Android is a funny chap. Other threads is not allowed to make any changes to the GUI. We get around this limitation by posting an instance of a Runnable object to the event queue of the Main Thread.

All events, whether it is swiping or tapping on the screen gets stored as an event on above mentioned queue. The GUI thread process these events one by one. Our Runnable object can also be viewed as an event to be processed by the GUI thread.

Opcode not supported Popups

When we ran the Klaus Test suite on my JavaScript Emulator, one type issue that serviced a number of times was opcodes that we forgot to implement. Luckily we could catch these missing op codes by means of a default case selector within the opcode switch statement in the step method. Within the default case selector we just added an alert() that would popup a message informing the user of the opcode that wasn't implemented.

A similar pop up mechanism would be nice to have within our Android C64 emulator. It should be noted, however, that within our Android Emulator the step() method lives within native C code, which is shielded a bit away from the Android Popups.

Therefore, to implement the missing opcode popups in our Android Emulator, we need to depend on result codes bubbling up all the to our Java code.

Let us start to implement this functionality by first tackling cpu.c:

  int step() {
      int result = 0;
      int opcode = memory_read(pc);

      switch (opcode)
      {
...
        default:
          result = (opcode << 16) | pc;
        break;
...
      }

      return result;
    }

int runBatch() {
  remainingCycles = 20000;
  int lastResult = 0;
  while ((remainingCycles > 0) && (lastResult == 0)) {
    lastResult = step();
    if (lastResult != 0)
      break;
  }

  return lastResult;
}

jint Java_com_johan_emulator_MainActivity_runBatch(JNIEnv* pEnv, jobject pObj) {
  return runBatch();
}

For starters, the signatures of a couple of methods was changed to return a result code.

You might find the build up of the result code interesting. The resulting result code can be viewed as three bytes with the first byte been the offending opcode, and the last two bytes the address where it happened.

Lets move on to the MainActivity class. We need to make the following changes to it:

    public native int runBatch(int address);

    public void onRunClick(View v) {
        running = true;
        timer = new Timer();

        timerTask = new TimerTask() {
            @Override
            public void run() {

              final int result = runBatch();

              if (result > 0) {
                  handler.post(new Runnable() {
                      @Override
                      public void run() {
                          timer.cancel();
                          doAlert(result);
                      }
                  });
              } 
...
        };

        timer.schedule(timerTask, 20, 20);
    }

    public void doAlert(int result) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder
                .setTitle("Error")
                .setMessage(result+"")
                .setPositiveButton("Yes",null)
                .show();
    }

If result code is bigger than zero, a Runnable class gets added to event queue of the main thread, stopping the timer and popping up a message box. Interesting to note how a popup gets created in Android.

At this point, it might be interesting to see how the popup looks like in practice. If you use the instruction implementation of the previous post, you will get a popup right at the start:


To get meaning from the error, you first need to convert the number to hexadecimal, which is D80401. This means the unimplemented opcode is D8, which is CLD, and it happened more or less at address 401.  The address will usually point to the next instruction. Of course results may differ if it is an undocumented instruction.

Adding Breakpoint

Time to implement the breakpoint functionality.

To implement the breakpoint functionality, we start off adding an extra paramater to the runBatch() method within cpu.c. This will change our cpu.c as follows:

int runBatch(int address) {
  remainingCycles = 20000;
  int lastResult = 0;
  while ((remainingCycles > 0) && (lastResult == 0)) {
    lastResult = step();
    if (lastResult != 0)
      break;
    if ((address > 0) && (pc == address)) {
      lastResult = -1;
      break;
    }  }

  return lastResult;
}

jint Java_com_johan_emulator_MainActivity_runBatch(JNIEnv* pEnv, jobject pObj, jint address) {
  return runBatch(address);
}


You will notice that within the while loop of runBatch, we keep checking whether the target address has been reached, and if so, we break out of the while loop.

If  the applicable breakpoint address has been reached, a -1 gets returned as a result code.

There is also a number of things we need to do within the class MainActivity for the breakpoint functionality, so let tackle that quickly.

First, we need to write a method to convert the string contents of the breakpoint edit box, and convert it to an integer:

    private int getBreakAddress () {
        EditText editText = (EditText) findViewById(R.id.breakAddress);
        String editAddress = "0"+editText.getText().toString();

        int intaddress = Integer.parseInt(editAddress,16);
        return intaddress;
    }

There is also a couple of changes we need to make to onRunClick:

    public void onRunClick(View v) {
        running = true;
        timer = new Timer();
        breakAddress = getBreakAddress();

        timerTask = new TimerTask() {
            @Override
            public void run() {
              //System.out.println("In Beginning: " + System.currentTimeMillis());
              final int result = runBatch(breakAddress);
              //System.out.println("In End: " + System.currentTimeMillis());
              if (result > 0) {
                  handler.post(new Runnable() {
                      @Override
                      public void run() {
                          timer.cancel();
                          doAlert(result);
                      }
                  });
              } else if (!running | (result < 0)) {
                  handler.post(new Runnable() {
                      @Override
                      public void run() {
                          timer.cancel();
                          refreshControls();
                      }
                  });

              }
            }
        };

        timer.schedule(timerTask, 20, 20);
    }

So, in effect the same process gets followed when a breakpoint fired as when you tap the STOP button.

In Summary

In this post we did the necessary preparation for running the Klaus Test Suite on our Android emulator. The preparation included implementing continuous running running together with some debugging functionality like breakpoints, Stopping and unsupported opcode alerts.

In this post I haven't focussed so much on how to debug our Emulator since the nature of the bugs was more or less the same as in my JavaScript emulator.

However, I managed to fix all bugs so that the Klaus Test Suite runs to completion. As with the other posts I have provided the source for download via GitHub.

In the next post we will be trying to boot the C64 with all its assosiated code ROMS: Kernal and Basic.

One of the members at 6502.org, @WhiteFlame, gave me a very interesting suggestion where one could make use of functioning inlining to try and compact the code for the instruction decoding switch statement. So, I am going to play around with the suggestion and give some feedback in the next post.

Till next time!