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"
61d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        EXT(21);   // Followed by immediate indicating ExtendedOpcodes.
62d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
63d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        final int value;
64d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
65d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private Opcodes(int value) {
66d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            this.value = value;
67d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
68d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
69d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    // Extended opcodes. Primary opcode is Opcodes.EXT. ExtendedOpcodes are encoded in the immediate
70d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    // field.
71d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private enum ExtendedOpcodes {
72d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        LDM(0),   // Load from memory, e.g. "ldm R0,5"
73d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        STM(16),  // Store to memory, e.g. "stm R0,5"
74d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        NOT(32),  // Not, e.g. "not R0"
75d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        NEG(33),  // Negate, e.g. "neg R0"
76d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        SWAP(34), // Swap, e.g. "swap R0,R1"
77d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        MOVE(35);  // Move, e.g. "move R0,R1"
78d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
79d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        final int value;
80d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
81d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private ExtendedOpcodes(int value) {
82d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            this.value = value;
83d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
84d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
85d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public enum Register {
86d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        R0(0),
87d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        R1(1);
88d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
89d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        final int value;
90d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
91d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private Register(int value) {
92d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            this.value = value;
93d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
94d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
95d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private class Instruction {
96d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private final byte mOpcode;   // A "Opcode" value.
97d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private final byte mRegister; // A "Register" value.
98d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private boolean mHasImm;
99d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private byte mImmSize;
100d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private boolean mImmSigned;
101d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private int mImm;
102d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // When mOpcode is a jump:
103d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private byte mTargetLabelSize;
104d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private String mTargetLabel;
105d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // When mOpcode == Opcodes.LABEL:
106d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private String mLabel;
107d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // When mOpcode == Opcodes.JNEBS:
108d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private byte[] mCompareBytes;
109d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}.
110d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        int offset;
111d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
112d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction(Opcodes opcode, Register register) {
113d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mOpcode = (byte)opcode.value;
114d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mRegister = (byte)register.value;
115d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
116d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
117d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction(Opcodes opcode) {
118d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            this(opcode, Register.R0);
119d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
120d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
121d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        void setImm(int imm, boolean signed) {
122d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mHasImm = true;
123d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mImm = imm;
124d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mImmSigned = signed;
125d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mImmSize = calculateImmSize(imm, signed);
126d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
127d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
128d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        void setUnsignedImm(int imm) {
129d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            setImm(imm, false);
130d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
131d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
132d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        void setSignedImm(int imm) {
133d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            setImm(imm, true);
134d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
135d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
136d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        void setLabel(String label) throws IllegalInstructionException {
137d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mLabels.containsKey(label)) {
138d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                throw new IllegalInstructionException("duplicate label " + label);
139d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
140d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mOpcode != Opcodes.LABEL.value) {
141d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                throw new IllegalStateException("adding label to non-label instruction");
142d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
143d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mLabel = label;
144d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mLabels.put(label, this);
145d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
146d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
147d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        void setTargetLabel(String label) {
148d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mTargetLabel = label;
149d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mTargetLabelSize = 4; // May shrink later on in generate().
150d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
151d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
152d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        void setCompareBytes(byte[] bytes) {
153d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mOpcode != Opcodes.JNEBS.value) {
154d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                throw new IllegalStateException("adding compare bytes to non-JNEBS instruction");
155d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
156d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mCompareBytes = bytes;
157d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
158d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
159d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        /**
160d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * @return size of instruction in bytes.
161d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         */
162d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        int size() {
163d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mOpcode == Opcodes.LABEL.value) {
164d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                return 0;
165d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
166d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            int size = 1;
167d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mHasImm) {
168d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                size += generatedImmSize();
169d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
170d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mTargetLabel != null) {
171d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                size += generatedImmSize();
172d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
173d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mCompareBytes != null) {
174d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                size += mCompareBytes.length;
175d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
176d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return size;
177d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
178d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
179d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        /**
180d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * Resize immediate value field so that it's only as big as required to
181d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * contain the offset of the jump destination.
182d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * @return {@code true} if shrunk.
183d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         */
184d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        boolean shrink() throws IllegalInstructionException {
185d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mTargetLabel == null) {
186d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                return false;
187d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
188d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            int oldSize = size();
189d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            int oldTargetLabelSize = mTargetLabelSize;
190d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mTargetLabelSize = calculateImmSize(calculateTargetLabelOffset(), false);
191d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mTargetLabelSize > oldTargetLabelSize) {
192d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                throw new IllegalStateException("instruction grew");
193d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
194d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return size() < oldSize;
195d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
196d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
197d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        /**
198d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * Assemble value for instruction size field.
199d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         */
200d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private byte generateImmSizeField() {
201d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            byte immSize = generatedImmSize();
202d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            // Encode size field to fit in 2 bits: 0->0, 1->1, 2->2, 3->4.
203d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return immSize == 4 ? 3 : immSize;
204d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
205d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
206d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        /**
207d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * Assemble first byte of generated instruction.
208d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         */
209d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private byte generateInstructionByte() {
210d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            byte sizeField = generateImmSizeField();
211d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return (byte)((mOpcode << 3) | (sizeField << 1) | mRegister);
212d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
213d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
214d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        /**
215d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * Write {@code value} at offset {@code writingOffset} into {@code bytecode}.
216d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * {@link generatedImmSize} bytes are written. {@code value} is truncated to
217d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * {@code generatedImmSize} bytes. {@code value} is treated simply as a
218d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * 32-bit value, so unsigned values should be zero extended and the truncation
219d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * should simply throw away their zero-ed upper bits, and signed values should
220d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * be sign extended and the truncation should simply throw away their signed
221d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * upper bits.
222d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         */
223d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private int writeValue(int value, byte[] bytecode, int writingOffset) {
224d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            for (int i = generatedImmSize() - 1; i >= 0; i--) {
225d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                bytecode[writingOffset++] = (byte)((value >> (i * 8)) & 255);
226d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
227d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return writingOffset;
228d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
229d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
230d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        /**
231d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * Generate bytecode for this instruction at offset {@link offset}.
232d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         */
233d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        void generate(byte[] bytecode) throws IllegalInstructionException {
234d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mOpcode == Opcodes.LABEL.value) {
235d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                return;
236d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
237d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            int writingOffset = offset;
238d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            bytecode[writingOffset++] = generateInstructionByte();
239d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mTargetLabel != null) {
240d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                writingOffset = writeValue(calculateTargetLabelOffset(), bytecode, writingOffset);
241d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
242d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mHasImm) {
243d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                writingOffset = writeValue(mImm, bytecode, writingOffset);
244d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
245d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mCompareBytes != null) {
246d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                System.arraycopy(mCompareBytes, 0, bytecode, writingOffset, mCompareBytes.length);
247d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                writingOffset += mCompareBytes.length;
248d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
249d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if ((writingOffset - offset) != size()) {
250d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                throw new IllegalStateException("wrote " + (writingOffset - offset) +
251d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                        " but should have written " + size());
252d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
253d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
254d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
255d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        /**
256d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * Calculate the size of either the immediate field or the target label field, if either is
257d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * present. Most instructions have either an immediate or a target label field, but for the
258d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * instructions that have both, the size of the target label field must be the same as the
259d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * size of the immediate field, because there is only one length field in the instruction
260d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * byte, hence why this function simply takes the maximum of the two sizes, so neither is
261d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         * truncated.
262d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen         */
263d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private byte generatedImmSize() {
264d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return mImmSize > mTargetLabelSize ? mImmSize : mTargetLabelSize;
265d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
266d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
267d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private int calculateTargetLabelOffset() throws IllegalInstructionException {
268d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            Instruction targetLabelInstruction;
269d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (mTargetLabel == DROP_LABEL) {
270d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                targetLabelInstruction = mDropLabel;
271d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            } else if (mTargetLabel == PASS_LABEL) {
272d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                targetLabelInstruction = mPassLabel;
273d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            } else {
274d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                targetLabelInstruction = mLabels.get(mTargetLabel);
275d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
276d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (targetLabelInstruction == null) {
277d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                throw new IllegalInstructionException("label not found: " + mTargetLabel);
278d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
279d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            // Calculate distance from end of this instruction to instruction.offset.
280d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            final int targetLabelOffset = targetLabelInstruction.offset - (offset + size());
281d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (targetLabelOffset < 0) {
282d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                throw new IllegalInstructionException("backward branches disallowed; label: " +
283d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                        mTargetLabel);
284d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
285d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return targetLabelOffset;
286d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
287d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
288d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        private byte calculateImmSize(int imm, boolean signed) {
289d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (imm == 0) {
290d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                return 0;
291d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
292d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (signed && (imm >= -128 && imm <= 127) ||
293d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                    !signed && (imm >= 0 && imm <= 255)) {
294d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                return 1;
295d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
296d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (signed && (imm >= -32768 && imm <= 32767) ||
297d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                    !signed && (imm >= 0 && imm <= 65535)) {
298d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                return 2;
299d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
300d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            return 4;
301d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
302d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
303d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
304d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
305d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Jump to this label to terminate the program and indicate the packet
306d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * should be dropped.
307d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
308d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final String DROP_LABEL = "__DROP__";
309d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
310d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
311d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Jump to this label to terminate the program and indicate the packet
312d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * should be passed to the AP.
313d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
314d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final String PASS_LABEL = "__PASS__";
315d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
316d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
317d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Number of memory slots available for access via APF stores to memory and loads from memory.
318d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * The memory slots are numbered 0 to {@code MEMORY_SLOTS} - 1. This must be kept in sync with
319d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * the APF interpreter.
320d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
321d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final int MEMORY_SLOTS = 16;
322d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
323d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
324d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Memory slot number that is prefilled with the IPv4 header length.
325d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Note that this memory slot may be overwritten by a program that
326d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * executes stores to this memory slot. This must be kept in sync with
327d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * the APF interpreter.
328d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
329d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final int IPV4_HEADER_SIZE_MEMORY_SLOT = 13;
330d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
331d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
332d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Memory slot number that is prefilled with the size of the packet being filtered in bytes.
333d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Note that this memory slot may be overwritten by a program that
334d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * executes stores to this memory slot. This must be kept in sync with the APF interpreter.
335d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
336d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final int PACKET_SIZE_MEMORY_SLOT = 14;
337d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
338d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
339d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Memory slot number that is prefilled with the age of the filter in seconds. The age of the
340d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * filter is the time since the filter was installed until now.
341d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Note that this memory slot may be overwritten by a program that
342d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * executes stores to this memory slot. This must be kept in sync with the APF interpreter.
343d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
344d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final int FILTER_AGE_MEMORY_SLOT = 15;
345d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
346d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
347d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * First memory slot containing prefilled values. Can be used in range comparisons to determine
348d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * if memory slot index is within prefilled slots.
349d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
350d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final int FIRST_PREFILLED_MEMORY_SLOT = IPV4_HEADER_SIZE_MEMORY_SLOT;
351d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
352d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
353d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Last memory slot containing prefilled values. Can be used in range comparisons to determine
354d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * if memory slot index is within prefilled slots.
355d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
356d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public static final int LAST_PREFILLED_MEMORY_SLOT = FILTER_AGE_MEMORY_SLOT;
357d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
358d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private final ArrayList<Instruction> mInstructions = new ArrayList<Instruction>();
359d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private final HashMap<String, Instruction> mLabels = new HashMap<String, Instruction>();
360d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private final Instruction mDropLabel = new Instruction(Opcodes.LABEL);
361d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private final Instruction mPassLabel = new Instruction(Opcodes.LABEL);
362d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private boolean mGenerated;
363d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
364d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
365d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Set version of APF instruction set to generate instructions for. Returns {@code true}
366d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * if generating for this version is supported, {@code false} otherwise.
367d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
368d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public boolean setApfVersion(int version) {
369d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h
370d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return version == 2;
371d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
372d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
373d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private void addInstruction(Instruction instruction) {
374d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        if (mGenerated) {
375d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            throw new IllegalStateException("Program already generated");
376d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
377d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        mInstructions.add(instruction);
378d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
379d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
380d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
381d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Define a label at the current end of the program. Jumps can jump to this label. Labels are
382d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * their own separate instructions, though with size 0. This facilitates having labels with
383d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * no corresponding code to execute, for example a label at the end of a program. For example
384d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * an {@link ApfGenerator} might be passed to a function that adds a filter like so:
385d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * <pre>
386d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     *   load from packet
387d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     *   compare loaded data, jump if not equal to "next_filter"
388d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     *   load from packet
389d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     *   compare loaded data, jump if not equal to "next_filter"
390d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     *   jump to drop label
391d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     *   define "next_filter" here
392d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * </pre>
393d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * In this case "next_filter" may not have any generated code associated with it.
394d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
395d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator defineLabel(String name) throws IllegalInstructionException {
396d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LABEL);
397d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setLabel(name);
398d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
399d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
400d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
401d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
402d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
403d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an unconditional jump instruction to the end of the program.
404d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
405d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJump(String target) {
406d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JMP);
407d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
408d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
409d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
410d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
411d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
412d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
413d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to load the byte at offset {@code offset}
414d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * bytes from the begining of the packet into {@code register}.
415d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
416d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoad8(Register register, int offset) {
417d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LDB, register);
418d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(offset);
419d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
420d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
421d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
422d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
423d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
424d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to load 16-bits at offset {@code offset}
425d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * bytes from the begining of the packet into {@code register}.
426d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
427d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoad16(Register register, int offset) {
428d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LDH, register);
429d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(offset);
430d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
431d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
432d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
433d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
434d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
435d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to load 32-bits at offset {@code offset}
436d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * bytes from the begining of the packet into {@code register}.
437d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
438d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoad32(Register register, int offset) {
439d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LDW, register);
440d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(offset);
441d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
442d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
443d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
444d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
445d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
446d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to load a byte from the packet into
447d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * {@code register}. The offset of the loaded byte from the begining of the packet is
448d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * the sum of {@code offset} and the value in register R1.
449d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
450d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoad8Indexed(Register register, int offset) {
451d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LDBX, register);
452d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(offset);
453d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
454d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
455d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
456d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
457d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
458d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to load 16-bits from the packet into
459d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * {@code register}. The offset of the loaded 16-bits from the begining of the packet is
460d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * the sum of {@code offset} and the value in register R1.
461d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
462d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoad16Indexed(Register register, int offset) {
463d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LDHX, register);
464d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(offset);
465d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
466d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
467d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
468d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
469d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
470d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to load 32-bits from the packet into
471d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * {@code register}. The offset of the loaded 32-bits from the begining of the packet is
472d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * the sum of {@code offset} and the value in register R1.
473d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
474d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoad32Indexed(Register register, int offset) {
475d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LDWX, register);
476d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(offset);
477d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
478d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
479d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
480d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
481d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
482d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to add {@code value} to register R0.
483d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
484d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addAdd(int value) {
485d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.ADD);
486d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setSignedImm(value);
487d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
488d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
489d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
490d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
491d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
492d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to multiply register R0 by {@code value}.
493d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
494d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addMul(int value) {
495d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.MUL);
496d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setSignedImm(value);
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 divide register R0 by {@code value}.
503d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
504d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addDiv(int value) {
505d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.DIV);
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 logically and register R0 with {@code value}.
513d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
514d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addAnd(int value) {
515d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.AND);
516d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(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 logically or register R0 with {@code value}.
523d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
524d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addOr(int value) {
525d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.OR);
526d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(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 shift left register R0 by {@code value} bits.
533d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
534d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLeftShift(int value) {
535d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.SH);
536d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setSignedImm(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 shift right register R0 by {@code value}
543d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * bits.
544d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
545d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addRightShift(int value) {
546d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.SH);
547d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setSignedImm(-value);
548d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
549d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
550d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
551d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
552d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
553d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to add register R1 to register R0.
554d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
555d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addAddR1() {
556d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.ADD, Register.R1);
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 multiply register R0 by register R1.
563d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
564d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addMulR1() {
565d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.MUL, Register.R1);
566d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
567d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
568d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
569d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
570d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
571d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to divide register R0 by register R1.
572d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
573d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addDivR1() {
574d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.DIV, Register.R1);
575d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
576d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
577d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
578d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
579d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
580d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to logically and register R0 with register R1
581d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * and store the result back into register R0.
582d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
583d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addAndR1() {
584d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.AND, Register.R1);
585d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
586d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
587d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
588d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
589d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
590d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to logically or register R0 with register R1
591d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * and store the result back into register R0.
592d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
593d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addOrR1() {
594d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.OR, 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 shift register R0 left by the value in
601d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * register R1.
602d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
603d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLeftShiftR1() {
604d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.SH, 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 move {@code value} into {@code register}.
611d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
612d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoadImmediate(Register register, int value) {
613d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.LI, register);
614d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setSignedImm(value);
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 jump to {@code target} if register R0's
621d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value equals {@code value}.
622d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
623d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0Equals(int value, String target) {
624d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JEQ);
625d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(value);
626d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
627d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
628d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
629d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
630d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
631d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
632d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
633d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value does not equal {@code value}.
634d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
635d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0NotEquals(int value, String target) {
636d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JNE);
637d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(value);
638d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
639d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
640d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
641d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
642d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
643d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
644d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
645d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value is greater than {@code value}.
646d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
647d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0GreaterThan(int value, String target) {
648d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JGT);
649d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(value);
650d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
651d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
652d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
653d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
654d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
655d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
656d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
657d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value is less than {@code value}.
658d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
659d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0LessThan(int value, String target) {
660d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JLT);
661d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(value);
662d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
663d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
664d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
665d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
666d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
667d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
668d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
669d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value has any bits set that are also set in {@code value}.
670d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
671d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0AnyBitsSet(int value, String target) {
672d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JSET);
673d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(value);
674d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
675d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
676d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
677d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
678d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
679d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
680d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value equals register R1's value.
681d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
682d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0EqualsR1(String target) {
683d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JEQ, Register.R1);
684d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
685d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
686d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
687d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
688d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
689d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
690d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
691d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value does not equal register R1's value.
692d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
693d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0NotEqualsR1(String target) {
694d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JNE, Register.R1);
695d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
696d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
697d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
698d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
699d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
700d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
701d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
702d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value is greater than register R1's value.
703d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
704d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0GreaterThanR1(String target) {
705d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JGT, Register.R1);
706d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
707d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
708d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
709d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
710d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
711d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
712d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
713d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value is less than register R1's value.
714d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
715d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0LessThanR1(String target) {
716d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JLT, Register.R1);
717d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
718d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
719d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
720d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
721d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
722d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
723d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if register R0's
724d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * value has any bits set that are also set in R1's value.
725d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
726d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addJumpIfR0AnyBitsSetR1(String target) {
727d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JSET, Register.R1);
728d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
729d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
730d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
731d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
732d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
733d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
734d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to jump to {@code target} if the bytes of the
735d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * packet at, an offset specified by {@code register}, match {@code bytes}.
736d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
73791723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen    public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target)
73891723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen            throws IllegalInstructionException {
73991723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen        if (register == Register.R1) {
74091723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen            throw new IllegalInstructionException("JNEBS fails with R1");
74191723d7f7ecc07e9bfa84c445213acf1dec0664fPaul Jensen        }
742d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.JNEBS, register);
743d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(bytes.length);
744d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setTargetLabel(target);
745d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setCompareBytes(bytes);
746d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
747d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
748d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
749d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
750d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
751d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to load memory slot {@code slot} into
752d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * {@code register}.
753d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
754d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addLoadFromMemory(Register register, int slot)
755d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            throws IllegalInstructionException {
756d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        if (slot < 0 || slot > (MEMORY_SLOTS - 1)) {
757d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            throw new IllegalInstructionException("illegal memory slot number: " + slot);
758d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
759d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.EXT, register);
760d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(ExtendedOpcodes.LDM.value + slot);
761d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
762d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
763d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
764d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
765d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
766d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to store {@code register} into memory slot
767d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * {@code slot}.
768d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
769d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addStoreToMemory(Register register, int slot)
770d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            throws IllegalInstructionException {
771d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        if (slot < 0 || slot > (MEMORY_SLOTS - 1)) {
772d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            throw new IllegalInstructionException("illegal memory slot number: " + slot);
773d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
774d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.EXT, register);
775d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(ExtendedOpcodes.STM.value + slot);
776d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
777d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
778d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
779d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
780d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
781d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to logically not {@code register}.
782d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
783d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addNot(Register register) {
784d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.EXT, register);
785d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(ExtendedOpcodes.NOT.value);
786d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
787d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
788d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
789d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
790d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
791d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to the end of the program to negate {@code register}.
792d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
793d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addNeg(Register register) {
794d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.EXT, register);
795d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(ExtendedOpcodes.NEG.value);
796d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
797d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
798d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
799d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
800d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
801d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Add an instruction to swap the values in register R0 and register R1.
802d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
803d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addSwap() {
804d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.EXT);
805d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(ExtendedOpcodes.SWAP.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 move the value into
812d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * {@code register} from the other register.
813d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
814d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public ApfGenerator addMove(Register register) {
815d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        Instruction instruction = new Instruction(Opcodes.EXT, register);
816d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        instruction.setUnsignedImm(ExtendedOpcodes.MOVE.value);
817d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        addInstruction(instruction);
818d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return this;
819d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
820d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
821d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
822d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Updates instruction offset fields using latest instruction sizes.
823d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * @return current program length in bytes.
824d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
825d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    private int updateInstructionOffsets() {
826d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        int offset = 0;
827d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        for (Instruction instruction : mInstructions) {
828d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            instruction.offset = offset;
829d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            offset += instruction.size();
830d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
831d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return offset;
832d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
833d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
834d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
835d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Returns an overestimate of the size of the generated program. {@link #generate} may return
836d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * a program that is smaller.
837d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
838d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public int programLengthOverEstimate() {
839d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return updateInstructionOffsets();
840d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
841d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
842d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    /**
843d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * Generate the bytecode for the APF program.
844d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * @return the bytecode.
845d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     * @throws IllegalStateException if a label is referenced but not defined.
846d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen     */
847d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    public byte[] generate() throws IllegalInstructionException {
848d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // Enforce that we can only generate once because we cannot unshrink instructions and
849d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // PASS/DROP labels may move further away requiring unshrinking if we add further
850d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // instructions.
851d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        if (mGenerated) {
852d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            throw new IllegalStateException("Can only generate() once!");
853d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
854d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        mGenerated = true;
855d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        int total_size;
856d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        boolean shrunk;
857d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // Shrink the immediate value fields of instructions.
858d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // As we shrink the instructions some branch offset
859d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // fields may shrink also, thereby shrinking the
860d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // instructions further. Loop until we've reached the
861d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // minimum size. Rarely will this loop more than a few times.
862d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // Limit iterations to avoid O(n^2) behavior.
863d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        int iterations_remaining = 10;
864d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        do {
865d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            total_size = updateInstructionOffsets();
866d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            // Update drop and pass label offsets.
867d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mDropLabel.offset = total_size + 1;
868d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            mPassLabel.offset = total_size;
869d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            // Limit run-time in aberant circumstances.
870d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            if (iterations_remaining-- == 0) break;
871d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            // Attempt to shrink instructions.
872d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            shrunk = false;
873d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            for (Instruction instruction : mInstructions) {
874d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                if (instruction.shrink()) {
875d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                    shrunk = true;
876d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen                }
877d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            }
878d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        } while (shrunk);
879d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        // Generate bytecode for instructions.
880d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        byte[] bytecode = new byte[total_size];
881d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        for (Instruction instruction : mInstructions) {
882d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen            instruction.generate(bytecode);
883d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        }
884d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen        return bytecode;
885d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen    }
886d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen}
887d38fb7662d0e525eee57062ee8c14f661b1aee2dPaul Jensen
888