Nestor80 is a Z80, R800 and Z280 assembler almost fully compatible with Microsoft's Macro80 at the source code level. It can produce absolute and relocatable files; relocatable files can be linked using the Linkstor80 package.
Nestor80 is published as a standalone command line application, N80
(or N80.exe
). Additionally, you can use this NuGet package to assemble code programmatically. The process is as follows:
-
Create an instance of
AssemblyConfiguration
and set its properties as appropriate. The properties of this class mimic the command line arguments of the N80 application, you can get a reference by runningN80 --help
or by looking at the help text in the N80 source code. -
Run
AssemblySourceProcessor.Assemble
, passing an open stream for the source code and the instance ofAssemblyConfiguration
created in the previous step. The output is an instance ofAssemblyResult
containing an abstraction of the assembled code and any errors that were found during the process. -
If the
AssemblyResult
'sHasErrors
property is true, the process failed. Show the errors (Errors
property) and abort the process. Note that some errors can be just warnings (IsWarning
property on each individual error object), but if all errors are warningsHasErrors
will be false. -
Run
OutputGenerator.GenerateAbsolute
,GenerateRelocatable
orGenerateSdccRelocatable
, passing the instance ofAssemblyResult
and an open writable stream for the resulting binary file. -
Optionally, create a listing file by executing
ListingFileGenerator.GenerateListingFile
, passing the instance ofAssemblyResult
, an open writable stream for the listing file, and an instance ofListingFileConfiguration
.
Below is a simple but fully funcional assembler, it takes a source code file as its only argument and generates an absolute binary file (same filename in same directory but with .bin
extension) and a listing file (same filename in same directory but with .lst
extension).
using Konamiman.Nestor80.Assembler;
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace SimpleAssembler;
internal class Program
{
static void Main(string[] args)
{
if(args.Length == 0) {
Console.WriteLine("*** Usage: SimpleAssembler <source file>");
return;
}
// Step 1: Generate an AssemblyResult instance from the source file
var sourceFile = args[0];
var sourceStream = File.OpenRead(sourceFile);
var assemblyConfig = new AssemblyConfiguration() {
BuildType = BuildType.Absolute,
PredefinedSymbols = new (string, ushort)[] { ("DEBUGGING", 0xFFFF) }
};
var assemblyResult = AssemblySourceProcessor.Assemble(sourceStream, Encoding.UTF8, assemblyConfig);
sourceStream.Close();
if(assemblyResult.HasErrors) {
Console.WriteLine("*** Errors!!");
foreach(var error in assemblyResult.Errors) {
Console.WriteLine($"Line {error.LineNumber} : {error.Message}");
}
}
else {
// If there are warnings, show them
var warnings = assemblyResult.Errors.Where(e => e.IsWarning);
foreach(var warning in warnings) {
Console.WriteLine($"WARNING: Line {warning.LineNumber} : {warning.Message}");
}
// Step 2: Generate the binary file from the instance of AssemblyResult
var outputFileName = Path.Combine(Path.GetDirectoryName(sourceFile) ?? "", Path.GetFileNameWithoutExtension(sourceFile) + ".bin");
var outputStream = File.Create(outputFileName);
OutputGenerator.GenerateAbsolute(assemblyResult, outputStream);
outputStream.Close();
// Step 3 (optional): Generate a listing file
var listingFileName = Path.Combine(Path.GetDirectoryName(sourceFile) ?? "", Path.GetFileNameWithoutExtension(sourceFile) + ".lst");
var listingStreamWriter = File.CreateText(listingFileName);
var listingConfig = new ListingFileConfiguration() {
TitleSignature = "My simple assembler",
MaxSymbolLength = 255
};
ListingFileGenerator.GenerateListingFile(assemblyResult, listingStreamWriter, listingConfig);
listingStreamWriter.Close();
Console.WriteLine("Done! Generated file: " + outputFileName);
}
}
}
You can try it with the following Z80 source file, name it test.asm
:
org 100h
ld a,34
ret
Running SimpleAssembler test.asm
will generate test.bin
and test.lst
.
If you want to force errors you can change it to:
org 100h
ld a,1000h
ld b,2000h
ret
...and if you want to force warnings:
org 100h
ld a,34
if1 ;To prevent warnings from displaying twice (Nestor80 is a two pass assembler)
.warn This is a warning!
.warn Another one!
endif
ret
See also: