All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javr.util.generators.InstructionGenerator Maven / Gradle / Ivy

// Copyright 2018 The JavaAVR Project Developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package javr.util.generators;

import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

import javr.core.AvrInstruction;
import javr.core.AvrInstruction.Opcode;

public class InstructionGenerator {
	private final Opcode[] values;
	private final PrintWriter out;

	public InstructionGenerator(OutputStream out,Opcode... values) {
		this.values = values;
		this.out = new PrintWriter(new OutputStreamWriter(out));
	}

	public void generate() {
		for(int i=0;i!=values.length;++i) {
			generate(values[i]);
		}
		out.flush();
	}

	private void generate(Opcode opcode) {
		String baseClass = determineBaseClass(opcode);
		out.println("/**");
		out.println(" * " + opcode.getDescription() + ".");
		out.println(" * ");
		out.println(" * " + opcode.getOpcodeFormat());
		if(opcode.getOperandFormat() != null) {
			out.println(" * " + opcode.getOperandFormat());
		}
		out.println(" */");
		out.println("public static final class " + opcode + " extends " + baseClass + " {");
		generateConstructor(opcode);
		generateDescriptor(opcode);
		generateWidth(opcode);
		generateEncoder(opcode);
		out.println("}");
	}

	private void generateDescriptor(Opcode opcode) {
		out.println("    public String getDescription() { return \"" + opcode.getDescription() + "\"; }");
		out.println();
	}

	private void generateWidth(Opcode opcode) {
		if(opcode.getOperandFormat() != null) {
			out.println("    public int getWidth() { return 2; }");
			out.println();
		}
	}

	private void generateConstructor(Opcode opcode) {
		out.print("    public " + opcode + "(");
		AvrInstruction.Argument[] args = opcode.getArguments();
		for(int i=0;i!=args.length;++i) {
			if(i != 0) {
				out.print(", ");
			}
			out.print("int " + args[i].id);
		}
		out.println(") {");
		out.print("        super(Opcode." + opcode);
		for (AvrInstruction.Argument arg : opcode.getArguments()) {
			out.print(", " + arg.id);
		}
		out.println(");");
		for (AvrInstruction.Argument arg : opcode.getArguments()) {
			generateInvariantTest(arg);
		}
		out.println("    }");
		out.println();
	}

	private void generateInvariantTest(AvrInstruction.Argument arg) {
		int min = getMinInteger(arg.signed,arg.width);
		int max = getMaxInteger(arg.signed,arg.width);
		boolean shifted = false;
		for(AvrInstruction.Transform t : arg.transforms) {
			if(t instanceof AvrInstruction.ShiftLeft) {
				shifted = true;
				min = min << 1;
				max = max << 1;
			} else {
				AvrInstruction.Offset o = (AvrInstruction.Offset) t;
				min += o.offset;
				max += o.offset;
			}
		}
		out.print("        if(");
		out.print(arg.id + " < " + min + " || " + arg.id + " > " + max);
		if(shifted) {
			out.print(" || (" + arg.id  + " % 2) != 0");
		}
		out.println(") {");
		out.println("            throw new IllegalArgumentException(\"invalid argument " + arg.id + "\");");
		out.println("        }");
	}

	private int getMinInteger(boolean signed, int width) {
		if(signed) {
			return -1 << (width-1);
		} else {
			return 0;
		}
	}

	private int getMaxInteger(boolean signed, int width) {
		if(signed) {
			return (1 << (width-1))-1;
		} else {
			return (1 << width) - 1;
		}
	}

	private void generateEncoder(Opcode opcode) {
		out.println("    public byte[] getBytes() {");
		out.println("        int opcode = 0b" + Integer.toBinaryString(opcode.getBinaryBase()) + ";");
		for (AvrInstruction.Argument arg : opcode.getArguments()) {
			AvrInstruction.Bits[] bits = arg.getBitRanges(opcode);
			int width = 0;
			// FIXME: we need to undo transforms here.
			for (int i = 0; i != bits.length; ++i) {
				AvrInstruction.Bits b = bits[i];
				int shift = b.getStart() - width;
				out.println("        opcode |= (this." + arg.name + " << " + shift + ") & 0b"
						+ Integer.toBinaryString(b.toMask()) + ";");
				width = width + b.getWidth();
			}
		}
		if(opcode.getOperandFormat() == null) {
			out.println("        return new byte[]{ (byte) opcode, (byte) (opcode >> 8) };");
		} else {
			out.println("        return new byte[]{ (byte) opcode, (byte) (opcode >> 8), (byte) (opcode >> 16), (byte) (opcode >> 24) };");
		}
		out.println("    }");
	}

	private String determineBaseClass(Opcode opcode) {
		AvrInstruction.Argument[] args = opcode.getArguments();
		if (args.length == 0) {
			return "AvrInstruction";
		} else {
			String r = "";
			for (int i = 0; i != args.length; ++i) {
				r = r + args[i].kind;
			}
			return r;
		}
	}

	public static void main(String[] args) {
		new InstructionGenerator(System.out, Opcode.values()).generate();
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy