Adding binary Apple Checker 3.0 code and test.

This commit is contained in:
Rob Greene
2026-01-11 12:38:56 -06:00
parent c254ec94ca
commit f3ea9f659d
7 changed files with 125 additions and 53 deletions
@@ -0,0 +1,12 @@
package org.applecommander.bastools.api.proofreaders;
/**
* Standard interface for proofreaders that evaluate a binary program.
*/
public interface BinaryProofReader {
default void addProgram(String text) {
// TODO
}
/** Parses the line and adds to the current checksums. */
void addBytes(int address, byte... binary);
}
@@ -20,12 +20,12 @@ package org.applecommander.bastools.api.proofreaders;
import org.applecommander.bastools.api.Configuration;
import org.applecommander.bastools.api.model.Program;
public class NibbleAppleChecker implements ApplesoftTokenizedProofReader {
public class NibbleAppleCheckerApplesoft implements ApplesoftTokenizedProofReader {
private final Configuration config;
private int length;
private final Checksum checksum = new Checksum();
private final NibbleAppleCheckerChecksum checksum = new NibbleAppleCheckerChecksum();
public NibbleAppleChecker(Configuration config) {
public NibbleAppleCheckerApplesoft(Configuration config) {
this.config = config;
}
@@ -75,50 +75,4 @@ public class NibbleAppleChecker implements ApplesoftTokenizedProofReader {
public int getChecksumValue() {
return checksum.value();
}
/**
* Compute a single iteration of the checksum. Broken out for testing purposes.
* <pre>
* SUMIT CLC
* EOR CKCD
* ROL A
* ADC CKCD
* ADC #0
* STA CKCD
* </pre>
*/
public static class Checksum implements ProofReaderChecksum {
private int checksum;
@Override
public void reset() {
this.checksum = 0;
}
@Override
public void add(int acc) {
// EOR CKCD
acc ^= checksum;
// ROL A
acc <<= 1;
// ADC CKCD
if (acc >= 0xff) {
checksum++;
acc &= 0xff;
}
acc += checksum;
// ADC #0
if (acc > 0xff) {
acc++;
acc &= 0xff;
}
// STA CKCD
checksum = acc;
}
@Override
public int value() {
return this.checksum;
}
}
}
@@ -0,0 +1,32 @@
package org.applecommander.bastools.api.proofreaders;
public class NibbleAppleCheckerBinary implements BinaryProofReader {
private final String filename;
private int length;
private final NibbleAppleCheckerChecksum checksum = new NibbleAppleCheckerChecksum();
public NibbleAppleCheckerBinary(String filename) {
this.filename = filename;
}
@Override
public void addBytes(int address, byte... binary) {
for (byte b : binary) {
checksum.add(Byte.toUnsignedInt(b));
length++;
}
System.out.printf("On: %s\n", filename);
System.out.println("Type: B");
System.out.println();
System.out.printf("Length: %04X\n", length);
System.out.printf("Checksum: %02X\n", checksum.value());
}
public int getLength() {
return length;
}
public int getChecksumValue() {
return checksum.value();
}
}
@@ -0,0 +1,47 @@
package org.applecommander.bastools.api.proofreaders;
/**
* Compute a single iteration of the checksum. Broken out for testing purposes.
* <pre>
* SUMIT CLC
* EOR CKCD
* ROL A
* ADC CKCD
* ADC #0
* STA CKCD
* </pre>
*/
public class NibbleAppleCheckerChecksum implements ProofReaderChecksum {
private int checksum;
@Override
public void reset() {
this.checksum = 0;
}
@Override
public void add(int acc) {
// EOR CKCD
acc ^= checksum;
// ROL A
acc <<= 1;
// ADC CKCD
if (acc >= 0xff) {
checksum++;
acc &= 0xff;
}
acc += checksum;
// ADC #0
if (acc > 0xff) {
acc++;
acc &= 0xff;
}
// STA CKCD
checksum = acc;
}
@Override
public int value() {
return this.checksum;
}
}
@@ -24,11 +24,11 @@ import java.io.File;
import static org.junit.Assert.assertEquals;
public class NibbleAppleCheckerTest {
public class NibbleAppleCheckerApplesoftTest {
@Test
public void testChecksum() {
// Based on 6502 assembly run - checks step-by-step values
NibbleAppleChecker.Checksum checksum = new NibbleAppleChecker.Checksum();
NibbleAppleCheckerChecksum checksum = new NibbleAppleCheckerChecksum();
checksum.add(0x89); // TEXT
assertEquals(0x13, checksum.value());
checksum.add(0x3a); // :
@@ -43,7 +43,7 @@ public class NibbleAppleCheckerTest {
.startAddress(0xb01)
.sourceFile(new File("test.bas"))
.build();
NibbleAppleChecker checker = new NibbleAppleChecker(config);
NibbleAppleCheckerApplesoft checker = new NibbleAppleCheckerApplesoft(config);
// 10 TEXT:HOME as a sample...
byte[] code = { 0x09, 0x0b, 0x0a, (byte)0x89, 0x3a, (byte)0x97, 0x00, 0x00, 0x00, 0x00, 0x00 };
checker.addBytes(code);
@@ -0,0 +1,27 @@
package org.applecommander.bastools.api.proofreaders;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class NibbleAppleCheckerBinaryTest {
@Test
public void testBinary() {
runTest(0x300, 0x7a,
0xa9, 0x01, 0x8d, 0x00, 0x0a, 0xad, 0x00, 0x0a, // 0300-
0x20, 0xa8, 0xfc, 0x20, 0xe4, 0xfb, 0x4c, 0x05, // 0308-
0x03); // 0310-
}
public void runTest(int address, int expectedChecksum, int... bytes) {
byte[] code = new byte[bytes.length];
for (int i=0; i<bytes.length; i++) {
code[i] = (byte) bytes[i];
}
NibbleAppleCheckerBinary proofreader = new NibbleAppleCheckerBinary("test.bin");
proofreader.addBytes(address, code);
assertEquals(bytes.length, proofreader.getLength());
assertEquals(expectedChecksum, proofreader.getChecksumValue());
}
}
@@ -368,7 +368,7 @@ public class Main implements Callable<Integer> {
@Option(names = "--apple-checker", description = "Apply Nibble Apple Checker 3.0 (ca 1982) to code")
public void selectNibbleAppleChecker(boolean flag) {
this.proofReaderFn = (c,p) -> {
NibbleAppleChecker proofreader = new NibbleAppleChecker(c);
NibbleAppleCheckerApplesoft proofreader = new NibbleAppleCheckerApplesoft(c);
proofreader.addProgram(p);
};
}