Saturday, 9 November 2024

A Commodore 64 Emulator in Flutter: Part 1

Foreword

It has been a quite a while since I last publish a post in my blog.

It was quite an eventful couple of years. I was fortunate to work fully remote during lock down and even a couple of years thereafter.

However, since last year they gradually asked us to come back to office more often until we found ourselves back at office full time. Suddenly I found myself wasting more time in traffic.

It was clear for me the whole concept of working from home is gone, so, with that in mind, I find a job closer to home with more opportunities.

One of the opportunities I got at my new job was to learn a new cross platform UI framework, called Flutter.

My colleagues at my job is quite a bit younger than me, and with that always comes an atmosphere of more enthusiasm. They mentioned that they read articles that you can even write games in Flutter. Something else that also picked my interest about Flutter is that you can also run it in a browser, but it doesn't make use of the DOM which HTML uses for rendering. Instead, it renders everything to a canvas and make use of WebGL as well as WebAssembly.

So, sounding like Flutter having a lot of power under the bonnet, I ask myself:"Why not write another Commodore C64 emulator in Flutter?" That is what I will be exploring in the next couple of blog posts.

In this post I will be covering some of the basics of Flutter. I coming series I will just build on the idea and add more functionality.

You maybe wondering what my plans are for my Amiga on an FPGA project. I have decided to put this project on hold for a bit, just to take break, and just try something new, like this Flutter project.

Hope you enjoy this series!

Installing Flutter

As mentioned, Flutter is a cross platform framework. You can create apps for Android, IOS, Windows, Linux and for web. In my series, however, I will mainly focus on web on a Linux machine.

The following link explains how to install flutter on your development machine:

https://docs.flutter.dev/get-started/install/linux/web

In short, you basically need to download the sdk, extract it to a path, and then add a location to your $PATH environment variable so that the you can run the flutter executable from the command line.

You obviously will also need to setup your IDE to develop in Flutter. In my case, I am using IntelliJ Ultimate and I just installed the Flutter Plugin, so I can easily run and debug Flutter applications.

Creating your first Flutter app

Let us create our first Flutter app using IntelliJ.

With IntelliJ open select File/New Project and Select Flutter from the generators:



Also, at the top ensure that you have selected the path to your Flutter SDK.

Now click next and specify a name and a path for you new project:


At this point, we should maybe just talk a bit about naming conventions. All file names are in lower case, with words separated by underscores.

With classes inside the files, you make use of Camel case for naming.

Now, if you click create, your new project will be created. Your project structure will something like the following:




In general, the only thing you need to worry about is the lib folder, where you put all your source code and pubspec.yaml, where you put important settings of your project.

If you look at the top, you will see a drop down displaying "no device selected". Click this drop down and select Chrome.

Your toolbar will now look like this:

Now, click the play button. You project will be build, and eventually a Chrome Browser window will open with your app:


Flutter have created a default app counting how many times you have pressed the plus button.

Unpacking the generated code

Let us unpack the generated code a bit. Looking at the code, we have everything generated in a single file called main.dart. You are not bound to this and you can put your stuff into multiple files.

First thing we see in main.dart, is a main method:

  void main() {
    runApp(const MyApp());
  }
We create an instance of MyApp and then run it.

Let us look at the definition of MyApp:

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      home: const MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

To save space, I have removed most of the comments.

Now, we see MyApp extends StatelessWidget. I will cover in a moment on what a StatelessWidget is, but for now just think of it as some kind of widget.

In Flutter, Everything you display on the screen is a Widget. One of the things a widget always have is a build method, which, you have guest it, returns a Widget.

MyApp is our main widget, which in this case is an instance of MaterialApp. MaterialApp does the heavy lifting, applying the appropriate styling to all visual components, to give your App the look and feel of a Material application.

Within the MaterialApp instance, there is a property home, where you specify your homepage widget. This is basically the entry page to your application. Once in your homepage, you can also navigate to other pages as well, almost like a web application.

Next, let us have a look at MyHomePage:

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

Firstly, look at the interesting way the constructor works. You will always specify the parameters in curly braces. Also, you use the word required, if it is compulsory to specify the given parameter.

At this point you will notice that MyApp is a StatelessWidget and MyHomePage is a StatefulWidget. These are two very important concepts in Flutter.

A stateless widget is immutable. In order to change what it displays, you need to destroy the instance and create a new one.

A statefull widget on the other hand, can store state, and if you need to change what it displays, you can keep the same instance.

Having said all this, our demo created app might sound confusing that we have a stateful widget inside a stateless widget. Does this mean that if our HomePage change that our Myapp instance will be destroyed and a new one created? Not at all. Remember, although MyHomePage lives inside Myapp, it is still self contained. So, it can do display updates within its own area on the screen, and without effecting the parent.

If there is actually display elements outside MyHomePage, inside the parent, it would not be possible to redraw any changes. To make changes to such elements, one would need to create a new instance of the Stateless widget, which in this case would mean bringing down the application, which we don't want 😁

Stateful widget are actually very smart, and usually just redraw parts of the screen that have changed, thus avoiding redrawing the whole screen. Having said that, despite the cleverness of Stateful Widgets, Flutter textbooks actually warns against using them and advise to rather use Stateless widgets where possible.

The reason authors provide for avoiding Stateful Widgets, is because code for managing the screen and business logic can easily get mixed up together. Separation of concerns is actually key here.

In this series of creating a Commodore C64 emulator in Flutter, I will take these authors advice to heart and stick with Stateless beans.

In the next section I will describe what my approach will be for the rest of the series.

The approach

Let us discuss the approach I am going to take for creating a C64 emulator in Flutter.

As mentioned earlier, I am going to stick with Stateless widgets. As the name imply the widget itself is not going to have state. So, one will need to keep the state outside the widget.

There are quite few patterns in flutter that can provide this functionality of providing state outside a stateless widget. I will be using the BLoC pattern, which is short for Business Logic Component.

Let us use our C64 Emulator as an example to explain the concept of a BLoC. The following diagram sums up everything:

It is still early days for our flutter Emulator, so one cannot expect any fancy stuff at his point 😂 At this point we will incrementally add more CPU instructions to our emulator, and single step through 6502 machine code, and seeing the values of the registers and a small section of memory.

Clicking on the Step button on the widget will trigger an event for which the BloC will listen for. Upon receiving the event, the Block will execute on CPU instruction which will potentially effect registers in the CPU and locations in memory.

When the BLoC has executed one CPU instruction, it will send a state update to the widget, which in effect will destroy the widget and create a new one with the updated values. The state will contain the values of the registers and a snippet of the updated memory. The widget in turn will display this to the user.

In Summary

In this post I gave an introduction to my idea of creating a C64 emulator in Flutter. I will start off using a Stateless Widget with a BLoC.

Initially my Emulator will just be single stepping through CPU instructions, showing the values of the registers and memory after each step. Once we have implemented all 6502 CPU instructions, we will move onto more interesting visual elements of a C64 emulator.

Until next time!