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

jnr.a64asm.Assembler_A64 Maven / Gradle / Ivy

/*
 * Copyright (C) 2018 Ossdev07
 *
 * This file is part of the JNR project.
 *
 * 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 jnr.a64asm;

import java.nio.ByteBuffer;
import java.util.LinkedList;
import java.util.List;

import static jnr.a64asm.INST_CODE.*;
import static jnr.a64asm.InstructionGroup.*;  
import static jnr.a64asm.SIZE.*; 

/**
 * Low level code generation.
 */
@SuppressWarnings({ "unused"})
public final class Assembler_A64 extends Serializer {
    private final CodeBuffer _buffer = new CodeBuffer();
    private final List _relocData = new LinkedList();
    private final CpuInfo cpuInfo = CpuInfo.GENERIC;
    private int _properties = 0;

    private final Logger _logger = null;

    private final CPU_A64 cpu;

    @Override
    boolean is64() {
        return cpu == CPU_A64.A64;
    }

    private static final int intValue(boolean b) {
        return b ? 1 : 0;
    }

    public static final CPU_A64 Aarch_64 = CPU_A64.Aarch64;
    public Assembler_A64(CPU_A64 cpu) {
        this.cpu = cpu;
    }

    public final int offset() {
        return _buffer.offset();
    }

    /** Gets the required size of memory required to store all the generated code */
    public final int codeSize() {
        return _buffer.offset();
    }

    //! @brief Set byte at position @a pos.
    public final byte getByteAt(int pos) {
        return _buffer.getByteAt(pos);
    }

    //! @brief Set word at position @a pos.
    public final short getWordAt(int pos) {
        return _buffer.getWordAt(pos);
    }

    //! @brief Set word at position @a pos.
    public final int getDWordAt(int pos) {
        return _buffer.getDWordAt(pos);
    }

    //! @brief Set word at position @a pos.
    public final long getQWordAt(int pos) {
        return _buffer.getQWordAt(pos);
    }

    //! @brief Set byte at position @a pos.
    public final void setByteAt(int pos, byte x) {
        _buffer.setByteAt(pos, x);
    }

    //! @brief Set word at position @a pos.
    public final void setWordAt(int pos, short x) {
        _buffer.setWordAt(pos, x);
    }

    //! @brief Set word at position @a pos.
    public final void setDWordAt(int pos, int x) {
        _buffer.setDWordAt(pos, x);
    }

    //! @brief Set word at position @a pos.
    public final void setQWordAt(int pos, long x) {
        _buffer.setQWordAt(pos, x);
    }

    //! @brief Set word at position @a pos.
    public final int getInt32At(int pos) {
        return (int) _buffer.getDWordAt(pos);
    }

    //! @brief Set int32 at position @a pos.
    public final void setInt32At(int pos, long x) {
        _buffer.setDWordAt(pos, (int) x);
    }

    public final void setVarAt(int pos, long i, boolean isUnsigned, int size) {
        switch (size) {
            case 1:
                setByteAt(pos, (byte) i);
                break;
            case 2:
                setWordAt(pos, (short) i);
                break;
            case 4:
                setDWordAt(pos, (int) i);
                break;
            case 8:
                setQWordAt(pos, i);
            default:
                throw new IllegalArgumentException("invalid size");
        }
    }

    /** Emit Byte to internal buffer. */
    final void _emitByte(int  x) {
        _buffer.emitByte((byte) x);
    }

    /** Emit Word (2 bytes) to internal buffer. */
    final void _emitWord(int x) {
        _buffer.emitWord((short) x);
    }

    /** Emit DWord (4 bytes) to internal buffer. */
    final void _emitDWord(int x) {
        _buffer.emitDWord(x);
    }

    /** Emit QWord (8 bytes) to internal buffer. */
    final void _emitQWord(long x) {
        _buffer.emitQWord(x);
    }

    /** Emit Int32 (4 bytes) to internal buffer. */
    final void _emitInt32(int x) {
        _buffer.emitDWord(x);
    }

    /** Emit system signed integer (4 or 8 bytes) to internal buffer. */
    final void _emitSysInt(long x) {
        if (is64()) {
            _buffer.emitQWord(x);
        } else {
            _buffer.emitDWord((int) x);
        }
    }

    //! @brief Emit single @a opCode without operands.
    final void _emitOpCode(int opCode) {
        if ((opCode & 0xFF000000) != 0) {
            _emitByte((byte) ((opCode & 0xFF000000) >> 24));
        }
        if ((opCode & 0x00FF0000) != 0) {
            _emitByte((byte) ((opCode & 0x00FF0000) >> 16));
        }
        if ((opCode & 0x0000FF00) != 0) {
            _emitByte((byte) ((opCode & 0x0000FF00) >> 8));
        }
        _emitByte((byte) (opCode & 0x000000FF));
    }

