Skip to content

2. First Steps

sy2002 edited this page Jan 7, 2023 · 26 revisions

M2M offers a fully-featured example design including a demo-core to experiment with. This allows you to get started and learn more about M2M without the need of a MiSTer core.

The demo-core outputs a 4:3 720x576 @ 50 Hz (aka PAL) video signal via the VGA port of the MEGA65 and a 16:9 1280x720 @ 50 Hz (aka 720p) video signal via HDMI. Audio output works via the 3.5mm audio-out and via HDMI as well. On HDMI, the signal can be changed to 60 Hz if there are compatibility issues with the 50 Hz.

Have a look at the following screenshot. This is what the demo-core looks like on HDMI while the on-screen-menu is open because the Help key was pressed:

Let's get started and build this demo core, so that we can learn more about how M2M works and what services it provides to you.

You can also watch this section as a video tutorial on YouTube.

Creating your first M2M core

Step #0 - Prerequisites

  • You need to have a GitHub account. If you do not have one, yet, click here to learn how to get one. The free tier is absolutely OK and sufficient.

  • You need to have a unixoid terminal/shell that includes the "usual suspects" for development such as the GNU compiler toolchain including gcc and make. You also need git and bash, etc. Obviously most Linux versions work out-of-the-box. MacOS works fine, too after you installed missing tools using a package manager such as HomeBrew. For Windows we recommend to use the Windows Subsystem for Linux.

  • You need Vivado version 2022.2 (or newer), which runs on Linux and on Windows. The free version of Vivado is sufficient. Make sure that you install the "Full Product Installation". This tutorial video on YouTube might be helpful for you when it comes to installing Vivado.

  • You need a MEGA65 R3 (or newer), i.e. either a DevKit version (R3) or the commercially available version (R3A). We plan to support the older pre-release series R2, too at a later stage.

  • Optionally - but highly recommended - you need a JTAG adapter for the MEGA65, because otherwise you will need to manually convert each bitstream version you build into a .cor file, copy it on a SD card and flash it. In contrast, when you use a JTAG adapter, Vivado's hardware manager and/or the m65 tool can directly transfer the bitstream via USB. Your workflow is 100x faster.

Step #1 - Get the repo and its dependencies

Use GitHub's templating functionality to create a new project based on MiSTer2MEGA65. To do so, navigate to MiSTer2MEGA65's GitHub page and press the green Use this template button as shown in this screenshot:

After that, walk through the project creation wizard as described in this GitHub help page and use the following name for your project, so that you are consistent with the next steps described in the tutorial: MyFirstM2M

Right now, the new project MyFirstM2M is only availble online, on GitHub. You need to clone it for being able to work with it locally. MiSTer2MEGA65 contains sub-modules, so make sure that you do not "just" clone but also initialize the submodules afterwards. Make sure to replace <your-github-username> with your GitHub user name before executing the commands in your terminal window:

git clone https://github.com/<your-github-username>/MyFirstM2M.git
cd MyFirstM2M
git submodule update --init --recursive
git remote add upstream https://github.com/sy2002/MiSTer2MEGA65.git

The last line, which adds the original MiSTer2MEGA65 repository as a remote called upstream is not strictly necessary for the tutorials. You might also omit it. It is needed for "real" projects, because it gives you the opportunity to upgrade your local M2M version with a newer one.

Step #2 - Make the tool chain

Make sure that the QNICE development framework and the QNICE's "operating system" called "Monitor" is available to MiSTer2MEGA65. You can build it using the following commands:

cd M2M/QNICE/tools/
./make-toolchain.sh 

Answer all questions that you are being asked while the QNICE tool chain is being built by pressing Enter. You can check the success of the process by checking if the Monitor is available as .rom file:

ls -l ../monitor/monitor.rom

Step #3 - Build the core

  1. Go to the folder CORE/m2m-rom and build the M2M firmware:

    cd ../../../CORE/m2m-rom
    ./make_rom.sh
    
  2. Go to the folder CORE and open Vivado there. This makes sure that the project-specific subfolders that Vivado will create are located in the right M2M subfolder.

cd ..
vivado
  1. Chose the right project file for your MEGA65 revision. M2M strives to support R2 and R3 (and newer), but at the time of writing this only R3 (and newer) are supported:

    Open CORE-R3.xpr in Vivado.

  2. Create the bitstream.

    While doing so, Vivado will create multiple folders following the pattern CORE-R3.* inside your CORE folder. This is OK, you can ignore them and .gitignore is also set-up to ignore them.

    The bitstream file will be located in CORE/CORE-R3.runs/impl_1/CORE_R3.bit.

