Jelajahi Sumber

implementation of holtek finnished.

Klaas, Wilfried 6 tahun lalu
induk
melakukan
33cf144197

+ 5 - 1
src/main/java/de/mcs/tools/sps/EmulatorInput.java

@@ -8,8 +8,12 @@ public interface EmulatorInput {
 
   void reset();
 
-  void setFeature(String name, byte register);
+  void setFeature(String name, byte value);
 
   byte getFeature(String name);
 
+  void setFeature(String name, boolean value);
+
+  boolean getFeatureAsBool(String name);
+
 }

+ 5 - 0
src/main/java/de/mcs/tools/sps/EmulatorInternals.java

@@ -25,4 +25,9 @@ public interface EmulatorInternals {
 
   byte getRegister(String register);
 
+  void setAddress(int i);
+
+  void pushRtrAddress();
+
+  void popRtrAddress();
 }

+ 95 - 79
src/main/java/de/mcs/tools/sps/holtek/HoltekEmulator.java

@@ -32,7 +32,7 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     commands.add(SPS_A_INPUT);
     commands.add(SPS_A_CALCULATE);
     commands.add(SPS_PAGE);
-    commands.add(SPS_JUMP_UP);
+    commands.add(SPS_JUMP);
     commands.add(SPS_C_LOOP);
     commands.add(SPS_D_LOOP);
     commands.add(SPS_SKIP_IF);
@@ -424,11 +424,11 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     }
   }
 
-  private static SPSCommand SPS_JUMP_UP = new SPSCommandImpl().setName("Jump").setMnemonic("JMP")
+  private static SPSCommand SPS_JUMP = new SPSCommandImpl().setName("Jump").setMnemonic("JMP")
       .setCommandByte((byte) 0x90);
   static {
     for (int i = 0; i < 16; i++) {
-      SPS_JUMP_UP.getCommandDatas().add(new SPSCommandDataImpl() {
+      SPS_JUMP.getCommandDatas().add(new SPSCommandDataImpl() {
         @Override
         public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
           ((HoltekEmulatorInternals) internals).address = getData()
@@ -436,7 +436,7 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
           return output;
         }
       }.setName("Jump " + Integer.toString(i)).setMnemonic("JMP" + Integer.toString(i))
-          .setCommandByte((byte) (SPS_JUMP_UP.getCommandByte() + i)).setCommand(SPS_JUMP_UP));
+          .setCommandByte((byte) (SPS_JUMP.getCommandByte() + i)).setCommand(SPS_JUMP));
     }
   }
 
@@ -447,7 +447,16 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
       SPS_C_LOOP.getCommandDatas().add(new SPSCommandDataImpl() {
         @Override
         public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-          ((HoltekEmulatorInternals) internals).address++;
+          byte c = internals.getRegister(HoltekEmulatorInternals.REGISTER_C);
+          if (c > 0) {
+            c -= 1;
+            c = (byte) (c & 0x0F);
+            internals.setRegister(HoltekEmulatorInternals.REGISTER_C, c);
+            ((HoltekEmulatorInternals) internals).address = getData()
+                + (internals.getRegister(HoltekEmulatorInternals.REGISTER_PAGE) * 16);
+          } else {
+            internals.incAddress(1);
+          }
           return output;
         }
       }.setName("C* Loop " + Integer.toString(i)).setMnemonic("CLOP" + Integer.toString(i))
@@ -462,7 +471,16 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
       SPS_D_LOOP.getCommandDatas().add(new SPSCommandDataImpl() {
         @Override
         public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-          ((HoltekEmulatorInternals) internals).address++;
+          byte d = internals.getRegister(HoltekEmulatorInternals.REGISTER_D);
+          if (d > 0) {
+            d -= 1;
+            d = (byte) (d & 0x0F);
+            internals.setRegister(HoltekEmulatorInternals.REGISTER_D, d);
+            ((HoltekEmulatorInternals) internals).address = getData()
+                + (internals.getRegister(HoltekEmulatorInternals.REGISTER_PAGE) * 16);
+          } else {
+            internals.incAddress(1);
+          }
           return output;
         }
       }.setName("D* Loop " + Integer.toString(i)).setMnemonic("DLOP" + Integer.toString(i))
