1d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen/* 2d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Copyright (C) 2016 The Android Open Source Project 3d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 4d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Licensed under the Apache License, Version 2.0 (the "License"); 5d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * you may not use this file except in compliance with the License. 6d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * You may obtain a copy of the License at 7d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 8d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * http://www.apache.org/licenses/LICENSE-2.0 9d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 10d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Unless required by applicable law or agreed to in writing, software 11d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * distributed under the License is distributed on an "AS IS" BASIS, 12d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * See the License for the specific language governing permissions and 14d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * limitations under the License. 15d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 16d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 17d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenpackage android.net.apf; 18d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 19d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenimport java.util.ArrayList; 20d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenimport java.util.HashMap; 21d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 22d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen/** 23d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * APF assembler/generator. A tool for generating an APF program. 24d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 25d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Call add*() functions to add instructions to the program, then call 26d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@link generate} to get the APF bytecode for the program. 27d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 28d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @hide 29d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 30d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensenpublic class ApfGenerator { 31d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 32d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * This exception is thrown when an attempt is made to generate an illegal instruction. 33d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 34d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static class IllegalInstructionException extends Exception { 35d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen IllegalInstructionException(String msg) { 36d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen super(msg); 37d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 38d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 39d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private enum Opcodes { 40d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LABEL(-1), 41d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDB(1), // Load 1 byte from immediate offset, e.g. "ldb R0, [5]" 42d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDH(2), // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]" 43d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDW(3), // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]" 44d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDBX(4), // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5]R0" 45d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDHX(5), // Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5]R0" 46d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDWX(6), // Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5]R0" 47d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen ADD(7), // Add, e.g. "add R0,5" 48d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen MUL(8), // Multiply, e.g. "mul R0,5" 49d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen DIV(9), // Divide, e.g. "div R0,5" 50d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen AND(10), // And, e.g. "and R0,5" 51d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen OR(11), // Or, e.g. "or R0,5" 52d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen SH(12), // Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right) 53d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LI(13), // Load immediate, e.g. "li R0,5" (immediate encoded as signed value) 54d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JMP(14), // Jump, e.g. "jmp label" 55d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JEQ(15), // Compare equal and branch, e.g. "jeq R0,5,label" 56d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JNE(16), // Compare not equal and branch, e.g. "jne R0,5,label" 57d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JGT(17), // Compare greater than and branch, e.g. "jgt R0,5,label" 58d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JLT(18), // Compare less than and branch, e.g. "jlt R0,5,label" 59d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JSET(19), // Compare any bits set and branch, e.g. "jset R0,5,label" 60d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen JNEBS(20), // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455" 61408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti EXT(21), // Followed by immediate indicating ExtendedOpcodes. 62408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti LDDW(22), // Load 4 bytes from data memory address (register + immediate): "lddw R0, [5]R1" 63408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti STDW(23); // Store 4 bytes to data memory address (register + immediate): "stdw R0, [5]R1" 64d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 65d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int value; 66d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 67d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private Opcodes(int value) { 68d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this.value = value; 69d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 70d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 71d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Extended opcodes. Primary opcode is Opcodes.EXT. ExtendedOpcodes are encoded in the immediate 72d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // field. 73d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private enum ExtendedOpcodes { 74d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen LDM(0), // Load from memory, e.g. "ldm R0,5" 75d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen STM(16), // Store to memory, e.g. "stm R0,5" 76d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen NOT(32), // Not, e.g. "not R0" 77d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen NEG(33), // Negate, e.g. "neg R0" 78d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen SWAP(34), // Swap, e.g. "swap R0,R1" 79d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen MOVE(35); // Move, e.g. "move R0,R1" 80d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 81d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int value; 82d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 83d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private ExtendedOpcodes(int value) { 84d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this.value = value; 85d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 86d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 87d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public enum Register { 88d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen R0(0), 89d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen R1(1); 90d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 91d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int value; 92d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 93d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private Register(int value) { 94d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this.value = value; 95d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 96d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 97d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private class Instruction { 98d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final byte mOpcode; // A "Opcode" value. 99d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final byte mRegister; // A "Register" value. 100d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private boolean mHasImm; 101d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte mImmSize; 102d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private boolean mImmSigned; 103d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int mImm; 104d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // When mOpcode is a jump: 105d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte mTargetLabelSize; 106d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private String mTargetLabel; 107d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // When mOpcode == Opcodes.LABEL: 108d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private String mLabel; 109d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // When mOpcode == Opcodes.JNEBS: 110d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte[] mCompareBytes; 111d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}. 112d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int offset; 113d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 114d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction(Opcodes opcode, Register register) { 115d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mOpcode = (byte)opcode.value; 116d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mRegister = (byte)register.value; 117d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 118d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 119d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction(Opcodes opcode) { 120d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen this(opcode, Register.R0); 121d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 122d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 123d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setImm(int imm, boolean signed) { 124d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mHasImm = true; 125d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mImm = imm; 126d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mImmSigned = signed; 127d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mImmSize = calculateImmSize(imm, signed); 128d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 129d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 130d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setUnsignedImm(int imm) { 131d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen setImm(imm, false); 132d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 133d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 134d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setSignedImm(int imm) { 135d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen setImm(imm, true); 136d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 137d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 138d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setLabel(String label) throws IllegalInstructionException { 139d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mLabels.containsKey(label)) { 140d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("duplicate label " + label); 141d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 142d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode != Opcodes.LABEL.value) { 143d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("adding label to non-label instruction"); 144d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 145d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mLabel = label; 146d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mLabels.put(label, this); 147d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 148d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 149d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setTargetLabel(String label) { 150d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabel = label; 151d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabelSize = 4; // May shrink later on in generate(). 152d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 153d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 154d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void setCompareBytes(byte[] bytes) { 155d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode != Opcodes.JNEBS.value) { 156d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("adding compare bytes to non-JNEBS instruction"); 157d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 158d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mCompareBytes = bytes; 159d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 160d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 161d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 162d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return size of instruction in bytes. 163d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 164d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int size() { 165d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode == Opcodes.LABEL.value) { 166d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 0; 167d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 168d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int size = 1; 169d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mHasImm) { 170d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen size += generatedImmSize(); 171d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 172d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel != null) { 173d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen size += generatedImmSize(); 174d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 175d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mCompareBytes != null) { 176d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen size += mCompareBytes.length; 177d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 178d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return size; 179d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 180d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 181d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 182d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Resize immediate value field so that it's only as big as required to 183d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * contain the offset of the jump destination. 184d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return {@code true} if shrunk. 185d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 186d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen boolean shrink() throws IllegalInstructionException { 187d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel == null) { 188d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return false; 189d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 190d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int oldSize = size(); 191d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int oldTargetLabelSize = mTargetLabelSize; 192d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabelSize = calculateImmSize(calculateTargetLabelOffset(), false); 193d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabelSize > oldTargetLabelSize) { 194d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("instruction grew"); 195d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 196d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return size() < oldSize; 197d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 198d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 199d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 200d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Assemble value for instruction size field. 201d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 202d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte generateImmSizeField() { 203d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen byte immSize = generatedImmSize(); 204d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Encode size field to fit in 2 bits: 0->0, 1->1, 2->2, 3->4. 205d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return immSize == 4 ? 3 : immSize; 206d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 207d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 208d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 209d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Assemble first byte of generated instruction. 210d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 211d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte generateInstructionByte() { 212d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen byte sizeField = generateImmSizeField(); 213d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return (byte)((mOpcode << 3) | (sizeField << 1) | mRegister); 214d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 215d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 216d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 217d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Write {@code value} at offset {@code writingOffset} into {@code bytecode}. 218d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@link generatedImmSize} bytes are written. {@code value} is truncated to 219d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code generatedImmSize} bytes. {@code value} is treated simply as a 220d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * 32-bit value, so unsigned values should be zero extended and the truncation 221d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * should simply throw away their zero-ed upper bits, and signed values should 222d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * be sign extended and the truncation should simply throw away their signed 223d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * upper bits. 224d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 225d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int writeValue(int value, byte[] bytecode, int writingOffset) { 226d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (int i = generatedImmSize() - 1; i >= 0; i--) { 227d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen bytecode[writingOffset++] = (byte)((value >> (i * 8)) & 255); 228d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 229d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return writingOffset; 230d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 231d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 232d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 233d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Generate bytecode for this instruction at offset {@link offset}. 234d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 235d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen void generate(byte[] bytecode) throws IllegalInstructionException { 236d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mOpcode == Opcodes.LABEL.value) { 237d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return; 238d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 239d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int writingOffset = offset; 240d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen bytecode[writingOffset++] = generateInstructionByte(); 241d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel != null) { 242d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen writingOffset = writeValue(calculateTargetLabelOffset(), bytecode, writingOffset); 243d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 244d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mHasImm) { 245d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen writingOffset = writeValue(mImm, bytecode, writingOffset); 246d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 247d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mCompareBytes != null) { 248d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen System.arraycopy(mCompareBytes, 0, bytecode, writingOffset, mCompareBytes.length); 249d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen writingOffset += mCompareBytes.length; 250d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 251d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if ((writingOffset - offset) != size()) { 252d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("wrote " + (writingOffset - offset) + 253d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen " but should have written " + size()); 254d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 255d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 256d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 257d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 258d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Calculate the size of either the immediate field or the target label field, if either is 259d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * present. Most instructions have either an immediate or a target label field, but for the 260d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * instructions that have both, the size of the target label field must be the same as the 261d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * size of the immediate field, because there is only one length field in the instruction 262d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * byte, hence why this function simply takes the maximum of the two sizes, so neither is 263d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * truncated. 264d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 265d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte generatedImmSize() { 266d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return mImmSize > mTargetLabelSize ? mImmSize : mTargetLabelSize; 267d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 268d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 269d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int calculateTargetLabelOffset() throws IllegalInstructionException { 270d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction targetLabelInstruction; 271d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mTargetLabel == DROP_LABEL) { 272d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen targetLabelInstruction = mDropLabel; 273d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } else if (mTargetLabel == PASS_LABEL) { 274d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen targetLabelInstruction = mPassLabel; 275d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } else { 276d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen targetLabelInstruction = mLabels.get(mTargetLabel); 277d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 278d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (targetLabelInstruction == null) { 279d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("label not found: " + mTargetLabel); 280d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 281d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Calculate distance from end of this instruction to instruction.offset. 282d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen final int targetLabelOffset = targetLabelInstruction.offset - (offset + size()); 283d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (targetLabelOffset < 0) { 284d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("backward branches disallowed; label: " + 285d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mTargetLabel); 286d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 287d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return targetLabelOffset; 288d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 289d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 290d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private byte calculateImmSize(int imm, boolean signed) { 291d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (imm == 0) { 292d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 0; 293d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 294d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (signed && (imm >= -128 && imm <= 127) || 295d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen !signed && (imm >= 0 && imm <= 255)) { 296d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 1; 297d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 298d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (signed && (imm >= -32768 && imm <= 32767) || 299d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen !signed && (imm >= 0 && imm <= 65535)) { 300d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 2; 301d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 302d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return 4; 303d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 304d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 305d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 306d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 307d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Jump to this label to terminate the program and indicate the packet 308d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * should be dropped. 309d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 310d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final String DROP_LABEL = "__DROP__"; 311d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 312d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 313d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Jump to this label to terminate the program and indicate the packet 314d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * should be passed to the AP. 315d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 316d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final String PASS_LABEL = "__PASS__"; 317d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 318d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 319d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Number of memory slots available for access via APF stores to memory and loads from memory. 320d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * The memory slots are numbered 0 to {@code MEMORY_SLOTS} - 1. This must be kept in sync with 321d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the APF interpreter. 322d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 323d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int MEMORY_SLOTS = 16; 324d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 325d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 326d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Memory slot number that is prefilled with the IPv4 header length. 327d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Note that this memory slot may be overwritten by a program that 328d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * executes stores to this memory slot. This must be kept in sync with 329d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the APF interpreter. 330d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 331d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int IPV4_HEADER_SIZE_MEMORY_SLOT = 13; 332d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 333d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 334d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Memory slot number that is prefilled with the size of the packet being filtered in bytes. 335d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Note that this memory slot may be overwritten by a program that 336d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * executes stores to this memory slot. This must be kept in sync with the APF interpreter. 337d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 338d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int PACKET_SIZE_MEMORY_SLOT = 14; 339d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 340d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 341d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Memory slot number that is prefilled with the age of the filter in seconds. The age of the 342d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * filter is the time since the filter was installed until now. 343d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Note that this memory slot may be overwritten by a program that 344d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * executes stores to this memory slot. This must be kept in sync with the APF interpreter. 345d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 346d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int FILTER_AGE_MEMORY_SLOT = 15; 347d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 348d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 349d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * First memory slot containing prefilled values. Can be used in range comparisons to determine 350d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * if memory slot index is within prefilled slots. 351d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 352d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int FIRST_PREFILLED_MEMORY_SLOT = IPV4_HEADER_SIZE_MEMORY_SLOT; 353d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 354d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 355d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Last memory slot containing prefilled values. Can be used in range comparisons to determine 356d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * if memory slot index is within prefilled slots. 357d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 358d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public static final int LAST_PREFILLED_MEMORY_SLOT = FILTER_AGE_MEMORY_SLOT; 359d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 360408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h 361408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti private static final int MIN_APF_VERSION = 2; 362408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti 363d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final ArrayList<Instruction> mInstructions = new ArrayList<Instruction>(); 364d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final HashMap<String, Instruction> mLabels = new HashMap<String, Instruction>(); 365d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final Instruction mDropLabel = new Instruction(Opcodes.LABEL); 366d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private final Instruction mPassLabel = new Instruction(Opcodes.LABEL); 367408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti private final int mVersion; 368d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private boolean mGenerated; 369d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 370d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 371408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti * Creates an ApfGenerator instance which is able to emit instructions for the specified 372408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti * {@code version} of the APF interpreter. Throws {@code IllegalInstructionException} if 373408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti * the requested version is unsupported. 374408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti */ 375408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti ApfGenerator(int version) throws IllegalInstructionException { 376408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti mVersion = version; 377408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti requireApfVersion(MIN_APF_VERSION); 378408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti } 379408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti 380408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti /** 3813cc40ea6c50c976dd4e6485574a8be899867f610Bernie Innocenti * Returns true if the ApfGenerator supports the specified {@code version}, otherwise false. 382d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 383408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti public static boolean supportsVersion(int version) { 384408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti return version >= MIN_APF_VERSION; 385408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti } 386408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti 387408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti private void requireApfVersion(int minimumVersion) throws IllegalInstructionException { 388408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti if (mVersion < minimumVersion) { 389408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti throw new IllegalInstructionException("Requires APF >= " + minimumVersion); 390408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti } 391d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 392d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 393d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private void addInstruction(Instruction instruction) { 394d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mGenerated) { 395d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("Program already generated"); 396d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 397d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mInstructions.add(instruction); 398d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 399d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 400d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 401d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Define a label at the current end of the program. Jumps can jump to this label. Labels are 402d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * their own separate instructions, though with size 0. This facilitates having labels with 403d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * no corresponding code to execute, for example a label at the end of a program. For example 404d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * an {@link ApfGenerator} might be passed to a function that adds a filter like so: 405d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * <pre> 406d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * load from packet 407d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * compare loaded data, jump if not equal to "next_filter" 408d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * load from packet 409d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * compare loaded data, jump if not equal to "next_filter" 410d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * jump to drop label 411d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * define "next_filter" here 412d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * </pre> 413d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * In this case "next_filter" may not have any generated code associated with it. 414d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 415d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator defineLabel(String name) throws IllegalInstructionException { 416d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LABEL); 417d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setLabel(name); 418d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 419d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 420d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 421d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 422d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 423d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an unconditional jump instruction to the end of the program. 424d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 425d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJump(String target) { 426d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JMP); 427d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 428d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 429d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 430d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 431d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 432d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 433d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load the byte at offset {@code offset} 434d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bytes from the begining of the packet into {@code register}. 435d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 436d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad8(Register register, int offset) { 437d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDB, register); 438d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 439d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 440d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 441d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 442d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 443d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 444d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 16-bits at offset {@code offset} 445d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bytes from the begining of the packet into {@code register}. 446d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 447d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad16(Register register, int offset) { 448d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDH, register); 449d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 450d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 451d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 452d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 453d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 454d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 455d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 32-bits at offset {@code offset} 456d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bytes from the begining of the packet into {@code register}. 457d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 458d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad32(Register register, int offset) { 459d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDW, register); 460d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 461d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 462d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 463d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 464d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 465d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 466d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load a byte from the packet into 467d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. The offset of the loaded byte from the begining of the packet is 468d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the sum of {@code offset} and the value in register R1. 469d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 470d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad8Indexed(Register register, int offset) { 471d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDBX, register); 472d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 473d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 474d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 475d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 476d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 477d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 478d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 16-bits from the packet into 479d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. The offset of the loaded 16-bits from the begining of the packet is 480d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the sum of {@code offset} and the value in register R1. 481d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 482d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad16Indexed(Register register, int offset) { 483d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDHX, register); 484d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 485d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 486d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 487d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 488d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 489d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 490d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load 32-bits from the packet into 491d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. The offset of the loaded 32-bits from the begining of the packet is 492d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * the sum of {@code offset} and the value in register R1. 493d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 494d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoad32Indexed(Register register, int offset) { 495d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LDWX, register); 496d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(offset); 497d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 498d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 499d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 500d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 501d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 502d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to add {@code value} to register R0. 503d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 504d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAdd(int value) { 505d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.ADD); 506d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 507d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 508d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 509d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 510d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 511d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 512d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to multiply register R0 by {@code value}. 513d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 514d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addMul(int value) { 515d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.MUL); 516d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 517d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 518d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 519d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 520d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 521d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 522d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to divide register R0 by {@code value}. 523d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 524d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addDiv(int value) { 525d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.DIV); 526d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 527d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 528d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 529d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 530d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 531d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 532d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically and register R0 with {@code value}. 533d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 534d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAnd(int value) { 535d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.AND); 536d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 537d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 538d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 539d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 540d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 541d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 542d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically or register R0 with {@code value}. 543d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 544d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addOr(int value) { 545d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.OR); 546d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 547d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 548d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 549d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 550d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 551d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 552d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to shift left register R0 by {@code value} bits. 553d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 554d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLeftShift(int value) { 555d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.SH); 556d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 557d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 558d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 559d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 560d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 561d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 562d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to shift right register R0 by {@code value} 563d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * bits. 564d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 565d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addRightShift(int value) { 566d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.SH); 567d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(-value); 568d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 569d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 570d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 571d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 572d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 573d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to add register R1 to register R0. 574d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 575d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAddR1() { 576d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.ADD, Register.R1); 577d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 578d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 579d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 580d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 581d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 582d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to multiply register R0 by register R1. 583d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 584d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addMulR1() { 585d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.MUL, Register.R1); 586d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 587d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 588d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 589d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 590d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 591d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to divide register R0 by register R1. 592d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 593d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addDivR1() { 594d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.DIV, Register.R1); 595d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 596d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 597d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 598d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 599d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 600d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically and register R0 with register R1 601d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * and store the result back into register R0. 602d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 603d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addAndR1() { 604d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.AND, Register.R1); 605d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 606d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 607d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 608d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 609d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 610d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically or register R0 with register R1 611d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * and store the result back into register R0. 612d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 613d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addOrR1() { 614d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.OR, Register.R1); 615d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 616d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 617d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 618d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 619d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 620d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to shift register R0 left by the value in 621d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * register R1. 622d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 623d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLeftShiftR1() { 624d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.SH, Register.R1); 625d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 626d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 627d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 628d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 629d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 630d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to move {@code value} into {@code register}. 631d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 632d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoadImmediate(Register register, int value) { 633d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.LI, register); 634d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setSignedImm(value); 635d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 636d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 637d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 638d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 639d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 640d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 641d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value equals {@code value}. 642d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 643d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0Equals(int value, String target) { 644d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JEQ); 645d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 646d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 647d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 648d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 649d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 650d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 651d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 652d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 653d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value does not equal {@code value}. 654d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 655d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0NotEquals(int value, String target) { 656d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JNE); 657d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 658d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 659d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 660d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 661d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 662d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 663d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 664d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 665d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is greater than {@code value}. 666d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 667d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0GreaterThan(int value, String target) { 668d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JGT); 669d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 670d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 671d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 672d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 673d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 674d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 675d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 676d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 677d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is less than {@code value}. 678d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 679d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0LessThan(int value, String target) { 680d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JLT); 681d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 682d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 683d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 684d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 685d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 686d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 687d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 688d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 689d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value has any bits set that are also set in {@code value}. 690d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 691d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0AnyBitsSet(int value, String target) { 692d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JSET); 693d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(value); 694d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 695d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 696d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 697d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 698d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 699d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 700d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value equals register R1's value. 701d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 702d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0EqualsR1(String target) { 703d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JEQ, Register.R1); 704d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 705d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 706d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 707d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 708d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 709d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 710d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 711d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value does not equal register R1's value. 712d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 713d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0NotEqualsR1(String target) { 714d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JNE, Register.R1); 715d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 716d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 717d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 718d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 719d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 720d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 721d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 722d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is greater than register R1's value. 723d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 724d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0GreaterThanR1(String target) { 725d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JGT, Register.R1); 726d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 727d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 728d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 729d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 730d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 731d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 732d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 733d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value is less than register R1's value. 734d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 735d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0LessThanR1(String target) { 736d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JLT, Register.R1); 737d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 738d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 739d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 740d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 741d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 742d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 743d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if register R0's 744d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * value has any bits set that are also set in R1's value. 745d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 746d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addJumpIfR0AnyBitsSetR1(String target) { 747d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JSET, Register.R1); 748d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 749d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 750d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 751d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 752d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 753d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 754d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to jump to {@code target} if the bytes of the 7553cc40ea6c50c976dd4e6485574a8be899867f610Bernie Innocenti * packet at an offset specified by {@code register} match {@code bytes}. 756d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 75791723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target) 75891723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen throws IllegalInstructionException { 75991723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen if (register == Register.R1) { 76091723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen throw new IllegalInstructionException("JNEBS fails with R1"); 76191723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen } 762d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.JNEBS, register); 763d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(bytes.length); 764d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setTargetLabel(target); 765d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setCompareBytes(bytes); 766d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 767d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 768d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 769d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 770d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 771d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to load memory slot {@code slot} into 772d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register}. 773d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 774d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addLoadFromMemory(Register register, int slot) 775d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throws IllegalInstructionException { 776d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (slot < 0 || slot > (MEMORY_SLOTS - 1)) { 777d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("illegal memory slot number: " + slot); 778d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 779d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 780d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.LDM.value + slot); 781d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 782d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 783d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 784d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 785d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 786d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to store {@code register} into memory slot 787d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code slot}. 788d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 789d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addStoreToMemory(Register register, int slot) 790d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throws IllegalInstructionException { 791d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (slot < 0 || slot > (MEMORY_SLOTS - 1)) { 792d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalInstructionException("illegal memory slot number: " + slot); 793d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 794d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 795d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.STM.value + slot); 796d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 797d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 798d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 799d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 800d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 801d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to logically not {@code register}. 802d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 803d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addNot(Register register) { 804d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 805d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.NOT.value); 806d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 807d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 808d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 809d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 810d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 811d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to negate {@code register}. 812d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 813d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addNeg(Register register) { 814d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 815d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.NEG.value); 816d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 817d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 818d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 819d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 820d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 821d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to swap the values in register R0 and register R1. 822d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 823d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addSwap() { 824d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT); 825d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.SWAP.value); 826d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 827d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 828d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 829d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 830d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 831d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Add an instruction to the end of the program to move the value into 832d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * {@code register} from the other register. 833d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 834d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public ApfGenerator addMove(Register register) { 835d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen Instruction instruction = new Instruction(Opcodes.EXT, register); 836d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.setUnsignedImm(ExtendedOpcodes.MOVE.value); 837d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen addInstruction(instruction); 838d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return this; 839d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 840d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 841d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 842408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti * Add an instruction to the end of the program to load 32 bits from the data memory into 843deb145d2334635dc15781415603ff3a8559e7c49Bernie Innocenti * {@code register}. The source address is computed by adding the signed immediate 844deb145d2334635dc15781415603ff3a8559e7c49Bernie Innocenti * @{code offset} to the other register. 845408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti * Requires APF v3 or greater. 846408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti */ 847408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti public ApfGenerator addLoadData(Register destinationRegister, int offset) 848408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti throws IllegalInstructionException { 849408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti requireApfVersion(3); 850408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti Instruction instruction = new Instruction(Opcodes.LDDW, destinationRegister); 851deb145d2334635dc15781415603ff3a8559e7c49Bernie Innocenti instruction.setSignedImm(offset); 852408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti addInstruction(instruction); 853408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti return this; 854408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti } 855408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti 856408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti /** 857408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti * Add an instruction to the end of the program to store 32 bits from {@code register} into the 858deb145d2334635dc15781415603ff3a8559e7c49Bernie Innocenti * data memory. The destination address is computed by adding the signed immediate 859deb145d2334635dc15781415603ff3a8559e7c49Bernie Innocenti * @{code offset} to the other register. 860408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti * Requires APF v3 or greater. 861408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti */ 862408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti public ApfGenerator addStoreData(Register sourceRegister, int offset) 863408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti throws IllegalInstructionException { 864408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti requireApfVersion(3); 865408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti Instruction instruction = new Instruction(Opcodes.STDW, sourceRegister); 866deb145d2334635dc15781415603ff3a8559e7c49Bernie Innocenti instruction.setSignedImm(offset); 867408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti addInstruction(instruction); 868408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti return this; 869408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti } 870408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti 871408dbda4c1fbee064c7878ef5cfb000e58027a5fBernie Innocenti /** 872d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Updates instruction offset fields using latest instruction sizes. 873d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return current program length in bytes. 874d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 875d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen private int updateInstructionOffsets() { 876d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int offset = 0; 877d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (Instruction instruction : mInstructions) { 878d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.offset = offset; 879d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen offset += instruction.size(); 880d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 881d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return offset; 882d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 883d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 884d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 885d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Returns an overestimate of the size of the generated program. {@link #generate} may return 886d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * a program that is smaller. 887d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 888d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public int programLengthOverEstimate() { 889d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return updateInstructionOffsets(); 890d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 891d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 892d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen /** 893d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * Generate the bytecode for the APF program. 894d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @return the bytecode. 895d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen * @throws IllegalStateException if a label is referenced but not defined. 896d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen */ 897d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen public byte[] generate() throws IllegalInstructionException { 898d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Enforce that we can only generate once because we cannot unshrink instructions and 899d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // PASS/DROP labels may move further away requiring unshrinking if we add further 900d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // instructions. 901d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (mGenerated) { 902d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen throw new IllegalStateException("Can only generate() once!"); 903d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 904d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mGenerated = true; 905d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int total_size; 906d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen boolean shrunk; 907d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Shrink the immediate value fields of instructions. 908d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // As we shrink the instructions some branch offset 909d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // fields may shrink also, thereby shrinking the 910d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // instructions further. Loop until we've reached the 911d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // minimum size. Rarely will this loop more than a few times. 912d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Limit iterations to avoid O(n^2) behavior. 913d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen int iterations_remaining = 10; 914d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen do { 915d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen total_size = updateInstructionOffsets(); 916d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Update drop and pass label offsets. 917d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mDropLabel.offset = total_size + 1; 918d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen mPassLabel.offset = total_size; 919d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Limit run-time in aberant circumstances. 920d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (iterations_remaining-- == 0) break; 921d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Attempt to shrink instructions. 922d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen shrunk = false; 923d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (Instruction instruction : mInstructions) { 924d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen if (instruction.shrink()) { 925d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen shrunk = true; 926d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 927d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 928d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } while (shrunk); 929d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen // Generate bytecode for instructions. 930d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen byte[] bytecode = new byte[total_size]; 931d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen for (Instruction instruction : mInstructions) { 932d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen instruction.generate(bytecode); 933d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 934d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen return bytecode; 935d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen } 936d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen} 937d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen 938