thumb: initialise instruction formats
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
		
							
								
								
									
										191
									
								
								src/cpu/thumb/instruction.cc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								src/cpu/thumb/instruction.cc
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,191 @@
 | 
			
		||||
#include "instruction.hh"
 | 
			
		||||
#include "util/bits.hh"
 | 
			
		||||
#include <iterator>
 | 
			
		||||
 | 
			
		||||
namespace matar {
 | 
			
		||||
namespace thumb {
 | 
			
		||||
 | 
			
		||||
Instruction::Instruction(uint16_t insn) {
 | 
			
		||||
    // Format 1:  Move Shifted Register
 | 
			
		||||
    if ((insn & 0xE000) == 0x0000) {
 | 
			
		||||
        uint8_t rd       = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rs       = bit_range(insn, 3, 5);
 | 
			
		||||
        uint8_t offset   = bit_range(insn, 6, 10);
 | 
			
		||||
        ShiftType opcode = static_cast<ShiftType>(bit_range(insn, 11, 12));
 | 
			
		||||
 | 
			
		||||
        data = MoveShiftedRegister{
 | 
			
		||||
            .rd = rd, .rs = rs, .offset = offset, .opcode = opcode
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Format 2: Add/Subtract
 | 
			
		||||
    } else if ((insn & 0xF800) == 0x1800) {
 | 
			
		||||
        uint8_t rd     = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rs     = bit_range(insn, 3, 5);
 | 
			
		||||
        uint8_t offset = bit_range(insn, 6, 8);
 | 
			
		||||
        AddSubtract::OpCode opcode =
 | 
			
		||||
          static_cast<AddSubtract::OpCode>(get_bit(insn, 9));
 | 
			
		||||
        bool imm = get_bit(insn, 10);
 | 
			
		||||
 | 
			
		||||
        data = AddSubtract{
 | 
			
		||||
            .rd = rd, .rs = rs, .offset = offset, .opcode = opcode, .imm = imm
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Format 3: Move/compare/add/subtract immediate
 | 
			
		||||
    } else if ((insn & 0xE000) == 0x2000) {
 | 
			
		||||
        uint8_t offset = bit_range(insn, 0, 7);
 | 
			
		||||
        uint8_t rd     = bit_range(insn, 8, 10);
 | 
			
		||||
        MovCmpAddSubImmediate::OpCode opcode =
 | 
			
		||||
          static_cast<MovCmpAddSubImmediate::OpCode>(bit_range(insn, 11, 12));
 | 
			
		||||
 | 
			
		||||
        data =
 | 
			
		||||
          MovCmpAddSubImmediate{ .offset = offset, .rd = rd, .opcode = opcode };
 | 
			
		||||
 | 
			
		||||
        // Format 4: ALU operations
 | 
			
		||||
    } else if ((insn & 0xFC00) == 0x4000) {
 | 
			
		||||
        uint8_t rd = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rs = bit_range(insn, 3, 5);
 | 
			
		||||
        AluOperations::OpCode opcode =
 | 
			
		||||
          static_cast<AluOperations::OpCode>(bit_range(insn, 6, 9));
 | 
			
		||||
 | 
			
		||||
        data = AluOperations{ .rd = rd, .rs = rs, .opcode = opcode };
 | 
			
		||||
 | 
			
		||||
        // Format 5: Hi register operations/branch exchange
 | 
			
		||||
    } else if ((insn & 0xFC00) == 0x4400) {
 | 
			
		||||
        uint8_t rd = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rs = bit_range(insn, 3, 5);
 | 
			
		||||
        bool hi_2  = get_bit(insn, 6);
 | 
			
		||||
        bool hi_1  = get_bit(insn, 7);
 | 
			
		||||
        HiRegisterOperations::OpCode opcode =
 | 
			
		||||
          static_cast<HiRegisterOperations::OpCode>(bit_range(insn, 8, 9));
 | 
			
		||||
 | 
			
		||||
        data = HiRegisterOperations{
 | 
			
		||||
            .rd = rd, .rs = rs, .hi_2 = hi_2, .hi_1 = hi_1, .opcode = opcode
 | 
			
		||||
        };
 | 
			
		||||
        // Format 6: PC-relative load
 | 
			
		||||
    } else if ((insn & 0xF800) == 0x4800) {
 | 
			
		||||
        uint8_t word = bit_range(insn, 0, 7);
 | 
			
		||||
        uint8_t rd   = bit_range(insn, 8, 10);
 | 
			
		||||
 | 
			
		||||
        data = PcRelativeLoad{ .word = word, .rd = rd };
 | 
			
		||||
 | 
			
		||||
        // Format 7: Load/store with register offset
 | 
			
		||||
    } else if ((insn & 0xF200) == 0x5000) {
 | 
			
		||||
        uint8_t rd = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rb = bit_range(insn, 3, 5);
 | 
			
		||||
        uint8_t ro = bit_range(insn, 6, 8);
 | 
			
		||||
        bool byte  = get_bit(insn, 10);
 | 
			
		||||
        bool load  = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = LoadStoreRegisterOffset{
 | 
			
		||||
            .rd = rd, .rb = rb, .ro = ro, .byte = byte, .load = load
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Format 8: Load/store sign-extended byte/halfword
 | 
			
		||||
    } else if ((insn & 0xF200) == 0x5200) {
 | 
			
		||||
        uint8_t rd = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rb = bit_range(insn, 3, 5);
 | 
			
		||||
        uint8_t ro = bit_range(insn, 6, 8);
 | 
			
		||||
        bool s     = get_bit(insn, 10);
 | 
			
		||||
        bool h     = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = LoadStoreSignExtendedHalfword{
 | 
			
		||||
            .rd = rd, .rb = rb, .ro = ro, .s = s, .h = h
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Format 9: Load/store with immediate offset
 | 
			
		||||
    } else if ((insn & 0xF000) == 0x6000) {
 | 
			
		||||
        uint8_t rd     = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rb     = bit_range(insn, 3, 5);
 | 
			
		||||
        uint8_t offset = bit_range(insn, 6, 10);
 | 
			
		||||
        bool load      = get_bit(insn, 11);
 | 
			
		||||
        bool byte      = get_bit(insn, 12);
 | 
			
		||||
 | 
			
		||||
        data = LoadStoreImmediateOffset{
 | 
			
		||||
            .rd = rd, .rb = rb, .offset = offset, .load = load, .byte = byte
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Format 10: Load/store halfword
 | 
			
		||||
    } else if ((insn & 0xF000) == 0x8000) {
 | 
			
		||||
        uint8_t rd     = bit_range(insn, 0, 2);
 | 
			
		||||
        uint8_t rb     = bit_range(insn, 3, 5);
 | 
			
		||||
        uint8_t offset = bit_range(insn, 6, 10);
 | 
			
		||||
        bool load      = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = LoadStoreHalfword{
 | 
			
		||||
            .rd = rd, .rb = rb, .offset = offset, .load = load
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Format 11: SP-relative load/store
 | 
			
		||||
    } else if ((insn & 0xF000) == 0x9000) {
 | 
			
		||||
        uint8_t word = bit_range(insn, 0, 7);
 | 
			
		||||
        uint8_t rd   = bit_range(insn, 8, 10);
 | 
			
		||||
        bool load    = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = SpRelativeLoad{ .word = word, .rd = rd, .load = load };
 | 
			
		||||
 | 
			
		||||
        // Format 12: Load address
 | 
			
		||||
    } else if ((insn & 0xF000) == 0xA000) {
 | 
			
		||||
        uint8_t word = bit_range(insn, 0, 7);
 | 
			
		||||
        uint8_t rd   = bit_range(insn, 8, 10);
 | 
			
		||||
        bool sp      = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = LoadAddress{ .word = word, .rd = rd, .sp = sp };
 | 
			
		||||
 | 
			
		||||
        // Format 12: Load address
 | 
			
		||||
    } else if ((insn & 0xF000) == 0xA000) {
 | 
			
		||||
        uint8_t word = bit_range(insn, 0, 7);
 | 
			
		||||
        uint8_t rd   = bit_range(insn, 8, 10);
 | 
			
		||||
        bool sp      = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = LoadAddress{ .word = word, .rd = rd, .sp = sp };
 | 
			
		||||
 | 
			
		||||
        // Format 13: Add offset to stack pointer
 | 
			
		||||
    } else if ((insn & 0xFF00) == 0xB000) {
 | 
			
		||||
        uint8_t word = bit_range(insn, 0, 6);
 | 
			
		||||
        bool sign    = get_bit(insn, 7);
 | 
			
		||||
 | 
			
		||||
        data = AddOffsetStackPointer{ .word = word, .sign = sign };
 | 
			
		||||
 | 
			
		||||
        // Format 14: Push/pop registers
 | 
			
		||||
    } else if ((insn & 0xF600) == 0xB400) {
 | 
			
		||||
        uint8_t regs = bit_range(insn, 0, 7);
 | 
			
		||||
        bool pclr    = get_bit(insn, 8);
 | 
			
		||||
        bool load    = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = PushPopRegister{ .regs = regs, .pclr = pclr, .load = load };
 | 
			
		||||
 | 
			
		||||
        // Format 15: Multiple load/store
 | 
			
		||||
    } else if ((insn & 0xF000) == 0xC000) {
 | 
			
		||||
        uint8_t regs = bit_range(insn, 0, 7);
 | 
			
		||||
        uint8_t rb   = bit_range(insn, 8, 10);
 | 
			
		||||
        bool load    = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = MultipleLoad{ .regs = regs, .rb = rb, .load = load };
 | 
			
		||||
 | 
			
		||||
        // Format 17: Software interrupt
 | 
			
		||||
    } else if ((insn & 0xFF00) == 0xDF00) {
 | 
			
		||||
        data = SoftwareInterrupt{};
 | 
			
		||||
 | 
			
		||||
        // Format 16: Conditional branch
 | 
			
		||||
    } else if ((insn & 0xF000) == 0xD000) {
 | 
			
		||||
        uint8_t offset      = bit_range(insn, 0, 7);
 | 
			
		||||
        Condition condition = static_cast<Condition>(bit_range(insn, 8, 11));
 | 
			
		||||
 | 
			
		||||
        data = ConditionalBranch{ .offset = offset, .condition = condition };
 | 
			
		||||
 | 
			
		||||
        // Format 18: Unconditional branch
 | 
			
		||||
    } else if ((insn & 0xF800) == 0xE000) {
 | 
			
		||||
        uint16_t offset = bit_range(insn, 0, 10);
 | 
			
		||||
 | 
			
		||||
        data = UnconditionalBranch{ .offset = offset };
 | 
			
		||||
 | 
			
		||||
        // Format 19: Long branch with link
 | 
			
		||||
    } else if ((insn & 0xF000) == 0xF000) {
 | 
			
		||||
        uint16_t offset = bit_range(insn, 0, 10);
 | 
			
		||||
        bool high       = get_bit(insn, 11);
 | 
			
		||||
 | 
			
		||||
        data = LongBranchWithLink{ .offset = offset, .high = high };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										230
									
								
								src/cpu/thumb/instruction.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								src/cpu/thumb/instruction.hh
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,230 @@
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "cpu/alu.hh"
 | 
			
		||||
#include "cpu/psr.hh"
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <fmt/ostream.h>
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
namespace matar {
 | 
			
		||||
namespace thumb {
 | 
			
		||||
 | 
			
		||||
template<class... Ts>
 | 
			
		||||
struct overloaded : Ts... {
 | 
			
		||||
    using Ts::operator()...;
 | 
			
		||||
};
 | 
			
		||||
template<class... Ts>
 | 
			
		||||
overloaded(Ts...) -> overloaded<Ts...>;
 | 
			
		||||
 | 
			
		||||
static constexpr size_t INSTRUCTION_SIZE = 2;
 | 
			
		||||
 | 
			
		||||
struct MoveShiftedRegister {
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rs;
 | 
			
		||||
    uint8_t offset;
 | 
			
		||||
    ShiftType opcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct AddSubtract {
 | 
			
		||||
    enum class OpCode {
 | 
			
		||||
        ADD = 0,
 | 
			
		||||
        SUB = 1
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rs;
 | 
			
		||||
    uint8_t offset;
 | 
			
		||||
    OpCode opcode;
 | 
			
		||||
    bool imm;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MovCmpAddSubImmediate {
 | 
			
		||||
    enum class OpCode {
 | 
			
		||||
        MOV = 0b00,
 | 
			
		||||
        CMP = 0b01,
 | 
			
		||||
        ADD = 0b10,
 | 
			
		||||
        SUB = 0b11
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    uint8_t offset;
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    OpCode opcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct AluOperations {
 | 
			
		||||
    enum class OpCode {
 | 
			
		||||
        AND = 0b0000,
 | 
			
		||||
        EOR = 0b0001,
 | 
			
		||||
        LSL = 0b0010,
 | 
			
		||||
        LSR = 0b0011,
 | 
			
		||||
        ASR = 0b0100,
 | 
			
		||||
        ADC = 0b0101,
 | 
			
		||||
        SBC = 0b0110,
 | 
			
		||||
        ROR = 0b0111,
 | 
			
		||||
        TST = 0b1000,
 | 
			
		||||
        NEG = 0b1001,
 | 
			
		||||
        CMP = 0b1010,
 | 
			
		||||
        CMN = 0b1011,
 | 
			
		||||
        ORR = 0b1100,
 | 
			
		||||
        MUL = 0b1101,
 | 
			
		||||
        BIC = 0b1110,
 | 
			
		||||
        MVN = 0b1111
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rs;
 | 
			
		||||
    OpCode opcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct HiRegisterOperations {
 | 
			
		||||
    enum class OpCode {
 | 
			
		||||
        ADD = 0b00,
 | 
			
		||||
        CMP = 0b01,
 | 
			
		||||
        MOV = 0b10,
 | 
			
		||||
        BX  = 0b11
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rs;
 | 
			
		||||
    bool hi_2;
 | 
			
		||||
    bool hi_1;
 | 
			
		||||
    OpCode opcode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PcRelativeLoad {
 | 
			
		||||
    uint8_t word;
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LoadStoreRegisterOffset {
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rb;
 | 
			
		||||
    uint8_t ro;
 | 
			
		||||
    bool byte;
 | 
			
		||||
    bool load;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LoadStoreSignExtendedHalfword {
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rb;
 | 
			
		||||
    uint8_t ro;
 | 
			
		||||
    bool s;
 | 
			
		||||
    bool h;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LoadStoreImmediateOffset {
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rb;
 | 
			
		||||
    uint8_t offset;
 | 
			
		||||
    bool load;
 | 
			
		||||
    bool byte;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LoadStoreHalfword {
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    uint8_t rb;
 | 
			
		||||
    uint8_t offset;
 | 
			
		||||
    bool load;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SpRelativeLoad {
 | 
			
		||||
    uint8_t word;
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    bool load;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LoadAddress {
 | 
			
		||||
    uint8_t word;
 | 
			
		||||
    uint8_t rd;
 | 
			
		||||
    bool sp;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct AddOffsetStackPointer {
 | 
			
		||||
    uint8_t word;
 | 
			
		||||
    bool sign;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct PushPopRegister {
 | 
			
		||||
    uint8_t regs;
 | 
			
		||||
    bool pclr;
 | 
			
		||||
    bool load;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MultipleLoad {
 | 
			
		||||
    uint8_t regs;
 | 
			
		||||
    uint8_t rb;
 | 
			
		||||
    bool load;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ConditionalBranch {
 | 
			
		||||
    uint8_t offset;
 | 
			
		||||
    Condition condition;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct SoftwareInterrupt {};
 | 
			
		||||
 | 
			
		||||
struct UnconditionalBranch {
 | 
			
		||||
    uint16_t offset;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct LongBranchWithLink {
 | 
			
		||||
    uint16_t offset;
 | 
			
		||||
    bool high;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
using InstructionData = std::variant<MoveShiftedRegister,
 | 
			
		||||
                                     AddSubtract,
 | 
			
		||||
                                     MovCmpAddSubImmediate,
 | 
			
		||||
                                     AluOperations,
 | 
			
		||||
                                     HiRegisterOperations,
 | 
			
		||||
                                     PcRelativeLoad,
 | 
			
		||||
                                     LoadStoreRegisterOffset,
 | 
			
		||||
                                     LoadStoreSignExtendedHalfword,
 | 
			
		||||
                                     LoadStoreImmediateOffset,
 | 
			
		||||
                                     LoadStoreHalfword,
 | 
			
		||||
                                     SpRelativeLoad,
 | 
			
		||||
                                     LoadAddress,
 | 
			
		||||
                                     AddOffsetStackPointer,
 | 
			
		||||
                                     PushPopRegister,
 | 
			
		||||
                                     MultipleLoad,
 | 
			
		||||
                                     ConditionalBranch,
 | 
			
		||||
                                     SoftwareInterrupt,
 | 
			
		||||
                                     UnconditionalBranch,
 | 
			
		||||
                                     LongBranchWithLink>;
 | 
			
		||||
 | 
			
		||||
struct Instruction {
 | 
			
		||||
    InstructionData data;
 | 
			
		||||
 | 
			
		||||
    Instruction(uint16_t insn);
 | 
			
		||||
 | 
			
		||||
    std::string disassemble();
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const AddSubtract::OpCode cond);
 | 
			
		||||
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const MovCmpAddSubImmediate::OpCode cond);
 | 
			
		||||
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const AluOperations::OpCode cond);
 | 
			
		||||
 | 
			
		||||
std::ostream&
 | 
			
		||||
operator<<(std::ostream& os, const HiRegisterOperations::OpCode cond);
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace fmt {
 | 
			
		||||
template<>
 | 
			
		||||
struct formatter<matar::thumb::AddSubtract::OpCode> : ostream_formatter {};
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
struct formatter<matar::thumb::MovCmpAddSubImmediate::OpCode>
 | 
			
		||||
  : ostream_formatter {};
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
struct formatter<matar::thumb::AluOperations::OpCode> : ostream_formatter {};
 | 
			
		||||
 | 
			
		||||
template<>
 | 
			
		||||
struct formatter<matar::thumb::HiRegisterOperations::OpCode>
 | 
			
		||||
  : ostream_formatter {};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										3
									
								
								src/cpu/thumb/meson.build
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/cpu/thumb/meson.build
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
lib_sources += files(
 | 
			
		||||
  'instruction.cc'
 | 
			
		||||
)
 | 
			
		||||
		Reference in New Issue
	
	Block a user