@@ -476,7 +494,12 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        byte a = internals.getRegister(HoltekEmulatorInternals.REGISTER_A);
+        byte b = internals.getRegister(HoltekEmulatorInternals.REGISTER_B);
+        if (a > b) {
+          internals.incAddress(1);
+        }
+        internals.incAddress(1);
         return output;
       }
     }.setName("A>B").setMnemonic("AGRB").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x01))
@@ -484,7 +507,12 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        byte a = internals.getRegister(HoltekEmulatorInternals.REGISTER_A);
+        byte b = internals.getRegister(HoltekEmulatorInternals.REGISTER_B);
+        if (a < b) {
+          internals.incAddress(1);
+        }
+        internals.incAddress(1);
         return output;
       }
     }.setName("A<B").setMnemonic("ASMB").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x02))
@@ -492,79 +520,56 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        byte a = internals.getRegister(HoltekEmulatorInternals.REGISTER_A);
+        byte b = internals.getRegister(HoltekEmulatorInternals.REGISTER_B);
+        if (a == b) {
+          internals.incAddress(1);
+        }
+        internals.incAddress(1);
         return output;
       }
     }.setName("A=B").setMnemonic("AEQB").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x03))
         .setCommand(SPS_SKIP_IF));
+
+    for (int i = 0; i < 4; i++) {
+      SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
+        @Override
+        public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
+          byte in = input.getInput();
+          byte data = (byte) (getData() - 0x04);
+          if ((in & (0x01 << data)) > 0) {
+            internals.incAddress(1);
+          }
+          internals.incAddress(1);
+          return output;
+        }
+      }.setName(String.format("In.%d=1", i + 1)).setMnemonic(String.format("IN%d1", i + 1))
+          .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x04 + i)).setCommand(SPS_SKIP_IF));
+    }
+
+    for (int i = 0; i < 4; i++) {
+      SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
+        @Override
+        public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
+          byte in = input.getInput();
+          byte data = (byte) (getData() - 0x08);
+          if ((in & (0x01 << data)) == 0) {
+            internals.incAddress(1);
+          }
+          internals.incAddress(1);
+          return output;
+        }
+      }.setName(String.format("In.%d=0", i + 1)).setMnemonic(String.format("IN%d0", i + 1))
+          .setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x08 + i)).setCommand(SPS_SKIP_IF));
+    }
+
     SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.1=1").setMnemonic("IN11").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x04))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.2=1").setMnemonic("IN21").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x05))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.3=1").setMnemonic("IN31").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x06))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.4=1").setMnemonic("IN41").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x07))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.1=0").setMnemonic("IN10").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x08))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.2=0").setMnemonic("IN20").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x09))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.3=0").setMnemonic("IN30").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0A))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
-        return output;
-      }
-    }.setName("In.4=0").setMnemonic("IN40").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0B))
-        .setCommand(SPS_SKIP_IF));
-    SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
-      @Override
-      public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        if (!input.getFeatureAsBool(HoltekEmulatorInput.S1)) {
+          internals.incAddress(1);
+        }
+        internals.incAddress(1);
         return output;
       }
     }.setName("S1=0").setMnemonic("S10").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0C))
@@ -572,7 +577,10 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        if (!input.getFeatureAsBool(HoltekEmulatorInput.S2)) {
+          internals.incAddress(1);
+        }
+        internals.incAddress(1);
         return output;
       }
     }.setName("S2=0").setMnemonic("S20").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0D))
@@ -580,7 +588,10 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        if (input.getFeatureAsBool(HoltekEmulatorInput.S1)) {
+          internals.incAddress(1);
+        }
+        internals.incAddress(1);
         return output;
       }
     }.setName("S1=1").setMnemonic("S11").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0E))
@@ -588,7 +599,10 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     SPS_SKIP_IF.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        if (input.getFeatureAsBool(HoltekEmulatorInput.S2)) {
+          internals.incAddress(1);
+        }
+        internals.incAddress(1);
         return output;
       }
     }.setName("S2=1").setMnemonic("S21").setCommandByte((byte) (SPS_SKIP_IF.getCommandByte() + 0x0F))
