SpectNet IDE

Visual Studio 2017/2019 integrated ZX Spectrum IDE for the Community

Scripting » Overview

SpectNetIde is not just a simple ZX Spectrum emulator and a set of development tools integrated with Visual Studio, it offers a collection of .NET objects that you can use to automate ZX Spectrum related tasks.

Should it be looking for infinite lives for a game, understanding the structure of a complex application, finding out how a particular code works within special conditions — scripting makes it easy to automate mechanical tasks.

The Spect.Net.SpectrumEmu.Scripting namespace provides a dozen of object types suited for automation. You can use these types from any .NET language, and scripting engines that support directly.

Many popular scripting languages may support .NET objects through wrappers. Although SpectNetIde does not have any direct support for these languages, contributors are welcomed to create such adapters. If you are interested, please contact me at dotneteer@hotmail.com.

A Sample Script

Just for the sake of demonstration, here is a short sample that sets the border to red, and checks that the screen is rendered accordingly:

using System;
using System.Threading.Tasks;
using Spect.Net.SpectrumEmu.Scripting;

namespace MyFirstScript
{
  class Program
  {
    static async Task Main(string[] args)
    {
      var sm = SpectrumVmFactory.CreateSpectrum48Pal();
      Console.WriteLine("Setting the border to red");

      await sm.StartAndRunToMain();
      var entryAddr = sm.InjectCode(@"
        .org #8000
        ld a,2       ; RED
        out (#FE),a  ; Set the border colour to red
        halt         ; Wait for 2 frames (rendering)
        halt
        ret          ; Finished
      ");
      sm.CallCode(entryAddr);
      await sm.CompletionTask;

      var screen = sm.ScreenConfiguration;
      var redCount = 0;
      for (var i = 0; i < screen.ScreenLines; i++)
        for (var j = 0; j < screen.ScreenWidth; j++)
          redCount += sm.ScreenBitmap[i,j] == 0x02 ? 1 : 0;

      Console.WriteLine($"#of red pixels: {redCount}");
      var borderPixels = screen.ScreenLines * screen.ScreenWidth
        - screen.DisplayLines * screen.DisplayWidth;
      Console.WriteLine($"#of border pixels: {borderPixels}");
    }
  }
}

The script starts with creating a ZX Spectrum 48 virtual machine:

var sm = SpectrumVmFactory.CreateSpectrum48Pal();

Then the code starts the virtual machine (asynchronously in the background) and waits while it initializes the operating system, and enters into its main execution cycle:

await sm.StartAndRunToMain();

As it reaches the desired state, the virtual machine pauses. At this point, it is ready for code injection. As the next code snippet shows, _SpectNetIde__ makes it extremely easy to inject source code into the machine:

var entryAddr = sm.InjectCode(@"
  .org #8000
  ld a,2       ; RED
  out (#FE),a  ; Set the border colour to red
  halt         ; Wait for 2 frames (rendering)
  halt
  ret          ; Finished
");

You can utilize the Z80 Assembler syntax (the same as the IDE uses) to define the machine code to inject. The InjectCode() method returns the entry address of the code, so you can explicitly start the code in the virtual machine:

sm.CallCode(entryAddr);
await sm.CompletionTask;

The CallCode() method continues the execution cycle of the machine and pauses it when the code returns. The sm.CompletionTask provides an awaiter to wait while the machine gets paused.

The last part of the code uses the ScreenConfiguration property to get information about the screen. The ScreenBitmap object can be used to check every pixel in the rendered screen (including the border pixels):

var screen = sm.ScreenConfiguration;
var redCount = 0;
for (var i = 0; i < screen.ScreenLines; i++)
    for (var j = 0; j < screen.ScreenWidth; j++)
        redCount += sm.ScreenBitmap[i,j] == 0x02 ? 1 : 0;

Console.WriteLine($"#of red pixels: {redCount}");
var borderPixels = screen.ScreenLines * screen.ScreenWidth
    - screen.DisplayLines * screen.DisplayWidth;
Console.WriteLine($"#of border pixels: {borderPixels}");

When you start this code from Visual Studio, it produces this output:

Setting the border to red
#of red pixels: 52224
#of border pixels: 52224

The result proves that the virtual machine renders all border pixels with red color.