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