Step #4 - Run the core

  • If you have a JTAG connector installed in your MEGA65, you can now either use Vivado's hardware manager directly after the bitstream has been built or the "M65 tool" to run the bitstream on your MEGA65.

  • Using Vivado's hardware manager is highly recommended while doing this tutorial, because it is the fastest and easiest way to move forward. Later, you might prefer command line tools such as the "M65 tool".

  • Without a JTAG connector, you need to convert the bitstream, which is a .bit file, into a .cor file and use MEGA65's No Scroll boot menu to flash the core. Use "bit2core" for that.

MEGA65 tools

The GitHub repository mega65-tools contains among other things two tools that are relevant in the M2M context:

  • The "M65 tool" is also known as m65. It is a swiss army knife of tools for automated actions to perform on MEGA65 hardware.
  • bit2core which is used to convert .bit files into .cor files.

You can download the most recent binaries for your platform here. If you are on a Mac, you might need to proactively allow the system to run these unsigned binaries.

The README.md of the MEGA65 tools GitHub repository also contains detaild build instructions in case you want to build the tools for yourself.

You might want to consider putting m65 and bit2core into a folder where your shell has search-path access to.

Running a .bit bitstream using m65

There are multiple ways to run a bitstream using m65. For "alternative cores", i.e. the cores that we are creating using M2M, the -q option is the right one to use:

m65 -q name-of-your-bitstream.bit

This will auto-detect your MEGA65 that needs to be connected via JTAG and USB with your computer, transfer the bitstream and immediately run it. While Vivado's hardware manager is nice, m65 is fast.

Therefore, if you have a working JTAG connection to your MEGA65, we recommend to create a file called load_bitstream.sh and put it into the user space main folder CORE. There is already an entry CORE/load_bitstream.sh in M2M's .gitignore.

Here is an example file from sy2002's C64MEGA65 local folder:

#!/usr/bin/env bash
../../mega65-tools/bin/m65.osx -q CORE-R3.runs/impl_1/CORE_R3.bit
Converting a .bit bitstream into a MEGA65 .cor core

MEGA65's core loader that is activated using the No Scroll mechanism expects an own file format. Use bit2core to convert .bit bitstreams into MEGA65 .cor core files.

The built-in help of bit2core is great, so we won't discuss all options here. In case you wanted to convert the "First Steps" core that we created during the course of this tutorial into a .cor file and assuming that you are in the folder CORE, here is how you can do that:

bit2core mega65r3 CORE-R3.runs/impl_1/CORE_R3.bit MyFirstM2M V1 mfm2m.cor

You will receive a warning that talks about bit2core not being able to distinguish between multiple MEGA65 targets, but this is OK. After you successfully ran this command, you will have mfm2m.cor and from here you can install the .cor on the MEGA65. Learn more about how to do this on the Alternative MEGA65 cores website or by watching this great Tutorial on YouTube.

Explore some capabilities of M2M

Play BreakOut

The demo-core is provided by M2M so that you can play with M2M, experiment and learn without the need of a MiSTer core. It is not meant to be understood how it works. Of course you can go to the folder M2M/vhdl/democore and read through the source code. But the idea is that you treat the demo-core as a black-box, just like you (in most cases) would treat the MiSTer core as a black-box and then start working with it inside M2M's defined structure of files that are accessible to you in CORE/vhdl.

Video and audio

After the core starts, you will see a welcome screen. Read it and then press Space to continue. Now you will hear a siren via the 3.5mm audio-out and via HDMI audio. And you will see a "BreakOut" set-up on your screen, i.e. a "ball", a "paddle" and something to hit.

One of the basic ideas of M2M video output is: Output a truly "retro" signal on the VGA. That means use the original core's aspect ratio (very often this is 4:3) and go as close to the original core's resolution as you can without sacrificing support on VGA displays. It might be that you need to use M2M's built-in scan-doubler or other mechanisms to actually achieve this, but this is for a later stage. Our demo-core outputs PAL, so this is a nice example of such a "retro" resolution on VGA. On HDMI, on the other hand, M2M outputs a standardized 720p 16:9 image that is a pixel-perfect scaled representation of the original core's output.

