Skip to content

Commit

Permalink
add JAB instruction & MOV labels support
Browse files Browse the repository at this point in the history
This commit adds two changes:
- Absolute Jump instruction (JAB). It receives one parameter: either a target or a fixed number.
Contrary to MOV <SRC> PC which effectively jumps to PC+1, JAB jumps __exactly__ to PC.
- MOV is now able to operate on labels, treating them as PC indices corresponding to their location.

These two changes allow for simpler function implementations, see an example function that multiplies input arg by two:

Before this commit:
```
#DEFINE KEYPAD DOWN
#DEFINE STACK UP

BEGIN:
MOV KEYPAD ACC

SAV
MOV PC ACC
ADD 5
MOV ACC STACK
SWP
MOV ACC STACK
JMP MUL2

MOV STACK ACC

JMP BEGIN

MUL2:
MOV STACK ACC
MUL 2
SAV
MOV STACK ACC
SWP
MOV ACC STACK
SWP
SUB PC
JRO ACC
```
After:
```
#DEFINE KEYPAD DOWN
#DEFINE STACK UP

BEGIN:
MOV KEYPAD STACK
MOV MUL2_RET STACK
JMP MUL2

MUL2_RET:
MOV STACK ACC
JMP BEGIN

MUL2:
MOV STACK ACC
SAV
MOV STACK ACC
MUL 2
MOV ACC STACK
SWP
JAB ACC
```
  • Loading branch information
UQuark authored and fnuecke committed Apr 15, 2024
1 parent ea259fd commit e57a1e3
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ private static void parseInstruction(final Matcher matcher, final MachineState s
builder.put(JumpLessThanZeroInstruction.NAME, new LabelInstructionEmitter(JumpLessThanZeroInstruction::new));
builder.put(JumpNotZeroInstruction.NAME, new LabelInstructionEmitter(JumpNotZeroInstruction::new));
builder.put(JumpRelativeInstruction.NAME, new TargetOrImmediateInstructionEmitter(JumpRelativeInstruction::new, JumpRelativeImmediateInstruction::new));
builder.put(JumpAbsoluteInstruction.NAME, new TargetOrImmediateInstructionEmitter(JumpAbsoluteInstruction::new, JumpAbsoluteImmediateInstruction::new));

// Data transfer.
builder.put(MoveInstruction.NAME, new MoveInstructionEmitter());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,21 @@ static Object checkTargetOrNumber(String name, final int lineNumber, final Map<S
}
}
}

static Object checkTargetOrNumberOrLabel(String name, final int lineNumber, final Map<String, String> defines, final int start, final int end) throws ParseException {
name = defines.getOrDefault(name, name);
try {
final Target target = Enum.valueOf(Target.class, name);
if (!Target.VALID_TARGETS.contains(target)) {
throw new ParseException(Strings.MESSAGE_PARAMETER_INVALID, lineNumber, start, end);
}
return target;
} catch (final IllegalArgumentException ex) {
try {
return Integer.decode(name).shortValue();
} catch (final NumberFormatException ignored) {
return name;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package li.cil.tis3d.common.module.execution.compiler.instruction;

import li.cil.tis3d.common.module.execution.MachineState;
import li.cil.tis3d.common.module.execution.compiler.ParseException;
import li.cil.tis3d.common.module.execution.compiler.Strings;
import li.cil.tis3d.common.module.execution.compiler.Validator;
import li.cil.tis3d.common.module.execution.instruction.Instruction;
import li.cil.tis3d.common.module.execution.instruction.MoveImmediateInstruction;
import li.cil.tis3d.common.module.execution.instruction.MoveInstruction;
import li.cil.tis3d.common.module.execution.instruction.MoveLabelInstruction;
import li.cil.tis3d.common.module.execution.target.Target;

import java.util.List;
Expand All @@ -14,7 +17,7 @@
public final class MoveInstructionEmitter extends AbstractInstructionEmitter {
@Override
public Instruction compile(final Matcher matcher, final int lineNumber, final Map<String, String> defines, final List<Validator> validators) throws ParseException {
final Object src = checkTargetOrNumber(checkArg(lineNumber, matcher, "arg1", "name"),
final Object src = checkTargetOrNumberOrLabel(checkArg(lineNumber, matcher, "arg1", "name"),
lineNumber, defines, matcher.start("arg1"), matcher.end("arg1"));
final Target dst = checkTarget(checkArg(lineNumber, matcher, "arg2", "arg1"),
lineNumber, defines, matcher.start("arg2"), matcher.end("arg2"));
Expand All @@ -24,8 +27,18 @@ public Instruction compile(final Matcher matcher, final int lineNumber, final Ma
return new MoveInstruction(target, dst);
} else if (src instanceof final Short value) {
return new MoveImmediateInstruction(value, dst);
} else if (src instanceof String) {
final String label = checkArg(lineNumber, matcher, "arg1", "name");
validators.add(state -> validateLabel(state, label, matcher, lineNumber));
return new MoveLabelInstruction(label, dst);
} else {
throw new AssertionError();
}
}

private static void validateLabel(final MachineState state, final String label, final Matcher matcher, final int lineNumber) throws ParseException {
if (!state.labels.containsKey(label)) {
throw new ParseException(Strings.MESSAGE_LABEL_NOT_FOUND, lineNumber, matcher.start("arg1"), matcher.end("arg1"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package li.cil.tis3d.common.module.execution.instruction;

import li.cil.tis3d.common.module.execution.Machine;

public class JumpAbsoluteImmediateInstruction implements Instruction {
private final short pc;

public JumpAbsoluteImmediateInstruction(final short pc) {
this.pc = pc;
}

@Override
public void step(final Machine machine) {
machine.getState().pc = pc;
}

@Override
public String toString() {
return JumpAbsoluteInstruction.NAME + " " + pc;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package li.cil.tis3d.common.module.execution.instruction;

import li.cil.tis3d.common.module.execution.Machine;
import li.cil.tis3d.common.module.execution.target.Target;
import li.cil.tis3d.common.module.execution.target.TargetInterface;

public class JumpAbsoluteInstruction implements Instruction {
public static final String NAME = "JAB";

private final Target source;

public JumpAbsoluteInstruction(final Target source) {
this.source = source;
}

@Override
public void step(final Machine machine) {
final TargetInterface sourceInterface = machine.getInterface(source);

if (!sourceInterface.isReading()) {
sourceInterface.beginRead();
}
if (sourceInterface.canTransfer()) {
machine.getState().pc = sourceInterface.read();
}
}

@Override
public String toString() {
return NAME + " " + source;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package li.cil.tis3d.common.module.execution.instruction;

import li.cil.tis3d.common.module.execution.Machine;
import li.cil.tis3d.common.module.execution.target.Target;
import li.cil.tis3d.common.module.execution.target.TargetInterface;

public class MoveLabelInstruction extends AbstractMoveInstruction {
private final String label;

public MoveLabelInstruction(final String label, final Target destination) {
super(destination);
this.label = label;
}

@Override
public void step(final Machine machine) {
final TargetInterface destinationInterface = machine.getInterface(destination);
int addr = machine.getState().labels.get(label);

if (!destinationInterface.isWriting()) {
if (destinationInterface.beginWrite((short) addr)) {
machine.getState().pc++;
}
}
}

@Override
public String toString() {
return MoveInstruction.NAME + " " + label + " " + destination;
}
}

0 comments on commit e57a1e3

Please sign in to comment.