package org.reasm.m68k.assembly.internal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.reasm.AssemblyMessage;
import org.reasm.m68k.ConfigurationOptions;
import org.reasm.m68k.M68KArchitecture;
import org.reasm.m68k.messages.InvalidExpressionErrorMessage;
import org.reasm.m68k.messages.MinusOneDistanceShortBranchErrorMessage;
import org.reasm.m68k.messages.ZeroDistanceShortBranchErrorMessage;
/**
* Test class for the {@link ConfigurationOptions#OPTIMIZE_UNSIZED_BRANCHES} configuration option.
*
* @author Francis Gagné
*/
@RunWith(Parameterized.class)
public class OptimizeUnsizedBranchesTest extends BaseInstructionsTest {
@Nonnull
private static final List<Object[]> TEST_DATA = new ArrayList<>();
static {
// BRA
addDataItem(" BRA", NO_DATA, WRONG_NUMBER_OF_OPERANDS);
addDataItem(" BRA UNDEFINED", new short[] { 0x60FE }, UNDEFINED_SYMBOL);
addDataItem(" BRA 0", new short[] { 0x60FE });
addDataItem(" BRA 0-", new short[] { 0x60FE }, new InvalidExpressionErrorMessage("0-"));
addDataItem(" BRA 0a", new short[] { 0x60FE }, new InvalidExpressionErrorMessage("0a"));
addDataItem(" BRA 1", new short[] { 0x6000, -1 });
addDataItem(" BRA 1", new short[] { 0x6000, -1 }, M68KArchitecture.MC68020);
addDataItem(" BRA 2", new short[] { 0x6000, 0x0000 });
addDataItem(" BRA $8000", new short[] { 0x6000, 0x7FFE });
addDataItem(" BRA $8002", new short[] { 0x6000, -0x8000 }, RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_WORD_HIGH);
addDataItem(" BRA $8002", new short[] { 0x60FF, 0, -0x8000 }, M68KArchitecture.MC68020);
addDataItem(" BRA -$8000", new short[] { 0x6000, 0x7FFE }, RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_WORD_LOW);
addDataItem(" BRA -$8000", new short[] { 0x60FF, -1, 0x7FFE }, M68KArchitecture.MC68020);
addDataItem(" BRA -$7FFE", new short[] { 0x6000, -0x8000 });
addDataItem(" BRA -$7FFC", new short[] { 0x6000, -0x7FFE });
addDataItem(" BRA $80000002", new short[] { 0x60FF, -0x8000, 0 }, M68KArchitecture.MC68020,
RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_LONG_HIGH);
addDataItem(" BRA -$80000000", new short[] { 0x60FF, 0x7FFF, -2 }, M68KArchitecture.MC68020,
RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_LONG_LOW);
addDataItem("HANG: BRA HANG", new short[] { 0x60FE });
addDataItem(" BRA 0.5", new short[] { 0x60FE }, LABEL_EXPECTED);
addDataItem(" BRA 'ab'", new short[] { 0x60FE }, LABEL_EXPECTED);
// TODO: test with a built-in function symbol
//addDataItem(" BRA STRLEN", new short[] { 0x60FE }, LABEL_EXPECTED);
addDataItem(" BRA. 0", new short[] { 0x60FE }, INVALID_SIZE_ATTRIBUTE_EMPTY);
addDataItem(" BRA.B 0", new short[] { 0x60FE });
addDataItem(" BRA.B 1", new short[] { 0x60FF });
addDataItem(" BRA.B 1", new short[] { 0x60FE }, M68KArchitecture.MC68020, new MinusOneDistanceShortBranchErrorMessage());
addDataItem(" BRA.B 2", new short[] { 0x60FE }, new ZeroDistanceShortBranchErrorMessage());
addDataItem(" BRA.B 128", new short[] { 0x607E });
addDataItem(" BRA.B 130", new short[] { 0x6080 }, RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_BYTE_HIGH);
addDataItem(" BRA.B -128", new short[] { 0x607E }, RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_BYTE_LOW);
addDataItem(" BRA.B -126", new short[] { 0x6080 });
addDataItem(" BRA.S 0", new short[] { 0x60FE });
addDataItem(" BRA.W 0", new short[] { 0x6000, -2 });
addDataItem(" BRA.W 1", new short[] { 0x6000, -1 });
addDataItem(" BRA.W 1", new short[] { 0x6000, -1 }, M68KArchitecture.MC68020);
addDataItem(" BRA.W 2", new short[] { 0x6000, 0 });
addDataItem(" BRA.W $8000", new short[] { 0x6000, 0x7FFE });
addDataItem(" BRA.W $8002", new short[] { 0x6000, -0x8000 }, RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_WORD_HIGH);
addDataItem(" BRA.W -$8000", new short[] { 0x6000, 0x7FFE }, RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_WORD_LOW);
addDataItem(" BRA.W -$7FFE", new short[] { 0x6000, -0x8000 });
addDataItem(" BRA.L 0", new short[] { 0x60FF, -1, -2 }, NOT_SUPPORTED_ON_ARCHITECTURE);
addDataItem(" BRA.L 0", new short[] { 0x60FF, -1, -2 }, M68KArchitecture.MC68020);
addDataItem(" BRA.L 1", new short[] { 0x60FF, -1, -1 }, M68KArchitecture.MC68020);
addDataItem(" BRA.L 2", new short[] { 0x60FF, 0, 0 }, M68KArchitecture.MC68020);
addDataItem(" BRA.L $80000000", new short[] { 0x60FF, 0x7FFF, -2 }, M68KArchitecture.MC68020);
addDataItem(" BRA.L $80000002", new short[] { 0x60FF, -0x8000, 0 }, M68KArchitecture.MC68020,
RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_LONG_HIGH);
addDataItem(" BRA.L -$80000000", new short[] { 0x60FF, 0x7FFF, -2 }, M68KArchitecture.MC68020,
RELATIVE_BRANCH_TARGET_OUT_OF_RANGE_LONG_LOW);
addDataItem(" BRA.L -$7FFFFFFE", new short[] { 0x60FF, -0x8000, 0 }, M68KArchitecture.MC68020);
addDataItem(" BRA.Z 0", new short[] { 0x60FE }, INVALID_SIZE_ATTRIBUTE_Z);
// --> see also InstructionsTest for tests with the "optimize unsized branches" option disabled
}
/**
* Gets the test data for this parameterized test.
*
* @return the test data
*/
@Nonnull
@Parameters
public static List<Object[]> data() {
return TEST_DATA;
}
private static void addDataItem(@Nonnull String code, @Nonnull short[] output) {
addDataItem(code, output, M68KArchitecture.MC68000, (AssemblyMessage) null);
}
private static void addDataItem(@Nonnull String code, @Nonnull short[] output, @CheckForNull AssemblyMessage expectedMessage) {
addDataItem(code, output, M68KArchitecture.MC68000, expectedMessage);
}
private static void addDataItem(@Nonnull String code, @Nonnull short[] output, @Nonnull M68KArchitecture architecture) {
addDataItem(code, output, architecture, (AssemblyMessage) null);
}
private static void addDataItem(@Nonnull String code, @Nonnull short[] output, @Nonnull M68KArchitecture architecture,
@CheckForNull AssemblyMessage expectedMessage) {
TEST_DATA.add(new Object[] { code, output, architecture, expectedMessage });
}
/**
* Initializes a new OptimizeUnsizedBranchesTest.
*
* @param code
* a line of code containing an instruction
* @param output
* the generated opcode for the instruction
* @param architecture
* the target architecture
* @param expectedMessage
* an {@link AssemblyMessage} that is expected to be generated while assembling the line of code
*/
public OptimizeUnsizedBranchesTest(@Nonnull String code, @Nonnull short[] output, @Nonnull M68KArchitecture architecture,
@CheckForNull AssemblyMessage expectedMessage) {
super(code, output, architecture, expectedMessage, null);
}
@Nonnull
@Override
protected Map<String, Object> getM68KConfigurationOptions() {
final HashMap<String, Object> m68kOptions = new HashMap<>();
m68kOptions.put(ConfigurationOptions.OPTIMIZE_UNSIZED_BRANCHES, true);
return m68kOptions;
}
}