restructure: get rid of cpu/utility

Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
2023-09-23 14:12:53 +05:30
parent 1e8966553f
commit 6c33c77ef3
12 changed files with 197 additions and 191 deletions

View File

@@ -1,74 +1,7 @@
#include "utility.hh"
#include "alu.hh"
#include "util/bits.hh"
#include <bit>
namespace matar {
namespace arm {
std::ostream&
operator<<(std::ostream& os, const Condition cond) {
#define CASE(cond) \
case Condition::cond: \
os << #cond; \
break;
switch (cond) {
CASE(EQ)
CASE(NE)
CASE(CS)
CASE(CC)
CASE(MI)
CASE(PL)
CASE(VS)
CASE(VC)
CASE(HI)
CASE(LS)
CASE(GE)
CASE(LT)
CASE(GT)
CASE(LE)
case Condition::AL: {
// empty
}
}
#undef CASE
return os;
}
std::ostream&
operator<<(std::ostream& os, const OpCode opcode) {
#define CASE(opcode) \
case OpCode::opcode: \
os << #opcode; \
break;
switch (opcode) {
CASE(AND)
CASE(EOR)
CASE(SUB)
CASE(RSB)
CASE(ADD)
CASE(ADC)
CASE(SBC)
CASE(RSC)
CASE(TST)
CASE(TEQ)
CASE(CMP)
CASE(CMN)
CASE(ORR)
CASE(MOV)
CASE(BIC)
CASE(MVN)
}
#undef CASE
return os;
}
uint32_t
eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry) {
uint32_t eval = 0;
@@ -136,4 +69,3 @@ operator<<(std::ostream& os, const ShiftType shift_type) {
return os;
}
}
}

35
src/cpu/alu.hh Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
#include <cstdint>
#include <fmt/ostream.h>
namespace matar {
enum class ShiftType {
LSL = 0b00,
LSR = 0b01,
ASR = 0b10,
ROR = 0b11
};
struct ShiftData {
ShiftType type;
bool immediate;
uint8_t operand;
};
struct Shift {
uint8_t rm;
ShiftData data;
};
uint32_t
eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry);
// https://fmt.dev/dev/api.html#std-ostream-support
std::ostream&
operator<<(std::ostream& os, const ShiftType cond);
}
namespace fmt {
template<>
struct formatter<matar::ShiftType> : ostream_formatter {};
}

View File

@@ -7,7 +7,7 @@ using namespace logger;
namespace matar {
void
CpuImpl::exec_arm(const arm::Instruction instruction) {
arm::Condition cond = instruction.condition;
Condition cond = instruction.condition;
arm::InstructionData data = instruction.data;
debug(cpsr.condition(cond));
@@ -387,6 +387,8 @@ CpuImpl::exec_arm(const arm::Instruction instruction) {
}
},
[this, pc_error](DataProcessing& data) {
using OpCode = DataProcessing::OpCode;
uint32_t op_1 = gpr[data.rn];
uint32_t op_2 = 0;

View File

@@ -1,5 +1,4 @@
#include "instruction.hh"
#include "cpu/utility.hh"
#include "util/bits.hh"
#include <iterator>
@@ -153,6 +152,8 @@ Instruction::Instruction(uint32_t insn)
// Data Processing
} else if ((insn & 0x0C000000) == 0x00000000) {
using OpCode = DataProcessing::OpCode;
uint8_t rd = bit_range(insn, 12, 15);
uint8_t rn = bit_range(insn, 16, 19);
bool set = get_bit(insn, 20);
@@ -420,6 +421,8 @@ Instruction::disassemble() {
}
},
[this](DataProcessing& data) {
using OpCode = DataProcessing::OpCode;
std::string op_2;
if (const uint32_t* operand =
@@ -496,5 +499,37 @@ Instruction::disassemble() {
[](auto) { return std::string("unknown instruction"); } },
data);
}
std::ostream&
operator<<(std::ostream& os, const DataProcessing::OpCode opcode) {
#define CASE(opcode) \
case DataProcessing::OpCode::opcode: \
os << #opcode; \
break;
switch (opcode) {
CASE(AND)
CASE(EOR)
CASE(SUB)
CASE(RSB)
CASE(ADD)
CASE(ADC)
CASE(SBC)
CASE(RSC)
CASE(TST)
CASE(TEQ)
CASE(CMP)
CASE(CMN)
CASE(ORR)
CASE(MOV)
CASE(BIC)
CASE(MVN)
}
#undef CASE
return os;
}
}
}

View File

