Эх сурвалжийг харах

starting implementation of holtect emulator

Klaas, Wilfried 6 жил өмнө
parent
commit
4b3f300b64

+ 39 - 0
.classpath

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/5"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+/target/

+ 23 - 0
.project

@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>SPSEmulator</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+	</natures>
+</projectDescription>

+ 6 - 0
.settings/org.eclipse.core.resources.prefs

@@ -0,0 +1,6 @@
+eclipse.preferences.version=1
+encoding//src/main/java=UTF-8
+encoding//src/main/resources=UTF-8
+encoding//src/test/java=UTF-8
+encoding//src/test/resources=UTF-8
+encoding/<project>=UTF-8

+ 9 - 0
.settings/org.eclipse.jdt.core.prefs

@@ -0,0 +1,9 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.release=disabled
+org.eclipse.jdt.core.compiler.source=1.8

+ 4 - 0
.settings/org.eclipse.m2e.core.prefs

@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1

+ 171 - 0
pom.xml

@@ -0,0 +1,171 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>de.mcs.tools.sps</groupId>
+  <artifactId>SPSEmulator</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <name>SPS_Emulator</name>
+  <url>http://www.wk-music.de</url>
+  <description>SPS Emulator wirtten in java.</description>
+	<licenses>
+		<license>
+			<name>The Apache License, Version 2.0</name>
+			<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
+		</license>
+	</licenses>
+
+	<developers>
+		<developer>
+			<name>Wilfried Klaas</name>
+			<email>w.klaas@gmx.de</email>
+			<organization>MCS</organization>
+			<organizationUrl>http://www.wk-music.de</organizationUrl>
+		</developer>
+	</developers>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<timestamp>${maven.build.timestamp}</timestamp>
+		<maven.build.timestamp.format>dd.mm.yyyy HH:mm</maven.build.timestamp.format>
+		<jackson.version>2.8.5</jackson.version>
+	</properties>
+	<build>
+		<plugins>
+			<plugin>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<version>3.3</version>
+				<configuration>
+					<source>1.8</source>
+					<target>1.8</target>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<version>2.6</version>
+				<configuration>
+					<archive>
+						<manifest>
+							<mainClass>de.mcs.tools.addsub.Main</mainClass>
+							<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
+							<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
+						</manifest>
+						<manifestEntries>
+							<Build-Time>${maven.build.timestamp}</Build-Time>
+							<Application-Name>MCSAddSub</Application-Name>
+							<Application-Update-Id>72</Application-Update-Id>
+							<Application-Update-Url>http\://wkla.no-ip.biz/downloader/version.php?ID\=72</Application-Update-Url>
+							<Application-Url>http\://wkla.no-ip.biz/</Application-Url>
+							<Implementation-Vendor>MCS, Media Computer Software</Implementation-Vendor>
+						</manifestEntries>
+					</archive>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-shade-plugin</artifactId>
+				<version>2.4.1</version>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>shade</goal>
+						</goals>
+						<!-- <configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> 
+							<mainClass></mainClass> </transformer> </transformers> </configuration> -->
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>com.akathist.maven.plugins.launch4j</groupId>
+				<artifactId>launch4j-maven-plugin</artifactId>
+				<version>1.7.8</version>
+				<executions>
+					<execution>
+						<id>l4j-clui</id>
+						<phase>package</phase>
+						<goals>
+							<goal>launch4j</goal>
+						</goals>
+						<configuration>
+							<dontWrapJar>false</dontWrapJar>
+							<headerType>console</headerType>
+							<jar>${project.build.directory}/${project.artifactId}-${project.version}.jar</jar>
+							<outfile>${project.build.directory}/MCSAddSub.exe</outfile>
+							<downloadUrl>http://java.com/download</downloadUrl>
+							<!-- <classPath> <mainClass>com.howtodoinjava.ApplicationMain</mainClass> <preCp>anything</preCp> </classPath> -->
+							<icon>src\main\resources\MSA.ico</icon>
+							<jre>
+								<minVersion>1.8.0</minVersion>
+								<jdkPreference>jreOnly</jdkPreference>
+							</jre>
+							<versionInfo>
+								<fileVersion>1.0.0.0</fileVersion>
+								<txtFileVersion>${project.version}</txtFileVersion>
+								<fileDescription>${project.name}</fileDescription>
+								<copyright>2018 MCS</copyright>
+								<productVersion>1.0.0.0</productVersion>
+								<txtProductVersion>1.0.0.0</txtProductVersion>
+								<productName>${project.name}</productName>
+								<companyName>MCS</companyName>
+								<internalName>MCSAddSub</internalName>
+								<originalFilename>MCSAddSub.exe</originalFilename>
+							</versionInfo>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+	</build>
+	<dependencies>
+		<dependency>
+			<groupId>net.sourceforge.jmeasurement2</groupId>
+			<artifactId>MCSUtils</artifactId>
+			<version>1.0.150</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.5</version>
+		</dependency>
+		<dependency>
+			<groupId>net.sourceforge.jmeasurement2</groupId>
+			<artifactId>JMeasurement</artifactId>
+			<version>1.1.225</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-core</artifactId>
+			<version>${jackson.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-annotations</artifactId>
+			<version>${jackson.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.core</groupId>
+			<artifactId>jackson-databind</artifactId>
+			<version>${jackson.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.fasterxml.jackson.dataformat</groupId>
+			<artifactId>jackson-dataformat-yaml</artifactId>
+			<version>${jackson.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>log4j</groupId>
+			<artifactId>log4j</artifactId>
+			<version>1.2.17</version>
+		</dependency>
+		<dependency>
+			<groupId>com.martiansoftware</groupId>
+			<artifactId>jsap</artifactId>
+			<version>2.1</version>
+		</dependency>
+		<dependency>
+		  <groupId>org.apache.commons</groupId>
+		  <artifactId>commons-lang3</artifactId>
+		  <version>3.4</version>
+		</dependency>
+	</dependencies>
+</project>

+ 61 - 0
src/main/java/de/mcs/tools/sps/AbstractEmulator.java

@@ -0,0 +1,61 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+import java.util.List;
+
+import de.mcs.tools.sps.exceptions.WrongProgramSizeException;
+
+/**
+ * @author w.klaas
+ *
+ */
+public abstract class AbstractEmulator implements SPSEmulator {
+
+  @Override
+  public abstract List<SPSCommand> getCommands();
+
+  @Override
+  public abstract int getProgramSize();
+
+  @Override
+  public void loadProgram(byte[] program) throws WrongProgramSizeException {
+    if (program.length > getProgramSize()) {
+      throw new WrongProgramSizeException(
+          String.format("the program is to long. Only %d bytes are permitted", getProgramSize()));
+    }
+
+  }
+
+  @Override
+  public void startProgram(boolean debug) {
+
+  }
+
+  @Override
+  public void addCallback(TOutputCallback callback) {
+
+  }
+
+  @Override
+  public void nextStep() {
+
+  }
+
+  @Override
+  public boolean isActive() {
+    return false;
+  }
+
+  @Override
+  public void stop() {
+
+  }
+
+  @Override
+  public TEmulatorInternals getInternals() {
+    return null;
+  }
+
+}

+ 36 - 0
src/main/java/de/mcs/tools/sps/SPSCommand.java

@@ -0,0 +1,36 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+import java.util.List;
+
+/**
+ * a single Command for the emulator
+ * 
+ * @author w.klaas
+ *
+ */
+public interface SPSCommand {
+
+  /**
+   * @return the name of this command
+   */
+  String getName();
+
+  /**
+   * @return the short Mnemonic
+   */
+  String getMnemonic();
+
+  /**
+   * @return the byte code for this command
+   */
+  byte getCommandByte();
+
+  /**
+   * @return a lsit of all supported datas of this command
+   */
+  List<SPSCommandData> getCommandDatas();
+
+}

+ 35 - 0
src/main/java/de/mcs/tools/sps/SPSCommandData.java

@@ -0,0 +1,35 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+/**
+ * a single command data for the emulator
+ * 
+ * @author w.klaas
+ *
+ */
+public interface SPSCommandData {
+
+  /**
+   * 
+   * @return the command this data belongs to
+   */
+  SPSCommand getCommand();
+
+  /**
+   * @return the name of this command
+   */
+  String getName();
+
+  /**
+   * @return the short Mnemonic
+   */
+  String getMnemonic();
+
+  /**
+   * @return the byte code for this command and data
+   */
+  byte getCommandByte();
+
+}

+ 83 - 0
src/main/java/de/mcs/tools/sps/SPSCommandDataImpl.java

@@ -0,0 +1,83 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+/**
+ * @author w.klaas
+ *
+ */
+public class SPSCommandDataImpl implements SPSCommandData {
+
+  String name;
+  String mnemonic;
+  byte cmdByte;
+  SPSCommand command;
+
+  public SPSCommandDataImpl() {
+  }
+
+  @Override
+  public SPSCommand getCommand() {
+    return command;
+  }
+
+  @Override
+  public String getName() {
+    return name;
+  }
+
+  @Override
+  public String getMnemonic() {
+    return mnemonic;
+  }
+
+  /**
+   * @return the cmdByte
+   */
+  @Override
+  public byte getCommandByte() {
+    return cmdByte;
+  }
+
+  /**
+   * @param cmdByte
+   *          the cmdByte to set
+   * @return this instance
+   */
+  public SPSCommandDataImpl setCommandByte(byte cmdByte) {
+    this.cmdByte = cmdByte;
+    return this;
+  }
+
+  /**
+   * @param name
+   *          the name to set
+   * @return this instance
+   */
+  public SPSCommandDataImpl setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  /**
+   * @param mnemonic
+   *          the mnemonic to set
+   * @return this instance
+   */
+  public SPSCommandDataImpl setMnemonic(String mnemonic) {
+    this.mnemonic = mnemonic;
+    return this;
+  }
+
+  /**
+   * @param command
+   *          the command to set
+   * @return this instance
+   */
+  public SPSCommandDataImpl setCommand(SPSCommand command) {
+    this.command = command;
+    return this;
+  }
+
+}

+ 74 - 0
src/main/java/de/mcs/tools/sps/SPSCommandImpl.java

@@ -0,0 +1,74 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author w.klaas
+ *
+ */
+public class SPSCommandImpl implements SPSCommand {
+
+  String name;
+  String mnemonic;
+  byte cmdByte;
+  List<SPSCommandData> datas = new ArrayList<>();
+
+  /**
+   * 
+   */
+  public SPSCommandImpl() {
+  }
+
+  @Override
+  public String getName() {
+    return name;
+  }
+
+  @Override
+  public String getMnemonic() {
+    return mnemonic;
+  }
+
+  @Override
+  public byte getCommandByte() {
+    return cmdByte;
+  }
+
+  @Override
+  public List<SPSCommandData> getCommandDatas() {
+    return datas;
+  }
+
+  /**
+   * @param cmdByte
+   *          the cmdByte to set
+   */
+  public SPSCommandImpl setCommandByte(byte cmdByte) {
+    this.cmdByte = cmdByte;
+    return this;
+  }
+
+  /**
+   * @param name
+   *          the name to set
+   */
+  public SPSCommandImpl setName(String name) {
+    this.name = name;
+    return this;
+  }
+
+  /**
+   * @param mnemonic
+   *          the mnemonic to set
+   * @return
+   */
+  public SPSCommandImpl setMnemonic(String mnemonic) {
+    this.mnemonic = mnemonic;
+    return this;
+  }
+
+}

+ 75 - 0
src/main/java/de/mcs/tools/sps/SPSEmulator.java

@@ -0,0 +1,75 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+import java.util.List;
+
+import de.mcs.tools.sps.exceptions.WrongProgramSizeException;
+
+/**
+ * @author w.klaas
+ *
+ */
+public interface SPSEmulator {
+
+  /**
+   * returning all commands supported by this emulator
+   * 
+   * @return lsit of all supported commands
+   */
+  List<SPSCommand> getCommands();
+
+  /**
+   * @return the size of the internal program area
+   */
+  int getProgramSize();
+
+  /**
+   * loading a program into the emulator
+   * 
+   * @param program
+   *          to load
+   * @throws WrongProgramSizeException
+   */
+  void loadProgram(byte[] program) throws WrongProgramSizeException;
+
+  /**
+   * starting the program with or without debug mode
+   * 
+   * @param debug
+   *          if debug = <code>true</code> than the program will stop on every step, otherwise only the callbacks will
+   *          be called
+   */
+  void startProgram(boolean debug);
+
+  /**
+   * adding a callback for the outputs of the emulator
+   * 
+   * @param callback
+   */
+  void addCallback(TOutputCallback callback);
+
+  /**
+   * do the next step of the program
+   */
+  void nextStep();
+
+  /**
+   * sps emulator is active
+   * 
+   * @return
+   */
+  boolean isActive();
+
+  /**
+   * stop the actual process
+   */
+  void stop();
+
+  /**
+   * 
+   * @return the actual emualtor internals
+   */
+  TEmulatorInternals getInternals();
+}

+ 14 - 0
src/main/java/de/mcs/tools/sps/TEmulatorInternals.java

@@ -0,0 +1,14 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+/**
+ * This interface is for getting the emualtor internal
+ * 
+ * @author w.klaas
+ *
+ */
+public interface TEmulatorInternals {
+
+}

+ 14 - 0
src/main/java/de/mcs/tools/sps/TEmulatorOutput.java

@@ -0,0 +1,14 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+/**
+ * this is the interface of all Emulatoroutputs
+ * 
+ * @author w.klaas
+ *
+ */
+public interface TEmulatorOutput {
+
+}

+ 14 - 0
src/main/java/de/mcs/tools/sps/TOutputCallback.java

@@ -0,0 +1,14 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps;
+
+/**
+ * Interface for the callbacks on the emulator
+ * 
+ * @author w.klaas
+ *
+ */
+public interface TOutputCallback {
+  void onOutput(TEmulatorOutput output);
+}

+ 51 - 0
src/main/java/de/mcs/tools/sps/exceptions/WrongProgramSizeException.java

@@ -0,0 +1,51 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps.exceptions;
+
+/**
+ * @author w.klaas
+ *
+ */
+public class WrongProgramSizeException extends Exception {
+
+  /**
+   * 
+   */
+  public WrongProgramSizeException() {
+  }
+
+  /**
+   * @param message
+   */
+  public WrongProgramSizeException(String message) {
+    super(message);
+  }
+
+  /**
+   * @param cause
+   */
+  public WrongProgramSizeException(Throwable cause) {
+    super(cause);
+  }
+
+  /**
+   * @param message
+   * @param cause
+   */
+  public WrongProgramSizeException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  /**
+   * @param message
+   * @param cause
+   * @param enableSuppression
+   * @param writableStackTrace
+   */
+  public WrongProgramSizeException(String message, Throwable cause, boolean enableSuppression,
+      boolean writableStackTrace) {
+    super(message, cause, enableSuppression, writableStackTrace);
+  }
+
+}

+ 8 - 0
src/main/java/de/mcs/tools/sps/exceptions/package-info.java

@@ -0,0 +1,8 @@
+/**
+ * 
+ */
+/**
+ * @author w.klaas
+ *
+ */
+package de.mcs.tools.sps.exceptions;

+ 288 - 0
src/main/java/de/mcs/tools/sps/holtec/HoltecEmulator.java

@@ -0,0 +1,288 @@
+/**
+ * 
+ */
+package de.mcs.tools.sps.holtec;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import de.mcs.tools.sps.AbstractEmulator;
+import de.mcs.tools.sps.SPSCommand;
+import de.mcs.tools.sps.SPSCommandData;
+import de.mcs.tools.sps.SPSCommandDataImpl;
+import de.mcs.tools.sps.SPSCommandImpl;
+import de.mcs.tools.sps.SPSEmulator;
+
+/**
+ * @author w.klaas
+ *
+ */
+public class HoltecEmulator extends AbstractEmulator implements SPSEmulator {
+  private List<SPSCommand> commands = new ArrayList<>();
+  {
+    commands.add(SPS_PORT);
+    commands.add(SPS_WAIT);
+    commands.add(SPS_JUMP_DOWN);
+    commands.add(SPS_A_EQUALS);
+    commands.add(SPS_EQUALS_A);
+    commands.add(SPS_A_INPUT);
+    commands.add(SPS_A_CALCULATE);
+    commands.add(SPS_PAGE);
+    commands.add(SPS_JUMP_UP);
+    commands.add(SPS_C_LOOP);
+    commands.add(SPS_D_LOOP);
+    commands.add(SPS_SKIP_IF);
+    commands.add(SPS_CALL);
+    commands.add(SPS_RETURN);
+  }
+
+  private static SPSCommand SPS_PORT = new SPSCommandImpl().setName("Port Output").setMnemonic("PORT")
+      .setCommandByte((byte) 0x10);
+
+  static {
+    for (int i = 0; i < 16; i++) {
+      SPS_PORT.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("Port " + Integer.toString(i)).setMnemonic("PO" + Integer.toString(i))
+              .setCommandByte((byte) (SPS_PORT.getCommandByte() + i)).setCommand(SPS_PORT));
+    }
+  }
+
+  private static SPSCommand SPS_WAIT = new SPSCommandImpl().setName("WAIT").setMnemonic("WAIT")
+      .setCommandByte((byte) 0x20);
+  static {
+    List<SPSCommandData> datas = SPS_WAIT.getCommandDatas();
+    datas.add(new SPSCommandDataImpl().setName("Wait 1ms").setMnemonic("D1M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 2ms").setMnemonic("D2M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 5ms").setMnemonic("D5M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 10ms").setMnemonic("D10M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 20ms").setMnemonic("D20M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 50ms").setMnemonic("D50M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 100ms").setMnemonic("D100M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 200ms").setMnemonic("D200M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 500ms").setMnemonic("D500M")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 1s").setMnemonic("D1S")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 2s").setMnemonic("D2S")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 5s").setMnemonic("D5S")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 10s").setMnemonic("D10S")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 20s").setMnemonic("D20S")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 30s").setMnemonic("D30S")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+    datas.add(new SPSCommandDataImpl().setName("Wait 60s").setMnemonic("D60S")
+        .setCommandByte((byte) SPS_WAIT.getCommandByte()).setCommand(SPS_WAIT));
+  }
+
+  private static SPSCommand SPS_JUMP_DOWN = new SPSCommandImpl().setName("jump back").setMnemonic("JMP-")
+      .setCommandByte((byte) 0x30);
+  static {
+    for (int i = 0; i < 16; i++) {
+      SPS_JUMP_DOWN.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("Jump -" + Integer.toString(i)).setMnemonic("JN" + Integer.toString(i))
+              .setCommandByte((byte) (SPS_JUMP_DOWN.getCommandByte() + i)).setCommand(SPS_JUMP_DOWN));
+    }
+  }
+
+  private static SPSCommand SPS_A_EQUALS = new SPSCommandImpl().setName("Set A").setMnemonic("A=")
+      .setCommandByte((byte) 0x40);
+  static {
+    for (int i = 0; i < 16; i++) {
+      SPS_A_EQUALS.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("A= " + Integer.toString(i)).setMnemonic(String.format("A%02d", i))
+              .setCommandByte((byte) (SPS_A_EQUALS.getCommandByte() + i)).setCommand(SPS_A_EQUALS));
+    }
+  }
+
+  private static SPSCommand SPS_EQUALS_A = new SPSCommandImpl().setName("=A").setMnemonic("=A")
+      .setCommandByte((byte) 0x50);
+  static {
+    List<SPSCommandData> datas = SPS_EQUALS_A.getCommandDatas();
+    datas.add(new SPSCommandDataImpl().setName("B=A").setMnemonic("BEA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x01)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("C=A").setMnemonic("CEA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x02)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("D=A").setMnemonic("DEA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x03)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("Output=A").setMnemonic("OEA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x04)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("Output.1=A").setMnemonic("O1EA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x05)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("Output.2=A").setMnemonic("O2EA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x06)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("Output.3=A").setMnemonic("O3EA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x07)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("Output.4=A").setMnemonic("O4EA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x08)).setCommand(SPS_EQUALS_A));
+    datas.add(new SPSCommandDataImpl().setName("PWM=A").setMnemonic("PEA")
+        .setCommandByte((byte) (SPS_EQUALS_A.getCommandByte() + 0x09)).setCommand(SPS_EQUALS_A));
+  }
+
+  private static SPSCommand SPS_A_INPUT = new SPSCommandImpl().setName("A=(some input)").setMnemonic("AEI")
+      .setCommandByte((byte) 0x60);
+  static {
+    List<SPSCommandData> datas = SPS_A_INPUT.getCommandDatas();
+    datas.add(new SPSCommandDataImpl().setName("A=B").setMnemonic("AEB")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x01)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=C").setMnemonic("AEC")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x02)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=D").setMnemonic("AED")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x03)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=Input").setMnemonic("AEI")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x04)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=Input.1").setMnemonic("AEI1")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x05)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=Input.2").setMnemonic("AEI2")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x06)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=Input.3").setMnemonic("AEI3")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x07)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=Input.4").setMnemonic("AEI4")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x08)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=AD.1").setMnemonic("AEA1")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x09)).setCommand(SPS_A_INPUT));
+    datas.add(new SPSCommandDataImpl().setName("A=AD.2").setMnemonic("AEA2")
+        .setCommandByte((byte) (SPS_A_INPUT.getCommandByte() + 0x0A)).setCommand(SPS_A_INPUT));
+  }
+
+  private static SPSCommand SPS_A_CALCULATE = new SPSCommandImpl().setName("Calculate with A").setMnemonic("CALC")
+      .setCommandByte((byte) 0x70);
+  static {
+    List<SPSCommandData> datas = SPS_A_CALCULATE.getCommandDatas();
+    datas.add(new SPSCommandDataImpl().setName("A=A+1").setMnemonic("INCA")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x01)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A-1").setMnemonic("DECA")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x02)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A+B").setMnemonic("ADDB")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x03)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A-B").setMnemonic("SUBB")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x04)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A*B").setMnemonic("MULB")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x05)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A/B").setMnemonic("DIVB")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x06)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A AND B").setMnemonic("ANDB")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x07)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A OR B").setMnemonic("ORB")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x08)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=A XOR B").setMnemonic("XORB")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x09)).setCommand(SPS_A_CALCULATE));
+    datas.add(new SPSCommandDataImpl().setName("A=NOT A").setMnemonic("NOTA")
+        .setCommandByte((byte) (SPS_A_CALCULATE.getCommandByte() + 0x0A)).setCommand(SPS_A_CALCULATE));
+  }
+
+  private static SPSCommand SPS_PAGE = new SPSCommandImpl().setName("Page").setMnemonic("PG")
+      .setCommandByte((byte) 0x80);
+  static {
+    for (int i = 0; i < 8; i++) {
+      SPS_PAGE.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("Page " + Integer.toString(i)).setMnemonic("PG" + Integer.toString(i))
+              .setCommandByte((byte) (SPS_PAGE.getCommandByte() + i)).setCommand(SPS_PAGE));
+    }
+  }
+
+  private static SPSCommand SPS_JUMP_UP = new SPSCommandImpl().setName("Jump").setMnemonic("JMP")
+      .setCommandByte((byte) 0x90);
+  static {
+    for (int i = 0; i < 16; i++) {
+      SPS_JUMP_UP.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("Jump " + Integer.toString(i)).setMnemonic("JMP" + Integer.toString(i))
+              .setCommandByte((byte) (SPS_JUMP_UP.getCommandByte() + i)).setCommand(SPS_JUMP_UP));
+    }
+  }
+
+  private static SPSCommand SPS_C_LOOP = new SPSCommandImpl().setName("C* Loop").setMnemonic("CLOP")
+      .setCommandByte((byte) 0xA0);
+  static {
+    for (int i = 0; i < 16; i++) {
+      SPS_C_LOOP.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("C* Loop " + Integer.toString(i))
+              .setMnemonic("CLOP" + Integer.toString(i)).setCommandByte((byte) (SPS_C_LOOP.getCommandByte() + i))
+              .setCommand(SPS_C_LOOP));
+    }
+  }
+
+  private static SPSCommand SPS_D_LOOP = new SPSCommandImpl().setName("D* Loop").setMnemonic("DLOP")
+      .setCommandByte((byte) 0xB0);
+  static {
+    for (int i = 0; i < 16; i++) {
+      SPS_D_LOOP.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("D* Loop " + Integer.toString(i))
+              .setMnemonic("DLOP" + Integer.toString(i)).setCommandByte((byte) (SPS_D_LOOP.getCommandByte() + i))
+              .setCommand(SPS_D_LOOP));
+    }
+  }
+
+  private static SPSCommand SPS_SKIP_IF = new SPSCommandImpl().setName("Skip if").setMnemonic("SKIP")
+      .setCommandByte((byte) 0xC0);
+  static {
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("A>B").setMnemonic("AGRB")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x01)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("A<B").setMnemonic("ASMB")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x02)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("A=B").setMnemonic("AEQB")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x03)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.1=1").setMnemonic("IN11")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x04)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.2=1").setMnemonic("IN21")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x05)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.3=1").setMnemonic("IN31")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x06)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.4=1").setMnemonic("IN41")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x07)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.1=0").setMnemonic("IN10")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x08)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.2=0").setMnemonic("IN20")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x09)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.3=0").setMnemonic("IN30")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0A)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("In.4=0").setMnemonic("IN40")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0B)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("S1=0").setMnemonic("S10")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0C)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("S2=0").setMnemonic("S20")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0D)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("S1=1").setMnemonic("S11")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0E)).setCommand(SPS_SKIP_IF));
+    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl().setName("S2=1").setMnemonic("S21")
+        .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0F)).setCommand(SPS_SKIP_IF));
+  };
+
+  private static SPSCommand SPS_CALL = new SPSCommandImpl().setName("Call").setMnemonic("CALL")
+      .setCommandByte((byte) 0xD0);
+  static {
+    for (int i = 0; i < 16; i++) {
+      SPS_CALL.getCommandDatas()
+          .add(new SPSCommandDataImpl().setName("Call " + Integer.toString(i)).setMnemonic("CALL" + Integer.toString(i))
+              .setCommandByte((byte) (SPS_CALL.getCommandByte() + i)).setCommand(SPS_CALL));
+    }
+  }
+
+  private static SPSCommand SPS_RETURN = new SPSCommandImpl().setName("return").setMnemonic("RET")
+      .setCommandByte((byte) 0xE0);
+  static {
+    SPS_RETURN.getCommandDatas().add(new SPSCommandDataImpl().setName("Return").setMnemonic("RET")
+        .setCommandByte((byte) (SPS_RETURN.getCommandByte())).setCommand(SPS_RETURN));
+  }
+
+  @Override
+  public List<SPSCommand> getCommands() {
+    return commands;
+  }
+
+  @Override
+  public int getProgramSize() {
+    return 128;
+  }
+
+}