So we are catching two birds with one stone: Convenience on modern HDMI displays while still offering a "retro experience" via VGA.

Keyboard and joystick

Use the arrow keys and/or a joystick in port #1 to control the paddle. M2M debounces the joystick ports for you and provides an easy to use keyboard abstraction.

Play BreakOut! :-)

On-Screen-Menu and file browser

Press the Help key while the core is running to open the On-Screen-Menu (aka OSM and also dubbed "Help menu" or "Options menu"). You can close the menu while it is open by either pressing Help again or by choosing the menu item "Close Menu".

Play around with the menu a bit. Use Return to select menu items. Use Space to unmount a drive that has been mounted before. You will notice that the M2M framework is providing some interesting features:

  • Multi-select and single-select menu items: Multi-select in the M2M context means that you can select one option out of multiple options. The example in the demo-core is called "Item A.1", "Item, A.2", ... And "single-select" in the M2M context means that these are menu-items that are either ON or OFF. An example in the demo-core is the menu item "HDMI: CRT emulation". (We are aware that in other frameworks or contexts outside of M2M multi-select and single-select might mean something else.)

  • Make sure that at least one FAT32 formatted SD card is in your MEGA65 and then choose any of the three "Drive X", "Drive Y" or "Drive Z" virtual drive mounting menu items. You can now browse the SD card and "mount" any file as a "disk image". (Obviously, you are not mounting anything; this is just a demo of the file browser and virtual drive mounting system.)

  • Switching HDMI output between 50 Hz and 60 Hz

  • Play with the CRT emulation (video filter), audio improvements (audio filters) and the Zoom-in feature.

Understanding M2M's basic structure

Now that you have gotten a first glimpse of what M2M can do, it's time to go one level deeper and to understand the basic structure. There are two basic "realms" or "spaces": The framework space (M2M space) and the core space ("your" space). The M2M space is located in the folder M2M and the core space is in the folder CORE.

When porting a MiSTer core, you would create a Git submodule as a subdirectory of CORE for example CORE/MyCore_MiSTer and make sure it links to the MiSTer fork you have created. But in this "First Steps" tutorial, there is no MiSTer core. Just the demo core, which is part of the framework.

As a rule of thumb: Do not modify anything in the framework space, only modify what is really needed to make it run when it comes to the original MiSTer core and actually do your work in the core space's CORE folder.

Let's have a look at the hierarchical structure now. The following is a screenshot from Vivado's source explorer. The source explorer nicely shows the separation of the framework space and the user space: The framework is contained in i_framework; we collapsed the branch for a better overview. And the user space is represented by the following files:

  • top_mega65-r3.vhd: CORE_R3
  • mega65.vhd: CORE
  • clk.vhd: clk_gen
  • main.vhd: i_main
  • keyboard.vhd: i_keyboard

Two other important user space files that are not visible in this screenshot are CORE/vhdl/globals.vhd and CORE/vhdl/config.vhd.

As a user of M2M, you can and should ignore all files other than the ones mentioned in the user space list above: You would normally never touch them.

The next sections walk you quickly through the user space files and explain how they interact. For a more thorough description please have a look at the Reference Guide: Each of the following user space files has its own chapter there.

Overview of the layout

top_mega65-r3.vhd: CORE_R3

Top file of the whole machine.

M2M supports multiple MEGA65 machine architectures. Right now R2 machines (pre-series models), R3 machines ("DevKits") and R3A machines (first commercially available machines) are supported. Since R3and R3A are nearly identical, M2M just denotes them as R3.

For each architecture, M2M provides three files in user space:

  • Vivado project: In our case this is CORE/CORE-R3.xpr. The project file contains all references necessary to work with M2M and/or the core in the Vivado IDE and everything necessary to make a bitstream. In particular, it links to the two other files that are machine architecture dependent.

  • Constraints file: For our demo/walk-through this is CORE/CORE-R3.xdc. The constraints file is highly machine dependent and contains all the I/O mappings as well as definitions for successful timing closure.

  • Top file: For R3 this is CORE/vhdl/top_mega65-r3.vhd. The top file instantiates the whole machine and contains machine architecture dependent settings and modules.

The main module that the top file is instantiating is M2M. This module instantiates i_framework which contains everything that the framework needs to operate, including QNICE, the analog and digital rendering pipeline and the HyperRAM controller. The i_framework module also contains glue logic. The second module that M2M instantiates is mega65.vhd, where your actual core lives in.

mega65.vhd: CORE

It is fair to say that mega65.vhd is the "top file of the user space", as the following things are happening here:

  • Instantiation of the wrapper of the MiSTer core main.vhd
  • Instantiation of all clock-domain-crossing hardware such as core-specific RAMs, ROMs and other devices
  • Implementation of device-specific logic
  • Implementation of the logic that reacts to on-screen-menu items, such as the real-time configuration of audio and video settings

In our first steps demo/example, not a lot of sophisticated stuff is happening: main.vhd is instantiated and there is no core-specific RAM, ROM or device (other than i_vdrives). As we will cover the implementation of the logic that reacts to on-screen-menu items during the "Hello World" Tutorial, we will not go deeper here.

The topic of virtual drives is quite complex, which is why i_vdrives is not covered here, either, but in its own chapter Virtual Drives.

clk.vhd: clk_gen

The MiSTer core you are porting has very specific clocking needs. Some cores are happy with one clock, some cores need multiple clocks. Put all of them in CORE/vhdl/clk.vhd and make sure that you also implement the necessary clock-domain-crossing for each clock when it comes to reset generation.

The standard version of clk.vhd supports one clock, and therefore also one reset. Feel free to add more output signals.

main.vhd: i_main

We are wrapping the MiSTer core in main.vhd. The power of the M2M framework becomes visible, when you look at the output ports of main.vhd: The core just needs to output some retro video signal and signed 16-bit PCM audio and the framework does all the magic necessary to transform this into HDMI (incl. an 48 kHz sampled audio stream) and to a pulse density modulated stream for the 3.5mm audio out.

If you look at how everything is structured in main.vhd, then you will quickly notice that the MiSTer core can peacefully live in its own little bubble and clocking domain and whatnot without ever knowing anything about the MEGA65 it is running on and without ever knowing about screen overlays (for example for the on-screen-menu), SD cards and so on.

At least two modules need to be instantiated in main.vhd:

  • MiSTer core: In our case, this is i_democore
  • Keyboard: i_keyboard in keyboard.vhd

In practice, you will very likely instantiate more modules (for example additional glue-logic for the MiSTer core) and you will also add more input/output ports to main.vhd. But this is absolutely OK and meant to be like this.

keyboard.vhd: i_keyboard

M2M provides you with a very simple interface to the MEGA65 keyboard so that you are able to implement whatever mapping and logic the core needs. keyboard.vhd runs in the same clock-domain as the core, so that you can directly wire the output of your own keyboard mapper to MiSTer's keyboard input.

In our example, the demo core expects a std_logic_vector that has one active-low bit per key on the MEGA65's keyboard:

keyboard_n_i         : in  std_logic_vector(79 downto 0);

Therefore the whole logic of keyboard.vhd boils down to creating 80 flip-flops (i.e. a 80-bit register) and keeping them updated:

   example_n_o <= key_pressed_n;
   
   keyboard_state : process(clk_main_i)
   begin
      if rising_edge(clk_main_i) then
         key_pressed_n(key_num_i) <= key_pressed_n_i;
      end if;
   end process;

config.vhd: shell_cfg

The Shell is highly versatile and a lot of details of how it behaves and what services it shall offer to the users can be configured. You are doing this in config.vhd.

Vivado will synthesize config.vhd into a ROM that can be read by the QNICE firmware and by the Shell. As long as you "just" would like to use the Shell (instead of writing your own firmware from scratch), you do not need to understand how the underlying mechanisms work. In this case just stick with the comments in config.vhd and do not touch any part of the file that is marked with "DO NOT TOUCH".

The "Hello World" Tutorial will - among other things - show you how you can use config.vhd to create new menu items for the on-screen-menu (Help menu) and how to change the Welcome Screen's standard behavior.

globals.vhd

The things that you will need to change in globals.vhd are these:

  • Precise speed of your MiSTer core's clock(s) in Hertz
  • The DX and DY "retro" resolution of the core (remember: this is what will be output on the VGA port; HDMI will always be auto-scaled to 720p)
  • Virtual drives and/or ROMs
  • Audio filters (if any)

All of this is beyond the scope of our small first demo tour through M2M.

Next Steps

We highly encourage you to follow the track and continue with the "Hello World" Tutorial from here.