@@ -1,8 +1,13 @@
#pragma once
#include "cpu/utility.hh"
#include "cpu/alu.hh"
#include "cpu/psr.hh"
#include <cstdint>
#include <fmt/ostream.h>
#include <variant>
namespace matar {
namespace arm {
template<class... Ts>
struct overloaded : Ts... {
using Ts::operator()...;
@@ -10,8 +15,6 @@ struct overloaded : Ts... {
template<class... Ts>
overloaded(Ts...) -> overloaded<Ts...>;
namespace matar {
namespace arm {
static constexpr size_t INSTRUCTION_SIZE = 4;
struct BranchAndExchange {
@@ -84,6 +87,25 @@ struct BlockDataTransfer {
};
struct DataProcessing {
enum class OpCode {
AND = 0b0000,
EOR = 0b0001,
SUB = 0b0010,
RSB = 0b0011,
ADD = 0b0100,
ADC = 0b0101,
SBC = 0b0110,
RSC = 0b0111,
TST = 0b1000,
TEQ = 0b1001,
CMP = 0b1010,
CMN = 0b1011,
ORR = 0b1100,
MOV = 0b1101,
BIC = 0b1110,
MVN = 0b1111
};
std::variant<Shift, uint32_t> operand;
uint8_t rd;
uint8_t rn;
@@ -166,5 +188,13 @@ struct Instruction {
std::string disassemble();
};
std::ostream&
operator<<(std::ostream& os, const DataProcessing::OpCode cond);
}
}
namespace fmt {
template<>
struct formatter<matar::arm::DataProcessing::OpCode> : ostream_formatter {};
}

View File

@@ -1,7 +1,6 @@
#include "cpu-impl.hh"
#include "util/bits.hh"
#include "util/log.hh"
#include "utility.hh"
#include <algorithm>
#include <cstdio>

View File

@@ -2,7 +2,7 @@ lib_sources += files(
'cpu-impl.cc',
'cpu.cc',
'psr.cc',
'utility.cc'
'alu.cc'
)
subdir('arm')

View File

@@ -60,9 +60,7 @@ GET_SET_NTH_BIT_FUNCTIONS(n, 31);
#undef GET_SET_NTH_BIT_FUNCTIONS
bool
Psr::condition(arm::Condition cond) const {
using arm::Condition;
Psr::condition(Condition cond) const {
switch (cond) {
case Condition::EQ:
return z();
@@ -93,9 +91,42 @@ Psr::condition(arm::Condition cond) const {
case Condition::LE:
return z() || (n() != v());
case Condition::AL:
return true;
return true && state() == State::Arm;
}
return false;
}
std::ostream&
operator<<(std::ostream& os, const Condition cond) {
#define CASE(cond) \
case Condition::cond: \
os << #cond; \
break;
switch (cond) {
CASE(EQ)
CASE(NE)
CASE(CS)
CASE(CC)
CASE(MI)
CASE(PL)
CASE(VS)
CASE(VC)
CASE(HI)
CASE(LS)
CASE(GE)
CASE(LT)
CASE(GT)
CASE(LE)
case Condition::AL: {
// empty
}
}
#undef CASE
return os;
}
}

View File

@@ -1,10 +1,43 @@
#pragma once
#include "arm/instruction.hh"
#include "utility.hh"
#include <cstdint>
#include <fmt/ostream.h>
namespace matar {
enum class Mode {
/* M[4:0] in PSR */
User = 0b10000,
Fiq = 0b10001,
Irq = 0b10010,
Supervisor = 0b10011,
Abort = 0b10111,
Undefined = 0b11011,
System = 0b11111,
};
enum class State {
Arm = 0,
Thumb = 1
};
enum class Condition {
EQ = 0b0000,
NE = 0b0001,
CS = 0b0010,
CC = 0b0011,
MI = 0b0100,
PL = 0b0101,
VS = 0b0110,
VC = 0b0111,
HI = 0b1000,
LS = 0b1001,
GE = 0b1010,
LT = 0b1011,
GT = 0b1100,
LE = 0b1101,
AL = 0b1110
};
class Psr {
public:
// clear the reserved bits i.e, [8:27]
@@ -47,7 +80,7 @@ class Psr {
#undef GET_SET_NTH_BIT_FUNCTIONS
bool condition(arm::Condition cond) const;
bool condition(Condition cond) const;
private:
static constexpr uint32_t PSR_CLEAR_RESERVED = 0xF00000FF;
@@ -55,4 +88,13 @@ class Psr {
uint32_t psr;
};
// https://fmt.dev/dev/api.html#std-ostream-support
std::ostream&
operator<<(std::ostream& os, const Condition cond);
}
namespace fmt {
template<>
struct formatter<matar::Condition> : ostream_formatter {};
}

View File

@@ -1,103 +0,0 @@
#pragma once
#include <fmt/ostream.h>
#include <ostream>
static constexpr size_t THUMB_INSTRUCTION_SIZE = 2;
namespace matar {
enum class Mode {
/* M[4:0] in PSR */
User = 0b10000,
Fiq = 0b10001,
Irq = 0b10010,
Supervisor = 0b10011,
Abort = 0b10111,
Undefined = 0b11011,
System = 0b11111,
};
enum class State {
Arm = 0,
Thumb = 1
};
namespace arm {
enum class Condition {
EQ = 0b0000,
NE = 0b0001,
CS = 0b0010,
CC = 0b0011,
MI = 0b0100,
PL = 0b0101,
VS = 0b0110,
VC = 0b0111,
HI = 0b1000,
LS = 0b1001,
GE = 0b1010,
LT = 0b1011,
GT = 0b1100,
LE = 0b1101,
AL = 0b1110
};
// https://fmt.dev/dev/api.html#std-ostream-support
std::ostream&
operator<<(std::ostream& os, const Condition cond);
enum class OpCode {
AND = 0b0000,
EOR = 0b0001,
SUB = 0b0010,
RSB = 0b0011,
ADD = 0b0100,
ADC = 0b0101,
SBC = 0b0110,
RSC = 0b0111,
TST = 0b1000,
TEQ = 0b1001,
CMP = 0b1010,
CMN = 0b1011,
ORR = 0b1100,
MOV = 0b1101,
BIC = 0b1110,
MVN = 0b1111
};
// https://fmt.dev/dev/api.html#std-ostream-support
std::ostream&
operator<<(std::ostream& os, const OpCode cond);
enum class ShiftType {
LSL = 0b00,
LSR = 0b01,
ASR = 0b10,
ROR = 0b11
};
struct ShiftData {
ShiftType type;
bool immediate;
uint8_t operand;
};
struct Shift {
uint8_t rm;
ShiftData data;
};
uint32_t
eval_shift(ShiftType shift_type, uint32_t value, uint8_t amount, bool& carry);
// https://fmt.dev/dev/api.html#std-ostream-support
std::ostream&
operator<<(std::ostream& os, const ShiftType cond);
}
}
template<>
struct fmt::formatter<matar::arm::Condition> : ostream_formatter {};
template<>
struct fmt::formatter<matar::arm::OpCode> : ostream_formatter {};
template<>
struct fmt::formatter<matar::arm::ShiftType> : ostream_formatter {};

View File

@@ -1,11 +1,11 @@
#include "cpu/cpu-impl.hh"
#include "cpu/utility.hh"
#include "util/bits.hh"
#include <catch2/catch_test_macros.hpp>
#include <limits>
#include <variant>
using namespace matar;
class CpuFixture {
public:
CpuFixture()
@@ -13,8 +13,7 @@ class CpuFixture {
std::vector<uint8_t>(Header::HEADER_SIZE)))) {}
protected:
void exec(arm::InstructionData data,
arm::Condition condition = arm::Condition::AL) {
void exec(arm::InstructionData data, Condition condition = Condition::AL) {
arm::Instruction instruction(condition, data);
cpu.exec_arm(instruction);
}
@@ -746,6 +745,8 @@ TEST_CASE_METHOD(CpuFixture, "PSR Transfer", TAG) {
}
TEST_CASE_METHOD(CpuFixture, "Data Processing", TAG) {
using OpCode = DataProcessing::OpCode;
InstructionData data =
DataProcessing{ .operand = Shift{ .rm = 3,
.data =

View File

@@ -1,10 +1,10 @@
#include "cpu/arm/instruction.hh"
#include "cpu/utility.hh"
#include <catch2/catch_test_macros.hpp>
#define TAG "disassembler"
using namespace matar::arm;
using namespace matar;
using namespace arm;
TEST_CASE("Branch and Exchange", TAG) {
uint32_t raw = 0b11000001001011111111111100011010;
@@ -309,6 +309,8 @@ TEST_CASE("PSR Transfer", TAG) {
}
TEST_CASE("Data Processing", TAG) {
using OpCode = DataProcessing::OpCode;
uint32_t raw = 0b11100000000111100111101101100001;
Instruction instruction(raw);
DataProcessing* alu = nullptr;