    void _emitImmediate(Immediate imm, int size) {
        switch (size) {
            case 1:
                _emitByte(imm.byteValue());
                break;
            case 2:
                _emitWord(imm.shortValue());
                break;
            case 4:
                _emitDWord(imm.intValue());
                break;
            case 8:
                if (!is64()) {
                    throw new IllegalArgumentException("64 bit immediate values not supported for 32bit");
                }
                _emitQWord(imm.longValue());
                break;
            default:
                throw new IllegalArgumentException("invalid immediate operand size");
        }
    }

    void _emita64(INST_CODE code, Operand o1, Operand o2, Operand o3, Operand o4, Operand o5) {
        InstructionDescription id = InstructionDescription.find(code);
        switch(id.group){
            case addsub_carry:
            case addsub_ext:
            {
                int inst_to_emit = 0;
                if ((o1.isReg() && o2.isReg() && o3.isReg()) || (o4 != null && o4.isExtend())){
                    Register regD = (Register) o1;
                    Register regN = (Register) o2;
                    Register regM = (Register) o3;
                    Ext extV = null;
                    if(o4 != _none && o4.isExtend())
                        extV = (Ext) o4;
                    if(o1.size() == SIZE_DWORD){
                            inst_to_emit |= 1 << 31;
                    }
                    inst_to_emit |= regD.code & 0b11111;
                    inst_to_emit |= (regN.code &  0b11111) << 5;
                    inst_to_emit |= (regM.code &  0b11111) << 16;
                    if((id.group == addsub_ext) && (extV != null)){
                        inst_to_emit |= (extV.value() & 0b111) << 10;
                        inst_to_emit |= (extV.type() & 0b111) << 13;
                    }
                    inst_to_emit |= id.opcode;
                    _emitInt32(inst_to_emit);
                }
                else
                    throw new IllegalArgumentException("illegal arguments");
                break;
            }
            case addsub_imm:
            case addsub_shift:
            {
                int inst_to_emit = 0;
                if ((o1 != _none && o1.isReg()) && (o2 != _none && o2.isReg())){
                    Register regD = (Register) o1;
                    Register regN = (Register) o2;
                    Immediate val = null ;
                    if(o3 != _none  && o3.isImm())
                        val = (Immediate) o3;
                    Shift sft = null;
                    if(o4 != _none)
                        sft = (Shift) o4;
                    Register regM = null;
                    if(o3 != _none && o3.isReg())
                        regM = (Register) o3;
                    if(o1.size() == SIZE_DWORD)
                        inst_to_emit |= 1 << 31;
                    inst_to_emit |= regD.code & 0b11111;
                    inst_to_emit |= (regN.code &  0b11111) << 16;
                    if(id.group == addsub_shift){
                        if(regM != null)
                            inst_to_emit |= (regM.code &  0b11111) << 16;
                        if (sft != null)
                            inst_to_emit |= (sft.value() &  0b111111) << 10;
                    }
                    else {
                        if (val != null)
                            inst_to_emit |= (val.value() &  0xfff) << 10;
                    }
                    if(sft != null)
                        inst_to_emit |= (sft.type() & 0b11) << 22;
                    inst_to_emit |= id.opcode;
                    _emitInt32(inst_to_emit);
                }
                else
                    throw new IllegalArgumentException("illegal arguments");
                break;
            }
            case bitfield:
            {
                int inst_to_emit = 0;
                if (o1.isReg() && o2.isReg()){
                    Register regD = (Register) o1;
                    Register regN = (Register) o2;
                    Immediate val1 = null ;
                    if(o3.isImm())
                        val1 = (Immediate) o3;
                    Immediate val2 = null;
                    if(o4.isImm())
                        val2 = (Immediate) o4;
                    if(o1.size() == SIZE_DWORD){
                        inst_to_emit |= 1 << 31;
                        inst_to_emit |= 1 << 22;
                    }
                    inst_to_emit |= regD.code & 0b11111;
                    inst_to_emit |= (regN.code &  0b11111) << 5;
                    if (val1 != null)
                        inst_to_emit |= (val1.value() &  0b111111) << 10;
                    if (val2 != null)
                        inst_to_emit |= (val2.value() &  0b111111) << 16;
                    inst_to_emit |= id.opcode;
                    _emitInt32(inst_to_emit);
                }
                else
                    throw new IllegalArgumentException("illegal arguments");
                break;
            }
            case branch_imm:
            {
                int inst_to_emit = 0;
                if (o1 != _none){
                    Immediate mem = (Immediate) o1;
                    /*




© 2015 - 2024 Weber Informatics LLC | Privacy Policy