+ 8 - 0
src/main/java/de/mcs/tools/sps/holtec/package-info.java

@@ -0,0 +1,8 @@
+/**
+ * 
+ */
+/**
+ * @author w.klaas
+ *
+ */
+package de.mcs.tools.sps.holtec;

+ 8 - 0
src/main/java/de/mcs/tools/sps/package-info.java

@@ -0,0 +1,8 @@
+/**
+ * 
+ */
+/**
+ * @author w.klaas
+ *
+ */
+package de.mcs.tools.sps;

+ 107 - 0
src/test/java/de/mcs/tools/sps/holtec/TestHoltecEmualtor.java

@@ -0,0 +1,107 @@
+package de.mcs.tools.sps.holtec;
+
+import static org.junit.Assert.fail;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import de.mcs.tools.sps.SPSCommand;
+import de.mcs.tools.sps.SPSCommandData;
+import de.mcs.tools.sps.SPSEmulator;
+import de.mcs.tools.sps.exceptions.WrongProgramSizeException;
+
+class TestHoltecEmualtor {
+
+  private SPSEmulator holtectEmulator;
+
+  @BeforeEach
+  void setUp() throws Exception {
+    holtectEmulator = new HoltecEmulator();
+  }
+
+  @Test
+  void testOutputAllCommands() {
+    System.out.println("command list holtect");
+    List<SPSCommand> commands = holtectEmulator.getCommands();
+    commands.forEach(c -> {
+      List<SPSCommandData> commandDatas = c.getCommandDatas();
+      System.out.printf("Command %s(%s):", c.getMnemonic(), c.getName());
+      commandDatas.forEach(cd -> {
+        System.out.printf("%s(%s) ,", cd.getMnemonic(), cd.getName());
+      });
+      System.out.println();
+    });
+  }
+
+  @Test
+  void testProgramSize() throws WrongProgramSizeException {
+    assertEquals(128, holtectEmulator.getProgramSize());
+    byte[] prgMemory = new byte[128];
+    holtectEmulator.loadProgram(prgMemory);
+  }
+
+  @Test
+  void testWrongProgramSize() throws WrongProgramSizeException {
+    byte[] prgMemory = new byte[129];
+    Throwable exception = assertThrows(WrongProgramSizeException.class, () -> holtectEmulator.loadProgram(prgMemory));
+  }
+
+  @Test
+  void testCommandArray() {
+    List<SPSCommand> commands = holtectEmulator.getCommands();
+    assertEquals(14, commands.size());
+    for (SPSCommand spsCommand : commands) {
+      switch (spsCommand.getCommandByte()) {
+      case 0x10:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case 0x20:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case 0x30:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case 0x40:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case 0x50:
+        assertEquals(9, spsCommand.getCommandDatas().size());
+        break;
+      case 0x60:
+        assertEquals(10, spsCommand.getCommandDatas().size());
+        break;
+      case 0x70:
+        assertEquals(10, spsCommand.getCommandDatas().size());
+        break;
+      case (byte) 0x80:
+        assertEquals(8, spsCommand.getCommandDatas().size());
+        break;
+      case (byte) 0x90:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case (byte) 0xA0:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case (byte) 0xB0:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case (byte) 0xC0:
+        assertEquals(15, spsCommand.getCommandDatas().size());
+        break;
+      case (byte) 0xD0:
+        assertEquals(16, spsCommand.getCommandDatas().size());
+        break;
+      case (byte) 0xE0:
+        assertEquals(1, spsCommand.getCommandDatas().size());
+        break;
+      default:
+        fail(String.format("unknow command %s", spsCommand.getName()));
+        break;
+      }
+    }
+  }
+}