@@ -602,7 +616,9 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
       SPS_CALL.getCommandDatas().add(new SPSCommandDataImpl() {
         @Override
         public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-          ((HoltekEmulatorInternals) internals).address++;
+          internals.pushRtrAddress();
+          ((HoltekEmulatorInternals) internals).address = getData()
+              + (internals.getRegister(HoltekEmulatorInternals.REGISTER_PAGE) * 16);
           return output;
         }
       }.setName("Call " + Integer.toString(i)).setMnemonic("CALL" + Integer.toString(i))
@@ -617,7 +633,7 @@ public class HoltekEmulator extends AbstractEmulator implements SPSEmulator {
     SPS_RETURN.getCommandDatas().add(new SPSCommandDataImpl() {
       @Override
       public EmulatorOutput doWork(EmulatorInput input, EmulatorInternals internals, EmulatorOutput output) {
-        ((HoltekEmulatorInternals) internals).address++;
+        internals.popRtrAddress();
         return output;
       }
     }.setName("Return").setMnemonic("RET").setCommandByte((byte) (SPS_RETURN.getCommandByte())).setCommand(SPS_RETURN));

+ 56 - 5
src/main/java/de/mcs/tools/sps/holtek/HoltekEmulatorInput.java

@@ -11,7 +11,11 @@ import de.mcs.tools.sps.EmulatorInput;
  */
 public class HoltekEmulatorInput implements EmulatorInput {
 
-  boolean i0, i1, i2, i3;
+  public static final String AD1 = "AD1";
+  public static final String AD2 = "AD2";
+  public static final String S1 = "S1";
+  public static final String S2 = "S2";
+  boolean i0, i1, i2, i3, s1, s2;
   int ad1, ad2;
 
   @Override
@@ -20,6 +24,8 @@ public class HoltekEmulatorInput implements EmulatorInput {
     i1 = false;
     i2 = false;
     i3 = false;
+    s1 = false;
+    s2 = false;
     ad1 = 0;
     ad2 = 0;
   }
@@ -38,23 +44,68 @@ public class HoltekEmulatorInput implements EmulatorInput {
 
   @Override
   public void setFeature(String name, byte value) {
-    if ("AD1".equals(name.toUpperCase())) {
+    if (AD1.equals(name.toUpperCase())) {
       ad1 = value;
     }
-    if ("AD2".equals(name.toUpperCase())) {
+    if (AD2.equals(name.toUpperCase())) {
       ad2 = value;
     }
+    if (S1.equals(name.toUpperCase())) {
+      s1 = value > 0;
+    }
+    if (S2.equals(name.toUpperCase())) {
+      s2 = value > 0;
+    }
+  }
+
+  @Override
+  public void setFeature(String name, boolean value) {
+    if (AD1.equals(name.toUpperCase())) {
+      ad1 = value ? 1 : 0;
+    }
+    if (AD2.equals(name.toUpperCase())) {
+      ad2 = value ? 1 : 0;
+    }
+    if (S1.equals(name.toUpperCase())) {
+      s1 = value;
+    }
+    if (S2.equals(name.toUpperCase())) {
+      s2 = value;
+    }
   }
 
   @Override
   public byte getFeature(String name) {
-    if ("AD1".equals(name.toUpperCase())) {
+    if (AD1.equals(name.toUpperCase())) {
+      return (byte) ad1;
+    }
+    if (AD2.equals(name.toUpperCase())) {
+      return (byte) ad2;
+    }
+    if (S1.equals(name.toUpperCase())) {
       return (byte) ad1;
     }
-    if ("AD2".equals(name.toUpperCase())) {
+    if (S2.equals(name.toUpperCase())) {
       return (byte) ad2;
     }
     return 0;
   }
 
+  @Override
+  public boolean getFeatureAsBool(String name) {
+    if (AD1.equals(name.toUpperCase())) {
+      return (byte) ad1 > 0;
+    }
+    if (AD2.equals(name.toUpperCase())) {
+      return (byte) ad2 > 0;
+    }
+    if (S1.equals(name.toUpperCase())) {
+      return s1;
+    }
+    if (S2.equals(name.toUpperCase())) {
+      return s2;
+    }
+    return false;
+  }
+
 }

+ 16 - 0
src/main/java/de/mcs/tools/sps/holtek/HoltekEmulatorInternals.java

@@ -19,6 +19,7 @@ public class HoltekEmulatorInternals implements EmulatorInternals {
   int a, b, c, d;
   int page;
   long delay;
+  int rtrAddress;
 
   @Override
   public void reset() {
@@ -40,6 +41,11 @@ public class HoltekEmulatorInternals implements EmulatorInternals {
     address += i;
   }
 
+  @Override
+  public void setAddress(int i) {
+    address = i;
+  }
+
   @Override
   public void setDelay(long l) {
     delay = l;
@@ -88,4 +94,14 @@ public class HoltekEmulatorInternals implements EmulatorInternals {
     }
     return 0;
   }
+
+  @Override
+  public void pushRtrAddress() {
+    rtrAddress = address;
+  }
+
+  @Override
+  public void popRtrAddress() {
+    address = rtrAddress;
+  }
 }

+ 233 - 0
src/test/java/de/mcs/tools/sps/holtek/TestHoltekCommands.java

@@ -308,4 +308,237 @@ public class TestHoltekCommands {
       }
     }
   }
+
+  // C LOOP #
+  @Test
+  public void testCLoop() {
+    for (int page = 0; page < 16; page++) {
+      SPSCommandData data = getCommandData((byte) (0x80 + page));
+      if (page < 0x08) {
+        assertNotNull(data);
+        internals.reset();
+        data.doWork(input, internals, output);
+        assertEquals(page, internals.getRegister(HoltekEmulatorInternals.REGISTER_PAGE));
+        for (int x = 0; x < 16; x++) {
+          internals.setRegister(HoltekEmulatorInternals.REGISTER_C, (byte) 4);
+          data = getCommandData((byte) (0xA0 + x));
+          data.doWork(input, internals, output);
+          assertEquals((x + 16 * page), internals.getAddress());
+
+          internals.setAddress(0);
+          internals.setRegister(HoltekEmulatorInternals.REGISTER_C, (byte) 0);
+          data.doWork(input, internals, output);
+          assertEquals(0x01, internals.getAddress());
+        }
+      } else {
+        assertNull(data);
+      }
+    }
+  }
+
+  // D LOOP #
+  @Test
+  public void testDLoop() {
+    for (int page = 0; page < 16; page++) {
+      SPSCommandData data = getCommandData((byte) (0x80 + page));
+      if (page < 0x08) {
+        assertNotNull(data);
+        internals.reset();
+        data.doWork(input, internals, output);
+        assertEquals(page, internals.getRegister(HoltekEmulatorInternals.REGISTER_PAGE));
+        for (int x = 0; x < 16; x++) {
+          internals.setRegister(HoltekEmulatorInternals.REGISTER_D, (byte) 4);
+          data = getCommandData((byte) (0xB0 + x));
+          data.doWork(input, internals, output);
+          assertEquals((x + 16 * page), internals.getAddress());
+
+          internals.setAddress(0);
+          internals.setRegister(HoltekEmulatorInternals.REGISTER_D, (byte) 0);
+          data.doWork(input, internals, output);
+          assertEquals(0x01, internals.getAddress());
+        }
+      } else {
+        assertNull(data);
+      }
+    }
+  }
+
+  // SKIP IF A > B
+  @Test
+  public void testSkipIfAgtB() {
+    SPSCommandData data = getCommandData((byte) 0xC1);
+    assertNotNull(data);
+    internals.reset();
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_A, (byte) 0x03);
+
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_B, (byte) 0x04);
+    internals.setAddress(1);
+    data.doWork(input, internals, output);
+    assertEquals(2, internals.getAddress());
+
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_B, (byte) 0x02);
+    internals.setAddress(1);
+    data.doWork(input, internals, output);
+    assertEquals(3, internals.getAddress());
+  }
+
+  // SKIP IF A < B
+  @Test
+  public void testSkipIfAltB() {
+    SPSCommandData data = getCommandData((byte) 0xC2);
+    assertNotNull(data);
+    internals.reset();
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_A, (byte) 0x03);
+
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_B, (byte) 0x02);
+    internals.setAddress(1);
+    data.doWork(input, internals, output);
+    assertEquals(2, internals.getAddress());
+
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_B, (byte) 0x04);
+    internals.setAddress(1);
+    data.doWork(input, internals, output);
+    assertEquals(3, internals.getAddress());
+  }
+
+  // SKIP IF A = B
+  @Test
+  public void testSkipIfAeqB() {
+    SPSCommandData data = getCommandData((byte) 0xC3);
+    assertNotNull(data);
+    internals.reset();
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_A, (byte) 0x03);
+
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_B, (byte) 0x02);
+    internals.setAddress(1);
+    data.doWork(input, internals, output);
+    assertEquals(2, internals.getAddress());
+
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_B, (byte) 0x04);
+    internals.setAddress(1);
+    data.doWork(input, internals, output);
+    assertEquals(2, internals.getAddress());
+
+    internals.setRegister(HoltekEmulatorInternals.REGISTER_B, (byte) 0x03);
+    internals.setAddress(1);
+    data.doWork(input, internals, output);
+    assertEquals(3, internals.getAddress());
+  }
+
+  // SKIP IF Input = 1
+  @Test
+  public void testSkipIfIn1() {
+    for (int i = 0; i < 4; i++) {
+      SPSCommandData data = getCommandData((byte) (0xC4 + i));
+      assertNotNull(data);
+      internals.reset();
+      internals.setAddress(1);
+      input.setInput((byte) 0x00);
+      data.doWork(input, internals, output);
+      assertEquals(2, internals.getAddress());
+
+      internals.setAddress(1);
+      input.setInput((byte) (0x01 << i));
+      data.doWork(input, internals, output);
+      assertEquals(3, internals.getAddress());
+    }
+  }
+
+  // SKIP IF Input = 0
+  @Test
+  public void testSkipIfIn0() {
+    for (int i = 0; i < 4; i++) {
+      SPSCommandData data = getCommandData((byte) (0xC8 + i));
+      assertNotNull(data);
+      internals.reset();
+      internals.setAddress(1);
+      input.setInput((byte) 0x00);
+      data.doWork(input, internals, output);
+      assertEquals(3, internals.getAddress());
+
+      internals.setAddress(1);
+      input.setInput((byte) (0x01 << i));
+      data.doWork(input, internals, output);
+      assertEquals(2, internals.getAddress());
+    }
+  }
+
+  // SKIP IF S1, S2
+  @Test
+  public void testSkipIfS12() {
+    for (int i = 0; i < 4; i++) {
+      SPSCommandData data = getCommandData((byte) (0xCC));
+      assertNotNull(data);
+      internals.reset();
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S1, false);
+      data.doWork(input, internals, output);
+      assertEquals(3, internals.getAddress());
+
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S1, true);
+      data.doWork(input, internals, output);
+      assertEquals(2, internals.getAddress());
+
+      data = getCommandData((byte) (0xCD));
+      assertNotNull(data);
+      internals.reset();
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S2, false);
+      data.doWork(input, internals, output);
+      assertEquals(3, internals.getAddress());
+
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S2, true);
+      data.doWork(input, internals, output);
+      assertEquals(2, internals.getAddress());
+
+      data = getCommandData((byte) (0xCE));
+      assertNotNull(data);
+      internals.reset();
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S1, true);
+      data.doWork(input, internals, output);
+      assertEquals(3, internals.getAddress());
+
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S1, false);
+      data.doWork(input, internals, output);
+      assertEquals(2, internals.getAddress());
+
+      data = getCommandData((byte) (0xCF));
+      assertNotNull(data);
+      internals.reset();
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S2, true);
+      data.doWork(input, internals, output);
+      assertEquals(3, internals.getAddress());
+
+      internals.setAddress(1);
+      input.setFeature(HoltekEmulatorInput.S2, false);
+      data.doWork(input, internals, output);
+      assertEquals(2, internals.getAddress());
+    }
+  }
+
+  // Call & Return
+  @Test
+  public void testCallReturn() {
+    for (int i = 0; i < 16; i++) {
+      SPSCommandData data = getCommandData((byte) (0xD0 + i));
+      assertNotNull(data);
+      internals.reset();
+      internals.setAddress(i);
+      internals.setRegister(HoltekEmulatorInternals.REGISTER_PAGE, (byte) i);
+
+      data.doWork(input, internals, output);
+      assertEquals(i + 16 * i, internals.getAddress());
+      assertEquals(i, ((HoltekEmulatorInternals) internals).rtrAddress);
+
+      data = getCommandData((byte) 0xE0);
+      assertNotNull(data);
+      data.doWork(input, internals, output);
+      assertEquals(i, internals.getAddress());
+    }
+  }
 }